[gtk+] gsk: Add blend nodes
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] gsk: Add blend nodes
- Date: Tue, 20 Dec 2016 17:13:07 +0000 (UTC)
commit cf520b7a1f932100a0b87e85a4501d56e30762cc
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]