[librsvg/rustification] bbox.rs: Implement RsvgBbox in Rust



commit 0ca4455350b5bbab697a8f19aedc9c548fa24dc0
Author: Federico Mena Quintero <federico gnome org>
Date:   Fri Nov 25 16:36:09 2016 -0600

    bbox.rs: Implement RsvgBbox in Rust

 rsvg-base.c      |  119 -----------------------------------------
 rsvg-private.h   |    7 +++
 rust/src/bbox.rs |  156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 rust/src/lib.rs  |    8 +++
 4 files changed, 171 insertions(+), 119 deletions(-)
---
diff --git a/rsvg-base.c b/rsvg-base.c
index 2d1b379..4ef9c29 100644
--- a/rsvg-base.c
+++ b/rsvg-base.c
@@ -2368,125 +2368,6 @@ rsvg_render_free (RsvgRender * render)
 }
 
 void
-rsvg_bbox_init (RsvgBbox * self, cairo_matrix_t *affine)
-{
-    self->virgin = 1;
-    self->affine = *affine;
-}
-
-void
-rsvg_bbox_insert (RsvgBbox * dst, RsvgBbox * src)
-{
-    cairo_matrix_t affine;
-    double xmin, ymin;
-    double xmax, ymax;
-    int i;
-
-    if (src->virgin)
-        return;
-
-    if (!dst->virgin) {
-        xmin = dst->rect.x, ymin = dst->rect.y;
-        xmax = dst->rect.x + dst->rect.width, ymax = dst->rect.y + dst->rect.height;
-    } else {
-        xmin = ymin = xmax = ymax = 0;
-    }
-
-    affine = dst->affine;
-    if (cairo_matrix_invert (&affine) != CAIRO_STATUS_SUCCESS)
-      return; //FIXMEchpe correct??
-
-    cairo_matrix_multiply (&affine, &src->affine, &affine);
-
-    for (i = 0; i < 4; i++) {
-        double rx, ry, x, y;
-        rx = src->rect.x + src->rect.width * (double) (i % 2);
-        ry = src->rect.y + src->rect.height * (double) (i / 2);
-        x = affine.xx * rx + affine.xy * ry + affine.x0;
-        y = affine.yx * rx + affine.yy * ry + affine.y0;
-        if (dst->virgin) {
-            xmin = xmax = x;
-            ymin = ymax = y;
-            dst->virgin = 0;
-        } else {
-            if (x < xmin)
-                xmin = x;
-            if (x > xmax)
-                xmax = x;
-            if (y < ymin)
-                ymin = y;
-            if (y > ymax)
-                ymax = y;
-        }
-    }
-    dst->rect.x = xmin;
-    dst->rect.y = ymin;
-    dst->rect.width = xmax - xmin;
-    dst->rect.height = ymax - ymin;
-}
-
-void
-rsvg_bbox_clip (RsvgBbox * dst, RsvgBbox * src)
-{
-    cairo_matrix_t affine;
-       double xmin, ymin;
-       double xmax, ymax;
-    int i;
-
-    if (src->virgin)
-        return;
-
-    if (!dst->virgin) {
-        xmin = dst->rect.x + dst->rect.width, ymin = dst->rect.y + dst->rect.height;
-        xmax = dst->rect.x, ymax = dst->rect.y;
-    } else {
-        xmin = ymin = xmax = ymax = 0;
-    }
-
-    affine = dst->affine;
-    if (cairo_matrix_invert (&affine) != CAIRO_STATUS_SUCCESS)
-      return;
-
-    cairo_matrix_multiply (&affine, &src->affine, &affine);
-
-    for (i = 0; i < 4; i++) {
-        double rx, ry, x, y;
-        rx = src->rect.x + src->rect.width * (double) (i % 2);
-        ry = src->rect.y + src->rect.height * (double) (i / 2);
-        x = affine.xx * rx + affine.xy * ry + affine.x0;
-        y = affine.yx * rx + affine.yy * ry + affine.y0;
-        if (dst->virgin) {
-            xmin = xmax = x;
-            ymin = ymax = y;
-            dst->virgin = 0;
-        } else {
-            if (x < xmin)
-                xmin = x;
-            if (x > xmax)
-                xmax = x;
-            if (y < ymin)
-                ymin = y;
-            if (y > ymax)
-                ymax = y;
-        }
-    }
-
-    if (xmin < dst->rect.x)
-        xmin = dst->rect.x;
-    if (ymin < dst->rect.y)
-        ymin = dst->rect.y;
-    if (xmax > dst->rect.x + dst->rect.width)
-        xmax = dst->rect.x + dst->rect.width;
-    if (ymax > dst->rect.y + dst->rect.height)
-        ymax = dst->rect.y + dst->rect.height;
-
-    dst->rect.x = xmin;
-    dst->rect.width = xmax - xmin;
-    dst->rect.y = ymin;
-    dst->rect.height = ymax - ymin;
-}
-
-void
 rsvg_drawing_ctx_push_view_box (RsvgDrawingCtx * ctx, double w, double h)
 {
     RsvgViewBox *vb = g_new (RsvgViewBox, 1);
diff --git a/rsvg-private.h b/rsvg-private.h
index a833311..5785b01 100644
--- a/rsvg-private.h
+++ b/rsvg-private.h
@@ -264,6 +264,7 @@ typedef struct {
     LengthDir dir;
 } RsvgLength;
 
+/* Keep this in sync with rust/src/bbox.rs:RsvgBbox */
 typedef struct {
     cairo_rectangle_t rect;
     cairo_matrix_t affine;
@@ -424,10 +425,16 @@ cairo_surface_t *rsvg_get_surface_of_node (RsvgDrawingCtx * ctx, RsvgNode * draw
 
 G_GNUC_INTERNAL
 void rsvg_drawing_ctx_free (RsvgDrawingCtx * handle);
+
+/* Implemented in rust/src/bbox.rs */
 G_GNUC_INTERNAL
 void rsvg_bbox_init     (RsvgBbox * self, cairo_matrix_t *matrix);
+
+/* Implemented in rust/src/bbox.rs */
 G_GNUC_INTERNAL
 void rsvg_bbox_insert   (RsvgBbox * dst, RsvgBbox * src);
+
+/* Implemented in rust/src/bbox.rs */
 G_GNUC_INTERNAL
 void rsvg_bbox_clip     (RsvgBbox * dst, RsvgBbox * src);
 
diff --git a/rust/src/bbox.rs b/rust/src/bbox.rs
new file mode 100644
index 0000000..9e34596
--- /dev/null
+++ b/rust/src/bbox.rs
@@ -0,0 +1,156 @@
+extern crate cairo;
+
+use self::cairo::MatrixTrait;
+
+/* Keep this in sync with ../../rsvg-private.h:RsvgBbox */
+#[repr(C)]
+pub struct RsvgBbox {
+    rect:   cairo::Rectangle,
+    affine: cairo::Matrix,
+    virgin: bool
+}
+
+#[no_mangle]
+pub extern fn rsvg_bbox_init (raw_bbox: *mut RsvgBbox, raw_matrix: *const cairo::Matrix) {
+    assert! (!raw_bbox.is_null ());
+    assert! (!raw_matrix.is_null ());
+
+    let bbox: &mut RsvgBbox = unsafe { &mut (*raw_bbox) };
+
+    bbox.virgin = true;
+    bbox.affine = unsafe { *raw_matrix };
+}
+
+#[no_mangle]
+pub extern fn rsvg_bbox_insert (raw_dst: *mut RsvgBbox, raw_src: *const RsvgBbox) {
+    assert! (!raw_dst.is_null ());
+    assert! (!raw_src.is_null ());
+
+    let dst: &mut RsvgBbox = unsafe { &mut (*raw_dst) };
+    let src: &RsvgBbox = unsafe { &*raw_src };
+
+    if src.virgin {
+        return;
+    }
+
+    let mut xmin: f64;
+    let mut ymin: f64;
+    let mut xmax: f64;
+    let mut ymax: f64;
+
+    if !dst.virgin {
+        xmin = dst.rect.x;
+        ymin = dst.rect.y;
+        xmax = dst.rect.x + dst.rect.width;
+        ymax = dst.rect.y + dst.rect.height;
+    } else {
+        xmin = 0.0;
+        ymin = 0.0;
+        xmax = 0.0;
+        ymax = 0.0;
+    }
+
+    let mut affine = dst.affine;
+
+    affine.invert (); // this will panic!() if it's not invertible... should we check on our own?
+    affine = cairo::Matrix::multiply (&src.affine, &affine);
+
+    /* This is a trick.  We want to transform each of the corners of
+     * the rectangle defined by src.rect with the affine
+     * transformation, and get the bounding box of all the four
+     * resulting points.  The modulus and division accomplish this by
+     * running through all the combinations of adding or not adding
+     * the width/height to the first point src.rect.(x, y).
+     */
+    for i in 0..4 {
+        let rx: f64 = src.rect.x + src.rect.width * (i % 2) as f64;
+        let ry: f64 = src.rect.y + src.rect.height * (i / 2) as f64;
+        let x: f64  = affine.xx * rx + affine.xy * ry + affine.x0;
+        let y: f64  = affine.yx * rx + affine.yy * ry + affine.y0;
+
+        if dst.virgin {
+            xmin = x;
+            xmax = x;
+            ymin = y;
+            ymax = y;
+            dst.virgin = false;
+        } else {
+            if x < xmin { xmin = x; }
+            if x > xmax { xmax = x; }
+            if y < ymin { ymin = y; }
+            if y > ymax { ymax = y; }
+        }
+    }
+
+    dst.rect.x = xmin;
+    dst.rect.y = ymin;
+    dst.rect.width = xmax - xmin;
+    dst.rect.height = ymax - ymin;
+}
+
+#[no_mangle]
+pub extern fn rsvg_bbox_clip (raw_dst: *mut RsvgBbox, raw_src: *const RsvgBbox) {
+    assert! (!raw_dst.is_null ());
+    assert! (!raw_src.is_null ());
+
+    let dst: &mut RsvgBbox = unsafe { &mut (*raw_dst) };
+    let src: &RsvgBbox = unsafe { &*raw_src };
+
+    if src.virgin {
+        return;
+    }
+
+    let mut xmin: f64;
+    let mut ymin: f64;
+    let mut xmax: f64;
+    let mut ymax: f64;
+
+    if !dst.virgin {
+        xmin = dst.rect.x + dst.rect.width;
+        ymin = dst.rect.y + dst.rect.height;
+        xmax = dst.rect.x;
+        ymax = dst.rect.y;
+    } else {
+        xmin = 0.0;
+        ymin = 0.0;
+        xmax = 0.0;
+        ymax = 0.0;
+    }
+
+    let mut affine = dst.affine;
+
+    affine.invert ();
+    affine = cairo::Matrix::multiply (&src.affine, &affine);
+
+    /* This is a trick.  See rsvg_bbox_insert() for a description of how it works. */
+    for i in 0..4 {
+        let rx: f64 = src.rect.x + src.rect.width * (i % 2) as f64;
+        let ry: f64 = src.rect.y + src.rect.height * (i / 2) as f64;
+        let x = affine.xx * rx + affine.xy * ry + affine.x0;
+        let y = affine.yx * rx + affine.yy * ry + affine.y0;
+
+        if dst.virgin {
+            xmin = x;
+            xmax = x;
+            ymin = y;
+            ymax = y;
+            dst.virgin = false;
+        } else {
+            if x < xmin { xmin = x; }
+            if x > xmax { xmax = x; }
+            if y < ymin { ymin = y; }
+            if y > ymax { ymax = y; }
+        }
+    }
+
+    if xmin < dst.rect.x { xmin = dst.rect.x; }
+    if ymin < dst.rect.y { ymin = dst.rect.y; }
+
+    if xmax > dst.rect.x + dst.rect.width { xmax = dst.rect.x + dst.rect.width; }
+    if ymax > dst.rect.y + dst.rect.height { ymax = dst.rect.y + dst.rect.height; }
+
+    dst.rect.x = xmin;
+    dst.rect.width = xmax - xmin;
+    dst.rect.y = ymin;
+    dst.rect.y = ymax - ymin;
+}
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index f6ccfa7..39b97a3 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -1,3 +1,10 @@
+pub use bbox::{
+    RsvgBbox,
+    rsvg_bbox_init,
+    rsvg_bbox_insert,
+    rsvg_bbox_clip
+};
+
 pub use gradient::{
     gradient_linear_new,
     gradient_destroy,
@@ -32,6 +39,7 @@ pub use length::{
     rsvg_length_hand_normalize,
 };
 
+mod bbox;
 mod drawing_ctx;
 mod handle;
 mod gradient;


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