diff --git a/protocols/rdp/include/client.h b/protocols/rdp/include/client.h index abc9d6b0..78bbe2ad 100644 --- a/protocols/rdp/include/client.h +++ b/protocols/rdp/include/client.h @@ -118,6 +118,36 @@ typedef struct rdp_guac_client_data { */ const guac_layer* current_surface; + /** + * Whether graphical operations are restricted to a specific bounding + * rectangle. + */ + int bounded; + + /** + * The X coordinate of the upper-left corner of the bounding rectangle, + * if any. + */ + int bounds_left; + + /** + * The Y coordinate of the upper-left corner of the bounding rectangle, + * if any. + */ + int bounds_top; + + /** + * The X coordinate of the lower-right corner of the bounding rectangle, + * if any. + */ + int bounds_right; + + /** + * The Y coordinate of the lower-right corner of the bounding rectangle, + * if any. + */ + int bounds_bottom; + /** * The keymap to use when translating keysyms into scancodes or sequences * of scancodes for RDP. diff --git a/protocols/rdp/src/rdp_gdi.c b/protocols/rdp/src/rdp_gdi.c index 5672d448..7b8bdf33 100644 --- a/protocols/rdp/src/rdp_gdi.c +++ b/protocols/rdp/src/rdp_gdi.c @@ -44,6 +44,42 @@ #include "client.h" #include "rdp_bitmap.h" +static void __guac_rdp_clip_rect(rdp_guac_client_data* data, int* x, int* y, int* w, int* h) { + + if (data->bounded) { + + /* Get rect coordinates */ + int clipped_left = *x; + int clipped_top = *y; + int clipped_right = clipped_left + *w - 1; + int clipped_bottom = clipped_top + *h - 1; + + /* Clip left */ + if (clipped_left < data->bounds_left) clipped_left = data->bounds_left; + else if (clipped_left > data->bounds_left) clipped_left = data->bounds_left; + + /* Clip right */ + if (clipped_right < data->bounds_right) clipped_right = data->bounds_right; + else if (clipped_right > data->bounds_right) clipped_right = data->bounds_right; + + /* Clip top */ + if (clipped_top < data->bounds_top) clipped_top = data->bounds_top; + else if (clipped_top > data->bounds_top) clipped_top = data->bounds_top; + + /* Clip bottom */ + if (clipped_bottom < data->bounds_bottom) clipped_bottom = data->bounds_bottom; + else if (clipped_bottom > data->bounds_bottom) clipped_bottom = data->bounds_bottom; + + /* Store new rect dimensions */ + *x = clipped_left; + *y = clipped_right; + *w = clipped_right - clipped_left + 1; + *h = clipped_bottom - clipped_top + 1; + + } + +} + guac_transfer_function guac_rdp_rop3_transfer_function(guac_client* client, int rop3) { @@ -110,6 +146,9 @@ void guac_rdp_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt) { rdp_guac_client_data* data = (rdp_guac_client_data*) client->data; pthread_mutex_lock(&(data->update_lock)); + /* Clip operation to bounds */ + __guac_rdp_clip_rect(data, &(dstblt->nLeftRect), &(dstblt->nTopRect), &(dstblt->nWidth), &(dstblt->nHeight)); + switch (dstblt->bRop) { /* Blackness */ @@ -155,6 +194,8 @@ void guac_rdp_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) { const guac_layer* current_layer = ((rdp_guac_client_data*) client->data)->current_surface; + rdp_guac_client_data* data = (rdp_guac_client_data*) client->data; + /* Layer for actual transfer */ guac_layer* buffer; @@ -165,6 +206,9 @@ void guac_rdp_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) { guac_client_log_info(client, "Using fallback PATBLT (server is ignoring " "negotiated client capabilities)"); + /* Clip operation to bounds */ + __guac_rdp_clip_rect(data, &(patblt->nLeftRect), &(patblt->nTopRect), &(patblt->nWidth), &(patblt->nHeight)); + /* Render rectangle based on ROP */ switch (patblt->bRop) { @@ -250,6 +294,9 @@ void guac_rdp_gdi_scrblt(rdpContext* context, SCRBLT_ORDER* scrblt) { rdp_guac_client_data* data = (rdp_guac_client_data*) client->data; pthread_mutex_lock(&(data->update_lock)); + /* Clip operation to bounds */ + __guac_rdp_clip_rect(data, &(scrblt->nLeftRect), &(scrblt->nTopRect), &(scrblt->nWidth), &(scrblt->nHeight)); + /* Copy screen rect to current surface */ guac_protocol_send_copy(client->socket, GUAC_DEFAULT_LAYER, @@ -271,6 +318,9 @@ void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) { rdp_guac_client_data* data = (rdp_guac_client_data*) client->data; pthread_mutex_lock(&(data->update_lock)); + /* Clip operation to bounds */ + __guac_rdp_clip_rect(data, &(memblt->nLeftRect), &(memblt->nTopRect), &(memblt->nWidth), &(memblt->nHeight)); + switch (memblt->bRop) { /* If blackness, send black rectangle */ @@ -378,6 +428,10 @@ void guac_rdp_gdi_opaquerect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect rdp_guac_client_data* data = (rdp_guac_client_data*) client->data; pthread_mutex_lock(&(data->update_lock)); + /* Clip operation to bounds */ + __guac_rdp_clip_rect(data, &(opaque_rect->nLeftRect), &(opaque_rect->nTopRect), + &(opaque_rect->nWidth), &(opaque_rect->nHeight)); + guac_protocol_send_rect(client->socket, current_layer, opaque_rect->nLeftRect, opaque_rect->nTopRect, opaque_rect->nWidth, opaque_rect->nHeight); @@ -404,26 +458,21 @@ void guac_rdp_gdi_palette_update(rdpContext* context, PALETTE_UPDATE* palette) { void guac_rdp_gdi_set_bounds(rdpContext* context, rdpBounds* bounds) { guac_client* client = ((rdp_freerdp_context*) context)->client; - const guac_layer* current_layer = ((rdp_guac_client_data*) client->data)->current_surface; - rdp_guac_client_data* data = (rdp_guac_client_data*) client->data; - pthread_mutex_lock(&(data->update_lock)); - /* Reset clip */ - guac_protocol_send_reset(client->socket, current_layer); + /* If no bounds given, clear bounding rect */ + if (bounds == NULL) + data->bounded = false; - /* Set clip if specified */ - if (bounds != NULL) { - guac_protocol_send_rect(client->socket, current_layer, - bounds->left, bounds->top, - bounds->right - bounds->left + 1, - bounds->bottom - bounds->top + 1); - - guac_protocol_send_clip(client->socket, current_layer); + /* Otherwise, set bounding rectangle */ + else { + data->bounded = true; + data->bounds_left = bounds->left; + data->bounds_top = bounds->top; + data->bounds_right = bounds->right; + data->bounds_bottom = bounds->bottom; } - pthread_mutex_unlock(&(data->update_lock)); - } void guac_rdp_gdi_end_paint(rdpContext* context) {