rendernode: Add gsk_render_node_diff()
authorBenjamin Otte <otte@redhat.com>
Tue, 20 Mar 2018 00:37:05 +0000 (01:37 +0100)
committerBenjamin Otte <otte@redhat.com>
Thu, 5 Apr 2018 12:56:38 +0000 (14:56 +0200)
... and gsk_render_node_can_diff(). Those are vfuncs to compute a region
containing all the pixels that differ between the two nodes.

This is just the plumbing that chains into node classes. No node
implements it yet.

gsk/gskrendernode.c
gsk/gskrendernodeimpl.c
gsk/gskrendernodeprivate.h

index 5c7af1149313550c85b1b19a46ca389354068344..da858b71e9942f41e4c6c959293a0e455c5042f9 100644 (file)
@@ -266,6 +266,87 @@ gsk_render_node_draw (GskRenderNode *node,
     }
 }
 
+/*
+ * gsk_render_node_can_diff:
+ * @node1: a #GskRenderNode
+ * @node2: the #GskRenderNode to compare with
+ *
+ * Checks if 2 render nodes can be expected to be compared via
+ * gsk_render_node_diff(). The node diffing algorithm uses this function
+ * to match up similar nodes to compare when trying to minimze the
+ * resulting region.
+ *
+ * Nodes of different type always return %FALSE here.
+ *
+ * Returns: %TRUE if @node1 and @node2 can be expected to be compared
+ **/
+gboolean
+gsk_render_node_can_diff (GskRenderNode *node1,
+                          GskRenderNode *node2)
+{
+  if (node1 == node2)
+    return TRUE;
+
+  if (gsk_render_node_get_node_type (node1) != gsk_render_node_get_node_type (node2))
+    return FALSE;
+
+  return node1->node_class->can_diff (node1, node2);
+}
+
+static void
+rectangle_init_from_graphene (cairo_rectangle_int_t *cairo,
+                              const graphene_rect_t *graphene)
+{
+  cairo->x = floorf (graphene->origin.x);
+  cairo->y = floorf (graphene->origin.y);
+  cairo->width = ceilf (graphene->origin.x + graphene->size.width) - cairo->x;
+  cairo->height = ceilf (graphene->origin.y + graphene->size.height) - cairo->y;
+}
+
+void
+gsk_render_node_diff_impossible (GskRenderNode  *node1,
+                                 GskRenderNode  *node2,
+                                 cairo_region_t *region)
+{
+  cairo_rectangle_int_t rect;
+
+  rectangle_init_from_graphene (&rect, &node1->bounds);
+  cairo_region_union_rectangle (region, &rect);
+  rectangle_init_from_graphene (&rect, &node2->bounds);
+  cairo_region_union_rectangle (region, &rect);
+}
+
+/**
+ * gsk_render_node_diff:
+ * @node1: a #GskRenderNode
+ * @node2: the #GskRenderNode to compare with
+ * @region: a #cairo_region_t to add the differences to
+ *
+ * Compares @node1 and @node2 trying to compute the minimal region of changes.
+ * In the worst case, this is the union of the bounds of @node1 and @node2.
+ *
+ * This function is used to compute the area that needs to be redrawn when
+ * the previous contents were drawn by @node1 and the new contents should
+ * correspond to @node2. As such, it is important that this comparison is
+ * faster than the time it takes to actually do the redraw.
+ *
+ * Note that the passed in @region may already contain previous results from
+ * previous node comparisons, so this function call will only add to it.
+ **/
+void
+gsk_render_node_diff (GskRenderNode  *node1,
+                      GskRenderNode  *node2,
+                      cairo_region_t *region)
+{
+  if (node1 == node2)
+    return;
+
+  if (gsk_render_node_get_node_type (node1) != gsk_render_node_get_node_type (node2))
+    return gsk_render_node_diff_impossible (node1, node2, region);
+
+  return node1->node_class->diff (node1, node2, region);
+}
+
 #define GSK_RENDER_NODE_SERIALIZATION_VERSION 0
 #define GSK_RENDER_NODE_SERIALIZATION_ID "GskRenderNode"
 
index 3a3a7d783ca252e13a4582622aa6d997142419c9..15f9479d85ef57f7c835b01f63d9ff4b50abaf55 100644 (file)
@@ -43,6 +43,13 @@ check_variant_type (GVariant *variant,
   return TRUE;
 }
 
+static gboolean
+gsk_render_node_can_diff_impossible (GskRenderNode *node1,
+                                     GskRenderNode *node2)
+{
+  return FALSE;
+}
+
 /*** GSK_COLOR_NODE ***/
 
 typedef struct _GskColorNode GskColorNode;
@@ -110,6 +117,8 @@ static const GskRenderNodeClass GSK_COLOR_NODE_CLASS = {
   "GskColorNode",
   gsk_color_node_finalize,
   gsk_color_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_color_node_serialize,
   gsk_color_node_deserialize,
 };
@@ -286,6 +295,8 @@ static const GskRenderNodeClass GSK_LINEAR_GRADIENT_NODE_CLASS = {
   "GskLinearGradientNode",
   gsk_linear_gradient_node_finalize,
   gsk_linear_gradient_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_linear_gradient_node_serialize,
   gsk_linear_gradient_node_deserialize,
 };
@@ -296,6 +307,8 @@ static const GskRenderNodeClass GSK_REPEATING_LINEAR_GRADIENT_NODE_CLASS = {
   "GskRepeatingLinearGradientNode",
   gsk_linear_gradient_node_finalize,
   gsk_linear_gradient_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_linear_gradient_node_serialize,
   gsk_repeating_linear_gradient_node_deserialize,
 };
@@ -585,6 +598,8 @@ static const GskRenderNodeClass GSK_BORDER_NODE_CLASS = {
   "GskBorderNode",
   gsk_border_node_finalize,
   gsk_border_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_border_node_serialize,
   gsk_border_node_deserialize
 };
@@ -772,6 +787,8 @@ static const GskRenderNodeClass GSK_TEXTURE_NODE_CLASS = {
   "GskTextureNode",
   gsk_texture_node_finalize,
   gsk_texture_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_texture_node_serialize,
   gsk_texture_node_deserialize
 };
@@ -1278,6 +1295,8 @@ static const GskRenderNodeClass GSK_INSET_SHADOW_NODE_CLASS = {
   "GskInsetShadowNode",
   gsk_inset_shadow_node_finalize,
   gsk_inset_shadow_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_inset_shadow_node_serialize,
   gsk_inset_shadow_node_deserialize
 };
@@ -1579,6 +1598,8 @@ static const GskRenderNodeClass GSK_OUTSET_SHADOW_NODE_CLASS = {
   "GskOutsetShadowNode",
   gsk_outset_shadow_node_finalize,
   gsk_outset_shadow_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_outset_shadow_node_serialize,
   gsk_outset_shadow_node_deserialize
 };
@@ -1846,6 +1867,8 @@ static const GskRenderNodeClass GSK_CAIRO_NODE_CLASS = {
   "GskCairoNode",
   gsk_cairo_node_finalize,
   gsk_cairo_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_cairo_node_serialize,
   gsk_cairo_node_deserialize
 };
@@ -2075,6 +2098,8 @@ static const GskRenderNodeClass GSK_CONTAINER_NODE_CLASS = {
   "GskContainerNode",
   gsk_container_node_finalize,
   gsk_container_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_container_node_serialize,
   gsk_container_node_deserialize
 };
@@ -2258,6 +2283,8 @@ static const GskRenderNodeClass GSK_TRANSFORM_NODE_CLASS = {
   "GskTransformNode",
   gsk_transform_node_finalize,
   gsk_transform_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_transform_node_serialize,
   gsk_transform_node_deserialize
 };
@@ -2400,6 +2427,8 @@ static const GskRenderNodeClass GSK_OFFSET_NODE_CLASS = {
   "GskOffsetNode",
   gsk_offset_node_finalize,
   gsk_offset_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_offset_node_serialize,
   gsk_offset_node_deserialize
 };
@@ -2569,6 +2598,8 @@ static const GskRenderNodeClass GSK_OPACITY_NODE_CLASS = {
   "GskOpacityNode",
   gsk_opacity_node_finalize,
   gsk_opacity_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_opacity_node_serialize,
   gsk_opacity_node_deserialize
 };
@@ -2804,6 +2835,8 @@ static const GskRenderNodeClass GSK_COLOR_MATRIX_NODE_CLASS = {
   "GskColorMatrixNode",
   gsk_color_matrix_node_finalize,
   gsk_color_matrix_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_color_matrix_node_serialize,
   gsk_color_matrix_node_deserialize
 };
@@ -2992,6 +3025,8 @@ static const GskRenderNodeClass GSK_REPEAT_NODE_CLASS = {
   "GskRepeatNode",
   gsk_repeat_node_finalize,
   gsk_repeat_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_repeat_node_serialize,
   gsk_repeat_node_deserialize
 };
@@ -3137,6 +3172,8 @@ static const GskRenderNodeClass GSK_CLIP_NODE_CLASS = {
   "GskClipNode",
   gsk_clip_node_finalize,
   gsk_clip_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_clip_node_serialize,
   gsk_clip_node_deserialize
 };
@@ -3298,6 +3335,8 @@ static const GskRenderNodeClass GSK_ROUNDED_CLIP_NODE_CLASS = {
   "GskRoundedClipNode",
   gsk_rounded_clip_node_finalize,
   gsk_rounded_clip_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_rounded_clip_node_serialize,
   gsk_rounded_clip_node_deserialize
 };
@@ -3521,6 +3560,8 @@ static const GskRenderNodeClass GSK_SHADOW_NODE_CLASS = {
   "GskShadowNode",
   gsk_shadow_node_finalize,
   gsk_shadow_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_shadow_node_serialize,
   gsk_shadow_node_deserialize
 };
@@ -3735,6 +3776,8 @@ static const GskRenderNodeClass GSK_BLEND_NODE_CLASS = {
   "GskBlendNode",
   gsk_blend_node_finalize,
   gsk_blend_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_blend_node_serialize,
   gsk_blend_node_deserialize
 };
@@ -3905,6 +3948,8 @@ static const GskRenderNodeClass GSK_CROSS_FADE_NODE_CLASS = {
   "GskCrossFadeNode",
   gsk_cross_fade_node_finalize,
   gsk_cross_fade_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_cross_fade_node_serialize,
   gsk_cross_fade_node_deserialize
 };
@@ -4126,6 +4171,8 @@ static const GskRenderNodeClass GSK_TEXT_NODE_CLASS = {
   "GskTextNode",
   gsk_text_node_finalize,
   gsk_text_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_text_node_serialize,
   gsk_text_node_deserialize
 };
@@ -4511,6 +4558,8 @@ static const GskRenderNodeClass GSK_BLUR_NODE_CLASS = {
   "GskBlurNode",
   gsk_blur_node_finalize,
   gsk_blur_node_draw,
+  gsk_render_node_can_diff_impossible,
+  gsk_render_node_diff_impossible,
   gsk_blur_node_serialize,
   gsk_blur_node_deserialize
 };
index dad1703e0b36a0c97424bc39ba1c7c8406370b11..5cae3ec56216c7c1c61647f825b29bf1c6555cff 100644 (file)
@@ -31,6 +31,11 @@ struct _GskRenderNodeClass
   void            (* finalize)    (GskRenderNode  *node);
   void            (* draw)        (GskRenderNode  *node,
                                    cairo_t        *cr);
+  gboolean        (* can_diff)    (GskRenderNode  *node1,
+                                   GskRenderNode  *node2);
+  void            (* diff)        (GskRenderNode  *node1,
+                                   GskRenderNode  *node2,
+                                   cairo_region_t *region);
   GVariant *      (* serialize)   (GskRenderNode  *node);
   GskRenderNode * (* deserialize) (GVariant       *variant,
                                    GError        **error);
@@ -39,6 +44,15 @@ struct _GskRenderNodeClass
 GskRenderNode * gsk_render_node_new              (const GskRenderNodeClass  *node_class,
                                                   gsize                      extra_size);
 
+gboolean        gsk_render_node_can_diff         (GskRenderNode             *node1,
+                                                  GskRenderNode             *node2);
+void            gsk_render_node_diff             (GskRenderNode             *node1,
+                                                  GskRenderNode             *node2,
+                                                  cairo_region_t            *region);
+void            gsk_render_node_diff_impossible  (GskRenderNode             *node1,
+                                                  GskRenderNode             *node2,
+                                                  cairo_region_t            *region);
+
 GVariant *      gsk_render_node_serialize_node   (GskRenderNode             *node);
 GskRenderNode * gsk_render_node_deserialize_node (GskRenderNodeType          type,
                                                   GVariant                  *variant,