From 7ef1dcafbacc56e745b71aebee7246595424f603 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 31 Dec 2019 16:17:36 -0800 Subject: [PATCH] GUACAMOLE-249: Convert absolutely all rdpBitmaps before attempting to draw. --- src/protocols/rdp/bitmap.c | 53 ++++++++++++++++++++++++-------------- src/protocols/rdp/bitmap.h | 19 ++++++++++++++ src/protocols/rdp/gdi.c | 3 +++ 3 files changed, 55 insertions(+), 20 deletions(-) diff --git a/src/protocols/rdp/bitmap.c b/src/protocols/rdp/bitmap.c index f0c499ad..829280e0 100644 --- a/src/protocols/rdp/bitmap.c +++ b/src/protocols/rdp/bitmap.c @@ -37,6 +37,31 @@ #include #include +BOOL guac_rdp_bitmap_convert(rdpContext* context, rdpBitmap* bitmap) { + + /* No need to convert if there is no image data or the image data is + * already in the format used by libguac (the format used by Cairo) */ + if (bitmap->data == NULL || bitmap->format == PIXEL_FORMAT_BGRX32) + return TRUE; + + /* Allocate sufficient space for converted image */ + unsigned char* image_buffer = _aligned_malloc(bitmap->width * bitmap->height * 4, 16); + + /* Attempt image conversion, replacing existing image data if successful */ + if (freerdp_image_copy(image_buffer, PIXEL_FORMAT_BGRX32, 0, 0, 0, + bitmap->width, bitmap->height, bitmap->data, bitmap->format, + 0, 0, 0, &context->gdi->palette, FREERDP_FLIP_NONE)) { + _aligned_free(bitmap->data); + bitmap->data = image_buffer; + bitmap->format = PIXEL_FORMAT_BGRX32; + return TRUE; + } + + _aligned_free(image_buffer); + return FALSE; + +} + BOOL guac_rdp_cache_bitmap(rdpContext* context, rdpBitmap* bitmap) { guac_client* client = ((rdp_freerdp_context*) context)->client; @@ -49,6 +74,9 @@ BOOL guac_rdp_cache_bitmap(rdpContext* context, rdpBitmap* bitmap) { /* Cache image data if present */ if (bitmap->data != NULL) { + /* Convert image data to format used by libguac */ + guac_rdp_bitmap_convert(context, bitmap); + /* Create surface from image data */ cairo_surface_t* image = cairo_image_surface_create_for_data( bitmap->data, CAIRO_FORMAT_RGB24, @@ -71,26 +99,8 @@ BOOL guac_rdp_cache_bitmap(rdpContext* context, rdpBitmap* bitmap) { BOOL guac_rdp_bitmap_new(rdpContext* context, rdpBitmap* bitmap) { - /* Convert image data if present */ - if (bitmap->data != NULL && bitmap->format != PIXEL_FORMAT_BGRX32) { - - /* Allocate sufficient space for converted image */ - unsigned char* image_buffer = _aligned_malloc(bitmap->width * bitmap->height * 4, 16); - - /* Attempt image conversion */ - if (!freerdp_image_copy(image_buffer, PIXEL_FORMAT_BGRX32, 0, 0, 0, - bitmap->width, bitmap->height, bitmap->data, bitmap->format, - 0, 0, 0, &context->gdi->palette, FREERDP_FLIP_NONE)) { - _aligned_free(image_buffer); - } - - /* If successful, replace original image with converted image */ - else { - _aligned_free(bitmap->data); - bitmap->data = image_buffer; - } - - } + /* Convert image data to format used by libguac */ + guac_rdp_bitmap_convert(context, bitmap); /* No corresponding surface yet - caching is deferred. */ ((guac_rdp_bitmap*) bitmap)->layer = NULL; @@ -125,6 +135,9 @@ BOOL guac_rdp_bitmap_paint(rdpContext* context, rdpBitmap* bitmap) { /* Otherwise, draw with stored image data */ else if (bitmap->data != NULL) { + /* Convert image data to format used by libguac */ + guac_rdp_bitmap_convert(context, bitmap); + /* Create surface from image data */ cairo_surface_t* image = cairo_image_surface_create_for_data( bitmap->data, CAIRO_FORMAT_RGB24, diff --git a/src/protocols/rdp/bitmap.h b/src/protocols/rdp/bitmap.h index 70068b56..42108bc1 100644 --- a/src/protocols/rdp/bitmap.h +++ b/src/protocols/rdp/bitmap.h @@ -49,6 +49,25 @@ typedef struct guac_rdp_bitmap { } guac_rdp_bitmap; +/** + * Converts the image data within the given rdpBitmap to the pixel format used + * by libguac (Cairo) for 24-bit RGB images lacking an alpha channel. Any + * existing image data within the bitmap is freed and replaced with + * newly-allocated image data in the needed format, and the format field of the + * rdpBitmap is updated to match. + * + * @param context + * The rdpContext associated with the current RDP session. + * + * @param bitmap + * The rdpBitmap to convert. + * + * @return + * TRUE if image conversion was successful or there was no image data to + * convert, FALSE otherwise. + */ +BOOL guac_rdp_bitmap_convert(rdpContext* context, rdpBitmap* bitmap); + /** * Caches the given bitmap immediately, storing its data in a remote Guacamole * buffer. As RDP bitmaps are frequently created, used once, and immediately diff --git a/src/protocols/rdp/gdi.c b/src/protocols/rdp/gdi.c index 1961fdb5..69528dfb 100644 --- a/src/protocols/rdp/gdi.c +++ b/src/protocols/rdp/gdi.c @@ -274,6 +274,9 @@ BOOL guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) { if (bitmap->layer == NULL) { if (memblt->bitmap->data != NULL) { + /* Convert image data to format used by libguac */ + guac_rdp_bitmap_convert(context, memblt->bitmap); + /* Create surface from image data */ cairo_surface_t* surface = cairo_image_surface_create_for_data( memblt->bitmap->data + 4*(x_src + y_src*memblt->bitmap->width),