[librsvg: 16/45] Replace the two gradient nodes with a single NodeGradient



commit cede339afc3f381161b976b855b25def0d7ba377
Author: Federico Mena Quintero <federico gnome org>
Date:   Fri Sep 27 13:43:30 2019 -0500

    Replace the two gradient nodes with a single NodeGradient
    
    NodeGradient has an enum for the gradient's variant, instead of having
    macros that generate two different gradient types.
    
    This commit also removes conicalGradient, which is from Calligra's
    Karbon; it was being rendered as a radialGradient as a hack to "just
    do something" with it.  Instead, we'll wait until Cairo supports
    conical gradients (SVG1 and SVG2 don't).

 rsvg_internals/src/create_node.rs |  10 +-
 rsvg_internals/src/drawing_ctx.rs |  10 +-
 rsvg_internals/src/gradient.rs    | 385 ++++++++++++++++++++------------------
 rsvg_internals/src/node.rs        |   3 +-
 4 files changed, 207 insertions(+), 201 deletions(-)
---
diff --git a/rsvg_internals/src/create_node.rs b/rsvg_internals/src/create_node.rs
index 0c21995e..32011d58 100644
--- a/rsvg_internals/src/create_node.rs
+++ b/rsvg_internals/src/create_node.rs
@@ -22,7 +22,7 @@ use crate::filters::{
     turbulence::Turbulence,
 };
 
-use crate::gradient::{NodeLinearGradient, NodeRadialGradient, NodeStop};
+use crate::gradient::{NodeGradient, NodeStop};
 use crate::image::NodeImage;
 use crate::link::NodeLink;
 use crate::marker::NodeMarker;
@@ -75,8 +75,8 @@ mod creators {
     n!(create_group,                     Group,                      NodeGroup::default);
     n!(create_image,                     Image,                      NodeImage::default);
     n!(create_fe_image,                  FeImage,                    Image::default);
-    n!(create_linear_gradient,           LinearGradient,             NodeLinearGradient::default);
     n!(create_line,                      Line,                       NodeLine::default);
+    n!(create_linear_gradient,           Gradient,                   NodeGradient::new_linear);
     n!(create_link,                      Link,                       NodeLink::default);
     n!(create_marker,                    Marker,                     NodeMarker::default);
     n!(create_mask,                      Mask,                       NodeMask::default);
@@ -90,7 +90,7 @@ mod creators {
     n!(create_point_light,               PointLight,                 LightSource::new_point_light);
     n!(create_polygon,                   Polygon,                    NodePoly::new_closed);
     n!(create_polyline,                  Polyline,                   NodePoly::new_open);
-    n!(create_radial_gradient,           RadialGradient,             NodeRadialGradient::default);
+    n!(create_radial_gradient,           Gradient,                   NodeGradient::new_radial);
     n!(create_rect,                      Rect,                       NodeRect::default);
     n!(create_specular_lighting,         FeSpecularLighting,         Lighting::new_specular);
     n!(create_spot_light,                SpotLight,                  LightSource::new_spot_light);
@@ -106,9 +106,6 @@ mod creators {
     n!(create_turbulence,                FeTurbulence,               Turbulence::default);
     n!(create_use,                       Use,                        NodeUse::default);
 
-    // hack to partially support conical gradient
-    n!(create_conical_gradient,          RadialGradient,             NodeRadialGradient::default);
-
     // hack to make multiImage sort-of work
     n!(create_multi_image,               Switch,                     NodeSwitch::default);
     n!(create_sub_image,                 Group,                      NodeGroup::default);
@@ -142,7 +139,6 @@ lazy_static! {
         c!(h, "circle",              true,  create_circle);
         c!(h, "clipPath",            true,  create_clip_path);
         /* c!(h, "color-profile",    false, ); */
-        c!(h, "conicalGradient",     true,  create_conical_gradient);
         /* c!(h, "cursor",           false, ); */
         c!(h, "defs",                true,  create_defs);
         /* c!(h, "desc",             true,  ); */
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index 269eb118..c1b360f5 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -13,7 +13,7 @@ use crate::coord_units::CoordUnits;
 use crate::dpi::Dpi;
 use crate::error::RenderingError;
 use crate::filters;
-use crate::gradient::{NodeLinearGradient, NodeRadialGradient};
+use crate::gradient::NodeGradient;
 use crate::length::Dasharray;
 use crate::mask::NodeMask;
 use crate::node::{CascadedValues, NodeDraw, NodeType, RsvgNode};
@@ -619,13 +619,9 @@ impl DrawingCtx {
                     let node = acquired.get();
 
                     had_paint_server = match node.borrow().get_type() {
-                        NodeType::LinearGradient => node
+                        NodeType::Gradient => node
                             .borrow()
-                            .get_impl::<NodeLinearGradient>()
-                            .resolve_fallbacks_and_set_pattern(&node, self, opacity, bbox)?,
-                        NodeType::RadialGradient => node
-                            .borrow()
-                            .get_impl::<NodeRadialGradient>()
+                            .get_impl::<NodeGradient>()
                             .resolve_fallbacks_and_set_pattern(&node, self, opacity, bbox)?,
                         NodeType::Pattern => node
                             .borrow()
diff --git a/rsvg_internals/src/gradient.rs b/rsvg_internals/src/gradient.rs
index 1381113d..47b7182c 100644
--- a/rsvg_internals/src/gradient.rs
+++ b/rsvg_internals/src/gradient.rs
@@ -124,11 +124,7 @@ impl CommonGradient {
         self.add_color_stops_to_pattern(pattern, opacity);
     }
 
-    fn add_color_stops_to_pattern(
-        &self,
-        pattern: &cairo::Gradient,
-        opacity: &UnitInterval,
-    ) {
+    fn add_color_stops_to_pattern(&self, pattern: &cairo::Gradient, opacity: &UnitInterval) {
         for stop in &self.stops {
             let UnitInterval(stop_offset) = stop.offset;
             let &UnitInterval(o) = opacity;
@@ -185,7 +181,13 @@ impl CommonGradientData {
     fn to_resolved(self) -> CommonGradient {
         assert!(self.is_resolved());
 
-        let CommonGradientData { units, affine, spread, stops, .. } = self;
+        let CommonGradientData {
+            units,
+            affine,
+            spread,
+            stops,
+            ..
+        } = self;
 
         CommonGradient {
             units: units.unwrap(),
@@ -237,10 +239,7 @@ impl CommonGradientData {
     }
 
     fn add_color_stops_from_node(&mut self, node: &RsvgNode) {
-        assert!(
-            node.borrow().get_type() == NodeType::LinearGradient
-                || node.borrow().get_type() == NodeType::RadialGradient
-        );
+        assert!(node.borrow().get_type() == NodeType::Gradient);
 
         for child in node
             .children()
@@ -521,150 +520,218 @@ impl NodeTrait for NodeStop {
     }
 }
 
-macro_rules! impl_node_trait {
-    ($gradient_type:ty) => {
-        impl NodeTrait for $gradient_type {
-            fn set_atts(&mut self, _: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
-                self.common.set_atts(pbag)?;
-                self.variant.set_atts(pbag)?;
+#[derive(Clone)]
+enum GradientVariant {
+    Linear(LinearGradientData),
+    Radial(RadialGradientData),
+}
 
-                for (attr, value) in pbag.iter() {
-                    match attr {
-                        local_name!("xlink:href") => {
-                            self.fallback = Some(Fragment::parse(value).attribute(attr)?)
-                        }
-                        _ => (),
-                    }
-                }
+enum ResolvedGradientVariant {
+    Linear(LinearGradient),
+    Radial(RadialGradient),
+}
+
+impl GradientVariant {
+    fn to_resolved(self) -> ResolvedGradientVariant {
+        match self {
+            GradientVariant::Linear(v) => ResolvedGradientVariant::Linear(v.to_resolved()),
+            GradientVariant::Radial(v) => ResolvedGradientVariant::Radial(v.to_resolved()),
+        }
+    }
+
+    fn is_resolved(&self) -> bool {
+        match *self {
+            GradientVariant::Linear(v) => v.is_resolved(),
+            GradientVariant::Radial(v) => v.is_resolved(),
+        }
+    }
+
+    fn resolve_from_fallback(&mut self, fallback: &GradientVariant) {
+        match (self, fallback) {
+            (&mut GradientVariant::Linear(ref mut v), &GradientVariant::Linear(ref f)) => {
+                v.resolve_from_fallback(f)
+            }
 
-                Ok(())
+            (&mut GradientVariant::Radial(ref mut v), &GradientVariant::Radial(ref f)) => {
+                v.resolve_from_fallback(f)
             }
+
+            _ => (), // If variants are of different types, then nothing to resolve
+        }
+    }
+
+    fn resolve_from_defaults(&mut self) {
+        match *self {
+            GradientVariant::Linear(ref mut v) => v.resolve_from_defaults(),
+            GradientVariant::Radial(ref mut v) => v.resolve_from_defaults(),
+        }
+    }
+}
+
+#[derive(Clone)]
+pub struct NodeGradient {
+    common: CommonGradientData,
+    variant: GradientVariant,
+    fallback: Option<Fragment>,
+}
+
+pub struct ResolvedGradient {
+    common: CommonGradient,
+    variant: ResolvedGradientVariant,
+}
+
+impl NodeGradient {
+    pub fn new_linear() -> NodeGradient {
+        NodeGradient {
+            common: Default::default(),
+            variant: GradientVariant::Linear(LinearGradientData::default()),
+            fallback: Default::default(),
+        }
+    }
+
+    pub fn new_radial() -> NodeGradient {
+        NodeGradient {
+            common: Default::default(),
+            variant: GradientVariant::Radial(RadialGradientData::default()),
+            fallback: Default::default(),
         }
-    };
+    }
+
+    fn to_resolved(self) -> ResolvedGradient {
+        let NodeGradient {
+            common, variant, ..
+        } = self;
+
+        match variant {
+            GradientVariant::Linear(_) => ResolvedGradient {
+                common: common.to_resolved(),
+                variant: variant.to_resolved(),
+            },
+
+            GradientVariant::Radial(_) => ResolvedGradient {
+                common: common.to_resolved(),
+                variant: variant.to_resolved(),
+            },
+        }
+    }
 }
 
-macro_rules! impl_to_resolved {
-    ($gradient_type:tt, $resolved:tt) => {
-        impl $gradient_type {
-            fn to_resolved(self) -> $resolved {
-                assert!(self.is_resolved());
+impl NodeTrait for NodeGradient {
+    fn set_atts(&mut self, _: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
+        self.common.set_atts(pbag)?;
 
-                let $gradient_type { common, variant, .. } = self;
+        match self.variant {
+            GradientVariant::Linear(ref mut v) => v.set_atts(pbag)?,
+            GradientVariant::Radial(ref mut v) => v.set_atts(pbag)?,
+        }
 
-                $resolved {
-                    common: common.to_resolved(),
-                    variant: variant.to_resolved(),
+        for (attr, value) in pbag.iter() {
+            match attr {
+                local_name!("xlink:href") => {
+                    self.fallback = Some(Fragment::parse(value).attribute(attr)?)
                 }
+                _ => (),
             }
         }
-    };
+
+        Ok(())
+    }
 }
 
+impl Resolve for NodeGradient {
+    fn is_resolved(&self) -> bool {
+        self.common.is_resolved() && self.variant.is_resolved()
+    }
 
-macro_rules! impl_resolve {
-    ($gradient_type:ty) => {
-        impl Resolve for $gradient_type {
-            fn is_resolved(&self) -> bool {
-                self.common.is_resolved() && self.variant.is_resolved()
-            }
+    fn resolve_from_fallback(&mut self, fallback: &NodeGradient) {
+        self.common.resolve_from_fallback(&fallback.common);
+        self.variant.resolve_from_fallback(&fallback.variant);
+    }
 
-            fn resolve_from_fallback(&mut self, fallback: &$gradient_type) {
-                self.common.resolve_from_fallback(&fallback.common);
-                self.variant.resolve_from_fallback(&fallback.variant);
-            }
+    fn resolve_from_defaults(&mut self) {
+        self.common.resolve_from_defaults();
+        self.variant.resolve_from_defaults();
+    }
+}
 
-            fn resolve_from_defaults(&mut self) {
-                self.common.resolve_from_defaults();
-                self.variant.resolve_from_defaults();
-            }
-        }
-    };
-}
-
-macro_rules! impl_paint_source {
-    ($gradient:ty, $node_type:pat, $other_gradient:ty, $other_type:pat, $resolved:ty,) => {
-        impl PaintSource for $gradient {
-            type Resolved = $resolved;
-
-            fn resolve(
-                &self,
-                node: &RsvgNode,
-                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 stack = NodeStack::new();
-
-                while !result.is_resolved() {
-                    let acquired = acquire_gradient(draw_ctx, result.fallback.as_ref());
-
-                    if let Some(acquired) = acquired {
-                        let a_node = acquired.get();
-
-                        if stack.contains(a_node) {
-                            rsvg_log!("circular reference in gradient {}", node);
-                            return Err(RenderingError::CircularReference);
-                        }
-
-                        match a_node.borrow().get_type() {
-                            // Same type, resolve all attributes
-                            $node_type => {
-                                let mut fallback = a_node.borrow().get_impl::<$gradient>().clone();
-                                fallback.common.add_color_stops_from_node(a_node);
-                                result.resolve_from_fallback(&fallback);
-                            }
-                            // Other type of gradient, resolve common attributes
-                            $other_type => {
-                                let mut fallback =
-                                    a_node.borrow().get_impl::<$other_gradient>().clone();
-                                fallback.common.add_color_stops_from_node(a_node);
-                                result.common.resolve_from_fallback(&fallback.common);
-                            }
-                            _ => (),
-                        }
-
-                        stack.push(a_node);
-
-                        continue;
-                    }
-
-                    result.resolve_from_defaults();
-                }
+impl PaintSource for NodeGradient {
+    type Resolved = ResolvedGradient;
+
+    fn resolve(
+        &self,
+        node: &RsvgNode,
+        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 stack = NodeStack::new();
+
+        while !result.is_resolved() {
+            let acquired = acquire_gradient(draw_ctx, result.fallback.as_ref());
+
+            if let Some(acquired) = acquired {
+                let a_node = acquired.get();
 
-                if result.common.bounds_are_valid(bbox) {
-                    Ok(Some(result.to_resolved()))
-                } else {
-                    Ok(None)
+                if stack.contains(a_node) {
+                    rsvg_log!("circular reference in gradient {}", node);
+                    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);
+                result.resolve_from_fallback(&a_gradient);
+
+                stack.push(a_node);
+
+                continue;
             }
+
+            result.resolve_from_defaults();
         }
 
-        impl ResolvedPaintSource for $resolved {
-            fn set_pattern_on_draw_context(
-                self,
-                values: &ComputedValues,
-                draw_ctx: &mut DrawingCtx,
-                opacity: &UnitInterval,
-                bbox: &BoundingBox,
-            ) -> Result<bool, RenderingError> {
-                let units = self.common.units;
-                let params = if units == GradientUnits(CoordUnits::ObjectBoundingBox) {
-                    draw_ctx.push_view_box(1.0, 1.0)
-                } else {
-                    draw_ctx.get_view_params()
-                };
+        if result.common.bounds_are_valid(bbox) {
+            Ok(Some(result.to_resolved()))
+        } else {
+            Ok(None)
+        }
+    }
+}
 
-                let p = self.variant.to_cairo_gradient(values, &params);
-                self.common.set_on_cairo_pattern(&p, bbox, opacity);
-                let cr = draw_ctx.get_cairo_context();
-                cr.set_source(&p);
+impl ResolvedPaintSource for ResolvedGradient {
+    fn set_pattern_on_draw_context(
+        self,
+        values: &ComputedValues,
+        draw_ctx: &mut DrawingCtx,
+        opacity: &UnitInterval,
+        bbox: &BoundingBox,
+    ) -> Result<bool, RenderingError> {
+        let units = self.common.units;
+        let params = if units == GradientUnits(CoordUnits::ObjectBoundingBox) {
+            draw_ctx.push_view_box(1.0, 1.0)
+        } else {
+            draw_ctx.get_view_params()
+        };
 
-                Ok(true)
+        let p = match self.variant {
+            ResolvedGradientVariant::Linear(v) => {
+                let g = v.to_cairo_gradient(values, &params);
+                cairo::Gradient::clone(&g)
             }
-        }
-    };
+            
+            ResolvedGradientVariant::Radial(v) => {
+                let g = v.to_cairo_gradient(values, &params);
+                cairo::Gradient::clone(&g)
+            }
+        };
+
+        self.common.set_on_cairo_pattern(&p, bbox, opacity);
+        let cr = draw_ctx.get_cairo_context();
+        cr.set_source(&p);
+
+        Ok(true)
+    }
 }
 
 fn acquire_gradient<'a>(
@@ -675,7 +742,7 @@ fn acquire_gradient<'a>(
         .and_then(|acquired| {
             let node_type = acquired.get().borrow().get_type();
 
-            if node_type == NodeType::LinearGradient || node_type == NodeType::RadialGradient {
+            if node_type == NodeType::Gradient {
                 Some(acquired)
             } else {
                 None
@@ -683,58 +750,6 @@ fn acquire_gradient<'a>(
         })
 }
 
-#[derive(Clone, Default)]
-pub struct NodeLinearGradient {
-    common: CommonGradientData,
-    variant: LinearGradientData,
-    fallback: Option<Fragment>,
-}
-
-pub struct ResolvedLinearGradient {
-    common: CommonGradient,
-    variant: LinearGradient,
-}
-
-impl_node_trait!(NodeLinearGradient);
-
-impl_to_resolved!(NodeLinearGradient, ResolvedLinearGradient);
-
-impl_resolve!(NodeLinearGradient);
-
-impl_paint_source!(
-    NodeLinearGradient,
-    NodeType::LinearGradient,
-    NodeRadialGradient,
-    NodeType::RadialGradient,
-    ResolvedLinearGradient,
-);
-
-#[derive(Clone, Default)]
-pub struct NodeRadialGradient {
-    common: CommonGradientData,
-    variant: RadialGradientData,
-    fallback: Option<Fragment>,
-}
-
-pub struct ResolvedRadialGradient {
-    common: CommonGradient,
-    variant: RadialGradient,
-}
-
-impl_node_trait!(NodeRadialGradient);
-
-impl_to_resolved!(NodeRadialGradient, ResolvedRadialGradient);
-
-impl_resolve!(NodeRadialGradient);
-
-impl_paint_source!(
-    NodeRadialGradient,
-    NodeType::RadialGradient,
-    NodeLinearGradient,
-    NodeType::LinearGradient,
-    ResolvedRadialGradient,
-);
-
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -770,11 +785,11 @@ mod tests {
 
     #[test]
     fn gradient_resolved_from_defaults_is_really_resolved() {
-        let mut l = NodeLinearGradient::default();
+        let mut l = NodeGradient::new_linear();
         l.resolve_from_defaults();
         assert!(l.is_resolved());
 
-        let mut r = NodeRadialGradient::default();
+        let mut r = NodeGradient::new_radial();
         r.resolve_from_defaults();
         assert!(r.is_resolved());
     }
diff --git a/rsvg_internals/src/node.rs b/rsvg_internals/src/node.rs
index fa3f7b26..7ff22d7a 100644
--- a/rsvg_internals/src/node.rs
+++ b/rsvg_internals/src/node.rs
@@ -406,10 +406,10 @@ pub enum NodeType {
     DistantLight,
     Ellipse,
     Filter,
+    Gradient,
     Group,
     Image,
     Line,
-    LinearGradient,
     Link,
     Marker,
     Mask,
@@ -419,7 +419,6 @@ pub enum NodeType {
     PointLight,
     Polygon,
     Polyline,
-    RadialGradient,
     Rect,
     SpotLight,
     Stop,


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