[librsvg] shapes.rs: NodeRect completely implemented in Rust!



commit 489cd04ea075b78821bbfdc01292855968ed30c2
Author: Federico Mena Quintero <federico gnome org>
Date:   Mon Feb 20 17:30:18 2017 -0600

    shapes.rs: NodeRect completely implemented in Rust!

 rsvg-base.c        |    2 +-
 rsvg-shapes.c      |  194 +-------------------------------------------------
 rsvg-shapes.h      |    6 +-
 rust/src/lib.rs    |    1 +
 rust/src/shapes.rs |  205 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 210 insertions(+), 198 deletions(-)
---
diff --git a/rsvg-base.c b/rsvg-base.c
index 983576c..9671d63 100644
--- a/rsvg-base.c
+++ b/rsvg-base.c
@@ -318,7 +318,7 @@ static const NodeCreator node_creators[] = {
     { "polygon",             TRUE,  rsvg_new_polygon },
     { "polyline",            TRUE,  rsvg_new_polyline },
     { "radialGradient",      TRUE,  rsvg_new_radial_gradient },
-    { "rect",                TRUE,  rsvg_new_rect },
+    { "rect",                TRUE,  rsvg_node_rect_new },
     /* "script",             FALSE, */
     /* "set",                FALSE, */
     { "stop",                TRUE,  rsvg_new_stop },
diff --git a/rsvg-shapes.c b/rsvg-shapes.c
index 1ef1a9f..5ba3f59 100644
--- a/rsvg-shapes.c
+++ b/rsvg-shapes.c
@@ -167,198 +167,6 @@ rsvg_new_polyline (const char *element_name, RsvgNode *parent)
     return rsvg_new_any_poly (RSVG_NODE_TYPE_POLYLINE, parent);
 }
 
-typedef struct _RsvgNodeRect RsvgNodeRect;
-
-struct _RsvgNodeRect {
-    RsvgLength x, y, w, h, rx, ry;
-    gboolean got_rx, got_ry;
-};
-
-static void
-rsvg_node_rect_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
-{
-    RsvgNodeRect *rect = impl;
-    const char *value;
-
-    /* FIXME: negative w/h/rx/ry is an error, per http://www.w3.org/TR/SVG11/shapes.html#RectElement */
-    if ((value = rsvg_property_bag_lookup (atts, "x")))
-        rect->x = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
-    if ((value = rsvg_property_bag_lookup (atts, "y")))
-        rect->y = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
-    if ((value = rsvg_property_bag_lookup (atts, "width")))
-        rect->w = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
-    if ((value = rsvg_property_bag_lookup (atts, "height")))
-        rect->h = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
-    if ((value = rsvg_property_bag_lookup (atts, "rx"))) {
-        rect->rx = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
-        rect->got_rx = TRUE;
-    }
-    if ((value = rsvg_property_bag_lookup (atts, "ry"))) {
-        rect->ry = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
-        rect->got_ry = TRUE;
-    }
-}
-
-static void
-rsvg_node_rect_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
-{
-    RsvgNodeRect *rect = impl;
-    double x, y, w, h, rx, ry;
-    double half_w, half_h;
-    RsvgPathBuilder *builder;
-
-    x = rsvg_length_normalize (&rect->x, ctx);
-    y = rsvg_length_normalize (&rect->y, ctx);
-
-    /* FIXME: negative w/h/rx/ry is an error, per http://www.w3.org/TR/SVG11/shapes.html#RectElement
-     * For now we'll just take the absolute value.
-     */
-    w = fabs (rsvg_length_normalize (&rect->w, ctx));
-    h = fabs (rsvg_length_normalize (&rect->h, ctx));
-    rx = fabs (rsvg_length_normalize (&rect->rx, ctx));
-    ry = fabs (rsvg_length_normalize (&rect->ry, ctx));
-
-    if (w == 0. || h == 0.)
-        return;
-
-    if (rect->got_rx && !rect->got_ry)
-        ry = rx;
-    else if (!rect->got_rx && rect->got_ry)
-        rx = ry;
-
-    half_w = w / 2;
-    half_h = h / 2;
-
-    if (rx > half_w)
-        rx = half_w;
-
-    if (ry > half_h)
-        ry = half_h;
-
-    if (rx == 0)
-        ry = 0;
-    else if (ry == 0)
-        rx = 0;
-
-    builder = rsvg_path_builder_new ();
-
-    if (rx == 0) {
-        /* Easy case, no rounded corners */
-
-        rsvg_path_builder_move_to (builder, x, y);
-        rsvg_path_builder_line_to (builder, x + w, y);
-        rsvg_path_builder_line_to (builder, x + w, y + h);
-        rsvg_path_builder_line_to (builder, x, y + h);
-        rsvg_path_builder_line_to (builder, x, y);
-        rsvg_path_builder_close_path (builder);
-    } else {
-        double top_x1, top_x2, top_y;
-        double bottom_x1, bottom_x2, bottom_y;
-        double left_x, left_y1, left_y2;
-        double right_x, right_y1, right_y2;
-
-        /* Hard case, rounded corners
-         *
-         *      (top_x1, top_y)                   (top_x2, top_y)
-         *     *--------------------------------*
-         *    /                                  \
-         *   * (left_x, left_y1)                  * (right_x, right_y1)
-         *   |                                    |
-         *   |                                    |
-         *   |                                    |
-         *   |                                    |
-         *   |                                    |
-         *   |                                    |
-         *   |                                    |
-         *   |                                    |
-         *   |                                    |
-         *   * (left_x, left_y2)                  * (right_x, right_y2)
-         *    \                                  /
-         *     *--------------------------------*
-         *      (bottom_x1, bottom_y)            (bottom_x2, bottom_y)
-         */
-
-        top_x1 = x + rx;
-        top_x2 = x + w - rx;
-        top_y  = y;
-
-        bottom_x1 = top_x1;
-        bottom_x2 = top_x2;
-        bottom_y  = y + h;
-
-        left_x = x;
-        left_y1 = y + ry;
-        left_y2 = y + h - ry;
-
-        right_x = x + w;
-        right_y1 = left_y1;
-        right_y2 = left_y2;
-
-        rsvg_path_builder_move_to (builder, top_x1, top_y);
-        rsvg_path_builder_line_to (builder, top_x2, top_y);
-
-        rsvg_path_builder_arc (builder,
-                               top_x2, top_y,
-                               rx, ry, 0, FALSE, TRUE,
-                               right_x, right_y1);
-
-        rsvg_path_builder_line_to (builder, right_x, right_y2);
-
-        rsvg_path_builder_arc (builder,
-                               right_x, right_y2,
-                               rx, ry, 0, FALSE, TRUE,
-                               bottom_x2, bottom_y);
-
-        rsvg_path_builder_line_to (builder, bottom_x1, bottom_y);
-
-        rsvg_path_builder_arc (builder,
-                               bottom_x1, bottom_y,
-                               rx, ry, 0, FALSE, TRUE,
-                               left_x, left_y2);
-
-        rsvg_path_builder_line_to (builder, left_x, left_y1);
-
-        rsvg_path_builder_arc (builder,
-                               left_x, left_y1,
-                               rx, ry, 0, FALSE, TRUE,
-                               top_x1, top_y);
-
-        rsvg_path_builder_close_path (builder);
-    }
-
-    rsvg_state_reinherit_top (ctx, rsvg_node_get_state (node), dominate);
-
-    rsvg_render_path_builder (ctx, builder);
-
-    rsvg_path_builder_destroy (builder);
-}
-
-static void
-rsvg_node_rect_free (gpointer impl)
-{
-    RsvgNodeRect *rect = impl;
-
-    g_free (rect);
-}
-
-RsvgNode *
-rsvg_new_rect (const char *element_name, RsvgNode *parent)
-{
-    RsvgNodeRect *rect;
-
-    rect = g_new0 (RsvgNodeRect, 1);
-    rect->x = rect->y = rect->w = rect->h = rect->rx = rect->ry = rsvg_length_parse ("0", LENGTH_DIR_BOTH);
-    rect->got_rx = rect->got_ry = FALSE;
-
-    return rsvg_rust_cnode_new (RSVG_NODE_TYPE_RECT,
-                                parent,
-                                rsvg_state_new (),
-                                rect,
-                                rsvg_node_rect_set_atts,
-                                rsvg_node_rect_draw,
-                                rsvg_node_rect_free);
-}
-
 typedef struct _RsvgNodeCircle RsvgNodeCircle;
 
 struct _RsvgNodeCircle {
@@ -528,7 +336,7 @@ rsvg_node_ellipse_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int
 static void
 rsvg_node_ellipse_free (gpointer impl)
 {
-    RsvgNodeRect *ellipse = impl;
+    RsvgNodeEllipse *ellipse = impl;
 
     g_free (ellipse);
 }
diff --git a/rsvg-shapes.h b/rsvg-shapes.h
index 855f9e1..b7cef55 100644
--- a/rsvg-shapes.h
+++ b/rsvg-shapes.h
@@ -44,13 +44,15 @@ RsvgNode *rsvg_node_path_new (const char *element_name, RsvgNode *parent);
 G_GNUC_INTERNAL
 RsvgNode *rsvg_node_line_new (const char *element_name, RsvgNode *parent);
 
+/* Implemented in rust/src/shapes.rs */
+G_GNUC_INTERNAL
+RsvgNode *rsvg_node_rect_new (const char *element_name, RsvgNode *parent);
+
 G_GNUC_INTERNAL
 RsvgNode *rsvg_new_polygon (const char *element_name, RsvgNode *parent);
 G_GNUC_INTERNAL
 RsvgNode *rsvg_new_polyline (const char *element_name, RsvgNode *parent);
 G_GNUC_INTERNAL
-RsvgNode *rsvg_new_rect (const char *element_name, RsvgNode *parent);
-G_GNUC_INTERNAL
 RsvgNode *rsvg_new_circle (const char *element_name, RsvgNode *parent);
 G_GNUC_INTERNAL
 RsvgNode *rsvg_new_ellipse (const char *element_name, RsvgNode *parent);
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index ae61d88..1ceb665 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -81,6 +81,7 @@ pub use pattern::{
 pub use shapes::{
     rsvg_node_line_new,
     rsvg_node_path_new,
+    rsvg_node_rect_new,
 };
 pub use viewbox::{
     RsvgViewBox
diff --git a/rust/src/shapes.rs b/rust/src/shapes.rs
index adf6a7d..830a81e 100644
--- a/rust/src/shapes.rs
+++ b/rust/src/shapes.rs
@@ -153,10 +153,203 @@ impl NodeTrait for NodeLine {
     }
 }
 
+/***** NodeRect *****/
+
+struct NodeRect {
+    // x, y, width, height
+    x: Cell<RsvgLength>,
+    y: Cell<RsvgLength>,
+    w: Cell<RsvgLength>,
+    h: Cell<RsvgLength>,
+
+    // Radiuses for rounded corners
+    rx: Cell<Option<RsvgLength>>,
+    ry: Cell<Option<RsvgLength>>
+}
+
+impl NodeRect {
+    fn new () -> NodeRect {
+        NodeRect {
+            x: Cell::new (RsvgLength::default ()),
+            y: Cell::new (RsvgLength::default ()),
+            w: Cell::new (RsvgLength::default ()),
+            h: Cell::new (RsvgLength::default ()),
+
+            rx: Cell::new (None),
+            ry: Cell::new (None)
+        }
+    }
+}
+
+impl NodeTrait for NodeRect {
+    fn set_atts (&self, _: &RsvgNode, _: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
+        self.x.set (property_bag::lookup (pbag, "x").map_or (RsvgLength::default (),
+                                                             |v| RsvgLength::parse (&v, 
LengthDir::Horizontal)));
+
+        self.y.set (property_bag::lookup (pbag, "y").map_or (RsvgLength::default (),
+                                                             |v| RsvgLength::parse (&v, 
LengthDir::Vertical)));
+
+        self.w.set (property_bag::lookup (pbag, "width").map_or (RsvgLength::default (),
+                                                                 |v| RsvgLength::parse (&v, 
LengthDir::Horizontal)));
+
+        self.h.set (property_bag::lookup (pbag, "height").map_or (RsvgLength::default (),
+                                                                  |v| RsvgLength::parse (&v, 
LengthDir::Vertical)));
+
+        self.rx.set (property_bag::lookup (pbag, "rx").map_or (None,
+                                                               |v| Some (RsvgLength::parse (&v, 
LengthDir::Horizontal))));
+
+        self.ry.set (property_bag::lookup (pbag, "ry").map_or (None,
+                                                               |v| Some (RsvgLength::parse (&v, 
LengthDir::Vertical))));
+    }
+
+    fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
+        let x = self.x.get ().normalize (draw_ctx);
+        let y = self.y.get ().normalize (draw_ctx);
+
+        let w = self.w.get ().normalize (draw_ctx);
+        let h = self.h.get ().normalize (draw_ctx);
+
+        let mut rx;
+        let mut ry;
+
+        match (self.rx.get (), self.ry.get ()) {
+            (None, None) => {
+                rx = 0.0;
+                ry = 0.0;
+            },
+
+            (Some (_rx), None) => {
+                rx = _rx.normalize (draw_ctx);
+                ry = _rx.normalize (draw_ctx);
+            },
+
+            (None, Some (_ry)) => {
+                rx = _ry.normalize (draw_ctx);
+                ry = _ry.normalize (draw_ctx);
+            },
+
+            (Some (_rx), Some (_ry)) => {
+                rx = _rx.normalize (draw_ctx);
+                ry = _ry.normalize (draw_ctx);
+            }
+        }
+
+        // Per the spec, w,h must be >= 0
+        if w <= 0.0 || h <= 0.0 {
+            return;
+        }
+
+        // ... and rx,ry must be nonnegative
+        if rx < 0.0 || ry < 0.0 {
+            return;
+        }
+
+        let half_w = w / 2.0;
+        let half_h = h / 2.0;
+
+        if rx > half_w {
+            rx = half_w;
+        }
+
+        if ry > half_h {
+            ry = half_h;
+        }
+
+        if rx == 0.0 {
+            ry = 0.0;
+        } else if ry == 0.0 {
+            rx = 0.0;
+        }
+
+        let mut builder = RsvgPathBuilder::new ();
+
+        if rx == 0.0 {
+            /* Easy case, no rounded corners */
+
+            builder.move_to (x, y);
+            builder.line_to (x + w, y);
+            builder.line_to (x + w, y + h);
+            builder.line_to (x, y + h);
+            builder.line_to (x, y);
+            builder.close_path ();
+        } else {
+            /* Hard case, rounded corners
+             *
+             *      (top_x1, top_y)                   (top_x2, top_y)
+             *     *--------------------------------*
+             *    /                                  \
+             *   * (left_x, left_y1)                  * (right_x, right_y1)
+             *   |                                    |
+             *   |                                    |
+             *   |                                    |
+             *   |                                    |
+             *   |                                    |
+             *   |                                    |
+             *   |                                    |
+             *   |                                    |
+             *   |                                    |
+             *   * (left_x, left_y2)                  * (right_x, right_y2)
+             *    \                                  /
+             *     *--------------------------------*
+             *      (bottom_x1, bottom_y)            (bottom_x2, bottom_y)
+             */
+
+            let top_x1 = x + rx;
+            let top_x2 = x + w - rx;
+            let top_y  = y;
+
+            let bottom_x1 = top_x1;
+            let bottom_x2 = top_x2;
+            let bottom_y  = y + h;
+
+            let left_x  = x;
+            let left_y1 = y + ry;
+            let left_y2 = y + h - ry;
+
+            let right_x  = x + w;
+            let right_y1 = left_y1;
+            let right_y2 = left_y2;
+
+            builder.move_to (top_x1, top_y);
+            builder.line_to (top_x2, top_y);
+
+            builder.arc (top_x2, top_y,
+                         rx, ry, 0.0, false, true,
+                         right_x, right_y1);
+
+            builder.line_to (right_x, right_y2);
+
+            builder.arc (right_x, right_y2,
+                         rx, ry, 0.0, false, true,
+                         bottom_x2, bottom_y);
+
+            builder.line_to (bottom_x1, bottom_y);
+
+            builder.arc (bottom_x1, bottom_y,
+                         rx, ry, 0.0, false, true,
+                         left_x, left_y2);
+
+            builder.line_to (left_x, left_y1);
+
+            builder.arc (left_x, left_y1,
+                         rx, ry, 0.0, false, true,
+                         top_x1, top_y);
+
+            builder.close_path ();
+        }
+
+        render_path_builder (&builder, draw_ctx, node.get_state (), dominate, false);
+    }
+
+    fn get_c_impl (&self) -> *const RsvgCNodeImpl {
+        ptr::null ()
+    }
+}
+
 /***** C Prototypes *****/
 
 #[no_mangle]
-pub extern fn rsvg_node_path_new (element_name: *const libc::c_char, raw_parent: *const RsvgNode) -> *const 
RsvgNode {
+pub extern fn rsvg_node_path_new (_: *const libc::c_char, raw_parent: *const RsvgNode) -> *const RsvgNode {
     box_node (Rc::new (Node::new (NodeType::Path,
                                   parent_ptr_to_weak (raw_parent),
                                   drawing_ctx::state_new (),
@@ -164,9 +357,17 @@ pub extern fn rsvg_node_path_new (element_name: *const libc::c_char, raw_parent:
 }
 
 #[no_mangle]
-pub extern fn rsvg_node_line_new (element_name: *const libc::c_char, raw_parent: *const RsvgNode) -> *const 
RsvgNode {
+pub extern fn rsvg_node_line_new (_: *const libc::c_char, raw_parent: *const RsvgNode) -> *const RsvgNode {
     box_node (Rc::new (Node::new (NodeType::Line,
                                   parent_ptr_to_weak (raw_parent),
                                   drawing_ctx::state_new (),
                                   Box::new (NodeLine::new ()))))
 }
+
+#[no_mangle]
+pub extern fn rsvg_node_rect_new (_: *const libc::c_char, raw_parent: *const RsvgNode) -> *const RsvgNode {
+    box_node (Rc::new (Node::new (NodeType::Rect,
+                                  parent_ptr_to_weak (raw_parent),
+                                  drawing_ctx::state_new (),
+                                  Box::new (NodeRect::new ()))))
+}


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