GUACAMOLE-962: Restore OpaqueRect and PatBlt handlers.

This commit effectively reverts commit 9855d875c7.

With relaxed order checks enabled, FreeRDP will indeed invoke the
OpaqueRect and PatBlt handlers (even though we do not announce support
for those orders) as long as handlers are provided.
This commit is contained in:
Michael Jumper 2020-02-24 16:32:15 -08:00
parent 3b0abe376e
commit a80cd8db06
3 changed files with 136 additions and 0 deletions

View File

@ -18,6 +18,7 @@
*/
#include "bitmap.h"
#include "color.h"
#include "common/display.h"
#include "common/surface.h"
#include "rdp.h"
@ -139,6 +140,76 @@ BOOL guac_rdp_gdi_dstblt(rdpContext* context, const DSTBLT_ORDER* dstblt) {
}
BOOL guac_rdp_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) {
/*
* Note that this is not a full implementation of PATBLT. This is a
* fallback implementation which only renders a solid block of background
* color using the specified ROP3 operation, ignoring whatever brush
* was actually specified.
*
* As libguac-client-rdp explicitly tells the server not to send PATBLT,
* well-behaved RDP servers will not use this operation at all, while
* others will at least have a fallback.
*/
/* Get client and current layer */
guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_common_surface* current_surface =
((guac_rdp_client*) client->data)->current_surface;
int x = patblt->nLeftRect;
int y = patblt->nTopRect;
int w = patblt->nWidth;
int h = patblt->nHeight;
/*
* Warn that rendering is a fallback, as the server should not be sending
* this order.
*/
guac_client_log(client, GUAC_LOG_INFO, "Using fallback PATBLT (server is ignoring "
"negotiated client capabilities)");
/* Render rectangle based on ROP */
switch (patblt->bRop) {
/* If blackness, send black rectangle */
case 0x00:
guac_common_surface_set(current_surface, x, y, w, h,
0x00, 0x00, 0x00, 0xFF);
break;
/* If NOP, do nothing */
case 0xAA:
break;
/* If operation is just a copy, send foreground only */
case 0xCC:
case 0xF0:
guac_common_surface_set(current_surface, x, y, w, h,
(patblt->foreColor >> 16) & 0xFF,
(patblt->foreColor >> 8 ) & 0xFF,
(patblt->foreColor ) & 0xFF,
0xFF);
break;
/* If whiteness, send white rectangle */
case 0xFF:
guac_common_surface_set(current_surface, x, y, w, h,
0xFF, 0xFF, 0xFF, 0xFF);
break;
/* Otherwise, invert entire rect */
default:
guac_common_surface_transfer(current_surface, x, y, w, h,
GUAC_TRANSFER_BINARY_NDEST, current_surface, x, y);
}
return TRUE;
}
BOOL guac_rdp_gdi_scrblt(rdpContext* context, const SCRBLT_ORDER* scrblt) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
@ -256,6 +327,30 @@ BOOL guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) {
}
BOOL guac_rdp_gdi_opaquerect(rdpContext* context, const OPAQUE_RECT_ORDER* opaque_rect) {
/* Get client data */
guac_client* client = ((rdp_freerdp_context*) context)->client;
UINT32 color = guac_rdp_convert_color(context, opaque_rect->color);
guac_common_surface* current_surface = ((guac_rdp_client*) client->data)->current_surface;
int x = opaque_rect->nLeftRect;
int y = opaque_rect->nTopRect;
int w = opaque_rect->nWidth;
int h = opaque_rect->nHeight;
guac_common_surface_set(current_surface, x, y, w, h,
(color >> 16) & 0xFF,
(color >> 8 ) & 0xFF,
(color ) & 0xFF,
0xFF);
return TRUE;
}
BOOL guac_rdp_gdi_set_bounds(rdpContext* context, const rdpBounds* bounds) {
guac_client* client = ((rdp_freerdp_context*) context)->client;

View File

@ -62,6 +62,25 @@ guac_composite_mode guac_rdp_rop3_transfer_function(guac_client* client,
*/
BOOL guac_rdp_gdi_dstblt(rdpContext* context, const DSTBLT_ORDER* dstblt);
/**
* Handler for the PatBlt Primary Drawing Order. A PatBlt Primary Drawing Order
* paints a rectangle of image data, a brush pattern, and a three-way raster
* operation which considers the source data, the destination, AND the brush
* pattern. See:
*
* https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpegdi/bd4bf5e7-b988-45f9-8201-3b22cc9aeeb8
*
* @param context
* The rdpContext associated with the current RDP session.
*
* @param patblt
* The PATBLT update to handle.
*
* @return
* TRUE if successful, FALSE otherwise.
*/
BOOL guac_rdp_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt);
/**
* Handler for the ScrBlt Primary Drawing Order. A ScrBlt Primary Drawing Order
* paints a rectangle of image data using a raster operation which considers
@ -98,6 +117,26 @@ BOOL guac_rdp_gdi_scrblt(rdpContext* context, const SCRBLT_ORDER* scrblt);
*/
BOOL guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt);
/**
* Handler for the OpaqueRect Primary Drawing Order. An OpaqueRect Primary
* Drawing Order draws an opaque rectangle of a single solid color. Note that
* support for OpaqueRect cannot be claimed without also supporting PatBlt, as
* both use the same negotiation order number. See:
*
* https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpegdi/1eead7aa-ac63-411a-9f8c-b1b227526877
*
* @param context
* The rdpContext associated with the current RDP session.
*
* @param opaque_rect
* The OPAQUE RECT update to handle.
*
* @return
* TRUE if successful, FALSE otherwise.
*/
BOOL guac_rdp_gdi_opaquerect(rdpContext* context,
const OPAQUE_RECT_ORDER* opaque_rect);
/**
* Handler called prior to calling the handlers for specific updates when
* those updates are clipped by a bounding rectangle. This is not a true RDP

View File

@ -179,8 +179,10 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
rdpPrimaryUpdate* primary = instance->update->primary;
primary->DstBlt = guac_rdp_gdi_dstblt;
primary->PatBlt = guac_rdp_gdi_patblt;
primary->ScrBlt = guac_rdp_gdi_scrblt;
primary->MemBlt = guac_rdp_gdi_memblt;
primary->OpaqueRect = guac_rdp_gdi_opaquerect;
pointer_cache_register_callbacks(instance->update);
glyph_cache_register_callbacks(instance->update);