[gtk+/wip/otte/rendernode: 71/100] gsk: Add blend nodes



commit 1fba362bb83a81d0b7f6991c6342d7272cf6b252
Author: Benjamin Otte <otte redhat com>
Date:   Thu Dec 15 04:24:37 2016 +0100

    gsk: Add blend nodes
    
    Implement blend mode support in GTK background compositing with it.

 docs/reference/gsk/gsk4-sections.txt   |    4 +-
 gsk/gskenums.h                         |    4 +-
 gsk/gskglrenderer.c                    |    2 +-
 gsk/gskrendernode.c                    |   41 --------
 gsk/gskrendernode.h                    |    5 +-
 gsk/gskrendernodeimpl.c                |  178 ++++++++++++++++++++++++++++++++
 gsk/gskrendernodeprivate.h             |   10 +--
 gtk/gtkrenderbackground.c              |   46 +++++++--
 gtk/inspector/gtktreemodelrendernode.c |   11 ++
 gtk/inspector/recorder.c               |   19 ----
 10 files changed, 240 insertions(+), 80 deletions(-)
---
diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt
index a12c28d..c044864 100644
--- a/docs/reference/gsk/gsk4-sections.txt
+++ b/docs/reference/gsk/gsk4-sections.txt
@@ -29,8 +29,6 @@ gsk_render_node_unref
 GskRenderNodeType
 gsk_render_node_get_node_type
 gsk_render_node_draw
-GskBlendMode
-gsk_render_node_set_blend_mode
 GskScalingFilter
 gsk_render_node_set_scaling_filters
 gsk_render_node_set_name
@@ -49,6 +47,8 @@ gsk_clip_node_new
 gsk_clip_node_get_child
 gsk_rounded_clip_node_new
 gsk_rounded_clip_node_get_child
+GskBlendMode
+gsk_blend_node_new
 <SUBSECTION Standard>
 GSK_IS_RENDER_NODE
 GSK_RENDER_NODE
diff --git a/gsk/gskenums.h b/gsk/gskenums.h
index 145d035..d647495 100644
--- a/gsk/gskenums.h
+++ b/gsk/gskenums.h
@@ -34,6 +34,7 @@
  * @GSK_OPACITY_NODE: A node that changes the opacity of its child
  * @GSK_CLIP_NODE: A node that clips its child to a rectangular area
  * @GSK_ROUNDED_CLIP_NODE: A node that clips its child to a rounded rectangle
+ * @GSK_BLEND_NODE: A node the blends two children together
  *
  * The type of a node determines what the node is rendering.
  *
@@ -48,7 +49,8 @@ typedef enum {
   GSK_TRANSFORM_NODE,
   GSK_OPACITY_NODE,
   GSK_CLIP_NODE,
-  GSK_ROUNDED_CLIP_NODE
+  GSK_ROUNDED_CLIP_NODE,
+  GSK_BLEND_NODE
 } GskRenderNodeType;
 
 /**
diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c
index 7812121..1c09244 100644
--- a/gsk/gskglrenderer.c
+++ b/gsk/gskglrenderer.c
@@ -644,7 +644,7 @@ gsk_gl_renderer_add_render_item (GskGLRenderer           *self,
 
   item.opacity = 1.0;
 
-  item.blend_mode = gsk_render_node_get_blend_mode (node);
+  item.blend_mode = GSK_BLEND_MODE_DEFAULT;
 
   /* Back-pointer to the parent node */
   if (parent != NULL)
diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c
index ab41235..20d9bef 100644
--- a/gsk/gskrendernode.c
+++ b/gsk/gskrendernode.c
@@ -237,47 +237,6 @@ gsk_render_node_get_name (GskRenderNode *node)
   return node->name;
 }
 
-/**
- * gsk_render_node_set_blend_mode:
- * @node: a #GskRenderNode
- * @blend_mode: the blend mode to be applied to the node's children
- *
- * Sets the blend mode to be used when rendering the children
- * of the @node.
- *
- * The default value is %GSK_BLEND_MODE_DEFAULT.
- *
- * Since: 3.90
- */
-void
-gsk_render_node_set_blend_mode (GskRenderNode *node,
-                                GskBlendMode   blend_mode)
-{
-  g_return_if_fail (GSK_IS_RENDER_NODE (node));
-  g_return_if_fail (node->is_mutable);
-
-  if (node->blend_mode == blend_mode)
-    return;
-
-  node->blend_mode = blend_mode;
-}
-
-/*
- * gsk_render_node_get_blend_mode:
- * @node: a #GskRenderNode
- *
- * Retrieves the blend mode set by gsk_render_node_set_blend_mode().
- *
- * Returns: the blend mode
- */
-GskBlendMode
-gsk_render_node_get_blend_mode (GskRenderNode *node)
-{
-  g_return_val_if_fail (GSK_IS_RENDER_NODE (node), GSK_BLEND_MODE_DEFAULT);
-
-  return node->blend_mode;
-}
-
 /*< private >
  * gsk_render_node_make_immutable:
  * @node: a #GskRenderNode
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index 708a77d..5d92c73 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -93,8 +93,9 @@ GDK_AVAILABLE_IN_3_90
 GskRenderNode *         gsk_rounded_clip_node_get_child         (GskRenderNode            *node);
 
 GDK_AVAILABLE_IN_3_90
-void                    gsk_render_node_set_blend_mode          (GskRenderNode *node,
-                                                                 GskBlendMode   blend_mode);
+GskRenderNode *         gsk_blend_node_new                      (GskRenderNode            *bottom,
+                                                                 GskRenderNode            *top,
+                                                                 GskBlendMode              blend_mode);
 
 GDK_AVAILABLE_IN_3_90
 void                    gsk_render_node_set_scaling_filter      (GskRenderNode *node,
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index 9dbfd3f..90f90f1 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -1068,3 +1068,181 @@ gsk_rounded_clip_node_peek_clip (GskRenderNode *node)
   return &self->clip;
 }
 
+/*** GSK_BLEND_NODE ***/
+
+typedef struct _GskBlendNode GskBlendNode;
+
+struct _GskBlendNode
+{
+  GskRenderNode render_node;
+
+  GskRenderNode *bottom;
+  GskRenderNode *top;
+  GskBlendMode blend_mode;
+};
+
+static cairo_operator_t
+gsk_blend_mode_to_cairo_operator (GskBlendMode blend_mode)
+{
+  switch (blend_mode)
+    {
+    default:
+      g_assert_not_reached ();
+    case GSK_BLEND_MODE_DEFAULT:
+      return CAIRO_OPERATOR_OVER;
+    case GSK_BLEND_MODE_MULTIPLY:
+      return CAIRO_OPERATOR_MULTIPLY;
+    case GSK_BLEND_MODE_SCREEN:
+      return CAIRO_OPERATOR_SCREEN;
+    case GSK_BLEND_MODE_OVERLAY:
+      return CAIRO_OPERATOR_OVERLAY;
+    case GSK_BLEND_MODE_DARKEN:
+      return CAIRO_OPERATOR_DARKEN;
+    case GSK_BLEND_MODE_LIGHTEN:
+      return CAIRO_OPERATOR_LIGHTEN;
+    case GSK_BLEND_MODE_COLOR_DODGE:
+      return CAIRO_OPERATOR_COLOR_DODGE;
+    case GSK_BLEND_MODE_COLOR_BURN:
+      return CAIRO_OPERATOR_COLOR_BURN;
+    case GSK_BLEND_MODE_HARD_LIGHT:
+      return CAIRO_OPERATOR_HARD_LIGHT;
+    case GSK_BLEND_MODE_SOFT_LIGHT:
+      return CAIRO_OPERATOR_SOFT_LIGHT;
+    case GSK_BLEND_MODE_DIFFERENCE:
+      return CAIRO_OPERATOR_DIFFERENCE;
+    case GSK_BLEND_MODE_EXCLUSION:
+      return CAIRO_OPERATOR_EXCLUSION;
+    case GSK_BLEND_MODE_COLOR:
+      return CAIRO_OPERATOR_HSL_COLOR;
+    case GSK_BLEND_MODE_HUE:
+      return CAIRO_OPERATOR_HSL_HUE;
+    case GSK_BLEND_MODE_SATURATION:
+      return CAIRO_OPERATOR_HSL_SATURATION;
+    case GSK_BLEND_MODE_LUMINOSITY:
+      return CAIRO_OPERATOR_HSL_LUMINOSITY;
+    }
+}
+
+static void
+gsk_blend_node_finalize (GskRenderNode *node)
+{
+  GskBlendNode *self = (GskBlendNode *) node;
+
+  gsk_render_node_unref (self->bottom);
+  gsk_render_node_unref (self->top);
+}
+
+static void
+gsk_blend_node_make_immutable (GskRenderNode *node)
+{
+  GskBlendNode *self = (GskBlendNode *) node;
+
+  gsk_render_node_make_immutable (self->bottom);
+  gsk_render_node_make_immutable (self->top);
+}
+
+static void
+gsk_blend_node_draw (GskRenderNode *node,
+                     cairo_t       *cr)
+{
+  GskBlendNode *self = (GskBlendNode *) node;
+
+  cairo_push_group (cr);
+  gsk_render_node_draw (self->bottom, cr);
+
+  cairo_push_group (cr);
+  gsk_render_node_draw (self->top, cr);
+
+  cairo_pop_group_to_source (cr);
+  cairo_set_operator (cr, gsk_blend_mode_to_cairo_operator (self->blend_mode));
+  cairo_paint (cr);
+
+  cairo_pop_group_to_source (cr); /* resets operator */
+  cairo_paint (cr);
+}
+
+static void
+gsk_blend_node_get_bounds (GskRenderNode   *node,
+                           graphene_rect_t *bounds)
+{
+  GskBlendNode *self = (GskBlendNode *) node;
+  graphene_rect_t bottom_bounds, top_bounds;
+
+  gsk_render_node_get_bounds (self->bottom, &bottom_bounds);
+  gsk_render_node_get_bounds (self->top, &top_bounds);
+
+  graphene_rect_union (&bottom_bounds, &top_bounds, bounds);
+}
+
+static const GskRenderNodeClass GSK_BLEND_NODE_CLASS = {
+  GSK_BLEND_NODE,
+  sizeof (GskBlendNode),
+  "GskBlendNode",
+  gsk_blend_node_finalize,
+  gsk_blend_node_make_immutable,
+  gsk_blend_node_draw,
+  gsk_blend_node_get_bounds
+};
+
+/**
+ * gsk_blend_node_new:
+ * @bottom: The bottom node to be drawn
+ * @top: The node to be blended onto the @bottom node
+ * @blend_mode: The blend mode to use
+ *
+ * Creates a #GskRenderNode that will use @blend_mode to blend the @top
+ * node onto the @bottom node.
+ *
+ * Returns: A new #GskRenderNode
+ *
+ * Since: 3.90
+ */
+GskRenderNode *
+gsk_blend_node_new (GskRenderNode *bottom,
+                    GskRenderNode *top,
+                    GskBlendMode   blend_mode)
+{
+  GskBlendNode *self;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE (bottom), NULL);
+  g_return_val_if_fail (GSK_IS_RENDER_NODE (top), NULL);
+
+  self = (GskBlendNode *) gsk_render_node_new (&GSK_BLEND_NODE_CLASS);
+
+  self->bottom = gsk_render_node_ref (bottom);
+  self->top = gsk_render_node_ref (top);
+  self->blend_mode = blend_mode;
+
+  return &self->render_node;
+}
+
+GskRenderNode *
+gsk_blend_node_get_bottom_child (GskRenderNode *node)
+{
+  GskBlendNode *self = (GskBlendNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_BLEND_NODE), NULL);
+
+  return self->bottom;
+}
+
+GskRenderNode *
+gsk_blend_node_get_top_child (GskRenderNode *node)
+{
+  GskBlendNode *self = (GskBlendNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_BLEND_NODE), NULL);
+
+  return self->top;
+}
+
+GskBlendMode
+gsk_blend_node_get_blend_mode (GskRenderNode *node)
+{
+  GskBlendNode *self = (GskBlendNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_BLEND_NODE), GSK_BLEND_MODE_DEFAULT);
+
+  return self->blend_mode;
+}
+
diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h
index 98f8fc3..e4b9ee4 100644
--- a/gsk/gskrendernodeprivate.h
+++ b/gsk/gskrendernodeprivate.h
@@ -19,12 +19,6 @@ struct _GskRenderNode
   /* Use for debugging */
   char *name;
 
-  /* Paint opacity */
-  double opacity;
-
-  /* Blend mode */
-  GskBlendMode blend_mode;
-
   /* Scaling filters */
   GskScalingFilter min_filter;
   GskScalingFilter mag_filter;
@@ -66,7 +60,9 @@ const GskRoundedRect * gsk_rounded_clip_node_peek_clip (GskRenderNode *node);
 
 void gsk_transform_node_get_transform (GskRenderNode *node, graphene_matrix_t *transform);
 
-GskBlendMode gsk_render_node_get_blend_mode (GskRenderNode *node);
+GskRenderNode * gsk_blend_node_get_bottom_child (GskRenderNode *node);
+GskRenderNode * gsk_blend_node_get_top_child (GskRenderNode *node);
+GskBlendMode gsk_blend_node_get_blend_node (GskRenderNode *node);
 
 G_END_DECLS
 
diff --git a/gtk/gtkrenderbackground.c b/gtk/gtkrenderbackground.c
index 0bedcf1..10f54c6 100644
--- a/gtk/gtkrenderbackground.c
+++ b/gtk/gtkrenderbackground.c
@@ -683,22 +683,54 @@ gtk_css_style_snapshot_background (GtkCssStyle      *style,
    */
   if (_gtk_theming_background_needs_push_group (style))
     {
-      cairo_t *cr;
+      GtkCssValue *blend_modes;
+      GskBlendMode blend_mode;
 
-      cr = gtk_snapshot_append_cairo_node (snapshot,
-                                           &GRAPHENE_RECT_INIT (0, 0, width, height),
-                                           "Background");
+      blend_modes = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE);
 
-      _gtk_theming_background_paint_color (&bg, cr, bg_color, background_image);
+      gtk_snapshot_push (snapshot, TRUE, "BackgroundBlendGroup");
+
+      gtk_theming_background_snapshot_color (&bg, snapshot, bg_color, background_image);
 
       number_of_layers = _gtk_css_array_value_get_n_values (background_image);
 
       for (idx = number_of_layers - 1; idx >= 0; idx--)
         {
-          gtk_theming_background_paint_layer (&bg, idx, cr);
+          blend_mode = _gtk_css_blend_mode_value_get (_gtk_css_array_value_get_nth (blend_modes, idx));
+
+          if (blend_mode == GSK_BLEND_MODE_DEFAULT)
+            {
+              gtk_theming_background_snapshot_layer (&bg, idx, snapshot);
+            }
+          else
+            {
+              GskRenderNode *bottom, *top, *blend;
+
+              bottom = gtk_snapshot_pop (snapshot);
+
+              gtk_snapshot_push (snapshot, TRUE, "BackgroundBlendGroup<Mode%u>", blend_mode);
+              gtk_theming_background_snapshot_layer (&bg, idx, snapshot);
+              top = gtk_snapshot_pop (snapshot);
+
+              /* XXX: Is this necessary? Do we need a NULL node? */
+              if (top == NULL)
+                top = gsk_container_node_new (NULL, 0);
+              if (bottom == NULL)
+                bottom = gsk_container_node_new (NULL, 0);
+
+              blend = gsk_blend_node_new (bottom, top, blend_mode);
+              gsk_render_node_set_name (blend, "BackgroundBlend");
+
+              gtk_snapshot_push (snapshot, TRUE, "BackgroundBlendGroup");
+              gtk_snapshot_append_node (snapshot, blend);
+
+              gsk_render_node_unref (blend);
+              gsk_render_node_unref (top);
+              gsk_render_node_unref (bottom);
+            }
         }
 
-      cairo_destroy (cr);
+      gtk_snapshot_pop_and_append (snapshot);
     }
   else
     {
diff --git a/gtk/inspector/gtktreemodelrendernode.c b/gtk/inspector/gtktreemodelrendernode.c
index ce470ee..5426250 100644
--- a/gtk/inspector/gtktreemodelrendernode.c
+++ b/gtk/inspector/gtktreemodelrendernode.c
@@ -19,6 +19,8 @@
 
 #include "gtktreemodelrendernode.h"
 
+#include "gsk/gskrendernodeprivate.h"
+
 typedef struct _TreeElement TreeElement;
 
 /* This is an array of all nodes and the index of their parent. When adding a node,
@@ -542,6 +544,15 @@ append_node (GtkTreeModelRenderNode *nodemodel,
       append_node (nodemodel, gsk_rounded_clip_node_get_child (node), priv->nodes->len - 1);
       break;
 
+    case GSK_BLEND_NODE:
+      {
+        int elt_index = priv->nodes->len - 1;
+
+        append_node (nodemodel, gsk_blend_node_get_bottom_child (node), elt_index);
+        append_node (nodemodel, gsk_blend_node_get_top_child (node), elt_index);
+      }
+      break;
+
     case GSK_CONTAINER_NODE:
       {
         gint elt_index;
diff --git a/gtk/inspector/recorder.c b/gtk/inspector/recorder.c
index 1a0f5d1..839e828 100644
--- a/gtk/inspector/recorder.c
+++ b/gtk/inspector/recorder.c
@@ -133,9 +133,7 @@ populate_render_node_properties (GtkListStore  *store,
                                  GskRenderNode *node)
 {
   graphene_rect_t bounds;
-  int i;
   char *tmp;
-  GEnumClass *class;
 
   gtk_list_store_clear (store);
 
@@ -161,23 +159,6 @@ populate_render_node_properties (GtkListStore  *store,
                                      0, "Has Texture",
                                      1, gsk_render_node_get_node_type (node) == GSK_TEXTURE_NODE ? "TRUE" : 
"FALSE",
                                      -1);
-
-  class = g_type_class_ref (gsk_blend_mode_get_type ());
-  for (i = 0; i < class->n_values; i++)
-    {
-      if (class->values[i].value == gsk_render_node_get_blend_mode (node))
-        {
-          tmp = g_strdup (class->values[i].value_nick);
-          break;
-        }
-    }
-  g_type_class_unref (class);
-
-  gtk_list_store_insert_with_values (store, NULL, -1,
-                                     0, "Blendmode",
-                                     1, tmp,
-                                     -1);
-  g_free (tmp);
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]