[librsvg: 10/22] pattern: split off an UnresolvedPattern, similar to the gradient code
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 10/22] pattern: split off an UnresolvedPattern, similar to the gradient code
- Date: Wed, 2 Oct 2019 21:44:28 +0000 (UTC)
commit 0f34a58a7e157a6cffbb2639ef8a961fd5fdcd37
Author: Federico Mena Quintero <federico gnome org>
Date: Tue Oct 1 14:05:28 2019 -0500
pattern: split off an UnresolvedPattern, similar to the gradient code
Now both code bases have a similar structure.
rsvg_internals/src/pattern.rs | 188 +++++++++++++++++++++++++++++-------------
1 file changed, 131 insertions(+), 57 deletions(-)
---
diff --git a/rsvg_internals/src/pattern.rs b/rsvg_internals/src/pattern.rs
index e60b8532..6be35fd2 100644
--- a/rsvg_internals/src/pattern.rs
+++ b/rsvg_internals/src/pattern.rs
@@ -1,6 +1,5 @@
use cairo;
use markup5ever::local_name;
-use std::cell::RefCell;
use std::f64;
use crate::allowed_url::Fragment;
@@ -38,18 +37,53 @@ struct Common {
y: Option<LengthVertical>,
width: Option<LengthHorizontal>,
height: Option<LengthVertical>,
+}
+/// State used during the pattern resolution process
+///
+/// This is the current node's pattern information, plus the fallback
+/// that should be used in case that information is not complete for a
+/// resolved pattern yet.
+struct Unresolved {
+ pattern: UnresolvedPattern,
+ fallback: Option<Fragment>,
}
-#[derive(Clone, Default)]
-pub struct NodePattern {
+/// Main structure used during pattern resolution. For unresolved
+/// patterns, we store all fields as Option<T> - if None, it means
+/// that the field is not specified; if Some(T), it means that the
+/// field was specified.
+struct UnresolvedPattern {
common: Common,
// Point back to our corresponding node, or to the fallback node which has children.
// If the value is None, it means we are fully resolved and didn't find any children
// among the fallbacks.
- node: RefCell<Option<RsvgNode>>,
+ node: Option<RsvgNode>,
+}
+
+/// Resolved pattern
+pub struct Pattern {
+ units: PatternUnits,
+ content_units: PatternContentUnits,
+ // This Option<Option<ViewBox>> is a bit strange. We want a field
+ // with value None to mean, "this field isn't resolved yet". However,
+ // the vbox can very well be *not* specified in the SVG file.
+ // In that case, the fully resolved pattern will have a .vbox=Some(None) value.
+ vbox: Option<ViewBox>,
+ preserve_aspect_ratio: AspectRatio,
+ affine: cairo::Matrix,
+ x: LengthHorizontal,
+ y: LengthVertical,
+ width: LengthHorizontal,
+ height: LengthVertical,
+
+ node: Option<RsvgNode>,
+}
+#[derive(Clone, Default)]
+pub struct NodePattern {
+ common: Common,
fallback: Option<Fragment>,
}
@@ -90,52 +124,50 @@ impl NodeTrait for NodePattern {
}
impl PaintSource for NodePattern {
- type Resolved = NodePattern;
+ type Resolved = Pattern;
fn resolve(
&self,
node: &RsvgNode,
draw_ctx: &mut DrawingCtx,
) -> Result<Self::Resolved, PaintServerError> {
-
- let mut result = node.borrow().get_impl::<NodePattern>().clone();
- *result.node.borrow_mut() = Some(node.clone());
+ let Unresolved { mut pattern, mut fallback } = self.get_unresolved(node);
let mut stack = NodeStack::new();
- while !result.is_resolved() {
- if let Some(ref fallback) = result.fallback {
+ while !pattern.is_resolved() {
+ if let Some(ref fragment) = fallback {
if let Some(acquired) = draw_ctx
.acquired_nodes()
- .get_node_of_type(fallback, NodeType::Pattern)
+ .get_node_of_type(&fragment, NodeType::Pattern)
{
- let a_node = acquired.get();
+ let acquired_node = acquired.get();
- if stack.contains(a_node) {
- return Err(PaintServerError::CircularReference(fallback.clone()));
+ if stack.contains(acquired_node) {
+ return Err(PaintServerError::CircularReference(fragment.clone()));
}
- let node_data = a_node.borrow();
+ let borrowed_node = acquired_node.borrow();
+ let borrowed_pattern = borrowed_node.get_impl::<NodePattern>();
+ let unresolved = borrowed_pattern.get_unresolved(&acquired_node);
- let fallback_pattern = node_data.get_impl::<NodePattern>();
- *fallback_pattern.node.borrow_mut() = Some(a_node.clone());
+ pattern = pattern.resolve_from_fallback(&unresolved.pattern);
+ fallback = unresolved.fallback;
- result = result.resolve_from_fallback(fallback_pattern);
-
- stack.push(a_node);
+ stack.push(acquired_node);
} else {
- result = result.resolve_from_defaults();
+ pattern = pattern.resolve_from_defaults();
}
} else {
- result = result.resolve_from_defaults();
+ pattern = pattern.resolve_from_defaults();
}
}
- Ok(result)
+ Ok(pattern.to_resolved())
}
}
-impl ResolvedPaintSource for NodePattern {
+impl ResolvedPaintSource for Pattern {
fn set_pattern_on_draw_context(
self,
values: &ComputedValues,
@@ -143,19 +175,17 @@ impl ResolvedPaintSource for NodePattern {
_opacity: &UnitInterval,
bbox: &BoundingBox,
) -> Result<bool, RenderingError> {
- assert!(self.is_resolved());
-
- if self.node.borrow().is_none() {
+ if self.node.is_none() {
// This means we didn't find any children among the fallbacks,
// so there is nothing to render.
return Ok(false);
}
- let units = self.common.units.unwrap();
- let content_units = self.common.content_units.unwrap();
- let pattern_affine = self.common.affine.unwrap();
- let vbox = self.common.vbox.unwrap();
- let preserve_aspect_ratio = self.common.preserve_aspect_ratio.unwrap();
+ let units = self.units;
+ let content_units = self.content_units;
+ let pattern_affine = self.affine;
+ let vbox = self.vbox;
+ let preserve_aspect_ratio = self.preserve_aspect_ratio;
let (pattern_x, pattern_y, pattern_width, pattern_height) = {
let params = if units == PatternUnits(CoordUnits::ObjectBoundingBox) {
@@ -164,10 +194,10 @@ impl ResolvedPaintSource for NodePattern {
draw_ctx.get_view_params()
};
- let pattern_x = self.common.x.unwrap().normalize(values, ¶ms);
- let pattern_y = self.common.y.unwrap().normalize(values, ¶ms);
- let pattern_width = self.common.width.unwrap().normalize(values, ¶ms);
- let pattern_height = self.common.height.unwrap().normalize(values, ¶ms);
+ let pattern_x = self.x.normalize(values, ¶ms);
+ let pattern_y = self.y.normalize(values, ¶ms);
+ let pattern_width = self.width.normalize(values, ¶ms);
+ let pattern_height = self.height.normalize(values, ¶ms);
(pattern_x, pattern_y, pattern_width, pattern_height)
};
@@ -294,8 +324,7 @@ impl ResolvedPaintSource for NodePattern {
// Set up transformations to be determined by the contents units
// Draw everything
- let pattern_node_borrow = self.node.borrow();
- let pattern_node = pattern_node_borrow.as_ref().unwrap();
+ let pattern_node = self.node.as_ref().unwrap();
let pattern_cascaded = CascadedValues::new_from_node(pattern_node);
let pattern_values = pattern_cascaded.get();
@@ -326,7 +355,25 @@ impl ResolvedPaintSource for NodePattern {
}
}
-impl NodePattern {
+impl UnresolvedPattern {
+ fn to_resolved(self) -> Pattern {
+ assert!(self.is_resolved());
+
+ Pattern {
+ units: self.common.units.unwrap(),
+ content_units: self.common.content_units.unwrap(),
+ vbox: self.common.vbox.unwrap(),
+ preserve_aspect_ratio: self.common.preserve_aspect_ratio.unwrap(),
+ affine: self.common.affine.unwrap(),
+ x: self.common.x.unwrap(),
+ y: self.common.y.unwrap(),
+ width: self.common.width.unwrap(),
+ height: self.common.height.unwrap(),
+
+ node: self.node.clone(),
+ }
+ }
+
fn is_resolved(&self) -> bool {
self.common.units.is_some()
&& self.common.content_units.is_some()
@@ -340,7 +387,18 @@ impl NodePattern {
&& self.children_are_resolved()
}
- fn resolve_from_fallback(&self, fallback: &NodePattern) -> NodePattern {
+
+ fn children_are_resolved(&self) -> bool {
+ if let Some(ref node) = self.node {
+ node.has_children()
+ } else {
+ // We are an empty pattern; there is nothing further that
+ // can be resolved for children.
+ true
+ }
+ }
+
+ fn resolve_from_fallback(&self, fallback: &UnresolvedPattern) -> UnresolvedPattern {
let units = self.common.units.or(fallback.common.units);
let content_units = self.common.content_units.or(fallback.common.content_units);
let vbox = self.common.vbox.or(fallback.common.vbox);
@@ -357,9 +415,7 @@ impl NodePattern {
self.node.clone()
};
- let fallback = fallback.fallback.clone();
-
- NodePattern {
+ UnresolvedPattern {
common: Common {
units,
content_units,
@@ -372,11 +428,10 @@ impl NodePattern {
height,
},
node,
- fallback,
}
}
- fn resolve_from_defaults(&self) -> NodePattern {
+ fn resolve_from_defaults(&self) -> UnresolvedPattern {
let units = self.common.units.or(Some(PatternUnits::default()));
let content_units = self.common.content_units.or(Some(PatternContentUnits::default()));
let vbox = self.common.vbox.or(Some(None));
@@ -387,9 +442,8 @@ impl NodePattern {
let width = self.common.width.or(Some(Default::default()));
let height = self.common.height.or(Some(Default::default()));
let node = self.node.clone();
- let fallback = None;
- NodePattern {
+ UnresolvedPattern {
common: Common {
units,
content_units,
@@ -402,17 +456,26 @@ impl NodePattern {
height,
},
node,
- fallback,
}
}
+}
- fn children_are_resolved(&self) -> bool {
- if let Some(ref node) = *self.node.borrow() {
- node.has_children()
+impl NodePattern {
+ fn get_unresolved(&self, node: &RsvgNode) -> Unresolved {
+ let node_with_children = if node.has_children() {
+ Some(node.clone())
} else {
- // We are an empty pattern; there is nothing further that
- // can be resolved for children.
- true
+ None
+ };
+
+ let pattern = UnresolvedPattern {
+ common: self.common.clone(),
+ node: node_with_children,
+ };
+
+ Unresolved {
+ pattern,
+ fallback: self.fallback.clone(),
}
}
}
@@ -420,11 +483,22 @@ impl NodePattern {
#[cfg(test)]
mod tests {
use super::*;
+ use crate::node::{NodeData, NodeType, RsvgNode};
#[test]
fn pattern_resolved_from_defaults_is_really_resolved() {
- let pat = NodePattern::default();
- let res = pat.resolve_from_defaults();
- assert!(res.is_resolved());
+ let node = RsvgNode::new(NodeData::new(
+ NodeType::Pattern,
+ local_name!("pattern"),
+ None,
+ None,
+ Box::new(NodePattern::default())
+ ));
+
+ let borrow = node.borrow();
+ let p = borrow.get_impl::<NodePattern>();
+ let Unresolved { pattern, .. } = p.get_unresolved(&node);
+ let pattern = pattern.resolve_from_defaults();
+ assert!(pattern.is_resolved());
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]