[librsvg: 5/15] feMerge - extract the list of inputs to merge before doing the merging




commit 1d11da952d6e37b3b7340e3ad468134016edb969
Author: Federico Mena Quintero <federico gnome org>
Date:   Mon Mar 8 17:47:17 2021 -0600

    feMerge - extract the list of inputs to merge before doing the merging
    
    For filter primitives that require parameters from their nodes'
    children, we'll first build that list of parameters by walking the
    children or whatever, and then doing the final processing on nice data.

 src/filters/merge.rs | 87 ++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 68 insertions(+), 19 deletions(-)
---
diff --git a/src/filters/merge.rs b/src/filters/merge.rs
index 296055d0..f6aa6f8e 100644
--- a/src/filters/merge.rs
+++ b/src/filters/merge.rs
@@ -18,7 +18,7 @@ pub struct FeMerge {
 }
 
 /// The `<feMergeNode>` element.
-#[derive(Default)]
+#[derive(Clone, Debug, Default, PartialEq)]
 pub struct FeMergeNode {
     in_: Option<Input>,
 }
@@ -83,31 +83,23 @@ impl FilterRender for FeMerge {
         acquired_nodes: &mut AcquiredNodes<'_>,
         draw_ctx: &mut DrawingCtx,
     ) -> Result<FilterResult, FilterError> {
-        // Compute the filter bounds, taking each child node's input into account.
-        let mut bounds = self.base.get_bounds(ctx)?;
-        for child in node.children().filter(|c| c.is_element()) {
-            let elt = child.borrow_element();
-
-            if elt.is_in_error() {
-                return Err(FilterError::ChildNodeInError);
-            }
+        let parameters = get_parameters(node)?;
 
-            if let Element::FeMergeNode(ref merge_node) = *elt {
-                let input = ctx.get_input(acquired_nodes, draw_ctx, merge_node.in_.as_ref())?;
-                bounds = bounds.add_input(&input);
-            }
+        // Compute the filter bounds, taking each feMergeNode's input into account.
+        let mut bounds = self.base.get_bounds(ctx)?;
+        for merge_node in &parameters {
+            let input = ctx.get_input(acquired_nodes, draw_ctx, merge_node.in_.as_ref())?;
+            bounds = bounds.add_input(&input);
         }
 
         let bounds = bounds.into_irect(ctx, draw_ctx);
 
         // Now merge them all.
         let mut output_surface = None;
-        for child in node.children().filter(|c| c.is_element()) {
-            if let Element::FeMergeNode(ref merge_node) = *child.borrow_element() {
-                output_surface = merge_node
-                    .render(ctx, acquired_nodes, draw_ctx, bounds, output_surface)
-                    .ok();
-            }
+        for merge_node in &parameters {
+            output_surface = merge_node
+                .render(ctx, acquired_nodes, draw_ctx, bounds, output_surface)
+                .ok();
         }
 
         let surface = match output_surface {
@@ -132,3 +124,60 @@ impl FilterEffect for FeMerge {
         true
     }
 }
+
+/// Takes a feMerge and walks its children to produce a list of feMergeNode arguments.
+fn get_parameters(node: &Node) -> Result<Vec<FeMergeNode>, FilterError> {
+    let mut merge_nodes = Vec::new();
+
+    for child in node.children().filter(|c| c.is_element()) {
+        let elt = child.borrow_element();
+
+        if elt.is_in_error() {
+            return Err(FilterError::ChildNodeInError);
+        }
+
+        if let Element::FeMergeNode(ref merge_node) = *elt {
+            merge_nodes.push(merge_node.element_impl.clone());
+        }
+    }
+
+    Ok(merge_nodes)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::document::Document;
+
+    #[test]
+    fn extracts_parameters() {
+        let document = Document::load_from_bytes(
+            br#"<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg";>
+  <filter id="filter">
+    <feMerge id="merge">
+      <feMergeNode in="SourceGraphic"/>
+      <feMergeNode in="SourceAlpha"/>
+    </feMerge>
+  </filter>
+</svg>
+"#,
+        );
+
+        let merge = document.lookup_internal_node("merge").unwrap();
+
+        let params = get_parameters(&merge).unwrap();
+
+        assert_eq!(
+            &params[..],
+            vec![
+                FeMergeNode {
+                    in_: Some(Input::SourceGraphic)
+                },
+                FeMergeNode {
+                    in_: Some(Input::SourceAlpha)
+                },
+            ]
+        );
+    }
+}


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