gsk: Add gsk_render_node_draw()

Draws a node to a given cairo_t. This is mostly intended for fallback
usage.
This commit is contained in:
Benjamin Otte 2016-12-13 03:05:15 +01:00
parent 02131d590e
commit e82d02432e
6 changed files with 151 additions and 118 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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
};

View File

@ -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);
};