[gtk/wip/matthiasc/mask-node: 2/2] Introduce mask nodes




commit df48be7c4ceb2f9f4384f83c53341aa42ccc4ca6
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Mar 28 19:06:39 2018 +0200

    Introduce mask nodes
    
    Add GskMaskNode, and support it in the render node
    parser, in the inspector and in GtkSnapshot.
    
    The rendering is just fallback for now.
    
    Based on old work by Timm Bäder.

 gsk/gl/gskglrenderer.c           |  1 +
 gsk/gskenums.h                   |  3 +-
 gsk/gskrendernode.h              | 12 +++++
 gsk/gskrendernodeimpl.c          | 94 ++++++++++++++++++++++++++++++++++++++++
 gsk/gskrendernodeparser.c        | 37 ++++++++++++++++
 gsk/gskrendernodeprivate.h       |  2 +-
 gsk/vulkan/gskvulkanrenderpass.c |  1 +
 gtk/gtksnapshot.c                | 70 ++++++++++++++++++++++++++++++
 gtk/gtksnapshot.h                |  2 +
 gtk/inspector/recorder.c         |  8 ++++
 10 files changed, 228 insertions(+), 2 deletions(-)
---
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index 1731b7ca46..a740dcf119 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -3808,6 +3808,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer   *self,
     case GSK_REPEATING_LINEAR_GRADIENT_NODE:
     case GSK_REPEATING_RADIAL_GRADIENT_NODE:
     case GSK_CAIRO_NODE:
+    case GSK_MASK_NODE:
     default:
       {
         render_fallback_node (self, node, builder);
diff --git a/gsk/gskenums.h b/gsk/gskenums.h
index 243ab67cc8..1ae8bdcb00 100644
--- a/gsk/gskenums.h
+++ b/gsk/gskenums.h
@@ -79,7 +79,8 @@ typedef enum {
   GSK_TEXT_NODE,
   GSK_BLUR_NODE,
   GSK_DEBUG_NODE,
-  GSK_GL_SHADER_NODE
+  GSK_GL_SHADER_NODE,
+  GSK_MASK_NODE,
 } GskRenderNodeType;
 
 /**
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index 99af00286f..ac41d65f79 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -164,6 +164,7 @@ GskRenderNode *         gsk_render_node_deserialize             (GBytes
 #define GSK_TYPE_TEXT_NODE                      (gsk_text_node_get_type())
 #define GSK_TYPE_BLUR_NODE                      (gsk_blur_node_get_type())
 #define GSK_TYPE_GL_SHADER_NODE                 (gsk_gl_shader_node_get_type())
+#define GSK_TYPE_MASK_NODE                      (gsk_mask_node_get_type())
 
 typedef struct _GskDebugNode                    GskDebugNode;
 typedef struct _GskColorNode                    GskColorNode;
@@ -190,6 +191,7 @@ typedef struct _GskCrossFadeNode                GskCrossFadeNode;
 typedef struct _GskTextNode                     GskTextNode;
 typedef struct _GskBlurNode                     GskBlurNode;
 typedef struct _GskGLShaderNode                 GskGLShaderNode;
+typedef struct _GskMaskNode                     GskMaskNode;
 
 GDK_AVAILABLE_IN_ALL
 GType                   gsk_debug_node_get_type                 (void) G_GNUC_CONST;
@@ -531,6 +533,16 @@ GBytes *                gsk_gl_shader_node_get_args             (GskRenderNode
 GDK_AVAILABLE_IN_ALL
 GskGLShader *           gsk_gl_shader_node_get_shader           (GskRenderNode            *node);
 
+GDK_AVAILABLE_IN_ALL
+GType                   gsk_mask_node_get_type                  (void) G_GNUC_CONST;
+GDK_AVAILABLE_IN_ALL
+GskRenderNode *         gsk_mask_node_new                       (GskRenderNode            *source_child,
+                                                                 GskRenderNode            *mask_child);
+GDK_AVAILABLE_IN_ALL
+GskRenderNode *         gsk_mask_node_get_source                (GskRenderNode            *node);
+GDK_AVAILABLE_IN_ALL
+GskRenderNode *         gsk_mask_node_get_mask                  (GskRenderNode            *node);
+
 G_END_DECLS
 
 #endif /* __GSK_RENDER_NODE_H__ */
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index 9c93417423..6b570d42a6 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -5175,6 +5175,83 @@ gsk_gl_shader_node_get_args (GskRenderNode *node)
   return self->args;
 }
 
+/*** GSK_MASK_NODE ***/
+
+typedef struct _GskMaskNode GskMaskNode;
+
+struct _GskMaskNode
+{
+  GskRenderNode render_node;
+
+  GskRenderNode *mask_child;
+  GskRenderNode *source_child;
+};
+
+static void
+gsk_mask_node_finalize (GskRenderNode *node)
+{
+  GskMaskNode *self = (GskMaskNode *) node;
+
+  gsk_render_node_unref (self->source_child);
+  gsk_render_node_unref (self->mask_child);
+}
+
+static void
+gsk_mask_node_draw (GskRenderNode *node,
+                    cairo_t       *cr)
+{
+  GskMaskNode *self = (GskMaskNode *) node;
+  cairo_pattern_t *mask_pattern;
+
+  cairo_push_group (cr);
+  gsk_render_node_draw (self->source_child, cr);
+  cairo_pop_group_to_source (cr);
+
+  cairo_push_group (cr);
+  gsk_render_node_draw (self->mask_child, cr);
+  mask_pattern = cairo_pop_group (cr);
+
+  cairo_mask (cr, mask_pattern);
+}
+
+GskRenderNode *
+gsk_mask_node_new (GskRenderNode *source_child,
+                   GskRenderNode *mask_child)
+{
+  GskMaskNode *self;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE (source_child), NULL);
+  g_return_val_if_fail (GSK_IS_RENDER_NODE (mask_child), NULL);
+
+  self = gsk_render_node_alloc (GSK_MASK_NODE);
+  self->source_child = gsk_render_node_ref (source_child);
+  self->mask_child = gsk_render_node_ref (mask_child);
+
+  graphene_rect_union (&source_child->bounds, &mask_child->bounds, &self->render_node.bounds);
+
+  return &self->render_node;
+}
+
+GskRenderNode *
+gsk_mask_node_get_source (GskRenderNode *node)
+{
+  GskMaskNode *self = (GskMaskNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_MASK_NODE), NULL);
+
+  return self->source_child;
+}
+
+GskRenderNode *
+gsk_mask_node_get_mask (GskRenderNode *node)
+{
+  GskMaskNode *self = (GskMaskNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_MASK_NODE), NULL);
+
+  return self->mask_child;
+}
+
 GType gsk_render_node_types[GSK_RENDER_NODE_TYPE_N_TYPES];
 
 #ifndef I_
@@ -5214,6 +5291,7 @@ GSK_DEFINE_RENDER_NODE_TYPE (gsk_text_node, GSK_TEXT_NODE)
 GSK_DEFINE_RENDER_NODE_TYPE (gsk_blur_node, GSK_BLUR_NODE)
 GSK_DEFINE_RENDER_NODE_TYPE (gsk_gl_shader_node, GSK_GL_SHADER_NODE)
 GSK_DEFINE_RENDER_NODE_TYPE (gsk_debug_node, GSK_DEBUG_NODE)
+GSK_DEFINE_RENDER_NODE_TYPE (gsk_mask_node, GSK_MASK_NODE)
 
 static void
 gsk_render_node_init_types_once (void)
@@ -5617,6 +5695,22 @@ gsk_render_node_init_types_once (void)
     GType node_type = gsk_render_node_type_register_static (I_("GskDebugNode"), &node_info);
     gsk_render_node_types[GSK_DEBUG_NODE] = node_type;
   }
+
+  {
+    const GskRenderNodeTypeInfo node_info =
+    {
+      GSK_MASK_NODE,
+      sizeof (GskMaskNode),
+      NULL,
+      gsk_mask_node_finalize,
+      gsk_mask_node_draw,
+      NULL,
+      NULL,
+    };
+
+    GType node_type = gsk_render_node_type_register_static (I_("GskMaskNode"), &node_info);
+    gsk_render_node_types[GSK_MASK_NODE] = node_type;
+  }
 }
 /*< private >
  * gsk_render_node_init_types:
diff --git a/gsk/gskrendernodeparser.c b/gsk/gskrendernodeparser.c
index 756147adb2..a487632421 100644
--- a/gsk/gskrendernodeparser.c
+++ b/gsk/gskrendernodeparser.c
@@ -1565,6 +1565,31 @@ parse_blend_node (GtkCssParser *parser)
   return result;
 }
 
+static GskRenderNode *
+parse_mask_node (GtkCssParser *parser)
+{
+  GskRenderNode *source = NULL;
+  GskRenderNode *mask = NULL;
+  const Declaration declarations[] = {
+    { "source", parse_node, clear_node, &source },
+    { "mask", parse_node, clear_node, &mask },
+  };
+  GskRenderNode *result;
+
+  parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
+  if (source == NULL)
+    source = create_default_render_node ();
+  if (mask == NULL)
+    mask = gsk_color_node_new (&GDK_RGBA("AAFF00"), &GRAPHENE_RECT_INIT (0, 0, 50, 50));
+
+  result = gsk_mask_node_new (source, mask);
+
+  gsk_render_node_unref (source);
+  gsk_render_node_unref (mask);
+
+  return result;
+}
+
 static GskRenderNode *
 parse_repeat_node (GtkCssParser *parser)
 {
@@ -1843,6 +1868,7 @@ parse_node (GtkCssParser *parser,
     { "texture", parse_texture_node },
     { "transform", parse_transform_node },
     { "glshader", parse_glshader_node },
+    { "mask", parse_mask_node },
   };
   GskRenderNode **node_p = out_node;
   guint i;
@@ -2911,6 +2937,17 @@ render_node_print (Printer       *p,
       }
       break;
 
+    case GSK_MASK_NODE:
+      {
+        start_node (p, "mask");
+
+        append_node_param (p, "source", gsk_mask_node_get_source (node));
+        append_node_param (p, "mask", gsk_mask_node_get_mask (node));
+
+        end_node (p);
+      }
+      break;
+
     case GSK_NOT_A_RENDER_NODE:
       g_assert_not_reached ();
       break;
diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h
index 7e11a14b8f..89da9a1649 100644
--- a/gsk/gskrendernodeprivate.h
+++ b/gsk/gskrendernodeprivate.h
@@ -13,7 +13,7 @@ typedef struct _GskRenderNodeClass GskRenderNodeClass;
  * We don't add an "n-types" value to avoid having to handle
  * it in every single switch.
  */
-#define GSK_RENDER_NODE_TYPE_N_TYPES    (GSK_GL_SHADER_NODE + 1)
+#define GSK_RENDER_NODE_TYPE_N_TYPES    (GSK_MASK_NODE + 1)
 
 extern GType gsk_render_node_types[];
 
diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c
index d81d38fa33..0443555557 100644
--- a/gsk/vulkan/gskvulkanrenderpass.c
+++ b/gsk/vulkan/gskvulkanrenderpass.c
@@ -260,6 +260,7 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass           *self,
     case GSK_RADIAL_GRADIENT_NODE:
     case GSK_REPEATING_RADIAL_GRADIENT_NODE:
     case GSK_CONIC_GRADIENT_NODE:
+    case GSK_MASK_NODE:
     default:
       FALLBACK ("Unsupported node '%s'", g_type_name_from_instance ((GTypeInstance *) node));
 
diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c
index 7c5c744842..a7114992db 100644
--- a/gtk/gtksnapshot.c
+++ b/gtk/gtksnapshot.c
@@ -124,6 +124,9 @@ struct _GtkSnapshotState {
     struct {
       char *message;
     } debug;
+    struct {
+      GskRenderNode *source_node;
+    } mask;
   } data;
 };
 
@@ -1251,6 +1254,73 @@ gtk_snapshot_push_blend (GtkSnapshot  *snapshot,
                            NULL);
 }
 
+static GskRenderNode *
+gtk_snapshot_collect_mask_mask (GtkSnapshot      *snapshot,
+                                GtkSnapshotState *state,
+                                GskRenderNode   **nodes,
+                                guint             n_nodes)
+{
+  GskRenderNode *source_child, *mask_child, *mask_node;
+
+  mask_child = gtk_snapshot_collect_default (snapshot, state, nodes, n_nodes);
+  source_child = state->data.mask.source_node;
+
+  if (source_child == NULL ||
+      mask_child == NULL)
+    return NULL;
+
+  mask_node = gsk_mask_node_new (source_child, mask_child);
+
+  gsk_render_node_unref (source_child);
+  gsk_render_node_unref (mask_child);
+
+  return mask_node;
+}
+
+static GskRenderNode *
+gtk_snapshot_collect_mask_source (GtkSnapshot      *snapshot,
+                                  GtkSnapshotState *state,
+                                  GskRenderNode   **nodes,
+                                  guint             n_nodes)
+{
+  GtkSnapshotState *prev_state = gtk_snapshot_get_previous_state (snapshot);
+
+  g_assert (prev_state->collect_func == gtk_snapshot_collect_mask_mask);
+
+  prev_state->data.mask.source_node = gtk_snapshot_collect_default (snapshot, state, nodes, n_nodes);
+
+  return NULL;
+}
+
+static void
+gtk_snapshot_clear_mask_source (GtkSnapshotState *state)
+{
+  g_clear_pointer (&(state->data.mask.source_node), gsk_render_node_unref);
+}
+
+/**
+ * gtk_snapshot_push_mask:
+ * @snapshot: a #GtkSnapshot
+ *
+ * Calling this function requires 2 subsequent calls to gtk_snapshot_pop().
+ **/
+void
+gtk_snapshot_push_mask (GtkSnapshot *snapshot)
+{
+  GtkSnapshotState *current_state = gtk_snapshot_get_current_state (snapshot);
+  GtkSnapshotState *source_state;
+
+  source_state = gtk_snapshot_push_state (snapshot,
+                                          current_state->transform,
+                                          gtk_snapshot_collect_mask_source,
+                                          gtk_snapshot_clear_mask_source);
+
+  gtk_snapshot_push_state (snapshot,
+                           source_state->transform,
+                           gtk_snapshot_collect_mask_mask,
+                           NULL);
+}
+
 static GskRenderNode *
 gtk_snapshot_collect_cross_fade_end (GtkSnapshot      *snapshot,
                                      GtkSnapshotState *state,
diff --git a/gtk/gtksnapshot.h b/gtk/gtksnapshot.h
index 6125e44ecc..d64b00a9e8 100644
--- a/gtk/gtksnapshot.h
+++ b/gtk/gtksnapshot.h
@@ -96,6 +96,8 @@ GDK_AVAILABLE_IN_ALL
 void            gtk_snapshot_push_blend                 (GtkSnapshot            *snapshot,
                                                          GskBlendMode            blend_mode);
 GDK_AVAILABLE_IN_ALL
+void            gtk_snapshot_push_mask                  (GtkSnapshot            *snapshot);
+GDK_AVAILABLE_IN_ALL
 void            gtk_snapshot_push_cross_fade            (GtkSnapshot            *snapshot,
                                                          double                  progress);
 GDK_AVAILABLE_IN_ALL
diff --git a/gtk/inspector/recorder.c b/gtk/inspector/recorder.c
index 7e07e4413a..a1d413c603 100644
--- a/gtk/inspector/recorder.c
+++ b/gtk/inspector/recorder.c
@@ -168,6 +168,10 @@ create_list_model_for_render_node (GskRenderNode *node)
       return create_render_node_list_model ((GskRenderNode *[2]) { gsk_blend_node_get_bottom_child (node), 
                                                                    gsk_blend_node_get_top_child (node) }, 2);
 
+    case GSK_MASK_NODE:
+      return create_render_node_list_model ((GskRenderNode *[2]) { gsk_mask_node_get_source (node), 
+                                                                   gsk_mask_node_get_mask (node) }, 2);
+
     case GSK_CROSS_FADE_NODE:
       return create_render_node_list_model ((GskRenderNode *[2]) { gsk_cross_fade_node_get_start_child 
(node),
                                                                    gsk_cross_fade_node_get_end_child (node) 
}, 2);
@@ -294,6 +298,8 @@ node_type_name (GskRenderNodeType type)
       return "Blur";
     case GSK_GL_SHADER_NODE:
       return "GL Shader";
+    case GSK_MASK_NODE:
+      return "Mask";
     }
 }
 
@@ -323,6 +329,7 @@ node_name (GskRenderNode *node)
     case GSK_ROUNDED_CLIP_NODE:
     case GSK_SHADOW_NODE:
     case GSK_BLEND_NODE:
+    case GSK_MASK_NODE:
     case GSK_CROSS_FADE_NODE:
     case GSK_TEXT_NODE:
     case GSK_BLUR_NODE:
@@ -1136,6 +1143,7 @@ populate_render_node_properties (GtkListStore  *store,
       break;
 
     case GSK_NOT_A_RENDER_NODE:
+    case GSK_MASK_NODE:
     default:
       break;
     }


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