[gtk+] gsk: Replace gsk_render_node_set_opacity()



commit 07d39299ead9d936c05242d2aab664b7112c3070
Author: Benjamin Otte <otte redhat com>
Date:   Tue Dec 13 05:49:57 2016 +0100

    gsk: Replace gsk_render_node_set_opacity()
    
    ... with gsk_opacity_node_new().
    
    Also implement support for opacity in gtk_widget_snapshot() using this
    new node.

 docs/reference/gsk/gsk4-sections.txt   |    3 +-
 gsk/gskenums.h                         |    4 +-
 gsk/gskglrenderer.c                    |    7 +--
 gsk/gskrendernode.c                    |   40 ----------
 gsk/gskrendernode.h                    |    6 +-
 gsk/gskrendernodeimpl.c                |  127 ++++++++++++++++++++++++++++++++
 gsk/gskrendernodeprivate.h             |    2 +-
 gsk/gskvulkanrenderpass.c              |    8 --
 gtk/gtkwidget.c                        |   55 +++++++++-----
 gtk/inspector/gtktreemodelrendernode.c |    4 +
 gtk/inspector/recorder.c               |    7 --
 11 files changed, 179 insertions(+), 84 deletions(-)
---
diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt
index 6126c4f..486e31d 100644
--- a/docs/reference/gsk/gsk4-sections.txt
+++ b/docs/reference/gsk/gsk4-sections.txt
@@ -29,7 +29,6 @@ gsk_render_node_unref
 GskRenderNodeType
 gsk_render_node_get_node_type
 gsk_render_node_draw
-gsk_render_node_set_opacity
 GskBlendMode
 gsk_render_node_set_blend_mode
 GskScalingFilter
@@ -44,6 +43,8 @@ gsk_container_node_get_n_children
 gsk_container_node_get_child
 gsk_transform_node_new
 gsk_transform_node_get_child
+gsk_opacity_node_new
+gsk_opacity_node_get_child
 <SUBSECTION Standard>
 GSK_IS_RENDER_NODE
 GSK_RENDER_NODE
diff --git a/gsk/gskenums.h b/gsk/gskenums.h
index 579e3d9..caba77f 100644
--- a/gsk/gskenums.h
+++ b/gsk/gskenums.h
@@ -31,6 +31,7 @@
  * @GSK_TEXTURE_NODE: A node drawing a #GskTexture
  * @GSK_TRANSFORM_NODE: A node that renders its child after applying a
  *     matrix transform
+ * @GSK_OPACITY_NODE: A node that changes the opacity of its child
  *
  * The type of a node determines what the node is rendering.
  *
@@ -42,7 +43,8 @@ typedef enum {
   GSK_CAIRO_NODE,
   GSK_COLOR_NODE,
   GSK_TEXTURE_NODE,
-  GSK_TRANSFORM_NODE
+  GSK_TRANSFORM_NODE,
+  GSK_OPACITY_NODE
 } GskRenderNodeType;
 
 /**
diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c
index bb98e2f..7812121 100644
--- a/gsk/gskglrenderer.c
+++ b/gsk/gskglrenderer.c
@@ -592,11 +592,6 @@ project_item (const graphene_matrix_t *projection,
 static gboolean
 render_node_needs_render_target (GskRenderNode *node)
 {
-  double opacity = gsk_render_node_get_opacity (node);
-
-  if (opacity < 1.0)
-    return TRUE;
-
   return FALSE;
 }
 
@@ -647,7 +642,7 @@ gsk_gl_renderer_add_render_item (GskGLRenderer           *self,
   graphene_matrix_multiply (modelview, &self->mvp, &item.mvp);
   item.z = project_item (projection, modelview);
 
-  item.opacity = gsk_render_node_get_opacity (node);
+  item.opacity = 1.0;
 
   item.blend_mode = gsk_render_node_get_blend_mode (node);
 
diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c
index 1a343ae..ab41235 100644
--- a/gsk/gskrendernode.c
+++ b/gsk/gskrendernode.c
@@ -97,8 +97,6 @@ gsk_render_node_new (const GskRenderNodeClass *node_class)
 
   self->ref_count = 1;
 
-  self->opacity = 1.0;
-
   self->min_filter = GSK_SCALING_FILTER_NEAREST;
   self->mag_filter = GSK_SCALING_FILTER_NEAREST;
 
@@ -185,44 +183,6 @@ gsk_render_node_get_bounds (GskRenderNode   *node,
   node->node_class->get_bounds (node, bounds);
 }
 
-/**
- * gsk_render_node_set_opacity:
- * @node: a #GskRenderNode
- * @opacity: the opacity of the node, between 0 (fully transparent) and
- *   1 (fully opaque)
- *
- * Sets the opacity of the @node.
- *
- * Since: 3.90
- */
-void
-gsk_render_node_set_opacity (GskRenderNode *node,
-                             double         opacity)
-{
-  g_return_if_fail (GSK_IS_RENDER_NODE (node));
-  g_return_if_fail (node->is_mutable);
-
-  node->opacity = CLAMP (opacity, 0.0, 1.0);
-}
-
-/**
- * gsk_render_node_get_opacity:
- * @node: a #GskRenderNode
- *
- * Retrieves the opacity set using gsk_render_node_set_opacity().
- *
- * Returns: the opacity of the #GskRenderNode
- *
- * Since: 3.90
- */
-double
-gsk_render_node_get_opacity (GskRenderNode *node)
-{
-  g_return_val_if_fail (GSK_IS_RENDER_NODE (node), 0.0);
-
-  return node->opacity;
-}
-
 void
 gsk_render_node_set_scaling_filters (GskRenderNode    *node,
                                      GskScalingFilter  min_filter,
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index 2119dfb..3be2503 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -74,8 +74,10 @@ GDK_AVAILABLE_IN_3_90
 GskRenderNode *         gsk_transform_node_get_child            (GskRenderNode            *node);
 
 GDK_AVAILABLE_IN_3_90
-void                    gsk_render_node_set_opacity             (GskRenderNode *node,
-                                                                 double         opacity);
+GskRenderNode *         gsk_opacity_node_new                    (GskRenderNode            *child,
+                                                                 double                    opacity);
+GDK_AVAILABLE_IN_3_90
+GskRenderNode *         gsk_opacity_node_get_child              (GskRenderNode            *node);
 
 GDK_AVAILABLE_IN_3_90
 void                    gsk_render_node_set_blend_mode          (GskRenderNode *node,
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index feb7f08..764b702 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -692,3 +692,130 @@ gsk_transform_node_get_transform (GskRenderNode     *node,
   graphene_matrix_init_from_matrix (transform, &self->transform);
 }
 
+/*** GSK_OPACITY_NODE ***/
+
+typedef struct _GskOpacityNode GskOpacityNode;
+
+struct _GskOpacityNode
+{
+  GskRenderNode render_node;
+
+  GskRenderNode *child;
+  double opacity;
+};
+
+static void
+gsk_opacity_node_finalize (GskRenderNode *node)
+{
+  GskOpacityNode *self = (GskOpacityNode *) node;
+
+  gsk_render_node_unref (self->child);
+}
+
+static void
+gsk_opacity_node_make_immutable (GskRenderNode *node)
+{
+  GskOpacityNode *self = (GskOpacityNode *) node;
+
+  gsk_render_node_make_immutable (self->child);
+}
+
+static void
+gsk_opacity_node_draw (GskRenderNode *node,
+                       cairo_t       *cr)
+{
+  GskOpacityNode *self = (GskOpacityNode *) node;
+  graphene_rect_t bounds;
+
+  cairo_save (cr);
+
+  /* clip so the push_group() creates a smaller surface */
+  gsk_render_node_get_bounds (self->child, &bounds);
+  cairo_rectangle (cr, bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
+  cairo_clip (cr);
+
+  cairo_push_group (cr);
+
+  gsk_render_node_draw (self->child, cr);
+
+  cairo_pop_group_to_source (cr);
+  cairo_paint_with_alpha (cr, self->opacity);
+
+  cairo_restore (cr);
+}
+
+static void
+gsk_opacity_node_get_bounds (GskRenderNode   *node,
+                             graphene_rect_t *bounds)
+{
+  GskOpacityNode *self = (GskOpacityNode *) node;
+
+  gsk_render_node_get_bounds (self->child, bounds);
+}
+
+static const GskRenderNodeClass GSK_OPACITY_NODE_CLASS = {
+  GSK_OPACITY_NODE,
+  sizeof (GskOpacityNode),
+  "GskOpacityNode",
+  gsk_opacity_node_finalize,
+  gsk_opacity_node_make_immutable,
+  gsk_opacity_node_draw,
+  gsk_opacity_node_get_bounds
+};
+
+/**
+ * gsk_opacity_node_new:
+ * @child: The node to draw
+ * @opacity: The opacity to apply
+ *
+ * Creates a #GskRenderNode that will drawn the @child with reduced
+ * @opacity.
+ *
+ * Returns: A new #GskRenderNode
+ *
+ * Since: 3.90
+ */
+GskRenderNode *
+gsk_opacity_node_new (GskRenderNode *child,
+                      double         opacity)
+{
+  GskOpacityNode *self;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
+
+  self = (GskOpacityNode *) gsk_render_node_new (&GSK_OPACITY_NODE_CLASS);
+
+  self->child = gsk_render_node_ref (child);
+  self->opacity = CLAMP (opacity, 0.0, 1.0);
+
+  return &self->render_node;
+}
+
+/**
+ * gsk_opacity_node_get_child:
+ * @node: a opacity @GskRenderNode
+ *
+ * Gets the child node that is getting opacityed by the given @node.
+ *
+ * Returns: (transfer none): The child that is getting opacityed
+ **/
+GskRenderNode *
+gsk_opacity_node_get_child (GskRenderNode *node)
+{
+  GskOpacityNode *self = (GskOpacityNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_OPACITY_NODE), NULL);
+
+  return self->child;
+}
+
+double
+gsk_opacity_node_get_opacity (GskRenderNode *node)
+{
+  GskOpacityNode *self = (GskOpacityNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_OPACITY_NODE), 1.0);
+
+  return self->opacity;
+}
+
diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h
index c4e3c48..3ad5c43 100644
--- a/gsk/gskrendernodeprivate.h
+++ b/gsk/gskrendernodeprivate.h
@@ -52,7 +52,7 @@ void gsk_render_node_make_immutable (GskRenderNode *node);
 
 void gsk_render_node_get_bounds (GskRenderNode   *node,
                                  graphene_rect_t *frame);
-double gsk_render_node_get_opacity (GskRenderNode *node);
+double gsk_opacity_node_get_opacity (GskRenderNode *node);
 
 cairo_surface_t *gsk_cairo_node_get_surface (GskRenderNode *node);
 
diff --git a/gsk/gskvulkanrenderpass.c b/gsk/gskvulkanrenderpass.c
index 86ac1a1..9b28951 100644
--- a/gsk/gskvulkanrenderpass.c
+++ b/gsk/gskvulkanrenderpass.c
@@ -66,9 +66,6 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass     *self,
     .node = node
   };
 
-  if (gsk_render_node_get_opacity (node) < 1.0)
-    goto fallback;
-
   switch (gsk_render_node_get_node_type (node))
     {
     case GSK_NOT_A_RENDER_NODE:
@@ -115,11 +112,6 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass     *self,
       break;
 
     }
-
-  return;
-
-fallback:
-  g_array_append_val (self->render_ops, op);
 }
 
 void
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index cf2b961..8578316 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -6298,15 +6298,8 @@ gtk_widget_draw_internal (GtkWidget *widget,
       GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (widget);
       GdkWindow *event_window = NULL;
       gboolean result;
-      gboolean push_group;
       RenderMode mode;
 
-      push_group =
-        widget->priv->alpha != 255 && !_gtk_widget_is_toplevel (widget);
-
-      if (push_group)
-        cairo_push_group (cr);
-
 #ifdef G_ENABLE_CONSISTENCY_CHECKS
       if (_gtk_widget_get_alloc_needed (widget))
         g_warning ("%s %p is drawn without a current allocation. This should not happen.", 
G_OBJECT_TYPE_NAME (widget), widget);
@@ -6343,6 +6336,12 @@ gtk_widget_draw_internal (GtkWidget *widget,
         }
       else
         {
+          gboolean push_group = 
+            widget->priv->alpha != 255 && !_gtk_widget_is_toplevel (widget);
+
+          if (push_group)
+            cairo_push_group (cr);
+
           if (g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE))
             {
               g_signal_emit (widget, widget_signals[DRAW],
@@ -6355,6 +6354,13 @@ gtk_widget_draw_internal (GtkWidget *widget,
               GTK_WIDGET_GET_CLASS (widget)->draw (widget, cr);
               cairo_restore (cr);
             }
+
+          if (push_group)
+            {
+              cairo_pop_group_to_source (cr);
+              cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+              cairo_paint_with_alpha (cr, widget->priv->alpha / 255.0);
+            }
         }
 
 #ifdef G_ENABLE_DEBUG
@@ -6390,13 +6396,6 @@ gtk_widget_draw_internal (GtkWidget *widget,
         }
 #endif
 
-      if (push_group)
-        {
-          cairo_pop_group_to_source (cr);
-          cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
-          cairo_paint_with_alpha (cr, widget->priv->alpha / 255.0);
-        }
-
       if (cairo_status (cr) &&
           event_window != NULL)
         {
@@ -15538,6 +15537,7 @@ gtk_widget_snapshot (GtkWidget   *widget,
   GtkAllocation clip;
   GtkAllocation alloc;
   RenderMode mode;
+  double opacity;
 
   if (_gtk_widget_get_alloc_needed (widget))
     return;
@@ -15548,6 +15548,13 @@ gtk_widget_snapshot (GtkWidget   *widget,
   if (gtk_snapshot_clips_rect (snapshot, &bounds))
     return;
 
+  if (_gtk_widget_is_toplevel (widget))
+    opacity = 1.0;
+  else
+    opacity = widget->priv->alpha / 255.0;
+  if (opacity <= 0.0)
+    return;
+
   /* Compatibility mode: if the widget does not have a render node, we draw
    * using gtk_widget_draw() on a temporary node
    */
@@ -15565,6 +15572,11 @@ gtk_widget_snapshot (GtkWidget   *widget,
     }
   else
     {
+      if (opacity < 1.0)
+        gtk_snapshot_push (snapshot, TRUE, "OpacityGroup<%s>", G_OBJECT_TYPE_NAME (widget));
+
+      klass->snapshot (widget, snapshot);
+
       if (g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE))
         {
           /* Compatibility mode: if there's a ::draw signal handler, we add a
@@ -15573,17 +15585,24 @@ gtk_widget_snapshot (GtkWidget   *widget,
           gboolean result;
           cairo_t *cr;
 
-          klass->snapshot (widget, snapshot);
-
           cr = gtk_snapshot_append_cairo_node (snapshot, 
                                                &bounds,
                                                "DrawSignalContents<%s>", G_OBJECT_TYPE_NAME (widget));
           g_signal_emit (widget, widget_signals[DRAW], 0, cr, &result);
           cairo_destroy (cr);
         }
-      else
+
+      if (opacity < 1.0)
         {
-          klass->snapshot (widget, snapshot);
+          GskRenderNode *opacity_node, *node;
+
+          node = gtk_snapshot_pop (snapshot);
+          opacity_node = gsk_opacity_node_new (node, opacity);
+          gsk_render_node_set_name (opacity_node, "Opacity");
+          gsk_render_node_unref (node);
+
+          gtk_snapshot_append_node (snapshot, opacity_node);
+          gsk_render_node_unref (opacity_node);
         }
     }
 }
diff --git a/gtk/inspector/gtktreemodelrendernode.c b/gtk/inspector/gtktreemodelrendernode.c
index 617b4b7..b25ae64 100644
--- a/gtk/inspector/gtktreemodelrendernode.c
+++ b/gtk/inspector/gtktreemodelrendernode.c
@@ -530,6 +530,10 @@ append_node (GtkTreeModelRenderNode *nodemodel,
       append_node (nodemodel, gsk_transform_node_get_child (node), priv->nodes->len - 1);
       break;
 
+    case GSK_OPACITY_NODE:
+      append_node (nodemodel, gsk_opacity_node_get_child (node), priv->nodes->len - 1);
+      break;
+
     case GSK_CONTAINER_NODE:
       {
         gint elt_index;
diff --git a/gtk/inspector/recorder.c b/gtk/inspector/recorder.c
index 659921c..bffab83 100644
--- a/gtk/inspector/recorder.c
+++ b/gtk/inspector/recorder.c
@@ -152,13 +152,6 @@ populate_render_node_properties (GtkListStore  *store,
                                      -1);
   g_free (tmp);
 
-  tmp = g_strdup_printf ("%.2f", gsk_render_node_get_opacity (node));
-  gtk_list_store_insert_with_values (store, NULL, -1,
-                                     0, "Opacity",
-                                     1, tmp,
-                                     -1);
-  g_free (tmp);
-
   gtk_list_store_insert_with_values (store, NULL, -1,
                                      0, "Has Surface",
                                      1, gsk_render_node_get_node_type (node) == GSK_CAIRO_NODE ? "TRUE" : 
"FALSE",


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