[librsvg: 7/11] Normalize patterns before setting them on the cr




commit a1553f0e81a1fd8da33543f95594117c8c26083a
Author: Federico Mena Quintero <federico gnome org>
Date:   Tue Dec 1 10:48:07 2020 -0600

    Normalize patterns before setting them on the cr
    
    Analogous to the changes for gradients, we now have a
    UserSpacePattern.  For now this just has user-space versions of the
    pattern's (x, y, width, height) in the form of UserSpacePattern.rect.
    In the future this struct will hopefully have all the transforms
    already resolved, so that DrawingCtx doesn't have to do all the work.

 src/drawing_ctx.rs | 72 ++++++++++++++++++++++++---------------------------
 src/pattern.rs     | 75 +++++++++++++++++++++++++++++++++++-------------------
 2 files changed, 82 insertions(+), 65 deletions(-)
---
diff --git a/src/drawing_ctx.rs b/src/drawing_ctx.rs
index 7aa0e02e..31195957 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, PaintSource};
 use crate::path_builder::*;
-use crate::pattern::{PatternContentUnits, PatternUnits, ResolvedPattern};
+use crate::pattern::{PatternContentUnits, PatternUnits, UserSpacePattern};
 use crate::properties::ComputedValues;
 use crate::property_defs::{
     ClipRule, FillRule, Filter, MixBlendMode, Opacity, Overflow, PaintTarget, ShapeRendering,
@@ -972,41 +972,23 @@ impl DrawingCtx {
 
     fn set_pattern(
         &mut self,
-        pattern: &ResolvedPattern,
+        pattern: &UserSpacePattern,
         acquired_nodes: &mut AcquiredNodes<'_>,
         opacity: UnitInterval,
-        values: &ComputedValues,
-        bbox: &BoundingBox,
     ) -> Result<bool, RenderingError> {
-        let node = if let Some(n) = pattern.node_with_children() {
-            n
-        } else {
-            // This means we didn't find any children among the fallbacks,
-            // so there is nothing to render.
-            return Ok(false);
-        };
-
-        let units = pattern.get_units();
-        let content_units = pattern.get_content_units();
-        let pattern_transform = pattern.get_transform();
-
-        let params = self.push_coord_units(units.0);
-
-        let pattern_rect = pattern.get_rect(values, &params);
-
         // Work out the size of the rectangle so it takes into account the object bounding box
-        let (bbwscale, bbhscale) = match units {
-            PatternUnits(CoordUnits::ObjectBoundingBox) => bbox.rect.unwrap().size(),
+        let (bbwscale, bbhscale) = match pattern.units {
+            PatternUnits(CoordUnits::ObjectBoundingBox) => pattern.bbox.rect.unwrap().size(),
             PatternUnits(CoordUnits::UserSpaceOnUse) => (1.0, 1.0),
         };
 
-        let taffine = self.get_transform().pre_transform(&pattern_transform);
+        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;
+        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);
@@ -1023,30 +1005,30 @@ impl DrawingCtx {
         schscale = f64::from(ph) / scaled_height;
 
         // Create the pattern coordinate system
-        let mut affine = match units {
+        let mut affine = match pattern.units {
             PatternUnits(CoordUnits::ObjectBoundingBox) => {
-                let bbrect = bbox.rect.unwrap();
+                let bbrect = pattern.bbox.rect.unwrap();
                 Transform::new_translate(
-                    bbrect.x0 + pattern_rect.x0 * bbrect.width(),
-                    bbrect.y0 + pattern_rect.y0 * bbrect.height(),
+                    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)
+                Transform::new_translate(pattern.rect.x0, pattern.rect.y0)
             }
         };
 
         // Apply the pattern transform
-        affine = affine.post_transform(&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.get_vbox() {
+        let _params = if let Some(vbox) = pattern.vbox {
             // If there is a vbox, use that
             let r = pattern
-                .get_preserve_aspect_ratio()
+                .preserve_aspect_ratio
                 .compute(&vbox, &Rect::from_size(scaled_width, scaled_height));
 
             let sw = r.width() / vbox.width();
@@ -1058,11 +1040,11 @@ impl DrawingCtx {
 
             self.push_view_box(vbox.width(), vbox.height())
         } else {
-            let PatternContentUnits(content_units) = content_units;
+            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) = bbox.rect.unwrap().size();
+                let (bbw, bbh) = pattern.bbox.rect.unwrap().size();
                 Transform::new_scale(bbw, bbh)
             } else {
                 Transform::identity()
@@ -1093,14 +1075,18 @@ impl DrawingCtx {
 
         // Draw everything
         let res = self.with_alpha(opacity, &mut |dc| {
-            let pattern_cascaded = CascadedValues::new_from_node(&node);
+            let pattern_cascaded = CascadedValues::new_from_node(&pattern.node_with_children);
             let pattern_values = pattern_cascaded.get();
             dc.with_discrete_layer(
-                &node,
+                &pattern.node_with_children,
                 acquired_nodes,
                 pattern_values,
                 false,
-                &mut |an, dc| node.draw_children(an, &pattern_cascaded, dc, false),
+                &mut |an, dc| {
+                    pattern
+                        .node_with_children
+                        .draw_children(an, &pattern_cascaded, dc, false)
+                },
             )
         });
 
@@ -1165,7 +1151,15 @@ impl DrawingCtx {
                 }
             }
             PaintSource::Pattern(p, c) => {
-                if self.set_pattern(&p, acquired_nodes, opacity, values, bbox)? {
+                let had_pattern;
+
+                if let Some(pattern) = p.to_user_space(bbox, self, values) {
+                    had_pattern = self.set_pattern(&pattern, acquired_nodes, opacity)?;
+                } else {
+                    had_pattern = false;
+                }
+
+                if had_pattern {
                     Ok(true)
                 } else if let Some(c) = c {
                     self.set_color(c, opacity, current_color)
diff --git a/src/pattern.rs b/src/pattern.rs
index 1bb2ae0d..fd7a5b0c 100644
--- a/src/pattern.rs
+++ b/src/pattern.rs
@@ -5,9 +5,10 @@ use std::cell::RefCell;
 
 use crate::aspect_ratio::*;
 use crate::attributes::Attributes;
+use crate::bbox::BoundingBox;
 use crate::coord_units::CoordUnits;
 use crate::document::{AcquiredNodes, NodeStack};
-use crate::drawing_ctx::ViewParams;
+use crate::drawing_ctx::DrawingCtx;
 use crate::element::{Draw, Element, ElementResult, SetAttributes};
 use crate::error::*;
 use crate::href::{is_href, set_href};
@@ -103,6 +104,18 @@ pub struct ResolvedPattern {
     children: Children,
 }
 
+/// 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 transform: Transform,
+    pub rect: Rect,
+    pub node_with_children: Node,
+}
+
 #[derive(Default)]
 pub struct Pattern {
     common: Common,
@@ -300,40 +313,50 @@ impl UnresolvedChildren {
 }
 
 impl ResolvedPattern {
-    pub fn get_units(&self) -> PatternUnits {
-        self.units
-    }
-
-    pub fn get_content_units(&self) -> PatternContentUnits {
-        self.content_units
-    }
-
-    pub fn get_vbox(&self) -> Option<ViewBox> {
-        self.vbox
+    fn node_with_children(&self) -> Option<Node> {
+        match self.children {
+            Children::Empty => None,
+            Children::WithChildren(ref wc) => Some(wc.upgrade().unwrap()),
+        }
     }
 
-    pub fn get_preserve_aspect_ratio(&self) -> AspectRatio {
-        self.preserve_aspect_ratio
-    }
+    pub fn to_user_space(
+        &self,
+        bbox: &BoundingBox,
+        draw_ctx: &DrawingCtx,
+        values: &ComputedValues,
+    ) -> Option<UserSpacePattern> {
+        let node_with_children = if let Some(n) = self.node_with_children() {
+            n
+        } else {
+            // This means we didn't find any children among the fallbacks,
+            // so there is nothing to render.
+            return None;
+        };
 
-    pub fn get_transform(&self) -> Transform {
-        self.transform
-    }
+        let params = draw_ctx.push_coord_units(self.units.0);
 
-    pub 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 node_with_children(&self) -> Option<Node> {
-        match self.children {
-            Children::Empty => None,
-            Children::WithChildren(ref wc) => Some(wc.upgrade().unwrap()),
-        }
+        let rect = Rect::new(x, y, x + w, y + h);
+
+        // 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().
+
+        Some(UserSpacePattern {
+            units: self.units,
+            content_units: self.content_units,
+            vbox: self.vbox,
+            bbox: *bbox,
+            preserve_aspect_ratio: self.preserve_aspect_ratio,
+            transform: self.transform,
+            rect,
+            node_with_children,
+        })
     }
 }
 


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