[librsvg: 26/30] pattern: calculate transforms inside UserSpacePattern




commit b1a327838975c05faa0dd7240d10f8c71bf1d052
Author: Paolo Borelli <pborelli gnome org>
Date:   Sun Dec 27 15:33:52 2020 +0100

    pattern: calculate transforms inside UserSpacePattern
    
    As described in the preexisting FIXME comment, calculate the
    transforms in the pattern code instead of doing it in drawing_ctx.

 src/drawing_ctx.rs | 83 ++++++++++------------------------------------------
 src/pattern.rs     | 86 +++++++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 81 insertions(+), 88 deletions(-)
---
diff --git a/src/drawing_ctx.rs b/src/drawing_ctx.rs
index 33b2d129..f2962cd5 100644
--- a/src/drawing_ctx.rs
+++ b/src/drawing_ctx.rs
@@ -25,7 +25,7 @@ use crate::marker;
 use crate::node::{CascadedValues, Node, NodeBorrow, NodeDraw};
 use crate::paint_server::{PaintServer, UserSpacePaintSource};
 use crate::path_builder::*;
-use crate::pattern::{PatternContentUnits, PatternUnits, UserSpacePattern};
+use crate::pattern::UserSpacePattern;
 use crate::properties::ComputedValues;
 use crate::property_defs::{
     ClipRule, FillRule, Filter, MixBlendMode, Opacity, Overflow, PaintTarget, ShapeRendering,
@@ -981,88 +981,37 @@ impl DrawingCtx {
         acquired_nodes: &mut AcquiredNodes<'_>,
         opacity: UnitInterval,
     ) -> Result<bool, RenderingError> {
-        // Work out the size of the rectangle so it takes into account the object bounding box
-        let (bbwscale, bbhscale) = match pattern.units {
-            PatternUnits(CoordUnits::ObjectBoundingBox) => pattern.bbox.rect.unwrap().size(),
-            PatternUnits(CoordUnits::UserSpaceOnUse) => (1.0, 1.0),
-        };
+        if approx_eq!(f64, pattern.width, 0.0) || approx_eq!(f64, pattern.height, 0.0) {
+            return Ok(false);
+        }
 
         let taffine = self.get_transform().pre_transform(&pattern.transform);
 
         let mut scwscale = (taffine.xx.powi(2) + taffine.xy.powi(2)).sqrt();
         let mut schscale = (taffine.yx.powi(2) + taffine.yy.powi(2)).sqrt();
 
-        let scaled_width = pattern.rect.width() * bbwscale;
-        let scaled_height = pattern.rect.height() * bbhscale;
-
-        if approx_eq!(f64, scaled_width, 0.0) || approx_eq!(f64, scaled_height, 0.0) {
-            return Ok(false);
-        }
-
-        let pw: i32 = (scaled_width * scwscale) as i32;
-        let ph: i32 = (scaled_height * schscale) as i32;
+        let pw: i32 = (pattern.width * scwscale) as i32;
+        let ph: i32 = (pattern.height * schscale) as i32;
 
         if pw < 1 || ph < 1 {
             return Ok(false);
         }
 
-        scwscale = f64::from(pw) / scaled_width;
-        schscale = f64::from(ph) / scaled_height;
-
-        // Create the pattern coordinate system
-        let mut affine = match pattern.units {
-            PatternUnits(CoordUnits::ObjectBoundingBox) => {
-                let bbrect = pattern.bbox.rect.unwrap();
-                Transform::new_translate(
-                    bbrect.x0 + pattern.rect.x0 * bbrect.width(),
-                    bbrect.y0 + pattern.rect.y0 * bbrect.height(),
-                )
-            }
-
-            PatternUnits(CoordUnits::UserSpaceOnUse) => {
-                Transform::new_translate(pattern.rect.x0, pattern.rect.y0)
-            }
-        };
+        scwscale = f64::from(pw) / pattern.width;
+        schscale = f64::from(ph) / pattern.height;
 
         // Apply the pattern transform
-        affine = affine.post_transform(&pattern.transform);
-
-        let mut caffine: Transform;
-
-        // Create the pattern contents coordinate system
-        let _params = if let Some(vbox) = pattern.vbox {
-            // If there is a vbox, use that
-            let r = pattern
-                .preserve_aspect_ratio
-                .compute(&vbox, &Rect::from_size(scaled_width, scaled_height));
-
-            let sw = r.width() / vbox.width();
-            let sh = r.height() / vbox.height();
-            let x = r.x0 - vbox.x0 * sw;
-            let y = r.y0 - vbox.y0 * sh;
-
-            caffine = Transform::new_scale(sw, sh).pre_translate(x, y);
-
-            self.push_view_box(vbox.width(), vbox.height())
+        let (affine, caffine) = if scwscale.approx_eq_cairo(1.0) && schscale.approx_eq_cairo(1.0) {
+            (pattern.coord_transform, pattern.content_transform)
         } else {
-            let PatternContentUnits(content_units) = pattern.content_units;
-
-            caffine = if content_units == CoordUnits::ObjectBoundingBox {
-                // If coords are in terms of the bounding box, use them
-                let (bbw, bbh) = pattern.bbox.rect.unwrap().size();
-                Transform::new_scale(bbw, bbh)
-            } else {
-                Transform::identity()
-            };
-
-            self.push_coord_units(content_units)
+            (
+                pattern
+                    .coord_transform
+                    .pre_scale(1.0 / scwscale, 1.0 / schscale),
+                pattern.content_transform.post_scale(scwscale, schscale),
+            )
         };
 
-        if !scwscale.approx_eq_cairo(1.0) || !schscale.approx_eq_cairo(1.0) {
-            caffine = caffine.post_scale(scwscale, schscale);
-            affine = affine.pre_scale(1.0 / scwscale, 1.0 / schscale);
-        }
-
         // Draw to another surface
 
         let cr_save = self.cr.clone();
diff --git a/src/pattern.rs b/src/pattern.rs
index 05d57783..83a0836e 100644
--- a/src/pattern.rs
+++ b/src/pattern.rs
@@ -7,7 +7,7 @@ use crate::aspect_ratio::*;
 use crate::bbox::BoundingBox;
 use crate::coord_units::CoordUnits;
 use crate::document::{AcquiredNodes, NodeId, NodeStack};
-use crate::drawing_ctx::DrawingCtx;
+use crate::drawing_ctx::{DrawingCtx, ViewParams};
 use crate::element::{Draw, Element, ElementResult, SetAttributes};
 use crate::error::*;
 use crate::href::{is_href, set_href};
@@ -105,13 +105,11 @@ pub struct ResolvedPattern {
 
 /// Pattern normalized to user-space units.
 pub struct UserSpacePattern {
-    pub units: PatternUnits,
-    pub content_units: PatternContentUnits,
-    pub bbox: BoundingBox,
-    pub vbox: Option<ViewBox>,
-    pub preserve_aspect_ratio: AspectRatio,
+    pub width: f64,
+    pub height: f64,
     pub transform: Transform,
-    pub rect: Rect,
+    pub coord_transform: Transform,
+    pub content_transform: Transform,
     pub node_with_children: Node,
 }
 
@@ -315,6 +313,15 @@ impl ResolvedPattern {
         }
     }
 
+    fn get_rect(&self, values: &ComputedValues, params: &ViewParams) -> Rect {
+        let x = self.x.normalize(&values, &params);
+        let y = self.y.normalize(&values, &params);
+        let w = self.width.normalize(&values, &params);
+        let h = self.height.normalize(&values, &params);
+
+        Rect::new(x, y, x + w, y + h)
+    }
+
     pub fn to_user_space(
         &self,
         bbox: &BoundingBox,
@@ -325,25 +332,62 @@ impl ResolvedPattern {
 
         let params = draw_ctx.push_coord_units(self.units.0);
 
-        let x = self.x.normalize(&values, &params);
-        let y = self.y.normalize(&values, &params);
-        let w = self.width.normalize(&values, &params);
-        let h = self.height.normalize(&values, &params);
+        let rect = self.get_rect(values, &params);
+        let bbrect = bbox.rect.unwrap();
+
+        // Create the pattern coordinate system
+        let (width, height, coord_transform) = match self.units {
+            PatternUnits(CoordUnits::ObjectBoundingBox) => (
+                rect.width() * bbrect.width(),
+                rect.height() * bbrect.height(),
+                Transform::new_translate(
+                    bbrect.x0 + rect.x0 * bbrect.width(),
+                    bbrect.y0 + rect.y0 * bbrect.height(),
+                ),
+            ),
+            PatternUnits(CoordUnits::UserSpaceOnUse) => (
+                rect.width(),
+                rect.height(),
+                Transform::new_translate(rect.x0, rect.y0),
+            ),
+        };
+
+        let coord_transform = coord_transform.post_transform(&self.transform);
+
+        // Create the pattern contents coordinate system
+        let content_transform = if let Some(vbox) = self.vbox {
+            // If there is a vbox, use that
+            let r = self
+                .preserve_aspect_ratio
+                .compute(&vbox, &Rect::from_size(width, height));
+
+            let sw = r.width() / vbox.width();
+            let sh = r.height() / vbox.height();
+            let x = r.x0 - vbox.x0 * sw;
+            let y = r.y0 - vbox.y0 * sh;
+
+            let _params = draw_ctx.push_view_box(vbox.width(), vbox.height());
 
-        let rect = Rect::new(x, y, x + w, y + h);
+            Transform::new_scale(sw, sh).pre_translate(x, y)
+        } else {
+            let PatternContentUnits(content_units) = self.content_units;
+
+            let _params = draw_ctx.push_coord_units(content_units);
 
-        // FIXME: eventually UserSpacePattern should contain fewer fields; we should be able
-        // to figure out all the transforms in advance and just put them there, rather than
-        // leaving that responsibility to DrawingCtx.set_pattern().
+            match content_units {
+                CoordUnits::ObjectBoundingBox => {
+                    Transform::new_scale(bbrect.width(), bbrect.height())
+                }
+                CoordUnits::UserSpaceOnUse => Transform::identity(),
+            }
+        };
 
         Some(UserSpacePattern {
-            units: self.units,
-            content_units: self.content_units,
-            vbox: self.vbox,
-            bbox: *bbox,
-            preserve_aspect_ratio: self.preserve_aspect_ratio,
+            width,
+            height,
             transform: self.transform,
-            rect,
+            coord_transform,
+            content_transform,
             node_with_children,
         })
     }


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