[librsvg: 6/9] clip_to_node - Use a new function BoundingBox.rect_to_transform



commit 89f21a75463dedfdf5f485e76d74b8b6ea4324ff
Author: Federico Mena Quintero <federico gnome org>
Date:   Wed Apr 29 19:53:54 2020 -0500

    clip_to_node - Use a new function BoundingBox.rect_to_transform
    
    This checks the bbox.rect and the given CoordUnits, so that
    ObjectBoundingBox with an empty bbox.rect will not produce an invalid
    transform.

 rsvg_internals/src/bbox.rs        | 31 ++++++++++++++++++++++++
 rsvg_internals/src/drawing_ctx.rs | 51 +++++++++++++--------------------------
 2 files changed, 48 insertions(+), 34 deletions(-)
---
diff --git a/rsvg_internals/src/bbox.rs b/rsvg_internals/src/bbox.rs
index 311ebafc..46dba3a0 100644
--- a/rsvg_internals/src/bbox.rs
+++ b/rsvg_internals/src/bbox.rs
@@ -1,5 +1,6 @@
 //! Bounding boxes that know their coordinate space.
 
+use crate::coord_units::CoordUnits;
 use crate::rect::Rect;
 use crate::transform::Transform;
 
@@ -69,6 +70,36 @@ impl BoundingBox {
     pub fn ink_rect_is_empty(&self) -> bool {
         self.ink_rect.map(|r| r.is_empty()).unwrap_or(true)
     }
+
+    /// Creates a transform to map to the `self.rect`.
+    ///
+    /// This depends on a `CoordUnits` parameter.  When this is
+    /// `CoordUnits::ObjectBoundingBox`, the bounding box must not be
+    /// empty, since the calling code would then not have a usable
+    /// size to work with.  In that case, if the bbox is empty, this
+    /// function returns `Err(())`.
+    ///
+    /// Usually calling code can simply ignore the action it was about
+    /// to take if this function returns an error.
+    pub fn rect_to_transform(&self, units: CoordUnits) -> Result<Transform, ()> {
+        match units {
+            CoordUnits::UserSpaceOnUse => Ok(Transform::identity()),
+            CoordUnits::ObjectBoundingBox => {
+                if self.rect_is_empty() {
+                    Err(())
+                } else {
+                    let r = self.rect.as_ref().unwrap();
+                    let t = Transform::new_unchecked(r.width(), 0.0, 0.0, r.height(), r.x0, r.y0);
+
+                    if t.is_invertible() {
+                        Ok(t)
+                    } else {
+                        Err(())
+                    }
+                }
+            }
+        }
+    }
 }
 
 fn combine_rects(
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index f550abf1..c04cd7c7 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -340,44 +340,27 @@ impl DrawingCtx {
         let node = clip_node.as_ref().unwrap();
         let units = borrow_element_as!(node, ClipPath).get_units();
 
-        if units == CoordUnits::ObjectBoundingBox && bbox.rect.is_none() {
-            // The node being clipped is empty / doesn't have a
-            // bounding box, so there's nothing to clip!
-            return Ok(());
-        }
-
-        let cascaded = CascadedValues::new_from_node(node);
-
-        let transform = if units == CoordUnits::ObjectBoundingBox {
-            let bbox_rect = bbox.rect.as_ref().unwrap();
-
-            Transform::new_unchecked(
-                bbox_rect.width(),
-                0.0,
-                0.0,
-                bbox_rect.height(),
-                bbox_rect.x0,
-                bbox_rect.y0,
-            )
-        } else {
-            Transform::identity()
-        };
+        if let Ok(transform) = bbox.rect_to_transform(units) {
+            let cascaded = CascadedValues::new_from_node(node);
 
-        self.with_saved_transform(Some(transform), &mut |dc| {
-            let cr = dc.get_cairo_context();
+            self.with_saved_transform(Some(transform), &mut |dc| {
+                let cr = dc.get_cairo_context();
 
-            // here we don't push a layer because we are clipping
-            let res = node.draw_children(acquired_nodes, &cascaded, dc, true);
+                // here we don't push a layer because we are clipping
+                let res = node.draw_children(acquired_nodes, &cascaded, dc, true);
 
-            cr.clip();
+                cr.clip();
 
-            res
-        })
-        .and_then(|_bbox|
-            // Clipping paths do not contribute to bounding boxes (they should,
-            // but we need Real Computational Geometry(tm), so ignore the
-            // bbox from the clip path.
-            Ok(()))
+                res
+            })
+            .and_then(|_bbox|
+                         // Clipping paths do not contribute to bounding boxes (they should,
+                         // but we need Real Computational Geometry(tm), so ignore the
+                         // bbox from the clip path.
+                         Ok(()))
+        } else {
+            Ok(())
+        }
     }
 
     fn generate_cairo_mask(


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