forked from AuroraMiddleware/gtk
gsk: Add blend nodes
Implement blend mode support in GTK background compositing with it.
This commit is contained in:
parent
3e26fadb24
commit
cf520b7a1f
@ -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
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user