diff options
author | Alexander Larsson <alexl@redhat.com> | 2017-11-30 10:36:30 +0100 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2017-11-30 21:57:42 +0100 |
commit | 521b09cc964346e1eb5c3c9241cc68bef42f860c (patch) | |
tree | 2a9e1654c50bc73e9e898728f14757238958beb8 | |
parent | 3d4a9324e62b5ae106c335b20261f471ae8fba6b (diff) | |
download | gtk+-521b09cc964346e1eb5c3c9241cc68bef42f860c.tar.gz |
broadway: Send diffs of node trees
Reusing pre-created nodes is a lot faster both in terms of
dom modifications and of transfer sizes.
-rw-r--r-- | gdk/broadway/broadway-output.c | 52 | ||||
-rw-r--r-- | gdk/broadway/broadway-protocol.h | 2 | ||||
-rw-r--r-- | gdk/broadway/broadway-server.c | 39 | ||||
-rw-r--r-- | gdk/broadway/broadway-server.h | 6 | ||||
-rw-r--r-- | gdk/broadway/broadway.js | 204 | ||||
-rw-r--r-- | gdk/broadway/broadwayd.c | 7 | ||||
-rw-r--r-- | gsk/gskbroadwayrenderer.c | 130 |
7 files changed, 279 insertions, 161 deletions
diff --git a/gdk/broadway/broadway-output.c b/gdk/broadway/broadway-output.c index 9389de44ce..226526219a 100644 --- a/gdk/broadway/broadway-output.c +++ b/gdk/broadway/broadway-output.c @@ -309,17 +309,61 @@ broadway_output_set_transient_for (BroadwayOutput *output, append_uint16 (output, parent_id); } +/*********************************** + * This outputs the tree to the client, while at the same time diffing + * against the old tree. This allows us to avoid sending certain + * parts. + * + * Reusing existing dom nodes are problematic because doing so + * automatically inherits all their children. There are two cases + * where we do this: + * + * If the entire sub tree is identical we emit a KEEP_ALL node which + * just reuses the entire old dom subtree. + * + * If a the node is unchanged (but some descendant may have changed), + * and all parents are also unchanged, then we can just avoid + * changing the dom node at all, and we emit a KEEP_THIS node. + * + ***********************************/ + static void append_node (BroadwayOutput *output, - BroadwayNode *node) + BroadwayNode *node, + BroadwayNode *old_node, + gboolean all_parents_are_kept) { - append_uint32 (output, node->type); guint32 i; + if (old_node != NULL && broadway_node_equal (node, old_node)) + { + if (broadway_node_deep_equal (node, old_node)) + { + append_uint32 (output, BROADWAY_NODE_KEEP_ALL); + return; + } + + if (all_parents_are_kept) + { + append_uint32 (output, BROADWAY_NODE_KEEP_THIS); + append_uint32 (output, node->n_children); + for (i = 0; i < node->n_children; i++) + append_node (output, node->children[i], + i < old_node->n_children ? old_node->children[i] : NULL, + TRUE); + return; + } + } + + append_uint32 (output, node->type); + for (i = 0; i < node->n_data; i++) append_uint32 (output, node->data[i]); for (i = 0; i < node->n_children; i++) - append_node (output, node->children[i]); + append_node (output, + node->children[i], + (old_node != NULL && i < old_node->n_children) ? old_node->children[i] : NULL, + FALSE); } void @@ -337,7 +381,7 @@ broadway_output_window_set_nodes (BroadwayOutput *output, append_uint32 (output, 0); start = output->buf->len; - append_node (output, root); + append_node (output, root, old_root, TRUE); end = output->buf->len; patch_uint32 (output, (end - start) / 4, size_pos); } diff --git a/gdk/broadway/broadway-protocol.h b/gdk/broadway/broadway-protocol.h index 41861ef3f1..3457d2c6c8 100644 --- a/gdk/broadway/broadway-protocol.h +++ b/gdk/broadway/broadway-protocol.h @@ -20,6 +20,8 @@ typedef enum { /* Sync changes with broadway.js */ BROADWAY_NODE_SHADOW = 8, BROADWAY_NODE_OPACITY = 9, BROADWAY_NODE_CLIP = 10, + BROADWAY_NODE_KEEP_ALL = 11, + BROADWAY_NODE_KEEP_THIS = 12, } BroadwayNodeType; typedef enum { diff --git a/gdk/broadway/broadway-server.c b/gdk/broadway/broadway-server.c index bec36e3fae..18e37d62c5 100644 --- a/gdk/broadway/broadway-server.c +++ b/gdk/broadway/broadway-server.c @@ -147,33 +147,51 @@ broadway_node_free (BroadwayNode *node) gboolean broadway_node_equal (BroadwayNode *a, - BroadwayNode *b) + BroadwayNode *b) { int i; - if (a->hash != b->hash) - return FALSE; - if (a->type != b->type) return FALSE; if (a->n_data != b->n_data) return FALSE; - if (a->n_children != b->n_children) + /* Don't check data for containers, that is just n_children, which + we don't want to compare for a shallow equal */ + if (a->type != BROADWAY_NODE_CONTAINER) + { + for (i = 0; i < a->n_data; i++) + if (a->data[i] != b->data[i]) + return FALSE; + } + + return TRUE; +} + +gboolean +broadway_node_deep_equal (BroadwayNode *a, + BroadwayNode *b) +{ + int i; + + if (a->hash != b->hash) return FALSE; - for (i = 0; i < a->n_data; i++) - if (a->data[i] != b->data[i]) - return FALSE; + if (!broadway_node_equal (a,b)) + return FALSE; + + if (a->n_children != b->n_children) + return FALSE; for (i = 0; i < a->n_children; i++) - if (!broadway_node_equal (a->children[i], b->children[i])) + if (!broadway_node_deep_equal (a->children[i], b->children[i])) return FALSE; return TRUE; } + static void broadway_server_init (BroadwayServer *server) { @@ -1665,7 +1683,8 @@ broadway_server_window_set_nodes (BroadwayServer *server, if (server->output != NULL) broadway_output_window_set_nodes (server->output, window->id, - root, window->nodes); + root, + window->nodes); if (window->nodes) broadway_node_free (window->nodes); diff --git a/gdk/broadway/broadway-server.h b/gdk/broadway/broadway-server.h index dba16288af..3a40f72900 100644 --- a/gdk/broadway/broadway-server.h +++ b/gdk/broadway/broadway-server.h @@ -22,7 +22,7 @@ typedef struct _BroadwayNode BroadwayNode; struct _BroadwayNode { guint32 type; - guint32 hash; + guint32 hash; /* deep hash */ guint32 n_children; BroadwayNode **children; guint32 n_data; @@ -30,7 +30,9 @@ struct _BroadwayNode { }; gboolean broadway_node_equal (BroadwayNode *a, - BroadwayNode *b); + BroadwayNode *b); +gboolean broadway_node_deep_equal (BroadwayNode *a, + BroadwayNode *b); BroadwayServer *broadway_server_new (char *address, int port, diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js index 0f85c7aaf4..5474960bc7 100644 --- a/gdk/broadway/broadway.js +++ b/gdk/broadway/broadway.js @@ -301,31 +301,9 @@ function SwapNodes(node_data, div) { this.node_data_signed = new Int32Array(node_data); this.data_pos = 0; this.div = div; - this.div2 = document.createElement('div'); this.outstanding = 1; } -SwapNodes.prototype.did_one = function(image) { - this.outstanding--; - if (this.outstanding == 0) { - var oldDiv2 = null; - if (this.div.hasChildNodes()) - oldDiv2 = this.div.lastChild; - - this.div.appendChild(this.div2); - if (oldDiv2) - this.div.removeChild(oldDiv2); - } -} - -SwapNodes.prototype.add_image = function(image) { - this.outstanding++; - var v = this; - image.addEventListener('load', function() { - v.did_one (); - }, false); -}; - SwapNodes.prototype.decode_uint32 = function() { return this.node_data[this.data_pos++]; } @@ -421,26 +399,37 @@ function px(x) { return x + "px"; } -function set_rect_style (div, rect, offset_x, offset_y) { - div.style["left"] = px(rect.x - offset_x); - div.style["top"] = px(rect.y - offset_y); +function set_rect_style (div, rect) { + div.style["left"] = px(rect.x); + div.style["top"] = px(rect.y); div.style["width"] = px(rect.width); div.style["height"] = px(rect.height); } -function set_rrect_style (div, rrect, offset_x, offset_y) { - set_rect_style(div, rrect.bounds, offset_x, offset_y); +function set_rrect_style (div, rrect) { + set_rect_style(div, rrect.bounds); div.style["border-top-left-radius"] = args(px(rrect.sizes[0].width), px(rrect.sizes[0].height)); div.style["border-top-right-radius"] = args(px(rrect.sizes[1].width), px(rrect.sizes[1].height)); div.style["border-bottom-right-radius"] = args(px(rrect.sizes[2].width), px(rrect.sizes[2].height)); div.style["border-bottom-left-radius"] = args(px(rrect.sizes[3].width), px(rrect.sizes[3].height)); } -SwapNodes.prototype.handle_node = function(parent, offset_x, offset_y) +SwapNodes.prototype.insertNode = function(parent, posInParent, oldNode) { var type = this.decode_uint32(); + var newNode = null; + + // We need to dup this because as we reuse children the original order is lost + var oldChildren = []; + if (oldNode) { + for (var i = 0; i < oldNode.children.length; i++) + oldChildren[i] = oldNode.children[i]; + } + switch (type) { + /* Leaf nodes */ + case 0: // TEXTURE { var rect = this.decode_rect(); @@ -449,22 +438,10 @@ SwapNodes.prototype.handle_node = function(parent, offset_x, offset_y) image.width = rect.width; image.height = rect.height; image.style["position"] = "absolute"; - set_rect_style(image, rect, offset_x, offset_y); + set_rect_style(image, rect); var texture_url = textures[texture_id]; - this.add_image(image); image.src = texture_url; - parent.appendChild(image); - } - break; - - case 1: // CONTAINER - { - var div = document.createElement('div'); - var len = this.decode_uint32(); - for (var i = 0; i < len; i++) { - this.handle_node(div, offset_x, offset_y); - } - parent.appendChild(div); + newNode = image; } break; @@ -474,9 +451,9 @@ SwapNodes.prototype.handle_node = function(parent, offset_x, offset_y) var c = this.decode_color (); var div = document.createElement('div'); div.style["position"] = "absolute"; - set_rect_style(div, rect, offset_x, offset_y); + set_rect_style(div, rect); div.style["background-color"] = c; - parent.appendChild(div); + newNode = div; } break; @@ -494,7 +471,7 @@ SwapNodes.prototype.handle_node = function(parent, offset_x, offset_y) div.style["position"] = "absolute"; rrect.bounds.width -= border_widths[1] + border_widths[3]; rrect.bounds.height -= border_widths[0] + border_widths[2]; - set_rrect_style(div, rrect, offset_x, offset_y); + set_rrect_style(div, rrect); div.style["border-style"] = "solid"; div.style["border-top-color"] = border_colors[0]; div.style["border-top-width"] = px(border_widths[0]); @@ -504,7 +481,7 @@ SwapNodes.prototype.handle_node = function(parent, offset_x, offset_y) div.style["border-bottom-width"] = px(border_widths[2]); div.style["border-left-color"] = border_colors[3]; div.style["border-left-width"] = px(border_widths[3]); - parent.appendChild(div); + newNode = div; } break; @@ -519,9 +496,9 @@ SwapNodes.prototype.handle_node = function(parent, offset_x, offset_y) var div = document.createElement('div'); div.style["position"] = "absolute"; - set_rrect_style(div, rrect, offset_x, offset_y); + set_rrect_style(div, rrect); div.style["box-shadow"] = args(px(dx), px(dy), px(blur), px(spread), color); - parent.appendChild(div); + newNode = div; } break; @@ -536,23 +513,12 @@ SwapNodes.prototype.handle_node = function(parent, offset_x, offset_y) var div = document.createElement('div'); div.style["position"] = "absolute"; - set_rrect_style(div, rrect, offset_x, offset_y); + set_rrect_style(div, rrect); div.style["box-shadow"] = args("inset", px(dx), px(dy), px(blur), px(spread), color); - parent.appendChild(div); + newNode = div; } break; - case 6: // ROUNDED_CLIP - { - var rrect = this.decode_rounded_rect(); - var div = document.createElement('div'); - div.style["position"] = "absolute"; - set_rrect_style(div, rrect, offset_x, offset_y); - div.style["overflow"] = "hidden"; - parent.appendChild(div); - this.handle_node(div, rrect.bounds.x, rrect.bounds.y); - } - break; case 7: // LINEAR_GRADIENT { @@ -562,7 +528,7 @@ SwapNodes.prototype.handle_node = function(parent, offset_x, offset_y) var stops = this.decode_color_stops (); var div = document.createElement('div'); div.style["position"] = "absolute"; - set_rect_style(div, rect, offset_x, offset_y); + set_rect_style(div, rect); // direction: var dx = end.x - start.x; @@ -595,7 +561,48 @@ SwapNodes.prototype.handle_node = function(parent, offset_x, offset_y) gradient = gradient + ")"; div.style["background-image"] = gradient; - parent.appendChild(div); + newNode = div; + } + break; + + + /* Bin nodes */ + + case 10: // CLIP + { + var rect = this.decode_rect(); + var div = document.createElement('div'); + div.style["position"] = "absolute"; + set_rect_style(div, rect); + div.style["overflow"] = "hidden"; + this.insertNode(div, -1, oldChildren[0]); + newNode = div; + } + break; + + case 6: // ROUNDED_CLIP + { + var rrect = this.decode_rounded_rect(); + var div = document.createElement('div'); + div.style["position"] = "absolute"; + set_rrect_style(div, rrect); + div.style["overflow"] = "hidden"; + this.insertNode(div, -1, oldChildren[0]); + newNode = div; + } + break; + + case 9: // OPACITY + { + var opacity = this.decode_float(); + var div = document.createElement('div'); + div.style["position"] = "absolute"; + div.style["left"] = px(0); + div.style["top"] = px(0); + div.style["opacity"] = opacity; + + this.insertNode(div, -1, oldChildren[0]); + newNode = div; } break; @@ -616,40 +623,72 @@ SwapNodes.prototype.handle_node = function(parent, offset_x, offset_y) div.style["top"] = px(0); div.style["filter"] = filters; - parent.appendChild(div); - this.handle_node(div, offset_x, offset_y); + this.insertNode(div, -1, oldChildren[0]); + newNode = div; } break; - case 9: // OPACITY + /* Generic nodes */ + + case 1: // CONTAINER { - var opacity = this.decode_float(); var div = document.createElement('div'); - div.style["position"] = "absolute"; - div.style["left"] = px(0); - div.style["top"] = px(0); - div.style["opacity"] = opacity; + var len = this.decode_uint32(); + for (var i = 0; i < len; i++) { + this.insertNode(div, -1, oldChildren[i]); + } + newNode = div; + } + break; + + case 11: // KEEP_ALL + { + if (!oldNode) + alert("KEEP_ALL with no oldNode"); - parent.appendChild(div); - this.handle_node(div, offset_x, offset_y); + if (oldNode.parentNode != parent) + newNode = oldNode; + else + newNode = null; } break; - case 10: // CLIP + case 12: // KEEP_THIS { - var rect = this.decode_rect(); - var div = document.createElement('div'); - div.style["position"] = "absolute"; - set_rect_style(div, rect, offset_x, offset_y); - div.style["overflow"] = "hidden"; - parent.appendChild(div); - this.handle_node(div, rect.x, rect.y); + if (!oldNode) + alert("KEEP_THIS with no oldNode "); + + /* We only get keep-this if all parents were kept, check this */ + if (oldNode.parentNode != parent) + alert("Got KEEP_THIS for non-kept parent"); + + var len = this.decode_uint32(); + var i; + + for (i = 0; i < len; i++) { + this.insertNode(oldNode, i, + oldChildren[i]); + } + + /* Remove children that are after the new length */ + for (i = oldChildren.length - 1; i > len - 1; i--) + oldNode.removeChild(oldChildren[i]); + + /* NOTE: No need to modify the parent, we're keeping this node as is */ + newNode = null; } break; default: alert("Unexpected node type " + type); } + + if (newNode) { + if (posInParent >= 0 && parent.children[posInParent]) + parent.replaceChild(newNode, parent.children[posInParent]); + else + parent.appendChild(newNode); + } } function cmdWindowSetNodes(id, node_data) @@ -662,10 +701,9 @@ function cmdWindowSetNodes(id, node_data) /* We use a secondary div so that we can remove all previous children in one go */ var swap = new SwapNodes (node_data, div); - swap.handle_node(swap.div2, 0, 0); + swap.insertNode(div, 0, div.firstChild); if (swap.data_pos != node_data.length) alert ("Did not consume entire array (len " + node_data.length + " end " + end + ")"); - swap.did_one (); } function cmdUploadTexture(id, data) diff --git a/gdk/broadway/broadwayd.c b/gdk/broadway/broadwayd.c index a885a5e665..9a0f42013e 100644 --- a/gdk/broadway/broadwayd.c +++ b/gdk/broadway/broadwayd.c @@ -234,7 +234,7 @@ rotl (guint32 value, int shift) static BroadwayNode * decode_nodes (BroadwayClient *client, - int len, guint32 data[], int *pos) + int len, guint32 data[], int *pos) { BroadwayNode *node; guint32 type; @@ -305,9 +305,8 @@ decode_nodes (BroadwayClient *client, { node->data[i] = data[(*pos)++]; if (i == texture_offset) - node->data[i] = GPOINTER_TO_INT (g_hash_table_lookup (client->textures, - GINT_TO_POINTER (node->data[i]))); - + node->data[i] = GPOINTER_TO_INT (g_hash_table_lookup (client->textures, + GINT_TO_POINTER (node->data[i]))); } for (i = 0; i < n_children; i++) diff --git a/gsk/gskbroadwayrenderer.c b/gsk/gskbroadwayrenderer.c index e388c31b1f..887befdd4a 100644 --- a/gsk/gskbroadwayrenderer.c +++ b/gsk/gskbroadwayrenderer.c @@ -116,10 +116,10 @@ add_float (GArray *nodes, float f) } static void -add_point (GArray *nodes, const graphene_point_t *point) +add_point (GArray *nodes, const graphene_point_t *point, float offset_x, float offset_y) { - add_float (nodes, point->x); - add_float (nodes, point->y); + add_float (nodes, point->x - offset_x); + add_float (nodes, point->y - offset_y); } static void @@ -130,17 +130,17 @@ add_size (GArray *nodes, const graphene_size_t *size) } static void -add_rect (GArray *nodes, const graphene_rect_t *rect) +add_rect (GArray *nodes, const graphene_rect_t *rect, float offset_x, float offset_y) { - add_point (nodes, &rect->origin); + add_point (nodes, &rect->origin, offset_x, offset_y); add_size (nodes, &rect->size); } static void -add_rounded_rect (GArray *nodes, const GskRoundedRect *rrect) +add_rounded_rect (GArray *nodes, const GskRoundedRect *rrect, float offset_x, float offset_y) { int i; - add_rect (nodes, &rrect->bounds); + add_rect (nodes, &rrect->bounds, offset_x, offset_y); for (i = 0; i < 4; i++) add_size (nodes, &rrect->corner[i]); } @@ -461,11 +461,17 @@ node_texture_fallback (GskRenderNode *node, return texture; } +/* Note: This tracks the offset so that we can convert + the absolute coordinates of the GskRenderNodes to + parent-relative which is what the dom uses, and + which is good for re-using subtrees. */ static void gsk_broadway_renderer_add_node (GskRenderer *self, GArray *nodes, GPtrArray *node_textures, - GskRenderNode *node) + GskRenderNode *node, + float offset_x, + float offset_y) { GdkDisplay *display = gsk_renderer_get_display (self); @@ -475,6 +481,8 @@ gsk_broadway_renderer_add_node (GskRenderer *self, g_assert_not_reached (); return; + /* Leaf nodes */ + case GSK_TEXTURE_NODE: { GdkTexture *texture = gsk_texture_node_get_texture (node); @@ -484,10 +492,7 @@ gsk_broadway_renderer_add_node (GskRenderer *self, texture_id = gdk_broadway_display_ensure_texture (display, texture); add_uint32 (nodes, BROADWAY_NODE_TEXTURE); - add_float (nodes, node->bounds.origin.x); - add_float (nodes, node->bounds.origin.y); - add_float (nodes, gdk_texture_get_width (texture)); - add_float (nodes, gdk_texture_get_height (texture)); + add_rect (nodes, &node->bounds, offset_x, offset_y); add_uint32 (nodes, texture_id); } return; @@ -495,39 +500,23 @@ gsk_broadway_renderer_add_node (GskRenderer *self, case GSK_CAIRO_NODE: { const cairo_surface_t *surface = gsk_cairo_node_peek_surface (node); - GdkTexture *texture; + GdkTexture *texture; guint32 texture_id; - texture = gdk_texture_new_for_surface ((cairo_surface_t *)surface); + texture = gdk_texture_new_for_surface ((cairo_surface_t *)surface); g_ptr_array_add (node_textures, g_object_ref (texture)); /* Transfers ownership to node_textures */ texture_id = gdk_broadway_display_ensure_texture (display, texture); add_uint32 (nodes, BROADWAY_NODE_TEXTURE); - add_float (nodes, node->bounds.origin.x); - add_float (nodes, node->bounds.origin.y); - add_float (nodes, node->bounds.size.width); - add_float (nodes, node->bounds.size.height); + add_rect (nodes, &node->bounds, offset_x, offset_y); add_uint32 (nodes, texture_id); } return; - case GSK_CONTAINER_NODE: - { - guint i; - - add_uint32 (nodes, BROADWAY_NODE_CONTAINER); - add_uint32 (nodes, gsk_container_node_get_n_children (node)); - - for (i = 0; i < gsk_container_node_get_n_children (node); i++) - gsk_broadway_renderer_add_node (self, nodes, node_textures, - gsk_container_node_get_child (node, i)); - } - return; - case GSK_COLOR_NODE: { add_uint32 (nodes, BROADWAY_NODE_COLOR); - add_rect (nodes, &node->bounds); + add_rect (nodes, &node->bounds, offset_x, offset_y); add_rgba (nodes, gsk_color_node_peek_color (node)); } return; @@ -536,7 +525,7 @@ gsk_broadway_renderer_add_node (GskRenderer *self, { int i; add_uint32 (nodes, BROADWAY_NODE_BORDER); - add_rounded_rect (nodes, gsk_border_node_peek_outline (node)); + add_rounded_rect (nodes, gsk_border_node_peek_outline (node), offset_x, offset_y); for (i = 0; i < 4; i++) add_float (nodes, gsk_border_node_peek_widths (node)[i]); for (i = 0; i < 4; i++) @@ -547,7 +536,7 @@ gsk_broadway_renderer_add_node (GskRenderer *self, case GSK_OUTSET_SHADOW_NODE: { add_uint32 (nodes, BROADWAY_NODE_OUTSET_SHADOW); - add_rounded_rect (nodes, gsk_outset_shadow_node_peek_outline (node)); + add_rounded_rect (nodes, gsk_outset_shadow_node_peek_outline (node), offset_x, offset_y); add_rgba (nodes, gsk_outset_shadow_node_peek_color (node)); add_float (nodes, gsk_outset_shadow_node_get_dx (node)); add_float (nodes, gsk_outset_shadow_node_get_dy (node)); @@ -559,7 +548,7 @@ gsk_broadway_renderer_add_node (GskRenderer *self, case GSK_INSET_SHADOW_NODE: { add_uint32 (nodes, BROADWAY_NODE_INSET_SHADOW); - add_rounded_rect (nodes, gsk_inset_shadow_node_peek_outline (node)); + add_rounded_rect (nodes, gsk_inset_shadow_node_peek_outline (node), offset_x, offset_y); add_rgba (nodes, gsk_inset_shadow_node_peek_color (node)); add_float (nodes, gsk_inset_shadow_node_get_dx (node)); add_float (nodes, gsk_inset_shadow_node_get_dy (node)); @@ -568,23 +557,14 @@ gsk_broadway_renderer_add_node (GskRenderer *self, } return; - case GSK_ROUNDED_CLIP_NODE: - { - add_uint32 (nodes, BROADWAY_NODE_ROUNDED_CLIP); - add_rounded_rect (nodes, gsk_rounded_clip_node_peek_clip (node)); - gsk_broadway_renderer_add_node (self, nodes, node_textures, - gsk_rounded_clip_node_get_child (node)); - } - return; - case GSK_LINEAR_GRADIENT_NODE: { guint i, n; add_uint32 (nodes, BROADWAY_NODE_LINEAR_GRADIENT); - add_rect (nodes, &node->bounds); - add_point (nodes, gsk_linear_gradient_node_peek_start (node)); - add_point (nodes, gsk_linear_gradient_node_peek_end (node)); + add_rect (nodes, &node->bounds, offset_x, offset_y); + add_point (nodes, gsk_linear_gradient_node_peek_start (node), offset_x, offset_y); + add_point (nodes, gsk_linear_gradient_node_peek_end (node), offset_x, offset_y); n = gsk_linear_gradient_node_get_n_color_stops (node); add_uint32 (nodes, n); for (i = 0; i < n; i++) @@ -592,6 +572,8 @@ gsk_broadway_renderer_add_node (GskRenderer *self, } return; + /* Bin nodes */ + case GSK_SHADOW_NODE: { gsize i, n_shadows = gsk_shadow_node_get_n_shadows (node); @@ -606,7 +588,8 @@ gsk_broadway_renderer_add_node (GskRenderer *self, add_float (nodes, shadow->radius); } gsk_broadway_renderer_add_node (self, nodes, node_textures, - gsk_shadow_node_get_child (node)); + gsk_shadow_node_get_child (node), + offset_x, offset_y); } return; @@ -615,16 +598,47 @@ gsk_broadway_renderer_add_node (GskRenderer *self, add_uint32 (nodes, BROADWAY_NODE_OPACITY); add_float (nodes, gsk_opacity_node_get_opacity (node)); gsk_broadway_renderer_add_node (self, nodes, node_textures, - gsk_opacity_node_get_child (node)); + gsk_opacity_node_get_child (node), + offset_x, offset_y); + } + return; + + case GSK_ROUNDED_CLIP_NODE: + { + const GskRoundedRect *rclip = gsk_rounded_clip_node_peek_clip (node); + add_uint32 (nodes, BROADWAY_NODE_ROUNDED_CLIP); + add_rounded_rect (nodes, rclip, offset_x, offset_y); + gsk_broadway_renderer_add_node (self, nodes, node_textures, + gsk_rounded_clip_node_get_child (node), + rclip->bounds.origin.x, + rclip->bounds.origin.y); } return; case GSK_CLIP_NODE: { + const graphene_rect_t *clip = gsk_clip_node_peek_clip (node); add_uint32 (nodes, BROADWAY_NODE_CLIP); - add_rect (nodes, gsk_clip_node_peek_clip (node)); + add_rect (nodes, clip, offset_x, offset_y); gsk_broadway_renderer_add_node (self, nodes, node_textures, - gsk_clip_node_get_child (node)); + gsk_clip_node_get_child (node), + clip->origin.x, + clip->origin.y); + } + return; + + /* Generic nodes */ + + case GSK_CONTAINER_NODE: + { + guint i; + + add_uint32 (nodes, BROADWAY_NODE_CONTAINER); + add_uint32 (nodes, gsk_container_node_get_n_children (node)); + + for (i = 0; i < gsk_container_node_get_n_children (node); i++) + gsk_broadway_renderer_add_node (self, nodes, node_textures, + gsk_container_node_get_child (node, i), offset_x, offset_y); } return; @@ -643,25 +657,25 @@ gsk_broadway_renderer_add_node (GskRenderer *self, { GdkTexture *texture; guint32 texture_id; - float off_x = 0, off_y = 0; + float t_off_x = 0, t_off_y = 0; - texture = node_cache_lookup (node, &off_x, &off_y); + texture = node_cache_lookup (node, &t_off_x, &t_off_y); if (!texture) { - texture = node_texture_fallback (node, &off_x, &off_y); + texture = node_texture_fallback (node, &t_off_x, &t_off_y); #if 0 g_print ("Fallback %p for %s\n", texture, node->node_class->type_name); #endif - node_cache_store (node, texture, off_x, off_y); + node_cache_store (node, texture, t_off_x, t_off_y); } g_ptr_array_add (node_textures, texture); /* Transfers ownership to node_textures */ texture_id = gdk_broadway_display_ensure_texture (display, texture); add_uint32 (nodes, BROADWAY_NODE_TEXTURE); - add_float (nodes, node->bounds.origin.x + off_x); - add_float (nodes, node->bounds.origin.y + off_y); + add_float (nodes, node->bounds.origin.x + t_off_x - offset_x); + add_float (nodes, node->bounds.origin.y + t_off_y - offset_y); add_float (nodes, gdk_texture_get_width (texture)); add_float (nodes, gdk_texture_get_height (texture)); add_uint32 (nodes, texture_id); @@ -676,7 +690,7 @@ gsk_broadway_renderer_render (GskRenderer *self, GArray *nodes = g_array_new (FALSE, FALSE, sizeof(guint32)); GPtrArray *node_textures = g_ptr_array_new_with_free_func (g_object_unref); - gsk_broadway_renderer_add_node (self, nodes, node_textures, root); + gsk_broadway_renderer_add_node (self, nodes, node_textures, root, 0, 0); gdk_broadway_window_set_nodes (window, nodes, node_textures); g_array_unref (nodes); g_ptr_array_unref (node_textures); |