[librsvg: 7/15] Normalize the Filter element into a ResolvedFilter as early as possible




commit 4487bc25bb583310a0bc30c6281f99c0b0814ea8
Author: Federico Mena Quintero <federico gnome org>
Date:   Thu Apr 8 14:06:32 2021 -0500

    Normalize the Filter element into a ResolvedFilter as early as possible
    
    This finally lets us remove all the length normalization while running the
    filter primitives.

 src/filter.rs          | 17 +++++++++++++++--
 src/filters/context.rs | 17 ++++++-----------
 src/filters/mod.rs     |  9 ++++++++-
 3 files changed, 29 insertions(+), 14 deletions(-)
---
diff --git a/src/filter.rs b/src/filter.rs
index 7ea31c81..a1568bfc 100644
--- a/src/filter.rs
+++ b/src/filter.rs
@@ -26,6 +26,13 @@ pub struct Filter {
     primitive_units: CoordUnits,
 }
 
+/// A <filter> element definition in user-space coordinates.
+pub struct ResolvedFilter {
+    pub rect: Rect,
+    pub filter_units: CoordUnits,
+    pub primitive_units: CoordUnits,
+}
+
 impl Default for Filter {
     /// Constructs a new `Filter` with default properties.
     fn default() -> Self {
@@ -49,7 +56,7 @@ impl Filter {
         self.primitive_units
     }
 
-    pub fn get_rect(&self, values: &ComputedValues, params: &ViewParams) -> Rect {
+    pub fn resolve(&self, values: &ComputedValues, params: &ViewParams) -> ResolvedFilter {
         // With filterunits == ObjectBoundingBox, lengths represent fractions or percentages of the
         // referencing node. No units are allowed (it's checked during attribute parsing).
         let (x, y, w, h) = if self.filter_units == CoordUnits::ObjectBoundingBox {
@@ -68,7 +75,13 @@ impl Filter {
             )
         };
 
-        Rect::new(x, y, x + w, y + h)
+        let rect = Rect::new(x, y, x + w, y + h);
+
+        ResolvedFilter {
+            rect,
+            filter_units: self.filter_units,
+            primitive_units: self.primitive_units,
+        }
     }
 }
 
diff --git a/src/filters/context.rs b/src/filters/context.rs
index adc97732..ee705a13 100644
--- a/src/filters/context.rs
+++ b/src/filters/context.rs
@@ -5,7 +5,7 @@ use crate::bbox::BoundingBox;
 use crate::coord_units::CoordUnits;
 use crate::document::AcquiredNodes;
 use crate::drawing_ctx::DrawingCtx;
-use crate::filter::Filter;
+use crate::filter::ResolvedFilter;
 use crate::paint_server::UserSpacePaintSource;
 use crate::parsers::CustomIdent;
 use crate::properties::ComputedValues;
@@ -100,7 +100,7 @@ pub struct FilterContext {
 impl FilterContext {
     /// Creates a new `FilterContext`.
     pub fn new(
-        filter: &Filter,
+        filter: &ResolvedFilter,
         computed_from_node_being_filtered: &ComputedValues,
         stroke_paint: UserSpacePaintSource,
         fill_paint: UserSpacePaintSource,
@@ -113,8 +113,7 @@ impl FilterContext {
         // However, with userSpaceOnUse it's still possible to create images with a filter.
         let bbox_rect = node_bbox.rect.unwrap_or_default();
 
-        let filter_units = filter.get_filter_units();
-        let affine = match filter_units {
+        let affine = match filter.filter_units {
             CoordUnits::UserSpaceOnUse => draw_transform,
             CoordUnits::ObjectBoundingBox => Transform::new_unchecked(
                 bbox_rect.width(),
@@ -127,8 +126,7 @@ impl FilterContext {
             .post_transform(&draw_transform),
         };
 
-        let primitive_units = filter.get_primitive_units();
-        let paffine = match primitive_units {
+        let paffine = match filter.primitive_units {
             CoordUnits::UserSpaceOnUse => draw_transform,
             CoordUnits::ObjectBoundingBox => Transform::new_unchecked(
                 bbox_rect.width(),
@@ -148,13 +146,10 @@ impl FilterContext {
         }
 
         let effects_region = {
-            let params = draw_ctx.push_coord_units(filter_units);
-            let filter_rect = filter.get_rect(&computed_from_node_being_filtered, &params);
-
             let mut bbox = BoundingBox::new();
             let other_bbox = BoundingBox::new()
                 .with_transform(affine)
-                .with_rect(filter_rect);
+                .with_rect(filter.rect);
 
             // At this point all of the previous viewbox and matrix business gets converted to pixel
             // coordinates in the final surface, because bbox is created with an identity transform.
@@ -178,7 +173,7 @@ impl FilterContext {
             background_surface: OnceCell::new(),
             stroke_paint_surface: OnceCell::new(),
             fill_paint_surface: OnceCell::new(),
-            primitive_units,
+            primitive_units: filter.primitive_units,
             effects_region,
             _affine: affine,
             paffine,
diff --git a/src/filters/mod.rs b/src/filters/mod.rs
index d278421c..3c78f5ad 100644
--- a/src/filters/mod.rs
+++ b/src/filters/mod.rs
@@ -259,8 +259,15 @@ pub fn render(
         .resolve(acquired_nodes, values.fill_opacity().0, values.color().0)?
         .to_user_space(&node_bbox, draw_ctx, values);
 
+    let resolved_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.resolve(values, &params)
+    };
+
     if let Ok(mut filter_ctx) = FilterContext::new(
-        &filter,
+        &resolved_filter,
         computed_from_node_being_filtered,
         stroke_paint_source,
         fill_paint_source,


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