diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 947104aeb..c2be3f59d 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -31,36 +31,20 @@ SUBDIRS = . tests noinst_HEADERS = \ common/io.h \ - common/blank_cursor.h \ common/clipboard.h \ - common/cursor.h \ common/defaults.h \ - common/display.h \ - common/dot_cursor.h \ - common/ibar_cursor.h \ common/iconv.h \ common/json.h \ common/list.h \ - common/pointer_cursor.h \ - common/rect.h \ - common/string.h \ - common/surface.h + common/string.h libguac_common_la_SOURCES = \ io.c \ - blank_cursor.c \ clipboard.c \ - cursor.c \ - display.c \ - dot_cursor.c \ - ibar_cursor.c \ iconv.c \ json.c \ list.c \ - pointer_cursor.c \ - rect.c \ - string.c \ - surface.c + string.c libguac_common_la_CFLAGS = \ -Werror -Wall -pedantic \ diff --git a/src/common/blank_cursor.c b/src/common/blank_cursor.c deleted file mode 100644 index c65db0cbf..000000000 --- a/src/common/blank_cursor.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -/* Dimensions */ -const int guac_common_blank_cursor_width = 1; -const int guac_common_blank_cursor_height = 1; - -/* Format */ -const cairo_format_t guac_common_blank_cursor_format = CAIRO_FORMAT_ARGB32; -const int guac_common_blank_cursor_stride = 4; - -/* Embedded blank cursor graphic */ -unsigned char guac_common_blank_cursor[] = { - - 0x00,0x00,0x00,0x00 - -}; - -void guac_common_set_blank_cursor(guac_user* user) { - - guac_client* client = user->client; - guac_socket* socket = user->socket; - - /* Draw to buffer */ - guac_layer* cursor = guac_client_alloc_buffer(client); - - cairo_surface_t* graphic = cairo_image_surface_create_for_data( - guac_common_blank_cursor, - guac_common_blank_cursor_format, - guac_common_blank_cursor_width, - guac_common_blank_cursor_height, - guac_common_blank_cursor_stride); - - guac_user_stream_png(user, socket, GUAC_COMP_SRC, cursor, - 0, 0, graphic); - cairo_surface_destroy(graphic); - - /* Set cursor */ - guac_protocol_send_cursor(socket, 0, 0, cursor, 0, 0, - guac_common_blank_cursor_width, - guac_common_blank_cursor_height); - - /* Free buffer */ - guac_client_free_buffer(client, cursor); - - guac_client_log(client, GUAC_LOG_DEBUG, - "Client cursor image set to generic transparent (blank) cursor."); - -} - diff --git a/src/common/common/blank_cursor.h b/src/common/common/blank_cursor.h deleted file mode 100644 index 86a4a9ff2..000000000 --- a/src/common/common/blank_cursor.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef GUAC_COMMON_BLANK_CURSOR_H -#define GUAC_COMMON_BLANK_CURSOR_H - -#include "config.h" - -#include -#include - -/** - * Width of the embedded transparent (blank) mouse cursor graphic. - */ -extern const int guac_common_blank_cursor_width; - -/** - * Height of the embedded transparent (blank) mouse cursor graphic. - */ -extern const int guac_common_blank_cursor_height; - -/** - * Number of bytes in each row of the embedded transparent (blank) mouse cursor - * graphic. - */ -extern const int guac_common_blank_cursor_stride; - -/** - * The Cairo grapic format of the transparent (blank) mouse cursor graphic. - */ -extern const cairo_format_t guac_common_blank_cursor_format; - -/** - * Embedded transparent (blank) mouse cursor graphic. - */ -extern unsigned char guac_common_blank_cursor[]; - -/** - * Sets the cursor of the remote display to the embedded transparent (blank) - * cursor graphic. - * - * @param user - * The guac_user to send the cursor to. - */ -void guac_common_set_blank_cursor(guac_user* user); - -#endif - diff --git a/src/common/common/cursor.h b/src/common/common/cursor.h deleted file mode 100644 index 96c1c6f23..000000000 --- a/src/common/common/cursor.h +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef GUAC_COMMON_CURSOR_H -#define GUAC_COMMON_CURSOR_H - -#include "surface.h" - -#include -#include -#include -#include - -/** - * The default size of the cursor image buffer. - */ -#define GUAC_COMMON_CURSOR_DEFAULT_SIZE 64*64*4 - -/** - * Cursor object which maintains and synchronizes the current mouse cursor - * state across all users of a specific client. - */ -typedef struct guac_common_cursor { - - /** - * The client to maintain the mouse cursor for. - */ - guac_client* client; - - /** - * The buffer containing the current cursor image. - */ - guac_layer* buffer; - - /** - * The width of the cursor image, in pixels. - */ - int width; - - /** - * The height of the cursor image, in pixels. - */ - int height; - - /** - * Arbitrary image data buffer, backing the Cairo surface used to store - * the cursor image. - */ - unsigned char* image_buffer; - - /** - * The size of the image data buffer, in bytes. - */ - size_t image_buffer_size; - - /** - * The current cursor image, if any. If the mouse cursor has not yet been - * set, this will be NULL. - */ - cairo_surface_t* surface; - - /** - * The X coordinate of the hotspot of the mouse cursor. - */ - int hotspot_x; - - /** - * The Y coordinate of the hotspot of the mouse cursor. - */ - int hotspot_y; - - /** - * The last user to move the mouse, or NULL if no user has moved the - * mouse yet. - */ - guac_user* user; - - /** - * The X coordinate of the current mouse cursor location. - */ - int x; - - /** - * The Y coordinate of the current mouse cursor location. - */ - int y; - - /** - * An integer value representing the current state of each button, where - * the Nth bit within the integer is set to 1 if and only if the Nth mouse - * button is currently pressed. The lowest-order bit is the left mouse - * button, followed by the middle button, right button, and finally the up - * and down buttons of the scroll wheel. - * - * @see GUAC_CLIENT_MOUSE_LEFT - * @see GUAC_CLIENT_MOUSE_MIDDLE - * @see GUAC_CLIENT_MOUSE_RIGHT - * @see GUAC_CLIENT_MOUSE_SCROLL_UP - * @see GUAC_CLIENT_MOUSE_SCROLL_DOWN - */ - int button_mask; - - /** - * The server timestamp representing the point in time when the mouse - * location was last updated. - */ - guac_timestamp timestamp; - - /** - * Lock which restricts simultaneous access to the cursor, guaranteeing - * ordered modifications to the cursor and that incompatible operations - * do not occur simultaneously. This lock is for internal use within the - * cursor only. - */ - pthread_mutex_t _lock; - -} guac_common_cursor; - -/** - * Allocates a new cursor object which maintains and synchronizes the current - * mouse cursor state across all users of the given client. - * - * @param client - * The client for which this object shall maintain the mouse cursor. - * - * @return - * The newly-allocated mouse cursor. - */ -guac_common_cursor* guac_common_cursor_alloc(guac_client* client); - -/** - * Frees the given cursor. - * - * @param cursor - * The cursor to free. - */ -void guac_common_cursor_free(guac_common_cursor* cursor); - -/** - * Sends the current state of this cursor across the given socket, including - * the current cursor image. The resulting cursor on the remote display will - * be visible. - * - * @param cursor - * The cursor to send. - * - * @param client - * The user receiving the updated cursor. - * - * @param socket - * The socket over which the updated cursor should be sent. - */ -void guac_common_cursor_dup( - guac_common_cursor* cursor, guac_client* client, guac_socket* socket); - -/** - * Updates the current position and button state of the mouse cursor, marking - * the given user as the most recent user of the mouse. The remote mouse cursor - * will be hidden for this user and shown for all others. - * - * @param cursor - * The cursor being updated. - * - * @param user - * The user that moved the cursor. - * - * @param x - * The new X coordinate of the cursor. - * - * @param y - * The new Y coordinate of the cursor. - * - * @param button_mask - * An integer value representing the current state of each button, where - * the Nth bit within the integer is set to 1 if and only if the Nth mouse - * button is currently pressed. The lowest-order bit is the left mouse - * button, followed by the middle button, right button, and finally the up - * and down buttons of the scroll wheel. - * - * @see GUAC_CLIENT_MOUSE_LEFT - * @see GUAC_CLIENT_MOUSE_MIDDLE - * @see GUAC_CLIENT_MOUSE_RIGHT - * @see GUAC_CLIENT_MOUSE_SCROLL_UP - * @see GUAC_CLIENT_MOUSE_SCROLL_DOWN - */ -void guac_common_cursor_update(guac_common_cursor* cursor, guac_user* user, - int x, int y, int button_mask); - -/** - * Sets the cursor image to the given raw image data. This raw image data must - * be in 32-bit ARGB format, having 8 bits per color component, where the - * alpha component is stored in the high-order 8 bits, and blue is stored - * in the low-order 8 bits. - * - * @param cursor - * The cursor to set the image of. - * - * @param hx - * The X coordinate of the hotspot of the new cursor image. - * - * @param hy - * The Y coordinate of the hotspot of the new cursor image. - * - * @param data - * A pointer to raw 32-bit ARGB image data. - * - * @param width - * The width of the given image data, in pixels. - * - * @param height - * The height of the given image data, in pixels. - * - * @param stride - * The number of bytes in a single row of image data. - */ -void guac_common_cursor_set_argb(guac_common_cursor* cursor, int hx, int hy, - unsigned const char* data, int width, int height, int stride); - -/** - * Sets the cursor image to the contents of the given surface. The entire - * contents of the surface are used, and the dimensions of the resulting - * cursor will be the dimensions of the given surface. - * - * @param cursor - * The cursor to set the image of. - * - * @param hx - * The X coordinate of the hotspot of the new cursor image. - * - * @param hy - * The Y coordinate of the hotspot of the new cursor image. - * - * @param surface - * The surface containing the cursor image. - */ -void guac_common_cursor_set_surface(guac_common_cursor* cursor, int hx, int hy, - guac_common_surface* surface); - -/** - * Set the cursor of the remote display to the embedded "pointer" graphic. The - * pointer graphic is a black arrow with white border. - * - * @param cursor - * The cursor to set the image of. - */ -void guac_common_cursor_set_pointer(guac_common_cursor* cursor); - -/** - * Set the cursor of the remote display to the embedded "dot" graphic. The dot - * graphic is a small black square with white border. - * - * @param cursor - * The cursor to set the image of. - */ -void guac_common_cursor_set_dot(guac_common_cursor* cursor); - -/** - * Sets the cursor of the remote display to the embedded "I-bar" graphic. The - * I-bar graphic is a small black "I" shape with white border, used to indicate - * the presence of selectable or editable text. - * - * @param cursor - * The cursor to set the image of. - */ -void guac_common_cursor_set_ibar(guac_common_cursor* cursor); - -/** - * Sets the cursor of the remote display to the embedded transparent (blank) - * graphic, effectively hiding the mouse cursor. - * - * @param cursor - * The cursor to set the image of. - */ -void guac_common_cursor_set_blank(guac_common_cursor* cursor); - -/** - * Removes the given user, such that future synchronization will not occur. - * This is necessary when a user leaves the connection. If a user leaves the - * connection and this is not called, the mouse cursor state may not update - * correctly in response to mouse events. - * - * @param cursor - * The cursor to remove the user from. - * - * @param user - * The user to remove. - */ -void guac_common_cursor_remove_user(guac_common_cursor* cursor, - guac_user* user); - -#endif diff --git a/src/common/common/display.h b/src/common/common/display.h deleted file mode 100644 index 92999930b..000000000 --- a/src/common/common/display.h +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef GUAC_COMMON_DISPLAY_H -#define GUAC_COMMON_DISPLAY_H - -#include "cursor.h" -#include "surface.h" - -#include -#include - -#include - -/** - * The minimum display size (height or width) in pixels. - */ -#define GUAC_COMMON_DISPLAY_MIN_SIZE 200 - -/** - * The maximum display size (height or width) in pixels. - */ -#define GUAC_COMMON_DISPLAY_MAX_SIZE 8192 - -/** - * The minimum amount of time that must elapse between display size updates, - * in milliseconds. - */ -#define GUAC_COMMON_DISPLAY_UPDATE_INTERVAL 500 - -/** - * A list element representing a pairing of a Guacamole layer with a - * corresponding guac_common_surface which wraps that layer. Adjacent layers - * within the same list are pointed to with traditional prev/next pointers. The - * order of layers in lists need not correspond in any way to the natural - * ordering of those layers' indexes nor their stacking order (Z-order) within - * the display. - */ -typedef struct guac_common_display_layer guac_common_display_layer; - -struct guac_common_display_layer { - - /** - * A Guacamole layer. - */ - guac_layer* layer; - - /** - * The surface which wraps the associated layer. - */ - guac_common_surface* surface; - - /** - * The layer immediately prior to this layer within the list containing - * this layer, or NULL if this is the first layer/buffer in the list. - */ - guac_common_display_layer* prev; - - /** - * The layer immediately following this layer within the list containing - * this layer, or NULL if this is the last layer/buffer in the list. - */ - guac_common_display_layer* next; - -}; - -/** - * Abstracts a remote Guacamole display, having an associated client, - * default surface, mouse cursor, and various allocated buffers and layers. - */ -typedef struct guac_common_display { - - /** - * The client associate with this display. - */ - guac_client* client; - - /** - * The default surface of the client display. - */ - guac_common_surface* default_surface; - - /** - * Client-wide cursor, synchronized across all users. - */ - guac_common_cursor* cursor; - - /** - * The first element within a linked list of all currently-allocated - * layers, or NULL if no layers are currently allocated. The default layer, - * layer #0, is stored within default_surface and will not have a - * corresponding element within this list. - */ - guac_common_display_layer* layers; - - /** - * The first element within a linked list of all currently-allocated - * buffers, or NULL if no buffers are currently allocated. - */ - guac_common_display_layer* buffers; - - /** - * Non-zero if all graphical updates for this display should use lossless - * compression, 0 otherwise. By default, newly-created displays will use - * lossy compression when heuristics determine it is appropriate. - */ - int lossless; - - /** - * Mutex which is locked internally when access to the display must be - * synchronized. All public functions of guac_common_display should be - * considered threadsafe. - */ - pthread_mutex_t _lock; - -} guac_common_display; - -/** - * Allocates a new display, abstracting the cursor and buffer/layer allocation - * operations of the given guac_client such that client state can be easily - * synchronized to joining users. - * - * @param client - * The guac_client to associate with this display. - * - * @param width - * The initial width of the display, in pixels. - * - * @param height - * The initial height of the display, in pixels. - * - * @return - * The newly-allocated display. - */ -guac_common_display* guac_common_display_alloc(guac_client* client, - int width, int height); - -/** - * Fits a given dimension within the allowed bounds for display sizing, - * adjusting the other dimension such that aspect ratio is maintained. - * - * @param a - * The dimension to fit within allowed bounds. - * - * @param b - * The other dimension to adjust if and only if necessary to preserve - * aspect ratio. - */ -void guac_common_display_fit(int* a, int* b); - -/** - * Frees the given display, and any associated resources, including any - * allocated buffers/layers. - * - * @param display - * The display to free. - */ -void guac_common_display_free(guac_common_display* display); - -/** - * Duplicates the state of the given display to the given socket. Any pending - * changes to buffers, layers, or the default layer are not flushed. - * - * @param display - * The display whose state should be sent along the given socket. - * - * @param client - * The client associated with the users receiving the display state. - * - * @param socket - * The socket over which the display state should be sent. - */ -void guac_common_display_dup( - guac_common_display* display, guac_client* client, - guac_socket* socket); - -/** - * Flushes pending changes to the given display. All pending operations will - * become visible to any connected users. - * - * @param display - * The display to flush. - */ -void guac_common_display_flush(guac_common_display* display); - -/** - * Allocates a new layer, returning a new wrapped layer and corresponding - * surface. The layer may be reused from a previous allocation, if that layer - * has since been freed. - * - * @param display - * The display to allocate a new layer from. - * - * @param width - * The width of the layer to allocate, in pixels. - * - * @param height - * The height of the layer to allocate, in pixels. - * - * @return - * A newly-allocated layer. - */ -guac_common_display_layer* guac_common_display_alloc_layer( - guac_common_display* display, int width, int height); - -/** - * Allocates a new buffer, returning a new wrapped buffer and corresponding - * surface. The buffer may be reused from a previous allocation, if that buffer - * has since been freed. - * - * @param display - * The display to allocate a new buffer from. - * - * @param width - * The width of the buffer to allocate, in pixels. - * - * @param height - * The height of the buffer to allocate, in pixels. - * - * @return - * A newly-allocated buffer. - */ -guac_common_display_layer* guac_common_display_alloc_buffer( - guac_common_display* display, int width, int height); - -/** - * Frees the given surface and associated layer, returning the layer to the - * given display for future use. - * - * @param display - * The display originally allocating the layer. - * - * @param display_layer - * The layer to free. - */ -void guac_common_display_free_layer(guac_common_display* display, - guac_common_display_layer* display_layer); - -/** - * Frees the given surface and associated buffer, returning the buffer to the - * given display for future use. - * - * @param display - * The display originally allocating the buffer. - * - * @param display_buffer - * The buffer to free. - */ -void guac_common_display_free_buffer(guac_common_display* display, - guac_common_display_layer* display_buffer); - -/** - * Sets the overall lossless compression policy of the given display to the - * given value, affecting all current and future layers/buffers maintained by - * the display. By default, newly-created displays will use lossy compression - * for graphical updates when heuristics determine that doing so is - * appropriate. Specifying a non-zero value here will force all graphical - * updates to always use lossless compression, whereas specifying zero will - * restore the default policy. - * - * Note that this can also be adjusted on a per-layer / per-buffer basis with - * guac_common_surface_set_lossless(). - * - * @param display - * The display to modify. - * - * @param lossless - * Non-zero if all graphical updates for this display should use lossless - * compression, 0 otherwise. - */ -void guac_common_display_set_lossless(guac_common_display* display, - int lossless); - - - -#endif - diff --git a/src/common/common/dot_cursor.h b/src/common/common/dot_cursor.h deleted file mode 100644 index c5b73880e..000000000 --- a/src/common/common/dot_cursor.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef _GUAC_COMMON_DOT_CURSOR_H -#define _GUAC_COMMON_DOT_CURSOR_H - -#include "config.h" - -#include -#include - -/** - * Width of the embedded mouse cursor graphic. - */ -extern const int guac_common_dot_cursor_width; - -/** - * Height of the embedded mouse cursor graphic. - */ -extern const int guac_common_dot_cursor_height; - -/** - * Number of bytes in each row of the embedded mouse cursor graphic. - */ -extern const int guac_common_dot_cursor_stride; - -/** - * The Cairo graphic format of the mouse cursor graphic. - */ -extern const cairo_format_t guac_common_dot_cursor_format; - -/** - * Embedded mouse cursor graphic. - */ -extern unsigned char guac_common_dot_cursor[]; - -/** - * Set the cursor of the remote display to the embedded cursor graphic. - * - * @param user The guac_user to send the cursor to. - */ -void guac_common_set_dot_cursor(guac_user* user); - -#endif diff --git a/src/common/common/ibar_cursor.h b/src/common/common/ibar_cursor.h deleted file mode 100644 index ae11fff7c..000000000 --- a/src/common/common/ibar_cursor.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef GUAC_COMMON_IBAR_CURSOR_H -#define GUAC_COMMON_IBAR_CURSOR_H - -#include "config.h" - -#include -#include - -/** - * Width of the embedded I-bar mouse cursor graphic. - */ -extern const int guac_common_ibar_cursor_width; - -/** - * Height of the embedded I-bar mouse cursor graphic. - */ -extern const int guac_common_ibar_cursor_height; - -/** - * Number of bytes in each row of the embedded I-bar mouse cursor graphic. - */ -extern const int guac_common_ibar_cursor_stride; - -/** - * The Cairo grapic format of the I-bar mouse cursor graphic. - */ -extern const cairo_format_t guac_common_ibar_cursor_format; - -/** - * Embedded I-bar mouse cursor graphic. - */ -extern unsigned char guac_common_ibar_cursor[]; - -/** - * Sets the cursor of the remote display to the embedded I-bar cursor graphic. - * - * @param user - * The guac_user to send the cursor to. - */ -void guac_common_set_ibar_cursor(guac_user* user); - -#endif - diff --git a/src/common/common/pointer_cursor.h b/src/common/common/pointer_cursor.h deleted file mode 100644 index 74559ba33..000000000 --- a/src/common/common/pointer_cursor.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef _GUAC_COMMON_POINTER_CURSOR_H -#define _GUAC_COMMON_POINTER_CURSOR_H - -#include "config.h" - -#include -#include - -/** - * Width of the embedded mouse cursor graphic. - */ -extern const int guac_common_pointer_cursor_width; - -/** - * Height of the embedded mouse cursor graphic. - */ -extern const int guac_common_pointer_cursor_height; - -/** - * Number of bytes in each row of the embedded mouse cursor graphic. - */ -extern const int guac_common_pointer_cursor_stride; - -/** - * The Cairo grapic format of the mouse cursor graphic. - */ -extern const cairo_format_t guac_common_pointer_cursor_format; - -/** - * Embedded mouse cursor graphic. - */ -extern unsigned char guac_common_pointer_cursor[]; - -/** - * Set the cursor of the remote display to the embedded cursor graphic. - * - * @param user The guac_user to send the cursor to. - */ -void guac_common_set_pointer_cursor(guac_user* user); - -#endif diff --git a/src/common/common/rect.h b/src/common/common/rect.h deleted file mode 100644 index 6b3104865..000000000 --- a/src/common/common/rect.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef __GUAC_COMMON_RECT_H -#define __GUAC_COMMON_RECT_H - -#include "config.h" - -/** - * Simple representation of a rectangle, having a defined corner and dimensions. - */ -typedef struct guac_common_rect { - - /** - * The X coordinate of the upper-left corner of this rectangle. - */ - int x; - - /** - * The Y coordinate of the upper-left corner of this rectangle. - */ - int y; - - /** - * The width of this rectangle. - */ - int width; - - /** - * The height of this rectangle. - */ - int height; - -} guac_common_rect; - -/** - * Initialize the given rect with the given coordinates and dimensions. - * - * @param rect The rect to initialize. - * @param x The X coordinate of the upper-left corner of the rect. - * @param y The Y coordinate of the upper-left corner of the rect. - * @param width The width of the rect. - * @param height The height of the rect. - */ -void guac_common_rect_init(guac_common_rect* rect, int x, int y, int width, int height); - -/** - * Expand the rectangle to fit an NxN grid. - * - * The rectangle will be shifted to the left and up, expanded and adjusted to - * fit within the max bounding rect. - * - * @param cell_size - * The (NxN) grid cell size. - * - * @param rect - * The rectangle to adjust. - * - * @param max_rect - * The bounding area in which the given rect can exist. - * - * @return - * Zero on success, non-zero on error. - */ -int guac_common_rect_expand_to_grid(int cell_size, guac_common_rect* rect, - const guac_common_rect* max_rect); - -/** - * Extend the given rect such that it contains at least the specified minimum - * rect. - * - * @param rect The rect to extend. - * @param min The minimum area which must be contained within the given rect. - */ -void guac_common_rect_extend(guac_common_rect* rect, const guac_common_rect* min); - -/** - * Collapse the given rect such that it exists only within the given maximum - * rect. - * - * @param rect The rect to extend. - * @param max The maximum area in which the given rect can exist. - */ -void guac_common_rect_constrain(guac_common_rect* rect, const guac_common_rect* max); - -/** - * Check whether a rectangle intersects another. - * - * @param rect - * Rectangle to check for intersection. - * - * @param other - * The other rectangle. - * - * @return - * Zero if no intersection, 1 if partial intersection, - * 2 if first rect is completely inside the other. - */ -int guac_common_rect_intersects(const guac_common_rect* rect, - const guac_common_rect* other); - -/** - * Clip and split a rectangle into rectangles which are not covered by the - * hole rectangle. - * - * This function will clip and split single edges when executed and must be - * invoked until it returns zero. The edges are handled counter-clockwise - * starting at the top edge. - * - * @param rect - * The rectangle to be split. This rectangle will be clipped by the - * split_rect. - * - * @param hole - * The rectangle which represents the hole. - * - * @param split_rect - * Resulting split rectangle. - * - * @return - * Zero when no splits were done, non-zero when the rectangle was split. - */ -int guac_common_rect_clip_and_split(guac_common_rect* rect, - const guac_common_rect* hole, guac_common_rect* split_rect); - -#endif - diff --git a/src/common/common/surface.h b/src/common/common/surface.h deleted file mode 100644 index 21859a3e1..000000000 --- a/src/common/common/surface.h +++ /dev/null @@ -1,539 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef __GUAC_COMMON_SURFACE_H -#define __GUAC_COMMON_SURFACE_H - -#include "config.h" -#include "rect.h" - -#include -#include -#include -#include -#include - -#include - -/** - * The maximum number of updates to allow within the bitmap queue. - */ -#define GUAC_COMMON_SURFACE_QUEUE_SIZE 256 - -/** - * Heat map cell size in pixels. Each side of each heat map cell will consist - * of this many pixels. - */ -#define GUAC_COMMON_SURFACE_HEAT_CELL_SIZE 64 - -/** - * The width or height of the heat map (in cells) given the width or height of - * the image (in pixels). - */ -#define GUAC_COMMON_SURFACE_HEAT_DIMENSION(x) ( \ - (x + GUAC_COMMON_SURFACE_HEAT_CELL_SIZE - 1) \ - / GUAC_COMMON_SURFACE_HEAT_CELL_SIZE \ -) - -/** - * The number of entries to collect within each heat map cell. Collected - * history entries are used to determine the framerate of the region associated - * with that cell. - */ -#define GUAC_COMMON_SURFACE_HEAT_CELL_HISTORY_SIZE 5 - -/** - * Representation of a cell in the refresh heat map. This cell is used to keep - * track of how often an area on a surface is refreshed. - */ -typedef struct guac_common_surface_heat_cell { - - /** - * Timestamps of each of the last N updates covering the location - * associated with this heat map cell. This is used to calculate the - * framerate. This array is structured as a ring buffer containing history - * entries in chronologically-ascending order, starting at the entry - * pointed to by oldest_entry and proceeding through all other entries, - * wrapping around if the end of the array is reached. - */ - guac_timestamp history[GUAC_COMMON_SURFACE_HEAT_CELL_HISTORY_SIZE]; - - /** - * Index of the oldest entry within the history. - */ - int oldest_entry; - -} guac_common_surface_heat_cell; - -/** - * Representation of a bitmap update, having a rectangle of image data (stored - * elsewhere) and a flushed/not-flushed state. - */ -typedef struct guac_common_surface_bitmap_rect { - - /** - * Whether this rectangle has been flushed. - */ - int flushed; - - /** - * The rectangle containing the bitmap update. - */ - guac_common_rect rect; - -} guac_common_surface_bitmap_rect; - -/** - * Surface which backs a Guacamole buffer or layer, automatically - * combining updates when possible. - */ -typedef struct guac_common_surface { - - /** - * The layer this surface will draw to. - */ - const guac_layer* layer; - - /** - * The client associated with this surface. - */ - guac_client* client; - - /** - * The socket to send instructions on when flushing. - */ - guac_socket* socket; - - /** - * The number of simultaneous touches that this surface can accept, where 0 - * indicates that the surface does not support touch events at all. - */ - int touches; - - /** - * Non-zero if all graphical updates for this surface should use lossless - * compression, 0 otherwise. By default, newly-created surfaces will use - * lossy compression when heuristics determine it is appropriate. - */ - int lossless; - - /** - * The X coordinate of the upper-left corner of this layer, in pixels, - * relative to its parent layer. This is only applicable to visible - * (non-buffer) layers which are not the default layer. - */ - int x; - - /** - * The Y coordinate of the upper-left corner of this layer, in pixels, - * relative to its parent layer. This is only applicable to visible - * (non-buffer) layers which are not the default layer. - */ - int y; - - /** - * The Z-order of this layer, relative to sibling layers. This is only - * applicable to visible (non-buffer) layers which are not the default - * layer. - */ - int z; - - /** - * The level of opacity applied to this layer. Fully opaque is 255, while - * fully transparent is 0. This is only applicable to visible (non-buffer) - * layers which are not the default layer. - */ - int opacity; - - /** - * The layer which contains this layer. This is only applicable to visible - * (non-buffer) layers which are not the default layer. - */ - const guac_layer* parent; - - /** - * The width of this layer, in pixels. - */ - int width; - - /** - * The height of this layer, in pixels. - */ - int height; - - /** - * The size of each image row, in bytes. - */ - int stride; - - /** - * The underlying buffer of the Cairo surface. - */ - unsigned char* buffer; - - /** - * Non-zero if the location or parent layer of this surface has been - * changed and needs to be flushed, 0 otherwise. - */ - int location_dirty; - - /** - * Non-zero if the opacity of this surface has been changed and needs to be - * flushed, 0 otherwise. - */ - int opacity_dirty; - - /** - * Non-zero if this surface is dirty and needs to be flushed, 0 otherwise. - */ - int dirty; - - /** - * The dirty rectangle. - */ - guac_common_rect dirty_rect; - - /** - * Whether the surface actually exists on the client. - */ - int realized; - - /** - * Whether drawing operations are currently clipped by the clipping - * rectangle. - */ - int clipped; - - /** - * The clipping rectangle. - */ - guac_common_rect clip_rect; - - /** - * The number of updates in the bitmap queue. - */ - int bitmap_queue_length; - - /** - * All queued bitmap updates. - */ - guac_common_surface_bitmap_rect bitmap_queue[GUAC_COMMON_SURFACE_QUEUE_SIZE]; - - /** - * A heat map keeping track of the refresh frequency of - * the areas of the screen. - */ - guac_common_surface_heat_cell* heat_map; - - /** - * Mutex which is locked internally when access to the surface must be - * synchronized. All public functions of guac_common_surface should be - * considered threadsafe. - */ - pthread_mutex_t _lock; - -} guac_common_surface; - -/** - * Allocates a new guac_common_surface, assigning it to the given layer. - * - * @param client - * The client associated with the given layer. - * - * @param socket - * The socket to send instructions on when flushing. - * - * @param layer - * The layer to associate with the new surface. - * - * @param w - * The width of the surface. - * - * @param h - * The height of the surface. - * - * @return - * A newly-allocated guac_common_surface. - */ -guac_common_surface* guac_common_surface_alloc(guac_client* client, - guac_socket* socket, const guac_layer* layer, int w, int h); - -/** - * Frees the given guac_common_surface. Beware that this will NOT free any - * associated layers, which must be freed manually. - * - * @param surface The surface to free. - */ -void guac_common_surface_free(guac_common_surface* surface); - - /** - * Resizes the given surface to the given size. - * - * @param surface The surface to resize. - * @param w The width of the surface. - * @param h The height of the surface. - */ -void guac_common_surface_resize(guac_common_surface* surface, int w, int h); - -/** - * Draws the given data to the given guac_common_surface. If the source surface - * is ARGB, the draw operation will be performed using the Porter-Duff "over" - * composite operator. If the source surface is RGB (no alpha channel), no - * compositing is performed and destination pixels are ignored. - * - * @param surface - * The surface to draw to. - * - * @param x - * The X coordinate of the draw location. - * - * @param y - * The Y coordinate of the draw location. - * - * @param src - * The Cairo surface to retrieve data from. - */ -void guac_common_surface_draw(guac_common_surface* surface, int x, int y, - cairo_surface_t* src); - -/** - * Paints to the given guac_common_surface using the given data as a stencil, - * filling opaque regions with the specified color, and leaving transparent - * regions untouched. - * - * @param surface The surface to draw to. - * @param x The X coordinate of the draw location. - * @param y The Y coordinate of the draw location. - * @param src The Cairo surface to retrieve data from. - * @param red The red component of the fill color. - * @param green The green component of the fill color. - * @param blue The blue component of the fill color. - */ -void guac_common_surface_paint(guac_common_surface* surface, int x, int y, cairo_surface_t* src, - int red, int green, int blue); - -/** - * Copies a rectangle of data between two surfaces. - * - * @param src The source surface. - * @param sx The X coordinate of the upper-left corner of the source rect. - * @param sy The Y coordinate of the upper-left corner of the source rect. - * @param w The width of the source rect. - * @param h The height of the source rect. - * @param dst The destination surface. - * @param dx The X coordinate of the upper-left corner of the destination rect. - * @param dy The Y coordinate of the upper-left corner of the destination rect. - */ -void guac_common_surface_copy(guac_common_surface* src, int sx, int sy, int w, int h, - guac_common_surface* dst, int dx, int dy); - -/** - * Transfers a rectangle of data between two surfaces. - * - * @param src The source surface. - * @param sx The X coordinate of the upper-left corner of the source rect. - * @param sy The Y coordinate of the upper-left corner of the source rect. - * @param w The width of the source rect. - * @param h The height of the source rect. - * @param op The transfer function. - * @param dst The destination surface. - * @param dx The X coordinate of the upper-left corner of the destination rect. - * @param dy The Y coordinate of the upper-left corner of the destination rect. - */ -void guac_common_surface_transfer(guac_common_surface* src, int sx, int sy, int w, int h, - guac_transfer_function op, guac_common_surface* dst, int dx, int dy); - -/** - * 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_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 - * operations within that rectangle. - * - * @param surface The surface whose clipping rectangle should be changed. - * @param x The X coordinate of the upper-left corner of the bounding rectangle. - * @param y The Y coordinate of the upper-left corner of the bounding rectangle. - * @param w The width of the bounding rectangle. - * @param h The height of the bounding rectangle. - */ -void guac_common_surface_clip(guac_common_surface* surface, int x, int y, int w, int h); - -/** - * Resets the clipping rectangle, allowing drawing operations throughout the - * entire surface. - * - * @param surface The surface whose clipping rectangle should be reset. - */ -void guac_common_surface_reset_clip(guac_common_surface* surface); - -/** - * Changes the location of the surface relative to its parent layer. If the - * surface does not represent a non-default visible layer, then this function - * has no effect. - * - * @param surface - * The surface to move relative to its parent layer. - * - * @param x - * The new X coordinate for the upper-left corner of the layer, in pixels. - * - * @param y - * The new Y coordinate for the upper-left corner of the layer, in pixels. - */ -void guac_common_surface_move(guac_common_surface* surface, int x, int y); - -/** - * Changes the stacking order of the surface relative to other surfaces within - * the same parent layer. If the surface does not represent a non-default - * visible layer, then this function has no effect. - * - * @param surface - * The surface to reorder relative to sibling layers. - * - * @param z - * The new Z-order for this layer, relative to sibling layers. - */ -void guac_common_surface_stack(guac_common_surface* surface, int z); - -/** - * Changes the parent layer of ths given surface. By default, layers will be - * children of the default layer. If the surface does not represent a - * non-default visible layer, then this function has no effect. - * - * @param surface - * The surface whose parent layer should be changed. - * - * @param parent - * The layer which should be set as the new parent of the given surface. - */ -void guac_common_surface_set_parent(guac_common_surface* surface, - const guac_layer* parent); - -/** - * Sets the opacity of the surface. If the surface does not represent a - * non-default visible layer, then this function has no effect. - * - * @param surface - * The surface whose opacity should be changed. - * - * @param opacity - * The level of opacity applied to this surface, where fully opaque is 255, - * and fully transparent is 0. - */ -void guac_common_surface_set_opacity(guac_common_surface* surface, int opacity); - -/** - * Flushes the given surface, including any applicable properties, drawing any - * pending operations on the remote display. - * - * @param surface - * The surface to flush. - */ -void guac_common_surface_flush(guac_common_surface* surface); - -/** - * Duplicates the contents of the current surface to the given socket. Pending - * changes are not flushed. - * - * @param surface - * The surface to duplicate. - * - * @param client - * The client whose users are receiving the surface. - * - * @param socket - * The socket over which the surface contents should be sent. - */ -void guac_common_surface_dup(guac_common_surface* surface, - guac_client* client, guac_socket* socket); - -/** - * Declares that the given surface should receive touch events. By default, - * surfaces are assumed to not expect touch events. This value is advisory, and - * the client is not required to honor the declared level of touch support. - * Implementations are expected to safely handle or ignore any received touch - * events, regardless of the level of touch support declared. regardless of - * the level of touch support declared. - * - * @param surface - * The surface to modify. - * - * @param touches - * The number of simultaneous touches that this surface can accept, where 0 - * indicates that the surface does not support touch events at all. - */ -void guac_common_surface_set_multitouch(guac_common_surface* surface, - int touches); - -/** - * Sets the lossless compression policy of the given surface to the given - * value. By default, newly-created surfaces will use lossy compression for - * graphical updates when heuristics determine that doing so is appropriate. - * Specifying a non-zero value here will force all graphical updates to always - * use lossless compression, whereas specifying zero will restore the default - * policy. - * - * @param surface - * The surface to modify. - * - * @param lossless - * Non-zero if all graphical updates for this surface should use lossless - * compression, 0 otherwise. - */ -void guac_common_surface_set_lossless(guac_common_surface* surface, - int lossless); - -#endif - diff --git a/src/common/cursor.c b/src/common/cursor.c deleted file mode 100644 index 9bb51aedf..000000000 --- a/src/common/cursor.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "common/blank_cursor.h" -#include "common/dot_cursor.h" -#include "common/cursor.h" -#include "common/ibar_cursor.h" -#include "common/pointer_cursor.h" -#include "common/surface.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/** - * Allocates a cursor as well as an image buffer where the cursor is rendered. - * - * @param client - * The client owning the cursor. - * - * @return - * The newly-allocated cursor or NULL if cursor cannot be allocated. - */ -guac_common_cursor* guac_common_cursor_alloc(guac_client* client) { - - guac_common_cursor* cursor = guac_mem_alloc(sizeof(guac_common_cursor)); - if (cursor == NULL) - return NULL; - - /* Associate cursor with client and allocate cursor buffer */ - cursor->client = client; - cursor->buffer = guac_client_alloc_buffer(client); - - /* Allocate initial image buffer */ - cursor->image_buffer_size = GUAC_COMMON_CURSOR_DEFAULT_SIZE; - cursor->image_buffer = guac_mem_alloc(cursor->image_buffer_size); - - /* No cursor image yet */ - cursor->width = 0; - cursor->height = 0; - cursor->surface = NULL; - cursor->hotspot_x = 0; - cursor->hotspot_y = 0; - - /* No user has moved the mouse yet */ - cursor->user = NULL; - cursor->timestamp = guac_timestamp_current(); - - /* Start cursor in upper-left */ - cursor->x = 0; - cursor->y = 0; - - pthread_mutex_init(&(cursor->_lock), NULL); - - return cursor; - -} - -void guac_common_cursor_free(guac_common_cursor* cursor) { - - pthread_mutex_destroy(&(cursor->_lock)); - - guac_client* client = cursor->client; - guac_layer* buffer = cursor->buffer; - cairo_surface_t* surface = cursor->surface; - - /* Free image buffer and surface */ - guac_mem_free(cursor->image_buffer); - if (surface != NULL) - cairo_surface_destroy(surface); - - /* Destroy buffer within remotely-connected client */ - guac_protocol_send_dispose(client->socket, buffer); - - /* Return buffer to pool */ - guac_client_free_buffer(client, buffer); - - guac_mem_free(cursor); - -} - -void guac_common_cursor_dup( - guac_common_cursor* cursor, guac_client* client, guac_socket* socket) { - - pthread_mutex_lock(&(cursor->_lock)); - - /* Synchronize location */ - guac_protocol_send_mouse(socket, cursor->x, cursor->y, cursor->button_mask, - cursor->timestamp); - - /* Synchronize cursor image */ - if (cursor->surface != NULL) { - guac_protocol_send_size(socket, cursor->buffer, - cursor->width, cursor->height); - - guac_client_stream_png(client, socket, GUAC_COMP_SRC, - cursor->buffer, 0, 0, cursor->surface); - - guac_protocol_send_cursor(socket, - cursor->hotspot_x, cursor->hotspot_y, - cursor->buffer, 0, 0, cursor->width, cursor->height); - } - - pthread_mutex_unlock(&(cursor->_lock)); - - guac_socket_flush(socket); - -} - -/** - * Callback for guac_client_foreach_user() which sends the current cursor - * position and button state to any given user except the user that moved the - * cursor last. - * - * @param data - * A pointer to the guac_common_cursor whose state should be broadcast to - * all users except the user that moved the cursor last. - * - * @return - * Always NULL. - */ -static void* guac_common_cursor_broadcast_state(guac_user* user, - void* data) { - - guac_common_cursor* cursor = (guac_common_cursor*) data; - - /* Send cursor state only if the user is not moving the cursor */ - if (user != cursor->user) { - guac_protocol_send_mouse(user->socket, cursor->x, cursor->y, - cursor->button_mask, cursor->timestamp); - guac_socket_flush(user->socket); - } - - return NULL; - -} - -void guac_common_cursor_update(guac_common_cursor* cursor, guac_user* user, - int x, int y, int button_mask) { - - pthread_mutex_lock(&(cursor->_lock)); - - /* Update current user of cursor */ - cursor->user = user; - - /* Update cursor state */ - cursor->x = x; - cursor->y = y; - cursor->button_mask = button_mask; - - /* Store time at which cursor was updated */ - cursor->timestamp = guac_timestamp_current(); - - /* Notify all other users of change in cursor state */ - guac_client_foreach_user(cursor->client, - guac_common_cursor_broadcast_state, cursor); - - pthread_mutex_unlock(&(cursor->_lock)); - -} - -/** - * Ensures the cursor image buffer has enough room to fit an image with the - * given characteristics. Existing image buffer data may be destroyed. - * - * @param cursor - * The cursor whose buffer size should be checked. If this cursor lacks - * sufficient space to contain a cursor image of the specified width, - * height, and stride, the current contents of this cursor will be - * destroyed and replaced with an new buffer having sufficient space. - * - * @param width - * The required cursor width, in pixels. - * - * @param height - * The required cursor height, in pixels. - * - * @param stride - * The number of bytes in each row of image data. - */ -static void guac_common_cursor_resize(guac_common_cursor* cursor, - int width, int height, int stride) { - - size_t minimum_size = guac_mem_ckd_mul_or_die(height, stride); - - /* Grow image buffer if necessary */ - if (cursor->image_buffer_size < minimum_size) { - - /* Calculate new size */ - cursor->image_buffer_size = guac_mem_ckd_mul_or_die(minimum_size, 2); - - /* Destructively reallocate image buffer */ - guac_mem_free(cursor->image_buffer); - cursor->image_buffer = guac_mem_alloc(cursor->image_buffer_size); - - } - -} - -void guac_common_cursor_set_argb(guac_common_cursor* cursor, int hx, int hy, - unsigned const char* data, int width, int height, int stride) { - - pthread_mutex_lock(&(cursor->_lock)); - - /* Copy image data */ - guac_common_cursor_resize(cursor, width, height, stride); - memcpy(cursor->image_buffer, data, height * stride); - - if (cursor->surface != NULL) - cairo_surface_destroy(cursor->surface); - - cursor->surface = cairo_image_surface_create_for_data(cursor->image_buffer, - CAIRO_FORMAT_ARGB32, width, height, stride); - - /* Set new cursor parameters */ - cursor->width = width; - cursor->height = height; - cursor->hotspot_x = hx; - cursor->hotspot_y = hy; - - /* Broadcast new cursor image to all users */ - guac_protocol_send_size(cursor->client->socket, cursor->buffer, - width, height); - - guac_client_stream_png(cursor->client, cursor->client->socket, - GUAC_COMP_SRC, cursor->buffer, 0, 0, cursor->surface); - - /* Update cursor image */ - guac_protocol_send_cursor(cursor->client->socket, - cursor->hotspot_x, cursor->hotspot_y, - cursor->buffer, 0, 0, cursor->width, cursor->height); - - guac_socket_flush(cursor->client->socket); - - pthread_mutex_unlock(&(cursor->_lock)); - -} - -void guac_common_cursor_set_surface(guac_common_cursor* cursor, int hx, int hy, - guac_common_surface* surface) { - - /* Set cursor to surface contents */ - guac_common_cursor_set_argb(cursor, hx, hy, surface->buffer, - surface->width, surface->height, surface->stride); - -} - -void guac_common_cursor_set_pointer(guac_common_cursor* cursor) { - - guac_common_cursor_set_argb(cursor, 0, 0, - guac_common_pointer_cursor, - guac_common_pointer_cursor_width, - guac_common_pointer_cursor_height, - guac_common_pointer_cursor_stride); - -} - -void guac_common_cursor_set_dot(guac_common_cursor* cursor) { - - guac_common_cursor_set_argb(cursor, 2, 2, - guac_common_dot_cursor, - guac_common_dot_cursor_width, - guac_common_dot_cursor_height, - guac_common_dot_cursor_stride); - -} - -void guac_common_cursor_set_ibar(guac_common_cursor* cursor) { - - guac_common_cursor_set_argb(cursor, - guac_common_ibar_cursor_width / 2, - guac_common_ibar_cursor_height / 2, - guac_common_ibar_cursor, - guac_common_ibar_cursor_width, - guac_common_ibar_cursor_height, - guac_common_ibar_cursor_stride); - -} - -void guac_common_cursor_set_blank(guac_common_cursor* cursor) { - - guac_common_cursor_set_argb(cursor, 0, 0, - guac_common_blank_cursor, - guac_common_blank_cursor_width, - guac_common_blank_cursor_height, - guac_common_blank_cursor_stride); - -} - -void guac_common_cursor_remove_user(guac_common_cursor* cursor, - guac_user* user) { - - pthread_mutex_lock(&(cursor->_lock)); - - /* Disassociate from given user */ - if (cursor->user == user) - cursor->user = NULL; - - pthread_mutex_unlock(&(cursor->_lock)); - -} - diff --git a/src/common/display.c b/src/common/display.c deleted file mode 100644 index a17b2ecca..000000000 --- a/src/common/display.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "common/cursor.h" -#include "common/display.h" -#include "common/surface.h" - -#include -#include -#include - -#include -#include -#include - -/** - * Synchronizes all surfaces within the given linked list to the given socket. - * If the provided pointer to the linked list is NULL, this function has no - * effect. - * - * @param layers - * The head element of the linked list of layers to synchronize, which may - * be NULL if the list is currently empty. - * - * @param client - * The client associated with the users receiving the layers. - * - * @param socket - * The socket over which each layer should be sent. - */ -static void guac_common_display_dup_layers(guac_common_display_layer* layers, - guac_client* client, guac_socket* socket) { - - guac_common_display_layer* current = layers; - - /* Synchronize all surfaces in given list */ - while (current != NULL) { - guac_common_surface_dup(current->surface, client, socket); - current = current->next; - } - -} - -/** - * Frees all layers and associated surfaces within the given list, as well as - * their corresponding list elements. If the provided pointer to the linked - * list is NULL, this function has no effect. - * - * @param layers - * The head element of the linked list of layers to free, which may be NULL - * if the list is currently empty. - * - * @param client - * The client owning the layers wrapped by each of the layers in the list. - */ -static void guac_common_display_free_layers(guac_common_display_layer* layers, - guac_client* client) { - - guac_common_display_layer* current = layers; - - /* Free each surface in given list */ - while (current != NULL) { - - guac_common_display_layer* next = current->next; - guac_layer* layer = current->layer; - - /* Free surface */ - guac_common_surface_free(current->surface); - - /* Destroy layer within remotely-connected client */ - guac_protocol_send_dispose(client->socket, layer); - - /* Free layer or buffer depending on index */ - if (layer->index < 0) - guac_client_free_buffer(client, layer); - else if (layer->index > 0) - guac_client_free_layer(client, layer); - - /* Free current element and advance to next */ - guac_mem_free(current); - current = next; - - } - -} - -/** - * Allocates a display and a cursor which are used to represent the remote - * display and cursor. - * - * @param client - * The client owning the cursor. - * - * @param width - * The desired width of the display. - * - * @param height - * The desired height of the display. - * - * @return - * The newly-allocated display or NULL if display cannot be allocated. - */ -guac_common_display* guac_common_display_alloc(guac_client* client, - int width, int height) { - - /* Allocate display */ - guac_common_display* display = guac_mem_alloc(sizeof(guac_common_display)); - if (display == NULL) - return NULL; - - /* Allocate shared cursor */ - display->cursor = guac_common_cursor_alloc(client); - if (display->cursor == NULL) { - guac_mem_free(display); - return NULL; - } - - pthread_mutex_init(&display->_lock, NULL); - - /* Associate display with given client */ - display->client = client; - - display->default_surface = guac_common_surface_alloc(client, - client->socket, GUAC_DEFAULT_LAYER, width, height); - - /* No initial layers or buffers */ - display->layers = NULL; - display->buffers = NULL; - - return display; - -} - -void guac_common_display_free(guac_common_display* display) { - - /* Free shared cursor */ - guac_common_cursor_free(display->cursor); - - /* Free default surface */ - guac_common_surface_free(display->default_surface); - - /* Free all layers and buffers */ - guac_common_display_free_layers(display->buffers, display->client); - guac_common_display_free_layers(display->layers, display->client); - - pthread_mutex_destroy(&display->_lock); - guac_mem_free(display); - -} - -void guac_common_display_dup( - guac_common_display* display, guac_client* client, - guac_socket* socket) { - - pthread_mutex_lock(&display->_lock); - - /* Synchronize shared cursor */ - guac_common_cursor_dup(display->cursor, client, socket); - - /* Synchronize default surface */ - guac_common_surface_dup(display->default_surface, client, socket); - - /* Synchronize all layers and buffers */ - guac_common_display_dup_layers(display->layers, client, socket); - guac_common_display_dup_layers(display->buffers, client, socket); - - /* Sends a sync instruction to mark the boundary of the first frame */ - guac_protocol_send_sync(socket, client->last_sent_timestamp, 1); - - pthread_mutex_unlock(&display->_lock); - -} - -void guac_common_display_fit(int* a, int* b) { - - int a_value = *a; - int b_value = *b; - - /* Ensure first dimension is within allowed range */ - if (a_value < GUAC_COMMON_DISPLAY_MIN_SIZE) { - - /* Adjust other dimension to maintain aspect ratio */ - int adjusted_b = b_value * GUAC_COMMON_DISPLAY_MIN_SIZE / a_value; - if (adjusted_b > GUAC_COMMON_DISPLAY_MAX_SIZE) - adjusted_b = GUAC_COMMON_DISPLAY_MAX_SIZE; - - *a = GUAC_COMMON_DISPLAY_MIN_SIZE; - *b = adjusted_b; - - } - else if (a_value > GUAC_COMMON_DISPLAY_MAX_SIZE) { - - /* Adjust other dimension to maintain aspect ratio */ - int adjusted_b = b_value * GUAC_COMMON_DISPLAY_MAX_SIZE / a_value; - if (adjusted_b < GUAC_COMMON_DISPLAY_MIN_SIZE) - adjusted_b = GUAC_COMMON_DISPLAY_MIN_SIZE; - - *a = GUAC_COMMON_DISPLAY_MAX_SIZE; - *b = adjusted_b; - - } - -} - -void guac_common_display_set_lossless(guac_common_display* display, - int lossless) { - - pthread_mutex_lock(&display->_lock); - - /* Update lossless setting to be applied to all newly-allocated - * layers/buffers */ - display->lossless = lossless; - - /* Update losslessness of all allocated layers/buffers */ - guac_common_display_layer* current = display->layers; - while (current != NULL) { - guac_common_surface_set_lossless(current->surface, lossless); - current = current->next; - } - - /* Update losslessness of default display layer (not included within layers - * list) */ - guac_common_surface_set_lossless(display->default_surface, lossless); - - pthread_mutex_unlock(&display->_lock); - -} - -void guac_common_display_flush(guac_common_display* display) { - - pthread_mutex_lock(&display->_lock); - - guac_common_display_layer* current = display->layers; - - /* Flush all surfaces */ - while (current != NULL) { - guac_common_surface_flush(current->surface); - current = current->next; - } - - guac_common_surface_flush(display->default_surface); - - pthread_mutex_unlock(&display->_lock); - -} - -/** - * Allocates and inserts a new element into the given linked list of display - * layers, associating it with the given layer and surface. - * - * @param head - * A pointer to the head pointer of the list of layers. The head pointer - * will be updated by this function to point to the newly-allocated - * display layer. - * - * @param layer - * The Guacamole layer to associated with the new display layer. - * - * @param surface - * The surface associated with the given Guacamole layer and which should - * be associated with the new display layer. - * - * @return - * The newly-allocated display layer, which has been associated with the - * provided layer and surface. - */ -static guac_common_display_layer* guac_common_display_add_layer( - guac_common_display_layer** head, guac_layer* layer, - guac_common_surface* surface) { - - guac_common_display_layer* old_head = *head; - - guac_common_display_layer* display_layer = - guac_mem_alloc(sizeof(guac_common_display_layer)); - - /* Init layer/surface pair */ - display_layer->layer = layer; - display_layer->surface = surface; - - /* Insert list element as the new head */ - display_layer->prev = NULL; - display_layer->next = old_head; - *head = display_layer; - - /* Update old head to point to new element, if it existed */ - if (old_head != NULL) - old_head->prev = display_layer; - - return display_layer; - -} - -/** - * Removes the given display layer from the linked list whose head pointer is - * provided. - * - * @param head - * A pointer to the head pointer of the list of layers. The head pointer - * will be updated by this function if necessary, and will be set to NULL - * if the display layer being removed is the only layer in the list. - * - * @param display_layer - * The display layer to remove from the given list. - */ -static void guac_common_display_remove_layer(guac_common_display_layer** head, - guac_common_display_layer* display_layer) { - - /* Update previous element, if it exists */ - if (display_layer->prev != NULL) - display_layer->prev->next = display_layer->next; - - /* If there is no previous element, update the list head */ - else - *head = display_layer->next; - - /* Update next element, if it exists */ - if (display_layer->next != NULL) - display_layer->next->prev = display_layer->prev; - -} - -guac_common_display_layer* guac_common_display_alloc_layer( - guac_common_display* display, int width, int height) { - - pthread_mutex_lock(&display->_lock); - - /* Allocate Guacamole layer */ - guac_layer* layer = guac_client_alloc_layer(display->client); - - /* Allocate corresponding surface */ - guac_common_surface* surface = guac_common_surface_alloc(display->client, - display->client->socket, layer, width, height); - - /* Apply current display losslessness */ - guac_common_surface_set_lossless(surface, display->lossless); - - /* Add layer and surface to list */ - guac_common_display_layer* display_layer = - guac_common_display_add_layer(&display->layers, layer, surface); - - pthread_mutex_unlock(&display->_lock); - return display_layer; - -} - -guac_common_display_layer* guac_common_display_alloc_buffer( - guac_common_display* display, int width, int height) { - - pthread_mutex_lock(&display->_lock); - - /* Allocate Guacamole buffer */ - guac_layer* buffer = guac_client_alloc_buffer(display->client); - - /* Allocate corresponding surface */ - guac_common_surface* surface = guac_common_surface_alloc(display->client, - display->client->socket, buffer, width, height); - - /* Apply current display losslessness */ - guac_common_surface_set_lossless(surface, display->lossless); - - /* Add buffer and surface to list */ - guac_common_display_layer* display_layer = - guac_common_display_add_layer(&display->buffers, buffer, surface); - - pthread_mutex_unlock(&display->_lock); - return display_layer; - -} - -void guac_common_display_free_layer(guac_common_display* display, - guac_common_display_layer* display_layer) { - - pthread_mutex_lock(&display->_lock); - - /* Remove list element from list */ - guac_common_display_remove_layer(&display->layers, display_layer); - - /* Free associated layer and surface */ - guac_common_surface_free(display_layer->surface); - guac_client_free_layer(display->client, display_layer->layer); - - /* Free list element */ - guac_mem_free(display_layer); - - pthread_mutex_unlock(&display->_lock); - -} - -void guac_common_display_free_buffer(guac_common_display* display, - guac_common_display_layer* display_buffer) { - - pthread_mutex_lock(&display->_lock); - - /* Remove list element from list */ - guac_common_display_remove_layer(&display->buffers, display_buffer); - - /* Free associated layer and surface */ - guac_common_surface_free(display_buffer->surface); - guac_client_free_buffer(display->client, display_buffer->layer); - - /* Free list element */ - guac_mem_free(display_buffer); - - pthread_mutex_unlock(&display->_lock); - -} diff --git a/src/common/dot_cursor.c b/src/common/dot_cursor.c deleted file mode 100644 index fde79b01a..000000000 --- a/src/common/dot_cursor.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -/* Macros for prettying up the embedded image. */ -#define X 0x00,0x00,0x00,0xFF -#define O 0xFF,0xFF,0xFF,0xFF -#define _ 0x00,0x00,0x00,0x00 - -/* Dimensions */ -const int guac_common_dot_cursor_width = 5; -const int guac_common_dot_cursor_height = 5; - -/* Format */ -const cairo_format_t guac_common_dot_cursor_format = CAIRO_FORMAT_ARGB32; -const int guac_common_dot_cursor_stride = 20; - -/* Embedded pointer graphic */ -unsigned char guac_common_dot_cursor[] = { - - _,O,O,O,_, - O,X,X,X,O, - O,X,X,X,O, - O,X,X,X,O, - _,O,O,O,_ - -}; - -void guac_common_set_dot_cursor(guac_user* user) { - - guac_client* client = user->client; - guac_socket* socket = user->socket; - - /* Draw to buffer */ - guac_layer* cursor = guac_client_alloc_buffer(client); - - cairo_surface_t* graphic = cairo_image_surface_create_for_data( - guac_common_dot_cursor, - guac_common_dot_cursor_format, - guac_common_dot_cursor_width, - guac_common_dot_cursor_height, - guac_common_dot_cursor_stride); - - guac_user_stream_png(user, socket, GUAC_COMP_SRC, cursor, - 0, 0, graphic); - cairo_surface_destroy(graphic); - - /* Set cursor */ - guac_protocol_send_cursor(socket, 2, 2, cursor, - 0, 0, - guac_common_dot_cursor_width, - guac_common_dot_cursor_height); - - /* Free buffer */ - guac_client_free_buffer(client, cursor); - - guac_client_log(client, GUAC_LOG_DEBUG, - "Client cursor image set to generic built-in dot."); - -} - diff --git a/src/common/ibar_cursor.c b/src/common/ibar_cursor.c deleted file mode 100644 index 6494591bc..000000000 --- a/src/common/ibar_cursor.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -/* Macros for prettying up the embedded image. */ -#define X 0x00,0x00,0x00,0xFF -#define U 0x80,0x80,0x80,0xFF -#define O 0xFF,0xFF,0xFF,0xFF -#define _ 0x00,0x00,0x00,0x00 - -/* Dimensions */ -const int guac_common_ibar_cursor_width = 7; -const int guac_common_ibar_cursor_height = 16; - -/* Format */ -const cairo_format_t guac_common_ibar_cursor_format = CAIRO_FORMAT_ARGB32; -const int guac_common_ibar_cursor_stride = 28; - -/* Embedded I-bar graphic */ -unsigned char guac_common_ibar_cursor[] = { - - X,X,X,X,X,X,X, - X,O,O,U,O,O,X, - X,X,X,O,X,X,X, - _,_,X,O,X,_,_, - _,_,X,O,X,_,_, - _,_,X,O,X,_,_, - _,_,X,O,X,_,_, - _,_,X,O,X,_,_, - _,_,X,O,X,_,_, - _,_,X,O,X,_,_, - _,_,X,O,X,_,_, - _,_,X,O,X,_,_, - _,_,X,O,X,_,_, - X,X,X,O,X,X,X, - X,O,O,U,O,O,X, - X,X,X,X,X,X,X - -}; - -void guac_common_set_ibar_cursor(guac_user* user) { - - guac_client* client = user->client; - guac_socket* socket = user->socket; - - /* Draw to buffer */ - guac_layer* cursor = guac_client_alloc_buffer(client); - - cairo_surface_t* graphic = cairo_image_surface_create_for_data( - guac_common_ibar_cursor, - guac_common_ibar_cursor_format, - guac_common_ibar_cursor_width, - guac_common_ibar_cursor_height, - guac_common_ibar_cursor_stride); - - guac_user_stream_png(user, socket, GUAC_COMP_SRC, cursor, - 0, 0, graphic); - cairo_surface_destroy(graphic); - - /* Set cursor */ - guac_protocol_send_cursor(socket, 0, 0, cursor, - guac_common_ibar_cursor_width / 2, - guac_common_ibar_cursor_height / 2, - guac_common_ibar_cursor_width, - guac_common_ibar_cursor_height); - - /* Free buffer */ - guac_client_free_buffer(client, cursor); - - guac_client_log(client, GUAC_LOG_DEBUG, - "Client cursor image set to generic built-in I-bar."); - -} - diff --git a/src/common/pointer_cursor.c b/src/common/pointer_cursor.c deleted file mode 100644 index fbcb60230..000000000 --- a/src/common/pointer_cursor.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -/* Macros for prettying up the embedded image. */ -#define X 0x00,0x00,0x00,0xFF -#define O 0xFF,0xFF,0xFF,0xFF -#define _ 0x00,0x00,0x00,0x00 - -/* Dimensions */ -const int guac_common_pointer_cursor_width = 11; -const int guac_common_pointer_cursor_height = 16; - -/* Format */ -const cairo_format_t guac_common_pointer_cursor_format = CAIRO_FORMAT_ARGB32; -const int guac_common_pointer_cursor_stride = 44; - -/* Embedded pointer graphic */ -unsigned char guac_common_pointer_cursor[] = { - - O,_,_,_,_,_,_,_,_,_,_, - O,O,_,_,_,_,_,_,_,_,_, - O,X,O,_,_,_,_,_,_,_,_, - O,X,X,O,_,_,_,_,_,_,_, - O,X,X,X,O,_,_,_,_,_,_, - O,X,X,X,X,O,_,_,_,_,_, - O,X,X,X,X,X,O,_,_,_,_, - O,X,X,X,X,X,X,O,_,_,_, - O,X,X,X,X,X,X,X,O,_,_, - O,X,X,X,X,X,X,X,X,O,_, - O,X,X,X,X,X,O,O,O,O,O, - O,X,X,O,X,X,O,_,_,_,_, - O,X,O,_,O,X,X,O,_,_,_, - O,O,_,_,O,X,X,O,_,_,_, - O,_,_,_,_,O,X,X,O,_,_, - _,_,_,_,_,O,O,O,O,_,_ - -}; - -void guac_common_set_pointer_cursor(guac_user* user) { - - guac_client* client = user->client; - guac_socket* socket = user->socket; - - /* Draw to buffer */ - guac_layer* cursor = guac_client_alloc_buffer(client); - - cairo_surface_t* graphic = cairo_image_surface_create_for_data( - guac_common_pointer_cursor, - guac_common_pointer_cursor_format, - guac_common_pointer_cursor_width, - guac_common_pointer_cursor_height, - guac_common_pointer_cursor_stride); - - guac_user_stream_png(user, socket, GUAC_COMP_SRC, cursor, - 0, 0, graphic); - cairo_surface_destroy(graphic); - - /* Set cursor */ - guac_protocol_send_cursor(socket, 0, 0, cursor, - 0, 0, - guac_common_pointer_cursor_width, - guac_common_pointer_cursor_height); - - /* Free buffer */ - guac_client_free_buffer(client, cursor); - - guac_client_log(client, GUAC_LOG_DEBUG, - "Client cursor image set to generic built-in pointer."); - -} - diff --git a/src/common/rect.c b/src/common/rect.c deleted file mode 100644 index a7ca7da52..000000000 --- a/src/common/rect.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "config.h" -#include "common/rect.h" - -void guac_common_rect_init(guac_common_rect* rect, int x, int y, int width, int height) { - rect->x = x; - rect->y = y; - rect->width = width; - rect->height = height; -} - -void guac_common_rect_extend(guac_common_rect* rect, const guac_common_rect* min) { - - /* Calculate extents of existing dirty rect */ - int left = rect->x; - int top = rect->y; - int right = left + rect->width; - int bottom = top + rect->height; - - /* Calculate missing extents of given new rect */ - int min_left = min->x; - int min_top = min->y; - int min_right = min_left + min->width; - int min_bottom = min_top + min->height; - - /* Update minimums */ - if (min_left < left) left = min_left; - if (min_top < top) top = min_top; - if (min_right > right) right = min_right; - if (min_bottom > bottom) bottom = min_bottom; - - /* Commit rect */ - guac_common_rect_init(rect, left, top, right - left, bottom - top); - -} - -void guac_common_rect_constrain(guac_common_rect* rect, const guac_common_rect* max) { - - /* Calculate extents of existing dirty rect */ - int left = rect->x; - int top = rect->y; - int right = left + rect->width; - int bottom = top + rect->height; - - /* Calculate missing extents of given new rect */ - int max_left = max->x; - int max_top = max->y; - int max_right = max_left + max->width; - int max_bottom = max_top + max->height; - - /* Update maximums */ - if (max_left > left) left = max_left; - if (max_top > top) top = max_top; - if (max_right < right) right = max_right; - if (max_bottom < bottom) bottom = max_bottom; - - /* Commit rect */ - guac_common_rect_init(rect, left, top, right - left, bottom - top); - -} - -int guac_common_rect_expand_to_grid(int cell_size, guac_common_rect* rect, - const guac_common_rect* max_rect) { - - /* Invalid cell_size received */ - if (cell_size <= 0) - return -1; - - /* Nothing to do */ - if (cell_size == 1) - return 0; - - /* Calculate how much the rectangle must be adjusted to fit within the - * given cell size. */ - int dw = cell_size - rect->width % cell_size; - int dh = cell_size - rect->height % cell_size; - - int dx = dw / 2; - int dy = dh / 2; - - /* Set initial extents of adjusted rectangle. */ - int top = rect->y - dy; - int left = rect->x - dx; - int bottom = top + rect->height + dh; - int right = left + rect->width + dw; - - /* The max rectangle */ - int max_left = max_rect->x; - int max_top = max_rect->y; - int max_right = max_left + max_rect->width; - int max_bottom = max_top + max_rect->height; - - /* If the adjusted rectangle has sides beyond the max rectangle, or is larger - * in any direction; shift or adjust the rectangle while trying to fit in - * the grid */ - - /* Adjust left/right */ - if (right > max_right) { - - /* shift to left */ - dw = right - max_right; - right -= dw; - left -= dw; - - /* clamp left if too far */ - if (left < max_left) { - left = max_left; - } - } - else if (left < max_left) { - - /* shift to right */ - dw = max_left - left; - left += dw; - right += dw; - - /* clamp right if too far */ - if (right > max_right) { - right = max_right; - } - } - - /* Adjust top/bottom */ - if (bottom > max_bottom) { - - /* shift up */ - dh = bottom - max_bottom; - bottom -= dh; - top -= dh; - - /* clamp top if too far */ - if (top < max_top) { - top = max_top; - } - } - else if (top < max_top) { - - /* shift down */ - dh = max_top - top; - top += dh; - bottom += dh; - - /* clamp bottom if too far */ - if (bottom > max_bottom) { - bottom = max_bottom; - } - } - - /* Commit rect */ - guac_common_rect_init(rect, left, top, right - left, bottom - top); - - return 0; - -} - -int guac_common_rect_intersects(const guac_common_rect* rect, - const guac_common_rect* other) { - - /* Empty (no intersection) */ - if (other->x + other->width < rect->x || rect->x + rect->width < other->x || - other->y + other->height < rect->y || rect->y + rect->height < other->y) { - return 0; - } - /* Complete */ - else if (other->x <= rect->x && (other->x + other->width) >= (rect->x + rect->width) && - other->y <= rect->y && (other->y + other->height) >= (rect->y + rect->height)) { - return 2; - } - /* Partial intersection */ - return 1; - -} - -int guac_common_rect_clip_and_split(guac_common_rect* rect, - const guac_common_rect* hole, guac_common_rect* split_rect) { - - /* Only continue if the rectangles intersects */ - if (!guac_common_rect_intersects(rect, hole)) - return 0; - - int top, left, bottom, right; - - /* Clip and split top */ - if (rect->y < hole->y) { - top = rect->y; - left = rect->x; - bottom = hole->y; - right = rect->x + rect->width; - guac_common_rect_init(split_rect, left, top, right - left, bottom - top); - - /* Re-initialize original rect */ - top = hole->y; - bottom = rect->y + rect->height; - guac_common_rect_init(rect, left, top, right - left, bottom - top); - - return 1; - } - - /* Clip and split left */ - else if (rect->x < hole->x) { - top = rect->y; - left = rect->x; - bottom = rect->y + rect->height; - right = hole->x; - guac_common_rect_init(split_rect, left, top, right - left, bottom - top); - - /* Re-initialize original rect */ - left = hole->x; - right = rect->x + rect->width; - guac_common_rect_init(rect, left, top, right - left, bottom - top); - - return 1; - } - - /* Clip and split bottom */ - else if (rect->y + rect->height > hole->y + hole->height) { - top = hole->y + hole->height; - left = rect->x; - bottom = rect->y + rect->height; - right = rect->x + rect->width; - guac_common_rect_init(split_rect, left, top, right - left, bottom - top); - - /* Re-initialize original rect */ - top = rect->y; - bottom = hole->y + hole->height; - guac_common_rect_init(rect, left, top, right - left, bottom - top); - - return 1; - } - - /* Clip and split right */ - else if (rect->x + rect->width > hole->x + hole->width) { - top = rect->y; - left = hole->x + hole->width; - bottom = rect->y + rect->height; - right = rect->x + rect->width; - guac_common_rect_init(split_rect, left, top, right - left, bottom - top); - - /* Re-initialize original rect */ - left = rect->x; - right = hole->x + hole->width; - guac_common_rect_init(rect, left, top, right - left, bottom - top); - - return 1; - } - - return 0; -} diff --git a/src/common/surface.c b/src/common/surface.c deleted file mode 100644 index 3ec5517e9..000000000 --- a/src/common/surface.c +++ /dev/null @@ -1,2041 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "config.h" -#include "common/rect.h" -#include "common/surface.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/** - * The width of an update which should be considered negible and thus - * trivial overhead compared ot the cost of two updates. - */ -#define GUAC_SURFACE_NEGLIGIBLE_WIDTH 64 - -/** - * The height of an update which should be considered negible and thus - * trivial overhead compared ot the cost of two updates. - */ -#define GUAC_SURFACE_NEGLIGIBLE_HEIGHT 64 - -/** - * The proportional increase in cost contributed by transfer and processing of - * image data, compared to processing an equivalent amount of client-side - * data. - */ -#define GUAC_SURFACE_DATA_FACTOR 16 - -/** - * The base cost of every update. Each update should be considered to have - * this starting cost, plus any additional cost estimated from its - * content. - */ -#define GUAC_SURFACE_BASE_COST 4096 - -/** - * An increase in cost is negligible if it is less than - * 1/GUAC_SURFACE_NEGLIGIBLE_INCREASE of the old cost. - */ -#define GUAC_SURFACE_NEGLIGIBLE_INCREASE 4 - -/** - * If combining an update because it appears to be follow a fill pattern, - * the combined cost must not exceed - * GUAC_SURFACE_FILL_PATTERN_FACTOR * (total uncombined cost). - */ -#define GUAC_SURFACE_FILL_PATTERN_FACTOR 3 - -/* Define cairo_format_stride_for_width() if missing */ -#ifndef HAVE_CAIRO_FORMAT_STRIDE_FOR_WIDTH -#define cairo_format_stride_for_width(format, width) (width*4) -#endif - -/** - * The framerate which, if exceeded, indicates that JPEG is preferred. - */ -#define GUAC_COMMON_SURFACE_JPEG_FRAMERATE 3 - -/** - * Minimum JPEG bitmap size (area). If the bitmap is smaller than this threshold, - * it should be compressed as a PNG image to avoid the JPEG compression tax. - */ -#define GUAC_SURFACE_JPEG_MIN_BITMAP_SIZE 4096 - -/** - * The JPEG compression min block size. This defines the optimal rectangle block - * size factor for JPEG compression. Usually 8x8 would suffice, but use 16 to - * reduce the occurrence of ringing artifacts further. - */ -#define GUAC_SURFACE_JPEG_BLOCK_SIZE 16 - -/** - * The WebP compression min block size. This defines the optimal rectangle block - * size factor for WebP compression. WebP does utilize variable block size, but - * ensuring a block size factor reduces any noise on the image edges. - */ -#define GUAC_SURFACE_WEBP_BLOCK_SIZE 8 - -void guac_common_surface_set_multitouch(guac_common_surface* surface, - int touches) { - - pthread_mutex_lock(&surface->_lock); - - surface->touches = touches; - guac_protocol_send_set_int(surface->socket, surface->layer, - GUAC_PROTOCOL_LAYER_PARAMETER_MULTI_TOUCH, touches); - - pthread_mutex_unlock(&surface->_lock); - -} - -void guac_common_surface_set_lossless(guac_common_surface* surface, - int lossless) { - - pthread_mutex_lock(&surface->_lock); - surface->lossless = lossless; - pthread_mutex_unlock(&surface->_lock); - -} - -void guac_common_surface_move(guac_common_surface* surface, int x, int y) { - - pthread_mutex_lock(&surface->_lock); - - surface->x = x; - surface->y = y; - surface->location_dirty = 1; - - pthread_mutex_unlock(&surface->_lock); - -} - -void guac_common_surface_stack(guac_common_surface* surface, int z) { - - pthread_mutex_lock(&surface->_lock); - - surface->z = z; - surface->location_dirty = 1; - - pthread_mutex_unlock(&surface->_lock); - -} - -void guac_common_surface_set_parent(guac_common_surface* surface, - const guac_layer* parent) { - - pthread_mutex_lock(&surface->_lock); - - surface->parent = parent; - surface->location_dirty = 1; - - pthread_mutex_unlock(&surface->_lock); - -} - -void guac_common_surface_set_opacity(guac_common_surface* surface, - int opacity) { - - pthread_mutex_lock(&surface->_lock); - - surface->opacity = opacity; - surface->opacity_dirty = 1; - - pthread_mutex_unlock(&surface->_lock); - -} - -/** - * Updates the coordinates of the given rectangle to be within the bounds of - * the given surface. - * - * @param surface The surface to use for clipping. - * @param rect The rectangle to clip. - * @param sx The X coordinate of the source rectangle, if any. - * @param sy The Y coordinate of the source rectangle, if any. - */ -static void __guac_common_bound_rect(guac_common_surface* surface, - guac_common_rect* rect, int* sx, int* sy) { - - guac_common_rect bounds_rect = { - .x = 0, - .y = 0, - .width = surface->width, - .height = surface->height - }; - - int orig_x = rect->x; - int orig_y = rect->y; - - guac_common_rect_constrain(rect, &bounds_rect); - - /* Update source X/Y if given */ - if (sx != NULL) *sx += rect->x - orig_x; - if (sy != NULL) *sy += rect->y - orig_y; - -} - -/** - * Updates the coordinates of the given rectangle to be within the clipping - * rectangle of the given surface, which must always be within the bounding - * rectangle of the given surface. - * - * @param surface The surface to use for clipping. - * @param rect The rectangle to clip. - * @param sx The X coordinate of the source rectangle, if any. - * @param sy The Y coordinate of the source rectangle, if any. - */ -static void __guac_common_clip_rect(guac_common_surface* surface, - guac_common_rect* rect, int* sx, int* sy) { - - int orig_x = rect->x; - int orig_y = rect->y; - - /* Just bound within surface if no clipping rectangle applied */ - if (!surface->clipped) { - __guac_common_bound_rect(surface, rect, sx, sy); - return; - } - - guac_common_rect_constrain(rect, &surface->clip_rect); - - /* Update source X/Y if given */ - if (sx != NULL) *sx += rect->x - orig_x; - if (sy != NULL) *sy += rect->y - orig_y; - -} - -/** - * 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 image data, or would be best - * kept independent of the current rectangle. - * - * @param surface - * The surface being updated. - * - * @param rect - * The bounding rectangle of the update being made to the surface. - * - * @param rect_only - * Non-zero if this update, by its nature, contains only metainformation - * about the update's bounding rectangle, zero if the update also contains - * image data. - * - * @return - * Non-zero if the update should be combined with any existing update, zero - * otherwise. - */ -static int __guac_common_should_combine(guac_common_surface* surface, const guac_common_rect* rect, int rect_only) { - - /* Always favor combining updates if surface is currently a purely - * server-side scratch area */ - if (!surface->realized) - return 1; - - if (surface->dirty) { - - int combined_cost, dirty_cost, update_cost; - - /* Simulate combination */ - guac_common_rect combined = surface->dirty_rect; - guac_common_rect_extend(&combined, rect); - - /* Combine if result is still small */ - if (combined.width <= GUAC_SURFACE_NEGLIGIBLE_WIDTH && combined.height <= GUAC_SURFACE_NEGLIGIBLE_HEIGHT) - return 1; - - /* Estimate costs of the existing update, new update, and both combined */ - combined_cost = GUAC_SURFACE_BASE_COST + combined.width * combined.height; - dirty_cost = GUAC_SURFACE_BASE_COST + surface->dirty_rect.width * surface->dirty_rect.height; - update_cost = GUAC_SURFACE_BASE_COST + rect->width * rect->height; - - /* Reduce cost if no image data */ - if (rect_only) - update_cost /= GUAC_SURFACE_DATA_FACTOR; - - /* Combine if cost estimate shows benefit */ - if (combined_cost <= update_cost + dirty_cost) - return 1; - - /* Combine if increase in cost is negligible */ - if (combined_cost - dirty_cost <= dirty_cost / GUAC_SURFACE_NEGLIGIBLE_INCREASE) - return 1; - - if (combined_cost - update_cost <= update_cost / GUAC_SURFACE_NEGLIGIBLE_INCREASE) - return 1; - - /* Combine if we anticipate further updates, as this update follows a common fill pattern */ - if (rect->x == surface->dirty_rect.x && rect->y == surface->dirty_rect.y + surface->dirty_rect.height) { - if (combined_cost <= (dirty_cost + update_cost) * GUAC_SURFACE_FILL_PATTERN_FACTOR) - return 1; - } - - } - - /* Otherwise, do not combine */ - return 0; - -} - -/** - * Expands the dirty rect of the given surface to contain the rect described by the given - * coordinates. - * - * @param surface The surface to mark as dirty. - * @param rect The rectangle of the update which is dirtying the surface. - */ -static void __guac_common_mark_dirty(guac_common_surface* surface, const guac_common_rect* rect) { - - /* Ignore empty rects */ - if (rect->width <= 0 || rect->height <= 0) - return; - - /* If already dirty, update existing rect */ - if (surface->dirty) - guac_common_rect_extend(&surface->dirty_rect, rect); - - /* Otherwise init dirty rect */ - else { - surface->dirty_rect = *rect; - surface->dirty = 1; - } - -} - -/** - * Calculate the current average framerate for a given area on the surface. - * - * @param surface - * The surface on which the framerate will be calculated. - * - * @param rect - * The rect containing the area for which the average framerate will be - * calculated. - * - * @return - * The average framerate of the given area, in frames per second. - */ -static unsigned int __guac_common_surface_calculate_framerate( - guac_common_surface* surface, const guac_common_rect* rect) { - - int x, y; - - /* Calculate heat map dimensions */ - size_t heat_width = GUAC_COMMON_SURFACE_HEAT_DIMENSION(surface->width); - - /* Calculate minimum X/Y coordinates intersecting given rect */ - int min_x = rect->x / GUAC_COMMON_SURFACE_HEAT_CELL_SIZE; - int min_y = rect->y / GUAC_COMMON_SURFACE_HEAT_CELL_SIZE; - - /* Calculate maximum X/Y coordinates intersecting given rect */ - int max_x = min_x + (rect->width - 1) / GUAC_COMMON_SURFACE_HEAT_CELL_SIZE; - int max_y = min_y + (rect->height - 1) / GUAC_COMMON_SURFACE_HEAT_CELL_SIZE; - - unsigned int sum_framerate = 0; - unsigned int count = 0; - - /* Get start of buffer at given coordinates */ - const guac_common_surface_heat_cell* heat_row = - surface->heat_map + min_y * heat_width + min_x; - - /* Iterate over all the heat map cells for the area - * and calculate the average framerate */ - for (y = min_y; y < max_y; y++) { - - /* Get current row of heat map */ - const guac_common_surface_heat_cell* heat_cell = heat_row; - - /* For each cell in subset of row */ - for (x = min_x; x < max_x; x++) { - - /* Calculate indicies for latest and oldest history entries */ - int oldest_entry = heat_cell->oldest_entry; - int latest_entry = oldest_entry - 1; - if (latest_entry < 0) - latest_entry = GUAC_COMMON_SURFACE_HEAT_CELL_HISTORY_SIZE - 1; - - /* Calculate elapsed time covering entire history for this cell */ - int elapsed_time = heat_cell->history[latest_entry] - - heat_cell->history[oldest_entry]; - - /* Calculate and add framerate */ - if (elapsed_time) - sum_framerate += GUAC_COMMON_SURFACE_HEAT_CELL_HISTORY_SIZE - * 1000 / elapsed_time; - - /* Next heat map cell */ - heat_cell++; - count++; - - } - - /* Next heat map row */ - heat_row += heat_width; - - } - - /* Calculate the average framerate over entire rect */ - if (count) - return sum_framerate / count; - - return 0; - -} - - /** - * Guesses whether a rectangle within a particular surface would be better - * compressed as PNG or using a lossy format like JPEG. Positive values - * indicate PNG is likely to be superior, while negative values indicate the - * opposite. - * - * @param surface - * The surface containing the image data to check. - * - * @param rect - * The rect to check within the given surface. - * - * @return - * Positive values if PNG compression is likely to perform better than - * lossy alternatives, or negative values if PNG is likely to perform - * worse. - */ -static int __guac_common_surface_png_optimality(guac_common_surface* surface, - const guac_common_rect* rect) { - - int x, y; - - int num_same = 0; - int num_different = 1; - - /* Get image/buffer metrics */ - int width = rect->width; - int height = rect->height; - int stride = surface->stride; - - /* Get buffer from surface */ - unsigned char* buffer = surface->buffer + rect->y * stride + rect->x * 4; - - /* Image must be at least 1x1 */ - if (width < 1 || height < 1) - return 0; - - /* For each row */ - for (y = 0; y < height; y++) { - - uint32_t* row = (uint32_t*) buffer; - uint32_t last_pixel = *(row++) | 0xFF000000; - - /* For each pixel in current row */ - for (x = 1; x < width; x++) { - - /* Get next pixel */ - uint32_t current_pixel = *(row++) | 0xFF000000; - - /* Update same/different counts according to pixel value */ - if (current_pixel == last_pixel) - num_same++; - else - num_different++; - - last_pixel = current_pixel; - - } - - /* Advance to next row */ - buffer += stride; - - } - - /* Return rough approximation of optimality for PNG compression */ - return 0x100 * num_same / num_different - 0x400; - -} - -/** - * Returns whether the given rectangle would be optimally encoded as JPEG - * rather than PNG. - * - * @param surface - * The surface to be queried. - * - * @param rect - * The rectangle to check. - * - * @return - * Non-zero if the rectangle would be optimally encoded as JPEG, zero - * otherwise. - */ -static int __guac_common_surface_should_use_jpeg(guac_common_surface* surface, - const guac_common_rect* rect) { - - /* Do not use JPEG if lossless quality is required */ - if (surface->lossless) - return 0; - - /* Calculate the average framerate for the given rect */ - int framerate = __guac_common_surface_calculate_framerate(surface, rect); - - int rect_size = rect->width * rect->height; - - /* JPEG is preferred if: - * - frame rate is high enough - * - image size is large enough - * - PNG is not more optimal based on image contents */ - return framerate >= GUAC_COMMON_SURFACE_JPEG_FRAMERATE - && rect_size > GUAC_SURFACE_JPEG_MIN_BITMAP_SIZE - && __guac_common_surface_png_optimality(surface, rect) < 0; - -} - -/** - * Returns whether the given rectangle would be optimally encoded as WebP - * rather than PNG. - * - * @param surface - * The surface to be queried. - * - * @param rect - * The rectangle to check. - * - * @return - * Non-zero if the rectangle would be optimally encoded as WebP, zero - * otherwise. - */ -static int __guac_common_surface_should_use_webp(guac_common_surface* surface, - const guac_common_rect* rect) { - - /* Do not use WebP if not supported */ - if (!guac_client_supports_webp(surface->client)) - return 0; - - /* Calculate the average framerate for the given rect */ - int framerate = __guac_common_surface_calculate_framerate(surface, rect); - - /* WebP is preferred if: - * - frame rate is high enough - * - PNG is not more optimal based on image contents */ - return framerate >= GUAC_COMMON_SURFACE_JPEG_FRAMERATE - && __guac_common_surface_png_optimality(surface, rect) < 0; - -} - -/** - * Updates the heat map cells which intersect the given rectangle using the - * given timestamp. This timestamp, along with timestamps from past updates, - * is used to calculate the framerate of each heat cell. - * - * @param surface - * The surface containing the heat map cells to be updated. - * - * @param rect - * The rectangle containing the heat map cells to be updated. - * - * @param time - * The timestamp to use when updating the heat map cells which intersect - * the given rectangle. - */ -static void __guac_common_surface_touch_rect(guac_common_surface* surface, - guac_common_rect* rect, guac_timestamp time) { - - int x, y; - - /* Calculate heat map dimensions */ - size_t heat_width = GUAC_COMMON_SURFACE_HEAT_DIMENSION(surface->width); - - /* Calculate minimum X/Y coordinates intersecting given rect */ - int min_x = rect->x / GUAC_COMMON_SURFACE_HEAT_CELL_SIZE; - int min_y = rect->y / GUAC_COMMON_SURFACE_HEAT_CELL_SIZE; - - /* Calculate maximum X/Y coordinates intersecting given rect */ - int max_x = min_x + (rect->width - 1) / GUAC_COMMON_SURFACE_HEAT_CELL_SIZE; - int max_y = min_y + (rect->height - 1) / GUAC_COMMON_SURFACE_HEAT_CELL_SIZE; - - /* Get start of buffer at given coordinates */ - guac_common_surface_heat_cell* heat_row = - surface->heat_map + min_y * heat_width + min_x; - - /* Update all heat map cells which intersect with rectangle */ - for (y = min_y; y <= max_y; y++) { - - /* Get current row of heat map */ - guac_common_surface_heat_cell* heat_cell = heat_row; - - /* For each cell in subset of row */ - for (x = min_x; x <= max_x; x++) { - - /* Replace oldest entry with new timestamp */ - heat_cell->history[heat_cell->oldest_entry] = time; - - /* Update to next oldest entry */ - heat_cell->oldest_entry++; - if (heat_cell->oldest_entry >= - GUAC_COMMON_SURFACE_HEAT_CELL_HISTORY_SIZE) - heat_cell->oldest_entry = 0; - - /* Advance to next heat map cell */ - heat_cell++; - - } - - /* Next heat map row */ - heat_row += heat_width; - - } - -} - -/** - * Flushes the bitmap update currently described by the dirty rectangle within the - * given surface to that surface's bitmap queue. There MUST be space within the - * queue. - * - * @param surface The surface to flush. - */ -static void __guac_common_surface_flush_to_queue(guac_common_surface* surface) { - - guac_common_surface_bitmap_rect* rect; - - /* Do not flush if not dirty */ - if (!surface->dirty) - return; - - /* Add new rect to queue */ - rect = &(surface->bitmap_queue[surface->bitmap_queue_length++]); - rect->rect = surface->dirty_rect; - rect->flushed = 0; - - /* Surface now flushed */ - surface->dirty = 0; - -} - -/** - * Flushes the given surface, drawing any pending operations on the remote - * display. Surface properties are not flushed. - * - * @param surface - * The surface to flush. - */ -static void __guac_common_surface_flush(guac_common_surface* surface); - -/** - * Schedules a deferred flush of the given surface. This will not immediately - * flush the surface to the client. Instead, the result of the flush is - * added to a queue which is reinspected and combined (if possible) with other - * deferred flushes during the call to guac_common_surface_flush(). - * - * @param surface The surface to flush. - */ -static void __guac_common_surface_flush_deferred(guac_common_surface* surface) { - - /* Do not flush if not dirty */ - if (!surface->dirty) - return; - - /* Flush if queue size has reached maximum (space is reserved for the final - * dirty rect, as __guac_common_surface_flush() MAY add an additional rect - * to the queue */ - if (surface->bitmap_queue_length == GUAC_COMMON_SURFACE_QUEUE_SIZE-1) - __guac_common_surface_flush(surface); - - /* Append dirty rect to queue */ - __guac_common_surface_flush_to_queue(surface); - -} - -/** - * Transfers a single uint32_t using the given transfer function. - * - * @param op The transfer function to use. - * @param src The source of the uint32_t value. - * @param dst THe destination which will hold the result of the transfer. - * @return Non-zero if the destination value was changed, zero otherwise. - */ -static int __guac_common_surface_transfer_int(guac_transfer_function op, uint32_t* src, uint32_t* dst) { - - uint32_t orig = *dst; - - switch (op) { - - case GUAC_TRANSFER_BINARY_BLACK: - *dst = 0xFF000000; - break; - - case GUAC_TRANSFER_BINARY_WHITE: - *dst = 0xFFFFFFFF; - break; - - case GUAC_TRANSFER_BINARY_SRC: - *dst = *src; - break; - - case GUAC_TRANSFER_BINARY_DEST: - /* NOP */ - break; - - case GUAC_TRANSFER_BINARY_NSRC: - *dst = *src ^ 0x00FFFFFF; - break; - - case GUAC_TRANSFER_BINARY_NDEST: - *dst = *dst ^ 0x00FFFFFF; - break; - - case GUAC_TRANSFER_BINARY_AND: - *dst = ((*dst) & (0xFF000000 | *src)); - break; - - case GUAC_TRANSFER_BINARY_NAND: - *dst = ((*dst) & (0xFF000000 | *src)) ^ 0x00FFFFFF; - break; - - case GUAC_TRANSFER_BINARY_OR: - *dst = ((*dst) | (0x00FFFFFF & *src)); - break; - - case GUAC_TRANSFER_BINARY_NOR: - *dst = ((*dst) | (0x00FFFFFF & *src)) ^ 0x00FFFFFF; - break; - - case GUAC_TRANSFER_BINARY_XOR: - *dst = ((*dst) ^ (0x00FFFFFF & *src)); - break; - - case GUAC_TRANSFER_BINARY_XNOR: - *dst = ((*dst) ^ (0x00FFFFFF & *src)) ^ 0x00FFFFFF; - break; - - case GUAC_TRANSFER_BINARY_NSRC_AND: - *dst = ((*dst) & (0xFF000000 | (*src ^ 0x00FFFFFF))); - break; - - case GUAC_TRANSFER_BINARY_NSRC_NAND: - *dst = ((*dst) & (0xFF000000 | (*src ^ 0x00FFFFFF))) ^ 0x00FFFFFF; - break; - - case GUAC_TRANSFER_BINARY_NSRC_OR: - *dst = ((*dst) | (0x00FFFFFF & (*src ^ 0x00FFFFFF))); - break; - - case GUAC_TRANSFER_BINARY_NSRC_NOR: - *dst = ((*dst) | (0x00FFFFFF & (*src ^ 0x00FFFFFF))) ^ 0x00FFFFFF; - break; - - } - - return *dst != orig; - -} - -/** - * 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 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_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 = (alpha << 24) | (red << 16) | (green << 8) | blue; - - int min_x = rect->width - 1; - int min_y = rect->height - 1; - int max_x = 0; - int max_y = 0; - - dst_stride = dst->stride; - dst_buffer = dst->buffer + (dst_stride * rect->y) + (4 * rect->x); - - /* For each row */ - for (y=0; y < rect->height; y++) { - - uint32_t* dst_current = (uint32_t*) dst_buffer; - - /* Set row */ - for (x=0; x < rect->width; x++) { - - uint32_t old_color = *dst_current; - - if (old_color != color) { - if (x < min_x) min_x = x; - if (y < min_y) min_y = y; - if (x > max_x) max_x = x; - if (y > max_y) max_y = y; - *dst_current = color; - } - - dst_current++; - } - - /* Next row */ - dst_buffer += dst_stride; - - } - - /* Restrict destination rect to only updated pixels */ - if (max_x >= min_x && max_y >= min_y) { - rect->x += min_x; - rect->y += min_y; - rect->width = max_x - min_x + 1; - rect->height = max_y - min_y + 1; - } - else { - rect->width = 0; - rect->height = 0; - } - -} - -/** - * Applies the Porter-Duff "over" composite operator, blending the two given - * color components using the given alpha value. - * - * @param dst - * The destination color component. - * - * @param src - * The source color component. - * - * @param alpha - * The alpha value which applies to the blending operation. - * - * @return - * The result of applying the Porter-Duff "over" composite operator to the - * given source and destination components. - */ -static int guac_common_surface_blend_component(int dst, int src, int alpha) { - - int blended = src + dst * (0xFF - alpha); - - /* Do not exceed maximum component value */ - if (blended > 0xFF) - return 0xFF; - - return blended; - -} - -/** - * Applies the Porter-Duff "over" composite operator, blending each component - * of the two given ARGB colors. - * - * @param dst - * The destination ARGB color. - * - * @param src - * The source ARGB color. - * - * @return - * The result of applying the Porter-Duff "over" composite operator to the - * given source and destination colors. - */ -static uint32_t guac_common_surface_argb_blend(uint32_t dst, uint32_t src) { - - /* Separate destination ARGB color into its components */ - int dst_a = (dst >> 24) & 0xFF; - int dst_r = (dst >> 16) & 0xFF; - int dst_g = (dst >> 8) & 0xFF; - int dst_b = dst & 0xFF; - - /* Separate source ARGB color into its components */ - int src_a = (src >> 24) & 0xFF; - int src_r = (src >> 16) & 0xFF; - int src_g = (src >> 8) & 0xFF; - int src_b = src & 0xFF; - - /* If source is fully opaque (or destination is fully transparent), the - * blended result is the source */ - if (src_a == 0xFF || dst_a == 0x00) - return src; - - /* If source is fully transparent, the blended result is the destination */ - if (src_a == 0x00) - return dst; - - /* Otherwise, blend each ARGB component, assuming pre-multiplied alpha */ - int r = guac_common_surface_blend_component(dst_r, src_r, src_a); - int g = guac_common_surface_blend_component(dst_g, src_g, src_a); - int b = guac_common_surface_blend_component(dst_b, src_b, src_a); - int a = guac_common_surface_blend_component(dst_a, src_a, src_a); - - /* Recombine blended components */ - return (a << 24) | (r << 16) | (g << 8) | b; - -} - -/** - * Copies data from the given buffer to the surface at the given coordinates. - * The dimensions and location of the destination rectangle will be altered - * to remove as many unchanged pixels as possible. - * - * @param src_buffer The buffer to copy. - * @param src_stride The number of bytes in each row of the source buffer. - * @param sx The X coordinate of the source rectangle. - * @param sy The Y coordinate of the source rectangle. - * @param dst The destination surface. - * @param rect The destination rectangle. - * @param opaque Non-zero if the source surface is opaque (its alpha channel - * should be ignored), zero otherwise. - */ -static void __guac_common_surface_put(unsigned char* src_buffer, int src_stride, - int* sx, int* sy, - guac_common_surface* dst, guac_common_rect* rect, - int opaque) { - - unsigned char* dst_buffer = dst->buffer; - int dst_stride = dst->stride; - - int x, y; - - int min_x = rect->width; - int min_y = rect->height; - int max_x = 0; - int max_y = 0; - - int orig_x = rect->x; - int orig_y = rect->y; - - src_buffer += src_stride * (*sy) + 4 * (*sx); - dst_buffer += (dst_stride * rect->y) + (4 * rect->x); - - /* For each row */ - for (y=0; y < rect->height; y++) { - - uint32_t* src_current = (uint32_t*) src_buffer; - uint32_t* dst_current = (uint32_t*) dst_buffer; - - /* Copy row */ - for (x=0; x < rect->width; x++) { - - uint32_t color; - - /* Get source and destination color values */ - uint32_t src_color = *src_current; - uint32_t dst_color = *dst_current; - - /* Ignore alpha channel if opaque */ - if (opaque) - color = src_color | 0xFF000000; - - /* Otherwise, perform alpha blending operation */ - else - color = guac_common_surface_argb_blend(dst_color, src_color); - - /* If the destination color is changing, update rectangle bounds - * and store the new color */ - if (dst_color != color) { - if (x < min_x) min_x = x; - if (y < min_y) min_y = y; - if (x > max_x) max_x = x; - if (y > max_y) max_y = y; - *dst_current = color; - } - - /* Advance to next pixel */ - src_current++; - dst_current++; - - } - - /* Next row */ - src_buffer += src_stride; - dst_buffer += dst_stride; - - } - - /* Restrict destination rect to only updated pixels */ - if (max_x >= min_x && max_y >= min_y) { - rect->x += min_x; - rect->y += min_y; - rect->width = max_x - min_x + 1; - rect->height = max_y - min_y + 1; - } - else { - rect->width = 0; - rect->height = 0; - } - - /* Update source X/Y */ - *sx += rect->x - orig_x; - *sy += rect->y - orig_y; - -} - -/** - * Fills the given surface with color, using the given buffer as a mask. Color - * will be added to the given surface iff the corresponding pixel within the - * buffer is opaque. - * - * @param src_buffer The buffer to use as a mask. - * @param src_stride The number of bytes in each row of the source buffer. - * @param sx The X coordinate of the source rectangle. - * @param sy The Y coordinate of the source rectangle. - * @param dst The destination surface. - * @param rect The destination rectangle. - * @param red The red component of the color of the fill. - * @param green The green component of the color of the fill. - * @param blue The blue component of the color of the fill. - */ -static void __guac_common_surface_fill_mask(unsigned char* src_buffer, int src_stride, - int sx, int sy, - guac_common_surface* dst, guac_common_rect* rect, - int red, int green, int blue) { - - unsigned char* dst_buffer = dst->buffer; - int dst_stride = dst->stride; - - uint32_t color = 0xFF000000 | (red << 16) | (green << 8) | blue; - int x, y; - - src_buffer += src_stride*sy + 4*sx; - dst_buffer += (dst_stride * rect->y) + (4 * rect->x); - - /* For each row */ - for (y=0; y < rect->height; y++) { - - uint32_t* src_current = (uint32_t*) src_buffer; - uint32_t* dst_current = (uint32_t*) dst_buffer; - - /* Stencil row */ - for (x=0; x < rect->width; x++) { - - /* Fill with color if opaque */ - if (*src_current & 0xFF000000) - *dst_current = color; - - src_current++; - dst_current++; - } - - /* Next row */ - src_buffer += src_stride; - dst_buffer += dst_stride; - - } - -} - -/** - * Copies data from the given surface to the given destination surface using - * the specified transfer function. - * - * @param src_buffer The buffer to copy. - * @param src_stride The number of bytes in each row of the source buffer. - * @param sx The X coordinate of the source rectangle. - * @param sy The Y coordinate of the source rectangle. - * @param op The transfer function to use. - * @param dst The destination surface. - * @param rect The destination rectangle. - */ -static void __guac_common_surface_transfer(guac_common_surface* src, int* sx, int* sy, - guac_transfer_function op, - guac_common_surface* dst, guac_common_rect* rect) { - - unsigned char* src_buffer = src->buffer; - unsigned char* dst_buffer = dst->buffer; - - int x, y; - int src_stride, dst_stride; - int step = 1; - - int min_x = rect->width - 1; - int min_y = rect->height - 1; - int max_x = 0; - int max_y = 0; - - int orig_x = rect->x; - int orig_y = rect->y; - - /* Copy forwards only if destination is in a different surface or is before source */ - if (src != dst || rect->y < *sy || (rect->y == *sy && rect->x < *sx)) { - src_buffer += src->stride * (*sy) + 4 * (*sx); - dst_buffer += (dst->stride * rect->y) + (4 * rect->x); - src_stride = src->stride; - dst_stride = dst->stride; - step = 1; - } - - /* Otherwise, copy backwards */ - else { - src_buffer += src->stride * (*sy + rect->height - 1) + 4 * (*sx + rect->width - 1); - dst_buffer += dst->stride * (rect->y + rect->height - 1) + 4 * (rect->x + rect->width - 1); - src_stride = -src->stride; - dst_stride = -dst->stride; - step = -1; - } - - /* For each row */ - for (y=0; y < rect->height; y++) { - - uint32_t* src_current = (uint32_t*) src_buffer; - uint32_t* dst_current = (uint32_t*) dst_buffer; - - /* Transfer each pixel in row */ - for (x=0; x < rect->width; x++) { - - if (__guac_common_surface_transfer_int(op, src_current, dst_current)) { - if (x < min_x) min_x = x; - if (y < min_y) min_y = y; - if (x > max_x) max_x = x; - if (y > max_y) max_y = y; - } - - src_current += step; - dst_current += step; - } - - /* Next row */ - src_buffer += src_stride; - dst_buffer += dst_stride; - - } - - /* Translate X coordinate space of moving backwards */ - if (step < 0) { - int old_max_x = max_x; - max_x = rect->width - 1 - min_x; - min_x = rect->width - 1 - old_max_x; - } - - /* Translate Y coordinate space of moving backwards */ - if (dst_stride < 0) { - int old_max_y = max_y; - max_y = rect->height - 1 - min_y; - min_y = rect->height - 1 - old_max_y; - } - - /* Restrict destination rect to only updated pixels */ - if (max_x >= min_x && max_y >= min_y) { - rect->x += min_x; - rect->y += min_y; - rect->width = max_x - min_x + 1; - rect->height = max_y - min_y + 1; - } - else { - rect->width = 0; - rect->height = 0; - } - - /* Update source X/Y */ - *sx += rect->x - orig_x; - *sy += rect->y - orig_y; - -} - -guac_common_surface* guac_common_surface_alloc(guac_client* client, - guac_socket* socket, const guac_layer* layer, int w, int h) { - - /* Calculate heat map dimensions */ - size_t heat_width = GUAC_COMMON_SURFACE_HEAT_DIMENSION(w); - size_t heat_height = GUAC_COMMON_SURFACE_HEAT_DIMENSION(h); - - /* Init surface */ - guac_common_surface* surface = guac_mem_zalloc(sizeof(guac_common_surface)); - surface->client = client; - surface->socket = socket; - surface->layer = layer; - surface->parent = GUAC_DEFAULT_LAYER; - surface->opacity = 0xFF; - surface->width = w; - surface->height = h; - - pthread_mutex_init(&surface->_lock, NULL); - - /* Create corresponding Cairo surface */ - surface->stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, w); - surface->buffer = guac_mem_zalloc(h, surface->stride); - - /* Create corresponding heat map */ - surface->heat_map = guac_mem_zalloc(heat_width, heat_height, - sizeof(guac_common_surface_heat_cell)); - - /* Reset clipping rect */ - guac_common_surface_reset_clip(surface); - - /* Layers must initially exist */ - if (layer->index >= 0) { - guac_protocol_send_size(socket, layer, w, h); - surface->realized = 1; - } - - /* Defer creation of buffers */ - else - surface->realized = 0; - - return surface; -} - -void guac_common_surface_free(guac_common_surface* surface) { - - /* Only dispose of surface if it exists */ - if (surface->realized) - guac_protocol_send_dispose(surface->socket, surface->layer); - - pthread_mutex_destroy(&surface->_lock); - - guac_mem_free(surface->heat_map); - guac_mem_free(surface->buffer); - guac_mem_free(surface); - -} - -void guac_common_surface_resize(guac_common_surface* surface, int w, int h) { - - pthread_mutex_lock(&surface->_lock); - - /* Ignore if resize will have no effect */ - if (w == surface->width && h == surface->height) - goto complete; - - guac_socket* socket = surface->socket; - const guac_layer* layer = surface->layer; - - unsigned char* old_buffer; - int old_stride; - guac_common_rect old_rect; - - int sx = 0; - int sy = 0; - - /* Calculate heat map dimensions */ - size_t heat_width = GUAC_COMMON_SURFACE_HEAT_DIMENSION(w); - size_t heat_height = GUAC_COMMON_SURFACE_HEAT_DIMENSION(h); - - /* Copy old surface data */ - old_buffer = surface->buffer; - old_stride = surface->stride; - guac_common_rect_init(&old_rect, 0, 0, surface->width, surface->height); - - /* Re-initialize at new size */ - surface->width = w; - surface->height = h; - surface->stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, w); - surface->buffer = guac_mem_zalloc(h, surface->stride); - __guac_common_bound_rect(surface, &surface->clip_rect, NULL, NULL); - - /* Copy relevant old data */ - __guac_common_bound_rect(surface, &old_rect, NULL, NULL); - __guac_common_surface_put(old_buffer, old_stride, &sx, &sy, surface, &old_rect, 1); - - /* Free old data */ - guac_mem_free(old_buffer); - - /* Allocate completely new heat map (can safely discard old stats) */ - guac_mem_free(surface->heat_map); - surface->heat_map = guac_mem_zalloc(heat_width, heat_height, - sizeof(guac_common_surface_heat_cell)); - - /* Resize dirty rect to fit new surface dimensions */ - if (surface->dirty) { - __guac_common_bound_rect(surface, &surface->dirty_rect, NULL, NULL); - if (surface->dirty_rect.width <= 0 || surface->dirty_rect.height <= 0) - surface->dirty = 0; - } - - /* Update Guacamole layer */ - if (surface->realized) - guac_protocol_send_size(socket, layer, w, h); - -complete: - pthread_mutex_unlock(&surface->_lock); - -} - -void guac_common_surface_draw(guac_common_surface* surface, int x, int y, cairo_surface_t* src) { - - pthread_mutex_lock(&surface->_lock); - - unsigned char* buffer = cairo_image_surface_get_data(src); - cairo_format_t format = cairo_image_surface_get_format(src); - int stride = cairo_image_surface_get_stride(src); - int w = cairo_image_surface_get_width(src); - int h = cairo_image_surface_get_height(src); - - int sx = 0; - int sy = 0; - - guac_common_rect rect; - guac_common_rect_init(&rect, x, y, w, h); - - /* Clip operation */ - __guac_common_clip_rect(surface, &rect, &sx, &sy); - if (rect.width <= 0 || rect.height <= 0) - goto complete; - - /* Update backing surface */ - __guac_common_surface_put(buffer, stride, &sx, &sy, surface, &rect, format != CAIRO_FORMAT_ARGB32); - if (rect.width <= 0 || rect.height <= 0) - goto complete; - - /* Update the heat map for the update rectangle. */ - guac_timestamp time = guac_timestamp_current(); - __guac_common_surface_touch_rect(surface, &rect, time); - - /* 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); - -complete: - pthread_mutex_unlock(&surface->_lock); - -} - -void guac_common_surface_paint(guac_common_surface* surface, int x, int y, - cairo_surface_t* src, int red, int green, int blue) { - - pthread_mutex_lock(&surface->_lock); - - unsigned char* buffer = cairo_image_surface_get_data(src); - int stride = cairo_image_surface_get_stride(src); - int w = cairo_image_surface_get_width(src); - int h = cairo_image_surface_get_height(src); - - int sx = 0; - int sy = 0; - - guac_common_rect rect; - guac_common_rect_init(&rect, x, y, w, h); - - /* Clip operation */ - __guac_common_clip_rect(surface, &rect, &sx, &sy); - if (rect.width <= 0 || rect.height <= 0) - goto complete; - - /* Update backing surface */ - __guac_common_surface_fill_mask(buffer, stride, sx, sy, surface, &rect, red, green, blue); - - /* 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); - -complete: - pthread_mutex_unlock(&surface->_lock); - -} - -void guac_common_surface_copy(guac_common_surface* src, int sx, int sy, - int w, int h, guac_common_surface* dst, int dx, int dy) { - - /* Lock both surfaces */ - pthread_mutex_lock(&dst->_lock); - if (src != dst) - pthread_mutex_lock(&src->_lock); - - guac_socket* socket = dst->socket; - const guac_layer* src_layer = src->layer; - const guac_layer* dst_layer = dst->layer; - - guac_common_rect srect; - guac_common_rect_init(&srect, sx, sy, w, h); - - /* Clip operation source rect to bounds */ - __guac_common_bound_rect(src, &srect, &dx, &dy); - if (srect.width <= 0 || srect.height <= 0) - goto complete; - - guac_common_rect drect; - guac_common_rect_init(&drect, dx, dy, - srect.width, srect.height); - - /* Clip operation destination rect */ - __guac_common_clip_rect(dst, &drect, &srect.x, &srect.y); - if (drect.width <= 0 || drect.height <= 0) - goto complete; - - /* NOTE: Being the last rectangle to be adjusted, only the width/height of - * drect is now correct! */ - - /* Update backing surface first only if drect cannot intersect srect */ - if (src != dst) { - __guac_common_surface_transfer(src, &srect.x, &srect.y, - GUAC_TRANSFER_BINARY_SRC, dst, &drect); - if (drect.width <= 0 || drect.height <= 0) - goto complete; - } - - /* Defer if combining */ - if (__guac_common_should_combine(dst, &drect, 1)) - __guac_common_mark_dirty(dst, &drect); - - /* Otherwise, flush and draw immediately */ - else { - __guac_common_surface_flush(dst); - __guac_common_surface_flush(src); - guac_protocol_send_copy(socket, src_layer, srect.x, srect.y, - drect.width, drect.height, GUAC_COMP_OVER, dst_layer, - drect.x, drect.y); - dst->realized = 1; - } - - /* Update backing surface last if drect can intersect srect */ - if (src == dst) - __guac_common_surface_transfer(src, &srect.x, &srect.y, - GUAC_TRANSFER_BINARY_SRC, dst, &drect); - -complete: - - /* Unlock both surfaces */ - pthread_mutex_unlock(&dst->_lock); - if (src != dst) - pthread_mutex_unlock(&src->_lock); - -} - -void guac_common_surface_transfer(guac_common_surface* src, int sx, int sy, int w, int h, - guac_transfer_function op, guac_common_surface* dst, int dx, int dy) { - - /* Lock both surfaces */ - pthread_mutex_lock(&dst->_lock); - if (src != dst) - pthread_mutex_lock(&src->_lock); - - guac_socket* socket = dst->socket; - const guac_layer* src_layer = src->layer; - const guac_layer* dst_layer = dst->layer; - - guac_common_rect srect; - guac_common_rect_init(&srect, sx, sy, w, h); - - /* Clip operation source rect to bounds */ - __guac_common_bound_rect(src, &srect, &dx, &dy); - if (srect.width <= 0 || srect.height <= 0) - goto complete; - - guac_common_rect drect; - guac_common_rect_init(&drect, dx, dy, - srect.width, srect.height); - - /* Clip operation destination rect */ - __guac_common_clip_rect(dst, &drect, &srect.x, &srect.y); - if (drect.width <= 0 || drect.height <= 0) - goto complete; - - /* NOTE: Being the last rectangle to be adjusted, only the width/height of - * drect is now correct! */ - - /* Update backing surface first only if drect cannot intersect srect */ - if (src != dst) { - __guac_common_surface_transfer(src, &srect.x, &srect.y, op, dst, &drect); - if (drect.width <= 0 || drect.height <= 0) - goto complete; - } - - /* Defer if combining */ - if (__guac_common_should_combine(dst, &drect, 1)) - __guac_common_mark_dirty(dst, &drect); - - /* Otherwise, flush and draw immediately */ - else { - __guac_common_surface_flush(dst); - __guac_common_surface_flush(src); - guac_protocol_send_transfer(socket, src_layer, srect.x, srect.y, - drect.width, drect.height, op, dst_layer, drect.x, drect.y); - dst->realized = 1; - } - - /* Update backing surface last if drect can intersect srect */ - if (src == dst) - __guac_common_surface_transfer(src, &srect.x, &srect.y, op, dst, &drect); - -complete: - - /* Unlock both surfaces */ - pthread_mutex_unlock(&dst->_lock); - if (src != dst) - pthread_mutex_unlock(&src->_lock); - -} - -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); - - guac_socket* socket = surface->socket; - const guac_layer* layer = surface->layer; - - guac_common_rect rect; - guac_common_rect_init(&rect, x, y, w, h); - - /* Clip operation */ - __guac_common_clip_rect(surface, &rect, NULL, NULL); - if (rect.width <= 0 || rect.height <= 0) - goto complete; - - /* Update backing surface */ - __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 */ - 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, alpha); - surface->realized = 1; - } - -complete: - pthread_mutex_unlock(&surface->_lock); - -} - -void guac_common_surface_clip(guac_common_surface* surface, int x, int y, int w, int h) { - - pthread_mutex_lock(&surface->_lock); - - guac_common_rect clip; - - /* Init clipping rectangle if clipping not already applied */ - if (!surface->clipped) { - guac_common_rect_init(&surface->clip_rect, 0, 0, surface->width, surface->height); - surface->clipped = 1; - } - - guac_common_rect_init(&clip, x, y, w, h); - guac_common_rect_constrain(&surface->clip_rect, &clip); - - pthread_mutex_unlock(&surface->_lock); - -} - -void guac_common_surface_reset_clip(guac_common_surface* surface) { - pthread_mutex_lock(&surface->_lock); - surface->clipped = 0; - pthread_mutex_unlock(&surface->_lock); -} - -/** - * Flushes the bitmap update currently described by the dirty rectangle within - * the given surface directly via an "img" instruction as PNG data. The - * resulting instructions will be sent over the socket associated with the - * given 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, - int opaque) { - - if (surface->dirty) { - - guac_socket* socket = surface->socket; - const guac_layer* layer = surface->layer; - - /* Get Cairo surface for specified rect */ - unsigned char* buffer = surface->buffer - + surface->dirty_rect.y * surface->stride - + surface->dirty_rect.x * 4; - - 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, - layer, surface->dirty_rect.x, surface->dirty_rect.y, rect); - - cairo_surface_destroy(rect); - surface->realized = 1; - - /* Surface is no longer dirty */ - surface->dirty = 0; - - } - -} - -/** - * Returns an appropriate quality between 0 and 100 for lossy encoding - * depending on the current processing lag calculated for the given client. - * - * @param client - * The client for which the lossy quality is being calculated. - * - * @return - * A value between 0 and 100 inclusive which seems appropriate for the - * client based on lag measurements. - */ -static int guac_common_surface_suggest_quality(guac_client* client) { - - int lag = guac_client_get_processing_lag(client); - - /* Scale quality linearly from 90 to 30 as lag varies from 20ms to 80ms */ - int quality = 90 - (lag - 20); - - /* Do not exceed 90 for quality */ - if (quality > 90) - return 90; - - /* Do not go below 30 for quality */ - if (quality < 30) - return 30; - - return quality; - -} - -/** - * Flushes the bitmap update currently described by the dirty rectangle within - * the given surface directly via an "img" instruction as JPEG data. The - * resulting instructions will be sent over the socket associated with the - * given surface. - * - * @param surface - * The surface to flush. - */ -static void __guac_common_surface_flush_to_jpeg(guac_common_surface* surface) { - - if (surface->dirty) { - - guac_socket* socket = surface->socket; - const guac_layer* layer = surface->layer; - - guac_common_rect max; - guac_common_rect_init(&max, 0, 0, surface->width, surface->height); - - /* Expand the dirty rect size to fit in a grid with cells equal to the - * minimum JPEG block size */ - guac_common_rect_expand_to_grid(GUAC_SURFACE_JPEG_BLOCK_SIZE, - &surface->dirty_rect, &max); - - /* Get Cairo surface for specified rect */ - unsigned char* buffer = surface->buffer - + 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); - - /* Send JPEG for rect */ - guac_client_stream_jpeg(surface->client, socket, GUAC_COMP_OVER, layer, - surface->dirty_rect.x, surface->dirty_rect.y, rect, - guac_common_surface_suggest_quality(surface->client)); - - cairo_surface_destroy(rect); - surface->realized = 1; - - /* Surface is no longer dirty */ - surface->dirty = 0; - - } - -} - -/** - * Flushes the bitmap update currently described by the dirty rectangle within - * the given surface directly via an "img" instruction as WebP data. The - * resulting instructions will be sent over the socket associated with the - * given 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, - int opaque) { - - if (surface->dirty) { - - guac_socket* socket = surface->socket; - const guac_layer* layer = surface->layer; - - guac_common_rect max; - guac_common_rect_init(&max, 0, 0, surface->width, surface->height); - - /* Expand the dirty rect size to fit in a grid with cells equal to the - * minimum WebP block size */ - guac_common_rect_expand_to_grid(GUAC_SURFACE_WEBP_BLOCK_SIZE, - &surface->dirty_rect, &max); - - /* Get Cairo surface for specified rect */ - unsigned char* buffer = surface->buffer - + surface->dirty_rect.y * surface->stride - + surface->dirty_rect.x * 4; - - 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, - surface->dirty_rect.x, surface->dirty_rect.y, rect, - guac_common_surface_suggest_quality(surface->client), - surface->lossless ? 1 : 0); - - cairo_surface_destroy(rect); - surface->realized = 1; - - /* Surface is no longer dirty */ - surface->dirty = 0; - - } - -} - -/** - * Comparator for instances of guac_common_surface_bitmap_rect, the elements - * which make up a surface's bitmap buffer. - * - * @see qsort - */ -static int __guac_common_surface_bitmap_rect_compare(const void* a, const void* b) { - - guac_common_surface_bitmap_rect* ra = (guac_common_surface_bitmap_rect*) a; - guac_common_surface_bitmap_rect* rb = (guac_common_surface_bitmap_rect*) b; - - /* Order roughly top to bottom, left to right */ - if (ra->rect.y != rb->rect.y) return ra->rect.y - rb->rect.y; - if (ra->rect.x != rb->rect.x) return ra->rect.x - rb->rect.x; - - /* Wider updates should come first (more likely to intersect later) */ - if (ra->rect.width != rb->rect.width) return rb->rect.width - ra->rect.width; - - /* Shorter updates should come first (less likely to increase cost) */ - return ra->rect.height - rb->rect.height; - -} - -/** - * Flushes only the properties of the given surface, such as layer location or - * opacity. Image state is not flushed. If the surface represents a buffer or - * the default layer, this function has no effect. - * - * @param surface - * The surface to flush. - */ -static void __guac_common_surface_flush_properties( - guac_common_surface* surface) { - - guac_socket* socket = surface->socket; - - /* Only applicable to non-default visible layers */ - if (surface->layer->index <= 0) - return; - - /* Flush opacity */ - if (surface->opacity_dirty) { - guac_protocol_send_shade(socket, surface->layer, surface->opacity); - surface->opacity_dirty = 0; - } - - /* Flush location and hierarchy */ - if (surface->location_dirty) { - guac_protocol_send_move(socket, surface->layer, - surface->parent, surface->x, surface->y, surface->z); - surface->location_dirty = 0; - } - -} - -static void __guac_common_surface_flush(guac_common_surface* surface) { - - /* Flush final dirty rectangle to queue. */ - __guac_common_surface_flush_to_queue(surface); - - guac_common_surface_bitmap_rect* current = surface->bitmap_queue; - int i, j; - int original_queue_length; - int flushed = 0; - - original_queue_length = surface->bitmap_queue_length; - - /* Sort updates to make combination less costly */ - qsort(surface->bitmap_queue, surface->bitmap_queue_length, sizeof(guac_common_surface_bitmap_rect), - __guac_common_surface_bitmap_rect_compare); - - /* Flush all rects in queue */ - for (i=0; i < surface->bitmap_queue_length; i++) { - - /* Get next unflushed candidate */ - guac_common_surface_bitmap_rect* candidate = current; - if (!candidate->flushed) { - - int combined = 0; - - /* Build up rect as much as possible */ - for (j=i; j < surface->bitmap_queue_length; j++) { - - if (!candidate->flushed) { - - /* Clip candidate within current bounds */ - __guac_common_bound_rect(surface, &candidate->rect, NULL, NULL); - if (candidate->rect.width <= 0 || candidate->rect.height <= 0) - candidate->flushed = 1; - - /* Combine if reasonable */ - else if (__guac_common_should_combine(surface, &candidate->rect, 0) || !surface->dirty) { - __guac_common_mark_dirty(surface, &candidate->rect); - candidate->flushed = 1; - combined++; - } - - } - - candidate++; - - } - - /* Re-add to queue if there's room and this update was modified or we expect others might be */ - if ((combined > 1 || i < original_queue_length) - && surface->bitmap_queue_length < GUAC_COMMON_SURFACE_QUEUE_SIZE) - __guac_common_surface_flush_to_queue(surface); - - /* Flush as bitmap otherwise */ - else if (surface->dirty) { - - 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, opaque); - - /* If not WebP, JPEG is the next best (lossy) choice */ - 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, opaque); - - } - - } - - current++; - - } - - /* Flush complete */ - surface->bitmap_queue_length = 0; - -} - -void guac_common_surface_flush(guac_common_surface* surface) { - - pthread_mutex_lock(&surface->_lock); - - /* Flush any applicable layer properties */ - __guac_common_surface_flush_properties(surface); - - /* Flush surface contents */ - __guac_common_surface_flush(surface); - - pthread_mutex_unlock(&surface->_lock); - -} - -void guac_common_surface_dup(guac_common_surface* surface, - guac_client* client, guac_socket* socket) { - - pthread_mutex_lock(&surface->_lock); - - /* Do nothing if not realized */ - if (!surface->realized) - goto complete; - - /* Synchronize layer-specific properties if applicable */ - if (surface->layer->index > 0) { - - /* Synchronize opacity */ - guac_protocol_send_shade(socket, surface->layer, surface->opacity); - - /* Synchronize location and hierarchy */ - guac_protocol_send_move(socket, surface->layer, - surface->parent, surface->x, surface->y, surface->z); - - } - - /* Synchronize multi-touch support level */ - else if (surface->layer->index == 0) - guac_protocol_send_set_int(socket, surface->layer, - GUAC_PROTOCOL_LAYER_PARAMETER_MULTI_TOUCH, - surface->touches); - - /* Sync size to new socket */ - guac_protocol_send_size(socket, surface->layer, - surface->width, surface->height); - - /* Send contents of layer, if non-empty */ - if (surface->width > 0 && surface->height > 0) { - - /* Get entire surface */ - cairo_surface_t* rect = cairo_image_surface_create_for_data( - surface->buffer, CAIRO_FORMAT_ARGB32, - surface->width, surface->height, surface->stride); - - /* Send PNG for rect */ - guac_client_stream_png(client, socket, GUAC_COMP_OVER, surface->layer, - 0, 0, rect); - cairo_surface_destroy(rect); - - } - -complete: - pthread_mutex_unlock(&surface->_lock); - -} diff --git a/src/common/tests/Makefile.am b/src/common/tests/Makefile.am index 27ac75cd1..b84dc827f 100644 --- a/src/common/tests/Makefile.am +++ b/src/common/tests/Makefile.am @@ -39,12 +39,6 @@ noinst_HEADERS = \ test_common_SOURCES = \ iconv/convert.c \ iconv/convert-test-data.c \ - rect/clip_and_split.c \ - rect/constrain.c \ - rect/expand_to_grid.c \ - rect/extend.c \ - rect/init.c \ - rect/intersects.c \ string/count_occurrences.c \ string/split.c diff --git a/src/common/tests/rect/clip_and_split.c b/src/common/tests/rect/clip_and_split.c deleted file mode 100644 index e286bce9f..000000000 --- a/src/common/tests/rect/clip_and_split.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "common/rect.h" - -#include - -/** - * Test which verifies that guac_common_rect_clip_and_split() divides a - * rectangle into subrectangles after removing a "hole" rectangle. - */ -void test_rect__clip_and_split() { - - int res; - - guac_common_rect cut; - guac_common_rect min; - guac_common_rect rect; - - guac_common_rect_init(&min, 10, 10, 10, 10); - - /* Clip top */ - guac_common_rect_init(&rect, 10, 5, 10, 10); - res = guac_common_rect_clip_and_split(&rect, &min, &cut); - CU_ASSERT_EQUAL(1, res); - CU_ASSERT_EQUAL(10, cut.x); - CU_ASSERT_EQUAL(5, cut.y); - CU_ASSERT_EQUAL(10, cut.width); - CU_ASSERT_EQUAL(5, cut.height); - - CU_ASSERT_EQUAL(10, rect.x); - CU_ASSERT_EQUAL(10, rect.y); - CU_ASSERT_EQUAL(10, rect.width); - CU_ASSERT_EQUAL(5, rect.height); - - /* Clip bottom */ - guac_common_rect_init(&rect, 10, 15, 10, 10); - res = guac_common_rect_clip_and_split(&rect, &min, &cut); - CU_ASSERT_EQUAL(1, res); - CU_ASSERT_EQUAL(10, cut.x); - CU_ASSERT_EQUAL(20, cut.y); - CU_ASSERT_EQUAL(10, cut.width); - CU_ASSERT_EQUAL(5, cut.height); - - CU_ASSERT_EQUAL(10, rect.x); - CU_ASSERT_EQUAL(15, rect.y); - CU_ASSERT_EQUAL(10, rect.width); - CU_ASSERT_EQUAL(5, rect.height); - - /* Clip left */ - guac_common_rect_init(&rect, 5, 10, 10, 10); - res = guac_common_rect_clip_and_split(&rect, &min, &cut); - CU_ASSERT_EQUAL(1, res); - CU_ASSERT_EQUAL(5, cut.x); - CU_ASSERT_EQUAL(10, cut.y); - CU_ASSERT_EQUAL(5, cut.width); - CU_ASSERT_EQUAL(10, cut.height); - - CU_ASSERT_EQUAL(10, rect.x); - CU_ASSERT_EQUAL(10, rect.y); - CU_ASSERT_EQUAL(5, rect.width); - CU_ASSERT_EQUAL(10, rect.height); - - /* Clip right */ - guac_common_rect_init(&rect, 15, 10, 10, 10); - res = guac_common_rect_clip_and_split(&rect, &min, &cut); - CU_ASSERT_EQUAL(1, res); - CU_ASSERT_EQUAL(20, cut.x); - CU_ASSERT_EQUAL(10, cut.y); - CU_ASSERT_EQUAL(5, cut.width); - CU_ASSERT_EQUAL(10, cut.height); - - CU_ASSERT_EQUAL(15, rect.x); - CU_ASSERT_EQUAL(10, rect.y); - CU_ASSERT_EQUAL(5, rect.width); - CU_ASSERT_EQUAL(10, rect.height); - - /* - * Test a rectangle which completely covers the hole. - * Clip and split until done. - */ - guac_common_rect_init(&rect, 5, 5, 20, 20); - - /* Clip top */ - res = guac_common_rect_clip_and_split(&rect, &min, &cut); - CU_ASSERT_EQUAL(1, res); - CU_ASSERT_EQUAL(5, cut.x); - CU_ASSERT_EQUAL(5, cut.y); - CU_ASSERT_EQUAL(20, cut.width); - CU_ASSERT_EQUAL(5, cut.height); - - CU_ASSERT_EQUAL(5, rect.x); - CU_ASSERT_EQUAL(10, rect.y); - CU_ASSERT_EQUAL(20, rect.width); - CU_ASSERT_EQUAL(15, rect.height); - - /* Clip left */ - res = guac_common_rect_clip_and_split(&rect, &min, &cut); - CU_ASSERT_EQUAL(1, res); - CU_ASSERT_EQUAL(5, cut.x); - CU_ASSERT_EQUAL(10, cut.y); - CU_ASSERT_EQUAL(5, cut.width); - CU_ASSERT_EQUAL(15, cut.height); - - CU_ASSERT_EQUAL(10, rect.x); - CU_ASSERT_EQUAL(10, rect.y); - CU_ASSERT_EQUAL(15, rect.width); - CU_ASSERT_EQUAL(15, rect.height); - - /* Clip bottom */ - res = guac_common_rect_clip_and_split(&rect, &min, &cut); - CU_ASSERT_EQUAL(1, res); - CU_ASSERT_EQUAL(10, cut.x); - CU_ASSERT_EQUAL(20, cut.y); - CU_ASSERT_EQUAL(15, cut.width); - CU_ASSERT_EQUAL(5, cut.height); - - CU_ASSERT_EQUAL(10, rect.x); - CU_ASSERT_EQUAL(10, rect.y); - CU_ASSERT_EQUAL(15, rect.width); - CU_ASSERT_EQUAL(10, rect.height); - - /* Clip right */ - res = guac_common_rect_clip_and_split(&rect, &min, &cut); - CU_ASSERT_EQUAL(20, cut.x); - CU_ASSERT_EQUAL(10, cut.y); - CU_ASSERT_EQUAL(5, cut.width); - CU_ASSERT_EQUAL(10, cut.height); - - CU_ASSERT_EQUAL(10, rect.x); - CU_ASSERT_EQUAL(10, rect.y); - CU_ASSERT_EQUAL(10, rect.width); - CU_ASSERT_EQUAL(10, rect.height); - - /* Make sure nothing is left to do */ - res = guac_common_rect_clip_and_split(&rect, &min, &cut); - CU_ASSERT_EQUAL(0, res); - -} - diff --git a/src/common/tests/rect/constrain.c b/src/common/tests/rect/constrain.c deleted file mode 100644 index 793aac224..000000000 --- a/src/common/tests/rect/constrain.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "common/rect.h" - -#include - -/** - * Test which verifies that guac_common_rect_constrain() restricts a given - * rectangle to arbitrary bounds. - */ -void test_rect__constrain() { - - guac_common_rect max; - guac_common_rect rect; - - guac_common_rect_init(&rect, -10, -10, 110, 110); - guac_common_rect_init(&max, 0, 0, 100, 100); - guac_common_rect_constrain(&rect, &max); - - CU_ASSERT_EQUAL(0, rect.x); - CU_ASSERT_EQUAL(0, rect.y); - CU_ASSERT_EQUAL(100, rect.width); - CU_ASSERT_EQUAL(100, rect.height); - -} - diff --git a/src/common/tests/rect/expand_to_grid.c b/src/common/tests/rect/expand_to_grid.c deleted file mode 100644 index beef87d89..000000000 --- a/src/common/tests/rect/expand_to_grid.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "common/rect.h" - -#include - -/** - * Test which verifies guac_common_rect_expand_to_grid() properly shifts and - * resizes rectangles to fit an NxN grid. - */ -void test_rect__expand_to_grid() { - - int cell_size = 16; - - guac_common_rect max; - guac_common_rect rect; - - /* Simple adjustment */ - guac_common_rect_init(&rect, 0, 0, 25, 25); - guac_common_rect_init(&max, 0, 0, 100, 100); - guac_common_rect_expand_to_grid(cell_size, &rect, &max); - CU_ASSERT_EQUAL(0, rect.x); - CU_ASSERT_EQUAL(0, rect.y); - CU_ASSERT_EQUAL(32, rect.width); - CU_ASSERT_EQUAL(32, rect.height); - - /* Adjustment with moving of rect */ - guac_common_rect_init(&rect, 75, 75, 25, 25); - guac_common_rect_init(&max, 0, 0, 100, 100); - guac_common_rect_expand_to_grid(cell_size, &rect, &max); - CU_ASSERT_EQUAL(max.width - 32, rect.x); - CU_ASSERT_EQUAL(max.height - 32, rect.y); - CU_ASSERT_EQUAL(32, rect.width); - CU_ASSERT_EQUAL(32, rect.height); - - guac_common_rect_init(&rect, -5, -5, 25, 25); - guac_common_rect_init(&max, 0, 0, 100, 100); - guac_common_rect_expand_to_grid(cell_size, &rect, &max); - CU_ASSERT_EQUAL(0, rect.x); - CU_ASSERT_EQUAL(0, rect.y); - CU_ASSERT_EQUAL(32, rect.width); - CU_ASSERT_EQUAL(32, rect.height); - - /* Adjustment with moving and clamping of rect */ - guac_common_rect_init(&rect, 0, 0, 25, 15); - guac_common_rect_init(&max, 0, 5, 32, 15); - guac_common_rect_expand_to_grid(cell_size, &rect, &max); - CU_ASSERT_EQUAL(max.x, rect.x); - CU_ASSERT_EQUAL(max.y, rect.y); - CU_ASSERT_EQUAL(max.width, rect.width); - CU_ASSERT_EQUAL(max.height, rect.height); - -} - diff --git a/src/common/tests/rect/extend.c b/src/common/tests/rect/extend.c deleted file mode 100644 index dc2a0e308..000000000 --- a/src/common/tests/rect/extend.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "common/rect.h" - -#include - -/** - * Test which verifies that guac_common_rect_extend() expands the given - * rectangle as necessary to contain at least the given bounds. - */ -void test_rect__extend() { - - guac_common_rect max; - guac_common_rect rect; - - guac_common_rect_init(&rect, 10, 10, 90, 90); - guac_common_rect_init(&max, 0, 0, 100, 100); - guac_common_rect_extend(&rect, &max); - CU_ASSERT_EQUAL(0, rect.x); - CU_ASSERT_EQUAL(0, rect.y); - CU_ASSERT_EQUAL(100, rect.width); - CU_ASSERT_EQUAL(100, rect.height); - -} - diff --git a/src/common/tests/rect/init.c b/src/common/tests/rect/init.c deleted file mode 100644 index 288cd751b..000000000 --- a/src/common/tests/rect/init.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "common/rect.h" - -#include - -/** - * Test which verifies rectangle initialization via guac_common_rect_init(). - */ -void test_rect__init() { - - guac_common_rect max; - - guac_common_rect_init(&max, 0, 0, 100, 100); - - CU_ASSERT_EQUAL(0, max.x); - CU_ASSERT_EQUAL(0, max.y); - CU_ASSERT_EQUAL(100, max.width); - CU_ASSERT_EQUAL(100, max.height); - -} - diff --git a/src/common/tests/rect/intersects.c b/src/common/tests/rect/intersects.c deleted file mode 100644 index c48026844..000000000 --- a/src/common/tests/rect/intersects.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "common/rect.h" - -#include - -/** - * Test which verifies intersection testing via guac_common_rect_intersects(). - */ -void test_rect__intersects() { - - int res; - - guac_common_rect min; - guac_common_rect rect; - - guac_common_rect_init(&min, 10, 10, 10, 10); - - /* Rectangle intersection - empty - * rectangle is outside */ - guac_common_rect_init(&rect, 25, 25, 5, 5); - res = guac_common_rect_intersects(&rect, &min); - CU_ASSERT_EQUAL(0, res); - - /* Rectangle intersection - complete - * rectangle is completely inside */ - guac_common_rect_init(&rect, 11, 11, 5, 5); - res = guac_common_rect_intersects(&rect, &min); - CU_ASSERT_EQUAL(2, res); - - /* Rectangle intersection - partial - * rectangle intersects UL */ - guac_common_rect_init(&rect, 8, 8, 5, 5); - res = guac_common_rect_intersects(&rect, &min); - CU_ASSERT_EQUAL(1, res); - - /* Rectangle intersection - partial - * rectangle intersects LR */ - guac_common_rect_init(&rect, 18, 18, 5, 5); - res = guac_common_rect_intersects(&rect, &min); - CU_ASSERT_EQUAL(1, res); - - /* Rectangle intersection - complete - * rect intersects along UL but inside */ - guac_common_rect_init(&rect, 10, 10, 5, 5); - res = guac_common_rect_intersects(&rect, &min); - CU_ASSERT_EQUAL(2, res); - - /* Rectangle intersection - partial - * rectangle intersects along L but outside */ - guac_common_rect_init(&rect, 5, 10, 5, 5); - res = guac_common_rect_intersects(&rect, &min); - CU_ASSERT_EQUAL(1, res); - - /* Rectangle intersection - complete - * rectangle intersects along LR but rest is inside */ - guac_common_rect_init(&rect, 15, 15, 5, 5); - res = guac_common_rect_intersects(&rect, &min); - CU_ASSERT_EQUAL(2, res); - - /* Rectangle intersection - partial - * rectangle intersects along R but rest is outside */ - guac_common_rect_init(&rect, 20, 10, 5, 5); - res = guac_common_rect_intersects(&rect, &min); - CU_ASSERT_EQUAL(1, res); - - /* Rectangle intersection - partial - * rectangle encloses min; which is a partial intersection */ - guac_common_rect_init(&rect, 5, 5, 20, 20); - res = guac_common_rect_intersects(&rect, &min); - CU_ASSERT_EQUAL(1, res); - -} - diff --git a/src/protocols/vnc/user.c b/src/protocols/vnc/user.c index 7c813a94f..7025be1f9 100644 --- a/src/protocols/vnc/user.c +++ b/src/protocols/vnc/user.c @@ -21,8 +21,6 @@ #include "clipboard.h" #include "input.h" -#include "common/dot_cursor.h" -#include "common/pointer_cursor.h" #include "user.h" #include "sftp.h" #include "vnc.h"