[librsvg] rsvg: Add rsvg_acquire_node()



commit a51919f7e1ca9c535390a746fbf6e28c8402dc61
Author: Benjamin Otte <otte redhat com>
Date:   Wed Oct 7 08:45:37 2015 +0200

    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.

 rsvg-base.c         |   55 +++++++++++++++++++++++++++++++++++++++++++++++++++
 rsvg-cairo-draw.c   |   15 ++++++++++---
 rsvg-cairo-render.c |    1 +
 rsvg-filter.c       |    9 ++++++-
 rsvg-private.h      |    5 ++++
 5 files changed, 79 insertions(+), 6 deletions(-)
---
diff --git a/rsvg-base.c b/rsvg-base.c
index be170ab..17cbb02 100644
--- a/rsvg-base.c
+++ b/rsvg-base.c
@@ -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)
 {
diff --git a/rsvg-cairo-draw.c b/rsvg-cairo-draw.c
index 816235c..a8aea82 100644
--- a/rsvg-cairo-draw.c
+++ b/rsvg-cairo-draw.c
@@ -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
diff --git a/rsvg-cairo-render.c b/rsvg-cairo-render.c
index 0d51dde..0dd1162 100644
--- a/rsvg-cairo-render.c
+++ b/rsvg-cairo-render.c
@@ -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);
diff --git a/rsvg-filter.c b/rsvg-filter.c
index b4eedec..a8f6a27 100644
--- a/rsvg-filter.c
+++ b/rsvg-filter.c
@@ -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 *
diff --git a/rsvg-private.h b/rsvg-private.h
index 651e2f6..fd1c1c4 100644
--- a/rsvg-private.h
+++ b/rsvg-private.h
@@ -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,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]