From 4710994bc37bfec64240ade7480506a50e1343ca Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 3 Apr 2012 11:19:37 -0700 Subject: [PATCH 01/13] Do NOT flush the socket after EVERY GLYPH! --- protocols/rdp/src/rdp_glyph.c | 1 - 1 file changed, 1 deletion(-) diff --git a/protocols/rdp/src/rdp_glyph.c b/protocols/rdp/src/rdp_glyph.c index 9e33ba09..08b33aa1 100644 --- a/protocols/rdp/src/rdp_glyph.c +++ b/protocols/rdp/src/rdp_glyph.c @@ -99,7 +99,6 @@ void guac_rdp_glyph_new(rdpContext* context, rdpGlyph* glyph) { surface = cairo_image_surface_create_for_data(image_buffer, CAIRO_FORMAT_ARGB32, width, height, stride); guac_protocol_send_png(socket, GUAC_COMP_SRC, layer, 0, 0, surface); - guac_socket_flush(socket); /* Free surface */ cairo_surface_destroy(surface); From e75e6bbb53ff361a5860a10f1623ccb27d900c01 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 3 Apr 2012 14:03:52 -0700 Subject: [PATCH 02/13] Only cache bitmap on client if not ephemeral. --- protocols/rdp/src/rdp_bitmap.c | 55 +++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/protocols/rdp/src/rdp_bitmap.c b/protocols/rdp/src/rdp_bitmap.c index 38a90fc4..2a514476 100644 --- a/protocols/rdp/src/rdp_bitmap.c +++ b/protocols/rdp/src/rdp_bitmap.c @@ -73,20 +73,21 @@ void guac_rdp_bitmap_new(rdpContext* context, rdpBitmap* bitmap) { context->instance->settings->color_depth, 32, ((rdp_freerdp_context*) context)->clrconv); - /* Create surface from image data */ - cairo_surface_t* surface = cairo_image_surface_create_for_data( - image_buffer, 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); - - /* Free surface */ - cairo_surface_destroy(surface); - - /* If ephemeral, just free image data */ + /* If not ephemeral, store cached image, and free image data */ if (!bitmap->ephemeral) { + /* Create surface from image data */ + cairo_surface_t* surface = cairo_image_surface_create_for_data( + image_buffer, 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); + + /* Free surface */ + cairo_surface_destroy(surface); + /* Free image data if actually alloated */ if (image_buffer != bitmap->data) free(image_buffer); @@ -117,11 +118,31 @@ void guac_rdp_bitmap_paint(rdpContext* context, rdpBitmap* bitmap) { int width = bitmap->right - bitmap->left + 1; int height = bitmap->bottom - bitmap->top + 1; - 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 not ephemeral, retrieve from cache */ + if (!bitmap->ephemeral) + guac_protocol_send_copy(socket, + ((guac_rdp_bitmap*) bitmap)->layer, + 0, 0, width, height, + GUAC_COMP_OVER, + GUAC_DEFAULT_LAYER, 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( + 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); + + /* Free surface */ + cairo_surface_destroy(surface); + + } } From ec66c2b1b655eaa17aac40789d482f22c78b483a Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 3 Apr 2012 17:58:31 -0700 Subject: [PATCH 03/13] Implement EndPaint. --- protocols/rdp/include/rdp_gdi.h | 1 + protocols/rdp/src/client.c | 1 + protocols/rdp/src/rdp_gdi.c | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/protocols/rdp/include/rdp_gdi.h b/protocols/rdp/include/rdp_gdi.h index 97cc3057..1f68352e 100644 --- a/protocols/rdp/include/rdp_gdi.h +++ b/protocols/rdp/include/rdp_gdi.h @@ -51,5 +51,6 @@ void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt); void guac_rdp_gdi_opaquerect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect); void guac_rdp_gdi_palette_update(rdpContext* context, PALETTE_UPDATE* palette); void guac_rdp_gdi_set_bounds(rdpContext* context, rdpBounds* bounds); +void guac_rdp_gdi_end_paint(rdpContext* context); #endif diff --git a/protocols/rdp/src/client.c b/protocols/rdp/src/client.c index e6a028b9..d7f0b8d4 100644 --- a/protocols/rdp/src/client.c +++ b/protocols/rdp/src/client.c @@ -145,6 +145,7 @@ boolean rdp_freerdp_pre_connect(freerdp* instance) { xfree(pointer); /* Set up GDI */ + instance->update->EndPaint = guac_rdp_gdi_end_paint; instance->update->Palette = guac_rdp_gdi_palette_update; instance->update->SetBounds = guac_rdp_gdi_set_bounds; diff --git a/protocols/rdp/src/rdp_gdi.c b/protocols/rdp/src/rdp_gdi.c index e2202e73..7153f4bb 100644 --- a/protocols/rdp/src/rdp_gdi.c +++ b/protocols/rdp/src/rdp_gdi.c @@ -264,3 +264,8 @@ void guac_rdp_gdi_set_bounds(rdpContext* context, rdpBounds* bounds) { } +void guac_rdp_gdi_end_paint(rdpContext* context) { + guac_client* client = ((rdp_freerdp_context*) context)->client; + guac_socket_flush(client->socket); +} + From 6659af55c27fc7c17838ed1ab6462064a10354bc Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 5 Apr 2012 16:45:04 -0700 Subject: [PATCH 04/13] Render all glyphs server-side. --- protocols/rdp/include/client.h | 10 ++++ protocols/rdp/include/rdp_glyph.h | 4 +- protocols/rdp/src/rdp_glyph.c | 98 +++++++++++++++++-------------- 3 files changed, 66 insertions(+), 46 deletions(-) diff --git a/protocols/rdp/include/client.h b/protocols/rdp/include/client.h index a6bb8016..ac869110 100644 --- a/protocols/rdp/include/client.h +++ b/protocols/rdp/include/client.h @@ -63,6 +63,16 @@ typedef struct rdp_guac_client_data { guac_rdp_color foreground; guac_rdp_color background; + /** + * Cairo surface which will receive all drawn glyphs. + */ + cairo_surface_t* glyph_surface; + + /** + * Cairo instance for drawing to glyph surface. + */ + cairo_t* glyph_cairo; + const guac_layer* current_surface; guac_rdp_static_keymap keymap; diff --git a/protocols/rdp/include/rdp_glyph.h b/protocols/rdp/include/rdp_glyph.h index 8270fbbf..2c9510a3 100644 --- a/protocols/rdp/include/rdp_glyph.h +++ b/protocols/rdp/include/rdp_glyph.h @@ -50,9 +50,9 @@ typedef struct guac_rdp_glyph { rdpGlyph glyph; /** - * Guacamole layer containing cached image data. + * Cairo surface layer containing cached image data. */ - guac_layer* layer; + cairo_surface_t* surface; } guac_rdp_glyph; diff --git a/protocols/rdp/src/rdp_glyph.c b/protocols/rdp/src/rdp_glyph.c index 08b33aa1..8a65c6ff 100644 --- a/protocols/rdp/src/rdp_glyph.c +++ b/protocols/rdp/src/rdp_glyph.c @@ -45,11 +45,6 @@ void guac_rdp_glyph_new(rdpContext* context, rdpGlyph* glyph) { - /* Allocate buffer */ - guac_client* client = ((rdp_freerdp_context*) context)->client; - guac_socket* socket = client->socket; - guac_layer* layer = guac_client_alloc_buffer(client); - int x, y, i; int stride; unsigned char* image_buffer; @@ -59,8 +54,6 @@ void guac_rdp_glyph_new(rdpContext* context, rdpGlyph* glyph) { int width = glyph->cx; int height = glyph->cy; - cairo_surface_t* surface; - /* Init Cairo buffer */ stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); image_buffer = malloc(height*stride); @@ -97,15 +90,9 @@ void guac_rdp_glyph_new(rdpContext* context, rdpGlyph* glyph) { } } - surface = cairo_image_surface_create_for_data(image_buffer, CAIRO_FORMAT_ARGB32, width, height, stride); - guac_protocol_send_png(socket, GUAC_COMP_SRC, layer, 0, 0, surface); - - /* Free surface */ - cairo_surface_destroy(surface); - free(image_buffer); - - /* Store layer */ - ((guac_rdp_glyph*) glyph)->layer = layer; + /* Store glyph surface */ + ((guac_rdp_glyph*) glyph)->surface = cairo_image_surface_create_for_data( + image_buffer, CAIRO_FORMAT_ARGB32, width, height, stride); } @@ -113,29 +100,27 @@ void guac_rdp_glyph_draw(rdpContext* context, rdpGlyph* glyph, int x, int y) { 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; - /* Colorize glyph */ - guac_protocol_send_rect(client->socket, ((guac_rdp_glyph*) glyph)->layer, - 0, 0, glyph->cx, glyph->cy); + /* Use glyph as mask */ + cairo_mask_surface( + guac_client_data->glyph_cairo, + ((guac_rdp_glyph*) glyph)->surface, x, y); - guac_protocol_send_cfill(client->socket, - GUAC_COMP_ATOP, ((guac_rdp_glyph*) glyph)->layer, - guac_client_data->foreground.red, - guac_client_data->foreground.green, - guac_client_data->foreground.blue, - 255); - - /* Draw glyph */ - guac_protocol_send_copy(client->socket, - ((guac_rdp_glyph*) glyph)->layer, 0, 0, glyph->cx, glyph->cy, - GUAC_COMP_OVER, current_layer, x, y); + /* Fill rectangle with foreground */ + cairo_rectangle(guac_client_data->glyph_cairo, x, y, glyph->cx, glyph->cy); + cairo_fill(guac_client_data->glyph_cairo); } void guac_rdp_glyph_free(rdpContext* context, rdpGlyph* glyph) { - guac_client* client = ((rdp_freerdp_context*) context)->client; - guac_client_free_buffer(client, ((guac_rdp_glyph*) glyph)->layer); + + unsigned char* image_buffer = cairo_image_surface_get_data( + ((guac_rdp_glyph*) glyph)->surface); + + /* Free surface */ + cairo_surface_destroy(((guac_rdp_glyph*) glyph)->surface); + free(image_buffer); + } void guac_rdp_glyph_begindraw(rdpContext* context, @@ -143,7 +128,6 @@ void guac_rdp_glyph_begindraw(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; bgcolor = freerdp_color_convert_var(bgcolor, context->instance->settings->color_depth, 32, @@ -161,21 +145,47 @@ void guac_rdp_glyph_begindraw(rdpContext* context, guac_client_data->background.green = (bgcolor & 0x00FF00) >> 8; guac_client_data->background.red = (bgcolor & 0xFF0000) >> 16; - /* Paint background on destination */ - guac_protocol_send_rect(client->socket, current_layer, - x, y, width, height); + /* Create glyph surface and cairo instance */ + guac_client_data->glyph_surface = cairo_image_surface_create( + CAIRO_FORMAT_RGB24, width, height); - guac_protocol_send_cfill(client->socket, - GUAC_COMP_OVER, current_layer, - guac_client_data->background.red, - guac_client_data->background.green, - guac_client_data->background.blue, - 255); + guac_client_data->glyph_cairo = cairo_create( + guac_client_data->glyph_surface); + + /* Fill with color */ + cairo_set_source_rgb(guac_client_data->glyph_cairo, + guac_client_data->background.red / 255.0, + guac_client_data->background.green / 255.0, + guac_client_data->background.blue / 255.0); + + cairo_rectangle(guac_client_data->glyph_cairo, + 0, 0, width, height); + + cairo_fill(guac_client_data->glyph_cairo); + + /* Prepare for glyph drawing */ + cairo_set_source_rgb(guac_client_data->glyph_cairo, + guac_client_data->foreground.red / 255.0, + guac_client_data->foreground.green / 255.0, + guac_client_data->foreground.blue / 255.0); } void guac_rdp_glyph_enddraw(rdpContext* context, int x, int y, int width, int height, uint32 fgcolor, uint32 bgcolor) { - /* UNUSED */ + + 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; + + /* Send surface with all glyphs to layer */ + guac_protocol_send_png(client->socket, + GUAC_COMP_OVER, current_layer, x, y, + guac_client_data->glyph_surface); + + /* Clean up cairo and glyph surface */ + cairo_destroy(guac_client_data->glyph_cairo); + cairo_surface_destroy(guac_client_data->glyph_surface); + } From 6781338aaa58c47958e200f570a6a196409fc685 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 5 Apr 2012 22:38:10 -0700 Subject: [PATCH 05/13] Working glyph rendering (except for transparent text) --- protocols/rdp/include/client.h | 9 ---- protocols/rdp/src/client.c | 15 +++++-- protocols/rdp/src/rdp_glyph.c | 80 ++++++++++++++++++---------------- 3 files changed, 54 insertions(+), 50 deletions(-) diff --git a/protocols/rdp/include/client.h b/protocols/rdp/include/client.h index ac869110..246834f3 100644 --- a/protocols/rdp/include/client.h +++ b/protocols/rdp/include/client.h @@ -47,12 +47,6 @@ #define RDP_DEFAULT_PORT 3389 -typedef struct guac_rdp_color { - int red; - int green; - int blue; -} guac_rdp_color; - typedef struct rdp_guac_client_data { freerdp* rdp_inst; @@ -60,9 +54,6 @@ typedef struct rdp_guac_client_data { int mouse_button_mask; - guac_rdp_color foreground; - guac_rdp_color background; - /** * Cairo surface which will receive all drawn glyphs. */ diff --git a/protocols/rdp/src/client.c b/protocols/rdp/src/client.c index d7f0b8d4..e71d8393 100644 --- a/protocols/rdp/src/client.c +++ b/protocols/rdp/src/client.c @@ -193,10 +193,6 @@ boolean rdp_freerdp_post_connect(freerdp* instance) { client->mouse_handler = rdp_guac_client_mouse_handler; client->key_handler = rdp_guac_client_key_handler; - /* Send size */ - guac_protocol_send_size(client->socket, GUAC_DEFAULT_LAYER, - instance->settings->width, instance->settings->height); - return true; } @@ -393,6 +389,17 @@ int guac_client_init(guac_client* client, int argc, char** argv) { /* Send connection name */ guac_protocol_send_name(client->socket, settings->window_title); + /* Send size */ + guac_protocol_send_size(client->socket, GUAC_DEFAULT_LAYER, + settings->width, settings->height); + + /* Create glyph surface and cairo instance */ + guac_client_data->glyph_surface = cairo_image_surface_create( + CAIRO_FORMAT_RGB24, settings->width, settings->height); + + guac_client_data->glyph_cairo = cairo_create( + guac_client_data->glyph_surface); + /* Success */ return 0; diff --git a/protocols/rdp/src/rdp_glyph.c b/protocols/rdp/src/rdp_glyph.c index 8a65c6ff..c2597252 100644 --- a/protocols/rdp/src/rdp_glyph.c +++ b/protocols/rdp/src/rdp_glyph.c @@ -39,6 +39,7 @@ #include #include +#include #include "client.h" #include "rdp_glyph.h" @@ -100,16 +101,16 @@ void guac_rdp_glyph_draw(rdpContext* context, rdpGlyph* glyph, int x, int y) { guac_client* client = ((rdp_freerdp_context*) context)->client; rdp_guac_client_data* guac_client_data = (rdp_guac_client_data*) client->data; - + + /* Do not attempt to draw glyphs if glyph drawing is not begun */ + if (guac_client_data->glyph_cairo == NULL) + return; + /* Use glyph as mask */ cairo_mask_surface( guac_client_data->glyph_cairo, ((guac_rdp_glyph*) glyph)->surface, x, y); - /* Fill rectangle with foreground */ - cairo_rectangle(guac_client_data->glyph_cairo, x, y, glyph->cx, glyph->cy); - cairo_fill(guac_client_data->glyph_cairo); - } void guac_rdp_glyph_free(rdpContext* context, rdpGlyph* glyph) { @@ -127,47 +128,40 @@ void guac_rdp_glyph_begindraw(rdpContext* context, int x, int y, int width, int height, uint32 fgcolor, uint32 bgcolor) { guac_client* client = ((rdp_freerdp_context*) context)->client; - rdp_guac_client_data* guac_client_data = (rdp_guac_client_data*) client->data; - - bgcolor = freerdp_color_convert_var(bgcolor, - context->instance->settings->color_depth, 32, - ((rdp_freerdp_context*) context)->clrconv); + rdp_guac_client_data* guac_client_data = + (rdp_guac_client_data*) client->data; + /* Convert foreground color */ fgcolor = freerdp_color_convert_var(fgcolor, context->instance->settings->color_depth, 32, ((rdp_freerdp_context*) context)->clrconv); - guac_client_data->foreground.blue = fgcolor & 0x0000FF; - guac_client_data->foreground.green = (fgcolor & 0x00FF00) >> 8; - guac_client_data->foreground.red = (fgcolor & 0xFF0000) >> 16; + /* Fill background with color if specified */ + if (width != 0 && height != 0) { - guac_client_data->background.blue = bgcolor & 0x0000FF; - guac_client_data->background.green = (bgcolor & 0x00FF00) >> 8; - guac_client_data->background.red = (bgcolor & 0xFF0000) >> 16; + /* Convert background color */ + bgcolor = freerdp_color_convert_var(bgcolor, + context->instance->settings->color_depth, 32, + ((rdp_freerdp_context*) context)->clrconv); - /* Create glyph surface and cairo instance */ - guac_client_data->glyph_surface = cairo_image_surface_create( - CAIRO_FORMAT_RGB24, width, height); + /* Fill background */ + cairo_rectangle(guac_client_data->glyph_cairo, + x, y, width, height); - guac_client_data->glyph_cairo = cairo_create( - guac_client_data->glyph_surface); + cairo_set_source_rgb(guac_client_data->glyph_cairo, + ( bgcolor & 0x0000FF ) / 255.0, + ((bgcolor & 0x00FF00) >> 8 ) / 255.0, + ((bgcolor & 0xFF0000) >> 16) / 255.0); - /* Fill with color */ - cairo_set_source_rgb(guac_client_data->glyph_cairo, - guac_client_data->background.red / 255.0, - guac_client_data->background.green / 255.0, - guac_client_data->background.blue / 255.0); + cairo_fill(guac_client_data->glyph_cairo); - cairo_rectangle(guac_client_data->glyph_cairo, - 0, 0, width, height); - - cairo_fill(guac_client_data->glyph_cairo); + } /* Prepare for glyph drawing */ cairo_set_source_rgb(guac_client_data->glyph_cairo, - guac_client_data->foreground.red / 255.0, - guac_client_data->foreground.green / 255.0, - guac_client_data->foreground.blue / 255.0); + ( fgcolor & 0x0000FF ) / 255.0, + ((fgcolor & 0x00FF00) >> 8 ) / 255.0, + ((fgcolor & 0xFF0000) >> 16) / 255.0); } @@ -178,14 +172,26 @@ void guac_rdp_glyph_enddraw(rdpContext* context, 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; + /* Use glyph surface to provide image data for glyph rectangle */ + cairo_surface_t* glyph_surface = guac_client_data->glyph_surface; + int stride = cairo_image_surface_get_stride(glyph_surface); + + /* Ensure data is ready */ + cairo_surface_flush(glyph_surface); + + /* Create surface for subsection with text */ + cairo_surface_t* surface = cairo_image_surface_create_for_data( + cairo_image_surface_get_data(glyph_surface) + 4*x + y*stride, + 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, - guac_client_data->glyph_surface); + surface); - /* Clean up cairo and glyph surface */ - cairo_destroy(guac_client_data->glyph_cairo); - cairo_surface_destroy(guac_client_data->glyph_surface); + /* Destroy surface */ + cairo_surface_destroy(surface); } From a0cdb35b3bd1f9cef06a365b0cdb0f504855e008 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 5 Apr 2012 22:55:46 -0700 Subject: [PATCH 06/13] Fix transparent glyphs --- protocols/rdp/include/client.h | 16 ++++++++++++++-- protocols/rdp/src/client.c | 8 ++++---- protocols/rdp/src/rdp_glyph.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/protocols/rdp/include/client.h b/protocols/rdp/include/client.h index 246834f3..306dbcec 100644 --- a/protocols/rdp/include/client.h +++ b/protocols/rdp/include/client.h @@ -55,12 +55,24 @@ typedef struct rdp_guac_client_data { int mouse_button_mask; /** - * Cairo surface which will receive all drawn glyphs. + * Cairo surface which will receive all TRANSPARENT glyphs. + */ + cairo_surface_t* trans_glyph_surface; + + /** + * Cairo surface which will receive all OPAQUE glyphs. + */ + cairo_surface_t* opaque_glyph_surface; + + /** + * The current Cairo surface which will receive all drawn glyphs, + * depending on whether we are currently drawing transparent or + * opaque glyphs. */ cairo_surface_t* glyph_surface; /** - * Cairo instance for drawing to glyph surface. + * Cairo instance for drawing to the current glyph surface. */ cairo_t* glyph_cairo; diff --git a/protocols/rdp/src/client.c b/protocols/rdp/src/client.c index e71d8393..8a87d059 100644 --- a/protocols/rdp/src/client.c +++ b/protocols/rdp/src/client.c @@ -393,12 +393,12 @@ int guac_client_init(guac_client* client, int argc, char** argv) { guac_protocol_send_size(client->socket, GUAC_DEFAULT_LAYER, settings->width, settings->height); - /* Create glyph surface and cairo instance */ - guac_client_data->glyph_surface = cairo_image_surface_create( + /* Create glyph surfaces */ + guac_client_data->opaque_glyph_surface = cairo_image_surface_create( CAIRO_FORMAT_RGB24, settings->width, settings->height); - guac_client_data->glyph_cairo = cairo_create( - guac_client_data->glyph_surface); + guac_client_data->trans_glyph_surface = cairo_image_surface_create( + CAIRO_FORMAT_ARGB32, settings->width, settings->height); /* Success */ return 0; diff --git a/protocols/rdp/src/rdp_glyph.c b/protocols/rdp/src/rdp_glyph.c index c2597252..3e939f64 100644 --- a/protocols/rdp/src/rdp_glyph.c +++ b/protocols/rdp/src/rdp_glyph.c @@ -139,6 +139,14 @@ void guac_rdp_glyph_begindraw(rdpContext* context, /* Fill background with color if specified */ if (width != 0 && height != 0) { + /* Prepare for opaque glyphs */ + guac_client_data->glyph_surface = + guac_client_data->opaque_glyph_surface; + + /* Create cairo instance */ + guac_client_data->glyph_cairo = cairo_create( + guac_client_data->glyph_surface); + /* Convert background color */ bgcolor = freerdp_color_convert_var(bgcolor, context->instance->settings->color_depth, 32, @@ -157,6 +165,29 @@ void guac_rdp_glyph_begindraw(rdpContext* context, } + /* Otherwise, prepare for transparent glyphs */ + else { + + /* Select transparent glyph surface */ + guac_client_data->glyph_surface = + guac_client_data->trans_glyph_surface; + + guac_client_data->glyph_cairo = cairo_create( + guac_client_data->glyph_surface); + + /* Clear surface */ + cairo_set_operator(guac_client_data->glyph_cairo, + CAIRO_OPERATOR_SOURCE); + + cairo_set_source_rgba(guac_client_data->glyph_cairo, 0, 0, 0, 0); + cairo_paint(guac_client_data->glyph_cairo); + + /* Restore operator */ + cairo_set_operator(guac_client_data->glyph_cairo, + CAIRO_OPERATOR_OVER); + + } + /* Prepare for glyph drawing */ cairo_set_source_rgb(guac_client_data->glyph_cairo, ( fgcolor & 0x0000FF ) / 255.0, @@ -193,5 +224,8 @@ void guac_rdp_glyph_enddraw(rdpContext* context, /* Destroy surface */ cairo_surface_destroy(surface); + /* Destroy cairo instance */ + cairo_destroy(guac_client_data->glyph_cairo); + } From 7211513001e7b4747bb58b17d79f673023ee92ea Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 5 Apr 2012 23:03:19 -0700 Subject: [PATCH 07/13] Fix color order regression. --- protocols/rdp/src/rdp_glyph.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/protocols/rdp/src/rdp_glyph.c b/protocols/rdp/src/rdp_glyph.c index 3e939f64..603a1048 100644 --- a/protocols/rdp/src/rdp_glyph.c +++ b/protocols/rdp/src/rdp_glyph.c @@ -157,9 +157,9 @@ void guac_rdp_glyph_begindraw(rdpContext* context, x, y, width, height); cairo_set_source_rgb(guac_client_data->glyph_cairo, - ( bgcolor & 0x0000FF ) / 255.0, + ((bgcolor & 0xFF0000) >> 16) / 255.0, ((bgcolor & 0x00FF00) >> 8 ) / 255.0, - ((bgcolor & 0xFF0000) >> 16) / 255.0); + ( bgcolor & 0x0000FF ) / 255.0); cairo_fill(guac_client_data->glyph_cairo); @@ -190,9 +190,9 @@ void guac_rdp_glyph_begindraw(rdpContext* context, /* Prepare for glyph drawing */ cairo_set_source_rgb(guac_client_data->glyph_cairo, - ( fgcolor & 0x0000FF ) / 255.0, + ((fgcolor & 0xFF0000) >> 16) / 255.0, ((fgcolor & 0x00FF00) >> 8 ) / 255.0, - ((fgcolor & 0xFF0000) >> 16) / 255.0); + ( fgcolor & 0x0000FF ) / 255.0); } From 18a1996f6bb2a83d9a506605651e896ae18394ea Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 10 Apr 2012 11:04:38 -0700 Subject: [PATCH 08/13] Allocate buffers conservatively. --- protocols/rdp/src/rdp_bitmap.c | 91 +++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/protocols/rdp/src/rdp_bitmap.c b/protocols/rdp/src/rdp_bitmap.c index 2a514476..bf351be2 100644 --- a/protocols/rdp/src/rdp_bitmap.c +++ b/protocols/rdp/src/rdp_bitmap.c @@ -53,16 +53,38 @@ #include "client.h" #include "rdp_bitmap.h" -void guac_rdp_bitmap_new(rdpContext* context, rdpBitmap* bitmap) { +void __guac_rdp_cache_bitmap(rdpContext* context, rdpBitmap* bitmap) { guac_client* client = ((rdp_freerdp_context*) context)->client; guac_socket* socket = client->socket; - /* Allocate buffer */ - guac_layer* buffer = guac_client_alloc_buffer(client); + /* Cache image data if present */ + if (bitmap->data != NULL) { - /* Store buffer reference in bitmap */ - ((guac_rdp_bitmap*) bitmap)->layer = buffer; + /* Allocate buffer */ + guac_layer* buffer = guac_client_alloc_buffer(client); + + /* Create surface from image data */ + cairo_surface_t* surface = 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); + + /* Free surface */ + cairo_surface_destroy(surface); + + /* Store buffer reference in bitmap */ + ((guac_rdp_bitmap*) bitmap)->layer = buffer; + + } + +} + + +void guac_rdp_bitmap_new(rdpContext* context, rdpBitmap* bitmap) { /* Convert image data if present */ if (bitmap->data != NULL) { @@ -73,41 +95,27 @@ void guac_rdp_bitmap_new(rdpContext* context, rdpBitmap* bitmap) { context->instance->settings->color_depth, 32, ((rdp_freerdp_context*) context)->clrconv); - /* If not ephemeral, store cached image, and free image data */ - if (!bitmap->ephemeral) { + /* Free existing image, if any */ + if (image_buffer != bitmap->data) + free(bitmap->data); - /* Create surface from image data */ - cairo_surface_t* surface = cairo_image_surface_create_for_data( - image_buffer, CAIRO_FORMAT_RGB24, - bitmap->width, bitmap->height, 4*bitmap->width); + /* Store converted image in bitmap */ + bitmap->data = image_buffer; - /* Send surface to buffer */ - guac_protocol_send_png(socket, - GUAC_COMP_SRC, buffer, 0, 0, surface); + /* If not ephemeral, store cached image */ + if (!bitmap->ephemeral) + __guac_rdp_cache_bitmap(context, bitmap); - /* Free surface */ - cairo_surface_destroy(surface); - - /* Free image data if actually alloated */ - if (image_buffer != bitmap->data) - free(image_buffer); - - } - - /* Otherwise, store converted image in bitmap, free any existing */ - else { - - /* Free existing image, if any */ - if (image_buffer != bitmap->data) - free(bitmap->data); - - /* Store converted image in bitmap */ - bitmap->data = image_buffer; - - } + else + /* No corresponding layer */ + ((guac_rdp_bitmap*) bitmap)->layer = NULL; } + else + /* No corresponding layer */ + ((guac_rdp_bitmap*) bitmap)->layer = NULL; + } void guac_rdp_bitmap_paint(rdpContext* context, rdpBitmap* bitmap) { @@ -118,8 +126,8 @@ void guac_rdp_bitmap_paint(rdpContext* context, rdpBitmap* bitmap) { int width = bitmap->right - bitmap->left + 1; int height = bitmap->bottom - bitmap->top + 1; - /* If not ephemeral, retrieve from cache */ - if (!bitmap->ephemeral) + /* 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, @@ -160,9 +168,14 @@ void guac_rdp_bitmap_setsurface(rdpContext* context, rdpBitmap* bitmap, boolean if (primary) ((rdp_guac_client_data*) client->data)->current_surface = GUAC_DEFAULT_LAYER; - else - ((rdp_guac_client_data*) client->data)->current_surface - = ((guac_rdp_bitmap*) bitmap)->layer; + + else { + + if (((guac_rdp_bitmap*) bitmap)->layer != NULL) + ((rdp_guac_client_data*) client->data)->current_surface + = ((guac_rdp_bitmap*) bitmap)->layer; + + } } From 4de910748d9947fc56a6bae339c8b27c772d8ba6 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 10 Apr 2012 11:51:46 -0700 Subject: [PATCH 09/13] Fix artifacts. --- protocols/rdp/src/rdp_bitmap.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/protocols/rdp/src/rdp_bitmap.c b/protocols/rdp/src/rdp_bitmap.c index bf351be2..2448fdbf 100644 --- a/protocols/rdp/src/rdp_bitmap.c +++ b/protocols/rdp/src/rdp_bitmap.c @@ -58,12 +58,12 @@ void __guac_rdp_cache_bitmap(rdpContext* context, rdpBitmap* bitmap) { guac_client* client = ((rdp_freerdp_context*) context)->client; guac_socket* socket = client->socket; + /* Allocate buffer */ + guac_layer* buffer = guac_client_alloc_buffer(client); + /* Cache image data if present */ if (bitmap->data != NULL) { - /* Allocate buffer */ - guac_layer* buffer = guac_client_alloc_buffer(client); - /* Create surface from image data */ cairo_surface_t* surface = cairo_image_surface_create_for_data( bitmap->data, CAIRO_FORMAT_RGB24, @@ -76,11 +76,11 @@ void __guac_rdp_cache_bitmap(rdpContext* context, rdpBitmap* bitmap) { /* Free surface */ cairo_surface_destroy(surface); - /* Store buffer reference in bitmap */ - ((guac_rdp_bitmap*) bitmap)->layer = buffer; - } + /* Store buffer reference in bitmap */ + ((guac_rdp_bitmap*) bitmap)->layer = buffer; + } @@ -171,9 +171,12 @@ void guac_rdp_bitmap_setsurface(rdpContext* context, rdpBitmap* bitmap, boolean else { - if (((guac_rdp_bitmap*) bitmap)->layer != NULL) - ((rdp_guac_client_data*) client->data)->current_surface - = ((guac_rdp_bitmap*) bitmap)->layer; + /* If not available as a surface, make available. */ + if (((guac_rdp_bitmap*) bitmap)->layer == NULL) + __guac_rdp_cache_bitmap(context, bitmap); + + ((rdp_guac_client_data*) client->data)->current_surface + = ((guac_rdp_bitmap*) bitmap)->layer; } From 8d9a0211d33ca39ef1a19dd29a76b20467b97a18 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 10 Apr 2012 13:21:13 -0700 Subject: [PATCH 10/13] Defer caching. --- protocols/rdp/include/rdp_bitmap.h | 5 +++++ protocols/rdp/src/rdp_bitmap.c | 33 +++++++++++++++++++----------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/protocols/rdp/include/rdp_bitmap.h b/protocols/rdp/include/rdp_bitmap.h index 72fa11f7..39e51f4d 100644 --- a/protocols/rdp/include/rdp_bitmap.h +++ b/protocols/rdp/include/rdp_bitmap.h @@ -54,6 +54,11 @@ typedef struct guac_rdp_bitmap { */ guac_layer* layer; + /** + * The number of times a bitmap has been used. + */ + int used; + } guac_rdp_bitmap; void guac_rdp_bitmap_new(rdpContext* context, rdpBitmap* bitmap); diff --git a/protocols/rdp/src/rdp_bitmap.c b/protocols/rdp/src/rdp_bitmap.c index 2448fdbf..405aa00e 100644 --- a/protocols/rdp/src/rdp_bitmap.c +++ b/protocols/rdp/src/rdp_bitmap.c @@ -102,19 +102,13 @@ void guac_rdp_bitmap_new(rdpContext* context, rdpBitmap* bitmap) { /* Store converted image in bitmap */ bitmap->data = image_buffer; - /* If not ephemeral, store cached image */ - if (!bitmap->ephemeral) - __guac_rdp_cache_bitmap(context, bitmap); - - else - /* No corresponding layer */ - ((guac_rdp_bitmap*) bitmap)->layer = NULL; - } - else - /* No corresponding layer */ - ((guac_rdp_bitmap*) bitmap)->layer = NULL; + /* No corresponding layer yet - caching is deferred. */ + ((guac_rdp_bitmap*) bitmap)->layer = NULL; + + /* Start at zero usage */ + ((guac_rdp_bitmap*) bitmap)->used = 0; } @@ -126,6 +120,15 @@ void guac_rdp_bitmap_paint(rdpContext* context, rdpBitmap* bitmap) { 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 >= 2) { + __guac_rdp_cache_bitmap(context, bitmap); + + guac_client_log_info(client, "Deferred cache! bitmap used=%i", ((guac_rdp_bitmap*) bitmap)->used); + + } + /* If cached, retrieve from cache */ if (((guac_rdp_bitmap*) bitmap)->layer != NULL) guac_protocol_send_copy(socket, @@ -152,14 +155,20 @@ void guac_rdp_bitmap_paint(rdpContext* context, rdpBitmap* bitmap) { } + /* Increment usage counter */ + ((guac_rdp_bitmap*) bitmap)->used++; + + guac_client_log_info(client, "Used bitmap... used=%i", ((guac_rdp_bitmap*) bitmap)->used); + } void guac_rdp_bitmap_free(rdpContext* context, rdpBitmap* bitmap) { guac_client* client = ((rdp_freerdp_context*) context)->client; - /* Free layer, if any */ + /* If cached, free buffer */ if (((guac_rdp_bitmap*) bitmap)->layer != NULL) guac_client_free_buffer(client, ((guac_rdp_bitmap*) bitmap)->layer); + } void guac_rdp_bitmap_setsurface(rdpContext* context, rdpBitmap* bitmap, boolean primary) { From 82c2594320e686baf27d46811246d7f3241d8e02 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 10 Apr 2012 14:23:37 -0700 Subject: [PATCH 11/13] Implement deferred cache via memblt. --- protocols/rdp/include/rdp_bitmap.h | 1 + protocols/rdp/src/rdp_bitmap.c | 14 ++----- protocols/rdp/src/rdp_gdi.c | 59 ++++++++++++++++++++++++------ 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/protocols/rdp/include/rdp_bitmap.h b/protocols/rdp/include/rdp_bitmap.h index 39e51f4d..b4cdd1e0 100644 --- a/protocols/rdp/include/rdp_bitmap.h +++ b/protocols/rdp/include/rdp_bitmap.h @@ -61,6 +61,7 @@ typedef struct guac_rdp_bitmap { } guac_rdp_bitmap; +void guac_rdp_cache_bitmap(rdpContext* context, rdpBitmap* bitmap); void guac_rdp_bitmap_new(rdpContext* context, rdpBitmap* bitmap); void guac_rdp_bitmap_decompress(rdpContext* context, rdpBitmap* bitmap, uint8* data, int width, int height, int bpp, int length, boolean compressed); void guac_rdp_bitmap_paint(rdpContext* context, rdpBitmap* bitmap); diff --git a/protocols/rdp/src/rdp_bitmap.c b/protocols/rdp/src/rdp_bitmap.c index 405aa00e..2d674102 100644 --- a/protocols/rdp/src/rdp_bitmap.c +++ b/protocols/rdp/src/rdp_bitmap.c @@ -53,7 +53,7 @@ #include "client.h" #include "rdp_bitmap.h" -void __guac_rdp_cache_bitmap(rdpContext* context, rdpBitmap* bitmap) { +void guac_rdp_cache_bitmap(rdpContext* context, rdpBitmap* bitmap) { guac_client* client = ((rdp_freerdp_context*) context)->client; guac_socket* socket = client->socket; @@ -122,12 +122,8 @@ void guac_rdp_bitmap_paint(rdpContext* context, rdpBitmap* bitmap) { /* If not cached, cache if necessary */ if (((guac_rdp_bitmap*) bitmap)->layer == NULL - && ((guac_rdp_bitmap*) bitmap)->used >= 2) { - __guac_rdp_cache_bitmap(context, bitmap); - - guac_client_log_info(client, "Deferred cache! bitmap used=%i", ((guac_rdp_bitmap*) bitmap)->used); - - } + && ((guac_rdp_bitmap*) bitmap)->used >= 1) + guac_rdp_cache_bitmap(context, bitmap); /* If cached, retrieve from cache */ if (((guac_rdp_bitmap*) bitmap)->layer != NULL) @@ -158,8 +154,6 @@ void guac_rdp_bitmap_paint(rdpContext* context, rdpBitmap* bitmap) { /* Increment usage counter */ ((guac_rdp_bitmap*) bitmap)->used++; - guac_client_log_info(client, "Used bitmap... used=%i", ((guac_rdp_bitmap*) bitmap)->used); - } void guac_rdp_bitmap_free(rdpContext* context, rdpBitmap* bitmap) { @@ -182,7 +176,7 @@ void guac_rdp_bitmap_setsurface(rdpContext* context, rdpBitmap* bitmap, boolean /* If not available as a surface, make available. */ if (((guac_rdp_bitmap*) bitmap)->layer == NULL) - __guac_rdp_cache_bitmap(context, bitmap); + guac_rdp_cache_bitmap(context, bitmap); ((rdp_guac_client_data*) client->data)->current_surface = ((guac_rdp_bitmap*) bitmap)->layer; diff --git a/protocols/rdp/src/rdp_gdi.c b/protocols/rdp/src/rdp_gdi.c index 7153f4bb..a287e101 100644 --- a/protocols/rdp/src/rdp_gdi.c +++ b/protocols/rdp/src/rdp_gdi.c @@ -159,9 +159,7 @@ void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) { guac_socket* socket = client->socket; guac_rdp_bitmap* bitmap = (guac_rdp_bitmap*) memblt->bitmap; - if (bitmap->layer != NULL) { - - switch (memblt->bRop) { + switch (memblt->bRop) { /* If blackness, send black rectangle */ case 0x00: @@ -180,12 +178,45 @@ void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) { /* If operation is just SRC, simply copy */ case 0xCC: - guac_protocol_send_copy(socket, - bitmap->layer, - memblt->nXSrc, memblt->nYSrc, - memblt->nWidth, memblt->nHeight, - GUAC_COMP_OVER, - current_layer, memblt->nLeftRect, memblt->nTopRect); + + /* If not cached, cache if necessary */ + if (((guac_rdp_bitmap*) bitmap)->used >= 1) + guac_rdp_cache_bitmap(context, memblt->bitmap); + + /* If not cached, send as PNG */ + if (bitmap->layer == NULL) { + if (memblt->bitmap->data != NULL) { + + /* Create surface from image data */ + cairo_surface_t* surface = cairo_image_surface_create_for_data( + memblt->bitmap->data + 4*(memblt->nXSrc + memblt->nYSrc*memblt->bitmap->width), + CAIRO_FORMAT_RGB24, + memblt->nWidth, memblt->nHeight, + 4*memblt->bitmap->width); + + /* Send surface to buffer */ + guac_protocol_send_png(socket, + GUAC_COMP_OVER, current_layer, + memblt->nLeftRect, memblt->nTopRect, surface); + + /* Free surface */ + cairo_surface_destroy(surface); + + } + } + + /* Otherwise, copy */ + else + guac_protocol_send_copy(socket, + bitmap->layer, + memblt->nXSrc, memblt->nYSrc, + memblt->nWidth, memblt->nHeight, + GUAC_COMP_OVER, + current_layer, memblt->nLeftRect, memblt->nTopRect); + + /* Increment usage counter */ + ((guac_rdp_bitmap*) bitmap)->used++; + break; /* If whiteness, send white rectangle */ @@ -201,6 +232,11 @@ void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) { /* Otherwise, use transfer */ default: + + /* If not available as a surface, make available. */ + if (bitmap->layer == NULL) + guac_rdp_cache_bitmap(context, memblt->bitmap); + guac_protocol_send_transfer(socket, bitmap->layer, memblt->nXSrc, memblt->nYSrc, @@ -208,9 +244,10 @@ void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) { guac_rdp_rop3_transfer_function(client, memblt->bRop), current_layer, memblt->nLeftRect, memblt->nTopRect); - } + /* Increment usage counter */ + ((guac_rdp_bitmap*) bitmap)->used++; - } /* end if layer not NULL */ + } } From e659fca9228403117f95f38083103f11b846b272 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 10 Apr 2012 16:25:05 -0700 Subject: [PATCH 12/13] Only cache within memblt if not already cached. --- protocols/rdp/src/rdp_gdi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/protocols/rdp/src/rdp_gdi.c b/protocols/rdp/src/rdp_gdi.c index a287e101..66b3cde2 100644 --- a/protocols/rdp/src/rdp_gdi.c +++ b/protocols/rdp/src/rdp_gdi.c @@ -180,7 +180,8 @@ void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) { case 0xCC: /* If not cached, cache if necessary */ - if (((guac_rdp_bitmap*) bitmap)->used >= 1) + if (((guac_rdp_bitmap*) bitmap)->layer == NULL + && ((guac_rdp_bitmap*) bitmap)->used >= 1) guac_rdp_cache_bitmap(context, memblt->bitmap); /* If not cached, send as PNG */ From 79d388e0ecf8f6d2eb0e091eacf97bd1ed367f4b Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 10 Apr 2012 21:40:05 -0700 Subject: [PATCH 13/13] Fix boundary overflow. --- protocols/rdp/src/rdp_glyph.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/protocols/rdp/src/rdp_glyph.c b/protocols/rdp/src/rdp_glyph.c index 603a1048..951d8ecf 100644 --- a/protocols/rdp/src/rdp_glyph.c +++ b/protocols/rdp/src/rdp_glyph.c @@ -207,6 +207,14 @@ void guac_rdp_glyph_enddraw(rdpContext* context, cairo_surface_t* glyph_surface = guac_client_data->glyph_surface; int stride = cairo_image_surface_get_stride(glyph_surface); + /* Calculate bounds */ + int max_width = cairo_image_surface_get_width(glyph_surface) - x; + int max_height = cairo_image_surface_get_height(glyph_surface) - y; + + /* Ensure dimensions of glyph do not exceed bounds */ + if (width > max_width) width = max_width; + if (height > max_height) height = max_height; + /* Ensure data is ready */ cairo_surface_flush(glyph_surface);