Implement deferred cache via memblt.
[libguac-client-rdp.git] / src / rdp_gdi.c
index 0b027a6..a287e10 100644 (file)
@@ -112,11 +112,14 @@ void guac_rdp_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt) {
         case 0:
 
             /* Send black rectangle */
-            guac_protocol_send_rect(client->socket,
-                    GUAC_COMP_OVER, current_layer,
+            guac_protocol_send_rect(client->socket, current_layer,
                     dstblt->nLeftRect, dstblt->nTopRect,
-                    dstblt->nWidth, dstblt->nHeight,
+                    dstblt->nWidth, dstblt->nHeight);
+
+            guac_protocol_send_cfill(client->socket,
+                    GUAC_COMP_OVER, current_layer,
                     0, 0, 0, 255);
+
             break;
 
         /* Unsupported ROP3 */
@@ -156,16 +159,16 @@ 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:
-            guac_protocol_send_rect(client->socket,
-                    GUAC_COMP_OVER, current_layer,
+            guac_protocol_send_rect(client->socket, current_layer,
                     memblt->nLeftRect, memblt->nTopRect,
-                    memblt->nWidth, memblt->nHeight,
+                    memblt->nWidth, memblt->nHeight);
+
+            guac_protocol_send_cfill(client->socket,
+                    GUAC_COMP_OVER, current_layer,
                     0x00, 0x00, 0x00, 0xFF);
             break;
 
@@ -175,25 +178,65 @@ 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 */
         case 0xFF:
-            guac_protocol_send_rect(client->socket,
-                    GUAC_COMP_OVER, current_layer,
+            guac_protocol_send_rect(client->socket, current_layer,
                     memblt->nLeftRect, memblt->nTopRect,
-                    memblt->nWidth, memblt->nHeight,
+                    memblt->nWidth, memblt->nHeight);
+
+            guac_protocol_send_cfill(client->socket,
+                    GUAC_COMP_OVER, current_layer,
                     0xFF, 0xFF, 0xFF, 0xFF);
             break;
 
         /* 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,
@@ -201,6 +244,9 @@ 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++;
+
     }
 
 }
@@ -214,10 +260,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,
@@ -238,24 +286,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);
 }