[librsvg/librsvg-2.46] Make <use> always acquire itself, to catch circular references
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg/librsvg-2.46] Make <use> always acquire itself, to catch circular references
- Date: Tue, 15 Oct 2019 16:48:04 +0000 (UTC)
commit fcbf452059f5b229ba20031cec79a50eddeb20c6
Author: Federico Mena Quintero <federico gnome org>
Date: Tue Oct 15 10:14:17 2019 -0500
Make <use> always acquire itself, to catch circular references
rsvg_internals/src/drawing_ctx.rs | 53 +++++++++++++++++----------------------
rsvg_internals/src/structure.rs | 21 ++++++++++++----
2 files changed, 39 insertions(+), 35 deletions(-)
---
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index ecb33de9..d8b24cc3 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -339,7 +339,7 @@ impl DrawingCtx {
pub fn acquire_node(
&mut self,
fragment: &Fragment,
- node_types: &[NodeType]
+ node_types: &[NodeType],
) -> Result<AcquiredNode, AcquireError> {
self.num_elements_acquired += 1;
@@ -350,15 +350,17 @@ impl DrawingCtx {
self.acquired_nodes.acquire(fragment, node_types)
}
+ pub fn acquire_node_ref(&mut self, node: &RsvgNode) -> Result<AcquiredNode, AcquireError> {
+ self.acquired_nodes.push_node_ref(node)
+ }
+
// Returns (clip_in_user_space, clip_in_object_space), both Option<RsvgNode>
fn get_clip_in_user_and_object_space(
&mut self,
clip_uri: Option<&Fragment>,
) -> (Option<RsvgNode>, Option<RsvgNode>) {
clip_uri
- .and_then(|fragment| {
- self.acquire_node(fragment, &[NodeType::ClipPath]).ok()
- })
+ .and_then(|fragment| self.acquire_node(fragment, &[NodeType::ClipPath]).ok())
.and_then(|acquired| {
let clip_node = acquired.get().clone();
@@ -486,8 +488,7 @@ impl DrawingCtx {
// Mask
if let Some(fragment) = mask {
- if let Ok(acquired) = dc.acquire_node(fragment, &[NodeType::Mask])
- {
+ if let Ok(acquired) = dc.acquire_node(fragment, &[NodeType::Mask]) {
let mask_node = acquired.get();
res = res.and_then(|bbox| {
@@ -567,8 +568,7 @@ impl DrawingCtx {
child_surface: &cairo::ImageSurface,
node_bbox: BoundingBox,
) -> Result<cairo::ImageSurface, RenderingError> {
- match self.acquire_node(filter_uri, &[NodeType::Filter])
- {
+ match self.acquire_node(filter_uri, &[NodeType::Filter]) {
Ok(acquired) => {
let filter_node = acquired.get();
@@ -736,12 +736,7 @@ impl DrawingCtx {
let current_color = values.color.0;
let res = self
- .set_source_paint_server(
- &values.fill.0,
- values.fill_opacity.0,
- &bbox,
- current_color
- )
+ .set_source_paint_server(&values.fill.0, values.fill_opacity.0, &bbox, current_color)
.and_then(|had_paint_server| {
if had_paint_server {
if values.stroke.0 == PaintServer::None {
@@ -1139,15 +1134,7 @@ impl AcquiredNodes {
let node = self.lookup_node(fragment, node_types)?;
if node_is_accessed_by_reference(&node) {
- if self.node_stack.borrow().contains(&node) {
- Err(AcquireError::CircularReference(node.clone()))
- } else {
- self.node_stack.borrow_mut().push(&node);
- Ok(AcquiredNode {
- stack: Some(self.node_stack.clone()),
- node: node.clone()
- })
- }
+ self.push_node_ref(&node)
} else {
Ok(AcquiredNode {
stack: None,
@@ -1155,6 +1142,18 @@ impl AcquiredNodes {
})
}
}
+
+ fn push_node_ref(&self, node: &RsvgNode) -> Result<AcquiredNode, AcquireError> {
+ if self.node_stack.borrow().contains(&node) {
+ Err(AcquireError::CircularReference(node.clone()))
+ } else {
+ self.node_stack.borrow_mut().push(&node);
+ Ok(AcquiredNode {
+ stack: Some(self.node_stack.clone()),
+ node: node.clone(),
+ })
+ }
+ }
}
// Returns whether a node of a particular type is only accessed by reference
@@ -1164,13 +1163,7 @@ fn node_is_accessed_by_reference(node: &RsvgNode) -> bool {
use NodeType::*;
match node.borrow().get_type() {
- ClipPath |
- Filter |
- LinearGradient |
- Marker |
- Mask |
- Pattern |
- RadialGradient => true,
+ ClipPath | Filter | LinearGradient | Marker | Mask | Pattern | RadialGradient => true,
_ => false,
}
diff --git a/rsvg_internals/src/structure.rs b/rsvg_internals/src/structure.rs
index 773d1dff..b8c59ca1 100644
--- a/rsvg_internals/src/structure.rs
+++ b/rsvg_internals/src/structure.rs
@@ -313,6 +313,22 @@ impl NodeTrait for NodeUse {
let link = self.link.as_ref().unwrap();
+ // <use> is an element that is used directly, unlike
+ // <pattern>, which is used through a fill="url(#...)"
+ // reference. However, <use> will always reference another
+ // element, potentially itself or an ancestor of itself (or
+ // another <use> which references the first one, etc.). So,
+ // we acquire the <use> element itself so that circular
+ // references can be caught.
+ let _self_acquired = draw_ctx.acquire_node_ref(node).map_err(|e| {
+ if let AcquireError::CircularReference(_) = e {
+ rsvg_log!("circular reference in element {}", node);
+ RenderingError::CircularReference
+ } else {
+ unreachable!();
+ }
+ })?;
+
let acquired = match draw_ctx.acquire_node(link, &[]) {
Ok(acquired) => acquired,
@@ -335,11 +351,6 @@ impl NodeTrait for NodeUse {
let child = acquired.get();
- if node.ancestors().any(|ancestor| ancestor == *child) {
- // or, if we're <use>'ing ourselves
- return Err(RenderingError::CircularReference);
- }
-
let params = draw_ctx.get_view_params();
let nx = self.x.normalize(values, ¶ms);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]