[librsvg: 20/45] Add an UnresolvedGradient, and use that instead of temporary clones of NodeGradient



commit 60664219b25cfab79d8237b6efb6b275f022f8fe
Author: Federico Mena Quintero <federico gnome org>
Date:   Fri Sep 27 15:33:09 2019 -0500

    Add an UnresolvedGradient, and use that instead of temporary clones of NodeGradient
    
    A NodeGradient doesn't need to store a digested version of its stops;
    those can live as child NodeStop.
    
    So, we remove the common field from NodeGradient and just add back the
    fields that *are* part of a digested gradient node.
    
    Then, we add UnresolvedGradient, constructible with
    NodeGradient::get_unresolved(), and use *that* as the mutable thing
    that gets resolved gradually.

 rsvg_internals/src/gradient.rs | 152 ++++++++++++++++++++++++++++-------------
 1 file changed, 105 insertions(+), 47 deletions(-)
---
diff --git a/rsvg_internals/src/gradient.rs b/rsvg_internals/src/gradient.rs
index 99e760c1..a07a2195 100644
--- a/rsvg_internals/src/gradient.rs
+++ b/rsvg_internals/src/gradient.rs
@@ -79,7 +79,7 @@ macro_rules! fallback_to (
     );
 );
 
-#[derive(Clone, Default)]
+#[derive(Clone)]
 struct UnresolvedCommon {
     units: Option<GradientUnits>,
     affine: Option<cairo::Matrix>,
@@ -142,17 +142,17 @@ impl Common {
 }
 
 impl UnresolvedCommon {
-    fn set_atts(&mut self, pbag: &PropertyBag<'_>) -> NodeResult {
-        for (attr, value) in pbag.iter() {
-            match attr {
-                local_name!("gradientUnits") => self.units = Some(attr.parse(value)?),
-                local_name!("gradientTransform") => self.affine = Some(attr.parse(value)?),
-                local_name!("spreadMethod") => self.spread = Some(attr.parse(value)?),
-                _ => (),
-            }
+    fn new_without_stops(
+        units: Option<GradientUnits>,
+        affine: Option<cairo::Matrix>,
+        spread: Option<SpreadMethod>,
+    ) -> UnresolvedCommon {
+        UnresolvedCommon {
+            units,
+            affine,
+            spread,
+            stops: None,
         }
-
-        Ok(())
     }
 
     fn to_resolved(self) -> Common {
@@ -514,7 +514,7 @@ impl NodeTrait for NodeStop {
     }
 }
 
-#[derive(Clone)]
+#[derive(Copy, Clone)]
 enum UnresolvedVariant {
     Linear(UnresolvedLinear),
     Radial(UnresolvedRadial),
@@ -562,37 +562,29 @@ impl UnresolvedVariant {
     }
 }
 
-#[derive(Clone)]
 pub struct NodeGradient {
-    common: UnresolvedCommon,
+    units: Option<GradientUnits>,
+    affine: Option<cairo::Matrix>,
+    spread: Option<SpreadMethod>,
+
     variant: UnresolvedVariant,
+
     fallback: Option<Fragment>,
 }
 
+struct UnresolvedGradient {
+    common: UnresolvedCommon,
+    variant: UnresolvedVariant,
+}
+
 pub struct Gradient {
     common: Common,
     variant: Variant,
 }
 
-impl NodeGradient {
-    pub fn new_linear() -> NodeGradient {
-        NodeGradient {
-            common: Default::default(),
-            variant: UnresolvedVariant::Linear(UnresolvedLinear::default()),
-            fallback: Default::default(),
-        }
-    }
-
-    pub fn new_radial() -> NodeGradient {
-        NodeGradient {
-            common: Default::default(),
-            variant: UnresolvedVariant::Radial(UnresolvedRadial::default()),
-            fallback: Default::default(),
-        }
-    }
-
+impl UnresolvedGradient {
     fn to_resolved(self) -> Gradient {
-        let NodeGradient {
+        let UnresolvedGradient {
             common, variant, ..
         } = self;
 
@@ -613,7 +605,7 @@ impl NodeGradient {
         self.common.is_resolved() && self.variant.is_resolved()
     }
 
-    fn resolve_from_fallback(&mut self, fallback: &NodeGradient) {
+    fn resolve_from_fallback(&mut self, fallback: &UnresolvedGradient) {
         self.common.resolve_from_fallback(&fallback.common);
         self.variant.resolve_from_fallback(&fallback.variant);
     }
@@ -622,12 +614,54 @@ impl NodeGradient {
         self.common.resolve_from_defaults();
         self.variant.resolve_from_defaults();
     }
+}
 
+impl NodeGradient {
+    pub fn new_linear() -> NodeGradient {
+        NodeGradient {
+            units: Default::default(),
+            affine: Default::default(),
+            spread: Default::default(),
+            variant: UnresolvedVariant::Linear(UnresolvedLinear::default()),
+            fallback: Default::default(),
+        }
+    }
+
+    pub fn new_radial() -> NodeGradient {
+        NodeGradient {
+            units: Default::default(),
+            affine: Default::default(),
+            spread: Default::default(),
+            variant: UnresolvedVariant::Radial(UnresolvedRadial::default()),
+            fallback: Default::default(),
+        }
+    }
+
+    fn get_unresolved(&self, node: &RsvgNode) -> (UnresolvedGradient, Option<Fragment>) {
+        let mut common = UnresolvedCommon::new_without_stops(self.units, self.affine, self.spread);
+
+        common.add_color_stops_from_node(node);
+
+        (
+            UnresolvedGradient {
+                common,
+                variant: self.variant,
+            },
+            self.fallback.clone(),
+        )
+    }
 }
 
 impl NodeTrait for NodeGradient {
     fn set_atts(&mut self, _: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
-        self.common.set_atts(pbag)?;
+        for (attr, value) in pbag.iter() {
+            match attr {
+                local_name!("gradientUnits") => self.units = Some(attr.parse(value)?),
+                local_name!("gradientTransform") => self.affine = Some(attr.parse(value)?),
+                local_name!("spreadMethod") => self.spread = Some(attr.parse(value)?),
+                _ => (),
+            }
+        }
 
         match self.variant {
             UnresolvedVariant::Linear(ref mut v) => v.set_atts(pbag)?,
@@ -656,13 +690,12 @@ impl PaintSource for NodeGradient {
         draw_ctx: &mut DrawingCtx,
         bbox: &BoundingBox,
     ) -> Result<Option<Self::Resolved>, RenderingError> {
-        let mut result = self.clone();
-        result.common.add_color_stops_from_node(node);
+        let (mut result, mut fallback) = self.get_unresolved(node);
 
         let mut stack = NodeStack::new();
 
         while !result.is_resolved() {
-            if let Some(acquired) = acquire_gradient(draw_ctx, result.fallback.as_ref()) {
+            if let Some(acquired) = acquire_gradient(draw_ctx, fallback.as_ref()) {
                 let a_node = acquired.get();
 
                 if stack.contains(a_node) {
@@ -670,9 +703,13 @@ impl PaintSource for NodeGradient {
                     return Err(RenderingError::CircularReference);
                 }
 
-                let mut a_gradient = a_node.borrow().get_impl::<NodeGradient>().clone();
-                a_gradient.common.add_color_stops_from_node(a_node);
+                let (a_gradient, next_fallback) = a_node
+                    .borrow()
+                    .get_impl::<NodeGradient>()
+                    .get_unresolved(a_node);
+
                 result.resolve_from_fallback(&a_gradient);
+                fallback = next_fallback;
 
                 stack.push(a_node);
             } else {
@@ -708,7 +745,7 @@ impl ResolvedPaintSource for Gradient {
                 let g = v.to_cairo_gradient(values, &params);
                 cairo::Gradient::clone(&g)
             }
-            
+
             Variant::Radial(v) => {
                 let g = v.to_cairo_gradient(values, &params);
                 cairo::Gradient::clone(&g)
@@ -743,6 +780,7 @@ fn acquire_gradient<'a>(
 mod tests {
     use super::*;
     use crate::float_eq_cairo::ApproxEqCairo;
+    use crate::node::{NodeData, NodeType, RsvgNode};
 
     #[test]
     fn parses_spread_method() {
@@ -774,12 +812,32 @@ mod tests {
 
     #[test]
     fn gradient_resolved_from_defaults_is_really_resolved() {
-        let mut l = NodeGradient::new_linear();
-        l.resolve_from_defaults();
-        assert!(l.is_resolved());
-
-        let mut r = NodeGradient::new_radial();
-        r.resolve_from_defaults();
-        assert!(r.is_resolved());
+        let node = RsvgNode::new(NodeData::new(
+            NodeType::Gradient,
+            local_name!("linearGradient"),
+            None,
+            None,
+            Box::new(NodeGradient::new_linear())
+        ));
+
+        let borrow = node.borrow();
+        let g = borrow.get_impl::<NodeGradient>();
+        let (mut u, _) = g.get_unresolved(&node);
+        u.resolve_from_defaults();
+        assert!(u.is_resolved());
+
+        let node = RsvgNode::new(NodeData::new(
+            NodeType::Gradient,
+            local_name!("radialGradient"),
+            None,
+            None,
+            Box::new(NodeGradient::new_radial())
+        ));
+
+        let borrow = node.borrow();
+        let g = borrow.get_impl::<NodeGradient>();
+        let (mut u, _) = g.get_unresolved(&node);
+        u.resolve_from_defaults();
+        assert!(u.is_resolved());
     }
 }


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