summaryrefslogtreecommitdiff
path: root/gsk
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2016-12-13 03:05:15 +0100
committerBenjamin Otte <otte@redhat.com>2016-12-20 18:01:10 +0100
commite82d02432e57b00606976e8a84e06628dd9d4918 (patch)
tree61ca9bf52340f34af57eac21c623dbcd7cc461d8 /gsk
parent02131d590e2f4bdf9d2f487e619a3f08c1cf178e (diff)
downloadgtk+-e82d02432e57b00606976e8a84e06628dd9d4918.tar.gz
gsk: Add gsk_render_node_draw()
Draws a node to a given cairo_t. This is mostly intended for fallback usage.
Diffstat (limited to 'gsk')
-rw-r--r--gsk/gskcairorenderer.c117
-rw-r--r--gsk/gskrendernode.c59
-rw-r--r--gsk/gskrendernode.h3
-rw-r--r--gsk/gskrendernodeimpl.c87
-rw-r--r--gsk/gskrendernodeprivate.h2
5 files changed, 150 insertions, 118 deletions
diff --git a/gsk/gskcairorenderer.c b/gsk/gskcairorenderer.c
index 4fd85927d9..3fb394a5de 100644
--- a/gsk/gskcairorenderer.c
+++ b/gsk/gskcairorenderer.c
@@ -47,121 +47,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 ***/
@@ -48,6 +48,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
};
@@ -131,6 +156,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
};
@@ -314,6 +353,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
};
@@ -437,8 +490,37 @@ gsk_transform_node_make_immutable (GskRenderNode *node)
}
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);
};