From e82d02432e57b00606976e8a84e06628dd9d4918 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 13 Dec 2016 03:05:15 +0100 Subject: [PATCH] gsk: Add gsk_render_node_draw() Draws a node to a given cairo_t. This is mostly intended for fallback usage. --- docs/reference/gsk/gsk4-sections.txt | 1 + gsk/gskcairorenderer.c | 117 +-------------------------- gsk/gskrendernode.c | 59 ++++++++++++++ gsk/gskrendernode.h | 3 + gsk/gskrendernodeimpl.c | 87 +++++++++++++++++++- gsk/gskrendernodeprivate.h | 2 + 6 files changed, 151 insertions(+), 118 deletions(-) diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt index 4bbeba513a..8e6239d427 100644 --- a/docs/reference/gsk/gsk4-sections.txt +++ b/docs/reference/gsk/gsk4-sections.txt @@ -28,6 +28,7 @@ gsk_render_node_ref 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 diff --git a/gsk/gskcairorenderer.c b/gsk/gskcairorenderer.c index 4fd85927d9..3fb394a5de 100644 --- a/gsk/gskcairorenderer.c +++ b/gsk/gskcairorenderer.c @@ -46,121 +46,6 @@ gsk_cairo_renderer_unrealize (GskRenderer *renderer) } -static void -gsk_cairo_renderer_render_node (GskCairoRenderer *self, - GskRenderNode *node, - cairo_t *cr) -{ - gboolean pop_group = FALSE; - graphene_rect_t frame; - - cairo_save (cr); - - gsk_render_node_get_bounds (node, &frame); - GSK_NOTE (CAIRO, g_print ("CLIP = { .x = %g, .y = %g, .width = %g, .height = %g }\n", - frame.origin.x, frame.origin.y, - frame.size.width, frame.size.height)); - - if (!GSK_RENDER_MODE_CHECK (GEOMETRY)) - { - cairo_rectangle (cr, frame.origin.x, frame.origin.y, frame.size.width, frame.size.height); - cairo_clip (cr); - } - - if (gsk_render_node_get_opacity (node) != 1.0) - { - GSK_NOTE (CAIRO, g_print ("Pushing opacity group (opacity:%g)\n", - gsk_render_node_get_opacity (node))); - cairo_push_group (cr); - pop_group = TRUE; - } - - GSK_NOTE (CAIRO, g_print ("Rendering node %s[%p] at %g, %g\n", - node->name, - node, - frame.origin.x, frame.origin.y)); - - switch (gsk_render_node_get_node_type (node)) - { - case GSK_NOT_A_RENDER_NODE: - default: - g_assert_not_reached (); - break; - - case GSK_CONTAINER_NODE: - { - guint i; - GSK_NOTE (CAIRO, g_print ("Drawing %d children of node [%p]\n", - gsk_container_node_get_n_children (node), - node)); - for (i = 0; i < gsk_container_node_get_n_children (node); i++) - { - gsk_cairo_renderer_render_node (self, gsk_container_node_get_child (node, i), cr); - } - } - break; - - case GSK_TEXTURE_NODE: - { - GskTexture *texture = gsk_texture_node_get_texture (node); - cairo_surface_t *surface = gsk_texture_download (texture); - - cairo_set_source_surface (cr, surface, frame.origin.x, frame.origin.y); - cairo_paint (cr); - cairo_surface_destroy (surface); - } - break; - - case GSK_CAIRO_NODE: - { - cairo_set_source_surface (cr, gsk_cairo_node_get_surface (node), frame.origin.x, frame.origin.y); - cairo_paint (cr); - } - break; - - case GSK_TRANSFORM_NODE: - { - graphene_matrix_t mat; - cairo_matrix_t ctm; - - gsk_transform_node_get_transform (node, &mat); - if (graphene_matrix_to_2d (&mat, &ctm.xx, &ctm.yx, &ctm.xy, &ctm.yy, &ctm.x0, &ctm.y0)) - { - GSK_NOTE (CAIRO, g_print ("CTM = { .xx = %g, .yx = %g, .xy = %g, .yy = %g, .x0 = %g, .y0 = %g }\n", - ctm.xx, ctm.yx, - ctm.xy, ctm.yy, - ctm.x0, ctm.y0)); - cairo_transform (cr, &ctm); - } - else - g_critical ("Invalid non-affine transformation for node %p", node); - - gsk_cairo_renderer_render_node (self, gsk_transform_node_get_child (node), cr); - } - break; - } - - if (GSK_RENDER_MODE_CHECK (GEOMETRY)) - { - cairo_save (cr); - cairo_set_operator (cr, CAIRO_OPERATOR_OVER); - cairo_rectangle (cr, frame.origin.x - 1, frame.origin.y - 1, frame.size.width + 2, frame.size.height + 2); - cairo_set_line_width (cr, 2); - cairo_set_source_rgba (cr, 0, 0, 0, 0.5); - cairo_stroke (cr); - cairo_restore (cr); - } - - if (pop_group) - { - cairo_pop_group_to_source (cr); - cairo_set_operator (cr, CAIRO_OPERATOR_OVER); - cairo_paint_with_alpha (cr, gsk_render_node_get_opacity (node)); - } - - cairo_restore (cr); -} - static void gsk_cairo_renderer_render (GskRenderer *renderer, GskRenderNode *root) @@ -209,7 +94,7 @@ gsk_cairo_renderer_render (GskRenderer *renderer, gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time); #endif - gsk_cairo_renderer_render_node (self, root, cr); + gsk_render_node_draw (root, cr); #ifdef G_ENABLE_DEBUG cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time); diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c index 5b53c9197f..1a343ae852 100644 --- a/gsk/gskrendernode.c +++ b/gsk/gskrendernode.c @@ -335,3 +335,62 @@ gsk_render_node_make_immutable (GskRenderNode *node) node->is_mutable = FALSE; } +/** + * gsk_render_node_draw: + * @node: a #GskRenderNode + * @cr: cairo context to draw to + * + * Draw the contents of @node to the given cairo context. + * + * Typically, you'll use this function to implement fallback rendering + * of #GskRenderNodes on an intermediate Cairo context, instead of using + * the drawing context associated to a #GdkWindow's rendering buffer. + * + * For advanced nodes that cannot be supported using Cairo, in particular + * for nodes doing 3D operations, this function may fail. + **/ +void +gsk_render_node_draw (GskRenderNode *node, + cairo_t *cr) +{ + g_return_if_fail (GSK_IS_RENDER_NODE (node)); + g_return_if_fail (cr != NULL); + + cairo_save (cr); + + if (!GSK_RENDER_MODE_CHECK (GEOMETRY)) + { + graphene_rect_t frame; + + gsk_render_node_get_bounds (node, &frame); + GSK_NOTE (CAIRO, g_print ("CLIP = { .x = %g, .y = %g, .width = %g, .height = %g }\n", + frame.origin.x, frame.origin.y, + frame.size.width, frame.size.height)); + + cairo_rectangle (cr, frame.origin.x, frame.origin.y, frame.size.width, frame.size.height); + cairo_clip (cr); + } + + GSK_NOTE (CAIRO, g_print ("Rendering node %s[%p]\n", + node->name, + node)); + + node->node_class->draw (node, cr); + + if (GSK_RENDER_MODE_CHECK (GEOMETRY)) + { + graphene_rect_t frame; + + gsk_render_node_get_bounds (node, &frame); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_rectangle (cr, frame.origin.x - 1, frame.origin.y - 1, frame.size.width + 2, frame.size.height + 2); + cairo_set_line_width (cr, 2); + cairo_set_source_rgba (cr, 0, 0, 0, 0.5); + cairo_stroke (cr); + } + + cairo_restore (cr); +} + + diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h index 93a100eaf6..c874cb5b2e 100644 --- a/gsk/gskrendernode.h +++ b/gsk/gskrendernode.h @@ -88,6 +88,9 @@ void gsk_render_node_set_name (GskRenderNode * GDK_AVAILABLE_IN_3_90 const char * gsk_render_node_get_name (GskRenderNode *node); +GDK_AVAILABLE_IN_3_90 +void gsk_render_node_draw (GskRenderNode *node, + cairo_t *cr); G_END_DECLS #endif /* __GSK_RENDER_NODE_H__ */ diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index d23d18ddba..b80c0f6aee 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -20,7 +20,7 @@ #include "gskdebugprivate.h" #include "gskrendererprivate.h" -#include "gsktexture.h" +#include "gsktextureprivate.h" /*** GSK_TEXTURE_NODE ***/ @@ -47,6 +47,30 @@ gsk_texture_node_make_immutable (GskRenderNode *node) { } +static void +gsk_texture_node_draw (GskRenderNode *node, + cairo_t *cr) +{ + GskTextureNode *self = (GskTextureNode *) node; + cairo_surface_t *surface; + + surface = gsk_texture_download (self->texture); + + cairo_save (cr); + + cairo_translate (cr, self->bounds.origin.x, self->bounds.origin.y); + cairo_scale (cr, + self->bounds.size.width / gsk_texture_get_width (self->texture), + self->bounds.size.height / gsk_texture_get_height (self->texture)); + + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + + cairo_restore (cr); + + cairo_surface_destroy (surface); +} + static void gsk_texture_node_get_bounds (GskRenderNode *node, graphene_rect_t *bounds) @@ -62,6 +86,7 @@ static const GskRenderNodeClass GSK_TEXTURE_NODE_CLASS = { "GskTextureNode", gsk_texture_node_finalize, gsk_texture_node_make_immutable, + gsk_texture_node_draw, gsk_texture_node_get_bounds }; @@ -130,6 +155,19 @@ gsk_cairo_node_make_immutable (GskRenderNode *node) { } +static void +gsk_cairo_node_draw (GskRenderNode *node, + cairo_t *cr) +{ + GskCairoNode *self = (GskCairoNode *) node; + + if (self->surface == NULL) + return; + + cairo_set_source_surface (cr, self->surface, self->bounds.origin.x, self->bounds.origin.y); + cairo_paint (cr); +} + static void gsk_cairo_node_get_bounds (GskRenderNode *node, graphene_rect_t *bounds) @@ -145,6 +183,7 @@ static const GskRenderNodeClass GSK_CAIRO_NODE_CLASS = { "GskCairoNode", gsk_cairo_node_finalize, gsk_cairo_node_make_immutable, + gsk_cairo_node_draw, gsk_cairo_node_get_bounds }; @@ -313,6 +352,19 @@ gsk_container_node_make_immutable (GskRenderNode *node) } } +static void +gsk_container_node_draw (GskRenderNode *node, + cairo_t *cr) +{ + GskContainerNode *container = (GskContainerNode *) node; + guint i; + + for (i = 0; i < container->n_children; i++) + { + gsk_render_node_draw (container->children[i], cr); + } +} + static void gsk_container_node_get_bounds (GskRenderNode *node, graphene_rect_t *bounds) @@ -343,6 +395,7 @@ static const GskRenderNodeClass GSK_CONTAINER_NODE_CLASS = { "GskContainerNode", gsk_container_node_finalize, gsk_container_node_make_immutable, + gsk_container_node_draw, gsk_container_node_get_bounds }; @@ -436,9 +489,38 @@ gsk_transform_node_make_immutable (GskRenderNode *node) gsk_render_node_make_immutable (self->child); } +static void +gsk_transform_node_draw (GskRenderNode *node, + cairo_t *cr) +{ + GskTransformNode *self = (GskTransformNode *) node; + cairo_matrix_t ctm; + + if (graphene_matrix_to_2d (&self->transform, &ctm.xx, &ctm.yx, &ctm.xy, &ctm.yy, &ctm.x0, &ctm.y0)) + { + GSK_NOTE (CAIRO, g_print ("CTM = { .xx = %g, .yx = %g, .xy = %g, .yy = %g, .x0 = %g, .y0 = %g }\n", + ctm.xx, ctm.yx, + ctm.xy, ctm.yy, + ctm.x0, ctm.y0)); + cairo_transform (cr, &ctm); + + gsk_render_node_draw (self->child, cr); + } + else + { + graphene_rect_t bounds; + + gsk_render_node_get_bounds (node, &bounds); + + cairo_set_source_rgb (cr, 255 / 255., 105 / 255., 180 / 255.); + cairo_rectangle (cr, bounds.origin.x, bounds.origin.x, bounds.size.width, bounds.size.height); + cairo_fill (cr); + } +} + static void gsk_transform_node_get_bounds (GskRenderNode *node, - graphene_rect_t *bounds) + graphene_rect_t *bounds) { GskTransformNode *self = (GskTransformNode *) node; graphene_rect_t child_bounds; @@ -456,6 +538,7 @@ static const GskRenderNodeClass GSK_TRANSFORM_NODE_CLASS = { "GskTransformNode", gsk_transform_node_finalize, gsk_transform_node_make_immutable, + gsk_transform_node_draw, gsk_transform_node_get_bounds }; diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index 85117f4aa7..239e64dc70 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -40,6 +40,8 @@ struct _GskRenderNodeClass const char *type_name; void (* finalize) (GskRenderNode *node); void (* make_immutable) (GskRenderNode *node); + void (* draw) (GskRenderNode *node, + cairo_t *cr); void (* get_bounds) (GskRenderNode *node, graphene_rect_t *bounds); };