From ba9c1a2efd4f05d1815ec5e91dcfd0fdefeb5635 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 28 Feb 2016 01:36:50 -0800 Subject: [PATCH] GUAC-236: Ensure buffers are resized to fit draw operations (unless they are within layers). --- src/guacenc/buffer.c | 22 ++++++++++++++++++++++ src/guacenc/buffer.h | 29 +++++++++++++++++++++++++++++ src/guacenc/image-stream.c | 15 ++++++++------- src/guacenc/instruction-copy.c | 4 ++++ src/guacenc/instruction-rect.c | 4 ++++ 5 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/guacenc/buffer.c b/src/guacenc/buffer.c index 716a0411..22de51e0 100644 --- a/src/guacenc/buffer.c +++ b/src/guacenc/buffer.c @@ -25,6 +25,7 @@ #include +#include #include guacenc_buffer* guacenc_buffer_alloc() { @@ -115,3 +116,24 @@ int guacenc_buffer_resize(guacenc_buffer* buffer, int width, int height) { } +int guacenc_buffer_fit(guacenc_buffer* buffer, int x, int y) { + + /* Increase width to fit X (if necessary) */ + int new_width = buffer->width; + if (new_width < x+1) + new_width = x+1; + + /* Increase height to fit Y (if necessary) */ + int new_height = buffer->height; + if (new_height < y+1) + new_height = y+1; + + /* Resize buffer if size needs to change to fit X/Y coordinate */ + if (new_width != buffer->width || new_height != buffer->height) + return guacenc_buffer_resize(buffer, new_width, new_height); + + /* No change necessary */ + return 0; + +} + diff --git a/src/guacenc/buffer.h b/src/guacenc/buffer.h index d2d7f152..1cb0c7ae 100644 --- a/src/guacenc/buffer.h +++ b/src/guacenc/buffer.h @@ -27,12 +27,20 @@ #include +#include + /** * The image and size storage for either a buffer (a Guacamole layer with a * negative index) or a layer (a Guacamole layer with a non-negative index). */ typedef struct guacenc_buffer { + /** + * Whether this buffer should be automatically resized to fit any draw + * operation. + */ + bool autosize; + /** * The width of this buffer or layer, in pixels. */ @@ -107,5 +115,26 @@ void guacenc_buffer_free(guacenc_buffer* buffer); */ int guacenc_buffer_resize(guacenc_buffer* buffer, int width, int height); +/** + * Resizes the given buffer as necessary to contain at the given X/Y + * coordinate, allocating or freeing memory as necessary, and updating the + * buffer's width, height, and stride properties. If the buffer already + * contains the given coordinate, this function has no effect. + * + * @param buffer + * The buffer to resize. + * + * @param x + * The X coordinate to ensure is within the buffer. + * + * @param y + * The Y coordinate to ensure is within the buffer. + * + * @return + * Zero if the resize operation is successful or no resize was performed, + * non-zero if the resize operation failed. + */ +int guacenc_buffer_fit(guacenc_buffer* buffer, int x, int y); + #endif diff --git a/src/guacenc/image-stream.c b/src/guacenc/image-stream.c index b59ec71e..81ec4d21 100644 --- a/src/guacenc/image-stream.c +++ b/src/guacenc/image-stream.c @@ -132,18 +132,19 @@ int guacenc_image_stream_end(guacenc_image_stream* stream, if (surface == NULL) return 1; + /* Get surface dimensions */ + int width = cairo_image_surface_get_width(surface); + int height = cairo_image_surface_get_height(surface); + + /* Expand the buffer as necessary to fit the draw operation */ + if (buffer->autosize) + guacenc_buffer_fit(buffer, stream->x + width, stream->y + height); + /* Draw surface to buffer */ if (buffer->cairo != NULL) { - - /* Get surface dimensions */ - int width = cairo_image_surface_get_width(surface); - int height = cairo_image_surface_get_height(surface); - - /* Paint surface contents to buffer */ cairo_set_source_surface(buffer->cairo, surface, stream->x, stream->y); cairo_rectangle(buffer->cairo, stream->x, stream->y, width, height); cairo_fill(buffer->cairo); - } cairo_surface_destroy(surface); diff --git a/src/guacenc/instruction-copy.c b/src/guacenc/instruction-copy.c index b79fdd08..63b15700 100644 --- a/src/guacenc/instruction-copy.c +++ b/src/guacenc/instruction-copy.c @@ -57,6 +57,10 @@ int guacenc_handle_copy(guacenc_display* display, int argc, char** argv) { if (dst == NULL) return 1; + /* Expand the destination buffer as necessary to fit the draw operation */ + if (dst->autosize) + guacenc_buffer_fit(dst, dx + width, dy + height); + /* Copy rectangle from source to destination */ if (src->surface != NULL && dst->cairo != NULL) { cairo_set_operator(dst->cairo, guacenc_display_cairo_operator(mask)); diff --git a/src/guacenc/instruction-rect.c b/src/guacenc/instruction-rect.c index 94fea8f3..6617ecb0 100644 --- a/src/guacenc/instruction-rect.c +++ b/src/guacenc/instruction-rect.c @@ -50,6 +50,10 @@ int guacenc_handle_rect(guacenc_display* display, int argc, char** argv) { if (buffer == NULL) return 1; + /* Expand the buffer as necessary to fit the draw operation */ + if (buffer->autosize) + guacenc_buffer_fit(buffer, x + width, y + height); + /* Set path to rectangle */ if (buffer->cairo != NULL) cairo_rectangle(buffer->cairo, x, y, width, height);