[librsvg] Port NodeChars to Rust. Yay!
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] Port NodeChars to Rust. Yay!
- Date: Wed, 6 Dec 2017 01:51:28 +0000 (UTC)
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]