[librsvg/rustification] Use an iterator function rsvg_node_foreach_child() throughout



commit 852a2a3a827cf6922819802a7c67926f6880999c
Author: Federico Mena Quintero <federico gnome org>
Date:   Tue Nov 22 16:02:50 2016 -0600

    Use an iterator function rsvg_node_foreach_child() throughout
    
    This is instead of iterating through the node->children GPtrArray by
    hand.

 rsvg-base.c      |   52 +++++++++---
 rsvg-private.h   |    9 ++
 rsvg-structure.c |   72 ++++++++++-------
 rsvg-text.c      |  239 +++++++++++++++++++++++++++++++++++------------------
 4 files changed, 248 insertions(+), 124 deletions(-)
---
diff --git a/rsvg-base.c b/rsvg-base.c
index 9b6f651..6f9275c 100644
--- a/rsvg-base.c
+++ b/rsvg-base.c
@@ -445,6 +445,25 @@ rsvg_node_get_parent (RsvgNode *node)
     return node->parent;
 }
 
+void
+rsvg_node_foreach_child (RsvgNode *node, RsvgNodeForeachChildFn fn, gpointer data)
+{
+    guint len;
+    guint i;
+
+    len = node->children->len;
+
+    for (i = 0; i < len; i++) {
+        RsvgNode *child;
+        gboolean next;
+
+        child = g_ptr_array_index (node->children, i);
+        next = fn (child, data);
+        if (!next)
+            break;
+    }
+}
+
 /* extra (title, desc, metadata) */
 
 static void
@@ -885,6 +904,22 @@ rsvg_new_node_chars (const char *text,
     return self;
 }
 
+static gboolean
+find_last_chars_node (RsvgNode *node, gpointer data)
+{
+    RsvgNode **dest;
+
+    dest = data;
+
+    if (RSVG_NODE_TYPE (node) == RSVG_NODE_TYPE_CHARS) {
+        *dest = node;
+    } else if (RSVG_NODE_TYPE (node) == RSVG_NODE_TYPE_TSPAN) {
+        *dest = NULL;
+    }
+
+    return TRUE;
+}
+
 static void
 rsvg_characters_impl (RsvgHandle * ctx, const xmlChar * ch, int len)
 {
@@ -895,22 +930,13 @@ rsvg_characters_impl (RsvgHandle * ctx, const xmlChar * ch, int len)
 
     if (ctx->priv->currentnode) {
         RsvgNodeType type = RSVG_NODE_TYPE (ctx->priv->currentnode);
-        if (type == RSVG_NODE_TYPE_TSPAN ||
-            type == RSVG_NODE_TYPE_TEXT) {
-            guint i;
-
+        if (type == RSVG_NODE_TYPE_TSPAN || type == RSVG_NODE_TYPE_TEXT) {
             /* 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 */
             self = NULL;
-            for (i = 0; i < ctx->priv->currentnode->children->len; i++) {
-                RsvgNode *node = g_ptr_array_index (ctx->priv->currentnode->children, i);
-                if (RSVG_NODE_TYPE (node) == RSVG_NODE_TYPE_CHARS) {
-                    self = (RsvgNodeChars*)node;
-                }
-                else if (RSVG_NODE_TYPE (node) == RSVG_NODE_TYPE_TSPAN) {
-                    self = NULL;
-                }
-            }
+            rsvg_node_foreach_child (ctx->priv->currentnode,
+                                     find_last_chars_node,
+                                     &self);
 
             if (self != NULL) {
                 if (!g_utf8_validate ((char *) ch, len, NULL)) {
diff --git a/rsvg-private.h b/rsvg-private.h
index a5d55a8..313433b 100644
--- a/rsvg-private.h
+++ b/rsvg-private.h
@@ -346,6 +346,15 @@ RsvgState *rsvg_node_get_state (RsvgNode *node);
 G_GNUC_INTERNAL
 RsvgNode *rsvg_node_get_parent (RsvgNode *node);
 
+/* Used to iterate among a node's children with rsvg_node_foreach_child().
+ * If this caller-supplied function returns FALSE, iteration will stop.
+ * Otherwise, iteration will continue to the next child node.
+ */
+typedef gboolean (* RsvgNodeForeachChildFn) (RsvgNode *node, gpointer data);
+
+G_GNUC_INTERNAL
+void rsvg_node_foreach_child (RsvgNode *node, RsvgNodeForeachChildFn fn, gpointer data);
+
 struct _RsvgNodeChars {
     RsvgNode super;
     GString *contents;
diff --git a/rsvg-structure.c b/rsvg-structure.c
index ab6ec6d..5feb18b 100644
--- a/rsvg-structure.c
+++ b/rsvg-structure.c
@@ -22,8 +22,8 @@
    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
 
-   Authors: Raph Levien <raph artofcode com>, 
-            Dom Lachowicz <cinamod hotmail com>, 
+   Authors: Raph Levien <raph artofcode com>,
+            Dom Lachowicz <cinamod hotmail com>,
             Caleb Moore <c moore student unsw edu au>
 */
 
@@ -55,21 +55,32 @@ rsvg_node_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
     ctx->drawsub_stack = stacksave;
 }
 
+static gboolean
+draw_child (RsvgNode *node, gpointer data)
+{
+    RsvgDrawingCtx *ctx;
+
+    ctx = data;
+
+    rsvg_state_push (ctx);
+    rsvg_node_draw (node, ctx, 0);
+    rsvg_state_pop (ctx);
+
+    return TRUE;
+}
+
 /* generic function for drawing all of the children of a particular node */
 void
 _rsvg_node_draw_children (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
 {
-    guint i;
     if (dominate != -1) {
         rsvg_state_reinherit_top (ctx, rsvg_node_get_state (self), dominate);
 
         rsvg_push_discrete_layer (ctx);
     }
-    for (i = 0; i < self->children->len; i++) {
-        rsvg_state_push (ctx);
-        rsvg_node_draw (g_ptr_array_index (self->children, i), ctx, 0);
-        rsvg_state_pop (ctx);
-    }
+
+    rsvg_node_foreach_child (self, draw_child, ctx);
+
     if (dominate != -1)
         rsvg_pop_discrete_layer (ctx);
 }
@@ -233,7 +244,6 @@ rsvg_node_svg_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
     RsvgNodeSvg *sself;
     RsvgState *state;
     cairo_matrix_t affine, affine_old, affine_new;
-    guint i;
     double nx, ny, nw, nh;
     sself = (RsvgNodeSvg *) self;
 
@@ -272,7 +282,7 @@ rsvg_node_svg_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
 
     rsvg_push_discrete_layer (ctx);
 
-    /* Bounding box addition must be AFTER the discrete layer push, 
+    /* Bounding box addition must be AFTER the discrete layer push,
        which must be AFTER the transformation happens. */
     if (!state->overflow && rsvg_node_get_parent (self)) {
         state->affine = affine_old;
@@ -280,11 +290,7 @@ rsvg_node_svg_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
         state->affine = affine_new;
     }
 
-    for (i = 0; i < self->children->len; i++) {
-        rsvg_state_push (ctx);
-        rsvg_node_draw (g_ptr_array_index (self->children, i), ctx, 0);
-        rsvg_state_pop (ctx);
-    }
+    rsvg_node_foreach_child (self, draw_child, ctx);
 
     rsvg_pop_discrete_layer (ctx);
     rsvg_drawing_ctx_pop_view_box (ctx);
@@ -305,9 +311,9 @@ rsvg_node_svg_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * att
         svg->w = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
     if ((value = rsvg_property_bag_lookup (atts, "height")))
         svg->h = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
-    /* 
+    /*
      * x & y attributes have no effect on outermost svg
-     * http://www.w3.org/TR/SVG/struct.html#SVGElement 
+     * http://www.w3.org/TR/SVG/struct.html#SVGElement
      */
     if (rsvg_node_get_parent (self)) {
         if ((value = rsvg_property_bag_lookup (atts, "x")))
@@ -453,26 +459,32 @@ rsvg_new_defs (const char *element_name)
     return &group->super;
 }
 
+static gboolean
+draw_child_if_cond_true_and_stop (RsvgNode *node, gpointer data)
+{
+    RsvgDrawingCtx *ctx;
+
+    ctx = data;
+
+    if (rsvg_node_get_state (node)->cond_true) {
+        rsvg_state_push (ctx);
+        rsvg_node_draw (node, ctx, 0);
+        rsvg_state_pop (ctx);
+
+        return FALSE;
+    } else {
+        return TRUE;
+    }
+}
+
 static void
 _rsvg_node_switch_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
 {
-    guint i;
-
     rsvg_state_reinherit_top (ctx, rsvg_node_get_state (self), dominate);
 
     rsvg_push_discrete_layer (ctx);
 
-    for (i = 0; i < self->children->len; i++) {
-        RsvgNode *drawable = g_ptr_array_index (self->children, i);
-
-        if (rsvg_node_get_state (drawable)->cond_true) {
-            rsvg_state_push (ctx);
-            rsvg_node_draw (g_ptr_array_index (self->children, i), ctx, 0);
-            rsvg_state_pop (ctx);
-
-            break;              /* only render the 1st one */
-        }
-    }
+    rsvg_node_foreach_child (self, draw_child_if_cond_true_and_stop, ctx);
 
     rsvg_pop_discrete_layer (ctx);
 }
diff --git a/rsvg-text.c b/rsvg-text.c
index ee81ebf..79b0c9a 100644
--- a/rsvg-text.c
+++ b/rsvg-text.c
@@ -156,111 +156,188 @@ _rsvg_node_text_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * a
 static void
  rsvg_text_render_text (RsvgDrawingCtx * ctx, const char *text, gdouble * x, gdouble * y);
 
-
 static void
- _rsvg_node_text_type_tspan (RsvgNodeText * self, RsvgDrawingCtx * ctx,
-                             gdouble * x, gdouble * y, gboolean * lastwasspace,
-                             gboolean usetextonly);
+_rsvg_node_text_type_children (RsvgNode * self, RsvgDrawingCtx * ctx,
+                               gdouble * x, gdouble * y, gboolean * lastwasspace,
+                               gboolean usetextonly);
 
 static void
- _rsvg_node_text_type_tref (RsvgNodeTref * self, RsvgDrawingCtx * ctx,
+_rsvg_node_text_type_tspan (RsvgNodeText * self, RsvgDrawingCtx * ctx,
                             gdouble * x, gdouble * y, gboolean * lastwasspace,
                             gboolean usetextonly);
 
+static void
+_rsvg_node_text_type_tref (RsvgNodeTref * self, RsvgDrawingCtx * ctx,
+                           gdouble * x, gdouble * y, gboolean * lastwasspace,
+                           gboolean usetextonly);
+
+typedef struct {
+    RsvgDrawingCtx *ctx;
+    gdouble *x;
+    gdouble *y;
+    gboolean *lastwasspace;
+    gboolean usetextonly;
+} DrawTextClosure;
+
+static gboolean
+draw_text_child (RsvgNode *node, gpointer data)
+{
+    DrawTextClosure *closure;
+    RsvgNodeType type = RSVG_NODE_TYPE (node);
+
+    closure = data;
+
+    if (type == RSVG_NODE_TYPE_CHARS) {
+        RsvgNodeChars *chars = (RsvgNodeChars *) node;
+        GString *str = _rsvg_text_chomp (rsvg_current_state (closure->ctx), chars->contents, 
closure->lastwasspace);
+        rsvg_text_render_text (closure->ctx, str->str, closure->x, closure->y);
+        g_string_free (str, TRUE);
+    } else {
+        if (closure->usetextonly) {
+            _rsvg_node_text_type_children (node,
+                                           closure->ctx,
+                                           closure->x,
+                                           closure->y,
+                                           closure->lastwasspace,
+                                           closure->usetextonly);
+        } else {
+            if (type == RSVG_NODE_TYPE_TSPAN) {
+                RsvgNodeText *tspan = (RsvgNodeText *) node;
+                rsvg_state_push (closure->ctx);
+                _rsvg_node_text_type_tspan (tspan,
+                                            closure->ctx,
+                                            closure->x,
+                                            closure->y,
+                                            closure->lastwasspace,
+                                            closure->usetextonly);
+                rsvg_state_pop (closure->ctx);
+            } else if (type == RSVG_NODE_TYPE_TREF) {
+                RsvgNodeTref *tref = (RsvgNodeTref *) node;
+                _rsvg_node_text_type_tref (tref,
+                                           closure->ctx,
+                                           closure->x,
+                                           closure->y,
+                                           closure->lastwasspace,
+                                           closure->usetextonly);
+            }
+        }
+    }
+
+    return TRUE;
+}
+
 /* This function is responsible of selecting render for a text element including its children and giving it 
the drawing context */
 static void
 _rsvg_node_text_type_children (RsvgNode * self, RsvgDrawingCtx * ctx,
                                gdouble * x, gdouble * y, gboolean * lastwasspace,
                                gboolean usetextonly)
 {
-    guint i;
+    DrawTextClosure closure;
 
     rsvg_push_discrete_layer (ctx);
-    for (i = 0; i < self->children->len; i++) {
-        RsvgNode *node = g_ptr_array_index (self->children, i);
-        RsvgNodeType type = RSVG_NODE_TYPE (node);
-
-        if (type == RSVG_NODE_TYPE_CHARS) {
-            RsvgNodeChars *chars = (RsvgNodeChars *) node;
-            GString *str = _rsvg_text_chomp (rsvg_current_state (ctx), chars->contents, lastwasspace);
-            rsvg_text_render_text (ctx, str->str, x, y);
-            g_string_free (str, TRUE);
-        } else {
-            if (usetextonly) {
-                _rsvg_node_text_type_children (node, ctx, x, y, lastwasspace,
-                                               usetextonly);
-            } else {
-                if (type == RSVG_NODE_TYPE_TSPAN) {
-                    RsvgNodeText *tspan = (RsvgNodeText *) node;
-                    rsvg_state_push (ctx);
-                    _rsvg_node_text_type_tspan (tspan, ctx, x, y, lastwasspace,
-                                                usetextonly);
-                    rsvg_state_pop (ctx);
-                } else if (type == RSVG_NODE_TYPE_TREF) {
-                    RsvgNodeTref *tref = (RsvgNodeTref *) node;
-                    _rsvg_node_text_type_tref (tref, ctx, x, y, lastwasspace,
-                                               usetextonly);
-                }
-            }
-        }
-    }
+
+    closure.ctx = ctx;
+    closure.x = x;
+    closure.y = y;
+    closure.lastwasspace = lastwasspace;
+    closure.usetextonly = usetextonly;
+
+    rsvg_node_foreach_child (self, draw_text_child, &closure);
+
     rsvg_pop_discrete_layer (ctx);
 }
 
-static int
- _rsvg_node_text_length_tref (RsvgNodeTref * self, RsvgDrawingCtx * ctx,
+static gboolean
+_rsvg_node_text_length_children (RsvgNode * self, RsvgDrawingCtx * ctx,
+                                 gdouble * length, gboolean * lastwasspace,
+                                 gboolean usetextonly);
+
+static gboolean
+_rsvg_node_text_length_tref (RsvgNodeTref * self, RsvgDrawingCtx * ctx,
+                             gdouble * x, gboolean * lastwasspace,
+                             gboolean usetextonly);
+
+static gboolean
+_rsvg_node_text_length_tspan (RsvgNodeText * self, RsvgDrawingCtx * ctx,
                               gdouble * x, gboolean * lastwasspace,
                               gboolean usetextonly);
 
-static int
- _rsvg_node_text_length_tspan (RsvgNodeText * self, RsvgDrawingCtx * ctx,
-                               gdouble * x, gboolean * lastwasspace,
-                               gboolean usetextonly);
-
 static gdouble rsvg_text_length_text_as_string (RsvgDrawingCtx * ctx, const char *text);
 
-static int
-_rsvg_node_text_length_children (RsvgNode * self, RsvgDrawingCtx * ctx,
-                                 gdouble * length, gboolean * lastwasspace,
-                                 gboolean usetextonly)
+typedef struct {
+    RsvgDrawingCtx *ctx;
+    gdouble *length;
+    gboolean *lastwasspace;
+    gboolean usetextonly;
+    gboolean done;
+} ChildrenLengthClosure;
+
+static gboolean
+compute_child_length (RsvgNode *node, gpointer data)
 {
-    guint i;
-    int out = FALSE;
-    for (i = 0; i < self->children->len; i++) {
-        RsvgNode *node = g_ptr_array_index (self->children, i);
-        RsvgNodeType type = RSVG_NODE_TYPE (node);
-
-        rsvg_state_push (ctx);
-        rsvg_state_reinherit_top (ctx, rsvg_node_get_state (node), 0);
-        if (type == RSVG_NODE_TYPE_CHARS) {
-            RsvgNodeChars *chars = (RsvgNodeChars *) node;
-            GString *str = _rsvg_text_chomp (rsvg_current_state (ctx), chars->contents, lastwasspace);
-            *length += rsvg_text_length_text_as_string (ctx, str->str);
-            g_string_free (str, TRUE);
+    ChildrenLengthClosure *closure;
+    RsvgNodeType type = RSVG_NODE_TYPE (node);
+    gboolean done;
+
+    closure = data;
+    done = FALSE;
+
+    rsvg_state_push (closure->ctx);
+    rsvg_state_reinherit_top (closure->ctx, rsvg_node_get_state (node), 0);
+
+    if (type == RSVG_NODE_TYPE_CHARS) {
+        RsvgNodeChars *chars = (RsvgNodeChars *) node;
+        GString *str = _rsvg_text_chomp (rsvg_current_state (closure->ctx), chars->contents, 
closure->lastwasspace);
+        *closure->length += rsvg_text_length_text_as_string (closure->ctx, str->str);
+        g_string_free (str, TRUE);
+    } else {
+        if (closure->usetextonly) {
+            done = _rsvg_node_text_length_children (node,
+                                                    closure->ctx,
+                                                    closure->length,
+                                                    closure->lastwasspace,
+                                                    closure->usetextonly);
         } else {
-            if (usetextonly) {
-                out = _rsvg_node_text_length_children(node, ctx, length,
-                                                      lastwasspace,
-                                                      usetextonly);
-            } else {
-                if (type == RSVG_NODE_TYPE_TSPAN) {
-                    RsvgNodeText *tspan = (RsvgNodeText *) node;
-                    out = _rsvg_node_text_length_tspan (tspan, ctx, length,
-                                                        lastwasspace,
-                                                        usetextonly);
-                } else if (type == RSVG_NODE_TYPE_TREF) {
-                    RsvgNodeTref *tref = (RsvgNodeTref *) node;
-                    out = _rsvg_node_text_length_tref (tref, ctx, length,
-                                                       lastwasspace,
-                                                       usetextonly);
-                }
+            if (type == RSVG_NODE_TYPE_TSPAN) {
+                RsvgNodeText *tspan = (RsvgNodeText *) node;
+                done = _rsvg_node_text_length_tspan (tspan,
+                                                     closure->ctx,
+                                                     closure->length,
+                                                     closure->lastwasspace,
+                                                     closure->usetextonly);
+            } else if (type == RSVG_NODE_TYPE_TREF) {
+                RsvgNodeTref *tref = (RsvgNodeTref *) node;
+                done = _rsvg_node_text_length_tref (tref,
+                                                    closure->ctx,
+                                                    closure->length,
+                                                    closure->lastwasspace,
+                                                    closure->usetextonly);
             }
         }
-        rsvg_state_pop (ctx);
-        if (out)
-            break;
     }
-    return out;
+
+    rsvg_state_pop (closure->ctx);
+
+    closure->done = done;
+    return !done;
+}
+
+static gboolean
+_rsvg_node_text_length_children (RsvgNode * self, RsvgDrawingCtx * ctx,
+                                 gdouble * length, gboolean * lastwasspace,
+                                 gboolean usetextonly)
+{
+    ChildrenLengthClosure closure;
+
+    closure.ctx = ctx;
+    closure.length = length;
+    closure.lastwasspace = lastwasspace;
+    closure.usetextonly = usetextonly;
+    closure.done = FALSE;
+
+    rsvg_node_foreach_child (self, compute_child_length, &closure);
+
+    return closure.done;
 }
 
 
@@ -360,7 +437,7 @@ _rsvg_node_text_type_tspan (RsvgNodeText * self, RsvgDrawingCtx * ctx,
                                    usetextonly);
 }
 
-static int
+static gboolean
 _rsvg_node_text_length_tspan (RsvgNodeText * self,
                               RsvgDrawingCtx * ctx, gdouble * length,
                               gboolean * lastwasspace, gboolean usetextonly)
@@ -415,7 +492,7 @@ _rsvg_node_text_type_tref (RsvgNodeTref * self, RsvgDrawingCtx * ctx,
     rsvg_release_node (ctx, link);
 }
 
-static int
+static gboolean
 _rsvg_node_text_length_tref (RsvgNodeTref * self, RsvgDrawingCtx * ctx, gdouble * x,
                              gboolean * lastwasspace, gboolean usetextonly)
 {
@@ -526,7 +603,7 @@ rsvg_text_create_layout (RsvgDrawingCtx * ctx, const char *text, PangoContext *
     attribute = pango_attr_letter_spacing_new (rsvg_length_normalize (&state->letter_spacing, ctx) * 
PANGO_SCALE);
     attribute->start_index = 0;
     attribute->end_index = G_MAXINT;
-    pango_attr_list_insert (attr_list, attribute); 
+    pango_attr_list_insert (attr_list, attribute);
 
     if (state->has_font_decor && text) {
         if (state->font_decor & TEXT_UNDERLINE) {


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