/* GSK - The GTK Scene Kit
*
* Copyright 2025 Benjamin Otte
*
* 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 "gskcopynode.h"
#include "gskpastenode.h"
#include "gskrectprivate.h"
#include "gskrendernodeprivate.h"
#include "gskrenderreplay.h"
/**
* GskCopyNode :
*
* A render node that copies the current state of the rendering canvas
* so a [ class @ Gsk . PasteNode ] can draw it .
*
* Since : 4 . 22
*/
struct _GskCopyNode
{
GskRenderNode render_node;
GskRenderNode *child;
graphene_rect_t paste_area;
};
static void
gsk_copy_node_finalize (GskRenderNode *node)
{
GskCopyNode *self = (GskCopyNode *) node;
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_COPY_NODE));
gsk_render_node_unref (self->child);
parent_class->finalize (node);
}
static void
gsk_copy_node_draw (GskRenderNode *node,
cairo_t *cr,
GskCairoData *data)
{
GskCopyNode *self = (GskCopyNode *) node;
gsk_render_node_draw_full (self->child, cr, data);
}
static void
gsk_copy_node_diff (GskRenderNode *node1,
GskRenderNode *node2,
GskDiffData *data)
{
GskCopyNode *self1 = (GskCopyNode *) node1;
GskCopyNode *self2 = (GskCopyNode *) node2;
GSList copy = { cairo_region_copy (data->region), data->copies };
data->copies = ©
gsk_render_node_diff (self1->child, self2->child, data);
cairo_region_destroy (copy.data);
data->copies = copy.next;
}
static GskRenderNode **
gsk_copy_node_get_children (GskRenderNode *node,
gsize *n_children)
{
GskCopyNode *self = (GskCopyNode *) node;
*n_children = 1 ;
return &self->child;
}
static void
gsk_copy_node_render_opacity (GskRenderNode *node,
GskOpacityData *data)
{
GskCopyNode *self = (GskCopyNode *) node;
graphene_rect_t saved = data->opaque;
GSList copy = { &saved, (GSList *) data->copies };
data->copies = ©
gsk_render_node_render_opacity (self->child, data);
data->copies = data->copies->next;
}
static GskRenderNode *
gsk_copy_node_replay (GskRenderNode *node,
GskRenderReplay *replay)
{
GskCopyNode *self = (GskCopyNode *) node;
GskRenderNode *result, *child;
child = gsk_render_replay_filter_node (replay, self->child);
if (child == NULL)
return NULL;
if (child == self->child)
result = gsk_render_node_ref (node);
else
result = gsk_copy_node_new (child);
gsk_render_node_unref (child);
return result;
}
static void
gsk_copy_node_class_init (gpointer g_class,
gpointer class_data)
{
GskRenderNodeClass *node_class = g_class;
node_class->node_type = GSK_COPY_NODE;
node_class->finalize = gsk_copy_node_finalize;
node_class->draw = gsk_copy_node_draw;
node_class->diff = gsk_copy_node_diff;
node_class->get_children = gsk_copy_node_get_children;
node_class->replay = gsk_copy_node_replay;
node_class->render_opacity = gsk_copy_node_render_opacity;
}
GSK_DEFINE_RENDER_NODE_TYPE (GskCopyNode, gsk_copy_node)
static void
gsk_copy_node_analyze_child (GskCopyNode *self,
GskRenderNode *node,
guint depth)
{
GskRenderNode **children;
gsize i, n_children;
if (!gsk_render_node_contains_paste_node (node))
return ;
children = gsk_render_node_get_children (node, &n_children);
switch (gsk_render_node_get_node_type (node))
{
case GSK_COPY_NODE:
gsk_copy_node_analyze_child (self, children[0 ], depth + 1 );
break ;
case GSK_PASTE_NODE:
if (gsk_paste_node_get_depth (node) == depth)
{
if (gsk_rect_is_empty (&self->paste_area))
self->paste_area = node->bounds;
else
graphene_rect_union (&self->paste_area, &node->bounds, &self->paste_area);
}
else
{
self->render_node.contains_paste_node = TRUE ;
}
break ;
case GSK_CONTAINER_NODE:
case GSK_CAIRO_NODE:
case GSK_COLOR_NODE:
case GSK_LINEAR_GRADIENT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_RADIAL_GRADIENT_NODE:
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
case GSK_CONIC_GRADIENT_NODE:
case GSK_BORDER_NODE:
case GSK_TEXTURE_NODE:
case GSK_INSET_SHADOW_NODE:
case GSK_OUTSET_SHADOW_NODE:
case GSK_TRANSFORM_NODE:
case GSK_OPACITY_NODE:
case GSK_COLOR_MATRIX_NODE:
case GSK_REPEAT_NODE:
case GSK_CLIP_NODE:
case GSK_ROUNDED_CLIP_NODE:
case GSK_SHADOW_NODE:
case GSK_BLEND_NODE:
case GSK_CROSS_FADE_NODE:
case GSK_TEXT_NODE:
case GSK_BLUR_NODE:
case GSK_DEBUG_NODE:
case GSK_GL_SHADER_NODE:
case GSK_TEXTURE_SCALE_NODE:
case GSK_MASK_NODE:
case GSK_FILL_NODE:
case GSK_STROKE_NODE:
case GSK_SUBSURFACE_NODE:
case GSK_COMPONENT_TRANSFER_NODE:
case GSK_COMPOSITE_NODE:
case GSK_ISOLATION_NODE:
case GSK_DISPLACEMENT_NODE:
case GSK_ARITHMETIC_NODE:
case GSK_TURBULENCE_NODE:
for (i = 0 ; i < n_children; i++)
{
gsk_copy_node_analyze_child (self, children[i], depth);
}
break ;
case GSK_NOT_A_RENDER_NODE:
default :
g_assert_not_reached ();
return ;
}
}
/**
* gsk_copy_node_new :
* @ child : The child
*
* Creates a ` GskRenderNode ` that copies the current rendering
* canvas for playback by paste nodes that are part of the child .
*
* Returns : ( transfer full ) ( type GskCopyNode ) : A new ` GskRenderNode `
*
* Since : 4 . 22
*/
GskRenderNode *
gsk_copy_node_new (GskRenderNode *child)
{
GskCopyNode *self;
GskRenderNode *node;
g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
self = gsk_render_node_alloc (GSK_TYPE_COPY_NODE);
node = (GskRenderNode *) self;
node->fully_opaque = child->fully_opaque;
self->child = gsk_render_node_ref (child);
gsk_rect_init_from_rect (&node->bounds, &child->bounds);
node->preferred_depth = gsk_render_node_get_preferred_depth (child);
node->is_hdr = gsk_render_node_is_hdr (child);
node->clears_background = gsk_render_node_clears_background (child);
node->copy_mode = gsk_render_node_get_copy_mode (child);
node->contains_subsurface_node = gsk_render_node_contains_subsurface_node (child);
node->needs_blending = gsk_render_node_needs_blending (child);
gsk_copy_node_analyze_child (self, child, 0 );
if (!gsk_rect_is_empty (&self->paste_area))
node->copy_mode = GSK_COPY_ANY;
return node;
}
/**
* gsk_copy_node_get_child :
* @ node : ( type GskCopyNode ) : a copy ` GskRenderNode `
*
* Gets the child node that is getting drawn by the given @ node .
*
* Returns : ( transfer none ) : the child ` GskRenderNode `
*
* Since : 4 . 22
**/
GskRenderNode *
gsk_copy_node_get_child (const GskRenderNode *node)
{
const GskCopyNode *self = (const GskCopyNode *) node;
return self->child;
}
Messung V0.5 in Prozent C=98 H=95 G=96
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-07-03)
¤
*© Formatika GbR, Deutschland