[librsvg] (#398): Detect circular references in gradients
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] (#398): Detect circular references in gradients
- Date: Wed, 2 Jan 2019 18:07:45 +0000 (UTC)
commit 575a809111b78eea8ee59753360ccecb254da786
Author: Federico Mena Quintero <federico gnome org>
Date: Wed Jan 2 12:05:22 2019 -0600
(#398): Detect circular references in gradients
Similar to pattern.rs, we need to detect cycles in gradient
references.
Fixes https://gitlab.gnome.org/GNOME/librsvg/issues/398
rsvg_internals/src/gradient.rs | 69 ++++++++++++----------
.../infinite-loop/398-recursive-gradient.svg | 5 ++
2 files changed, 42 insertions(+), 32 deletions(-)
---
diff --git a/rsvg_internals/src/gradient.rs b/rsvg_internals/src/gradient.rs
index fb27d524..a045a523 100644
--- a/rsvg_internals/src/gradient.rs
+++ b/rsvg_internals/src/gradient.rs
@@ -7,7 +7,7 @@ use attributes::Attribute;
use bbox::*;
use coord_units::CoordUnits;
use defs::Fragment;
-use drawing_ctx::{AcquiredNode, DrawingCtx};
+use drawing_ctx::{AcquiredNode, DrawingCtx, NodeStack};
use error::*;
use handle::RsvgHandle;
use length::*;
@@ -444,18 +444,20 @@ impl Gradient {
}
}
-fn acquire_gradient<'a>(draw_ctx: &'a mut DrawingCtx, name: &Fragment) -> Option<AcquiredNode> {
- if let Some(acquired) = draw_ctx.get_acquired_node(name) {
- let node_type = acquired.get().get_type();
+fn acquire_gradient<'a>(
+ draw_ctx: &'a mut DrawingCtx,
+ name: Option<&Fragment>,
+) -> Option<AcquiredNode> {
+ name.and_then(move |fragment| draw_ctx.get_acquired_node(fragment))
+ .and_then(|acquired| {
+ let node_type = acquired.get().get_type();
- if node_type == NodeType::LinearGradient || node_type == NodeType::RadialGradient {
- return Some(acquired);
- }
- }
-
- rsvg_log!("element \"{}\" does not exist or is not a gradient", name);
-
- None
+ if node_type == NodeType::LinearGradient || node_type == NodeType::RadialGradient {
+ Some(acquired)
+ } else {
+ None
+ }
+ })
}
fn set_common_on_pattern<P: cairo::PatternTrait + cairo::Gradient>(
@@ -538,30 +540,33 @@ impl PaintSource for NodeGradient {
draw_ctx: &mut DrawingCtx,
bbox: &BoundingBox,
) -> Result<Option<Self::Source>, RenderingError> {
- let gradient =
- node.with_impl(|i: &NodeGradient| i.get_gradient_with_color_stops_from_node(node));
+ let node_gradient = node.get_impl::<NodeGradient>().unwrap();
+ let gradient = node_gradient.get_gradient_with_color_stops_from_node(node);
let mut result = gradient.clone();
+ let mut stack = NodeStack::new();
while !result.is_resolved() {
- result
- .common
- .fallback
- .as_ref()
- .and_then(|fallback_name| acquire_gradient(draw_ctx, fallback_name))
- .and_then(|acquired| {
- let fallback_node = acquired.get();
-
- fallback_node.with_impl(|i: &NodeGradient| {
- let fallback_grad =
- i.get_gradient_with_color_stops_from_node(&fallback_node);
- result.resolve_from_fallback(&fallback_grad)
- });
- Some(())
- })
- .or_else(|| {
- result.resolve_from_defaults();
- Some(())
+ if let Some(acquired) = acquire_gradient(draw_ctx, result.common.fallback.as_ref()) {
+ let a_node = acquired.get();
+
+ if stack.contains(a_node) {
+ rsvg_log!(
+ "circular reference in gradient {}",
+ node.get_human_readable_name()
+ );
+ return Err(RenderingError::CircularReference);
+ }
+
+ a_node.with_impl(|i: &NodeGradient| {
+ let fallback_grad = i.get_gradient_with_color_stops_from_node(&a_node);
+ result.resolve_from_fallback(&fallback_grad)
});
+
+ stack.push(a_node);
+ continue;
+ }
+
+ result.resolve_from_defaults();
}
if result.bounds_are_valid(bbox) {
diff --git a/tests/fixtures/infinite-loop/398-recursive-gradient.svg
b/tests/fixtures/infinite-loop/398-recursive-gradient.svg
new file mode 100644
index 00000000..dbe2e33d
--- /dev/null
+++ b/tests/fixtures/infinite-loop/398-recursive-gradient.svg
@@ -0,0 +1,5 @@
+<svg>
+ <linearGradient id="g1" xlink:href="#g1"/>
+ <linearGradient id="g2" xlink:href="#g1"/>
+ <rect fill="url(#g2)" width="100" height="100"/>
+</svg>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]