mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-28 22:41:43 +00:00
dace0791a9
While porting GTK to GskRenderer we noticed that the current fallback code for widgets using Cairo to draw is not enough to cover all the possible cases. For instance, if a container widget still uses GtkWidget::draw to render its children, and at least one of them has been ported to using render nodes instead, the container won't know how to draw it. For this reason we want to provide to layers above GSK the ability to create a "fallback" renderer instance, created using a "parent" GskRenderer instance, but using a Cairo context as the rendering target instead of a GdkDrawingContext. GTK will use this inside the gtk_widget_draw() implementation, if a widget implements GtkWidgetClass.get_render_node().
186 lines
5.2 KiB
C
186 lines
5.2 KiB
C
#include "config.h"
|
|
|
|
#include "gskcairorendererprivate.h"
|
|
|
|
#include "gskdebugprivate.h"
|
|
#include "gskrendererprivate.h"
|
|
#include "gskrendernodeiter.h"
|
|
#include "gskrendernodeprivate.h"
|
|
|
|
struct _GskCairoRenderer
|
|
{
|
|
GskRenderer parent_instance;
|
|
|
|
graphene_rect_t viewport;
|
|
};
|
|
|
|
struct _GskCairoRendererClass
|
|
{
|
|
GskRendererClass parent_class;
|
|
};
|
|
|
|
G_DEFINE_TYPE (GskCairoRenderer, gsk_cairo_renderer, GSK_TYPE_RENDERER)
|
|
|
|
static gboolean
|
|
gsk_cairo_renderer_realize (GskRenderer *renderer)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
gsk_cairo_renderer_unrealize (GskRenderer *renderer)
|
|
{
|
|
|
|
}
|
|
|
|
static void
|
|
gsk_cairo_renderer_render_node (GskCairoRenderer *self,
|
|
GskRenderNode *node,
|
|
cairo_t *cr)
|
|
{
|
|
GskRenderNodeIter iter;
|
|
GskRenderNode *child;
|
|
gboolean pop_group = FALSE;
|
|
graphene_matrix_t mvp;
|
|
cairo_matrix_t ctm;
|
|
graphene_rect_t frame;
|
|
|
|
if (gsk_render_node_is_hidden (node))
|
|
return;
|
|
|
|
cairo_save (cr);
|
|
|
|
if (!gsk_render_node_has_surface (node))
|
|
goto out;
|
|
|
|
gsk_render_node_get_world_matrix (node, &mvp);
|
|
if (graphene_matrix_to_2d (&mvp, &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_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_is_opaque (node) && 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 surface %p for node %s[%p] at %g, %g\n",
|
|
gsk_render_node_get_surface (node),
|
|
node->name,
|
|
node,
|
|
frame.origin.x, frame.origin.y));
|
|
cairo_set_source_surface (cr, gsk_render_node_get_surface (node), frame.origin.x, frame.origin.y);
|
|
cairo_paint (cr);
|
|
|
|
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);
|
|
}
|
|
|
|
cairo_matrix_invert (&ctm);
|
|
cairo_transform (cr, &ctm);
|
|
|
|
out:
|
|
if (gsk_render_node_get_n_children (node) != 0)
|
|
{
|
|
GSK_NOTE (CAIRO, g_print ("Drawing %d children of node [%p]\n",
|
|
gsk_render_node_get_n_children (node),
|
|
node));
|
|
gsk_render_node_iter_init (&iter, node);
|
|
while (gsk_render_node_iter_next (&iter, &child))
|
|
gsk_cairo_renderer_render_node (self, child, 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)
|
|
{
|
|
GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer);
|
|
GdkDrawingContext *context = gsk_renderer_get_drawing_context (renderer);
|
|
cairo_t *cr;
|
|
|
|
if (context != NULL)
|
|
cr = gdk_drawing_context_get_cairo_context (context);
|
|
else
|
|
cr = gsk_renderer_get_cairo_context (renderer);
|
|
|
|
if (cr == NULL)
|
|
return;
|
|
|
|
gsk_renderer_get_viewport (renderer, &self->viewport);
|
|
|
|
cairo_save (cr);
|
|
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
|
cairo_set_source_rgba (cr, 0, 0, 0, 0);
|
|
cairo_paint (cr);
|
|
cairo_restore (cr);
|
|
|
|
if (GSK_RENDER_MODE_CHECK (GEOMETRY))
|
|
{
|
|
cairo_save (cr);
|
|
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
|
cairo_rectangle (cr,
|
|
self->viewport.origin.x,
|
|
self->viewport.origin.y,
|
|
self->viewport.size.width,
|
|
self->viewport.size.height);
|
|
cairo_set_source_rgba (cr, 0, 0, 0.85, 0.5);
|
|
cairo_stroke (cr);
|
|
cairo_restore (cr);
|
|
}
|
|
|
|
gsk_cairo_renderer_render_node (self, root, cr);
|
|
}
|
|
|
|
static void
|
|
gsk_cairo_renderer_class_init (GskCairoRendererClass *klass)
|
|
{
|
|
GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass);
|
|
|
|
renderer_class->realize = gsk_cairo_renderer_realize;
|
|
renderer_class->unrealize = gsk_cairo_renderer_unrealize;
|
|
renderer_class->render = gsk_cairo_renderer_render;
|
|
}
|
|
|
|
static void
|
|
gsk_cairo_renderer_init (GskCairoRenderer *self)
|
|
{
|
|
|
|
}
|