GUAC-236: Fix comparator. Sort in descending order of depth.

This commit is contained in:
Michael Jumper 2016-02-28 14:07:10 -08:00
parent 2e93499383
commit 1d4e6ce924
2 changed files with 58 additions and 8 deletions

View File

@ -22,6 +22,7 @@
#include "config.h" #include "config.h"
#include "display.h" #include "display.h"
#include "layer.h"
#include "log.h" #include "log.h"
#include <cairo/cairo.h> #include <cairo/cairo.h>
@ -35,6 +36,14 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
/**
* The Guacamole video encoder display related to the current qsort()
* operation. As qsort() does not provide a means of passing arbitrary data to
* the comparitor, this value must be set prior to invoking qsort() with
* guacenc_display_layer_comparator.
*/
guacenc_display* __qsort_display;
/** /**
* Comparator which orders layer pointers such that (1) NULL pointers are last, * Comparator which orders layer pointers such that (1) NULL pointers are last,
* (2) layers with the same parent_index are adjacent, and (3) layers with the * (2) layers with the same parent_index are adjacent, and (3) layers with the
@ -44,22 +53,28 @@
*/ */
static int guacenc_display_layer_comparator(const void* a, const void* b) { static int guacenc_display_layer_comparator(const void* a, const void* b) {
guacenc_layer* layer_a = *((guacenc_layer**) a);
guacenc_layer* layer_b = *((guacenc_layer**) b);
/* If a is NULL, sort it to bottom */ /* If a is NULL, sort it to bottom */
if (a == NULL) { if (layer_a == NULL) {
/* ... unless b is also NULL, in which case they are equal */ /* ... unless b is also NULL, in which case they are equal */
if (b == NULL) if (layer_b == NULL)
return 0; return 0;
return 1; return 1;
} }
/* If b is NULL (and a is not NULL), sort it to bottom */ /* If b is NULL (and a is not NULL), sort it to bottom */
if (b == NULL) if (layer_b == NULL)
return -1; return -1;
guacenc_layer* layer_a = (guacenc_layer*) a; /* Order such that the deepest layers are first */
guacenc_layer* layer_b = (guacenc_layer*) b; int a_depth = guacenc_display_get_depth(__qsort_display, layer_a);
int b_depth = guacenc_display_get_depth(__qsort_display, layer_b);
if (b_depth != a_depth)
return b_depth - a_depth;
/* Order such that sibling layers are adjacent */ /* Order such that sibling layers are adjacent */
if (layer_b->parent_index != layer_a->parent_index) if (layer_b->parent_index != layer_a->parent_index)
@ -95,10 +110,13 @@ int guacenc_display_sync(guacenc_display* display, guac_timestamp timestamp) {
int i; int i;
guacenc_layer* render_order[GUACENC_DISPLAY_MAX_LAYERS]; guacenc_layer* render_order[GUACENC_DISPLAY_MAX_LAYERS];
/* Copy and sort layers (ensuring layer #0 is always first) */ /* Copy list of layers within display */
memcpy(render_order, display->layers, sizeof(render_order)); memcpy(render_order, display->layers, sizeof(render_order));
qsort(render_order + 1, GUACENC_DISPLAY_MAX_LAYERS - 1,
sizeof(guacenc_layer*), guacenc_display_layer_comparator); /* Sort layers by depth, parent, and Z */
__qsort_display = display;
qsort(render_order, GUACENC_DISPLAY_MAX_LAYERS, sizeof(guacenc_layer*),
guacenc_display_layer_comparator);
/* Render each layer, in order */ /* Render each layer, in order */
for (i = 0; i < GUACENC_DISPLAY_MAX_LAYERS; i++) { for (i = 0; i < GUACENC_DISPLAY_MAX_LAYERS; i++) {
@ -179,6 +197,25 @@ guacenc_layer* guacenc_display_get_layer(guacenc_display* display,
} }
int guacenc_display_get_depth(guacenc_display* display, guacenc_layer* layer) {
/* Non-existent layers have a depth of 0 */
if (layer == NULL)
return 0;
/* Layers with no parent have a depth of 0 */
if (layer->parent_index == GUACENC_LAYER_NO_PARENT)
return 0;
/* Retrieve parent layer */
guacenc_layer* parent =
guacenc_display_get_layer(display, layer->parent_index);
/* Current layer depth is the depth of the parent + 1 */
return guacenc_display_get_depth(display, parent) + 1;
}
int guacenc_display_free_layer(guacenc_display* display, int guacenc_display_free_layer(guacenc_display* display,
int index) { int index) {

View File

@ -151,6 +151,19 @@ int guacenc_display_free(guacenc_display* display);
guacenc_layer* guacenc_display_get_layer(guacenc_display* display, guacenc_layer* guacenc_display_get_layer(guacenc_display* display,
int index); int index);
/**
* Returns the depth of a given layer in terms of parent layers. The layer
* depth is the number of layers above the given layer in hierarchy, where a
* layer without any parent (such as the default layer) has a depth of 0.
*
* @param layer
* The layer to check.
*
* @return
* The depth of the layer.
*/
int guacenc_display_get_depth(guacenc_display* display, guacenc_layer* layer);
/** /**
* Frees all resources associated with the layer having the given index. If * Frees all resources associated with the layer having the given index. If
* the layer has not been allocated, this function has no effect. * the layer has not been allocated, this function has no effect.