[librsvg: 1/2] load: move some chars handling logic to rust



commit 9e137b5389936782e0c18305a4d8dec482cd89c3
Author: Paolo Borelli <pborelli gnome org>
Date:   Wed Jul 18 23:46:49 2018 +0200

    load: move some chars handling logic to rust

 librsvg/rsvg-load.c        | 85 ++++++----------------------------------------
 rsvg_internals/src/lib.rs  |  2 +-
 rsvg_internals/src/node.rs | 83 +++++++++++++++++++++++++++-----------------
 rsvg_internals/src/text.rs |  8 +++++
 4 files changed, 72 insertions(+), 106 deletions(-)
---
diff --git a/librsvg/rsvg-load.c b/librsvg/rsvg-load.c
index 7ba7c1b8..bf914806 100644
--- a/librsvg/rsvg-load.c
+++ b/librsvg/rsvg-load.c
@@ -625,97 +625,34 @@ sax_end_element_cb (void *data, const xmlChar * xmlname)
     }
 }
 
+/* Implemented in rust/src/node.rs */
+extern RsvgNode *rsvg_node_find_last_chars_child(RsvgNode *node, gboolean *accept_chars);
+
 /* Implemented in rust/src/text.rs */
 extern RsvgNode *rsvg_node_chars_new(RsvgNode *parent);
 
 /* Implemented in rust/src/text.rs */
 extern void rsvg_node_chars_append (RsvgNode *node, const char *text, gssize len);
 
-static gboolean
-node_is_text_or_tspan (RsvgNode *node)
-{
-    RsvgNodeType type;
-
-    if (!node) {
-        return FALSE;
-    }
-
-    type = rsvg_node_get_type (node);
-    return type == RSVG_NODE_TYPE_TEXT || type == RSVG_NODE_TYPE_TSPAN;
-}
-
-/* Finds the last chars child inside a given @node to which new characters can
- * be appended.  @node can be null; in this case we'll return NULL as we didn't
- * find any children.
- */
-static RsvgNode *
-find_last_chars_child (RsvgNode *node)
-{
-    RsvgNode *child = NULL;
-
-    RsvgNode *temp;
-    RsvgNodeChildrenIter *iter;
-
-    if (node_is_text_or_tspan (node)) {
-        /* find the last CHARS node in the text or tspan node, so that we can
-         * coalesce the text, and thus avoid screwing up the Pango layouts.
-         */
-        iter = rsvg_node_children_iter_begin (node);
-
-        while (rsvg_node_children_iter_next_back (iter, &temp)) {
-            /* If a tspan node is encountered before any chars node
-             * (which means there's a tspan node after any chars nodes,
-             * because this is backwards iteration), return NULL.
-             */
-            if (rsvg_node_get_type (temp) == RSVG_NODE_TYPE_TSPAN) {
-                temp = rsvg_node_unref (temp);
-                break;
-            } else if (rsvg_node_get_type (temp) == RSVG_NODE_TYPE_CHARS) {
-                child = temp;
-                break;
-            } else {
-                temp = rsvg_node_unref (temp);
-            }
-        }
-
-        rsvg_node_children_iter_end (iter);
-    }
-
-    return child;
-}
-
-static RsvgNode *
-add_new_chars_child_to_current_node (RsvgLoad *load)
-{
-    RsvgNode *node;
-
-    node = rsvg_node_chars_new (load->currentnode);
-    rsvg_add_node_to_handle (load->handle, node);
-
-    if (load->currentnode) {
-        rsvg_node_add_child (load->currentnode, node);
-    }
-
-    return node;
-}
-
 static void
 characters_impl (RsvgLoad *load, const char *ch, gssize len)
 {
-    RsvgNode *node = NULL;
+    RsvgNode *node;
+    gboolean accept_chars = FALSE;
 
-    if (!ch || !len) {
+    if (!ch || !len || !load->currentnode) {
         return;
     }
 
-    if (!node_is_text_or_tspan (load->currentnode)) {
+    node = rsvg_node_find_last_chars_child (load->currentnode, &accept_chars);
+    if (!accept_chars) {
         return;
     }
 
-    node = find_last_chars_child (load->currentnode);
-
     if (!node) {
-        node = add_new_chars_child_to_current_node (load);
+        node = rsvg_node_chars_new (load->currentnode);
+        rsvg_add_node_to_handle (load->handle, node);
+        rsvg_node_add_child (load->currentnode, node);
     }
 
     g_assert (rsvg_node_get_type (node) == RSVG_NODE_TYPE_CHARS);
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index 6bfca541..5b50a1b5 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -54,7 +54,7 @@ pub use node::{
     rsvg_node_children_iter_begin,
     rsvg_node_children_iter_end,
     rsvg_node_children_iter_next,
-    rsvg_node_children_iter_next_back,
+    rsvg_node_find_last_chars_child,
     rsvg_node_get_parent,
     rsvg_node_get_type,
     rsvg_node_is_same,
diff --git a/rsvg_internals/src/node.rs b/rsvg_internals/src/node.rs
index 44c3a66d..078307b9 100644
--- a/rsvg_internals/src/node.rs
+++ b/rsvg_internals/src/node.rs
@@ -123,6 +123,10 @@ pub trait NodeTrait: Downcast {
     /// from defaults in the node's `State`.
     fn set_overridden_properties(&self, _state: &mut State) {}
 
+    fn accept_chars(&self) -> bool {
+        false
+    }
+
     fn draw(
         &self,
         _node: &RsvgNode,
@@ -492,6 +496,30 @@ impl Node {
         let state = self.get_state_mut();
         state.values.overflow = SpecifiedValue::Specified(Overflow::Hidden);
     }
+
+    pub fn accept_chars(&self) -> bool {
+        self.node_impl.accept_chars()
+    }
+
+    // find the last Chars node so that we can coalesce
+    // the text and avoid screwing up the Pango layouts
+    pub fn find_last_chars_child(&self) -> Option<Rc<Node>> {
+        for child in self.children().rev() {
+            match child.get_type() {
+                NodeType::Chars => return Some(child),
+
+                // If a node that accepts chars is encountered before
+                // any chars node (which means for instance that there
+                // is a tspan node after any chars nodes, because this
+                // is backwards iteration), return None.
+                _ if child.accept_chars() => return None,
+
+                _ => {}
+            }
+        }
+
+        None
+    }
 }
 
 // Sigh, rsvg_state_free() is only available if we are being linked into
@@ -691,6 +719,30 @@ pub extern "C" fn rsvg_node_set_attribute_parse_error(
     }
 }
 
+#[no_mangle]
+pub extern "C" fn rsvg_node_find_last_chars_child(
+    raw_node: *const RsvgNode,
+    out_accept_chars: *mut glib_sys::gboolean,
+) -> *mut RsvgNode {
+    assert!(!raw_node.is_null());
+    let node: &RsvgNode = unsafe { &*raw_node };
+
+    let accept_chars = node.accept_chars();
+
+    assert!(!out_accept_chars.is_null());
+    unsafe {
+        *out_accept_chars = accept_chars.to_glib();
+    }
+
+    if accept_chars {
+        if let Some(chars) = node.find_last_chars_child() {
+            return box_node(chars);
+        }
+    }
+
+    ptr::null_mut()
+}
+
 #[no_mangle]
 pub extern "C" fn rsvg_node_children_iter_begin(raw_node: *const RsvgNode) -> *mut Children {
     assert!(!raw_node.is_null());
@@ -727,27 +779,6 @@ pub extern "C" fn rsvg_node_children_iter_next(
     }
 }
 
-#[no_mangle]
-pub extern "C" fn rsvg_node_children_iter_next_back(
-    iter: *mut Children,
-    out_child: *mut *mut RsvgNode,
-) -> glib_sys::gboolean {
-    assert!(!iter.is_null());
-
-    let iter = unsafe { &mut *iter };
-    if let Some(child) = iter.next_back() {
-        unsafe {
-            *out_child = box_node(child);
-        }
-        true.to_glib()
-    } else {
-        unsafe {
-            *out_child = ptr::null_mut();
-        }
-        false.to_glib()
-    }
-}
-
 #[no_mangle]
 pub extern "C" fn rsvg_root_node_cascade(raw_node: *const RsvgNode) {
     assert!(!raw_node.is_null());
@@ -977,15 +1008,5 @@ mod tests {
         assert_eq!(result, true);
         assert!(Rc::ptr_eq(unsafe { &*c }, &child));
         rsvg_node_unref(c);
-
-        let result: bool = from_glib(rsvg_node_children_iter_next_back(iter, &mut c));
-        assert_eq!(result, true);
-        assert!(Rc::ptr_eq(unsafe { &*c }, &second_child));
-        rsvg_node_unref(c);
-
-        let result: bool = from_glib(rsvg_node_children_iter_next(iter, &mut c));
-        assert_eq!(result, false);
-        let result: bool = from_glib(rsvg_node_children_iter_next_back(iter, &mut c));
-        assert_eq!(result, false);
     }
 }
diff --git a/rsvg_internals/src/text.rs b/rsvg_internals/src/text.rs
index b4bfcc62..4dd63593 100644
--- a/rsvg_internals/src/text.rs
+++ b/rsvg_internals/src/text.rs
@@ -141,6 +141,10 @@ impl NodeTrait for NodeText {
         Ok(())
     }
 
+    fn accept_chars(&self) -> bool {
+        true
+    }
+
     fn draw(
         &self,
         node: &RsvgNode,
@@ -359,6 +363,10 @@ impl NodeTrait for NodeTSpan {
 
         Ok(())
     }
+
+    fn accept_chars(&self) -> bool {
+        true
+    }
 }
 
 fn to_pango_units(v: f64) -> i32 {


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