Repository: incubator-guacamole-server
Updated Branches:
  refs/heads/master 075c77043 -> d831a4b9d


GUACAMOLE-188: Allow alpha component to be set within common surface.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/1a5f4896
Tree: 
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/1a5f4896
Diff: 
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/1a5f4896

Branch: refs/heads/master
Commit: 1a5f48961cd26c3d16a104d39bc8fe96e15ee24b
Parents: ea6b094
Author: Michael Jumper <[email protected]>
Authored: Mon Dec 19 21:13:20 2016 -0800
Committer: Michael Jumper <[email protected]>
Committed: Fri Jan 27 16:51:45 2017 -0800

----------------------------------------------------------------------
 src/common/common/surface.h   |  49 +++++++---
 src/common/surface.c          | 178 ++++++++++++++++++++++++++++++-------
 src/protocols/rdp/rdp_gdi.c   |  28 +++---
 src/protocols/rdp/rdp_glyph.c |  10 ++-
 src/terminal/display.c        |   5 +-
 5 files changed, 211 insertions(+), 59 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/1a5f4896/src/common/common/surface.h
----------------------------------------------------------------------
diff --git a/src/common/common/surface.h b/src/common/common/surface.h
index f92c068..964f8d3 100644
--- a/src/common/common/surface.h
+++ b/src/common/common/surface.h
@@ -336,20 +336,43 @@ void guac_common_surface_transfer(guac_common_surface* 
src, int sx, int sy, int
                                   guac_transfer_function op, 
guac_common_surface* dst, int dx, int dy);
 
 /**
- * Draws a solid color rectangle at the given coordinates on the given surface.
- *
- * @param surface The surface to draw upon.
- * @param x The X coordinate of the upper-left corner of the rectangle.
- * @param y The Y coordinate of the upper-left corner of the rectangle.
- * @param w The width of the rectangle.
- * @param h The height of the rectangle.
- * @param red The red component of the color of the rectangle.
- * @param green The green component of the color of the rectangle.
- * @param blue The blue component of the color of the rectangle.
+ * Assigns the given value to all pixels within a rectangle of the given
+ * surface. The color of all pixels within the rectangle, including the alpha
+ * component, is entirely replaced.
+ *
+ * @param surface
+ *     The surface to draw upon.
+ *
+ * @param x
+ *     The X coordinate of the upper-left corner of the rectangle.
+ *
+ * @param y
+ *     The Y coordinate of the upper-left corner of the rectangle.
+ *
+ * @param w
+ *     The width of the rectangle.
+ *
+ * @param h
+ *     The height of the rectangle.
+ *
+ * @param red
+ *     The red component of the color value to assign to all pixels within the
+ *     rectangle.
+ *
+ * @param green
+ *     The green component of the color value to assign to all pixels within
+ *     the rectangle.
+ *
+ * @param blue 
+ *     The blue component of the color value to assign to all pixels within the
+ *     rectangle.
+ *
+ * @param alpha 
+ *     The alpha component of the color value to assign to all pixels within
+ *     the rectangle.
  */
-void guac_common_surface_rect(guac_common_surface* surface,
-                              int x, int y, int w, int h,
-                              int red, int green, int blue);
+void guac_common_surface_set(guac_common_surface* surface, int x, int y,
+        int w, int h, int red, int green, int blue, int alpha);
 
 /**
  * Given the coordinates and dimensions of a rectangle, clips all future

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/1a5f4896/src/common/surface.c
----------------------------------------------------------------------
diff --git a/src/common/surface.c b/src/common/surface.c
index a4fd4c6..9aa60ca 100644
--- a/src/common/surface.c
+++ b/src/common/surface.c
@@ -225,6 +225,54 @@ static void __guac_common_clip_rect(guac_common_surface* 
surface,
 }
 
 /**
+ * Returns whether a rectangle within the given surface contains only fully
+ * opaque pixels.
+ *
+ * @param surface
+ *     The surface to check.
+ *
+ * @param rect
+ *     The rectangle to check.
+ *
+ * @return
+ *     Non-zero if the rectangle contains only fully opaque pixels, zero
+ *     otherwise.
+ */
+static int __guac_common_surface_is_opaque(guac_common_surface* surface,
+        guac_common_rect* rect) {
+
+    int x, y;
+
+    int stride = surface ->stride;
+    unsigned char* buffer =
+        surface->buffer + (stride * rect->y) + (4 * rect->x);
+
+    /* For each row */
+    for (y = 0; y < rect->height; y++) {
+
+        /* Search for a non-opaque pixel */
+        uint32_t* current = (uint32_t*) buffer;
+        for (x=0; x < rect->width; x++) {
+
+            /* Rectangle is non-opaque if a single non-opaque pixel is found */
+            uint32_t color = *(current++);
+            if ((color & 0xFF000000) != 0xFF000000)
+                return 0;
+
+        }
+
+        /* Next row */
+        buffer += stride;
+
+    }
+
+    /* Rectangle is opaque */
+    return 1;
+
+}
+
+
+/**
  * Returns whether the given rectangle should be combined into the existing
  * dirty rectangle, to be eventually flushed as a "png" instruction.
  *
@@ -730,24 +778,41 @@ static int 
__guac_common_surface_transfer_int(guac_transfer_function op, uint32_
 }
 
 /**
- * Draws a rectangle of solid color within the backing surface of the
- * given destination surface.
+ * Assigns the given value to all pixels within a rectangle of the backing
+ * surface of the given destination surface. The color of all pixels within the
+ * rectangle, including the alpha component, is entirely replaced.
  *
- * @param dst The destination surface.
- * @param rect The rectangle to draw.
- * @param red The red component of the color of the rectangle.
- * @param green The green component of the color of the rectangle.
- * @param blue The blue component of the color of the rectangle.
+ * @param dst
+ *     The destination surface.
+ *
+ * @param rect
+ *     The rectangle to draw.
+ *
+ * @param red
+ *     The red component of the color value to assign to all pixels within the
+ *     rectangle.
+ *
+ * @param green
+ *     The green component of the color value to assign to all pixels within
+ *     the rectangle.
+ *
+ * @param blue 
+ *     The blue component of the color value to assign to all pixels within the
+ *     rectangle.
+ *
+ * @param alpha 
+ *     The alpha component of the color value to assign to all pixels within
+ *     the rectangle.
  */
-static void __guac_common_surface_rect(guac_common_surface* dst, 
guac_common_rect* rect,
-                                       int red, int green, int blue) {
+static void __guac_common_surface_set(guac_common_surface* dst,
+        guac_common_rect* rect, int red, int green, int blue, int alpha) {
 
     int x, y;
 
     int dst_stride;
     unsigned char* dst_buffer;
 
-    uint32_t color = 0xFF000000 | (red << 16) | (green << 8) | blue;
+    uint32_t color = (alpha << 24) | (red << 16) | (green << 8) | blue;
 
     int min_x = rect->width - 1;
     int min_y = rect->height - 1;
@@ -1063,7 +1128,7 @@ guac_common_surface* 
guac_common_surface_alloc(guac_client* client,
     pthread_mutex_init(&surface->_lock, NULL);
 
     /* Create corresponding Cairo surface */
-    surface->stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, w);
+    surface->stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, w);
     surface->buffer = calloc(h, surface->stride);
 
     /* Create corresponding heat map */
@@ -1126,7 +1191,7 @@ void guac_common_surface_resize(guac_common_surface* 
surface, int w, int h) {
     /* Re-initialize at new size */
     surface->width  = w;
     surface->height = h;
-    surface->stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, w);
+    surface->stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, w);
     surface->buffer = calloc(h, surface->stride);
     __guac_common_bound_rect(surface, &surface->clip_rect, NULL, NULL);
 
@@ -1368,8 +1433,8 @@ complete:
 
 }
 
-void guac_common_surface_rect(guac_common_surface* surface,
-        int x, int y, int w, int h, int red, int green, int blue) {
+void guac_common_surface_set(guac_common_surface* surface,
+        int x, int y, int w, int h, int red, int green, int blue, int alpha) {
 
     pthread_mutex_lock(&surface->_lock);
 
@@ -1385,19 +1450,31 @@ void guac_common_surface_rect(guac_common_surface* 
surface,
         goto complete;
 
     /* Update backing surface */
-    __guac_common_surface_rect(surface, &rect, red, green, blue);
+    __guac_common_surface_set(surface, &rect, red, green, blue, alpha);
     if (rect.width <= 0 || rect.height <= 0)
         goto complete;
 
+    /* Handle as normal draw if non-opaque */
+    if (alpha != 0xFF) {
+
+        /* Flush if not combining */
+        if (!__guac_common_should_combine(surface, &rect, 0))
+            __guac_common_surface_flush_deferred(surface);
+
+        /* Always defer draws */
+        __guac_common_mark_dirty(surface, &rect);
+
+    }
+
     /* Defer if combining */
-    if (__guac_common_should_combine(surface, &rect, 1))
+    else if (__guac_common_should_combine(surface, &rect, 1))
         __guac_common_mark_dirty(surface, &rect);
 
     /* Otherwise, flush and draw immediately */
     else {
         __guac_common_surface_flush(surface);
         guac_protocol_send_rect(socket, layer, rect.x, rect.y, rect.width, 
rect.height);
-        guac_protocol_send_cfill(socket, GUAC_COMP_OVER, layer, red, green, 
blue, 0xFF);
+        guac_protocol_send_cfill(socket, GUAC_COMP_OVER, layer, red, green, 
blue, alpha);
         surface->realized = 1;
     }
 
@@ -1439,8 +1516,12 @@ void guac_common_surface_reset_clip(guac_common_surface* 
surface) {
  *
  * @param surface
  *     The surface to flush.
+ *
+ * @param opaque
+ *     Whether the rectangle being flushed contains only fully-opaque pixels.
  */
-static void __guac_common_surface_flush_to_png(guac_common_surface* surface) {
+static void __guac_common_surface_flush_to_png(guac_common_surface* surface,
+        int opaque) {
 
     if (surface->dirty) {
 
@@ -1452,9 +1533,29 @@ static void 
__guac_common_surface_flush_to_png(guac_common_surface* surface) {
                               + surface->dirty_rect.y * surface->stride
                               + surface->dirty_rect.x * 4;
 
-        cairo_surface_t* rect = cairo_image_surface_create_for_data(buffer,
-                CAIRO_FORMAT_RGB24, surface->dirty_rect.width,
-                surface->dirty_rect.height, surface->stride);
+        cairo_surface_t* rect;
+
+        /* Use RGB24 if the image is fully opaque */
+        if (opaque)
+            rect = cairo_image_surface_create_for_data(buffer,
+                    CAIRO_FORMAT_RGB24, surface->dirty_rect.width,
+                    surface->dirty_rect.height, surface->stride);
+
+        /* Otherwise ARGB32 is needed */
+        else {
+
+            rect = cairo_image_surface_create_for_data(buffer,
+                    CAIRO_FORMAT_ARGB32, surface->dirty_rect.width,
+                    surface->dirty_rect.height, surface->stride);
+
+            /* Clear destination rect first */
+            guac_protocol_send_rect(socket, layer,
+                    surface->dirty_rect.x, surface->dirty_rect.y,
+                    surface->dirty_rect.width, surface->dirty_rect.height);
+            guac_protocol_send_cfill(socket, GUAC_COMP_ROUT, layer,
+                    0x00, 0x00, 0x00, 0xFF);
+
+        }
 
         /* Send PNG for rect */
         guac_client_stream_png(surface->client, socket, GUAC_COMP_OVER,
@@ -1526,8 +1627,12 @@ static void 
__guac_common_surface_flush_to_jpeg(guac_common_surface* surface) {
  *
  * @param surface
  *     The surface to flush.
+ *
+ * @param opaque
+ *     Whether the rectangle being flushed contains only fully-opaque pixels.
  */
-static void __guac_common_surface_flush_to_webp(guac_common_surface* surface) {
+static void __guac_common_surface_flush_to_webp(guac_common_surface* surface,
+        int opaque) {
 
     if (surface->dirty) {
 
@@ -1547,9 +1652,19 @@ static void 
__guac_common_surface_flush_to_webp(guac_common_surface* surface) {
                               + surface->dirty_rect.y * surface->stride
                               + surface->dirty_rect.x * 4;
 
-        cairo_surface_t* rect = cairo_image_surface_create_for_data(buffer,
-                CAIRO_FORMAT_RGB24, surface->dirty_rect.width,
-                surface->dirty_rect.height, surface->stride);
+        cairo_surface_t* rect;
+
+        /* Use RGB24 if the image is fully opaque */
+        if (opaque)
+            rect = cairo_image_surface_create_for_data(buffer,
+                    CAIRO_FORMAT_RGB24, surface->dirty_rect.width,
+                    surface->dirty_rect.height, surface->stride);
+
+        /* Otherwise ARGB32 is needed */
+        else
+            rect = cairo_image_surface_create_for_data(buffer,
+                    CAIRO_FORMAT_ARGB32, surface->dirty_rect.width,
+                    surface->dirty_rect.height, surface->stride);
 
         /* Send WebP for rect */
         guac_client_stream_webp(surface->client, socket, GUAC_COMP_OVER, layer,
@@ -1679,19 +1794,22 @@ static void 
__guac_common_surface_flush(guac_common_surface* surface) {
 
                 flushed++;
 
+                int opaque = __guac_common_surface_is_opaque(surface,
+                            &surface->dirty_rect);
+
                 /* Prefer WebP when reasonable */
                 if (__guac_common_surface_should_use_webp(surface,
                             &surface->dirty_rect))
-                    __guac_common_surface_flush_to_webp(surface);
+                    __guac_common_surface_flush_to_webp(surface, opaque);
 
                 /* If not WebP, JPEG is the next best (lossy) choice */
-                else if (__guac_common_surface_should_use_jpeg(surface,
-                            &surface->dirty_rect))
+                else if (opaque && __guac_common_surface_should_use_jpeg(
+                            surface, &surface->dirty_rect))
                     __guac_common_surface_flush_to_jpeg(surface);
 
                 /* Use PNG if no lossy formats are appropriate */
                 else
-                    __guac_common_surface_flush_to_png(surface);
+                    __guac_common_surface_flush_to_png(surface, opaque);
 
             }
 
@@ -1750,7 +1868,7 @@ void guac_common_surface_dup(guac_common_surface* 
surface, guac_user* user,
 
         /* Get entire surface */
         cairo_surface_t* rect = cairo_image_surface_create_for_data(
-                surface->buffer, CAIRO_FORMAT_RGB24,
+                surface->buffer, CAIRO_FORMAT_ARGB32,
                 surface->width, surface->height, surface->stride);
 
         /* Send PNG for rect */

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/1a5f4896/src/protocols/rdp/rdp_gdi.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/rdp_gdi.c b/src/protocols/rdp/rdp_gdi.c
index 1805319..59fe64c 100644
--- a/src/protocols/rdp/rdp_gdi.c
+++ b/src/protocols/rdp/rdp_gdi.c
@@ -113,7 +113,8 @@ void guac_rdp_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* 
dstblt) {
         case 0:
 
             /* Send black rectangle */
-            guac_common_surface_rect(current_surface, x, y, w, h, 0, 0, 0);
+            guac_common_surface_set(current_surface, x, y, w, h,
+                    0x00, 0x00, 0x00, 0xFF);
             break;
 
         /* DSTINVERT */
@@ -128,7 +129,8 @@ void guac_rdp_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* 
dstblt) {
 
         /* Whiteness */
         case 0xFF:
-            guac_common_surface_rect(current_surface, x, y, w, h, 0xFF, 0xFF, 
0xFF);
+            guac_common_surface_set(current_surface, x, y, w, h,
+                    0xFF, 0xFF, 0xFF, 0xFF);
             break;
 
         /* Unsupported ROP3 */
@@ -175,7 +177,8 @@ void guac_rdp_gdi_patblt(rdpContext* context, PATBLT_ORDER* 
patblt) {
 
         /* If blackness, send black rectangle */
         case 0x00:
-            guac_common_surface_rect(current_surface, x, y, w, h, 0, 0, 0);
+            guac_common_surface_set(current_surface, x, y, w, h,
+                    0x00, 0x00, 0x00, 0xFF);
             break;
 
         /* If NOP, do nothing */
@@ -185,15 +188,17 @@ void guac_rdp_gdi_patblt(rdpContext* context, 
PATBLT_ORDER* patblt) {
         /* If operation is just a copy, send foreground only */
         case 0xCC:
         case 0xF0:
-            guac_common_surface_rect(current_surface, x, y, w, h,
+            guac_common_surface_set(current_surface, x, y, w, h,
                     (patblt->foreColor >> 16) & 0xFF,
                     (patblt->foreColor >> 8 ) & 0xFF,
-                    (patblt->foreColor      ) & 0xFF);
+                    (patblt->foreColor      ) & 0xFF,
+                    0xFF);
             break;
 
         /* If whiteness, send white rectangle */
         case 0xFF:
-            guac_common_surface_rect(current_surface, x, y, w, h, 0xFF, 0xFF, 
0xFF);
+            guac_common_surface_set(current_surface, x, y, w, h,
+                    0xFF, 0xFF, 0xFF, 0xFF);
             break;
 
         /* Otherwise, invert entire rect */
@@ -250,7 +255,8 @@ void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* 
memblt) {
 
         /* If blackness, send black rectangle */
         case 0x00:
-            guac_common_surface_rect(current_surface, x, y, w, h, 0, 0, 0);
+            guac_common_surface_set(current_surface, x, y, w, h,
+                    0x00, 0x00, 0x00, 0xFF);
             break;
 
         /* If NOP, do nothing */
@@ -294,7 +300,8 @@ void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* 
memblt) {
 
         /* If whiteness, send white rectangle */
         case 0xFF:
-            guac_common_surface_rect(current_surface, x, y, w, h, 0xFF, 0xFF, 
0xFF);
+            guac_common_surface_set(current_surface, x, y, w, h,
+                    0xFF, 0xFF, 0xFF, 0xFF);
             break;
 
         /* Otherwise, use transfer */
@@ -330,10 +337,11 @@ void guac_rdp_gdi_opaquerect(rdpContext* context, 
OPAQUE_RECT_ORDER* opaque_rect
     int w = opaque_rect->nWidth;
     int h = opaque_rect->nHeight;
 
-    guac_common_surface_rect(current_surface, x, y, w, h,
+    guac_common_surface_set(current_surface, x, y, w, h,
             (color >> 16) & 0xFF,
             (color >> 8 ) & 0xFF,
-            (color      ) & 0xFF);
+            (color      ) & 0xFF,
+            0xFF);
 
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/1a5f4896/src/protocols/rdp/rdp_glyph.c
----------------------------------------------------------------------
diff --git a/src/protocols/rdp/rdp_glyph.c b/src/protocols/rdp/rdp_glyph.c
index 68ce7a2..8ba1087 100644
--- a/src/protocols/rdp/rdp_glyph.c
+++ b/src/protocols/rdp/rdp_glyph.c
@@ -136,10 +136,12 @@ void guac_rdp_glyph_begindraw(rdpContext* context,
         /* Convert background color */
         bgcolor = guac_rdp_convert_color(context, bgcolor);
 
-        guac_common_surface_rect(rdp_client->current_surface, x, y, width, 
height,
-                                 (bgcolor & 0xFF0000) >> 16,
-                                 (bgcolor & 0x00FF00) >> 8,
-                                  bgcolor & 0x0000FF);
+        guac_common_surface_set(rdp_client->current_surface,
+                x, y, width, height,
+                (bgcolor & 0xFF0000) >> 16,
+                (bgcolor & 0x00FF00) >> 8,
+                (bgcolor & 0x0000FF),
+                0xFF);
 
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/1a5f4896/src/terminal/display.c
----------------------------------------------------------------------
diff --git a/src/terminal/display.c b/src/terminal/display.c
index da1a8d9..295bdb5 100644
--- a/src/terminal/display.c
+++ b/src/terminal/display.c
@@ -773,13 +773,14 @@ void 
__guac_terminal_display_flush_clear(guac_terminal_display* display) {
                 }
 
                 /* Send rect */
-                guac_common_surface_rect(
+                guac_common_surface_set(
                         display->display_surface,
                         col * display->char_width,
                         row * display->char_height,
                         rect_width * display->char_width,
                         rect_height * display->char_height,
-                        guac_color->red, guac_color->green, guac_color->blue);
+                        guac_color->red, guac_color->green, guac_color->blue,
+                        0xFF);
 
             } /* end if clear operation */
 

Reply via email to