[librsvg: 4/7] Move all the internals from cairo:Rect to Rect



commit aa3311e90084cae055d02f551ccd59091e330f94
Author: Paolo Borelli <pborelli gnome org>
Date:   Sun Dec 8 13:45:42 2019 +0100

    Move all the internals from cairo:Rect to Rect
    
    Note: this breaks three reftests for me, but they might be
    just different approximation

 rsvg_internals/src/aspect_ratio.rs    | 175 ++++++++++++----------------------
 rsvg_internals/src/bbox.rs            |  34 +++----
 rsvg_internals/src/clip_path.rs       |   8 +-
 rsvg_internals/src/drawing_ctx.rs     |  51 +++++-----
 rsvg_internals/src/filter.rs          |   6 +-
 rsvg_internals/src/filters/bounds.rs  |  18 ++--
 rsvg_internals/src/filters/context.rs |  31 +++---
 rsvg_internals/src/filters/image.rs   |  24 ++---
 rsvg_internals/src/gradient.rs        |   9 +-
 rsvg_internals/src/handle.rs          |  55 +++++------
 rsvg_internals/src/image.rs           |   8 +-
 rsvg_internals/src/marker.rs          |  23 ++---
 rsvg_internals/src/mask.rs            |   7 +-
 rsvg_internals/src/pattern.rs         |  28 +++---
 rsvg_internals/src/rect.rs            |  43 +++------
 rsvg_internals/src/structure.rs       |  29 +++---
 rsvg_internals/src/text.rs            |   6 +-
 17 files changed, 238 insertions(+), 317 deletions(-)
---
diff --git a/rsvg_internals/src/aspect_ratio.rs b/rsvg_internals/src/aspect_ratio.rs
index a42362d0..52941c0b 100644
--- a/rsvg_internals/src/aspect_ratio.rs
+++ b/rsvg_internals/src/aspect_ratio.rs
@@ -27,6 +27,7 @@ use cairo;
 use crate::error::ValueErrorKind;
 use crate::float_eq_cairo::ApproxEqCairo;
 use crate::parsers::Parse;
+use crate::rect::Rect;
 use crate::viewbox::ViewBox;
 use cssparser::{CowRcStr, Parser};
 
@@ -124,25 +125,29 @@ impl AspectRatio {
         }
     }
 
-    pub fn compute(&self, vbox: &ViewBox, viewport: &cairo::Rectangle) -> (f64, f64, f64, f64) {
+    pub fn compute(&self, vbox: &ViewBox, viewport: &Rect) -> Rect {
         match self.align {
-            None => (viewport.x, viewport.y, viewport.width, viewport.height),
+            None => *viewport,
 
             Some(Align { x, y, fit }) => {
-                let w_factor = viewport.width / vbox.width;
-                let h_factor = viewport.height / vbox.height;
+                let (vb_width, vb_height) = (vbox.width, vbox.height);
+                let (vp_width, vp_height) = viewport.size();
+
+                let w_factor = vp_width / vb_width;
+                let h_factor = vp_height / vb_height;
+
                 let factor = match fit {
                     FitMode::Meet => w_factor.min(h_factor),
                     FitMode::Slice => w_factor.max(h_factor),
                 };
 
-                let w = vbox.width * factor;
-                let h = vbox.height * factor;
+                let w = vb_width * factor;
+                let h = vb_height * factor;
 
-                let xpos = x.compute(viewport.x, viewport.width, w);
-                let ypos = y.compute(viewport.y, viewport.height, h);
+                let xpos = x.compute(viewport.x0, vp_width, w);
+                let ypos = y.compute(viewport.y0, vp_height, h);
 
-                (xpos, ypos, w, h)
+                Rect::new(xpos, ypos, xpos + w, ypos + h)
             }
         }
     }
@@ -152,7 +157,7 @@ impl AspectRatio {
     pub fn viewport_to_viewbox_transform(
         &self,
         vbox: Option<ViewBox>,
-        viewport: &cairo::Rectangle,
+        viewport: &Rect,
     ) -> Option<cairo::Matrix> {
         // width or height set to 0 disables rendering of the element
         // https://www.w3.org/TR/SVG/struct.html#SVGElementWidthAttribute
@@ -160,7 +165,7 @@ impl AspectRatio {
         // https://www.w3.org/TR/SVG/struct.html#ImageElementWidthAttribute
         // https://www.w3.org/TR/SVG/painting.html#MarkerWidthAttribute
 
-        if viewport.width.approx_eq_cairo(0.0) || viewport.height.approx_eq_cairo(0.0) {
+        if viewport.is_empty() {
             return None;
         }
 
@@ -172,16 +177,16 @@ impl AspectRatio {
                 // https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
                 None
             } else {
-                let (x, y, w, h) = self.compute(&vbox, viewport);
+                let r = self.compute(&vbox, viewport);
                 let mut matrix = cairo::Matrix::identity();
-                matrix.translate(x, y);
-                matrix.scale(w / vbox.width, h / vbox.height);
+                matrix.translate(r.x0, r.y0);
+                matrix.scale(r.width() / vbox.width, r.height() / vbox.height);
                 matrix.translate(-vbox.x, -vbox.y);
                 Some(matrix)
             }
         } else {
             let mut matrix = cairo::Matrix::identity();
-            matrix.translate(viewport.x, viewport.y);
+            matrix.translate(viewport.x0, viewport.y0);
             Some(matrix)
         }
     }
@@ -251,8 +256,6 @@ impl Parse for AspectRatio {
 mod tests {
     use super::*;
     use crate::float_eq_cairo::ApproxEqCairo;
-    use crate::rect::RectangleExt;
-    use cairo::Rectangle;
 
     #[test]
     fn parsing_invalid_strings_yields_error() {
@@ -337,139 +340,87 @@ mod tests {
         );
     }
 
-    fn assert_quadruples_equal(a: &(f64, f64, f64, f64), b: &(f64, f64, f64, f64)) {
-        assert_approx_eq_cairo!(a.0, b.0);
-        assert_approx_eq_cairo!(a.1, b.1);
-        assert_approx_eq_cairo!(a.2, b.2);
-        assert_approx_eq_cairo!(a.3, b.3);
+    fn assert_rect_equal(r1: &Rect, r2: &Rect) {
+        assert_approx_eq_cairo!(r1.x0, r2.x0);
+        assert_approx_eq_cairo!(r1.y0, r2.y0);
+        assert_approx_eq_cairo!(r1.x1, r2.x1);
+        assert_approx_eq_cairo!(r1.y1, r2.y1);
     }
 
     #[test]
     fn aligns() {
+        let viewbox = ViewBox::new(0.0, 0.0, 1.0, 10.0);
+
         let foo = AspectRatio::parse_str("xMinYMin meet").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(0.0, 0.0, 0.1, 1.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::from_size(0.1, 1.0));
 
         let foo = AspectRatio::parse_str("xMinYMin slice").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(0.0, 0.0, 10.0, 100.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::from_size(10.0, 100.0));
 
         let foo = AspectRatio::parse_str("xMinYMid meet").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(0.0, 0.0, 0.1, 1.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::from_size(0.1, 1.0));
 
         let foo = AspectRatio::parse_str("xMinYMid slice").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(0.0, -49.5, 10.0, 100.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::new(0.0, -49.5, 10.0, 100.0 - 49.5));
 
         let foo = AspectRatio::parse_str("xMinYMax meet").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(0.0, 0.0, 0.1, 1.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::from_size(0.1, 1.0));
 
         let foo = AspectRatio::parse_str("xMinYMax slice").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(0.0, -99.0, 10.0, 100.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::new(0.0, -99.0, 10.0, 1.0));
 
         let foo = AspectRatio::parse_str("xMidYMin meet").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(4.95, 0.0, 0.1, 1.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::new(4.95, 0.0, 4.95 + 0.1, 1.0));
 
         let foo = AspectRatio::parse_str("xMidYMin slice").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(0.0, 0.0, 10.0, 100.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::from_size(10.0, 100.0));
 
         let foo = AspectRatio::parse_str("xMidYMid meet").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(4.95, 0.0, 0.1, 1.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::new(4.95, 0.0, 4.95 + 0.1, 1.0));
 
         let foo = AspectRatio::parse_str("xMidYMid slice").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(0.0, -49.5, 10.0, 100.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::new(0.0, -49.5, 10.0, 100.0 - 49.5));
 
         let foo = AspectRatio::parse_str("xMidYMax meet").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(4.95, 0.0, 0.1, 1.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::new(4.95, 0.0, 4.95 + 0.1, 1.0));
 
         let foo = AspectRatio::parse_str("xMidYMax slice").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(0.0, -99.0, 10.0, 100.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::new(0.0, -99.0, 10.0, 1.0));
 
         let foo = AspectRatio::parse_str("xMaxYMin meet").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(9.9, 0.0, 0.1, 1.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::new(9.9, 0.0, 10.0, 1.0));
 
         let foo = AspectRatio::parse_str("xMaxYMin slice").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(0.0, 0.0, 10.0, 100.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::from_size(10.0, 100.0));
 
         let foo = AspectRatio::parse_str("xMaxYMid meet").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(9.9, 0.0, 0.1, 1.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::new(9.9, 0.0, 10.0, 1.0));
 
         let foo = AspectRatio::parse_str("xMaxYMid slice").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(0.0, -49.5, 10.0, 100.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::new(0.0, -49.5, 10.0, 100.0 - 49.5));
 
         let foo = AspectRatio::parse_str("xMaxYMax meet").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(9.9, 0.0, 0.1, 1.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::new(9.9, 0.0, 10.0, 1.0));
 
         let foo = AspectRatio::parse_str("xMaxYMax slice").unwrap();
-        let foo = foo.compute(
-            &ViewBox::new(0.0, 0.0, 1.0, 10.0),
-            &Rectangle::new(0.0, 0.0, 10.0, 1.0),
-        );
-        assert_quadruples_equal(&foo, &(0.0, -99.0, 10.0, 100.0));
+        let foo = foo.compute(&viewbox, &Rect::from_size(10.0, 1.0));
+        assert_rect_equal(&foo, &Rect::new(0.0, -99.0, 10.0, 1.0));
     }
 }
diff --git a/rsvg_internals/src/bbox.rs b/rsvg_internals/src/bbox.rs
index 2c4d7c82..1912d57c 100644
--- a/rsvg_internals/src/bbox.rs
+++ b/rsvg_internals/src/bbox.rs
@@ -1,12 +1,12 @@
 use cairo;
 
-use crate::rect::{RectangleExt, TransformRect};
+use crate::rect::{Rect, TransformRect};
 
 #[derive(Debug, Copy, Clone)]
 pub struct BoundingBox {
     pub affine: cairo::Matrix,
-    pub rect: Option<cairo::Rectangle>,     // without stroke
-    pub ink_rect: Option<cairo::Rectangle>, // with stroke
+    pub rect: Option<Rect>,     // without stroke
+    pub ink_rect: Option<Rect>, // with stroke
 }
 
 impl BoundingBox {
@@ -18,14 +18,14 @@ impl BoundingBox {
         }
     }
 
-    pub fn with_rect(self, rect: cairo::Rectangle) -> BoundingBox {
+    pub fn with_rect(self, rect: Rect) -> BoundingBox {
         BoundingBox {
             rect: Some(rect),
             ..self
         }
     }
 
-    pub fn with_ink_rect(self, ink_rect: cairo::Rectangle) -> BoundingBox {
+    pub fn with_ink_rect(self, ink_rect: Rect) -> BoundingBox {
         BoundingBox {
             ink_rect: Some(ink_rect),
             ..self
@@ -62,18 +62,18 @@ impl BoundingBox {
 }
 
 fn combine_rects(
-    r1: Option<cairo::Rectangle>,
-    r2: Option<cairo::Rectangle>,
+    r1: Option<Rect>,
+    r2: Option<Rect>,
     affine: &cairo::Matrix,
     clip: bool,
-) -> Option<cairo::Rectangle> {
+) -> Option<Rect> {
     match (r1, r2, clip) {
         (r1, None, _) => r1,
         (None, Some(r2), _) => Some(affine.transform_rect(&r2)),
         (Some(r1), Some(r2), true) => affine
             .transform_rect(&r2)
             .intersection(&r1)
-            .or_else(|| Some(cairo::Rectangle::new(0.0, 0.0, 0.0, 0.0))),
+            .or_else(|| Some(Rect::default())),
         (Some(r1), Some(r2), false) => Some(affine.transform_rect(&r2).union(&r1)),
     }
 }
@@ -84,9 +84,9 @@ mod tests {
 
     #[test]
     fn combine() {
-        let r1 = cairo::Rectangle::new(1.0, 2.0, 3.0, 4.0);
-        let r2 = cairo::Rectangle::new(1.5, 2.5, 3.0, 4.0);
-        let r3 = cairo::Rectangle::new(10.0, 11.0, 12.0, 13.0);
+        let r1 = Rect::new(1.0, 2.0, 3.0, 4.0);
+        let r2 = Rect::new(1.5, 2.5, 3.5, 4.5);
+        let r3 = Rect::new(10.0, 11.0, 12.0, 13.0);
         let affine = cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, 0.5, 0.5);
 
         let res = combine_rects(None, None, &affine, true);
@@ -102,18 +102,18 @@ mod tests {
         assert_eq!(res, Some(r1));
 
         let res = combine_rects(None, Some(r2), &affine, true);
-        assert_eq!(res, Some(cairo::Rectangle::new(2.0, 3.0, 3.0, 4.0)));
+        assert_eq!(res, Some(Rect::new(2.0, 3.0, 4.0, 5.0)));
 
         let res = combine_rects(None, Some(r2), &affine, false);
-        assert_eq!(res, Some(cairo::Rectangle::new(2.0, 3.0, 3.0, 4.0)));
+        assert_eq!(res, Some(Rect::new(2.0, 3.0, 4.0, 5.0)));
 
         let res = combine_rects(Some(r1), Some(r2), &affine, true);
-        assert_eq!(res, Some(cairo::Rectangle::new(2.0, 3.0, 2.0, 3.0)));
+        assert_eq!(res, Some(Rect::new(2.0, 3.0, 3.0, 4.0)));
 
         let res = combine_rects(Some(r1), Some(r3), &affine, true);
-        assert_eq!(res, Some(cairo::Rectangle::new(0.0, 0.0, 0.0, 0.0)));
+        assert_eq!(res, Some(Rect::default()));
 
         let res = combine_rects(Some(r1), Some(r2), &affine, false);
-        assert_eq!(res, Some(cairo::Rectangle::new(1.0, 2.0, 4.0, 5.0)));
+        assert_eq!(res, Some(Rect::new(1.0, 2.0, 4.0, 5.0)));
     }
 }
diff --git a/rsvg_internals/src/clip_path.rs b/rsvg_internals/src/clip_path.rs
index 5dfd21a2..3d9225d3 100644
--- a/rsvg_internals/src/clip_path.rs
+++ b/rsvg_internals/src/clip_path.rs
@@ -43,12 +43,12 @@ impl ClipPath {
                     let bbox_rect = bbox.rect.as_ref().unwrap();
 
                     cr.transform(cairo::Matrix::new(
-                        bbox_rect.width,
+                        bbox_rect.width(),
                         0.0,
                         0.0,
-                        bbox_rect.height,
-                        bbox_rect.x,
-                        bbox_rect.y,
+                        bbox_rect.height(),
+                        bbox_rect.x0,
+                        bbox_rect.y0,
                     ))
                 }
 
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index a776b468..ad74c097 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -23,7 +23,7 @@ use crate::properties::ComputedValues;
 use crate::property_defs::{
     ClipRule, FillRule, ShapeRendering, StrokeDasharray, StrokeLinecap, StrokeLinejoin,
 };
-use crate::rect::RectangleExt;
+use crate::rect::Rect;
 use crate::surface_utils::shared_surface::SharedImageSurface;
 use crate::unit_interval::UnitInterval;
 use crate::viewbox::ViewBox;
@@ -79,7 +79,7 @@ pub struct DrawingCtx {
 
     initial_affine: cairo::Matrix,
 
-    rect: cairo::Rectangle,
+    rect: Rect,
     dpi: Dpi,
 
     // This is a mitigation for SVG files that try to instance a huge number of
@@ -104,7 +104,7 @@ impl DrawingCtx {
         document: Rc<Document>,
         node: Option<&RsvgNode>,
         cr: &cairo::Context,
-        viewport: &cairo::Rectangle,
+        viewport: Rect,
         dpi: Dpi,
         measuring: bool,
         testing: bool,
@@ -116,12 +116,10 @@ impl DrawingCtx {
 
         let (rect, vbox) = if measuring {
             (
-                cairo::Rectangle::new(0.0, 0.0, 1.0, 1.0),
+                Rect::from_size(1.0, 1.0),
                 ViewBox::new(0.0, 0.0, 1.0, 1.0),
             )
         } else {
-            let rect = *viewport;
-
             // https://www.w3.org/TR/SVG2/coords.html#InitialCoordinateSystem
             //
             // "For the outermost svg element, the SVG user agent must
@@ -137,11 +135,11 @@ impl DrawingCtx {
             let vbox = ViewBox {
                 x: 0.0,
                 y: 0.0,
-                width: viewport.width,
-                height: viewport.height,
+                width: viewport.width(),
+                height: viewport.height(),
             };
 
-            (rect, vbox)
+            (viewport, vbox)
         };
 
         let mut view_box_stack = Vec::new();
@@ -171,7 +169,7 @@ impl DrawingCtx {
         draw_ctx
     }
 
-    pub fn toplevel_viewport(&self) -> cairo::Rectangle {
+    pub fn toplevel_viewport(&self) -> Rect {
         self.rect
     }
 
@@ -212,7 +210,7 @@ impl DrawingCtx {
     }
 
     fn size_for_temporary_surface(&self) -> (i32, i32) {
-        let (viewport_width, viewport_height) = (self.rect.width, self.rect.height);
+        let (viewport_width, viewport_height) = (self.rect.width(), self.rect.height());
 
         let (scaled_width, scaled_height) = self
             .initial_affine_with_offset()
@@ -292,25 +290,30 @@ impl DrawingCtx {
     pub fn push_new_viewport(
         &self,
         vbox: Option<ViewBox>,
-        viewport: &cairo::Rectangle,
+        viewport: Rect,
         preserve_aspect_ratio: AspectRatio,
         clip_mode: Option<ClipMode>,
     ) -> Option<ViewParams> {
         if let Some(ref clip) = clip_mode {
             if *clip == ClipMode::ClipToViewport {
-                self.clip(viewport.x, viewport.y, viewport.width, viewport.height);
+                self.clip(viewport);
             }
         }
 
         preserve_aspect_ratio
-            .viewport_to_viewbox_transform(vbox, viewport)
+            .viewport_to_viewbox_transform(vbox, &viewport)
             .and_then(|matrix| {
                 self.cr.transform(matrix);
 
                 if let Some(vbox) = vbox {
                     if let Some(ref clip) = clip_mode {
                         if *clip == ClipMode::ClipToVbox {
-                            self.clip(vbox.x, vbox.y, vbox.width, vbox.height);
+                            self.clip(Rect::new(
+                                vbox.x,
+                                vbox.y,
+                                vbox.x + vbox.width,
+                                vbox.y + vbox.height,
+                            ));
                         }
                     }
 
@@ -535,7 +538,7 @@ impl DrawingCtx {
 
     fn initial_affine_with_offset(&self) -> cairo::Matrix {
         let mut initial_with_offset = self.initial_affine;
-        initial_with_offset.translate(self.rect.x, self.rect.y);
+        initial_with_offset.translate(self.rect.x0, self.rect.y0);
         initial_with_offset
     }
 
@@ -783,10 +786,9 @@ impl DrawingCtx {
         res.and_then(|_: ()| Ok(bbox))
     }
 
-    pub fn clip(&self, x: f64, y: f64, w: f64, h: f64) {
+    pub fn clip(&self, rect: Rect) {
         let cr = self.get_cairo_context();
-
-        cr.rectangle(x, y, w, h);
+        cr.rectangle(rect.x0, rect.y0, rect.width(), rect.height());
         cr.clip();
     }
 
@@ -842,10 +844,7 @@ impl DrawingCtx {
         cr.set_matrix(affine);
 
         self.cr = cr;
-        self.rect.x = 0.0;
-        self.rect.y = 0.0;
-        self.rect.width = width;
-        self.rect.height = height;
+        self.rect = Rect::from_size(width, height);
 
         let res = self.draw_node_from_stack(cascaded, node, false);
 
@@ -966,21 +965,21 @@ fn compute_stroke_and_fill_box(cr: &cairo::Context, values: &ComputedValues) ->
     // rectangle's extents, even when it has no fill nor stroke.
 
     let (x0, y0, x1, y1) = cr.fill_extents();
-    let fb = BoundingBox::new(&affine).with_ink_rect(cairo::Rectangle::from_extents(x0, y0, x1, y1));
+    let fb = BoundingBox::new(&affine).with_ink_rect(Rect::new(x0, y0, x1, y1));
     bbox.insert(&fb);
 
     // Bounding box for stroke
 
     if values.stroke.0 != PaintServer::None {
         let (x0, y0, x1, y1) = cr.stroke_extents();
-        let sb = BoundingBox::new(&affine).with_ink_rect(cairo::Rectangle::from_extents(x0, y0, x1, y1));
+        let sb = BoundingBox::new(&affine).with_ink_rect(Rect::new(x0, y0, x1, y1));
         bbox.insert(&sb);
     }
 
     // objectBoundingBox
 
     let (x0, y0, x1, y1) = cr.path_extents();
-    let ob = BoundingBox::new(&affine).with_rect(cairo::Rectangle::from_extents(x0, y0, x1, y1));
+    let ob = BoundingBox::new(&affine).with_rect(Rect::new(x0, y0, x1, y1));
     bbox.insert(&ob);
 
     // restore tolerance
diff --git a/rsvg_internals/src/filter.rs b/rsvg_internals/src/filter.rs
index 3d5cd5f1..f9a1541d 100644
--- a/rsvg_internals/src/filter.rs
+++ b/rsvg_internals/src/filter.rs
@@ -10,7 +10,7 @@ use crate::node::{NodeResult, NodeTrait, RsvgNode};
 use crate::parsers::{Parse, ParseValue};
 use crate::properties::ComputedValues;
 use crate::property_bag::PropertyBag;
-use crate::rect::RectangleExt;
+use crate::rect::Rect;
 
 /// The <filter> node.
 pub struct Filter {
@@ -92,7 +92,7 @@ impl Filter {
             )
         };
 
-        let rect = cairo::Rectangle::new(x, y, w, h);
+        let rect = Rect::new(x, y, x + w, y + h);
         let other_bbox = BoundingBox::new(&affine).with_rect(rect);
 
         // At this point all of the previous viewbox and matrix business gets converted to pixel
@@ -100,7 +100,7 @@ impl Filter {
         bbox.insert(&other_bbox);
 
         // Finally, clip to the width and height of our surface.
-        let rect = cairo::Rectangle::from_size(width, height);
+        let rect = Rect::from_size(width, height);
         let other_bbox = BoundingBox::new(&cairo::Matrix::identity()).with_rect(rect);
         bbox.clip(&other_bbox);
 
diff --git a/rsvg_internals/src/filters/bounds.rs b/rsvg_internals/src/filters/bounds.rs
index 28291541..bc26962e 100644
--- a/rsvg_internals/src/filters/bounds.rs
+++ b/rsvg_internals/src/filters/bounds.rs
@@ -4,7 +4,7 @@ use cairo;
 use crate::bbox::BoundingBox;
 use crate::drawing_ctx::DrawingCtx;
 use crate::length::*;
-use crate::rect::IRect;
+use crate::rect::{IRect, Rect};
 
 use super::context::{FilterContext, FilterInput};
 
@@ -74,7 +74,7 @@ impl<'a> BoundsBuilder<'a> {
     }
 
     /// Returns the final exact bounds.
-    pub fn into_rect(self, draw_ctx: &mut DrawingCtx) -> cairo::Rectangle {
+    pub fn into_rect(self, draw_ctx: &mut DrawingCtx) -> Rect {
         let mut bbox = self.apply_properties(draw_ctx);
 
         let effects_region = self.ctx.effects_region();
@@ -91,7 +91,7 @@ impl<'a> BoundsBuilder<'a> {
     /// Returns the final pixel bounds without clipping to the filter effects region.
     ///
     /// Used by feImage.
-    pub fn into_rect_without_clipping(self, draw_ctx: &mut DrawingCtx) -> cairo::Rectangle {
+    pub fn into_rect_without_clipping(self, draw_ctx: &mut DrawingCtx) -> Rect {
         self.apply_properties(draw_ctx).rect.unwrap().into()
     }
 
@@ -118,16 +118,20 @@ impl<'a> BoundsBuilder<'a> {
             let rect = self.bbox.rect.as_mut().unwrap();
 
             if let Some(x) = self.x {
-                rect.x = x.normalize(values, &params);
+                let w = rect.width();
+                rect.x0 = x.normalize(values, &params);
+                rect.x1 = rect.x0 + w;
             }
             if let Some(y) = self.y {
-                rect.y = y.normalize(values, &params);
+                let h = rect.height();
+                rect.y0 = y.normalize(values, &params);
+                rect.y1 = rect.y0 + h;
             }
             if let Some(width) = self.width {
-                rect.width = width.normalize(values, &params);
+                rect.x1 = rect.x0 + width.normalize(values, &params);
             }
             if let Some(height) = self.height {
-                rect.height = height.normalize(values, &params);
+                rect.y1 = rect.y0 + height.normalize(values, &params);
             }
         }
 
diff --git a/rsvg_internals/src/filters/context.rs b/rsvg_internals/src/filters/context.rs
index 1dd8a886..e3719198 100644
--- a/rsvg_internals/src/filters/context.rs
+++ b/rsvg_internals/src/filters/context.rs
@@ -107,12 +107,7 @@ impl FilterContext {
 
         // The rect can be empty (for example, if the filter is applied to an empty group).
         // However, with userSpaceOnUse it's still possible to create images with a filter.
-        let bbox_rect = node_bbox.rect.unwrap_or(cairo::Rectangle {
-            x: 0.0,
-            y: 0.0,
-            width: 0.0,
-            height: 0.0,
-        });
+        let bbox_rect = node_bbox.rect.unwrap_or_default();
 
         let node_data = filter_node.borrow();
         let filter = node_data.get_impl::<Filter>();
@@ -121,12 +116,12 @@ impl FilterContext {
             CoordUnits::UserSpaceOnUse => cr_affine,
             CoordUnits::ObjectBoundingBox => {
                 let affine = cairo::Matrix::new(
-                    bbox_rect.width,
-                    0f64,
-                    0f64,
-                    bbox_rect.height,
-                    bbox_rect.x,
-                    bbox_rect.y,
+                    bbox_rect.width(),
+                    0.0,
+                    0.0,
+                    bbox_rect.height(),
+                    bbox_rect.x0,
+                    bbox_rect.y0,
                 );
                 cairo::Matrix::multiply(&affine, &cr_affine)
             }
@@ -136,12 +131,12 @@ impl FilterContext {
             CoordUnits::UserSpaceOnUse => cr_affine,
             CoordUnits::ObjectBoundingBox => {
                 let affine = cairo::Matrix::new(
-                    bbox_rect.width,
-                    0f64,
-                    0f64,
-                    bbox_rect.height,
-                    bbox_rect.x,
-                    bbox_rect.y,
+                    bbox_rect.width(),
+                    0.0,
+                    0.0,
+                    bbox_rect.height(),
+                    bbox_rect.x0,
+                    bbox_rect.y0,
                 );
                 cairo::Matrix::multiply(&affine, &cr_affine)
             }
diff --git a/rsvg_internals/src/filters/image.rs b/rsvg_internals/src/filters/image.rs
index 22c0e22e..9e668038 100644
--- a/rsvg_internals/src/filters/image.rs
+++ b/rsvg_internals/src/filters/image.rs
@@ -5,10 +5,10 @@ use crate::allowed_url::{Fragment, Href};
 use crate::aspect_ratio::AspectRatio;
 use crate::drawing_ctx::DrawingCtx;
 use crate::error::{NodeError, RenderingError};
-use crate::float_eq_cairo::ApproxEqCairo;
 use crate::node::{CascadedValues, NodeResult, NodeTrait, RsvgNode};
 use crate::parsers::ParseValue;
 use crate::property_bag::PropertyBag;
+use crate::rect::Rect;
 use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
 use crate::viewbox::ViewBox;
 
@@ -40,7 +40,7 @@ impl FeImage {
         &self,
         ctx: &FilterContext,
         draw_ctx: &mut DrawingCtx,
-        bounds: cairo::Rectangle,
+        bounds: Rect,
         fragment: &Fragment,
     ) -> Result<ImageSurface, FilterError> {
         let acquired_drawable = draw_ctx
@@ -99,8 +99,8 @@ impl FeImage {
         &self,
         ctx: &FilterContext,
         draw_ctx: &DrawingCtx,
-        bounds: &cairo::Rectangle,
-        unclipped_bounds: &cairo::Rectangle,
+        bounds: &Rect,
+        unclipped_bounds: &Rect,
         href: &Href,
     ) -> Result<ImageSurface, FilterError> {
         let surface = if let Href::PlainUrl(ref url) = *href {
@@ -119,7 +119,7 @@ impl FeImage {
         )?;
 
         // TODO: this goes through a f64->i32->f64 conversion.
-        let (x, y, w, h) = self.aspect.compute(
+        let r = self.aspect.compute(
             &ViewBox::new(
                 0.0,
                 0.0,
@@ -129,18 +129,18 @@ impl FeImage {
             &unclipped_bounds,
         );
 
-        if w.approx_eq_cairo(0.0) || h.approx_eq_cairo(0.0) {
+        if r.is_empty() {
             return Ok(output_surface);
         }
 
         let ptn = surface.to_cairo_pattern();
         let mut matrix = cairo::Matrix::new(
-            w / f64::from(surface.width()),
-            0f64,
-            0f64,
-            h / f64::from(surface.height()),
-            x,
-            y,
+            r.width() / f64::from(surface.width()),
+            0.0,
+            0.0,
+            r.height() / f64::from(surface.height()),
+            r.x0,
+            r.y0,
         );
         matrix.invert();
         ptn.set_matrix(matrix);
diff --git a/rsvg_internals/src/gradient.rs b/rsvg_internals/src/gradient.rs
index 638d1b3a..1fa672e1 100644
--- a/rsvg_internals/src/gradient.rs
+++ b/rsvg_internals/src/gradient.rs
@@ -15,7 +15,6 @@ use crate::parsers::{Parse, ParseValue};
 use crate::properties::ComputedValues;
 use crate::property_bag::PropertyBag;
 use crate::property_defs::StopColor;
-use crate::rect::RectangleExt;
 use crate::unit_interval::UnitInterval;
 
 /// Contents of a <stop> element for gradient color stops
@@ -740,12 +739,12 @@ impl Gradient {
         if self.units == GradientUnits(CoordUnits::ObjectBoundingBox) {
             let bbox_rect = bbox.rect.unwrap();
             let bbox_matrix = cairo::Matrix::new(
-                bbox_rect.width,
+                bbox_rect.width(),
                 0.0,
                 0.0,
-                bbox_rect.height,
-                bbox_rect.x,
-                bbox_rect.y,
+                bbox_rect.height(),
+                bbox_rect.x0,
+                bbox_rect.y0,
             );
             affine = cairo::Matrix::multiply(&affine, &bbox_matrix);
         }
diff --git a/rsvg_internals/src/handle.rs b/rsvg_internals/src/handle.rs
index 853d55db..6b47309f 100644
--- a/rsvg_internals/src/handle.rs
+++ b/rsvg_internals/src/handle.rs
@@ -15,7 +15,7 @@ use crate::dpi::Dpi;
 use crate::drawing_ctx::DrawingCtx;
 use crate::error::{DefsLookupErrorKind, LoadingError, RenderingError};
 use crate::node::{CascadedValues, RsvgNode};
-use crate::rect::RectangleExt;
+use crate::rect::{IRect, Rect};
 use crate::structure::{IntrinsicDimensions, Svg};
 use url::Url;
 
@@ -276,7 +276,7 @@ impl Handle {
     fn get_node_geometry_with_viewport(
         &self,
         node: &RsvgNode,
-        viewport: &cairo::Rectangle,
+        viewport: Rect,
         dpi: Dpi,
         is_testing: bool,
     ) -> Result<(cairo::Rectangle, cairo::Rectangle), RenderingError> {
@@ -293,12 +293,13 @@ impl Handle {
         );
         let root = self.document.root();
 
-        let bbox = draw_ctx.draw_node_from_stack(&CascadedValues::new_from_node(&root), &root, false)?;
+        let bbox =
+            draw_ctx.draw_node_from_stack(&CascadedValues::new_from_node(&root), &root, false)?;
 
-        let ink_rect = bbox.ink_rect.unwrap_or_else(|| cairo::Rectangle::new(0.0, 0.0, 0.0, 0.0));
-        let logical_rect = bbox.rect.unwrap_or_else(|| cairo::Rectangle::new(0.0, 0.0, 0.0, 0.0));
+        let ink_rect = bbox.ink_rect.unwrap_or_default();
+        let logical_rect = bbox.rect.unwrap_or_default();
 
-        Ok((ink_rect, logical_rect))
+        Ok((cairo::Rectangle::from(ink_rect), cairo::Rectangle::from(logical_rect)))
     }
 
     /// Returns (ink_rect, logical_rect)
@@ -320,16 +321,13 @@ impl Handle {
             if let Some((root_width, root_height)) =
                 node.borrow().get_impl::<Svg>().get_size(&values, dpi)
             {
-                let ink_r =
-                    cairo::Rectangle::from_size(f64::from(root_width), f64::from(root_height));
-
-                let logical_r = ink_r;
+                let rect = IRect::from_size(root_width, root_height);
 
-                return Ok((ink_r, logical_r));
+                return Ok((cairo::Rectangle::from(rect), cairo::Rectangle::from(rect)));
             }
         }
 
-        self.get_node_geometry_with_viewport(&node, &unit_rectangle(), dpi, is_testing)
+        self.get_node_geometry_with_viewport(&node, unit_rectangle(), dpi, is_testing)
     }
 
     fn get_node_or_root(&self, id: Option<&str>) -> Result<RsvgNode, RenderingError> {
@@ -348,6 +346,7 @@ impl Handle {
         is_testing: bool,
     ) -> Result<(cairo::Rectangle, cairo::Rectangle), RenderingError> {
         let node = self.get_node_or_root(id)?;
+        let viewport = Rect::from(*viewport);
         self.get_node_geometry_with_viewport(&node, viewport, dpi, is_testing)
     }
 
@@ -443,7 +442,7 @@ impl Handle {
             self.document.clone(),
             node.as_ref(),
             cr,
-            viewport,
+            Rect::from(*viewport),
             dpi,
             false,
             is_testing,
@@ -470,7 +469,7 @@ impl Handle {
             self.document.clone(),
             None,
             &cr,
-            &unit_rectangle(),
+            unit_rectangle(),
             dpi,
             true,
             is_testing,
@@ -490,13 +489,16 @@ impl Handle {
 
         let bbox = self.get_bbox_for_element(&node, dpi, is_testing)?;
 
-        let ink_rect = bbox.ink_rect.unwrap_or_else(|| cairo::Rectangle::new(0.0, 0.0, 0.0, 0.0));
-        let logical_rect = bbox.rect.unwrap_or_else(|| cairo::Rectangle::new(0.0, 0.0, 0.0, 0.0));
+        let ink_rect = bbox.ink_rect.unwrap_or_default();
+        let logical_rect = bbox.rect.unwrap_or_default();
 
         // Translate so ink_rect is always at offset (0, 0)
-        let ofs = (-ink_rect.x, -ink_rect.y);
+        let ofs = (-ink_rect.x0, -ink_rect.y0);
 
-        Ok((ink_rect.translate(ofs), logical_rect.translate(ofs)))
+        Ok((
+            cairo::Rectangle::from(ink_rect.translate(ofs)),
+            cairo::Rectangle::from(logical_rect.translate(ofs)),
+        ))
     }
 
     pub fn render_element(
@@ -518,7 +520,7 @@ impl Handle {
             return Ok(());
         }
 
-        let ink_r = bbox.ink_rect.unwrap_or_else(|| cairo::Rectangle::new(0.0, 0.0, 0.0, 0.0));
+        let ink_r = bbox.ink_rect.unwrap_or_default();
 
         if ink_r.is_empty() {
             return Ok(());
@@ -529,17 +531,17 @@ impl Handle {
         cr.save();
 
         let factor =
-            (element_viewport.width / ink_r.width).min(element_viewport.height / ink_r.height);
+            (element_viewport.width / ink_r.width()).min(element_viewport.height / ink_r.height());
 
         cr.translate(element_viewport.x, element_viewport.y);
         cr.scale(factor, factor);
-        cr.translate(-ink_r.x, -ink_r.y);
+        cr.translate(-ink_r.x0, -ink_r.y0);
 
         let mut draw_ctx = DrawingCtx::new(
             self.document.clone(),
             None,
             &cr,
-            &unit_rectangle(),
+            unit_rectangle(),
             dpi,
             false,
             is_testing,
@@ -589,11 +591,6 @@ fn locale_from_environment() -> Locale {
     locale
 }
 
-fn unit_rectangle() -> cairo::Rectangle {
-    cairo::Rectangle {
-        x: 0.0,
-        y: 0.0,
-        width: 1.0,
-        height: 1.0,
-    }
+fn unit_rectangle() -> Rect {
+    Rect::from_size(1.0, 1.0)
 }
diff --git a/rsvg_internals/src/image.rs b/rsvg_internals/src/image.rs
index 23b4d3af..46f924c6 100644
--- a/rsvg_internals/src/image.rs
+++ b/rsvg_internals/src/image.rs
@@ -1,5 +1,4 @@
 use cairo;
-use cairo::Rectangle;
 use markup5ever::{expanded_name, local_name, namespace_url, ns};
 
 use crate::allowed_url::Href;
@@ -12,7 +11,7 @@ use crate::length::*;
 use crate::node::*;
 use crate::parsers::ParseValue;
 use crate::property_bag::PropertyBag;
-use crate::rect::RectangleExt;
+use crate::rect::Rect;
 use crate::viewbox::ViewBox;
 
 #[derive(Default)]
@@ -99,7 +98,8 @@ impl NodeTrait for Image {
 
             // The bounding box for <image> is decided by the values of x, y, w, h and not by
             // the final computed image bounds.
-            let bbox = dc.empty_bbox().with_rect(cairo::Rectangle::new(x, y, w, h));
+            let rect = Rect::new(x, y, x + w, y + h);
+            let bbox = dc.empty_bbox().with_rect(rect);
 
             dc.with_saved_cr(&mut |dc| {
                 let cr = dc.get_cairo_context();
@@ -109,7 +109,7 @@ impl NodeTrait for Image {
 
                 if let Some(_params) = dc.push_new_viewport(
                     Some(ViewBox::new(0.0, 0.0, image_width, image_height)),
-                    &Rectangle::new(x, y, w, h),
+                    Rect::new(x, y, x + w, y + h),
                     self.aspect,
                     clip_mode,
                 ) {
diff --git a/rsvg_internals/src/marker.rs b/rsvg_internals/src/marker.rs
index 4edbf600..a62c64ec 100644
--- a/rsvg_internals/src/marker.rs
+++ b/rsvg_internals/src/marker.rs
@@ -18,7 +18,7 @@ use crate::parsers::{Parse, ParseValue};
 use crate::path_builder::*;
 use crate::properties::{ComputedValues, SpecifiedValue, SpecifiedValues};
 use crate::property_bag::PropertyBag;
-use crate::rect::RectangleExt;
+use crate::rect::Rect;
 use crate::viewbox::*;
 
 // markerUnits attribute: https://www.w3.org/TR/SVG/painting.html#MarkerElement
@@ -150,16 +150,15 @@ impl Marker {
             }
 
             let params = if let Some(vbox) = self.vbox {
-                let (_, _, w, h) = self.aspect.compute(
-                    &vbox,
-                    &cairo::Rectangle::from_size(marker_width, marker_height),
-                );
-
                 if vbox.width.approx_eq_cairo(0.0) || vbox.height.approx_eq_cairo(0.0) {
                     return Ok(dc.empty_bbox());
                 }
 
-                cr.scale(w / vbox.width, h / vbox.height);
+                let r = self
+                    .aspect
+                    .compute(&vbox, &Rect::from_size(marker_width, marker_height));
+
+                cr.scale(r.width() / vbox.width, r.height() / vbox.height);
 
                 dc.push_view_box(vbox.width, vbox.height)
             } else {
@@ -172,11 +171,13 @@ impl Marker {
             );
 
             if !values.is_overflow() {
-                if let Some(vbox) = self.vbox {
-                    dc.clip(vbox.x, vbox.y, vbox.width, vbox.height);
+                let clip_rect = if let Some(vbox) = self.vbox {
+                    Rect::new(vbox.x, vbox.y, vbox.x + vbox.width, vbox.y + vbox.height)
                 } else {
-                    dc.clip(0.0, 0.0, marker_width, marker_height);
-                }
+                    Rect::from_size(marker_width, marker_height)
+                };
+
+                dc.clip(clip_rect);
             }
 
             dc.with_discrete_layer(node, values, clipping, &mut |dc| {
diff --git a/rsvg_internals/src/mask.rs b/rsvg_internals/src/mask.rs
index ee25288d..b995151e 100644
--- a/rsvg_internals/src/mask.rs
+++ b/rsvg_internals/src/mask.rs
@@ -10,6 +10,7 @@ use crate::node::{CascadedValues, NodeDraw, NodeResult, NodeTrait, RsvgNode};
 use crate::parsers::{Parse, ParseValue};
 use crate::property_bag::PropertyBag;
 use crate::property_defs::Opacity;
+use crate::rect::Rect;
 use crate::surface_utils::{shared_surface::SharedImageSurface, shared_surface::SurfaceType};
 
 coord_units!(MaskUnits, CoordUnits::ObjectBoundingBox);
@@ -55,8 +56,8 @@ impl Mask {
         }
 
         let bbox_rect = bbox.rect.as_ref().unwrap();
-        let (bb_x, bb_y) = (bbox_rect.x, bbox_rect.y);
-        let (bb_w, bb_h) = (bbox_rect.width, bbox_rect.height);
+        let (bb_x, bb_y) = (bbox_rect.x0, bbox_rect.y0);
+        let (bb_w, bb_h) = bbox_rect.size();
 
         let cascaded = CascadedValues::new_from_node(mask_node);
         let values = cascaded.get();
@@ -96,7 +97,7 @@ impl Mask {
                 (x, y, w, h)
             };
 
-            draw_ctx.clip(x, y, w, h);
+            draw_ctx.clip(Rect::new(x, y, x + w, y + h));
 
             {
                 let _params = if content_units == CoordUnits::ObjectBoundingBox {
diff --git a/rsvg_internals/src/pattern.rs b/rsvg_internals/src/pattern.rs
index fe65edf5..5354f086 100644
--- a/rsvg_internals/src/pattern.rs
+++ b/rsvg_internals/src/pattern.rs
@@ -16,7 +16,7 @@ use crate::paint_server::{AsPaintSource, PaintSource};
 use crate::parsers::ParseValue;
 use crate::properties::ComputedValues;
 use crate::property_bag::PropertyBag;
-use crate::rect::RectangleExt;
+use crate::rect::Rect;
 use crate::unit_interval::UnitInterval;
 use crate::viewbox::*;
 
@@ -259,11 +259,7 @@ impl AsPaintSource for ResolvedPattern {
         // Work out the size of the rectangle so it takes into account the object bounding box
 
         let (bbwscale, bbhscale) = match units {
-            PatternUnits(CoordUnits::ObjectBoundingBox) => {
-                let rect = bbox.rect.unwrap();
-                (rect.width, rect.height)
-            }
-
+            PatternUnits(CoordUnits::ObjectBoundingBox) => bbox.rect.unwrap().size(),
             PatternUnits(CoordUnits::UserSpaceOnUse) => (1.0, 1.0),
         };
 
@@ -298,8 +294,8 @@ impl AsPaintSource for ResolvedPattern {
             PatternUnits(CoordUnits::ObjectBoundingBox) => {
                 let bbrect = bbox.rect.unwrap();
                 affine.translate(
-                    bbrect.x + pattern_x * bbrect.width,
-                    bbrect.y + pattern_y * bbrect.height,
+                    bbrect.x0 + pattern_x * bbrect.width(),
+                    bbrect.y0 + pattern_y * bbrect.height(),
                 );
             }
 
@@ -316,23 +312,25 @@ impl AsPaintSource for ResolvedPattern {
         // Create the pattern contents coordinate system
         let _params = if let Some(vbox) = vbox {
             // If there is a vbox, use that
-            let (mut x, mut y, w, h) = preserve_aspect_ratio.compute(
+            let r = preserve_aspect_ratio.compute(
                 &vbox,
-                &cairo::Rectangle::from_size(scaled_width, scaled_height),
+                &Rect::from_size(scaled_width, scaled_height),
             );
 
-            x -= vbox.x * w / vbox.width;
-            y -= vbox.y * h / vbox.height;
+            let sw = r.width() / vbox.width;
+            let sh = r.height() / vbox.height;
+            let x = r.x0 - vbox.x * sw;
+            let y = r.y0 - vbox.y * sh;
 
-            caffine = cairo::Matrix::new(w / vbox.width, 0.0, 0.0, h / vbox.height, x, y);
+            caffine = cairo::Matrix::new(sw, 0.0, 0.0, sh, x, y);
 
             draw_ctx.push_view_box(vbox.width, vbox.height)
         } else if content_units == PatternContentUnits(CoordUnits::ObjectBoundingBox) {
             // If coords are in terms of the bounding box, use them
-            let bbrect = bbox.rect.unwrap();
+            let (bbw, bbh) = bbox.rect.unwrap().size();
 
             caffine = cairo::Matrix::identity();
-            caffine.scale(bbrect.width, bbrect.height);
+            caffine.scale(bbw, bbh);
 
             draw_ctx.push_view_box(1.0, 1.0)
         } else {
diff --git a/rsvg_internals/src/rect.rs b/rsvg_internals/src/rect.rs
index 9d29127d..162ca1b2 100644
--- a/rsvg_internals/src/rect.rs
+++ b/rsvg_internals/src/rect.rs
@@ -321,16 +321,16 @@ impl RectangleExt for cairo::Rectangle {
 }
 
 pub trait TransformRect {
-    fn transform_rect(&self, rect: &cairo::Rectangle) -> cairo::Rectangle;
+    fn transform_rect(&self, rect: &Rect) -> Rect;
 }
 
 impl TransformRect for cairo::Matrix {
-    fn transform_rect(&self, rect: &cairo::Rectangle) -> cairo::Rectangle {
+    fn transform_rect(&self, rect: &Rect) -> Rect {
         let points = vec![
-            self.transform_point(rect.x, rect.y),
-            self.transform_point(rect.x + rect.width, rect.y),
-            self.transform_point(rect.x, rect.y + rect.height),
-            self.transform_point(rect.x + rect.width, rect.y + rect.height),
+            self.transform_point(rect.x0, rect.y0),
+            self.transform_point(rect.x1, rect.y0),
+            self.transform_point(rect.x0, rect.y1),
+            self.transform_point(rect.x1, rect.y1),
         ];
 
         let (mut xmin, mut ymin, mut xmax, mut ymax) = {
@@ -357,11 +357,11 @@ impl TransformRect for cairo::Matrix {
             }
         }
 
-        cairo::Rectangle {
-            x: xmin,
-            y: ymin,
-            width: xmax - xmin,
-            height: ymax - ymin,
+        Rect {
+            x0: xmin,
+            y0: ymin,
+            x1: xmax,
+            y1: ymax,
         }
     }
 }
@@ -441,25 +441,4 @@ mod tests {
         assert_approx_eq_cairo!(4.34_f64, r.width);
         assert_approx_eq_cairo!(4.34_f64, r.height);
     }
-
-    #[test]
-    fn transform_rect() {
-        let r = cairo::Rectangle {
-            x: 0.42,
-            y: 0.42,
-            width: 3.14,
-            height: 3.14,
-        };
-
-        let m = cairo::Matrix::identity();
-        let tr = m.transform_rect(&r);
-        assert_eq!(tr, r);
-
-        let m = cairo::Matrix::new(2.0, 0.0, 0.0, 2.0, 1.5, 1.5);
-        let tr = m.transform_rect(&r);
-        assert_approx_eq_cairo!(2.34_f64, tr.x);
-        assert_approx_eq_cairo!(2.34_f64, tr.y);
-        assert_approx_eq_cairo!(6.28_f64, tr.width);
-        assert_approx_eq_cairo!(6.28_f64, tr.height);
-    }
 }
diff --git a/rsvg_internals/src/structure.rs b/rsvg_internals/src/structure.rs
index 02c6aa6e..473855cb 100644
--- a/rsvg_internals/src/structure.rs
+++ b/rsvg_internals/src/structure.rs
@@ -1,4 +1,3 @@
-use cairo::Rectangle;
 use markup5ever::{expanded_name, local_name, namespace_url, ns};
 
 use crate::allowed_url::Fragment;
@@ -14,7 +13,7 @@ use crate::parsers::{Parse, ParseValue};
 use crate::properties::ComputedValues;
 use crate::property_bag::PropertyBag;
 use crate::property_defs::Overflow;
-use crate::rect::RectangleExt;
+use crate::rect::Rect;
 use crate::viewbox::*;
 
 #[derive(Default)]
@@ -162,15 +161,15 @@ impl Svg {
         (x, y, w, h)
     }
 
-    fn get_viewport(&self, values: &ComputedValues, params: &ViewParams) -> Rectangle {
+    fn get_viewport(&self, values: &ComputedValues, params: &ViewParams) -> Rect {
         let (x, y, w, h) = self.get_unnormalized_viewport();
 
-        Rectangle::new(
-            x.normalize(values, &params),
-            y.normalize(values, &params),
-            w.normalize(values, &params),
-            h.normalize(values, &params),
-        )
+        let nx = x.normalize(values, &params);
+        let ny = y.normalize(values, &params);
+        let nw = w.normalize(values, &params);
+        let nh = h.normalize(values, &params);
+
+        Rect::new(nx, ny, nx + nw, ny + nh)
     }
 }
 
@@ -247,8 +246,8 @@ impl NodeTrait for Svg {
                     Some(ViewBox {
                         x: 0.0,
                         y: 0.0,
-                        width: svg_viewport.width,
-                        height: svg_viewport.height,
+                        width: svg_viewport.width(),
+                        height: svg_viewport.height(),
                     })
                 }),
             )
@@ -256,7 +255,7 @@ impl NodeTrait for Svg {
 
         draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
             let _params =
-                dc.push_new_viewport(vbox, &viewport, self.preserve_aspect_ratio, clip_mode);
+                dc.push_new_viewport(vbox, viewport, self.preserve_aspect_ratio, clip_mode);
 
             node.draw_children(cascaded, dc, clipping)
         })
@@ -376,11 +375,9 @@ impl NodeTrait for Use {
             return Ok(draw_ctx.empty_bbox());
         }
 
-        let viewport = Rectangle::new(nx, ny, nw, nh);
-
         if child.borrow().get_type() != NodeType::Symbol {
             let cr = draw_ctx.get_cairo_context();
-            cr.translate(viewport.x, viewport.y);
+            cr.translate(nx, ny);
 
             draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
                 dc.draw_node_from_stack(
@@ -404,7 +401,7 @@ impl NodeTrait for Use {
             draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
                 let _params = dc.push_new_viewport(
                     symbol.vbox,
-                    &viewport,
+                    Rect::new(nx, ny, nx + nw, ny + nh),
                     symbol.preserve_aspect_ratio,
                     clip_mode,
                 );
diff --git a/rsvg_internals/src/text.rs b/rsvg_internals/src/text.rs
index 90cea086..58c43743 100644
--- a/rsvg_internals/src/text.rs
+++ b/rsvg_internals/src/text.rs
@@ -28,7 +28,7 @@ use crate::property_defs::{
     XmlLang,
     XmlSpace,
 };
-use crate::rect::RectangleExt;
+use crate::rect::Rect;
 use crate::space::{xml_space_normalize, NormalizeDefault, XmlSpaceNormalize};
 
 /// An absolutely-positioned array of `Span`s
@@ -352,7 +352,7 @@ impl PositionedSpan {
 
                     if !clipping {
                         let (x0, y0, x1, y1) = cr.stroke_extents();
-                        let r = cairo::Rectangle::from_extents(x0, y0, x1, y1);
+                        let r = Rect::new(x0, y0, x1, y1);
                         let ib = BoundingBox::new(&affine).with_ink_rect(r);
                         cr.stroke();
                         bbox.insert(&ib);
@@ -397,7 +397,7 @@ impl PositionedSpan {
             )
         };
 
-        let r = cairo::Rectangle::new(x, y, w, h);
+        let r = Rect::new(x, y, x + w, y + h);
         let bbox = BoundingBox::new(affine).with_rect(r).with_ink_rect(r);
 
         Some(bbox)


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