Quelle gskblendnode.c
Sprache: C
/* GSK - The GTK Scene Kit
*
* Copyright 2016 Endless
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library . If not , see < http : //www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gskblendnodeprivate.h"
#include "gskrendernodeprivate.h"
#include "gskrenderreplay.h"
#include "gskcontainernode.h"
#include "gskrectprivate.h"
#include "gdk/gdkcairoprivate.h"
/**
* GskBlendNode :
*
* A render node applying a blending function between its two child nodes .
*/
struct _GskBlendNode
{
GskRenderNode render_node;
union {
GskRenderNode *children[2 ];
struct {
GskRenderNode *bottom;
GskRenderNode *top;
};
};
GdkColorState *color_state;
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;
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_BLEND_NODE));
gdk_color_state_unref (self->color_state);
gsk_render_node_unref (self->bottom);
gsk_render_node_unref (self->top);
parent_class->finalize (node);
}
static void
gsk_blend_node_draw (GskRenderNode *node,
cairo_t *cr,
GskCairoData *data)
{
GskBlendNode *self = (GskBlendNode *) node;
if (gdk_cairo_is_all_clipped (cr))
return ;
if (!gdk_color_state_equal (data->ccs, GDK_COLOR_STATE_SRGB))
g_warning ("blend node in non-srgb colorstate isn't implemented yet." );
cairo_push_group (cr);
gsk_render_node_draw_full (self->bottom, cr, data);
cairo_push_group (cr);
gsk_render_node_draw_full (self->top, cr, data);
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_diff (GskRenderNode *node1,
GskRenderNode *node2,
GskDiffData *data)
{
GskBlendNode *self1 = (GskBlendNode *) node1;
GskBlendNode *self2 = (GskBlendNode *) node2;
if (self1->blend_mode == self2->blend_mode &&
gdk_color_state_equal (self1->color_state, self2->color_state))
{
gsk_render_node_diff (self1->top, self2->top, data);
gsk_render_node_diff (self1->bottom, self2->bottom, data);
}
else
{
gsk_render_node_diff_impossible (node1, node2, data);
}
}
static GskRenderNode **
gsk_blend_node_get_children (GskRenderNode *node,
gsize *n_children)
{
GskBlendNode *self = (GskBlendNode *) node;
*n_children = G_N_ELEMENTS (self->children);
return self->children;
}
static GskRenderNode *
gsk_blend_node_replay (GskRenderNode *node,
GskRenderReplay *replay)
{
GskBlendNode *self = (GskBlendNode *) node;
GskRenderNode *result, *top, *bottom;
top = gsk_render_replay_filter_node (replay, self->top);
bottom = gsk_render_replay_filter_node (replay, self->bottom);
if (top == NULL)
{
if (bottom == NULL)
return NULL;
top = gsk_container_node_new (NULL, 0 );
}
else if (bottom == NULL)
{
bottom = gsk_container_node_new (NULL, 0 );
}
if (top == self->top && bottom == self->bottom)
result = gsk_render_node_ref (node);
else
result = gsk_blend_node_new2 (bottom, top,
self->color_state,
self->blend_mode);
gsk_render_node_unref (top);
gsk_render_node_unref (bottom);
return result;
}
static void
gsk_blend_node_class_init (gpointer g_class,
gpointer class_data)
{
GskRenderNodeClass *node_class = g_class;
node_class->node_type = GSK_BLEND_NODE;
node_class->finalize = gsk_blend_node_finalize;
node_class->draw = gsk_blend_node_draw;
node_class->diff = gsk_blend_node_diff;
node_class->get_children = gsk_blend_node_get_children;
node_class->replay = gsk_blend_node_replay;
}
GSK_DEFINE_RENDER_NODE_TYPE (GskBlendNode, gsk_blend_node)
/**
* 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 : ( transfer full ) ( type GskBlendNode ) : A new ` GskRenderNode `
*/
GskRenderNode *
gsk_blend_node_new (GskRenderNode *bottom,
GskRenderNode *top,
GskBlendMode blend_mode)
{
return gsk_blend_node_new2 (bottom, top, GDK_COLOR_STATE_SRGB, blend_mode);
}
/*< private >
* gsk_blend_node_new2 :
* @ bottom : The bottom node to be drawn
* @ top : The node to be blended onto the @ bottom node
* @ color_state : The color state to blend in
* @ 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 : ( transfer full ) ( type GskBlendNode ) : A new ` GskRenderNode `
*/
GskRenderNode *
gsk_blend_node_new2 (GskRenderNode *bottom,
GskRenderNode *top,
GdkColorState *color_state,
GskBlendMode blend_mode)
{
GskBlendNode *self;
GskRenderNode *node;
g_return_val_if_fail (GSK_IS_RENDER_NODE (bottom), NULL);
g_return_val_if_fail (GSK_IS_RENDER_NODE (top), NULL);
g_return_val_if_fail (GDK_IS_DEFAULT_COLOR_STATE (color_state), NULL);
self = gsk_render_node_alloc (GSK_TYPE_BLEND_NODE);
node = (GskRenderNode *) self;
self->bottom = gsk_render_node_ref (bottom);
self->top = gsk_render_node_ref (top);
self->color_state = gdk_color_state_ref (color_state);
self->blend_mode = blend_mode;
graphene_rect_union (&bottom->bounds, &top->bounds, &node->bounds);
node->preferred_depth = gdk_memory_depth_merge (gsk_render_node_get_preferred_depth (bottom),
gsk_render_node_get_preferred_depth (top));
node->is_hdr = gsk_render_node_is_hdr (bottom) ||
gsk_render_node_is_hdr (top);
node->fully_opaque = gsk_render_node_is_fully_opaque (bottom) &&
gsk_render_node_is_fully_opaque (top) &&
gsk_rect_equal (&bottom->bounds, &top->bounds);
node->contains_subsurface_node = gsk_render_node_contains_subsurface_node (bottom) ||
gsk_render_node_contains_subsurface_node (top);
node->contains_paste_node = gsk_render_node_contains_paste_node (bottom) ||
gsk_render_node_contains_paste_node (top);
return node;
}
/**
* gsk_blend_node_get_bottom_child :
* @ node : ( type GskBlendNode ) : a blending ` GskRenderNode `
*
* Retrieves the bottom ` GskRenderNode ` child of the @ node .
*
* Returns : ( transfer none ) : the bottom child node
*/
GskRenderNode *
gsk_blend_node_get_bottom_child (const GskRenderNode *node)
{
const GskBlendNode *self = (const GskBlendNode *) node;
return self->bottom;
}
/**
* gsk_blend_node_get_top_child :
* @ node : ( type GskBlendNode ) : a blending ` GskRenderNode `
*
* Retrieves the top ` GskRenderNode ` child of the @ node .
*
* Returns : ( transfer none ) : the top child node
*/
GskRenderNode *
gsk_blend_node_get_top_child (const GskRenderNode *node)
{
const GskBlendNode *self = (const GskBlendNode *) node;
return self->top;
}
/**
* gsk_blend_node_get_blend_mode :
* @ node : ( type GskBlendNode ) : a blending ` GskRenderNode `
*
* Retrieves the blend mode used by @ node .
*
* Returns : the blend mode
*/
GskBlendMode
gsk_blend_node_get_blend_mode (const GskRenderNode *node)
{
const GskBlendNode *self = (const GskBlendNode *) node;
return self->blend_mode;
}
/*< private >
* gsk_blend_node_get_color_state :
* @ node : ( type GskBlendNode ) : a ` GskRenderNode `
*
* Retrieves the color state of the @ node .
*
* Returns : ( transfer none ) : the color state
*/
GdkColorState *
gsk_blend_node_get_color_state (const GskRenderNode *node)
{
const GskBlendNode *self = (const GskBlendNode *) node;
return self->color_state;
}
Messung V0.5 in Prozent C=98 H=92 G=94
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-07-03)
¤
*© Formatika GbR, Deutschland
2026-07-09