[librsvg] shapes.rs: NodeEllipse fully implemented in Rust!



commit 7a56919ff83c4e214527f9b7c7a4d6d83c44a148
Author: Federico Mena Quintero <federico gnome org>
Date:   Mon Feb 20 18:28:36 2017 -0600

    shapes.rs: NodeEllipse fully implemented in Rust!
    
    Factor out the function to draw ellipses and circles, too.

 rsvg-base.c        |    2 +-
 rsvg-shapes.c      |  100 --------------------------------------------
 rsvg-shapes.h      |    6 ++-
 rust/src/lib.rs    |    1 +
 rust/src/shapes.rs |  118 +++++++++++++++++++++++++++++++++++++++++-----------
 5 files changed, 99 insertions(+), 128 deletions(-)
---
diff --git a/rsvg-base.c b/rsvg-base.c
index df3119b..de7155b 100644
--- a/rsvg-base.c
+++ b/rsvg-base.c
@@ -267,7 +267,7 @@ static const NodeCreator node_creators[] = {
     /* "cursor",             FALSE, */
     { "defs",                TRUE,  rsvg_new_defs },
     /* "desc",               TRUE,  */
-    { "ellipse",             TRUE,  rsvg_new_ellipse },
+    { "ellipse",             TRUE,  rsvg_node_ellipse_new },
     { "feBlend",             TRUE,  rsvg_new_filter_primitive_blend },
     { "feColorMatrix",       TRUE,  rsvg_new_filter_primitive_color_matrix },
     { "feComponentTransfer", TRUE,  rsvg_new_filter_primitive_component_transfer },
diff --git a/rsvg-shapes.c b/rsvg-shapes.c
index 0a74f58..ae091ed 100644
--- a/rsvg-shapes.c
+++ b/rsvg-shapes.c
@@ -38,9 +38,6 @@
 #include "rsvg-path-builder.h"
 #include "rsvg-marker.h"
 
-/* 4/3 * (1-cos 45ƒ)/sin 45ƒ = 4/3 * sqrt(2) - 1 */
-#define RSVG_ARC_MAGIC ((double) 0.5522847498)
-
 typedef struct _RsvgNodePoly RsvgNodePoly;
 
 struct _RsvgNodePoly {
@@ -166,100 +163,3 @@ rsvg_new_polyline (const char *element_name, RsvgNode *parent)
 {
     return rsvg_new_any_poly (RSVG_NODE_TYPE_POLYLINE, parent);
 }
-
-typedef struct _RsvgNodeEllipse RsvgNodeEllipse;
-
-struct _RsvgNodeEllipse {
-    RsvgLength cx, cy, rx, ry;
-};
-
-static void
-rsvg_node_ellipse_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
-{
-    RsvgNodeEllipse *ellipse = impl;
-    const char *value;
-
-    if ((value = rsvg_property_bag_lookup (atts, "cx")))
-        ellipse->cx = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
-    if ((value = rsvg_property_bag_lookup (atts, "cy")))
-        ellipse->cy = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
-    if ((value = rsvg_property_bag_lookup (atts, "rx")))
-        ellipse->rx = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
-    if ((value = rsvg_property_bag_lookup (atts, "ry")))
-        ellipse->ry = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
-}
-
-static void
-rsvg_node_ellipse_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
-{
-    RsvgNodeEllipse *ellipse = impl;
-    double cx, cy, rx, ry;
-    RsvgPathBuilder *builder;
-
-    cx = rsvg_length_normalize (&ellipse->cx, ctx);
-    cy = rsvg_length_normalize (&ellipse->cy, ctx);
-    rx = rsvg_length_normalize (&ellipse->rx, ctx);
-    ry = rsvg_length_normalize (&ellipse->ry, ctx);
-
-    if (rx <= 0 || ry <= 0)
-        return;
-
-    /* approximate an ellipse using 4 bezier curves */
-
-    builder = rsvg_path_builder_new ();
-
-    rsvg_path_builder_move_to (builder, cx + rx, cy);
-
-    rsvg_path_builder_curve_to (builder,
-                                cx + rx, cy - RSVG_ARC_MAGIC * ry,
-                                cx + RSVG_ARC_MAGIC * rx, cy - ry,
-                                cx, cy - ry);
-
-    rsvg_path_builder_curve_to (builder,
-                                cx - RSVG_ARC_MAGIC * rx, cy - ry,
-                                cx - rx, cy - RSVG_ARC_MAGIC * ry,
-                                cx - rx, cy);
-
-    rsvg_path_builder_curve_to (builder,
-                                cx - rx, cy + RSVG_ARC_MAGIC * ry,
-                                cx - RSVG_ARC_MAGIC * rx, cy + ry,
-                                cx, cy + ry);
-
-    rsvg_path_builder_curve_to (builder,
-                                cx + RSVG_ARC_MAGIC * rx, cy + ry,
-                                cx + rx, cy + RSVG_ARC_MAGIC * ry,
-                                cx + rx, cy);
-
-    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_ellipse_free (gpointer impl)
-{
-    RsvgNodeEllipse *ellipse = impl;
-
-    g_free (ellipse);
-}
-
-RsvgNode *
-rsvg_new_ellipse (const char *element_name, RsvgNode *parent)
-{
-    RsvgNodeEllipse *ellipse;
-
-    ellipse = g_new0 (RsvgNodeEllipse, 1);
-    ellipse->cx = ellipse->cy = ellipse->rx = ellipse->ry = rsvg_length_parse ("0", LENGTH_DIR_BOTH);
-
-    return rsvg_rust_cnode_new (RSVG_NODE_TYPE_ELLIPSE,
-                                parent,
-                                rsvg_state_new (),
-                                ellipse,
-                                rsvg_node_ellipse_set_atts,
-                                rsvg_node_ellipse_draw,
-                                rsvg_node_ellipse_free);
-}
diff --git a/rsvg-shapes.h b/rsvg-shapes.h
index 3d21ee4..d6a0150 100644
--- a/rsvg-shapes.h
+++ b/rsvg-shapes.h
@@ -52,12 +52,14 @@ RsvgNode *rsvg_node_rect_new (const char *element_name, RsvgNode *parent);
 G_GNUC_INTERNAL
 RsvgNode *rsvg_node_circle_new (const char *element_name, RsvgNode *parent);
 
+/* Implemented in rust/src/shapes.rs */
+G_GNUC_INTERNAL
+RsvgNode *rsvg_node_ellipse_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_ellipse (const char *element_name, RsvgNode *parent);
 
 G_END_DECLS
 
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index e0047da..02116bf 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -80,6 +80,7 @@ pub use pattern::{
 
 pub use shapes::{
     rsvg_node_circle_new,
+    rsvg_node_ellipse_new,
     rsvg_node_line_new,
     rsvg_node_path_new,
     rsvg_node_rect_new,
diff --git a/rust/src/shapes.rs b/rust/src/shapes.rs
index b91da3d..a300c80 100644
--- a/rust/src/shapes.rs
+++ b/rust/src/shapes.rs
@@ -30,6 +30,49 @@ fn render_path_builder (builder:  &RsvgPathBuilder,
     }
 }
 
+fn render_ellipse (cx: f64,
+                   cy: f64,
+                   rx: f64,
+                   ry: f64,
+                   node: &RsvgNode,
+                   draw_ctx: *const RsvgDrawingCtx,
+                   dominate: i32) {
+    // Per the spec, rx and ry must be nonnegative
+
+    if rx <= 0.0 || ry <= 0.0 {
+        return;
+    }
+
+    // 4/3 * (1-cos 45°)/sin 45° = 4/3 * sqrt(2) - 1
+    let arc_magic: f64 = 0.5522847498;
+
+    // approximate an ellipse using 4 Bézier curves
+
+    let mut builder = RsvgPathBuilder::new ();
+
+    builder.move_to (cx + rx, cy);
+
+    builder.curve_to (cx + rx, cy - arc_magic * ry,
+                      cx + arc_magic * rx, cy - ry,
+                      cx, cy - ry);
+
+    builder.curve_to (cx - arc_magic * rx, cy - ry,
+                      cx - rx, cy - arc_magic * ry,
+                      cx - rx, cy);
+
+    builder.curve_to (cx - rx, cy + arc_magic * ry,
+                      cx - arc_magic * rx, cy + ry,
+                      cx, cy + ry);
+
+    builder.curve_to (cx + arc_magic * rx, cy + ry,
+                      cx + rx, cy + arc_magic * ry,
+                      cx + rx, cy);
+
+    builder.close_path ();
+
+    render_path_builder (&builder, draw_ctx, node.get_state (), dominate, false);
+}
+
 /***** NodePath *****/
 
 struct NodePath {
@@ -381,40 +424,57 @@ impl NodeTrait for NodeCircle {
         let cy = self.cy.get ().normalize (draw_ctx);
         let r = self.r.get ().normalize (draw_ctx);
 
-        // Per the spec, r must be nonnegative
-        if r <= 0.0 {
-            return;
-        }
-
-        // 4/3 * (1-cos 45°)/sin 45° = 4/3 * sqrt(2) - 1
-        let arc_magic: f64 = 0.5522847498;
+        render_ellipse (cx, cy, r, r, node, draw_ctx, dominate);
+    }
 
-        // approximate a circle using 4 Bézier curves
+    fn get_c_impl (&self) -> *const RsvgCNodeImpl {
+        ptr::null ()
+    }
+}
 
-        let mut builder = RsvgPathBuilder::new ();
+/***** NodeEllipse *****/
 
-        builder.move_to (cx + r, cy);
+struct NodeEllipse {
+    cx: Cell <RsvgLength>,
+    cy: Cell <RsvgLength>,
+    rx: Cell <RsvgLength>,
+    ry: Cell <RsvgLength>
+}
 
-        builder.curve_to (cx + r, cy + r * arc_magic,
-                          cx + r * arc_magic, cy + r,
-                          cx, cy + r);
+impl NodeEllipse {
+    fn new () -> NodeEllipse {
+        NodeEllipse {
+            cx: Cell::new (RsvgLength::default ()),
+            cy: Cell::new (RsvgLength::default ()),
+            rx: Cell::new (RsvgLength::default ()),
+            ry: Cell::new (RsvgLength::default ()),
+        }
+    }
+}
 
-        builder.curve_to (cx - r * arc_magic, cy + r,
-                          cx - r, cy + r * arc_magic,
-                          cx - r, cy);
+impl NodeTrait for NodeEllipse {
+    fn set_atts (&self, _: &RsvgNode, _: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
+        self.cx.set (property_bag::lookup (pbag, "cx").map_or (RsvgLength::default (),
+                                                              |v| RsvgLength::parse (&v, 
LengthDir::Horizontal)));
 
-        builder.curve_to (cx - r, cy - r * arc_magic,
-                          cx - r * arc_magic, cy - r,
-                          cx, cy - r);
+        self.cy.set (property_bag::lookup (pbag, "cy").map_or (RsvgLength::default (),
+                                                               |v| RsvgLength::parse (&v, 
LengthDir::Vertical)));
+    
+        self.rx.set (property_bag::lookup (pbag, "rx").map_or (RsvgLength::default (),
+                                                               |v| RsvgLength::parse (&v, 
LengthDir::Horizontal)));
 
-        builder.curve_to (cx + r * arc_magic, cy - r,
-                          cx + r, cy - r * arc_magic,
-                          cx + r, cy);
+        self.ry.set (property_bag::lookup (pbag, "ry").map_or (RsvgLength::default (),
+                                                               |v| RsvgLength::parse (&v, 
LengthDir::Vertical)));
+    }
 
-        builder.close_path ();
+    fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
+        let cx = self.cx.get ().normalize (draw_ctx);
+        let cy = self.cy.get ().normalize (draw_ctx);
+        let rx = self.rx.get ().normalize (draw_ctx);
+        let ry = self.ry.get ().normalize (draw_ctx);
 
-        render_path_builder (&builder, draw_ctx, node.get_state (), dominate, false);
-    }
+        render_ellipse (cx, cy, rx, ry, node, draw_ctx, dominate);
+    }        
 
     fn get_c_impl (&self) -> *const RsvgCNodeImpl {
         ptr::null ()
@@ -454,3 +514,11 @@ pub extern fn rsvg_node_circle_new (_: *const libc::c_char, raw_parent: *const R
                                   drawing_ctx::state_new (),
                                   Box::new (NodeCircle::new ()))))
 }
+
+#[no_mangle]
+pub extern fn rsvg_node_ellipse_new (_: *const libc::c_char, raw_parent: *const RsvgNode) -> *const RsvgNode 
{
+    box_node (Rc::new (Node::new (NodeType::Ellipse,
+                                  parent_ptr_to_weak (raw_parent),
+                                  drawing_ctx::state_new (),
+                                  Box::new (NodeEllipse::new ()))))
+}


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