[librsvg: 10/17] filters::render - Collect the user space primitives early




commit 0090999ffeffe0585fac999fe21543b12747a557
Author: Federico Mena Quintero <federico gnome org>
Date:   Fri Apr 16 19:17:06 2021 -0500

    filters::render - Collect the user space primitives early

 src/filters/context.rs |   3 +-
 src/filters/mod.rs     | 136 ++++++++++++++++++++++++++++++-------------------
 2 files changed, 84 insertions(+), 55 deletions(-)
---
diff --git a/src/filters/context.rs b/src/filters/context.rs
index 70c9bd38..b37282c9 100644
--- a/src/filters/context.rs
+++ b/src/filters/context.rs
@@ -257,13 +257,12 @@ impl FilterContext {
 
     /// Stores a filter primitive result into the context.
     #[inline]
-    pub fn store_result(&mut self, result: FilterResult) -> Result<(), FilterError> {
+    pub fn store_result(&mut self, result: FilterResult) {
         if let Some(name) = result.name {
             self.previous_results.insert(name, result.output.clone());
         }
 
         self.last_result = Some(result.output);
-        Ok(())
     }
 
     /// Returns the paffine matrix.
diff --git a/src/filters/mod.rs b/src/filters/mod.rs
index dbc68f32..19ef1185 100644
--- a/src/filters/mod.rs
+++ b/src/filters/mod.rs
@@ -244,7 +244,24 @@ pub fn render(
     let filter_node = &*filter_node;
     assert!(is_element_of_type!(filter_node, Filter));
 
-    let primitive_nodes: Vec<Node> = filter_node
+    let filter_element = filter_node.borrow_element();
+
+    if filter_element.is_in_error() {
+        return Ok(source_surface);
+    }
+
+    let user_space_filter = {
+        let filter_values = filter_element.get_computed_values();
+
+        let filter = borrow_element_as!(filter_node, Filter);
+
+        // This is in a temporary scope so we don't leave the coord_units pushed during
+        // the execution of all the filter primitives.
+        let params = draw_ctx.push_coord_units(filter.get_filter_units());
+        filter.to_user_space(filter_values, &params)
+    };
+
+    let res = filter_node
         .children()
         .filter(|c| c.is_element())
         // Skip nodes in error.
@@ -259,24 +276,52 @@ pub fn render(
         })
         // Keep only filter primitives (those that implement the Filter trait)
         .filter(|c| c.borrow_element().as_filter_effect().is_some())
-        .map(|n| n.clone())
-        .collect();
+        .map(|primitive_node| {
+            let elt = primitive_node.borrow_element();
+            let effect = elt.as_filter_effect().unwrap();
 
-    let filter_element = filter_node.borrow_element();
+            let primitive_values = elt.get_computed_values();
 
-    if filter_element.is_in_error() {
-        return Ok(source_surface);
-    }
+            let primitive_name = format!("{}", primitive_node);
+
+            effect
+                .resolve(&primitive_node)
+                .map_err(|e| {
+                    rsvg_log!(
+                        "(filter primitive {} returned an error: {})",
+                        primitive_name,
+                        e
+                    );
+                    e
+                })
+                .and_then(|(primitive, params)| {
+                    let user_space_primitive = primitive.to_user_space(
+                        user_space_filter.primitive_units,
+                        primitive_values,
+                        draw_ctx,
+                    );
 
-    let filter_values = filter_element.get_computed_values();
+                    Ok((user_space_primitive, params))
+                })
+        })
+        .collect::<Result<Vec<(UserSpacePrimitive, PrimitiveParams)>, FilterError>>();
 
-    let filter = borrow_element_as!(filter_node, Filter);
+    let primitives = match res {
+        Err(FilterError::CairoError(status)) => {
+            // Exit early on Cairo errors
+            return Err(RenderingError::from(status));
+        }
 
-    let user_space_filter = {
-        // This is in a temporary scope so we don't leave the coord_units pushed during
-        // the execution of all the filter primitives.
-        let params = draw_ctx.push_coord_units(filter.get_filter_units());
-        filter.to_user_space(filter_values, &params)
+        Err(_) => {
+            // ignore other filter errors and just return an empty surface
+            return Ok(SharedImageSurface::empty(
+                source_surface.width(),
+                source_surface.height(),
+                SurfaceType::AlphaOnly,
+            )?);
+        }
+
+        Ok(r) => r,
     };
 
     if let Ok(mut filter_ctx) = FilterContext::new(
@@ -287,33 +332,17 @@ pub fn render(
         transform,
         node_bbox,
     ) {
-        for primitive_node in primitive_nodes {
-            let elt = primitive_node.borrow_element();
-            let effect = elt.as_filter_effect().unwrap();
-
-            let primitive_values = elt.get_computed_values();
-
-            let primitive_name = format!("{}", primitive_node);
-
+        for (user_space_primitive, params) in primitives {
             let start = Instant::now();
 
-            if let Err(err) = effect
-                .resolve(&primitive_node)
-                .and_then(|(primitive, params)| {
-                    let user_space_primitive = primitive.to_user_space(
-                        user_space_filter.primitive_units,
-                        primitive_values,
-                        draw_ctx,
-                    );
-
-                    let output = render_primitive(
-                        &user_space_primitive,
-                        &params,
-                        &filter_ctx,
-                        acquired_nodes,
-                        draw_ctx,
-                    )?;
-
+            match render_primitive(
+                &user_space_primitive,
+                &params,
+                &filter_ctx,
+                acquired_nodes,
+                draw_ctx,
+            ) {
+                Ok(output) => {
                     let elapsed = start.elapsed();
                     rsvg_log!(
                         "(rendered filter primitive {} in\n    {} seconds)",
@@ -321,22 +350,23 @@ pub fn render(
                         elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) / 1e9
                     );
 
-                    Ok(FilterResult {
+                    filter_ctx.store_result(FilterResult {
                         name: user_space_primitive.result,
                         output,
-                    })
-                })
-                .and_then(|result| filter_ctx.store_result(result))
-            {
-                rsvg_log!(
-                    "(filter primitive {} returned an error: {})",
-                    primitive_name,
-                    err
-                );
-
-                // Exit early on Cairo errors. Continue rendering otherwise.
-                if let FilterError::CairoError(status) = err {
-                    return Err(RenderingError::from(status));
+                    });
+                }
+
+                Err(err) => {
+                    rsvg_log!(
+                        "(filter primitive {} returned an error: {})",
+                        params.name(),
+                        err
+                    );
+
+                    // Exit early on Cairo errors. Continue rendering otherwise.
+                    if let FilterError::CairoError(status) = err {
+                        return Err(RenderingError::from(status));
+                    }
                 }
             }
         }


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