[librsvg: 8/10] drawing_ctx: rename some methods to use the right naming convention
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 8/10] drawing_ctx: rename some methods to use the right naming convention
- Date: Mon, 14 May 2018 01:38:40 +0000 (UTC)
commit 9bddd4363572373f9e996d646c53e7cd33766535
Author: Paolo Borelli <pborelli gnome org>
Date: Sun May 13 16:01:10 2018 +0200
drawing_ctx: rename some methods to use the right naming convention
Also move the pixbuf related functions to file-util.c, despite the
name, this is where all the other pixbuf related function are.
librsvg/filters/image.c | 2 +-
librsvg/rsvg-base.c | 12 -
librsvg/rsvg-drawing-ctx.c | 1090 +++++++++++++++----------------------
librsvg/rsvg-drawing-ctx.h | 31 +-
librsvg/rsvg-file-util.c | 204 +++++++
rsvg_internals/src/drawing_ctx.rs | 88 +--
6 files changed, 712 insertions(+), 715 deletions(-)
---
diff --git a/librsvg/filters/image.c b/librsvg/filters/image.c
index d856dd5b..e8e09813 100644
--- a/librsvg/filters/image.c
+++ b/librsvg/filters/image.c
@@ -57,7 +57,7 @@ rsvg_filter_primitive_image_render_in (RsvgFilterPrimitiveImage *image, RsvgFilt
rsvg_state_set_affine (rsvg_drawing_ctx_get_current_state (ctx), context->paffine);
- result = rsvg_cairo_get_surface_of_node (ctx, drawable, context->width, context->height);
+ result = rsvg_drawing_ctx_get_surface_of_node (ctx, drawable, context->width, context->height);
rsvg_drawing_ctx_release_node (ctx, drawable);
diff --git a/librsvg/rsvg-base.c b/librsvg/rsvg-base.c
index 9c958b56..14e2dc37 100644
--- a/librsvg/rsvg-base.c
+++ b/librsvg/rsvg-base.c
@@ -332,18 +332,6 @@ rsvg_cleanup (void)
xmlCleanupParser ();
}
-void
-rsvg_pop_discrete_layer (RsvgDrawingCtx *ctx, gboolean clipping)
-{
- rsvg_cairo_pop_discrete_layer (ctx, clipping);
-}
-
-void
-rsvg_push_discrete_layer (RsvgDrawingCtx *ctx, gboolean clipping)
-{
- rsvg_cairo_push_discrete_layer (ctx, clipping);
-}
-
cairo_surface_t *
rsvg_cairo_surface_new_from_href (RsvgHandle *handle,
const char *href,
diff --git a/librsvg/rsvg-drawing-ctx.c b/librsvg/rsvg-drawing-ctx.c
index cec0e509..f7356f2c 100644
--- a/librsvg/rsvg-drawing-ctx.c
+++ b/librsvg/rsvg-drawing-ctx.c
@@ -52,137 +52,6 @@ void rsvg_cairo_add_clipping_rect (RsvgDrawingCtx *ctx,
double w,
double h);
-#ifdef HAVE_PANGOFT2
-static cairo_font_options_t *
-get_font_options_for_testing (void)
-{
- cairo_font_options_t *options;
-
- options = cairo_font_options_create ();
- cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
- cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_FULL);
- cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
-
- return options;
-}
-
-static void
-set_font_options_for_testing (PangoContext *context)
-{
- cairo_font_options_t *font_options;
-
- font_options = get_font_options_for_testing ();
- pango_cairo_context_set_font_options (context, font_options);
- cairo_font_options_destroy (font_options);
-}
-
-static void
-create_font_config_for_testing (RsvgDrawingCtx *ctx)
-{
- const char *font_paths[] = {
- SRCDIR "/tests/resources/Roboto-Regular.ttf",
- SRCDIR "/tests/resources/Roboto-Italic.ttf",
- SRCDIR "/tests/resources/Roboto-Bold.ttf",
- SRCDIR "/tests/resources/Roboto-BoldItalic.ttf",
- };
-
- int i;
-
- if (ctx->font_config_for_testing != NULL)
- return;
-
- ctx->font_config_for_testing = FcConfigCreate ();
-
- for (i = 0; i < G_N_ELEMENTS(font_paths); i++) {
- if (!FcConfigAppFontAddFile (ctx->font_config_for_testing, (const FcChar8 *) font_paths[i])) {
- g_error ("Could not load font file \"%s\" for tests; aborting", font_paths[i]);
- }
- }
-}
-
-static PangoFontMap *
-get_font_map_for_testing (RsvgDrawingCtx *ctx)
-{
- create_font_config_for_testing (ctx);
-
- if (ctx->font_map_for_testing == NULL) {
- ctx->font_map_for_testing = pango_cairo_font_map_new_for_font_type (CAIRO_FONT_TYPE_FT);
- pango_fc_font_map_set_config (PANGO_FC_FONT_MAP (ctx->font_map_for_testing),
- ctx->font_config_for_testing);
- }
-
- return ctx->font_map_for_testing;
-}
-#endif
-
-PangoContext *
-rsvg_cairo_get_pango_context (RsvgDrawingCtx * ctx)
-{
- PangoFontMap *fontmap;
- PangoContext *context;
- double dpi_y;
-
-#ifdef HAVE_PANGOFT2
- if (ctx->is_testing) {
- fontmap = get_font_map_for_testing (ctx);
- } else {
-#endif
- fontmap = pango_cairo_font_map_get_default ();
-#ifdef HAVE_PANGOFT2
- }
-#endif
-
- context = pango_font_map_create_context (fontmap);
- pango_cairo_update_context (ctx->cr, context);
-
- rsvg_drawing_ctx_get_dpi (ctx, NULL, &dpi_y);
- pango_cairo_context_set_resolution (context, dpi_y);
-
-#ifdef HAVE_PANGOFT2
- if (ctx->is_testing) {
- set_font_options_for_testing (context);
- }
-#endif
-
- return context;
-}
-
-cairo_t *
-rsvg_cairo_get_cairo_context (RsvgDrawingCtx *ctx)
-{
- return ctx->cr;
-}
-
-/* FIXME: Usage of this function is more less a hack. Some code does this:
- *
- * save_cr = rsvg_cairo_get_cairo_context (ctx);
- *
- * some_surface = create_surface ();
- *
- * cr = cairo_create (some_surface);
- *
- * rsvg_cairo_set_cairo_context (ctx, cr);
- *
- * ... draw with ctx but to that temporary surface
- *
- * rsvg_cairo_set_cairo_context (ctx, save_cr);
- *
- * It would be better to have an explicit push/pop for the cairo_t, or
- * pushing a temporary surface, or something that does not involve
- * monkeypatching the cr directly.
- */
-void
-rsvg_cairo_set_cairo_context (RsvgDrawingCtx *ctx, cairo_t *cr)
-{
- ctx->cr = cr;
-}
-
-gboolean
-rsvg_cairo_is_cairo_context_nested (RsvgDrawingCtx *ctx, cairo_t *cr)
-{
- return cr != ctx->initial_cr;
-}
-
static void
rsvg_cairo_generate_mask (cairo_t * cr, RsvgNode *mask, RsvgDrawingCtx *ctx)
{
@@ -387,136 +256,221 @@ rsvg_cairo_clip (RsvgDrawingCtx *ctx, RsvgNode *node_clip_path, RsvgBbox *bbox)
}
static void
-push_bounding_box (RsvgDrawingCtx *ctx)
+rsvg_cairo_transformed_image_bounding_box (cairo_matrix_t *affine,
+ double width, double height,
+ double *x0, double *y0, double *x1, double *y1)
{
- RsvgState *state;
- cairo_matrix_t affine;
- RsvgBbox *bbox, *ink_bbox;
+ double x00 = 0, x01 = 0, x10 = width, x11 = width;
+ double y00 = 0, y01 = height, y10 = 0, y11 = height;
+ double t;
- state = rsvg_drawing_ctx_get_current_state (ctx);
+ /* transform the four corners of the image */
+ cairo_matrix_transform_point (affine, &x00, &y00);
+ cairo_matrix_transform_point (affine, &x01, &y01);
+ cairo_matrix_transform_point (affine, &x10, &y10);
+ cairo_matrix_transform_point (affine, &x11, &y11);
- bbox = g_new0 (RsvgBbox, 1);
- *bbox = ctx->bbox;
- ctx->bb_stack = g_list_prepend (ctx->bb_stack, bbox);
+ /* find minimum and maximum coordinates */
+ t = x00 < x01 ? x00 : x01;
+ t = t < x10 ? t : x10;
+ *x0 = floor (t < x11 ? t : x11);
- ink_bbox = g_new0 (RsvgBbox, 1);
- *ink_bbox = ctx->ink_bbox;
- ctx->ink_bb_stack = g_list_prepend (ctx->ink_bb_stack, ink_bbox);
+ t = y00 < y01 ? y00 : y01;
+ t = t < y10 ? t : y10;
+ *y0 = floor (t < y11 ? t : y11);
- affine = rsvg_state_get_affine (state);
- rsvg_bbox_init (&ctx->bbox, &affine);
- rsvg_bbox_init (&ctx->ink_bbox, &affine);
+ t = x00 > x01 ? x00 : x01;
+ t = t > x10 ? t : x10;
+ *x1 = ceil (t > x11 ? t : x11);
+
+ t = y00 > y01 ? y00 : y01;
+ t = t > y10 ? t : y10;
+ *y1 = ceil (t > y11 ? t : y11);
}
-static void
-rsvg_cairo_push_render_stack (RsvgDrawingCtx * ctx)
+RsvgDrawingCtx *
+rsvg_drawing_ctx_new (cairo_t *cr, RsvgHandle *handle)
{
+ RsvgDimensionData data;
+ RsvgDrawingCtx *draw;
RsvgState *state;
- char *clip_path;
- char *filter;
- char *mask;
- guint8 opacity;
- cairo_operator_t comp_op;
- RsvgEnableBackgroundType enable_background;
- cairo_surface_t *surface;
- cairo_t *child_cr;
- gboolean lateclip = FALSE;
+ cairo_matrix_t affine;
+ cairo_matrix_t state_affine;
+ double bbx0, bby0, bbx1, bby1;
- state = rsvg_drawing_ctx_get_current_state (ctx);
- clip_path = rsvg_state_get_clip_path (state);
- filter = rsvg_state_get_filter (state);
- mask = rsvg_state_get_mask (state);
- opacity = rsvg_state_get_opacity (state);
- comp_op = rsvg_state_get_comp_op (state);
- enable_background = rsvg_state_get_enable_background (state);
+ rsvg_handle_get_dimensions (handle, &data);
+ if (data.width == 0 || data.height == 0)
+ return NULL;
- if (clip_path) {
- RsvgNode *node;
- node = rsvg_drawing_ctx_acquire_node_of_type (ctx, clip_path, RSVG_NODE_TYPE_CLIP_PATH);
- if (node) {
- switch (rsvg_node_clip_path_get_units (node)) {
- case userSpaceOnUse:
- rsvg_cairo_clip (ctx, node, NULL);
- break;
- case objectBoundingBox:
- lateclip = TRUE;
- break;
+ draw = g_new0 (RsvgDrawingCtx, 1);
- default:
- g_assert_not_reached ();
- break;
- }
+ cairo_get_matrix (cr, &affine);
- rsvg_drawing_ctx_release_node (ctx, node);
- }
+ /* find bounding box of image as transformed by the current cairo context
+ * The size of this bounding box determines the size of the intermediate
+ * surfaces allocated during drawing. */
+ rsvg_cairo_transformed_image_bounding_box (&affine,
+ data.width, data.height,
+ &bbx0, &bby0, &bbx1, &bby1);
- g_free (clip_path);
- }
+ draw->initial_cr = cr;
+ draw->cr = cr;
+ draw->cr_stack = NULL;
+ draw->surfaces_stack = NULL;
- if (opacity == 0xFF
- && !filter && !mask && !lateclip && (comp_op == CAIRO_OPERATOR_OVER)
- && (enable_background == RSVG_ENABLE_BACKGROUND_ACCUMULATE))
- return;
+ draw->offset_x = bbx0;
+ draw->offset_y = bby0;
+ draw->width = bbx1 - bbx0;
+ draw->height = bby1 - bby0;
- g_free (mask);
+ draw->state = NULL;
- if (!filter) {
- surface = cairo_surface_create_similar (cairo_get_target (ctx->cr),
- CAIRO_CONTENT_COLOR_ALPHA,
- ctx->width, ctx->height);
- } else {
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- ctx->width, ctx->height);
+ draw->defs = handle->priv->defs;
+ draw->dpi_x = handle->priv->dpi_x;
+ draw->dpi_y = handle->priv->dpi_y;
+ draw->vb.rect.width = data.em;
+ draw->vb.rect.height = data.ex;
+ draw->vb_stack = NULL;
+ draw->drawsub_stack = NULL;
+ draw->acquired_nodes = NULL;
+ draw->is_testing = handle->priv->is_testing;
- /* The surface reference is owned by the child_cr created below and put on the cr_stack! */
- ctx->surfaces_stack = g_list_prepend (ctx->surfaces_stack, surface);
+ rsvg_drawing_ctx_state_push (draw);
+ state = rsvg_drawing_ctx_get_current_state (draw);
- g_free (filter);
- }
+ state_affine = rsvg_state_get_affine (state);
-#if 0
- if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
- cairo_surface_destroy (surface);
- return;
+ /* apply cairo transformation to our affine transform */
+ cairo_matrix_multiply (&state_affine, &affine, &state_affine);
+
+ /* scale according to size set by size_func callback */
+ cairo_matrix_init_scale (&affine, data.width / data.em, data.height / data.ex);
+ cairo_matrix_multiply (&state_affine, &affine, &state_affine);
+
+ /* adjust transform so that the corner of the bounding box above is
+ * at (0,0) - we compensate for this in _set_rsvg_affine() in
+ * rsvg-cairo-render.c and a few other places */
+ state_affine.x0 -= draw->offset_x;
+ state_affine.y0 -= draw->offset_y;
+
+ rsvg_bbox_init (&draw->bbox, &state_affine);
+ rsvg_bbox_init (&draw->ink_bbox, &state_affine);
+
+ rsvg_state_set_affine (state, state_affine);
+
+#ifdef HAVE_PANGOFT2
+ draw->font_config_for_testing = NULL;
+ draw->font_map_for_testing = NULL;
+#endif
+
+ return draw;
+}
+
+void
+rsvg_drawing_ctx_free (RsvgDrawingCtx *ctx)
+{
+ g_assert (ctx->cr_stack == NULL);
+ g_assert (ctx->surfaces_stack == NULL);
+
+ g_assert(ctx->state);
+ g_assert(rsvg_state_parent(ctx->state) == NULL);
+ rsvg_state_free (ctx->state);
+
+ g_slist_free_full (ctx->drawsub_stack, (GDestroyNotify) rsvg_node_unref);
+
+ g_warn_if_fail (ctx->acquired_nodes == NULL);
+ g_slist_free (ctx->acquired_nodes);
+
+ g_assert (ctx->bb_stack == NULL);
+ g_assert (ctx->ink_bb_stack == NULL);
+
+#ifdef HAVE_PANGOFT2
+ if (ctx->font_config_for_testing) {
+ FcConfigDestroy (ctx->font_config_for_testing);
+ ctx->font_config_for_testing = NULL;
+ }
+
+ if (ctx->font_map_for_testing) {
+ g_object_unref (ctx->font_map_for_testing);
+ ctx->font_map_for_testing = NULL;
}
#endif
- child_cr = cairo_create (surface);
- cairo_surface_destroy (surface);
+ g_free (ctx);
+}
- ctx->cr_stack = g_list_prepend (ctx->cr_stack, ctx->cr);
- ctx->cr = child_cr;
+cairo_t *
+rsvg_drawing_ctx_get_cairo_context (RsvgDrawingCtx *ctx)
+{
+ return ctx->cr;
+}
- push_bounding_box (ctx);
+/* FIXME: Usage of this function is more less a hack. Some code does this:
+ *
+ * save_cr = rsvg_drawing_ctx_get_cairo_context (ctx);
+ *
+ * some_surface = create_surface ();
+ *
+ * cr = cairo_create (some_surface);
+ *
+ * rsvg_drawing_ctx_set_cairo_context (ctx, cr);
+ *
+ * ... draw with ctx but to that temporary surface
+ *
+ * rsvg_drawing_ctx_set_cairo_context (ctx, save_cr);
+ *
+ * It would be better to have an explicit push/pop for the cairo_t, or
+ * pushing a temporary surface, or something that does not involve
+ * monkeypatching the cr directly.
+ */
+void
+rsvg_drawing_ctx_set_cairo_context (RsvgDrawingCtx *ctx, cairo_t *cr)
+{
+ ctx->cr = cr;
+}
+
+gboolean
+rsvg_drawing_ctx_is_cairo_context_nested (RsvgDrawingCtx *ctx, cairo_t *cr)
+{
+ return cr != ctx->initial_cr;
+}
+
+RsvgState *
+rsvg_drawing_ctx_get_current_state (RsvgDrawingCtx *ctx)
+{
+ return ctx->state;
}
void
-rsvg_cairo_push_discrete_layer (RsvgDrawingCtx * ctx, gboolean clipping)
+rsvg_drawing_ctx_set_current_state (RsvgDrawingCtx *ctx, RsvgState *state)
{
- if (!clipping) {
- cairo_save (ctx->cr);
- rsvg_cairo_push_render_stack (ctx);
- }
+ ctx->state = state;
}
static void
-pop_bounding_box (RsvgDrawingCtx *ctx)
+push_bounding_box (RsvgDrawingCtx *ctx)
{
- rsvg_bbox_insert ((RsvgBbox *) ctx->bb_stack->data, &ctx->bbox);
- rsvg_bbox_insert ((RsvgBbox *) ctx->ink_bb_stack->data, &ctx->ink_bbox);
+ RsvgState *state;
+ cairo_matrix_t affine;
+ RsvgBbox *bbox, *ink_bbox;
- ctx->bbox = *((RsvgBbox *) ctx->bb_stack->data);
- ctx->ink_bbox = *((RsvgBbox *) ctx->ink_bb_stack->data);
+ state = rsvg_drawing_ctx_get_current_state (ctx);
- g_free (ctx->bb_stack->data);
- g_free (ctx->ink_bb_stack->data);
+ bbox = g_new0 (RsvgBbox, 1);
+ *bbox = ctx->bbox;
+ ctx->bb_stack = g_list_prepend (ctx->bb_stack, bbox);
- ctx->bb_stack = g_list_delete_link (ctx->bb_stack, ctx->bb_stack);
- ctx->ink_bb_stack = g_list_delete_link (ctx->ink_bb_stack, ctx->ink_bb_stack);
+ ink_bbox = g_new0 (RsvgBbox, 1);
+ *ink_bbox = ctx->ink_bbox;
+ ctx->ink_bb_stack = g_list_prepend (ctx->ink_bb_stack, ink_bbox);
+
+ affine = rsvg_state_get_affine (state);
+ rsvg_bbox_init (&ctx->bbox, &affine);
+ rsvg_bbox_init (&ctx->ink_bbox, &affine);
}
static void
-rsvg_cairo_pop_render_stack (RsvgDrawingCtx * ctx)
+rsvg_drawing_ctx_push_render_stack (RsvgDrawingCtx * ctx)
{
RsvgState *state;
char *clip_path;
@@ -525,11 +479,9 @@ rsvg_cairo_pop_render_stack (RsvgDrawingCtx * ctx)
guint8 opacity;
cairo_operator_t comp_op;
RsvgEnableBackgroundType enable_background;
- cairo_t *child_cr = ctx->cr;
- RsvgNode *lateclip = NULL;
- cairo_surface_t *surface = NULL;
- gboolean needs_destroy = FALSE;
- double offset_x = 0, offset_y = 0;
+ cairo_surface_t *surface;
+ cairo_t *child_cr;
+ gboolean lateclip = FALSE;
state = rsvg_drawing_ctx_get_current_state (ctx);
clip_path = rsvg_state_get_clip_path (state);
@@ -541,14 +493,22 @@ rsvg_cairo_pop_render_stack (RsvgDrawingCtx * ctx)
if (clip_path) {
RsvgNode *node;
-
node = rsvg_drawing_ctx_acquire_node_of_type (ctx, clip_path, RSVG_NODE_TYPE_CLIP_PATH);
if (node) {
- if (rsvg_node_clip_path_get_units (node) == objectBoundingBox) {
- lateclip = node;
- } else {
- rsvg_drawing_ctx_release_node (ctx, node);
+ switch (rsvg_node_clip_path_get_units (node)) {
+ case userSpaceOnUse:
+ rsvg_cairo_clip (ctx, node, NULL);
+ break;
+ case objectBoundingBox:
+ lateclip = TRUE;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
}
+
+ rsvg_drawing_ctx_release_node (ctx, node);
}
g_free (clip_path);
@@ -559,476 +519,176 @@ rsvg_cairo_pop_render_stack (RsvgDrawingCtx * ctx)
&& (enable_background == RSVG_ENABLE_BACKGROUND_ACCUMULATE))
return;
- surface = cairo_get_target (child_cr);
-
- if (filter) {
- RsvgNode *node;
- cairo_surface_t *output;
-
- output = ctx->surfaces_stack->data;
- ctx->surfaces_stack = g_list_delete_link (ctx->surfaces_stack, ctx->surfaces_stack);
+ g_free (mask);
- node = rsvg_drawing_ctx_acquire_node_of_type (ctx, filter, RSVG_NODE_TYPE_FILTER);
- if (node) {
- needs_destroy = TRUE;
- surface = rsvg_filter_render (node, output, ctx, "2103");
- rsvg_drawing_ctx_release_node (ctx, node);
+ if (!filter) {
+ surface = cairo_surface_create_similar (cairo_get_target (ctx->cr),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ ctx->width, ctx->height);
+ } else {
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ ctx->width, ctx->height);
- /* Don't destroy the output surface, it's owned by child_cr */
- }
+ /* The surface reference is owned by the child_cr created below and put on the cr_stack! */
+ ctx->surfaces_stack = g_list_prepend (ctx->surfaces_stack, surface);
g_free (filter);
}
- ctx->cr = (cairo_t *) ctx->cr_stack->data;
- ctx->cr_stack = g_list_delete_link (ctx->cr_stack, ctx->cr_stack);
-
- if (ctx->cr == ctx->initial_cr) {
- rsvg_drawing_ctx_get_offset (ctx, &offset_x, &offset_y);
- }
-
- cairo_identity_matrix (ctx->cr);
- cairo_set_source_surface (ctx->cr, surface, offset_x, offset_y);
-
- if (lateclip) {
- rsvg_cairo_clip (ctx, lateclip, &ctx->bbox);
- rsvg_drawing_ctx_release_node (ctx, lateclip);
- }
-
- cairo_set_operator (ctx->cr, comp_op);
-
- if (mask) {
- RsvgNode *node;
-
- node = rsvg_drawing_ctx_acquire_node_of_type (ctx, mask, RSVG_NODE_TYPE_MASK);
- if (node) {
- rsvg_cairo_generate_mask (ctx->cr, node, ctx);
- rsvg_drawing_ctx_release_node (ctx, node);
- }
-
- g_free (mask);
- } else if (opacity != 0xFF)
- cairo_paint_with_alpha (ctx->cr, (double) opacity / 255.0);
- else
- cairo_paint (ctx->cr);
-
- cairo_destroy (child_cr);
-
- pop_bounding_box (ctx);
-
- if (needs_destroy) {
- cairo_surface_destroy (surface);
- }
-}
-
-void
-rsvg_cairo_pop_discrete_layer (RsvgDrawingCtx * ctx, gboolean clipping)
-{
- if (!clipping) {
- rsvg_cairo_pop_render_stack (ctx);
- cairo_restore (ctx->cr);
- }
-}
-
-cairo_surface_t *
-rsvg_cairo_get_surface_of_node (RsvgDrawingCtx *ctx,
- RsvgNode *drawable,
- double width,
- double height)
-{
- cairo_surface_t *surface;
- cairo_t *cr;
- cairo_t *save_cr = ctx->cr;
- cairo_t *save_initial_cr = ctx->initial_cr;
- double save_x = ctx->offset_x;
- double save_y = ctx->offset_y;
- double save_w = ctx->width;
- double save_h = ctx->height;
-
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
- if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
- cairo_surface_destroy (surface);
- return NULL;
- }
-
- ctx->cr = cairo_create (surface);
- ctx->initial_cr = ctx->cr;
- ctx->offset_x = 0;
- ctx->offset_y = 0;
- ctx->width = width;
- ctx->height = height;
-
- rsvg_drawing_ctx_draw_node_from_stack (ctx, drawable, 0, FALSE);
-
- cairo_destroy (ctx->cr);
- ctx->cr = save_cr;
- ctx->initial_cr = save_initial_cr;
- ctx->offset_x = save_x;
- ctx->offset_y = save_y;
- ctx->width = save_w;
- ctx->height = save_h;
-
- return surface;
-}
-
-cairo_surface_t *
-rsvg_cairo_surface_from_pixbuf (const GdkPixbuf *pixbuf)
-{
- gint width, height, gdk_rowstride, n_channels, cairo_rowstride;
- guchar *gdk_pixels, *cairo_pixels;
- cairo_format_t format;
- cairo_surface_t *surface;
- int j;
-
- if (pixbuf == NULL)
- return NULL;
-
- width = gdk_pixbuf_get_width (pixbuf);
- height = gdk_pixbuf_get_height (pixbuf);
- gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
- gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
- n_channels = gdk_pixbuf_get_n_channels (pixbuf);
-
- if (n_channels == 3)
- format = CAIRO_FORMAT_RGB24;
- else
- format = CAIRO_FORMAT_ARGB32;
-
- surface = cairo_image_surface_create (format, width, height);
+#if 0
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
cairo_surface_destroy (surface);
- return NULL;
+ return;
}
-
- cairo_pixels = cairo_image_surface_get_data (surface);
- cairo_rowstride = cairo_image_surface_get_stride (surface);
-
- if (n_channels == 3) {
- for (j = height; j; j--) {
- guchar *p = gdk_pixels;
- guchar *q = cairo_pixels;
- guchar *end = p + 3 * width;
-
- while (p < end) {
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
- q[0] = p[2];
- q[1] = p[1];
- q[2] = p[0];
-#else
- q[1] = p[0];
- q[2] = p[1];
- q[3] = p[2];
#endif
- p += 3;
- q += 4;
- }
-
- gdk_pixels += gdk_rowstride;
- cairo_pixels += cairo_rowstride;
- }
- } else {
- for (j = height; j; j--) {
- guchar *p = gdk_pixels;
- guchar *q = cairo_pixels;
- guchar *end = p + 4 * width;
- guint t1, t2, t3;
-
-#define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
-
- while (p < end) {
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
- MULT (q[0], p[2], p[3], t1);
- MULT (q[1], p[1], p[3], t2);
- MULT (q[2], p[0], p[3], t3);
- q[3] = p[3];
-#else
- q[0] = p[3];
- MULT (q[1], p[0], p[3], t1);
- MULT (q[2], p[1], p[3], t2);
- MULT (q[3], p[2], p[3], t3);
-#endif
-
- p += 4;
- q += 4;
- }
-
-#undef MULT
- gdk_pixels += gdk_rowstride;
- cairo_pixels += cairo_rowstride;
- }
- }
- cairo_surface_mark_dirty (surface);
- return surface;
-}
+ child_cr = cairo_create (surface);
+ cairo_surface_destroy (surface);
-/* Copied from gtk+/gdk/gdkpixbuf-drawable.c, LGPL 2+.
- *
- * Copyright (C) 1999 Michael Zucchi
- *
- * Authors: Michael Zucchi <zucchi zedzone mmc com au>
- * Cody Russell <bratsche dfw net>
- * Federico Mena-Quintero <federico gimp org>
- */
+ ctx->cr_stack = g_list_prepend (ctx->cr_stack, ctx->cr);
+ ctx->cr = child_cr;
-static void
-convert_alpha (guchar *dest_data,
- int dest_stride,
- guchar *src_data,
- int src_stride,
- int src_x,
- int src_y,
- int width,
- int height)
-{
- int x, y;
-
- src_data += src_stride * src_y + src_x * 4;
-
- for (y = 0; y < height; y++) {
- guint32 *src = (guint32 *) src_data;
-
- for (x = 0; x < width; x++) {
- guint alpha = src[x] >> 24;
-
- if (alpha == 0) {
- dest_data[x * 4 + 0] = 0;
- dest_data[x * 4 + 1] = 0;
- dest_data[x * 4 + 2] = 0;
- } else {
- dest_data[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
- dest_data[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
- dest_data[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
- }
- dest_data[x * 4 + 3] = alpha;
- }
-
- src_data += src_stride;
- dest_data += dest_stride;
- }
+ push_bounding_box (ctx);
}
static void
-convert_no_alpha (guchar *dest_data,
- int dest_stride,
- guchar *src_data,
- int src_stride,
- int src_x,
- int src_y,
- int width,
- int height)
-{
- int x, y;
-
- src_data += src_stride * src_y + src_x * 4;
-
- for (y = 0; y < height; y++) {
- guint32 *src = (guint32 *) src_data;
-
- for (x = 0; x < width; x++) {
- dest_data[x * 3 + 0] = src[x] >> 16;
- dest_data[x * 3 + 1] = src[x] >> 8;
- dest_data[x * 3 + 2] = src[x];
- }
-
- src_data += src_stride;
- dest_data += dest_stride;
- }
-}
-
-GdkPixbuf *
-rsvg_cairo_surface_to_pixbuf (cairo_surface_t *surface)
+pop_bounding_box (RsvgDrawingCtx *ctx)
{
- cairo_content_t content;
- GdkPixbuf *dest;
- int width, height;
+ rsvg_bbox_insert ((RsvgBbox *) ctx->bb_stack->data, &ctx->bbox);
+ rsvg_bbox_insert ((RsvgBbox *) ctx->ink_bb_stack->data, &ctx->ink_bbox);
- /* General sanity checks */
- g_assert (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE);
+ ctx->bbox = *((RsvgBbox *) ctx->bb_stack->data);
+ ctx->ink_bbox = *((RsvgBbox *) ctx->ink_bb_stack->data);
- width = cairo_image_surface_get_width (surface);
- height = cairo_image_surface_get_height (surface);
- if (width == 0 || height == 0)
- return NULL;
+ g_free (ctx->bb_stack->data);
+ g_free (ctx->ink_bb_stack->data);
- content = cairo_surface_get_content (surface) | CAIRO_CONTENT_COLOR;
- dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
- !!(content & CAIRO_CONTENT_ALPHA),
- 8,
- width, height);
-
- if (gdk_pixbuf_get_has_alpha (dest))
- convert_alpha (gdk_pixbuf_get_pixels (dest),
- gdk_pixbuf_get_rowstride (dest),
- cairo_image_surface_get_data (surface),
- cairo_image_surface_get_stride (surface),
- 0, 0,
- width, height);
- else
- convert_no_alpha (gdk_pixbuf_get_pixels (dest),
- gdk_pixbuf_get_rowstride (dest),
- cairo_image_surface_get_data (surface),
- cairo_image_surface_get_stride (surface),
- 0, 0,
- width, height);
-
- return dest;
+ ctx->bb_stack = g_list_delete_link (ctx->bb_stack, ctx->bb_stack);
+ ctx->ink_bb_stack = g_list_delete_link (ctx->ink_bb_stack, ctx->ink_bb_stack);
}
static void
-rsvg_cairo_transformed_image_bounding_box (cairo_matrix_t *affine,
- double width, double height,
- double *x0, double *y0, double *x1, double *y1)
+rsvg_drawing_ctx_pop_render_stack (RsvgDrawingCtx * ctx)
{
- double x00 = 0, x01 = 0, x10 = width, x11 = width;
- double y00 = 0, y01 = height, y10 = 0, y11 = height;
- double t;
-
- /* transform the four corners of the image */
- cairo_matrix_transform_point (affine, &x00, &y00);
- cairo_matrix_transform_point (affine, &x01, &y01);
- cairo_matrix_transform_point (affine, &x10, &y10);
- cairo_matrix_transform_point (affine, &x11, &y11);
-
- /* find minimum and maximum coordinates */
- t = x00 < x01 ? x00 : x01;
- t = t < x10 ? t : x10;
- *x0 = floor (t < x11 ? t : x11);
-
- t = y00 < y01 ? y00 : y01;
- t = t < y10 ? t : y10;
- *y0 = floor (t < y11 ? t : y11);
-
- t = x00 > x01 ? x00 : x01;
- t = t > x10 ? t : x10;
- *x1 = ceil (t > x11 ? t : x11);
-
- t = y00 > y01 ? y00 : y01;
- t = t > y10 ? t : y10;
- *y1 = ceil (t > y11 ? t : y11);
-}
-
-RsvgDrawingCtx *
-rsvg_drawing_ctx_new (cairo_t *cr, RsvgHandle *handle)
-{
- RsvgDimensionData data;
- RsvgDrawingCtx *draw;
RsvgState *state;
- cairo_matrix_t affine;
- cairo_matrix_t state_affine;
- double bbx0, bby0, bbx1, bby1;
-
- rsvg_handle_get_dimensions (handle, &data);
- if (data.width == 0 || data.height == 0)
- return NULL;
-
- draw = g_new0 (RsvgDrawingCtx, 1);
+ char *clip_path;
+ char *filter;
+ char *mask;
+ guint8 opacity;
+ cairo_operator_t comp_op;
+ RsvgEnableBackgroundType enable_background;
+ cairo_t *child_cr = ctx->cr;
+ RsvgNode *lateclip = NULL;
+ cairo_surface_t *surface = NULL;
+ gboolean needs_destroy = FALSE;
+ double offset_x = 0, offset_y = 0;
- cairo_get_matrix (cr, &affine);
+ state = rsvg_drawing_ctx_get_current_state (ctx);
+ clip_path = rsvg_state_get_clip_path (state);
+ filter = rsvg_state_get_filter (state);
+ mask = rsvg_state_get_mask (state);
+ opacity = rsvg_state_get_opacity (state);
+ comp_op = rsvg_state_get_comp_op (state);
+ enable_background = rsvg_state_get_enable_background (state);
- /* find bounding box of image as transformed by the current cairo context
- * The size of this bounding box determines the size of the intermediate
- * surfaces allocated during drawing. */
- rsvg_cairo_transformed_image_bounding_box (&affine,
- data.width, data.height,
- &bbx0, &bby0, &bbx1, &bby1);
+ if (clip_path) {
+ RsvgNode *node;
- draw->initial_cr = cr;
- draw->cr = cr;
- draw->cr_stack = NULL;
- draw->surfaces_stack = NULL;
+ node = rsvg_drawing_ctx_acquire_node_of_type (ctx, clip_path, RSVG_NODE_TYPE_CLIP_PATH);
+ if (node) {
+ if (rsvg_node_clip_path_get_units (node) == objectBoundingBox) {
+ lateclip = node;
+ } else {
+ rsvg_drawing_ctx_release_node (ctx, node);
+ }
+ }
- draw->offset_x = bbx0;
- draw->offset_y = bby0;
- draw->width = bbx1 - bbx0;
- draw->height = bby1 - bby0;
+ g_free (clip_path);
+ }
- draw->state = NULL;
+ if (opacity == 0xFF
+ && !filter && !mask && !lateclip && (comp_op == CAIRO_OPERATOR_OVER)
+ && (enable_background == RSVG_ENABLE_BACKGROUND_ACCUMULATE))
+ return;
- draw->defs = handle->priv->defs;
- draw->dpi_x = handle->priv->dpi_x;
- draw->dpi_y = handle->priv->dpi_y;
- draw->vb.rect.width = data.em;
- draw->vb.rect.height = data.ex;
- draw->vb_stack = NULL;
- draw->drawsub_stack = NULL;
- draw->acquired_nodes = NULL;
- draw->is_testing = handle->priv->is_testing;
+ surface = cairo_get_target (child_cr);
- rsvg_drawing_ctx_state_push (draw);
- state = rsvg_drawing_ctx_get_current_state (draw);
+ if (filter) {
+ RsvgNode *node;
+ cairo_surface_t *output;
- state_affine = rsvg_state_get_affine (state);
+ output = ctx->surfaces_stack->data;
+ ctx->surfaces_stack = g_list_delete_link (ctx->surfaces_stack, ctx->surfaces_stack);
- /* apply cairo transformation to our affine transform */
- cairo_matrix_multiply (&state_affine, &affine, &state_affine);
+ node = rsvg_drawing_ctx_acquire_node_of_type (ctx, filter, RSVG_NODE_TYPE_FILTER);
+ if (node) {
+ needs_destroy = TRUE;
+ surface = rsvg_filter_render (node, output, ctx, "2103");
+ rsvg_drawing_ctx_release_node (ctx, node);
- /* scale according to size set by size_func callback */
- cairo_matrix_init_scale (&affine, data.width / data.em, data.height / data.ex);
- cairo_matrix_multiply (&state_affine, &affine, &state_affine);
+ /* Don't destroy the output surface, it's owned by child_cr */
+ }
- /* adjust transform so that the corner of the bounding box above is
- * at (0,0) - we compensate for this in _set_rsvg_affine() in
- * rsvg-cairo-render.c and a few other places */
- state_affine.x0 -= draw->offset_x;
- state_affine.y0 -= draw->offset_y;
+ g_free (filter);
+ }
- rsvg_bbox_init (&draw->bbox, &state_affine);
- rsvg_bbox_init (&draw->ink_bbox, &state_affine);
+ ctx->cr = (cairo_t *) ctx->cr_stack->data;
+ ctx->cr_stack = g_list_delete_link (ctx->cr_stack, ctx->cr_stack);
- rsvg_state_set_affine (state, state_affine);
+ if (ctx->cr == ctx->initial_cr) {
+ rsvg_drawing_ctx_get_offset (ctx, &offset_x, &offset_y);
+ }
-#ifdef HAVE_PANGOFT2
- draw->font_config_for_testing = NULL;
- draw->font_map_for_testing = NULL;
-#endif
+ cairo_identity_matrix (ctx->cr);
+ cairo_set_source_surface (ctx->cr, surface, offset_x, offset_y);
- return draw;
-}
+ if (lateclip) {
+ rsvg_cairo_clip (ctx, lateclip, &ctx->bbox);
+ rsvg_drawing_ctx_release_node (ctx, lateclip);
+ }
-void
-rsvg_drawing_ctx_free (RsvgDrawingCtx *ctx)
-{
- g_assert (ctx->cr_stack == NULL);
- g_assert (ctx->surfaces_stack == NULL);
+ cairo_set_operator (ctx->cr, comp_op);
- g_assert(ctx->state);
- g_assert(rsvg_state_parent(ctx->state) == NULL);
- rsvg_state_free (ctx->state);
+ if (mask) {
+ RsvgNode *node;
- g_slist_free_full (ctx->drawsub_stack, (GDestroyNotify) rsvg_node_unref);
+ node = rsvg_drawing_ctx_acquire_node_of_type (ctx, mask, RSVG_NODE_TYPE_MASK);
+ if (node) {
+ rsvg_cairo_generate_mask (ctx->cr, node, ctx);
+ rsvg_drawing_ctx_release_node (ctx, node);
+ }
- g_warn_if_fail (ctx->acquired_nodes == NULL);
- g_slist_free (ctx->acquired_nodes);
+ g_free (mask);
+ } else if (opacity != 0xFF)
+ cairo_paint_with_alpha (ctx->cr, (double) opacity / 255.0);
+ else
+ cairo_paint (ctx->cr);
- g_assert (ctx->bb_stack == NULL);
- g_assert (ctx->ink_bb_stack == NULL);
+ cairo_destroy (child_cr);
-#ifdef HAVE_PANGOFT2
- if (ctx->font_config_for_testing) {
- FcConfigDestroy (ctx->font_config_for_testing);
- ctx->font_config_for_testing = NULL;
- }
+ pop_bounding_box (ctx);
- if (ctx->font_map_for_testing) {
- g_object_unref (ctx->font_map_for_testing);
- ctx->font_map_for_testing = NULL;
+ if (needs_destroy) {
+ cairo_surface_destroy (surface);
}
-#endif
-
- g_free (ctx);
}
-RsvgState *
-rsvg_drawing_ctx_get_current_state (RsvgDrawingCtx *ctx)
+void
+rsvg_drawing_ctx_push_discrete_layer (RsvgDrawingCtx *ctx, gboolean clipping)
{
- return ctx->state;
+ if (!clipping) {
+ cairo_save (ctx->cr);
+ rsvg_drawing_ctx_push_render_stack (ctx);
+ }
}
void
-rsvg_drawing_ctx_set_current_state (RsvgDrawingCtx *ctx, RsvgState *state)
+rsvg_drawing_ctx_pop_discrete_layer (RsvgDrawingCtx *ctx, gboolean clipping)
{
- ctx->state = state;
+ if (!clipping) {
+ rsvg_drawing_ctx_pop_render_stack (ctx);
+ cairo_restore (ctx->cr);
+ }
}
/*
@@ -1234,3 +894,139 @@ rsvg_drawing_ctx_get_dpi (RsvgDrawingCtx *ctx, double *out_dpi_x, double *out_dp
if (out_dpi_y)
*out_dpi_y = ctx->dpi_y;
}
+
+#ifdef HAVE_PANGOFT2
+static cairo_font_options_t *
+get_font_options_for_testing (void)
+{
+ cairo_font_options_t *options;
+
+ options = cairo_font_options_create ();
+ cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
+ cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_FULL);
+ cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
+
+ return options;
+}
+
+static void
+set_font_options_for_testing (PangoContext *context)
+{
+ cairo_font_options_t *font_options;
+
+ font_options = get_font_options_for_testing ();
+ pango_cairo_context_set_font_options (context, font_options);
+ cairo_font_options_destroy (font_options);
+}
+
+static void
+create_font_config_for_testing (RsvgDrawingCtx *ctx)
+{
+ const char *font_paths[] = {
+ SRCDIR "/tests/resources/Roboto-Regular.ttf",
+ SRCDIR "/tests/resources/Roboto-Italic.ttf",
+ SRCDIR "/tests/resources/Roboto-Bold.ttf",
+ SRCDIR "/tests/resources/Roboto-BoldItalic.ttf",
+ };
+
+ int i;
+
+ if (ctx->font_config_for_testing != NULL)
+ return;
+
+ ctx->font_config_for_testing = FcConfigCreate ();
+
+ for (i = 0; i < G_N_ELEMENTS(font_paths); i++) {
+ if (!FcConfigAppFontAddFile (ctx->font_config_for_testing, (const FcChar8 *) font_paths[i])) {
+ g_error ("Could not load font file \"%s\" for tests; aborting", font_paths[i]);
+ }
+ }
+}
+
+static PangoFontMap *
+get_font_map_for_testing (RsvgDrawingCtx *ctx)
+{
+ create_font_config_for_testing (ctx);
+
+ if (ctx->font_map_for_testing == NULL) {
+ ctx->font_map_for_testing = pango_cairo_font_map_new_for_font_type (CAIRO_FONT_TYPE_FT);
+ pango_fc_font_map_set_config (PANGO_FC_FONT_MAP (ctx->font_map_for_testing),
+ ctx->font_config_for_testing);
+ }
+
+ return ctx->font_map_for_testing;
+}
+#endif
+
+PangoContext *
+rsvg_drawing_ctx_get_pango_context (RsvgDrawingCtx * ctx)
+{
+ PangoFontMap *fontmap;
+ PangoContext *context;
+ double dpi_y;
+
+#ifdef HAVE_PANGOFT2
+ if (ctx->is_testing) {
+ fontmap = get_font_map_for_testing (ctx);
+ } else {
+#endif
+ fontmap = pango_cairo_font_map_get_default ();
+#ifdef HAVE_PANGOFT2
+ }
+#endif
+
+ context = pango_font_map_create_context (fontmap);
+ pango_cairo_update_context (ctx->cr, context);
+
+ rsvg_drawing_ctx_get_dpi (ctx, NULL, &dpi_y);
+ pango_cairo_context_set_resolution (context, dpi_y);
+
+#ifdef HAVE_PANGOFT2
+ if (ctx->is_testing) {
+ set_font_options_for_testing (context);
+ }
+#endif
+
+ return context;
+}
+
+cairo_surface_t *
+rsvg_drawing_ctx_get_surface_of_node (RsvgDrawingCtx *ctx,
+ RsvgNode *drawable,
+ double width,
+ double height)
+{
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ cairo_t *save_cr = ctx->cr;
+ cairo_t *save_initial_cr = ctx->initial_cr;
+ double save_x = ctx->offset_x;
+ double save_y = ctx->offset_y;
+ double save_w = ctx->width;
+ double save_h = ctx->height;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
+ cairo_surface_destroy (surface);
+ return NULL;
+ }
+
+ ctx->cr = cairo_create (surface);
+ ctx->initial_cr = ctx->cr;
+ ctx->offset_x = 0;
+ ctx->offset_y = 0;
+ ctx->width = width;
+ ctx->height = height;
+
+ rsvg_drawing_ctx_draw_node_from_stack (ctx, drawable, 0, FALSE);
+
+ cairo_destroy (ctx->cr);
+ ctx->cr = save_cr;
+ ctx->initial_cr = save_initial_cr;
+ ctx->offset_x = save_x;
+ ctx->offset_y = save_y;
+ ctx->width = save_w;
+ ctx->height = save_h;
+
+ return surface;
+}
diff --git a/librsvg/rsvg-drawing-ctx.h b/librsvg/rsvg-drawing-ctx.h
index 843d2c31..c9735df6 100644
--- a/librsvg/rsvg-drawing-ctx.h
+++ b/librsvg/rsvg-drawing-ctx.h
@@ -61,15 +61,18 @@ struct RsvgDrawingCtx {
};
G_GNUC_INTERNAL
-void rsvg_pop_discrete_layer (RsvgDrawingCtx *ctx, gboolean clipping);
+RsvgDrawingCtx *rsvg_drawing_ctx_new (cairo_t *cr, RsvgHandle *handle);
+
G_GNUC_INTERNAL
-void rsvg_push_discrete_layer (RsvgDrawingCtx *ctx, gboolean clipping);
+void rsvg_drawing_ctx_free (RsvgDrawingCtx *draw_ctx);
G_GNUC_INTERNAL
-RsvgDrawingCtx *rsvg_drawing_ctx_new (cairo_t *cr, RsvgHandle *handle);
+cairo_t *rsvg_drawing_ctx_get_cairo_context (RsvgDrawingCtx *ctx);
+G_GNUC_INTERNAL
+void rsvg_drawing_ctx_set_cairo_context (RsvgDrawingCtx *ctx, cairo_t *cr);
G_GNUC_INTERNAL
-void rsvg_drawing_ctx_free (RsvgDrawingCtx *draw_ctx);
+gboolean rsvg_drawing_ctx_is_cairo_context_nested (RsvgDrawingCtx *ctx, cairo_t *cr);
G_GNUC_INTERNAL
RsvgState *rsvg_drawing_ctx_get_current_state (RsvgDrawingCtx * ctx);
@@ -117,24 +120,18 @@ G_GNUC_INTERNAL
void rsvg_drawing_ctx_get_dpi (RsvgDrawingCtx *ctx, double *out_dpi_x, double *out_dpi_y);
G_GNUC_INTERNAL
-PangoContext *rsvg_cairo_get_pango_context (RsvgDrawingCtx *ctx);
-
-G_GNUC_INTERNAL
-cairo_t *rsvg_cairo_get_cairo_context (RsvgDrawingCtx *ctx);
-G_GNUC_INTERNAL
-void rsvg_cairo_set_cairo_context (RsvgDrawingCtx *ctx, cairo_t *cr);
-
-G_GNUC_INTERNAL
-gboolean rsvg_cairo_is_cairo_context_nested (RsvgDrawingCtx *ctx, cairo_t *cr);
+PangoContext *rsvg_drawing_ctx_get_pango_context (RsvgDrawingCtx *ctx);
G_GNUC_INTERNAL
-void rsvg_cairo_push_discrete_layer (RsvgDrawingCtx *ctx, gboolean clipping);
+void rsvg_drawing_ctx_push_discrete_layer (RsvgDrawingCtx *ctx, gboolean clipping);
G_GNUC_INTERNAL
-void rsvg_cairo_pop_discrete_layer (RsvgDrawingCtx *ctx, gboolean clipping);
+void rsvg_drawing_ctx_pop_discrete_layer (RsvgDrawingCtx *ctx, gboolean clipping);
G_GNUC_INTERNAL
-cairo_surface_t*rsvg_cairo_get_surface_of_node (RsvgDrawingCtx *ctx, RsvgNode *drawable,
- double width, double height);
+cairo_surface_t *rsvg_drawing_ctx_get_surface_of_node (RsvgDrawingCtx *ctx,
+ RsvgNode *drawable,
+ double width,
+ double height);
G_END_DECLS
diff --git a/librsvg/rsvg-file-util.c b/librsvg/rsvg-file-util.c
index c8de90c6..47eeec58 100644
--- a/librsvg/rsvg-file-util.c
+++ b/librsvg/rsvg-file-util.c
@@ -298,3 +298,207 @@ rsvg_pixbuf_from_file_at_max_size (const gchar * file_name,
return rsvg_pixbuf_from_file_with_size_data (file_name, &data, error);
}
+
+cairo_surface_t *
+rsvg_cairo_surface_from_pixbuf (const GdkPixbuf *pixbuf)
+{
+ gint width, height, gdk_rowstride, n_channels, cairo_rowstride;
+ guchar *gdk_pixels, *cairo_pixels;
+ cairo_format_t format;
+ cairo_surface_t *surface;
+ int j;
+
+ if (pixbuf == NULL)
+ return NULL;
+
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+ gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
+ gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+
+ if (n_channels == 3)
+ format = CAIRO_FORMAT_RGB24;
+ else
+ format = CAIRO_FORMAT_ARGB32;
+
+ surface = cairo_image_surface_create (format, width, height);
+ if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
+ cairo_surface_destroy (surface);
+ return NULL;
+ }
+
+ cairo_pixels = cairo_image_surface_get_data (surface);
+ cairo_rowstride = cairo_image_surface_get_stride (surface);
+
+ if (n_channels == 3) {
+ for (j = height; j; j--) {
+ guchar *p = gdk_pixels;
+ guchar *q = cairo_pixels;
+ guchar *end = p + 3 * width;
+
+ while (p < end) {
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ q[0] = p[2];
+ q[1] = p[1];
+ q[2] = p[0];
+#else
+ q[1] = p[0];
+ q[2] = p[1];
+ q[3] = p[2];
+#endif
+ p += 3;
+ q += 4;
+ }
+
+ gdk_pixels += gdk_rowstride;
+ cairo_pixels += cairo_rowstride;
+ }
+ } else {
+ for (j = height; j; j--) {
+ guchar *p = gdk_pixels;
+ guchar *q = cairo_pixels;
+ guchar *end = p + 4 * width;
+ guint t1, t2, t3;
+
+#define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
+
+ while (p < end) {
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ MULT (q[0], p[2], p[3], t1);
+ MULT (q[1], p[1], p[3], t2);
+ MULT (q[2], p[0], p[3], t3);
+ q[3] = p[3];
+#else
+ q[0] = p[3];
+ MULT (q[1], p[0], p[3], t1);
+ MULT (q[2], p[1], p[3], t2);
+ MULT (q[3], p[2], p[3], t3);
+#endif
+
+ p += 4;
+ q += 4;
+ }
+
+#undef MULT
+ gdk_pixels += gdk_rowstride;
+ cairo_pixels += cairo_rowstride;
+ }
+ }
+
+ cairo_surface_mark_dirty (surface);
+ return surface;
+}
+
+/* Copied from gtk+/gdk/gdkpixbuf-drawable.c, LGPL 2+.
+ *
+ * Copyright (C) 1999 Michael Zucchi
+ *
+ * Authors: Michael Zucchi <zucchi zedzone mmc com au>
+ * Cody Russell <bratsche dfw net>
+ * Federico Mena-Quintero <federico gimp org>
+ */
+
+static void
+convert_alpha (guchar *dest_data,
+ int dest_stride,
+ guchar *src_data,
+ int src_stride,
+ int src_x,
+ int src_y,
+ int width,
+ int height)
+{
+ int x, y;
+
+ src_data += src_stride * src_y + src_x * 4;
+
+ for (y = 0; y < height; y++) {
+ guint32 *src = (guint32 *) src_data;
+
+ for (x = 0; x < width; x++) {
+ guint alpha = src[x] >> 24;
+
+ if (alpha == 0) {
+ dest_data[x * 4 + 0] = 0;
+ dest_data[x * 4 + 1] = 0;
+ dest_data[x * 4 + 2] = 0;
+ } else {
+ dest_data[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
+ dest_data[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
+ dest_data[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
+ }
+ dest_data[x * 4 + 3] = alpha;
+ }
+
+ src_data += src_stride;
+ dest_data += dest_stride;
+ }
+}
+
+static void
+convert_no_alpha (guchar *dest_data,
+ int dest_stride,
+ guchar *src_data,
+ int src_stride,
+ int src_x,
+ int src_y,
+ int width,
+ int height)
+{
+ int x, y;
+
+ src_data += src_stride * src_y + src_x * 4;
+
+ for (y = 0; y < height; y++) {
+ guint32 *src = (guint32 *) src_data;
+
+ for (x = 0; x < width; x++) {
+ dest_data[x * 3 + 0] = src[x] >> 16;
+ dest_data[x * 3 + 1] = src[x] >> 8;
+ dest_data[x * 3 + 2] = src[x];
+ }
+
+ src_data += src_stride;
+ dest_data += dest_stride;
+ }
+}
+
+GdkPixbuf *
+rsvg_cairo_surface_to_pixbuf (cairo_surface_t *surface)
+{
+ cairo_content_t content;
+ GdkPixbuf *dest;
+ int width, height;
+
+ /* General sanity checks */
+ g_assert (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+ width = cairo_image_surface_get_width (surface);
+ height = cairo_image_surface_get_height (surface);
+ if (width == 0 || height == 0)
+ return NULL;
+
+ content = cairo_surface_get_content (surface) | CAIRO_CONTENT_COLOR;
+ dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+ !!(content & CAIRO_CONTENT_ALPHA),
+ 8,
+ width, height);
+
+ if (gdk_pixbuf_get_has_alpha (dest))
+ convert_alpha (gdk_pixbuf_get_pixels (dest),
+ gdk_pixbuf_get_rowstride (dest),
+ cairo_image_surface_get_data (surface),
+ cairo_image_surface_get_stride (surface),
+ 0, 0,
+ width, height);
+ else
+ convert_no_alpha (gdk_pixbuf_get_pixels (dest),
+ gdk_pixbuf_get_rowstride (dest),
+ cairo_image_surface_get_data (surface),
+ cairo_image_surface_get_stride (surface),
+ 0, 0,
+ width, height);
+
+ return dest;
+}
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index f0478ac8..f266a0dd 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -20,6 +20,20 @@ extern "C" {
fn rsvg_drawing_ctx_get_current_state(draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState;
fn rsvg_drawing_ctx_set_current_state(draw_ctx: *mut RsvgDrawingCtx, state: *mut RsvgState);
+ fn rsvg_drawing_ctx_get_cairo_context(
+ draw_ctx: *const RsvgDrawingCtx,
+ ) -> *mut cairo_sys::cairo_t;
+
+ fn rsvg_drawing_ctx_set_cairo_context(
+ draw_ctx: *const RsvgDrawingCtx,
+ cr: *const cairo_sys::cairo_t,
+ );
+
+ fn rsvg_drawing_ctx_is_cairo_context_nested(
+ draw_ctx: *const RsvgDrawingCtx,
+ cr: *const cairo_sys::cairo_t,
+ ) -> glib_sys::gboolean;
+
fn rsvg_drawing_ctx_get_dpi(
draw_ctx: *const RsvgDrawingCtx,
out_dpi_x: *mut f64,
@@ -65,20 +79,42 @@ extern "C" {
clipping: glib_sys::gboolean,
);
- fn rsvg_push_discrete_layer(draw_ctx: *const RsvgDrawingCtx, clipping: glib_sys::gboolean);
- fn rsvg_pop_discrete_layer(draw_ctx: *const RsvgDrawingCtx, clipping: glib_sys::gboolean);
-
- fn rsvg_cairo_get_cairo_context(draw_ctx: *const RsvgDrawingCtx) -> *mut cairo_sys::cairo_t;
- fn rsvg_cairo_set_cairo_context(draw_ctx: *const RsvgDrawingCtx, cr: *const cairo_sys::cairo_t);
-
- fn rsvg_cairo_is_cairo_context_nested(
+ fn rsvg_drawing_ctx_get_pango_context(
draw_ctx: *const RsvgDrawingCtx,
- cr: *const cairo_sys::cairo_t,
- ) -> glib_sys::gboolean;
+ ) -> *mut pango_sys::PangoContext;
- fn rsvg_cairo_get_pango_context(
+ fn rsvg_drawing_ctx_push_discrete_layer(
draw_ctx: *const RsvgDrawingCtx,
- ) -> *mut pango_sys::PangoContext;
+ clipping: glib_sys::gboolean
+ );
+ fn rsvg_drawing_ctx_pop_discrete_layer(
+ draw_ctx: *const RsvgDrawingCtx,
+ clipping: glib_sys::gboolean
+ );
+}
+
+pub fn get_cairo_context(draw_ctx: *const RsvgDrawingCtx) -> cairo::Context {
+ unsafe {
+ let raw_cr = rsvg_drawing_ctx_get_cairo_context(draw_ctx);
+
+ cairo::Context::from_glib_none(raw_cr)
+ }
+}
+
+pub fn set_cairo_context(draw_ctx: *const RsvgDrawingCtx, cr: &cairo::Context) {
+ unsafe {
+ let raw_cr = cr.to_glib_none().0;
+
+ rsvg_drawing_ctx_set_cairo_context(draw_ctx, raw_cr);
+ }
+}
+
+pub fn is_cairo_context_nested(draw_ctx: *const RsvgDrawingCtx, cr: &cairo::Context) -> bool {
+ unsafe {
+ let raw_cr = cr.to_glib_none().0;
+
+ from_glib(rsvg_drawing_ctx_is_cairo_context_nested(draw_ctx, raw_cr))
+ }
}
pub fn get_dpi(draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
@@ -225,37 +261,13 @@ pub fn state_reinherit_top(draw_ctx: *const RsvgDrawingCtx, state: &State, domin
pub fn push_discrete_layer(draw_ctx: *const RsvgDrawingCtx, clipping: bool) {
unsafe {
- rsvg_push_discrete_layer(draw_ctx, clipping.to_glib());
+ rsvg_drawing_ctx_push_discrete_layer(draw_ctx, clipping.to_glib());
}
}
pub fn pop_discrete_layer(draw_ctx: *const RsvgDrawingCtx, clipping: bool) {
unsafe {
- rsvg_pop_discrete_layer(draw_ctx, clipping.to_glib());
- }
-}
-
-pub fn get_cairo_context(draw_ctx: *const RsvgDrawingCtx) -> cairo::Context {
- unsafe {
- let raw_cr = rsvg_cairo_get_cairo_context(draw_ctx);
-
- cairo::Context::from_glib_none(raw_cr)
- }
-}
-
-pub fn set_cairo_context(draw_ctx: *const RsvgDrawingCtx, cr: &cairo::Context) {
- unsafe {
- let raw_cr = cr.to_glib_none().0;
-
- rsvg_cairo_set_cairo_context(draw_ctx, raw_cr);
- }
-}
-
-pub fn is_cairo_context_nested(draw_ctx: *const RsvgDrawingCtx, cr: &cairo::Context) -> bool {
- unsafe {
- let raw_cr = cr.to_glib_none().0;
-
- from_glib(rsvg_cairo_is_cairo_context_nested(draw_ctx, raw_cr))
+ rsvg_drawing_ctx_pop_discrete_layer(draw_ctx, clipping.to_glib());
}
}
@@ -271,7 +283,7 @@ pub fn get_offset(draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
}
pub fn get_pango_context(draw_ctx: *const RsvgDrawingCtx) -> pango::Context {
- unsafe { from_glib_full(rsvg_cairo_get_pango_context(draw_ctx)) }
+ unsafe { from_glib_full(rsvg_drawing_ctx_get_pango_context(draw_ctx)) }
}
pub fn insert_bbox(draw_ctx: *const RsvgDrawingCtx, bbox: &RsvgBbox) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]