gtk2/gsk/gskcairorenderer.c
2016-11-08 20:31:34 +01:00

279 lines
8.1 KiB
C

#include "config.h"
#include "gskcairorendererprivate.h"
#include "gskdebugprivate.h"
#include "gskrendererprivate.h"
#include "gskrendernodeiter.h"
#include "gskrendernodeprivate.h"
#include "gsktextureprivate.h"
struct _GskCairoRenderer
{
GskRenderer parent_instance;
graphene_rect_t viewport;
};
struct _GskCairoRendererClass
{
GskRendererClass parent_class;
};
typedef struct _GskCairoTexture GskCairoTexture;
struct _GskCairoTexture {
GskTexture texture;
cairo_surface_t *surface;
};
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) &&
!gsk_render_node_has_texture (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));
if (gsk_render_node_has_texture (node))
{
GskCairoTexture *cairo_texture = (GskCairoTexture *) gsk_render_node_get_texture (node);
cairo_set_source_surface (cr, cairo_texture->surface, frame.origin.x, frame.origin.y);
cairo_paint (cr);
}
else
{
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 GskTexture *
gsk_cairo_texture_new_for_surface (GskRenderer *renderer,
cairo_surface_t *surface,
int width,
int height)
{
GskCairoTexture *texture;
texture = gsk_texture_new (GskCairoTexture, renderer, width, height);
texture->surface = cairo_surface_reference (surface);
return (GskTexture *) texture;
}
static GskTexture *
gsk_cairo_renderer_texture_new_for_data (GskRenderer *renderer,
const guchar *data,
int width,
int height,
int stride)
{
GskTexture *texture;
cairo_surface_t *original, *copy;
cairo_t *cr;
original = cairo_image_surface_create_for_data ((guchar *) data, CAIRO_FORMAT_ARGB32, width, height, stride);
copy = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
cr = cairo_create (copy);
cairo_set_source_surface (cr, original, 0, 0);
cairo_paint (cr);
cairo_destroy (cr);
texture = gsk_cairo_texture_new_for_surface (renderer,
copy,
width, height);
cairo_surface_destroy (copy);
cairo_surface_destroy (original);
return texture;
}
static GskTexture *
gsk_cairo_renderer_texture_new_for_pixbuf (GskRenderer *renderer,
GdkPixbuf *pixbuf)
{
GskTexture *texture;
cairo_surface_t *surface;
surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, NULL);
texture = gsk_cairo_texture_new_for_surface (renderer,
surface,
gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf));
cairo_surface_destroy (surface);
return texture;
}
static void
gsk_cairo_renderer_texture_destroy (GskTexture *texture)
{
GskCairoTexture *cairo_texture = (GskCairoTexture *) texture;
cairo_surface_destroy (cairo_texture->surface);
}
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;
renderer_class->texture_new_for_data = gsk_cairo_renderer_texture_new_for_data;
renderer_class->texture_new_for_pixbuf = gsk_cairo_renderer_texture_new_for_pixbuf;
renderer_class->texture_destroy = gsk_cairo_renderer_texture_destroy;
}
static void
gsk_cairo_renderer_init (GskCairoRenderer *self)
{
}