[librsvg: 4/8] Replace PrimitiveWithInput with some extra methods in Primitive




commit b4bd33b53f532a08be697d3dc6d5b92463945c41
Author: Federico Mena Quintero <federico gnome org>
Date:   Wed Mar 10 17:39:32 2021 -0600

    Replace PrimitiveWithInput with some extra methods in Primitive
    
    Seeing this inconsitency in the render() methods of filter primtives
    was bothering me:
    
        let input = self.base.get_input(ctx, acquired_nodes, draw_ctx)?;
        let input_2 = ctx.get_input(acquired_nodes, draw_ctx, &self.in2)?;
    
    With the following changes, the methods that take two inputs now look
    like this:
    
        let input_1 = ctx.get_input(acquired_nodes, draw_ctx, &self.in1)?;
        let input_2 = ctx.get_input(acquired_nodes, draw_ctx, &self.in2)?;
    
    The changes:
    
    * Remove PrimitiveWithInput, which was just a Primitive that could
    parse the "in" attribute.
    
    * Replace that with extra methods in Primitive:
    
        parse_no_inputs() -> Result<(), ...>
        parse_one_input() -> Result<Input, ...>
        parse_two_inputs() -> Result<(Input, Input), ...>
    
    * All primitives now have a "base: Primitive" field instead of either
    that or a "base: PrimitiveWithInput" field.
    
    * Primitives can add their own fields as needed:
    
        in1: Input,
        in2: Input,
    
    * Since Primitive no longer has a set_attributes() method, it no
    longer implements SetAttributes.

 src/filters/blend.rs              | 31 +++++++++--------
 src/filters/color_matrix.rs       | 18 +++++-----
 src/filters/component_transfer.rs | 19 ++++++-----
 src/filters/composite.rs          | 21 +++++++-----
 src/filters/convolve_matrix.rs    | 20 ++++++-----
 src/filters/displacement_map.rs   | 21 +++++++-----
 src/filters/flood.rs              |  2 +-
 src/filters/gaussian_blur.rs      | 20 ++++++-----
 src/filters/image.rs              |  2 +-
 src/filters/lighting.rs           | 24 +++++++------
 src/filters/merge.rs              |  2 +-
 src/filters/mod.rs                | 72 ++++++++++++---------------------------
 src/filters/morphology.rs         | 27 +++++++++------
 src/filters/offset.rs             | 16 +++++----
 src/filters/tile.rs               | 15 ++++----
 src/filters/turbulence.rs         |  2 +-
 16 files changed, 157 insertions(+), 155 deletions(-)
---
diff --git a/src/filters/blend.rs b/src/filters/blend.rs
index df94721d..9ff0d41d 100755
--- a/src/filters/blend.rs
+++ b/src/filters/blend.rs
@@ -10,7 +10,7 @@ use crate::parsers::{Parse, ParseValue};
 use crate::xml::Attributes;
 
 use super::context::{FilterContext, FilterOutput, FilterResult};
-use super::{FilterEffect, FilterError, FilterRender, Input, PrimitiveWithInput};
+use super::{FilterEffect, FilterError, FilterRender, Input, Primitive};
 
 /// Enumeration of the possible blending modes.
 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
@@ -37,7 +37,8 @@ enum_default!(Mode, Mode::Normal);
 
 /// The `feBlend` filter primitive.
 pub struct FeBlend {
-    base: PrimitiveWithInput,
+    base: Primitive,
+    in1: Input,
     in2: Input,
     mode: Mode,
 }
@@ -47,7 +48,8 @@ impl Default for FeBlend {
     #[inline]
     fn default() -> FeBlend {
         FeBlend {
-            base: PrimitiveWithInput::new(),
+            base: Primitive::new(),
+            in1: Default::default(),
             in2: Default::default(),
             mode: Mode::default(),
         }
@@ -56,13 +58,13 @@ impl Default for FeBlend {
 
 impl SetAttributes for FeBlend {
     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)?;
+        let (in1, in2) = self.base.parse_two_inputs(attrs)?;
+        self.in1 = in1;
+        self.in2 = in2;
 
         for (attr, value) in attrs.iter() {
-            match attr.expanded() {
-                expanded_name!("", "in2") => self.in2 = attr.parse(value)?,
-                expanded_name!("", "mode") => self.mode = attr.parse(value)?,
-                _ => (),
+            if let expanded_name!("", "mode") = attr.expanded() {
+                self.mode = attr.parse(value)?;
             }
         }
 
@@ -78,19 +80,20 @@ impl FilterRender for FeBlend {
         acquired_nodes: &mut AcquiredNodes<'_>,
         draw_ctx: &mut DrawingCtx,
     ) -> Result<FilterResult, FilterError> {
-        let input = self.base.get_input(ctx, acquired_nodes, draw_ctx)?;
+        let input_1 = ctx.get_input(acquired_nodes, draw_ctx, &self.in1)?;
         let input_2 = ctx.get_input(acquired_nodes, draw_ctx, &self.in2)?;
         let bounds = self
             .base
             .get_bounds(ctx)?
-            .add_input(&input)
+            .add_input(&input_1)
             .add_input(&input_2)
             .into_irect(ctx, draw_ctx);
 
-        let surface =
-            input
-                .surface()
-                .compose(input_2.surface(), bounds, cairo::Operator::from(self.mode))?;
+        let surface = input_1.surface().compose(
+            input_2.surface(),
+            bounds,
+            cairo::Operator::from(self.mode),
+        )?;
 
         Ok(FilterResult {
             name: self.base.result.clone(),
diff --git a/src/filters/color_matrix.rs b/src/filters/color_matrix.rs
index c56ef141..9cdb0ca1 100644
--- a/src/filters/color_matrix.rs
+++ b/src/filters/color_matrix.rs
@@ -15,7 +15,7 @@ use crate::util::clamp;
 use crate::xml::Attributes;
 
 use super::context::{FilterContext, FilterOutput, FilterResult};
-use super::{FilterEffect, FilterError, FilterRender, PrimitiveWithInput};
+use super::{FilterEffect, FilterError, FilterRender, Input, Primitive};
 
 /// Color matrix operation types.
 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
@@ -30,7 +30,8 @@ enum_default!(OperationType, OperationType::Matrix);
 
 /// The `feColorMatrix` filter primitive.
 pub struct FeColorMatrix {
-    base: PrimitiveWithInput,
+    base: Primitive,
+    in1: Input,
     matrix: Matrix5<f64>,
 }
 
@@ -39,7 +40,8 @@ impl Default for FeColorMatrix {
     #[inline]
     fn default() -> FeColorMatrix {
         FeColorMatrix {
-            base: PrimitiveWithInput::new(),
+            base: Primitive::new(),
+            in1: Default::default(),
             matrix: Matrix5::identity(),
         }
     }
@@ -48,7 +50,7 @@ impl Default for FeColorMatrix {
 #[rustfmt::skip]
 impl SetAttributes for FeColorMatrix {
     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)?;
+        self.in1 = self.base.parse_one_input(attrs)?;
 
         // First, determine the operation type.
         let mut operation_type = Default::default();
@@ -145,21 +147,21 @@ impl FilterRender for FeColorMatrix {
         acquired_nodes: &mut AcquiredNodes<'_>,
         draw_ctx: &mut DrawingCtx,
     ) -> Result<FilterResult, FilterError> {
-        let input = self.base.get_input(ctx, acquired_nodes, draw_ctx)?;
+        let input_1 = ctx.get_input(acquired_nodes, draw_ctx, &self.in1)?;
         let bounds = self
             .base
             .get_bounds(ctx)?
-            .add_input(&input)
+            .add_input(&input_1)
             .into_irect(ctx, draw_ctx);
 
         let mut surface = ExclusiveImageSurface::new(
             ctx.source_graphic().width(),
             ctx.source_graphic().height(),
-            input.surface().surface_type(),
+            input_1.surface().surface_type(),
         )?;
 
         surface.modify(&mut |data, stride| {
-            for (x, y, pixel) in Pixels::within(input.surface(), bounds) {
+            for (x, y, pixel) in Pixels::within(input_1.surface(), bounds) {
                 let alpha = f64::from(pixel.a) / 255f64;
 
                 let pixel_vec = if alpha == 0.0 {
diff --git a/src/filters/component_transfer.rs b/src/filters/component_transfer.rs
index f2745a5b..75d7a85e 100644
--- a/src/filters/component_transfer.rs
+++ b/src/filters/component_transfer.rs
@@ -16,11 +16,12 @@ use crate::util::clamp;
 use crate::xml::Attributes;
 
 use super::context::{FilterContext, FilterOutput, FilterResult};
-use super::{FilterEffect, FilterError, FilterRender, PrimitiveWithInput};
+use super::{FilterEffect, FilterError, FilterRender, Input, Primitive};
 
 /// The `feComponentTransfer` filter primitive.
 pub struct FeComponentTransfer {
-    base: PrimitiveWithInput,
+    base: Primitive,
+    in1: Input,
 }
 
 impl Default for FeComponentTransfer {
@@ -28,14 +29,16 @@ impl Default for FeComponentTransfer {
     #[inline]
     fn default() -> FeComponentTransfer {
         FeComponentTransfer {
-            base: PrimitiveWithInput::new(),
+            base: Primitive::new(),
+            in1: Default::default(),
         }
     }
 }
 
 impl SetAttributes for FeComponentTransfer {
     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)
+        self.in1 = self.base.parse_one_input(attrs)?;
+        Ok(())
     }
 }
 
@@ -293,18 +296,18 @@ impl FilterRender for FeComponentTransfer {
     ) -> Result<FilterResult, FilterError> {
         let functions = get_parameters(node)?;
 
-        let input = self.base.get_input(ctx, acquired_nodes, draw_ctx)?;
+        let input_1 = ctx.get_input(acquired_nodes, draw_ctx, &self.in1)?;
         let bounds = self
             .base
             .get_bounds(ctx)?
-            .add_input(&input)
+            .add_input(&input_1)
             .into_irect(ctx, draw_ctx);
 
         // Create the output surface.
         let mut surface = ExclusiveImageSurface::new(
             ctx.source_graphic().width(),
             ctx.source_graphic().height(),
-            input.surface().surface_type(),
+            input_1.surface().surface_type(),
         )?;
 
         #[inline]
@@ -338,7 +341,7 @@ impl FilterRender for FeComponentTransfer {
 
         // Do the actual processing.
         surface.modify(&mut |data, stride| {
-            for (x, y, pixel) in Pixels::within(input.surface(), bounds) {
+            for (x, y, pixel) in Pixels::within(input_1.surface(), bounds) {
                 let alpha = f64::from(pixel.a) / 255f64;
                 let new_alpha = compute_a(alpha);
 
diff --git a/src/filters/composite.rs b/src/filters/composite.rs
index 1d081b6d..0929d571 100644
--- a/src/filters/composite.rs
+++ b/src/filters/composite.rs
@@ -10,7 +10,7 @@ use crate::parsers::{Parse, ParseValue};
 use crate::xml::Attributes;
 
 use super::context::{FilterContext, FilterOutput, FilterResult};
-use super::{FilterEffect, FilterError, FilterRender, Input, PrimitiveWithInput};
+use super::{FilterEffect, FilterError, FilterRender, Input, Primitive};
 
 /// Enumeration of the possible compositing operations.
 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
@@ -25,7 +25,8 @@ enum Operator {
 
 /// The `feComposite` filter primitive.
 pub struct FeComposite {
-    base: PrimitiveWithInput,
+    base: Primitive,
+    in1: Input,
     in2: Input,
     operator: Operator,
     k1: f64,
@@ -39,7 +40,8 @@ impl Default for FeComposite {
     #[inline]
     fn default() -> FeComposite {
         FeComposite {
-            base: PrimitiveWithInput::new(),
+            base: Primitive::new(),
+            in1: Default::default(),
             in2: Default::default(),
             operator: Operator::Over,
             k1: 0.0,
@@ -52,11 +54,12 @@ impl Default for FeComposite {
 
 impl SetAttributes for FeComposite {
     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)?;
+        let (in1, in2) = self.base.parse_two_inputs(attrs)?;
+        self.in1 = in1;
+        self.in2 = in2;
 
         for (attr, value) in attrs.iter() {
             match attr.expanded() {
-                expanded_name!("", "in2") => self.in2 = attr.parse(value)?,
                 expanded_name!("", "operator") => self.operator = attr.parse(value)?,
                 expanded_name!("", "k1") => self.k1 = attr.parse(value)?,
                 expanded_name!("", "k2") => self.k2 = attr.parse(value)?,
@@ -78,17 +81,17 @@ impl FilterRender for FeComposite {
         acquired_nodes: &mut AcquiredNodes<'_>,
         draw_ctx: &mut DrawingCtx,
     ) -> Result<FilterResult, FilterError> {
-        let input = self.base.get_input(ctx, acquired_nodes, draw_ctx)?;
+        let input_1 = ctx.get_input(acquired_nodes, draw_ctx, &self.in1)?;
         let input_2 = ctx.get_input(acquired_nodes, draw_ctx, &self.in2)?;
         let bounds = self
             .base
             .get_bounds(ctx)?
-            .add_input(&input)
+            .add_input(&input_1)
             .add_input(&input_2)
             .into_irect(ctx, draw_ctx);
 
         let surface = if self.operator == Operator::Arithmetic {
-            input.surface().compose_arithmetic(
+            input_1.surface().compose_arithmetic(
                 input_2.surface(),
                 bounds,
                 self.k1,
@@ -97,7 +100,7 @@ impl FilterRender for FeComposite {
                 self.k4,
             )?
         } else {
-            input.surface().compose(
+            input_1.surface().compose(
                 input_2.surface(),
                 bounds,
                 cairo::Operator::from(self.operator),
diff --git a/src/filters/convolve_matrix.rs b/src/filters/convolve_matrix.rs
index 5e70d5c4..40449942 100644
--- a/src/filters/convolve_matrix.rs
+++ b/src/filters/convolve_matrix.rs
@@ -20,11 +20,12 @@ use crate::util::clamp;
 use crate::xml::Attributes;
 
 use super::context::{FilterContext, FilterOutput, FilterResult};
-use super::{FilterEffect, FilterError, FilterRender, PrimitiveWithInput};
+use super::{FilterEffect, FilterError, FilterRender, Input, Primitive};
 
 /// The `feConvolveMatrix` filter primitive.
 pub struct FeConvolveMatrix {
-    base: PrimitiveWithInput,
+    base: Primitive,
+    in1: Input,
     order: (u32, u32),
     kernel_matrix: Option<DMatrix<f64>>,
     divisor: f64,
@@ -41,7 +42,8 @@ impl Default for FeConvolveMatrix {
     #[inline]
     fn default() -> FeConvolveMatrix {
         FeConvolveMatrix {
-            base: PrimitiveWithInput::new(),
+            base: Primitive::new(),
+            in1: Default::default(),
             order: (3, 3),
             kernel_matrix: None,
             divisor: 0.0,
@@ -57,7 +59,7 @@ impl Default for FeConvolveMatrix {
 
 impl SetAttributes for FeConvolveMatrix {
     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)?;
+        self.in1 = self.base.parse_one_input(attrs)?;
 
         for (attr, value) in attrs.iter() {
             match attr.expanded() {
@@ -129,11 +131,11 @@ impl FilterRender for FeConvolveMatrix {
     ) -> Result<FilterResult, FilterError> {
         #![allow(clippy::many_single_char_names)]
 
-        let input = self.base.get_input(ctx, acquired_nodes, draw_ctx)?;
+        let input_1 = ctx.get_input(acquired_nodes, draw_ctx, &self.in1)?;
         let mut bounds = self
             .base
             .get_bounds(ctx)?
-            .add_input(&input)
+            .add_input(&input_1)
             .into_irect(ctx, draw_ctx);
         let original_bounds = bounds;
 
@@ -159,9 +161,9 @@ impl FilterRender for FeConvolveMatrix {
 
         let mut input_surface = if self.preserve_alpha {
             // preserve_alpha means we need to premultiply and unpremultiply the values.
-            input.surface().unpremultiply(bounds)?
+            input_1.surface().unpremultiply(bounds)?
         } else {
-            input.surface().clone()
+            input_1.surface().clone()
         };
 
         let scale = self
@@ -193,7 +195,7 @@ impl FilterRender for FeConvolveMatrix {
         let mut surface = ExclusiveImageSurface::new(
             input_surface.width(),
             input_surface.height(),
-            input.surface().surface_type(),
+            input_1.surface().surface_type(),
         )?;
 
         surface.modify(&mut |data, stride| {
diff --git a/src/filters/displacement_map.rs b/src/filters/displacement_map.rs
index ddae001e..6bd557ed 100644
--- a/src/filters/displacement_map.rs
+++ b/src/filters/displacement_map.rs
@@ -11,7 +11,7 @@ use crate::surface_utils::{iterators::Pixels, shared_surface::ExclusiveImageSurf
 use crate::xml::Attributes;
 
 use super::context::{FilterContext, FilterOutput, FilterResult};
-use super::{FilterEffect, FilterError, FilterRender, Input, PrimitiveWithInput};
+use super::{FilterEffect, FilterError, FilterRender, Input, Primitive};
 
 /// Enumeration of the color channels the displacement map can source.
 #[derive(Clone, Copy)]
@@ -24,7 +24,8 @@ enum ColorChannel {
 
 /// The `feDisplacementMap` filter primitive.
 pub struct FeDisplacementMap {
-    base: PrimitiveWithInput,
+    base: Primitive,
+    in1: Input,
     in2: Input,
     scale: f64,
     x_channel_selector: ColorChannel,
@@ -36,7 +37,8 @@ impl Default for FeDisplacementMap {
     #[inline]
     fn default() -> FeDisplacementMap {
         FeDisplacementMap {
-            base: PrimitiveWithInput::new(),
+            base: Primitive::new(),
+            in1: Default::default(),
             in2: Default::default(),
             scale: 0.0,
             x_channel_selector: ColorChannel::A,
@@ -47,11 +49,12 @@ impl Default for FeDisplacementMap {
 
 impl SetAttributes for FeDisplacementMap {
     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)?;
+        let (in1, in2) = self.base.parse_two_inputs(attrs)?;
+        self.in1 = in1;
+        self.in2 = in2;
 
         for (attr, value) in attrs.iter() {
             match attr.expanded() {
-                expanded_name!("", "in2") => self.in2 = attr.parse(value)?,
                 expanded_name!("", "scale") => self.scale = attr.parse(value)?,
                 expanded_name!("", "xChannelSelector") => {
                     self.x_channel_selector = attr.parse(value)?
@@ -75,12 +78,12 @@ impl FilterRender for FeDisplacementMap {
         acquired_nodes: &mut AcquiredNodes<'_>,
         draw_ctx: &mut DrawingCtx,
     ) -> Result<FilterResult, FilterError> {
-        let input = self.base.get_input(ctx, acquired_nodes, draw_ctx)?;
+        let input_1 = ctx.get_input(acquired_nodes, draw_ctx, &self.in1)?;
         let displacement_input = ctx.get_input(acquired_nodes, draw_ctx, &self.in2)?;
         let bounds = self
             .base
             .get_bounds(ctx)?
-            .add_input(&input)
+            .add_input(&input_1)
             .add_input(&displacement_input)
             .into_irect(ctx, draw_ctx);
 
@@ -92,7 +95,7 @@ impl FilterRender for FeDisplacementMap {
         let mut surface = ExclusiveImageSurface::new(
             ctx.source_graphic().width(),
             ctx.source_graphic().height(),
-            input.surface().surface_type(),
+            input_1.surface().surface_type(),
         )?;
 
         surface.draw(&mut |cr| {
@@ -120,7 +123,7 @@ impl FilterRender for FeDisplacementMap {
                 cr.reset_clip();
                 cr.clip();
 
-                input.surface().set_as_source_surface(&cr, -ox, -oy);
+                input_1.surface().set_as_source_surface(&cr, -ox, -oy);
                 cr.paint();
             }
 
diff --git a/src/filters/flood.rs b/src/filters/flood.rs
index a20d72a7..e461e0c6 100644
--- a/src/filters/flood.rs
+++ b/src/filters/flood.rs
@@ -24,7 +24,7 @@ impl Default for FeFlood {
 
 impl SetAttributes for FeFlood {
     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)
+        self.base.parse_no_inputs(attrs)
     }
 }
 
diff --git a/src/filters/gaussian_blur.rs b/src/filters/gaussian_blur.rs
index 5d652d05..5fe342b2 100644
--- a/src/filters/gaussian_blur.rs
+++ b/src/filters/gaussian_blur.rs
@@ -17,7 +17,7 @@ use crate::surface_utils::{
 use crate::xml::Attributes;
 
 use super::context::{FilterContext, FilterOutput, FilterResult};
-use super::{FilterEffect, FilterError, FilterRender, PrimitiveWithInput};
+use super::{FilterEffect, FilterError, FilterRender, Input, Primitive};
 
 /// The maximum gaussian blur kernel size.
 ///
@@ -26,7 +26,8 @@ const MAXIMUM_KERNEL_SIZE: usize = 500;
 
 /// The `feGaussianBlur` filter primitive.
 pub struct FeGaussianBlur {
-    base: PrimitiveWithInput,
+    base: Primitive,
+    in1: Input,
     std_deviation: (f64, f64),
 }
 
@@ -35,7 +36,8 @@ impl Default for FeGaussianBlur {
     #[inline]
     fn default() -> FeGaussianBlur {
         FeGaussianBlur {
-            base: PrimitiveWithInput::new(),
+            base: Primitive::new(),
+            in1: Default::default(),
             std_deviation: (0.0, 0.0),
         }
     }
@@ -43,7 +45,7 @@ impl Default for FeGaussianBlur {
 
 impl SetAttributes for FeGaussianBlur {
     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)?;
+        self.in1 = self.base.parse_one_input(attrs)?;
 
         for (attr, value) in attrs.iter() {
             if let expanded_name!("", "stdDeviation") = attr.expanded() {
@@ -193,11 +195,11 @@ impl FilterRender for FeGaussianBlur {
         acquired_nodes: &mut AcquiredNodes<'_>,
         draw_ctx: &mut DrawingCtx,
     ) -> Result<FilterResult, FilterError> {
-        let input = self.base.get_input(ctx, acquired_nodes, draw_ctx)?;
+        let input_1 = ctx.get_input(acquired_nodes, draw_ctx, &self.in1)?;
         let bounds = self
             .base
             .get_bounds(ctx)?
-            .add_input(&input)
+            .add_input(&input_1)
             .into_irect(ctx, draw_ctx);
 
         let (std_x, std_y) = self.std_deviation;
@@ -214,11 +216,11 @@ impl FilterRender for FeGaussianBlur {
         // Horizontal convolution.
         let horiz_result_surface = if std_x >= 2.0 {
             // The spec says for deviation >= 2.0 three box blurs can be used as an optimization.
-            three_box_blurs::<Horizontal>(input.surface(), bounds, std_x)?
+            three_box_blurs::<Horizontal>(input_1.surface(), bounds, std_x)?
         } else if std_x != 0.0 {
-            gaussian_blur(input.surface(), bounds, std_x, false)?
+            gaussian_blur(input_1.surface(), bounds, std_x, false)?
         } else {
-            input.surface().clone()
+            input_1.surface().clone()
         };
 
         // Vertical convolution.
diff --git a/src/filters/image.rs b/src/filters/image.rs
index 6044dfc7..e328ae98 100644
--- a/src/filters/image.rs
+++ b/src/filters/image.rs
@@ -99,7 +99,7 @@ impl FeImage {
 
 impl SetAttributes for FeImage {
     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)?;
+        self.base.parse_no_inputs(attrs)?;
 
         for (attr, value) in attrs.iter() {
             match attr.expanded() {
diff --git a/src/filters/lighting.rs b/src/filters/lighting.rs
index 51042a1d..81132bd9 100644
--- a/src/filters/lighting.rs
+++ b/src/filters/lighting.rs
@@ -12,7 +12,7 @@ use crate::drawing_ctx::DrawingCtx;
 use crate::element::{Draw, Element, ElementResult, SetAttributes};
 use crate::filters::{
     context::{FilterContext, FilterOutput, FilterResult},
-    FilterEffect, FilterError, FilterRender, PrimitiveWithInput,
+    FilterEffect, FilterError, FilterRender, Input, Primitive,
 };
 use crate::node::{CascadedValues, Node, NodeBorrow};
 use crate::parsers::{NonNegative, NumberOptionalNumber, ParseValue};
@@ -308,7 +308,8 @@ fn transform_dist(t: Transform, d: f64) -> f64 {
 
 /// The `feDiffuseLighting` filter primitives.
 pub struct FeDiffuseLighting {
-    base: PrimitiveWithInput,
+    base: Primitive,
+    in1: Input,
     surface_scale: f64,
     kernel_unit_length: Option<(f64, f64)>,
     diffuse_constant: f64,
@@ -317,7 +318,8 @@ pub struct FeDiffuseLighting {
 impl Default for FeDiffuseLighting {
     fn default() -> Self {
         Self {
-            base: PrimitiveWithInput::new(),
+            base: Primitive::new(),
+            in1: Default::default(),
             surface_scale: 1.0,
             kernel_unit_length: None,
             diffuse_constant: 1.0,
@@ -327,7 +329,7 @@ impl Default for FeDiffuseLighting {
 
 impl SetAttributes for FeDiffuseLighting {
     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)?;
+        self.in1 = self.base.parse_one_input(attrs)?;
 
         for (attr, value) in attrs.iter() {
             match attr.expanded() {
@@ -370,7 +372,8 @@ impl FeDiffuseLighting {
 
 /// The `feSpecularLighting` filter primitives.
 pub struct FeSpecularLighting {
-    base: PrimitiveWithInput,
+    base: Primitive,
+    in1: Input,
     surface_scale: f64,
     kernel_unit_length: Option<(f64, f64)>,
     specular_constant: f64,
@@ -380,7 +383,8 @@ pub struct FeSpecularLighting {
 impl Default for FeSpecularLighting {
     fn default() -> Self {
         Self {
-            base: PrimitiveWithInput::new(),
+            base: Primitive::new(),
+            in1: Default::default(),
             surface_scale: 1.0,
             kernel_unit_length: None,
             specular_constant: 1.0,
@@ -391,7 +395,7 @@ impl Default for FeSpecularLighting {
 
 impl SetAttributes for FeSpecularLighting {
     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)?;
+        self.in1 = self.base.parse_one_input(attrs)?;
 
         for (attr, value) in attrs.iter() {
             match attr.expanded() {
@@ -457,11 +461,11 @@ macro_rules! impl_lighting_filter {
                 acquired_nodes: &mut AcquiredNodes<'_>,
                 draw_ctx: &mut DrawingCtx,
             ) -> Result<FilterResult, FilterError> {
-                let input = self.base.get_input(ctx, acquired_nodes, draw_ctx)?;
+                let input_1 = ctx.get_input(acquired_nodes, draw_ctx, &self.in1)?;
                 let mut bounds = self
                     .base
                     .get_bounds(ctx)?
-                    .add_input(&input)
+                    .add_input(&input_1)
                     .into_irect(ctx, draw_ctx);
                 let original_bounds = bounds;
 
@@ -469,7 +473,7 @@ macro_rules! impl_lighting_filter {
                     .kernel_unit_length
                     .map(|(dx, dy)| ctx.paffine().transform_distance(dx, dy));
 
-                let mut input_surface = input.surface().clone();
+                let mut input_surface = input_1.surface().clone();
 
                 if let Some((ox, oy)) = scale {
                     // Scale the input surface to match kernel_unit_length.
diff --git a/src/filters/merge.rs b/src/filters/merge.rs
index 478a6510..0ba0d8b1 100644
--- a/src/filters/merge.rs
+++ b/src/filters/merge.rs
@@ -35,7 +35,7 @@ impl Default for FeMerge {
 
 impl SetAttributes for FeMerge {
     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)
+        self.base.parse_no_inputs(attrs)
     }
 }
 
diff --git a/src/filters/mod.rs b/src/filters/mod.rs
index d6286720..e69b6d97 100644
--- a/src/filters/mod.rs
+++ b/src/filters/mod.rs
@@ -2,7 +2,6 @@
 
 use cssparser::{BasicParseError, Parser};
 use markup5ever::{expanded_name, local_name, namespace_url, ns};
-use std::ops::Deref;
 use std::time::Instant;
 
 use crate::bbox::BoundingBox;
@@ -10,7 +9,7 @@ use crate::coord_units::CoordUnits;
 use crate::document::AcquiredNodes;
 use crate::drawing_ctx::DrawingCtx;
 use crate::element::{Draw, ElementResult, SetAttributes};
-use crate::error::{ParseError, RenderingError};
+use crate::error::{ElementError, ParseError, RenderingError};
 use crate::length::*;
 use crate::node::{CascadedValues, Node, NodeBorrow};
 use crate::parsers::{CustomIdent, Parse, ParseValue};
@@ -24,7 +23,7 @@ mod bounds;
 use self::bounds::BoundsBuilder;
 
 pub mod context;
-use self::context::{FilterContext, FilterInput, FilterResult};
+use self::context::{FilterContext, FilterResult};
 
 mod error;
 use self::error::FilterError;
@@ -122,12 +121,6 @@ impl Parse for Input {
     }
 }
 
-/// The base node for filter primitives which accept input.
-struct PrimitiveWithInput {
-    base: Primitive,
-    in1: Input,
-}
-
 impl Primitive {
     /// Constructs a new `Primitive` with empty properties.
     #[inline]
@@ -179,8 +172,14 @@ fn check_units<N: Normalize, V: Validate>(
     }
 }
 
-impl SetAttributes for Primitive {
-    fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
+impl Primitive {
+    fn parse_standard_attributes(
+        &mut self,
+        attrs: &Attributes,
+    ) -> Result<(Input, Input), ElementError> {
+        let mut input_1 = Input::Unspecified;
+        let mut input_2 = Input::Unspecified;
+
         for (attr, value) in attrs.iter() {
             match attr.expanded() {
                 expanded_name!("", "x") => self.x = attr.parse(value)?,
@@ -188,56 +187,27 @@ impl SetAttributes for Primitive {
                 expanded_name!("", "width") => self.width = attr.parse(value)?,
                 expanded_name!("", "height") => self.height = attr.parse(value)?,
                 expanded_name!("", "result") => self.result = attr.parse(value)?,
+                expanded_name!("", "in") => input_1 = attr.parse(value)?,
+                expanded_name!("", "in2") => input_2 = attr.parse(value)?,
                 _ => (),
             }
         }
 
-        Ok(())
-    }
-}
-
-impl PrimitiveWithInput {
-    /// Constructs a new `PrimitiveWithInput` with empty properties.
-    #[inline]
-    fn new() -> PrimitiveWithInput {
-        PrimitiveWithInput {
-            base: Primitive::new(),
-            in1: Default::default(),
-        }
-    }
-
-    /// Returns the input Cairo surface for this filter primitive.
-    #[inline]
-    fn get_input(
-        &self,
-        ctx: &FilterContext,
-        acquired_nodes: &mut AcquiredNodes<'_>,
-        draw_ctx: &mut DrawingCtx,
-    ) -> Result<FilterInput, FilterError> {
-        ctx.get_input(acquired_nodes, draw_ctx, &self.in1)
+        Ok((input_1, input_2))
     }
-}
-
-impl SetAttributes for PrimitiveWithInput {
-    fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)?;
-
-        for (attr, value) in attrs.iter() {
-            if let expanded_name!("", "in") = attr.expanded() {
-                self.in1 = attr.parse(value)?;
-            }
-        }
 
+    pub fn parse_no_inputs(&mut self, attrs: &Attributes) -> ElementResult {
+        let (_, _) = self.parse_standard_attributes(attrs)?;
         Ok(())
     }
-}
 
-impl Deref for PrimitiveWithInput {
-    type Target = Primitive;
+    pub fn parse_one_input(&mut self, attrs: &Attributes) -> Result<Input, ElementError> {
+        let (input_1, _) = self.parse_standard_attributes(attrs)?;
+        Ok(input_1)
+    }
 
-    #[inline]
-    fn deref(&self) -> &Self::Target {
-        &self.base
+    pub fn parse_two_inputs(&mut self, attrs: &Attributes) -> Result<(Input, Input), ElementError> {
+        self.parse_standard_attributes(attrs)
     }
 }
 
diff --git a/src/filters/morphology.rs b/src/filters/morphology.rs
index 8a1628c7..c88efbea 100644
--- a/src/filters/morphology.rs
+++ b/src/filters/morphology.rs
@@ -18,7 +18,7 @@ use crate::surface_utils::{
 use crate::xml::Attributes;
 
 use super::context::{FilterContext, FilterOutput, FilterResult};
-use super::{FilterEffect, FilterError, FilterRender, PrimitiveWithInput};
+use super::{FilterEffect, FilterError, FilterRender, Input, Primitive};
 
 /// Enumeration of the possible morphology operations.
 enum Operator {
@@ -28,7 +28,8 @@ enum Operator {
 
 /// The `feMorphology` filter primitive.
 pub struct FeMorphology {
-    base: PrimitiveWithInput,
+    base: Primitive,
+    in1: Input,
     operator: Operator,
     radius: (f64, f64),
 }
@@ -38,7 +39,8 @@ impl Default for FeMorphology {
     #[inline]
     fn default() -> FeMorphology {
         FeMorphology {
-            base: PrimitiveWithInput::new(),
+            base: Primitive::new(),
+            in1: Default::default(),
             operator: Operator::Erode,
             radius: (0.0, 0.0),
         }
@@ -47,7 +49,7 @@ impl Default for FeMorphology {
 
 impl SetAttributes for FeMorphology {
     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)?;
+        self.in1 = self.base.parse_one_input(attrs)?;
 
         for (attr, value) in attrs.iter() {
             match attr.expanded() {
@@ -72,11 +74,11 @@ impl FilterRender for FeMorphology {
         acquired_nodes: &mut AcquiredNodes<'_>,
         draw_ctx: &mut DrawingCtx,
     ) -> Result<FilterResult, FilterError> {
-        let input = self.base.get_input(ctx, acquired_nodes, draw_ctx)?;
+        let input_1 = ctx.get_input(acquired_nodes, draw_ctx, &self.in1)?;
         let bounds = self
             .base
             .get_bounds(ctx)?
-            .add_input(&input)
+            .add_input(&input_1)
             .into_irect(ctx, draw_ctx);
 
         let (rx, ry) = self.radius;
@@ -88,11 +90,11 @@ impl FilterRender for FeMorphology {
         let mut surface = ExclusiveImageSurface::new(
             ctx.source_graphic().width(),
             ctx.source_graphic().height(),
-            input.surface().surface_type(),
+            input_1.surface().surface_type(),
         )?;
 
         surface.modify(&mut |data, stride| {
-            for (x, y, _pixel) in Pixels::within(input.surface(), bounds) {
+            for (x, y, _pixel) in Pixels::within(input_1.surface(), bounds) {
                 // Compute the kernel rectangle bounds.
                 let kernel_bounds = IRect::new(
                     (f64::from(x) - rx).floor() as i32,
@@ -114,9 +116,12 @@ impl FilterRender for FeMorphology {
                     a: initial,
                 };
 
-                for (_x, _y, pixel) in
-                    PixelRectangle::within(&input.surface(), bounds, kernel_bounds, EdgeMode::None)
-                {
+                for (_x, _y, pixel) in PixelRectangle::within(
+                    &input_1.surface(),
+                    bounds,
+                    kernel_bounds,
+                    EdgeMode::None,
+                ) {
                     let op = match self.operator {
                         Operator::Erode => min,
                         Operator::Dilate => max,
diff --git a/src/filters/offset.rs b/src/filters/offset.rs
index 3446209a..213a5c77 100644
--- a/src/filters/offset.rs
+++ b/src/filters/offset.rs
@@ -8,11 +8,12 @@ use crate::parsers::ParseValue;
 use crate::xml::Attributes;
 
 use super::context::{FilterContext, FilterOutput, FilterResult};
-use super::{FilterEffect, FilterError, FilterRender, PrimitiveWithInput};
+use super::{FilterEffect, FilterError, FilterRender, Input, Primitive};
 
 /// The `feOffset` filter primitive.
 pub struct FeOffset {
-    base: PrimitiveWithInput,
+    base: Primitive,
+    in1: Input,
     dx: f64,
     dy: f64,
 }
@@ -22,7 +23,8 @@ impl Default for FeOffset {
     #[inline]
     fn default() -> FeOffset {
         FeOffset {
-            base: PrimitiveWithInput::new(),
+            base: Primitive::new(),
+            in1: Default::default(),
             dx: 0f64,
             dy: 0f64,
         }
@@ -31,7 +33,7 @@ impl Default for FeOffset {
 
 impl SetAttributes for FeOffset {
     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)?;
+        self.in1 = self.base.parse_one_input(attrs)?;
 
         for (attr, value) in attrs.iter() {
             match attr.expanded() {
@@ -53,16 +55,16 @@ impl FilterRender for FeOffset {
         acquired_nodes: &mut AcquiredNodes<'_>,
         draw_ctx: &mut DrawingCtx,
     ) -> Result<FilterResult, FilterError> {
-        let input = self.base.get_input(ctx, acquired_nodes, draw_ctx)?;
+        let input_1 = ctx.get_input(acquired_nodes, draw_ctx, &self.in1)?;
         let bounds = self
             .base
             .get_bounds(ctx)?
-            .add_input(&input)
+            .add_input(&input_1)
             .into_irect(ctx, draw_ctx);
 
         let (dx, dy) = ctx.paffine().transform_distance(self.dx, self.dy);
 
-        let surface = input.surface().offset(bounds, dx, dy)?;
+        let surface = input_1.surface().offset(bounds, dx, dy)?;
 
         Ok(FilterResult {
             name: self.base.result.clone(),
diff --git a/src/filters/tile.rs b/src/filters/tile.rs
index 1638d8dd..986eeff7 100644
--- a/src/filters/tile.rs
+++ b/src/filters/tile.rs
@@ -5,11 +5,12 @@ use crate::node::Node;
 use crate::xml::Attributes;
 
 use super::context::{FilterContext, FilterInput, FilterOutput, FilterResult};
-use super::{FilterEffect, FilterError, FilterRender, PrimitiveWithInput};
+use super::{FilterEffect, FilterError, FilterRender, Input, Primitive};
 
 /// The `feTile` filter primitive.
 pub struct FeTile {
-    base: PrimitiveWithInput,
+    base: Primitive,
+    in1: Input,
 }
 
 impl Default for FeTile {
@@ -17,14 +18,16 @@ impl Default for FeTile {
     #[inline]
     fn default() -> FeTile {
         FeTile {
-            base: PrimitiveWithInput::new(),
+            base: Primitive::new(),
+            in1: Default::default(),
         }
     }
 }
 
 impl SetAttributes for FeTile {
     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)
+        self.in1 = self.base.parse_one_input(attrs)?;
+        Ok(())
     }
 }
 
@@ -36,12 +39,12 @@ impl FilterRender for FeTile {
         acquired_nodes: &mut AcquiredNodes<'_>,
         draw_ctx: &mut DrawingCtx,
     ) -> Result<FilterResult, FilterError> {
-        let input = self.base.get_input(ctx, acquired_nodes, draw_ctx)?;
+        let input_1 = ctx.get_input(acquired_nodes, draw_ctx, &self.in1)?;
 
         // feTile doesn't consider its inputs in the filter primitive subregion calculation.
         let bounds = self.base.get_bounds(ctx)?.into_irect(ctx, draw_ctx);
 
-        let surface = match input {
+        let surface = match input_1 {
             FilterInput::StandardInput(input_surface) => input_surface,
             FilterInput::PrimitiveOutput(FilterOutput {
                 surface: input_surface,
diff --git a/src/filters/turbulence.rs b/src/filters/turbulence.rs
index dfdaedb7..eac10500 100644
--- a/src/filters/turbulence.rs
+++ b/src/filters/turbulence.rs
@@ -58,7 +58,7 @@ impl Default for FeTurbulence {
 
 impl SetAttributes for FeTurbulence {
     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
-        self.base.set_attributes(attrs)?;
+        self.base.parse_no_inputs(attrs)?;
 
         for (attr, value) in attrs.iter() {
             match attr.expanded() {


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