[librsvg] Port NodeChars to Rust. Yay!



commit 9b2b5ba5cf8a1d5efdafdbc06040460dc9f7895f
Author: Federico Mena Quintero <federico gnome org>
Date:   Tue Dec 5 19:25:39 2017 -0600

    Port NodeChars to Rust.  Yay!

 Makefile.am       |    1 +
 rsvg-base.c       |   85 ++------------------------------------
 rsvg-private.h    |    1 +
 rust/src/chars.rs |  118 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 rust/src/lib.rs   |    7 +++
 5 files changed, 132 insertions(+), 80 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index e5de7c7..63fbaa7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -70,6 +70,7 @@ RUST_SOURCES =                                        \
        rust/Cargo.toml                         \
        rust/src/aspect_ratio.rs                \
        rust/src/bbox.rs                        \
+       rust/src/chars.rs                       \
        rust/src/clip_path.rs                   \
        rust/src/cnode.rs                       \
        rust/src/color.rs                       \
diff --git a/rsvg-base.c b/rsvg-base.c
index cde82a4..ad94d45 100644
--- a/rsvg-base.c
+++ b/rsvg-base.c
@@ -882,86 +882,11 @@ rsvg_end_element (void *data, const xmlChar * xmlname)
     }
 }
 
-typedef struct {
-    GString *contents;
-} RsvgNodeChars;
-
-static void
-rsvg_node_chars_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag * atts)
-{
-    /* nothing */
-}
-
-static void
-rsvg_node_chars_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
-{
-    /* nothing */
-}
-
-static void
-rsvg_node_chars_free (gpointer impl)
-{
-    RsvgNodeChars *self = impl;
-    g_string_free (self->contents, TRUE);
-    g_free (self);
-}
-
-static void
-rsvg_node_chars_append (RsvgNode *node,
-                        const char *text,
-                        gssize len)
-{
-    RsvgNodeChars *chars;
-
-    g_assert (rsvg_node_get_type (node) == RSVG_NODE_TYPE_CHARS);
-    chars = rsvg_rust_cnode_get_impl (node);
-
-    if (!g_utf8_validate (text, len, NULL)) {
-        char *utf8;
+/* Implemented in rust/src/chars.rs */
+extern RsvgNode *rsvg_node_chars_new(RsvgNode *parent);
 
-        utf8 = rsvg_make_valid_utf8 (text, len);
-        g_string_append (chars->contents, utf8);
-        g_free (utf8);
-    } else {
-        g_string_append_len (chars->contents, text, len);
-    }
-}
-
-static RsvgNode *
-rsvg_new_node_chars (RsvgNode *parent)
-{
-    RsvgNodeChars *self;
-    RsvgState *state;
-    RsvgNode *node;
-
-    self = g_new0 (RsvgNodeChars, 1);
-    self->contents = g_string_new (NULL);
-
-    state = rsvg_state_new ();
-    state->cond_true = FALSE;
-
-    node = rsvg_rust_cnode_new (RSVG_NODE_TYPE_CHARS,
-                                parent,
-                                state,
-                                self,
-                                rsvg_node_chars_set_atts,
-                                rsvg_node_chars_draw,
-                                rsvg_node_chars_free);
-
-    return node;
-}
-
-void
-rsvg_node_chars_get_string (RsvgNode *node, const char **out_str, gsize *out_len)
-{
-    RsvgNodeChars *chars;
-
-    g_assert (rsvg_node_get_type (node) == RSVG_NODE_TYPE_CHARS);
-    chars = rsvg_rust_cnode_get_impl (node);
-
-    *out_str = chars->contents->str;
-    *out_len = chars->contents->len;
-}
+/* Implemented in rust/src/chars.rs */
+extern void rsvg_node_chars_append (RsvgNode *node, const char *text, gssize len);
 
 static gboolean
 find_last_chars_node (RsvgNode *node, gpointer data)
@@ -999,7 +924,7 @@ rsvg_characters_impl (RsvgHandle * ctx, const xmlChar * ch, gssize len)
     }
 
     if (!node) {
-        node = rsvg_new_node_chars (ctx->priv->currentnode);
+        node = rsvg_node_chars_new (ctx->priv->currentnode);
         add_node_to_handle (ctx, node);
 
         if (ctx->priv->currentnode)
diff --git a/rsvg-private.h b/rsvg-private.h
index f2bb025..d4afa7b 100644
--- a/rsvg-private.h
+++ b/rsvg-private.h
@@ -424,6 +424,7 @@ void rsvg_node_foreach_child (RsvgNode *node, RsvgNodeForeachChildFn fn, gpointe
 G_GNUC_INTERNAL
 void rsvg_node_draw_children (RsvgNode *node, RsvgDrawingCtx *ctx, int dominate);
 
+/* Implemented in rust/src/chars.rs */
 G_GNUC_INTERNAL
 void rsvg_node_chars_get_string (RsvgNode *node, const char **out_str, gsize *out_len);
 
diff --git a/rust/src/chars.rs b/rust/src/chars.rs
new file mode 100644
index 0000000..3faa558
--- /dev/null
+++ b/rust/src/chars.rs
@@ -0,0 +1,118 @@
+use libc;
+use std;
+use std::cell::RefCell;
+
+use drawing_ctx::{self, RsvgDrawingCtx};
+use handle::RsvgHandle;
+use node::{NodeResult, NodeTrait, NodeType, RsvgCNodeImpl, RsvgNode, boxed_node_new, rsvg_node_get_state};
+use property_bag::RsvgPropertyBag;
+
+/// Container for XML character data.
+///
+/// In SVG text elements, we use `NodeChars` to store character data.  For example,
+/// an element like `<text>Foo Bar</text>` will be a `NodeText` with a single child,
+/// and the child will be a `NodeChars` with "Foo Bar" for its contents.
+/// ```
+///
+/// Text elements can contain `<tspan>` sub-elements.  In this case,
+/// those `tspan` nodes will also contain `NodeChars` children.
+///
+/// A text or tspan element can contain more than one `NodeChars` child, for example,
+/// if there is an XML comment that splits the character contents in two:
+///
+/// ```xml
+/// <text>
+///   This sentence will create a NodeChars.
+///   <!-- this comment is ignored -->
+///   This sentence will cretea another NodeChars.
+/// </text>
+/// ```
+///
+/// When rendering a text element, it will take care of concatenating
+/// the strings in its `NodeChars` children as appropriate, depending
+/// on the `xml:space="preserve"` attribute.  A `NodeChars` stores the
+/// characters verbatim as they come out of the XML parser, after
+/// ensuring that they are valid UTF-8.
+struct NodeChars {
+    string: RefCell<String>
+}
+
+impl NodeChars {
+    fn new() -> NodeChars {
+        NodeChars {
+            string: RefCell::new(String::new())
+        }
+    }
+
+    fn append(&self, s: &str) {
+        self.string.borrow_mut().push_str(s);
+    }
+}
+
+impl NodeTrait for NodeChars {
+    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: *const RsvgPropertyBag) -> NodeResult {
+        Ok(())
+    }
+
+    fn draw(&self, _: &RsvgNode, _: *const RsvgDrawingCtx, _: i32) {
+        // nothing
+    }
+
+    fn get_c_impl(&self) -> *const RsvgCNodeImpl {
+        unreachable!();
+    }
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_chars_new(raw_parent: *const RsvgNode) -> *const RsvgNode {
+    let node = boxed_node_new(NodeType::Chars,
+                              raw_parent,
+                              Box::new(NodeChars::new()));
+
+    let state = rsvg_node_get_state(node);
+    drawing_ctx::state_set_cond_true(state, false);
+
+    node
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_chars_append(raw_node: *const RsvgNode,
+                                     text: *const libc::c_char,
+                                     len:  isize) {
+    assert!(!raw_node.is_null ());
+    let node: &RsvgNode = unsafe { & *raw_node };
+
+    assert!(!text.is_null());
+    assert!(len >= 0);
+
+    // We don't use from_glib to convert the text here, since we are
+    // not sure that it actually is valid UTF-8.  We can't use CStr
+    // because we are not getting passed nul-terminated data.  We'll
+    // do this by hand instead.
+
+    let bytes = unsafe { std::slice::from_raw_parts(text as *const u8, len as usize) };
+    let utf8 = String::from_utf8_lossy(bytes);
+
+    node.with_impl(|chars: &NodeChars| {
+        chars.append(&utf8);
+    });
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_chars_get_string(raw_node: *const RsvgNode,
+                                         out_str: *mut *const libc::c_char,
+                                         out_len: *mut usize) {
+    assert! (!raw_node.is_null ());
+    let node: &RsvgNode = unsafe { & *raw_node };
+
+    assert!(!out_str.is_null());
+    assert!(!out_len.is_null());
+
+    node.with_impl(|chars: &NodeChars| {
+        let s = chars.string.borrow();
+        unsafe {
+            *out_str = s.as_ptr() as *const libc::c_char;
+            *out_len = s.len();
+        }
+    });
+}
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 8924951..76a3e2c 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -15,6 +15,12 @@ pub use bbox::{
     rsvg_bbox_clip
 };
 
+pub use chars::{
+    rsvg_node_chars_new,
+    rsvg_node_chars_append,
+    rsvg_node_chars_get_string,
+};
+
 pub use clip_path::{
     rsvg_node_clip_path_new,
     rsvg_node_clip_path_get_units
@@ -141,6 +147,7 @@ mod coord_units;
 
 mod aspect_ratio;
 mod bbox;
+mod chars;
 mod clip_path;
 mod cnode;
 mod color;


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