Commit a51919f7 authored by Benjamin Otte's avatar Benjamin Otte

rsvg: Add rsvg_acquire_node()

This function does proper recursion checks when looking up resources
from URLs and thereby helps avoiding infinite loops when cyclic
references span multiple types of elements.
parent 6cfaab12
......@@ -1236,6 +1236,8 @@ rsvg_drawing_ctx_free (RsvgDrawingCtx * handle)
g_slist_free (handle->drawsub_stack);
g_slist_free (handle->ptrs);
g_warn_if_fail (handle->acquired_nodes == NULL);
g_slist_free (handle->acquired_nodes);
if (handle->base_uri)
g_free (handle->base_uri);
......@@ -2018,6 +2020,59 @@ rsvg_push_discrete_layer (RsvgDrawingCtx * ctx)
ctx->render->push_discrete_layer (ctx);
}
/*
* rsvg_acquire_node:
* @ctx: The drawing context in use
* @url: The IRI to lookup
*
* Use this function when looking up urls to other nodes. This
* function does proper recursion checking and thereby avoids
* infinite loops.
*
* Nodes acquired by this function must be released using
* rsvg_release_node() in reverse acquiring order.
*
* Returns: The node referenced by @url or %NULL if the @url
* does not reference a node.
*/
RsvgNode *
rsvg_acquire_node (RsvgDrawingCtx * ctx, const char *url)
{
RsvgNode *node;
node = rsvg_defs_lookup (ctx->defs, url);
if (node == NULL)
return NULL;
if (g_slist_find (ctx->acquired_nodes, node))
return NULL;
ctx->acquired_nodes = g_slist_prepend (ctx->acquired_nodes, node);
return node;
}
/*
* rsvg_release_node:
* @ctx: The drawing context the node was acquired from
* @node: Node to release
*
* Releases a node previously acquired via rsvg_acquire_node().
*
* if @node is %NULL, this function does nothing.
*/
void
rsvg_release_node (RsvgDrawingCtx * ctx, RsvgNode *node)
{
if (node == NULL)
return;
g_return_if_fail (ctx->acquired_nodes != NULL);
g_return_if_fail (ctx->acquired_nodes->data == node);
ctx->acquired_nodes = g_slist_remove (ctx->acquired_nodes, node);
}
void
rsvg_render_path (RsvgDrawingCtx * ctx, const cairo_path_t *path)
{
......
......@@ -730,7 +730,7 @@ rsvg_cairo_push_render_stack (RsvgDrawingCtx * ctx)
if (rsvg_current_state (ctx)->clip_path) {
RsvgNode *node;
node = rsvg_defs_lookup (ctx->defs, rsvg_current_state (ctx)->clip_path);
node = rsvg_acquire_node (ctx, rsvg_current_state (ctx)->clip_path);
if (node && RSVG_NODE_TYPE (node) == RSVG_NODE_TYPE_CLIP_PATH) {
RsvgClipPath *clip_path = (RsvgClipPath *) node;
......@@ -748,6 +748,8 @@ rsvg_cairo_push_render_stack (RsvgDrawingCtx * ctx)
}
}
rsvg_release_node (ctx, node);
}
if (state->opacity == 0xFF
......@@ -807,10 +809,12 @@ rsvg_cairo_pop_render_stack (RsvgDrawingCtx * ctx)
if (rsvg_current_state (ctx)->clip_path) {
RsvgNode *node;
node = rsvg_defs_lookup (ctx->defs, rsvg_current_state (ctx)->clip_path);
node = rsvg_acquire_node (ctx, rsvg_current_state (ctx)->clip_path);
if (node && RSVG_NODE_TYPE (node) == RSVG_NODE_TYPE_CLIP_PATH
&& ((RsvgClipPath *) node)->units == objectBoundingBox)
lateclip = (RsvgClipPath *) node;
else
rsvg_release_node (ctx, node);
}
if (state->opacity == 0xFF
......@@ -840,17 +844,20 @@ rsvg_cairo_pop_render_stack (RsvgDrawingCtx * ctx)
nest ? 0 : render->offset_x,
nest ? 0 : render->offset_y);
if (lateclip)
if (lateclip) {
rsvg_cairo_clip (ctx, lateclip, &render->bbox);
rsvg_release_node (ctx, (RsvgNode *) lateclip);
}
cairo_set_operator (render->cr, state->comp_op);
if (state->mask) {
RsvgNode *mask;
mask = rsvg_defs_lookup (ctx->defs, state->mask);
mask = rsvg_acquire_node (ctx, state->mask);
if (mask && RSVG_NODE_TYPE (mask) == RSVG_NODE_TYPE_MASK)
rsvg_cairo_generate_mask (render->cr, (RsvgMask *) mask, ctx, &render->bbox);
rsvg_release_node (ctx, mask);
} else if (state->opacity != 0xFF)
cairo_paint_with_alpha (render->cr, (double) state->opacity / 255.0);
else
......
......@@ -155,6 +155,7 @@ rsvg_cairo_new_drawing_ctx (cairo_t * cr, RsvgHandle * handle)
draw->pango_context = NULL;
draw->drawsub_stack = NULL;
draw->ptrs = NULL;
draw->acquired_nodes = NULL;
rsvg_state_push (draw);
state = rsvg_current_state (draw);
......
......@@ -3928,6 +3928,7 @@ rsvg_filter_primitive_image_render_in (RsvgFilterPrimitive * self, RsvgFilterCon
RsvgDrawingCtx *ctx;
RsvgFilterPrimitiveImage *upself;
RsvgNode *drawable;
cairo_surface_t *result;
ctx = context->ctx;
......@@ -3936,13 +3937,17 @@ rsvg_filter_primitive_image_render_in (RsvgFilterPrimitive * self, RsvgFilterCon
if (!upself->href)
return NULL;
drawable = rsvg_defs_lookup (ctx->defs, upself->href->str);
drawable = rsvg_acquire_node (ctx, upself->href->str);
if (!drawable)
return NULL;
rsvg_current_state (ctx)->affine = context->paffine;
return rsvg_get_surface_of_node (ctx, drawable, context->width, context->height);
result = rsvg_get_surface_of_node (ctx, drawable, context->width, context->height);
rsvg_release_node (ctx, drawable);
return result;
}
static cairo_surface_t *
......
......@@ -200,6 +200,7 @@ struct RsvgDrawingCtx {
GSList *vb_stack;
GSList *drawsub_stack;
GSList *ptrs;
GSList *acquired_nodes;
};
/*Abstract base class for context for our backends (one as yet)*/
......@@ -360,6 +361,10 @@ void rsvg_pop_discrete_layer (RsvgDrawingCtx * ctx);
G_GNUC_INTERNAL
void rsvg_push_discrete_layer (RsvgDrawingCtx * ctx);
G_GNUC_INTERNAL
RsvgNode *rsvg_acquire_node (RsvgDrawingCtx * ctx, const char *url);
G_GNUC_INTERNAL
void rsvg_release_node (RsvgDrawingCtx * ctx, RsvgNode *node);
G_GNUC_INTERNAL
void rsvg_render_path (RsvgDrawingCtx * ctx, const cairo_path_t *path);
G_GNUC_INTERNAL
void rsvg_render_surface (RsvgDrawingCtx * ctx, cairo_surface_t *surface,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment