GUAC-656: Migrate RDP to guac_common_surface.

This commit is contained in:
Michael Jumper 2014-04-30 11:44:06 -07:00
parent f6ccfd1211
commit f8ac59798f
7 changed files with 95 additions and 147 deletions

View File

@ -650,7 +650,6 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
guac_client_data->rdp_inst = rdp_inst;
guac_client_data->bounded = FALSE;
guac_client_data->mouse_button_mask = 0;
guac_client_data->current_surface = GUAC_DEFAULT_LAYER;
guac_client_data->clipboard = guac_common_clipboard_alloc(GUAC_RDP_CLIPBOARD_MAX_LENGTH);
guac_client_data->requested_clipboard_format = CB_FORMAT_TEXT;
guac_client_data->audio = NULL;
@ -707,10 +706,6 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
/* Send connection name */
guac_protocol_send_name(client->socket, settings->hostname);
/* Send size */
guac_protocol_send_size(client->socket, GUAC_DEFAULT_LAYER,
settings->width, settings->height);
/* Create glyph surfaces */
guac_client_data->opaque_glyph_surface = cairo_image_surface_create(
CAIRO_FORMAT_RGB24, settings->width, settings->height);
@ -718,6 +713,11 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
guac_client_data->trans_glyph_surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, settings->width, settings->height);
/* Create default surface */
guac_client_data->default_surface = guac_common_surface_alloc(client->socket, GUAC_DEFAULT_LAYER,
settings->width, settings->height);
guac_client_data->current_surface = guac_client_data->default_surface;
/* Set default pointer */
guac_common_set_pointer_cursor(client);

View File

@ -28,6 +28,7 @@
#include "guac_clipboard.h"
#include "guac_list.h"
#include "guac_surface.h"
#include "rdp_fs.h"
#include "rdp_keymap.h"
#include "rdp_settings.h"
@ -120,10 +121,15 @@ typedef struct rdp_guac_client_data {
cairo_t* glyph_cairo;
/**
* The Guacamole layer that GDI operations should draw to. RDP messages
* exist which change this surface to allow drawing to occur off-screen.
* The display.
*/
const guac_layer* current_surface;
guac_common_surface* default_surface;
/**
* The surface that GDI operations should draw to. RDP messages exist which
* change this surface to allow drawing to occur off-screen.
*/
guac_common_surface* current_surface;
/**
* Whether graphical operations are restricted to a specific bounding

View File

@ -25,6 +25,7 @@
#include "client.h"
#include "guac_handlers.h"
#include "guac_list.h"
#include "guac_surface.h"
#include "rdp_cliprdr.h"
#include "rdp_keymap.h"
#include "rdp_rail.h"
@ -92,6 +93,7 @@ int rdp_guac_client_free_handler(guac_client* client) {
/* Free client data */
guac_common_clipboard_free(guac_client_data->clipboard);
guac_common_surface_free(guac_client_data->default_surface);
cairo_surface_destroy(guac_client_data->opaque_glyph_surface);
cairo_surface_destroy(guac_client_data->trans_glyph_surface);
free(guac_client_data);

View File

@ -23,6 +23,7 @@
#include "config.h"
#include "client.h"
#include "guac_surface.h"
#include "rdp_bitmap.h"
#include <pthread.h>
@ -48,28 +49,29 @@ void guac_rdp_cache_bitmap(rdpContext* context, rdpBitmap* bitmap) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_socket* socket = client->socket;
/* Allocate buffer */
/* Allocate surface */
guac_layer* buffer = guac_client_alloc_buffer(client);
guac_common_surface* surface = guac_common_surface_alloc(socket, buffer, bitmap->width, bitmap->height);
/* Cache image data if present */
if (bitmap->data != NULL) {
/* Create surface from image data */
cairo_surface_t* surface = cairo_image_surface_create_for_data(
cairo_surface_t* image = cairo_image_surface_create_for_data(
bitmap->data, CAIRO_FORMAT_RGB24,
bitmap->width, bitmap->height, 4*bitmap->width);
/* Send surface to buffer */
guac_protocol_send_png(socket,
GUAC_COMP_SRC, buffer, 0, 0, surface);
guac_common_surface_draw(surface, 0, 0, image);
/* Free surface */
cairo_surface_destroy(surface);
cairo_surface_destroy(image);
}
/* Store buffer reference in bitmap */
((guac_rdp_bitmap*) bitmap)->layer = buffer;
((guac_rdp_bitmap*) bitmap)->buffer = buffer;
((guac_rdp_bitmap*) bitmap)->surface = surface;
}
@ -97,8 +99,9 @@ void guac_rdp_bitmap_new(rdpContext* context, rdpBitmap* bitmap) {
}
/* No corresponding layer yet - caching is deferred. */
((guac_rdp_bitmap*) bitmap)->layer = NULL;
/* No corresponding surface yet - caching is deferred. */
((guac_rdp_bitmap*) bitmap)->buffer = NULL;
((guac_rdp_bitmap*) bitmap)->surface = NULL;
/* Start at zero usage */
((guac_rdp_bitmap*) bitmap)->used = 0;
@ -108,39 +111,35 @@ void guac_rdp_bitmap_new(rdpContext* context, rdpBitmap* bitmap) {
void guac_rdp_bitmap_paint(rdpContext* context, rdpBitmap* bitmap) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_socket* socket = client->socket;
rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data;
guac_common_surface* surface = ((guac_rdp_bitmap*) bitmap)->surface;
int width = bitmap->right - bitmap->left + 1;
int height = bitmap->bottom - bitmap->top + 1;
/* If not cached, cache if necessary */
if (((guac_rdp_bitmap*) bitmap)->layer == NULL
&& ((guac_rdp_bitmap*) bitmap)->used >= 1)
if (surface == NULL && ((guac_rdp_bitmap*) bitmap)->used >= 1)
guac_rdp_cache_bitmap(context, bitmap);
/* If cached, retrieve from cache */
if (((guac_rdp_bitmap*) bitmap)->layer != NULL)
guac_protocol_send_copy(socket,
((guac_rdp_bitmap*) bitmap)->layer,
0, 0, width, height,
GUAC_COMP_OVER,
GUAC_DEFAULT_LAYER, bitmap->left, bitmap->top);
if (surface != NULL)
guac_common_surface_copy(surface, 0, 0, width, height,
client_data->default_surface, bitmap->left, bitmap->top);
/* Otherwise, draw with stored image data */
else if (bitmap->data != NULL) {
/* Create surface from image data */
cairo_surface_t* surface = cairo_image_surface_create_for_data(
cairo_surface_t* image = cairo_image_surface_create_for_data(
bitmap->data, CAIRO_FORMAT_RGB24,
width, height, 4*bitmap->width);
/* Send surface to buffer */
guac_protocol_send_png(socket,
GUAC_COMP_OVER, GUAC_DEFAULT_LAYER,
bitmap->left, bitmap->top, surface);
/* Draw image on default surface */
guac_common_surface_draw(client_data->default_surface, bitmap->left, bitmap->top, image);
/* Free surface */
cairo_surface_destroy(surface);
cairo_surface_destroy(image);
}
@ -150,20 +149,28 @@ void guac_rdp_bitmap_paint(rdpContext* context, rdpBitmap* bitmap) {
}
void guac_rdp_bitmap_free(rdpContext* context, rdpBitmap* bitmap) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_layer* buffer = ((guac_rdp_bitmap*) bitmap)->buffer;
guac_common_surface* surface = ((guac_rdp_bitmap*) bitmap)->surface;
/* If cached, free buffer */
if (((guac_rdp_bitmap*) bitmap)->layer != NULL)
guac_client_free_buffer(client, ((guac_rdp_bitmap*) bitmap)->layer);
if (buffer != NULL)
guac_client_free_buffer(client, buffer);
/* If cached, free surface */
if (surface != NULL)
guac_common_surface_free(surface);
}
void guac_rdp_bitmap_setsurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data;
if (primary)
((rdp_guac_client_data*) client->data)->current_surface
= GUAC_DEFAULT_LAYER;
client_data->current_surface = client_data->default_surface;
else {
@ -174,11 +181,10 @@ void guac_rdp_bitmap_setsurface(rdpContext* context, rdpBitmap* bitmap, BOOL pri
}
/* If not available as a surface, make available. */
if (((guac_rdp_bitmap*) bitmap)->layer == NULL)
if (((guac_rdp_bitmap*) bitmap)->surface == NULL)
guac_rdp_cache_bitmap(context, bitmap);
((rdp_guac_client_data*) client->data)->current_surface
= ((guac_rdp_bitmap*) bitmap)->layer;
client_data->current_surface = ((guac_rdp_bitmap*) bitmap)->surface;
}

View File

@ -25,6 +25,7 @@
#define _GUAC_RDP_RDP_BITMAP_H
#include "config.h"
#include "guac_surface.h"
#include <freerdp/freerdp.h>
#include <guacamole/protocol.h>
@ -43,9 +44,14 @@ typedef struct guac_rdp_bitmap {
rdpBitmap bitmap;
/**
* Guacamole layer containing cached image data.
* The allocated buffer which backs this bitmap.
*/
guac_layer* layer;
guac_layer* buffer;
/**
* Surface containing cached image data.
*/
guac_common_surface* surface;
/**
* The number of times a bitmap has been used.

View File

@ -23,6 +23,7 @@
#include "config.h"
#include "client.h"
#include "guac_surface.h"
#include "rdp_bitmap.h"
#include <pthread.h>
@ -96,7 +97,7 @@ guac_transfer_function guac_rdp_rop3_transfer_function(guac_client* client,
void guac_rdp_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
const guac_layer* current_layer = ((rdp_guac_client_data*) client->data)->current_surface;
guac_common_surface* current_surface = ((rdp_guac_client_data*) client->data)->current_surface;
int x = dstblt->nLeftRect;
int y = dstblt->nTopRect;
@ -114,23 +115,13 @@ void guac_rdp_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt) {
case 0:
/* Send black rectangle */
guac_protocol_send_rect(client->socket, current_layer, x, y, w, h);
guac_protocol_send_cfill(client->socket,
GUAC_COMP_OVER, current_layer,
0, 0, 0, 255);
guac_common_surface_rect(current_surface, x, y, w, h, 0, 0, 0);
break;
/* DSTINVERT */
case 0x55:
/* Invert */
guac_protocol_send_transfer(client->socket,
current_layer, x, y, w, h,
GUAC_TRANSFER_BINARY_NDEST,
current_layer, x, y);
guac_common_surface_transfer(current_surface, x, y, w, h,
GUAC_TRANSFER_BINARY_NDEST, current_surface, x, y);
break;
/* NOP */
@ -139,11 +130,7 @@ void guac_rdp_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt) {
/* Whiteness */
case 0xFF:
guac_protocol_send_rect(client->socket, current_layer, x, y, w, h);
guac_protocol_send_cfill(client->socket,
GUAC_COMP_OVER, current_layer,
0xFF, 0xFF, 0xFF, 0xFF);
guac_common_surface_rect(current_surface, x, y, w, h, 0xFF, 0xFF, 0xFF);
break;
/* Unsupported ROP3 */
@ -170,7 +157,7 @@ void guac_rdp_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) {
/* Get client and current layer */
guac_client* client = ((rdp_freerdp_context*) context)->client;
const guac_layer* current_layer =
guac_common_surface* current_surface =
((rdp_guac_client_data*) client->data)->current_surface;
int x = patblt->nLeftRect;
@ -180,9 +167,6 @@ void guac_rdp_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) {
rdp_guac_client_data* data = (rdp_guac_client_data*) client->data;
/* Layer for actual transfer */
guac_layer* buffer;
/*
* Warn that rendering is a fallback, as the server should not be sending
* this order.
@ -199,11 +183,7 @@ void guac_rdp_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) {
/* If blackness, send black rectangle */
case 0x00:
guac_protocol_send_rect(client->socket, current_layer, x, y, w, h);
guac_protocol_send_cfill(client->socket,
GUAC_COMP_OVER, current_layer,
0x00, 0x00, 0x00, 0xFF);
guac_common_surface_rect(current_surface, x, y, w, h, 0, 0, 0);
break;
/* If NOP, do nothing */
@ -213,53 +193,21 @@ void guac_rdp_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) {
/* If operation is just a copy, send foreground only */
case 0xCC:
case 0xF0:
guac_protocol_send_rect(client->socket, current_layer, x, y, w, h);
guac_protocol_send_cfill(client->socket,
GUAC_COMP_OVER, current_layer,
guac_common_surface_rect(current_surface, x, y, w, h,
(patblt->foreColor >> 16) & 0xFF,
(patblt->foreColor >> 8 ) & 0xFF,
(patblt->foreColor ) & 0xFF,
0xFF);
(patblt->foreColor ) & 0xFF);
break;
/* If whiteness, send white rectangle */
case 0xFF:
guac_protocol_send_rect(client->socket, current_layer, x, y, w, h);
guac_protocol_send_cfill(client->socket,
GUAC_COMP_OVER, current_layer,
0xFF, 0xFF, 0xFF, 0xFF);
guac_common_surface_rect(current_surface, x, y, w, h, 0xFF, 0xFF, 0xFF);
break;
/* Otherwise, invert entire rect */
default:
/* Allocate buffer for transfer */
buffer = guac_client_alloc_buffer(client);
/* Send rectangle stroke */
guac_protocol_send_rect(client->socket, buffer,
0, 0, w, h);
/* Fill rectangle with fore color only */
guac_protocol_send_cfill(client->socket, GUAC_COMP_OVER, buffer,
0xFF, 0xFF, 0xFF, 0xFF);
/* Transfer */
guac_protocol_send_transfer(client->socket,
/* ... from buffer */
buffer, 0, 0, w, h,
/* ... inverting */
GUAC_TRANSFER_BINARY_XOR,
/* ... to current layer */
current_layer, x, y);
/* Done with buffer */
guac_client_free_buffer(client, buffer);
guac_common_surface_transfer(current_surface, x, y, w, h,
GUAC_TRANSFER_BINARY_NDEST, current_surface, x, y);
}
@ -268,7 +216,7 @@ void guac_rdp_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) {
void guac_rdp_gdi_scrblt(rdpContext* context, SCRBLT_ORDER* scrblt) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
const guac_layer* current_layer = ((rdp_guac_client_data*) client->data)->current_surface;
guac_common_surface* current_surface = ((rdp_guac_client_data*) client->data)->current_surface;
int x = scrblt->nLeftRect;
int y = scrblt->nTopRect;
@ -288,17 +236,15 @@ void guac_rdp_gdi_scrblt(rdpContext* context, SCRBLT_ORDER* scrblt) {
y_src += y - scrblt->nTopRect;
/* Copy screen rect to current surface */
guac_protocol_send_copy(client->socket,
GUAC_DEFAULT_LAYER, x_src, y_src, w, h,
GUAC_COMP_OVER, current_layer, x, y);
guac_common_surface_copy(data->default_surface, x_src, y_src, w, h,
current_surface, x, y);
}
void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
const guac_layer* current_layer = ((rdp_guac_client_data*) client->data)->current_surface;
guac_socket* socket = client->socket;
guac_common_surface* current_surface = ((rdp_guac_client_data*) client->data)->current_surface;
guac_rdp_bitmap* bitmap = (guac_rdp_bitmap*) memblt->bitmap;
int x = memblt->nLeftRect;
@ -329,11 +275,7 @@ void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) {
/* If blackness, send black rectangle */
case 0x00:
guac_protocol_send_rect(client->socket, current_layer, x, y, w, h);
guac_protocol_send_cfill(client->socket,
GUAC_COMP_OVER, current_layer,
0x00, 0x00, 0x00, 0xFF);
guac_common_surface_rect(current_surface, x, y, w, h, 0, 0, 0);
break;
/* If NOP, do nothing */
@ -344,12 +286,11 @@ void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) {
case 0xCC:
/* If not cached, cache if necessary */
if (((guac_rdp_bitmap*) bitmap)->layer == NULL
&& ((guac_rdp_bitmap*) bitmap)->used >= 1)
if (bitmap->surface == NULL && bitmap->used >= 1)
guac_rdp_cache_bitmap(context, memblt->bitmap);
/* If not cached, send as PNG */
if (bitmap->layer == NULL) {
if (bitmap->surface == NULL) {
if (memblt->bitmap->data != NULL) {
/* Create surface from image data */
@ -358,9 +299,7 @@ void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) {
CAIRO_FORMAT_RGB24, w, h, 4*memblt->bitmap->width);
/* Send surface to buffer */
guac_protocol_send_png(socket,
GUAC_COMP_OVER, current_layer,
x, y, surface);
guac_common_surface_draw(current_surface, x, y, surface);
/* Free surface */
cairo_surface_destroy(surface);
@ -370,9 +309,8 @@ void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) {
/* Otherwise, copy */
else
guac_protocol_send_copy(socket,
bitmap->layer, x_src, y_src, w, h,
GUAC_COMP_OVER, current_layer, x, y);
guac_common_surface_copy(bitmap->surface, x_src, y_src, w, h,
current_surface, x, y);
/* Increment usage counter */
((guac_rdp_bitmap*) bitmap)->used++;
@ -381,24 +319,19 @@ void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) {
/* If whiteness, send white rectangle */
case 0xFF:
guac_protocol_send_rect(client->socket, current_layer, x, y, w, h);
guac_protocol_send_cfill(client->socket,
GUAC_COMP_OVER, current_layer,
0xFF, 0xFF, 0xFF, 0xFF);
guac_common_surface_rect(current_surface, x, y, w, h, 0xFF, 0xFF, 0xFF);
break;
/* Otherwise, use transfer */
default:
/* If not available as a surface, make available. */
if (bitmap->layer == NULL)
if (bitmap->surface == NULL)
guac_rdp_cache_bitmap(context, memblt->bitmap);
guac_protocol_send_transfer(socket,
bitmap->layer, x_src, y_src, w, h,
guac_common_surface_transfer(bitmap->surface, x_src, y_src, w, h,
guac_rdp_rop3_transfer_function(client, memblt->bRop),
current_layer, x, y);
current_surface, x, y);
/* Increment usage counter */
((guac_rdp_bitmap*) bitmap)->used++;
@ -417,7 +350,7 @@ void guac_rdp_gdi_opaquerect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect
client_data->settings.color_depth, 32,
((rdp_freerdp_context*) context)->clrconv);
const guac_layer* current_layer = ((rdp_guac_client_data*) client->data)->current_surface;
guac_common_surface* current_surface = ((rdp_guac_client_data*) client->data)->current_surface;
rdp_guac_client_data* data = (rdp_guac_client_data*) client->data;
@ -430,14 +363,10 @@ void guac_rdp_gdi_opaquerect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect
if (guac_rdp_clip_rect(data, &x, &y, &w, &h))
return;
guac_protocol_send_rect(client->socket, current_layer, x, y, w, h);
guac_protocol_send_cfill(client->socket,
GUAC_COMP_OVER, current_layer,
guac_common_surface_rect(current_surface, x, y, w, h,
(color >> 16) & 0xFF,
(color >> 8 ) & 0xFF,
(color ) & 0xFF,
255);
(color ) & 0xFF);
}

View File

@ -23,6 +23,7 @@
#include "config.h"
#include "client.h"
#include "guac_surface.h"
#include "rdp_glyph.h"
#include <pthread.h>
@ -199,7 +200,7 @@ void guac_rdp_glyph_enddraw(rdpContext* context,
guac_client* client = ((rdp_freerdp_context*) context)->client;
rdp_guac_client_data* guac_client_data = (rdp_guac_client_data*) client->data;
const guac_layer* current_layer = ((rdp_guac_client_data*) client->data)->current_surface;
guac_common_surface* current_surface = ((rdp_guac_client_data*) client->data)->current_surface;
/* Use glyph surface to provide image data for glyph rectangle */
cairo_surface_t* glyph_surface = guac_client_data->glyph_surface;
@ -225,10 +226,8 @@ void guac_rdp_glyph_enddraw(rdpContext* context,
cairo_image_surface_get_format(glyph_surface),
width, height, stride);
/* Send surface with all glyphs to layer */
guac_protocol_send_png(client->socket,
GUAC_COMP_OVER, current_layer, x, y,
surface);
/* Send surface with all glyphs to current surface */
guac_common_surface_draw(current_surface, x, y, surface);
/* Destroy surface */
cairo_surface_destroy(surface);