Make mask nodes more versatile
authorMatthias Clasen <mclasen@redhat.com>
Tue, 14 Feb 2023 18:44:39 +0000 (13:44 -0500)
committerMatthias Clasen <mclasen@redhat.com>
Wed, 15 Feb 2023 00:07:01 +0000 (19:07 -0500)
Add a GskMaskMode enumeration and implement it
in the GL and cairo renderers.

13 files changed:
demos/gtk-demo/demo4widget.c
gdk/wayland/gdkglcontext-wayland.c
gdk/wayland/gdksurface-wayland.c
gsk/gl/gskglprograms.defs
gsk/gl/gskglrenderjob.c
gsk/gl/resources/mask.glsl
gsk/gskenums.h
gsk/gskrendernode.h
gsk/gskrendernodeimpl.c
gsk/gskrendernodeparser.c
gtk/gtksnapshot.c
gtk/gtksnapshot.h
gtk/inspector/recorder.c

index 347827219753e0797fb92ed7dfde274c1bcf1bc8..0152581c3da3304d11ac3788be8782b8a70618bc 100644 (file)
@@ -92,7 +92,7 @@ demo4_widget_snapshot (GtkWidget   *widget,
   width = gtk_widget_get_width (widget);
   height = gtk_widget_get_height (widget);
 
-  gtk_snapshot_push_mask (snapshot);
+  gtk_snapshot_push_mask (snapshot, GSK_MASK_MODE_INVERTED_ALPHA);
   gtk_snapshot_append_layout (snapshot, self->layout, &(GdkRGBA) { 0, 0, 0, 1 });
   gtk_snapshot_pop (snapshot);
 
index e7341d4fe68e182023ee3a08dc065a0844f8f0fa..44e15fa0fd87162e1144fd50d053b1964a87eb68 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "gdkdisplay-wayland.h"
 #include "gdksurface-wayland.h"
+#include "gdksurface-wayland-private.h"
 
 #include "gdkwaylanddisplay.h"
 #include "gdkwaylandglcontext.h"
@@ -60,10 +61,15 @@ gdk_wayland_gl_context_end_frame (GdkDrawContext *draw_context,
                                   cairo_region_t *painted)
 {
   GdkSurface *surface = gdk_draw_context_get_surface (draw_context);
+  GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+  int dx = impl->pending_buffer_offset_x;
+  int dy = impl->pending_buffer_offset_y;
 
   gdk_wayland_surface_sync (surface);
   gdk_wayland_surface_request_frame (surface);
 
+  wl_surface_offset (impl->display_server.wl_surface, dx, dy);
+
   GDK_DRAW_CONTEXT_CLASS (gdk_wayland_gl_context_parent_class)->end_frame (draw_context, painted);
 
   gdk_wayland_surface_notify_committed (surface);
index 62115ab8500523c7bde66d441a0f98dab1932df2..8e34132bcca87ae2baa429750124a293d27abad0 100644 (file)
@@ -229,7 +229,7 @@ gdk_wayland_surface_update_size (GdkSurface *surface,
 
   if (impl->display_server.egl_window)
     wl_egl_window_resize (impl->display_server.egl_window, width * scale, height * scale, 0, 0);
-  if (impl->display_server.wl_surface)
+  if (impl->display_server.wl_surface && scale_changed)
     wl_surface_set_buffer_scale (impl->display_server.wl_surface, scale);
 
   gdk_surface_invalidate_rect (surface, NULL);
@@ -588,6 +588,7 @@ gdk_wayland_surface_sync_offset (GdkSurface *surface)
       WL_SURFACE_OFFSET_SINCE_VERSION)
     return;
 
+#if 0
   if (impl->pending_buffer_offset_x == 0 &&
       impl->pending_buffer_offset_y == 0)
     return;
@@ -597,6 +598,7 @@ gdk_wayland_surface_sync_offset (GdkSurface *surface)
                      impl->pending_buffer_offset_y);
   impl->pending_buffer_offset_x = 0;
   impl->pending_buffer_offset_y = 0;
+#endif
 }
 
 void
index 3301529f9c2a9bce64a8f54bff574a5ea81f54e2..9afb826bf6e0a9e58271fa5ae9c607e2d7383410 100644 (file)
@@ -62,7 +62,8 @@ GSK_GL_DEFINE_PROGRAM (linear_gradient,
 
 GSK_GL_DEFINE_PROGRAM (mask,
                        GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("mask.glsl")),
-                       GSK_GL_ADD_UNIFORM (1, MASK_SOURCE, u_mask))
+                       GSK_GL_ADD_UNIFORM (1, MASK_SOURCE, u_mask)
+                       GSK_GL_ADD_UNIFORM (2, MASK_MODE, u_mode))
 
 GSK_GL_DEFINE_PROGRAM (outset_shadow,
                        GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("outset_shadow.glsl")),
index 6381bcbb14bea41051b3a6cadd813de6e1a5a518..83f928ba5d893a4078bd855a62fd92767e5b37b7 100644 (file)
@@ -3278,8 +3278,8 @@ gsk_gl_render_job_visit_blend_node (GskGLRenderJob      *job,
 }
 
 static inline void
-gsk_gl_render_job_visit_mask_node (GskGLRenderJob       *job,
-                                    const GskRenderNode *node)
+gsk_gl_render_job_visit_mask_node (GskGLRenderJob      *job,
+                                   const GskRenderNode *node)
 {
   const GskRenderNode *source = gsk_mask_node_get_source (node);
   const GskRenderNode *mask = gsk_mask_node_get_mask (node);
@@ -3293,6 +3293,7 @@ gsk_gl_render_job_visit_mask_node (GskGLRenderJob       *job,
   mask_offscreen.bounds = &node->bounds;
   mask_offscreen.force_offscreen = TRUE;
   mask_offscreen.reset_clip = TRUE;
+  mask_offscreen.do_not_cache = TRUE;
 
   /* TODO: We create 2 textures here as big as the mask node, but both
    * nodes might be a lot smaller than that.
@@ -3323,6 +3324,9 @@ gsk_gl_render_job_visit_mask_node (GskGLRenderJob       *job,
                                       GL_TEXTURE_2D,
                                       GL_TEXTURE1,
                                       mask_offscreen.texture_id);
+  gsk_gl_program_set_uniform1i (job->current_program,
+                                UNIFORM_MASK_MODE, 0,
+                                gsk_mask_node_get_mask_mode (node));
   gsk_gl_render_job_draw_offscreen_rect (job, &node->bounds);
   gsk_gl_render_job_end_draw (job);
 }
index 9c187b5a4efdd410a120d202297d5dc3455ee098..f856cb8fd017424cb023517d8e2672e60b75650a 100644 (file)
@@ -10,10 +10,24 @@ void main() {
 // FRAGMENT_SHADER:
 // mask.glsl
 
+uniform int u_mode;
 uniform sampler2D u_mask;
 
 void main() {
   vec4 source = GskTexture(u_source, vUv);
   vec4 mask = GskTexture(u_mask, vUv);
-  gskSetOutputColor(vec4 (source * mask.a));
+  float mask_value;
+
+  if (u_mode == 0)
+    mask_value = mask.a;
+  else if (u_mode == 1)
+    mask_value = 1 - mask.a;
+  else if (u_mode == 2)
+    mask_value = (0.2126 * mask.r + 0.7152 * mask.g + 0.0722 * mask.b) * mask.a;
+  else if (u_mode == 3)
+    mask_value = 1 - (0.2126 * mask.r + 0.7152 * mask.g + 0.0722 * mask.b) * mask.a;
+  else
+    mask_value = 0;
+
+  gskSetOutputColor(vec4 (source * mask_value));
 }
index 20bcf050202e6a12cd375a0b87b7453701e9eaa2..92e6aa456a8c446111935db0134c8e34584d3457 100644 (file)
@@ -255,5 +255,25 @@ typedef enum
   GSK_GL_UNIFORM_TYPE_VEC4,
 } GskGLUniformType;
 
+/**
+ * GskMaskMode:
+ * @GSK_MASK_MODE_ALPHA: Use the alpha channel of the mask
+ * @GSK_MASK_MODE_INVERTED_ALPHA: Use the inverted alpha channel of the mask
+ * @GSK_MASK_MODE_LUMINANCE: Use the luminance of the mask,
+ *     multiplied by mask alpha
+ * @GSK_MASK_MODE_INVERTED_LUMINANCE: Use the inverted luminance of the mask,
+ *     multiplied by mask alpha
+ *
+ * The mask modes available for mask nodes.
+ *
+ * Since: 4.10
+ */
+typedef enum
+{
+  GSK_MASK_MODE_ALPHA,
+  GSK_MASK_MODE_INVERTED_ALPHA,
+  GSK_MASK_MODE_LUMINANCE,
+  GSK_MASK_MODE_INVERTED_LUMINANCE
+} GskMaskMode;
 
 #endif /* __GSK_TYPES_H__ */
index 7147b0b848f9756ef491e15d57d00a887c79b8fb..36b7ae190c1cfb44886d9f7fc8dec1b8807cf406 100644 (file)
@@ -535,11 +535,14 @@ GDK_AVAILABLE_IN_4_10
 GType                  gsk_mask_node_get_type                   (void) G_GNUC_CONST;
 GDK_AVAILABLE_IN_4_10
 GskRenderNode *        gsk_mask_node_new                        (GskRenderNode            *source,
-                                                                 GskRenderNode            *mask);
+                                                                 GskRenderNode            *mask,
+                                                                 GskMaskMode               mask_mode);
 GDK_AVAILABLE_IN_4_10
 GskRenderNode *        gsk_mask_node_get_source                 (const GskRenderNode      *node);
 GDK_AVAILABLE_IN_4_10
 GskRenderNode *        gsk_mask_node_get_mask                   (const GskRenderNode      *node);
+GDK_AVAILABLE_IN_4_10
+GskMaskMode            gsk_mask_node_get_mask_mode              (const GskRenderNode      *node);
 
 GDK_AVAILABLE_IN_ALL
 GType                   gsk_gl_shader_node_get_type             (void) G_GNUC_CONST;
index f9de3752d3c8135d6728ea03280eeacca58b75bd..819446e88e09deae529dcadfed989272518e9cee 100644 (file)
@@ -3410,29 +3410,18 @@ gsk_color_matrix_node_finalize (GskRenderNode *node)
 }
 
 static void
-gsk_color_matrix_node_draw (GskRenderNode *node,
-                            cairo_t       *cr)
+apply_color_matrix_to_pattern (cairo_pattern_t         *pattern,
+                               const graphene_matrix_t *color_matrix,
+                               const graphene_vec4_t   *color_offset,
+                               gboolean                 multiply_alpha)
 {
-  GskColorMatrixNode *self = (GskColorMatrixNode *) node;
-  cairo_pattern_t *pattern;
   cairo_surface_t *surface, *image_surface;
-  graphene_vec4_t pixel;
-  guint32* pixel_data;
   guchar *data;
   gsize x, y, width, height, stride;
-  float alpha;
-
-  cairo_save (cr);
-
-  /* clip so the push_group() creates a smaller surface */
-  gsk_cairo_rectangle (cr, &node->bounds);
-  cairo_clip (cr);
-
-  cairo_push_group (cr);
-
-  gsk_render_node_draw (self->child, cr);
+  float alpha, orig_alpha;
+  graphene_vec4_t pixel;
+  guint32* pixel_data;
 
-  pattern = cairo_pop_group (cr);
   cairo_pattern_get_surface (pattern, &surface);
   image_surface = cairo_surface_map_to_image (surface, NULL);
 
@@ -3446,7 +3435,7 @@ gsk_color_matrix_node_draw (GskRenderNode *node,
       pixel_data = (guint32 *) data;
       for (x = 0; x < width; x++)
         {
-          alpha = ((pixel_data[x] >> 24) & 0xFF) / 255.0;
+          alpha = orig_alpha = ((pixel_data[x] >> 24) & 0xFF) / 255.0;
 
           if (alpha == 0)
             {
@@ -3459,12 +3448,16 @@ gsk_color_matrix_node_draw (GskRenderNode *node,
                                   ((pixel_data[x] >>  8) & 0xFF) / (255.0 * alpha),
                                   ( pixel_data[x]        & 0xFF) / (255.0 * alpha),
                                   alpha);
-              graphene_matrix_transform_vec4 (&self->color_matrix, &pixel, &pixel);
+              graphene_matrix_transform_vec4 (color_matrix, &pixel, &pixel);
             }
 
-          graphene_vec4_add (&pixel, &self->color_offset, &pixel);
+          graphene_vec4_add (&pixel, color_offset, &pixel);
 
           alpha = graphene_vec4_get_w (&pixel);
+
+          if (multiply_alpha)
+            alpha *= orig_alpha;
+
           if (alpha > 0.0)
             {
               alpha = MIN (alpha, 1.0);
@@ -3483,6 +3476,28 @@ gsk_color_matrix_node_draw (GskRenderNode *node,
 
   cairo_surface_mark_dirty (image_surface);
   cairo_surface_unmap_image (surface, image_surface);
+}
+
+static void
+gsk_color_matrix_node_draw (GskRenderNode *node,
+                            cairo_t       *cr)
+{
+  GskColorMatrixNode *self = (GskColorMatrixNode *) node;
+  cairo_pattern_t *pattern;
+
+  cairo_save (cr);
+
+  /* clip so the push_group() creates a smaller surface */
+  gsk_cairo_rectangle (cr, &node->bounds);
+  cairo_clip (cr);
+
+  cairo_push_group (cr);
+
+  gsk_render_node_draw (self->child, cr);
+
+  pattern = cairo_pop_group (cr);
+
+  apply_color_matrix_to_pattern (pattern, &self->color_matrix, &self->color_offset, FALSE);
 
   cairo_set_source (cr, pattern);
   cairo_paint (cr);
@@ -5202,6 +5217,7 @@ struct _GskMaskNode
 
   GskRenderNode *mask;
   GskRenderNode *source;
+  GskMaskMode mask_mode;
 };
 
 static void
@@ -5219,6 +5235,8 @@ gsk_mask_node_draw (GskRenderNode *node,
 {
   GskMaskNode *self = (GskMaskNode *) node;
   cairo_pattern_t *mask_pattern;
+  graphene_matrix_t color_matrix;
+  graphene_vec4_t color_offset;
 
   cairo_push_group (cr);
   gsk_render_node_draw (self->source, cr);
@@ -5228,6 +5246,41 @@ gsk_mask_node_draw (GskRenderNode *node,
   gsk_render_node_draw (self->mask, cr);
   mask_pattern = cairo_pop_group (cr);
 
+  switch (self->mask_mode)
+    {
+    case GSK_MASK_MODE_ALPHA:
+      break;
+    case GSK_MASK_MODE_INVERTED_ALPHA:
+      graphene_matrix_init_from_float (&color_matrix, (float[]){ 1, 0, 0, 0,
+                                                                 0, 1, 0, 0,
+                                                                 0, 0, 1, 0,
+                                                                 0, 0, 0, -1 });
+      graphene_vec4_init (&color_offset, 0, 0, 0, 1);
+      apply_color_matrix_to_pattern (mask_pattern, &color_matrix, &color_offset, FALSE);
+      break;
+    case GSK_MASK_MODE_LUMINANCE:
+      graphene_matrix_init_from_float (&color_matrix, (float[]){ 1, 0, 0, 0.2126,
+                                                                 0, 1, 0, 0.7152,
+                                                                 0, 0, 1, 0.0722,
+                                                                 0, 0, 0, 0 });
+      graphene_vec4_init (&color_offset, 0, 0, 0, 0);
+      apply_color_matrix_to_pattern (mask_pattern, &color_matrix, &color_offset, TRUE);
+      break;
+    case GSK_MASK_MODE_INVERTED_LUMINANCE:
+      graphene_matrix_init_from_float (&color_matrix, (float[]){ 1, 0, 0, -0.2126,
+                                                                 0, 1, 0, -0.7152,
+                                                                 0, 0, 1, -0.0722,
+                                                                 0, 0, 0,  0 });
+      graphene_vec4_init (&color_offset, 0, 0, 0, 1);
+      apply_color_matrix_to_pattern (mask_pattern, &color_matrix, &color_offset, TRUE);
+      break;
+    default:
+      g_assert_not_reached ();
+    }
+
+  gsk_cairo_rectangle (cr, &node->bounds);
+  cairo_clip (cr);
+
   cairo_mask (cr, mask_pattern);
 }
 
@@ -5245,11 +5298,15 @@ gsk_mask_node_diff (GskRenderNode  *node1,
 
 /**
  * gsk_mask_node_new:
- * @source: The bottom node to be drawn
- * @mask: The node to be blended onto the @bottom node
+ * @source: The source node to be drawn
+ * @mask: The node to be used as mask
+ * @mask_mode: The mask mode to use
  *
- * Creates a `GskRenderNode` that will use @blend_mode to blend the @top
- * node onto the @bottom node.
+ * Creates a `GskRenderNode` that will mask a given node by another.
+ *
+ * The @mask_mode determines how the 'mask values' are derived from
+ * the colors of the @mask. Applying the mask consists of multiplying
+ * the 'mask value' with the alpha of the source.
  *
  * Returns: (transfer full) (type GskMaskNode): A new `GskRenderNode`
  *
@@ -5257,7 +5314,8 @@ gsk_mask_node_diff (GskRenderNode  *node1,
  */
 GskRenderNode *
 gsk_mask_node_new (GskRenderNode *source,
-                   GskRenderNode *mask)
+                   GskRenderNode *mask,
+                   GskMaskMode    mask_mode)
 {
   GskMaskNode *self;
 
@@ -5267,15 +5325,18 @@ gsk_mask_node_new (GskRenderNode *source,
   self = gsk_render_node_alloc (GSK_MASK_NODE);
   self->source = gsk_render_node_ref (source);
   self->mask = gsk_render_node_ref (mask);
+  self->mask_mode = mask_mode;
 
-  graphene_rect_union (&source->bounds, &mask->bounds, &self->render_node.bounds);
+  self->render_node.bounds = source->bounds;
+
+  self->render_node.prefers_high_depth = gsk_render_node_prefers_high_depth (source);
 
   return &self->render_node;
 }
 
 /**
  * gsk_mask_node_get_source:
- * @node: (type GskBlendNode): a mask `GskRenderNode`
+ * @node: (type GskMaskNode): a mask `GskRenderNode`
  *
  * Retrieves the source `GskRenderNode` child of the @node.
  *
@@ -5295,7 +5356,7 @@ gsk_mask_node_get_source (const GskRenderNode *node)
 
 /**
  * gsk_mask_node_get_mask:
- * @node: (type GskBlendNode): a mask `GskRenderNode`
+ * @node: (type GskMaskNode): a mask `GskRenderNode`
  *
  * Retrieves the mask `GskRenderNode` child of the @node.
  *
@@ -5313,6 +5374,24 @@ gsk_mask_node_get_mask (const GskRenderNode *node)
   return self->mask;
 }
 
+/**
+ * gsk_mask_node_get_mask_mode:
+ * @node: (type GskMaskNode): a blending `GskRenderNode`
+ *
+ * Retrieves the mask mode used by @node.
+ *
+ * Returns: the mask mode
+ *
+ * Since: 4.10
+ */
+GskMaskMode
+gsk_mask_node_get_mask_mode (const GskRenderNode *node)
+{
+  const GskMaskNode *self = (const GskMaskNode *) node;
+
+  return self->mask_mode;
+}
+
 /* }}} */
 /* {{{ GSK_DEBUG_NODE */
 
index 671ea34c02bbada4884b189c7c3d711e9cd6a971..fd68dd16a8193d1f41de9814549253d242504a45 100644 (file)
@@ -649,6 +649,18 @@ static const struct
   { GSK_BLEND_MODE_LUMINOSITY, "luminosity" }
 };
 
+static const char *
+get_blend_mode_name (GskBlendMode mode)
+{
+  for (unsigned int i = 0; i < G_N_ELEMENTS (blend_modes); i++)
+    {
+      if (blend_modes[i].mode == mode)
+        return blend_modes[i].name;
+    }
+
+  return NULL;
+}
+
 static gboolean
 parse_blend_mode (GtkCssParser *parser,
                   gpointer      out_mode)
@@ -667,6 +679,46 @@ parse_blend_mode (GtkCssParser *parser,
   return FALSE;
 }
 
+static const struct
+{
+  GskMaskMode mode;
+  const char *name;
+} mask_modes[] = {
+  { GSK_MASK_MODE_ALPHA, "alpha" },
+  { GSK_MASK_MODE_INVERTED_ALPHA, "inverted-alpha" },
+  { GSK_MASK_MODE_LUMINANCE, "luminance" },
+};
+
+static const char *
+get_mask_mode_name (GskMaskMode mode)
+{
+  for (unsigned int i = 0; i < G_N_ELEMENTS (mask_modes); i++)
+    {
+      if (mask_modes[i].mode == mode)
+        return mask_modes[i].name;
+    }
+
+  return NULL;
+}
+
+static gboolean
+parse_mask_mode (GtkCssParser *parser,
+                 gpointer      out_mode)
+{
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (mask_modes); i++)
+    {
+      if (gtk_css_parser_try_ident (parser, mask_modes[i].name))
+        {
+          *(GskMaskMode *) out_mode = mask_modes[i].mode;
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
 static PangoFont *
 font_from_string (const char *string)
 {
@@ -1381,7 +1433,9 @@ parse_mask_node (GtkCssParser *parser)
 {
   GskRenderNode *source = NULL;
   GskRenderNode *mask = NULL;
+  GskMaskMode mode = GSK_MASK_MODE_ALPHA;
   const Declaration declarations[] = {
+    { "mode", parse_mask_mode, NULL, &mode },
     { "source", parse_node, clear_node, &source },
     { "mask", parse_node, clear_node, &mask },
   };
@@ -1393,7 +1447,7 @@ parse_mask_node (GtkCssParser *parser)
   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);
+  result = gsk_mask_node_new (source, mask, mode);
 
   gsk_render_node_unref (source);
   gsk_render_node_unref (mask);
@@ -3103,21 +3157,13 @@ render_node_print (Printer       *p,
     case GSK_BLEND_NODE:
       {
         GskBlendMode mode = gsk_blend_node_get_blend_mode (node);
-        guint i;
 
         start_node (p, "blend");
 
         if (mode != GSK_BLEND_MODE_DEFAULT)
           {
             _indent (p);
-            for (i = 0; i < G_N_ELEMENTS (blend_modes); i++)
-              {
-                if (blend_modes[i].mode == mode)
-                  {
-                    g_string_append_printf (p->str, "mode: %s;\n", blend_modes[i].name);
-                    break;
-                  }
-              }
+            g_string_append_printf (p->str, "mode: %s;\n", get_blend_mode_name (mode));
           }
         append_node_param (p, "bottom", gsk_blend_node_get_bottom_child (node));
         append_node_param (p, "top", gsk_blend_node_get_top_child (node));
@@ -3128,8 +3174,15 @@ render_node_print (Printer       *p,
 
     case GSK_MASK_NODE:
       {
+        GskMaskMode mode = gsk_mask_node_get_mask_mode (node);
+
         start_node (p, "mask");
 
+        if (mode != GSK_MASK_MODE_ALPHA)
+          {
+            _indent (p);
+            g_string_append_printf (p->str, "mode: %s;\n", get_mask_mode_name (mode));
+          }
         append_node_param (p, "source", gsk_mask_node_get_source (node));
         append_node_param (p, "mask", gsk_mask_node_get_mask (node));
 
index f64a3cc99f5aa69f261390ca019ec98206c96d4d..1ebc641bea62056ade14a2084a32d232315edd4c 100644 (file)
@@ -122,6 +122,7 @@ struct _GtkSnapshotState {
       char *message;
     } debug;
     struct {
+      GskMaskMode mask_mode;
       GskRenderNode *mask_node;
     } mask;
   } data;
@@ -1258,7 +1259,7 @@ gtk_snapshot_collect_mask_source (GtkSnapshot      *snapshot,
   if (source_child == NULL || mask_child == NULL)
     return NULL;
 
-  mask_node = gsk_mask_node_new (source_child, mask_child);
+  mask_node = gsk_mask_node_new (source_child, mask_child, state->data.mask.mask_mode);
 
   gsk_render_node_unref (source_child);
   gsk_render_node_unref (mask_child);
@@ -1290,9 +1291,11 @@ gtk_snapshot_collect_mask_mask (GtkSnapshot      *snapshot,
 /**
  * gtk_snapshot_push_mask:
  * @snapshot: a #GtkSnapshot
+ * @mask_mode: mask mode to use
  *
  * Until the first call to [method@Gtk.Snapshot.pop], the
  * mask image for the mask operation will be recorded.
+ *
  * After that call, the source image will be recorded until
  * the second call to [method@Gtk.Snapshot.pop].
  *
@@ -1301,7 +1304,8 @@ gtk_snapshot_collect_mask_mask (GtkSnapshot      *snapshot,
  * Since: 4.10
  */
 void
-gtk_snapshot_push_mask (GtkSnapshot *snapshot)
+gtk_snapshot_push_mask (GtkSnapshot *snapshot,
+                        GskMaskMode  mask_mode)
 {
   GtkSnapshotState *current_state = gtk_snapshot_get_current_state (snapshot);
   GtkSnapshotState *source_state;
@@ -1311,6 +1315,8 @@ gtk_snapshot_push_mask (GtkSnapshot *snapshot)
                                           gtk_snapshot_collect_mask_source,
                                           gtk_snapshot_clear_mask_source);
 
+  source_state->data.mask.mask_mode = mask_mode;
+
   gtk_snapshot_push_state (snapshot,
                            source_state->transform,
                            gtk_snapshot_collect_mask_mask,
index d1d5c1a757ecd1a161fe3dc5414293b076af2051..f24e7955ce0e5a873db1f5fe3ad7f1d90f7cebc5 100644 (file)
@@ -96,7 +96,8 @@ GDK_AVAILABLE_IN_ALL
 void            gtk_snapshot_push_blend                 (GtkSnapshot            *snapshot,
                                                          GskBlendMode            blend_mode);
 GDK_AVAILABLE_IN_4_10
-void            gtk_snapshot_push_mask                  (GtkSnapshot            *snapshot);
+void            gtk_snapshot_push_mask                  (GtkSnapshot            *snapshot,
+                                                         GskMaskMode             mask_mode);
 
 GDK_AVAILABLE_IN_ALL
 void            gtk_snapshot_push_cross_fade            (GtkSnapshot            *snapshot,
index 9f75b1ab6ec5f2b9d7d766a0a3930cb537865b4d..78db4669cf2e407594c4ca0ec76ea8a5b682e719 100644 (file)
@@ -1140,6 +1140,12 @@ populate_render_node_properties (GListStore    *store,
       break;
 
     case GSK_MASK_NODE:
+      {
+        GskMaskMode mode = gsk_mask_node_get_mask_mode (node);
+        tmp = g_enum_to_string (GSK_TYPE_MASK_MODE, mode);
+        add_text_row (store, "Mask mode", tmp);
+        g_free (tmp);
+      }
       break;
 
     case GSK_BLUR_NODE: