Implement EndPaint.
[libguac-client-rdp.git] / src / rdp_gdi.c
old mode 100755 (executable)
new mode 100644 (file)
index 30b4db2..7153f4b
@@ -20,6 +20,7 @@
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
+ * Matt Hortman
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
 #include "client.h"
 #include "rdp_bitmap.h"
 
+guac_transfer_function guac_rdp_rop3_transfer_function(guac_client* client,
+        int rop3) {
+
+    /* Translate supported ROP3 opcodes into composite modes */
+    switch (rop3) {
+
+        /* "DSon" !(src | dest) */
+        case 0x11: return GUAC_TRANSFER_BINARY_NOR;
+
+        /* "DSna" !src & dest */
+        case 0x22: return GUAC_TRANSFER_BINARY_NSRC_AND;
+
+        /* "Sn" !src */
+        case 0x33: return GUAC_TRANSFER_BINARY_NSRC;
+
+        /* "SDna" (src & !dest) */
+        case 0x44: return GUAC_TRANSFER_BINARY_NDEST_AND;
+
+        /* "Dn" !dest */
+        case 0x55: return GUAC_TRANSFER_BINARY_NDEST;
+
+        /* "SRCINVERT" (src ^ dest) */
+        case 0x66: return GUAC_TRANSFER_BINARY_XOR;
+
+        /* "DSan" !(src & dest) */
+        case 0x77: return GUAC_TRANSFER_BINARY_NAND;
+
+        /* "SRCAND" (src & dest) */
+        case 0x88: return GUAC_TRANSFER_BINARY_AND;
+
+        /* "DSxn" !(src ^ dest) */
+        case 0x99: return GUAC_TRANSFER_BINARY_XNOR;
+
+        /* "MERGEPAINT" (!src | dest)*/
+        case 0xBB: return GUAC_TRANSFER_BINARY_NSRC_OR;
+
+        /* "SDno" (src | !dest) */
+        case 0xDD: return GUAC_TRANSFER_BINARY_NDEST_OR;
+
+        /* "SRCPAINT" (src | dest) */
+        case 0xEE: return GUAC_TRANSFER_BINARY_OR;
+
+        /* 0x00 = "BLACKNESS" (0) */
+        /* 0xAA = "NOP" (dest) */
+        /* 0xCC = "SRCCOPY" (src) */
+        /* 0xFF = "WHITENESS" (1) */
+
+    }
+
+    /* Log warning if ROP3 opcode not supported */
+    guac_client_log_info (client, "guac_rdp_rop3_transfer_function: "
+            "UNSUPPORTED opcode = 0x%02X", rop3);
+
+    /* Default to BINARY_SRC */
+    return GUAC_TRANSFER_BINARY_SRC;
+
+}
+
 void guac_rdp_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt) {
+
     guac_client* client = ((rdp_freerdp_context*) context)->client;
-    guac_client_log_info(client, "guac_rdp_gdi_dstblt()");
+    const guac_layer* current_layer = ((rdp_guac_client_data*) client->data)->current_surface;
+
+    switch (dstblt->bRop) {
+
+        /* Blackness */
+        case 0:
+
+            /* Send black rectangle */
+            guac_protocol_send_rect(client->socket, current_layer,
+                    dstblt->nLeftRect, dstblt->nTopRect,
+                    dstblt->nWidth, dstblt->nHeight);
+
+            guac_protocol_send_cfill(client->socket,
+                    GUAC_COMP_OVER, current_layer,
+                    0, 0, 0, 255);
+
+            break;
+
+        /* Unsupported ROP3 */
+        default:
+            guac_client_log_info(client,
+                    "guac_rdp_gdi_dstblt(rop3=%i)", dstblt->bRop);
+
+    }
+
+
+
 }
 
 void guac_rdp_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) {
@@ -73,12 +159,58 @@ 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)
-        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 (bitmap->layer != NULL) {
+
+        switch (memblt->bRop) {
+
+        /* If blackness, send black rectangle */
+        case 0x00:
+            guac_protocol_send_rect(client->socket, current_layer,
+                    memblt->nLeftRect, memblt->nTopRect,
+                    memblt->nWidth, memblt->nHeight);
+
+            guac_protocol_send_cfill(client->socket,
+                    GUAC_COMP_OVER, current_layer,
+                    0x00, 0x00, 0x00, 0xFF);
+            break;
+
+        /* If NOP, do nothing */
+        case 0xAA:
+            break;
+
+        /* 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);
+            break;
+
+        /* If whiteness, send white rectangle */
+        case 0xFF:
+            guac_protocol_send_rect(client->socket, current_layer,
+                    memblt->nLeftRect, memblt->nTopRect,
+                    memblt->nWidth, memblt->nHeight);
+
+            guac_protocol_send_cfill(client->socket,
+                    GUAC_COMP_OVER, current_layer,
+                    0xFF, 0xFF, 0xFF, 0xFF);
+            break;
+
+        /* Otherwise, use transfer */
+        default:
+            guac_protocol_send_transfer(socket,
+                    bitmap->layer,
+                    memblt->nXSrc, memblt->nYSrc,
+                    memblt->nWidth, memblt->nHeight,
+                    guac_rdp_rop3_transfer_function(client, memblt->bRop),
+                    current_layer, memblt->nLeftRect, memblt->nTopRect);
+
+        }
+
+    } /* end if layer not NULL */
 
 }
 
@@ -91,10 +223,12 @@ void guac_rdp_gdi_opaquerect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect
 
     const guac_layer* current_layer = ((rdp_guac_client_data*) client->data)->current_surface;
 
-    guac_protocol_send_rect(client->socket,
-            GUAC_COMP_OVER, current_layer,
+    guac_protocol_send_rect(client->socket, current_layer,
             opaque_rect->nLeftRect, opaque_rect->nTopRect,
-            opaque_rect->nWidth, opaque_rect->nHeight,
+            opaque_rect->nWidth, opaque_rect->nHeight);
+
+    guac_protocol_send_cfill(client->socket,
+            GUAC_COMP_OVER, current_layer,
             (color >> 16) & 0xFF,
             (color >> 8 ) & 0xFF,
             (color      ) & 0xFF,
@@ -115,24 +249,23 @@ 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;
 
+    /* Reset clip */
+    guac_protocol_send_reset(client->socket, current_layer);
+
     /* Set clip if specified */
-    if (bounds != NULL)
-        guac_protocol_send_clip(
-                client->socket,
-                current_layer,
-                bounds->left,
-                bounds->top,
+    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);
 
-    /* Otherwise, reset clip */
-    else
-        guac_protocol_send_clip(
-                client->socket,
-                current_layer,
-                0, 0,
-                context->instance->settings->width,
-                context->instance->settings->height);
+        guac_protocol_send_clip(client->socket, current_layer);
+    }
 
 }
 
+void guac_rdp_gdi_end_paint(rdpContext* context) {
+    guac_client* client = ((rdp_freerdp_context*) context)->client;
+    guac_socket_flush(client->socket);
+}
+