[librsvg] shapes.rs: NodeRect completely implemented in Rust!
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] shapes.rs: NodeRect completely implemented in Rust!
- Date: Mon, 20 Feb 2017 23:32:58 +0000 (UTC)
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]