]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktextbtree.c
Add a tooltip explaining the format of page ranges, and improve the page
[~andy/gtk] / gtk / gtktextbtree.c
index 7f270e19a8da16ceab35e61e44517b0775d93661..d8e436d74a7a0f5e5d553e1b08917853dfd9666a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * gtktextbtree.c --
+ * Gtktextbtree.c --
  *
  *      This file contains code that manages the B-tree representation
  *      of text for the text buffer and implements character and
  */
 
 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
+#include <config.h>
 #include "gtktextbtree.h"
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
-#include "gtksignal.h"
 #include "gtktexttag.h"
 #include "gtktexttagtable.h"
 #include "gtktextlayout.h"
 #include "gtktextiterprivate.h"
 #include "gtkdebug.h"
 #include "gtktextmarkprivate.h"
+#include "gtkalias.h"
 
 /*
  * Types
@@ -100,7 +101,7 @@ struct _NodeData {
 
   /* Height and width of this node */
   gint height;
-  gint width : 24;
+  signed int width : 24;
 
   /* boolean indicating whether the lines below this node are in need of validation.
    * However, width/height should always represent the current total width and
@@ -108,7 +109,7 @@ struct _NodeData {
    * width/height on the lines needs recomputing, not whether the totals
    * need recomputing.
    */
-  gint valid : 8;
+  guint valid : 8;             /* Actually a boolean */
 };
 
 
@@ -425,9 +426,9 @@ _gtk_text_btree_new (GtkTextTagTable *table,
   tree->end_iter_segment_byte_index = 0;
   tree->end_iter_segment_char_offset = 0;
   
-  g_object_ref (G_OBJECT (tree->table));
+  g_object_ref (tree->table);
 
-  tree->tag_changed_handler = g_signal_connect (G_OBJECT (tree->table),
+  tree->tag_changed_handler = g_signal_connect (tree->table,
                                                "tag_changed",
                                                G_CALLBACK (tag_changed_cb),
                                                tree);
@@ -471,8 +472,8 @@ _gtk_text_btree_new (GtkTextTagTable *table,
 
     seg->body.mark.not_deleteable = TRUE;
 
-    g_object_ref (G_OBJECT (tree->insert_mark));
-    g_object_ref (G_OBJECT (tree->selection_bound_mark));
+    g_object_ref (tree->insert_mark);
+    g_object_ref (tree->selection_bound_mark);
   }
 
   tree->refcount = 1;
@@ -499,10 +500,10 @@ _gtk_text_btree_unref (GtkTextBTree *tree)
 
   if (tree->refcount == 0)
     {      
-      g_signal_handler_disconnect (G_OBJECT (tree->table),
+      g_signal_handler_disconnect (tree->table,
                                    tree->tag_changed_handler);
 
-      g_object_unref (G_OBJECT (tree->table));
+      g_object_unref (tree->table);
       tree->table = NULL;
       
       gtk_text_btree_node_destroy (tree, tree->root_node);
@@ -517,9 +518,9 @@ _gtk_text_btree_unref (GtkTextBTree *tree)
          tree->child_anchor_table = NULL;
        }
 
-      g_object_unref (G_OBJECT (tree->insert_mark));
+      g_object_unref (tree->insert_mark);
       tree->insert_mark = NULL;
-      g_object_unref (G_OBJECT (tree->selection_bound_mark));
+      g_object_unref (tree->selection_bound_mark);
       tree->selection_bound_mark = NULL;
 
       g_free (tree);
@@ -555,6 +556,174 @@ _gtk_text_btree_segments_changed (GtkTextBTree *tree)
  * Indexable segment mutation
  */
 
+/*
+ *  The following function is responsible for resolving the bidi direction
+ *  for the lines between start and end. But it also calculates any
+ *  dependent bidi direction for surrounding lines that change as a result
+ *  of the bidi direction decisions within the range. The function is
+ *  trying to do as little propagation as is needed.
+ */
+static void
+gtk_text_btree_resolve_bidi (GtkTextIter *start,
+                            GtkTextIter *end)
+{
+  GtkTextBTree *tree = _gtk_text_iter_get_btree (start);
+  GtkTextLine *start_line, *end_line, *start_line_prev, *end_line_next, *line;
+  PangoDirection last_strong, dir_above_propagated, dir_below_propagated;
+
+  /* Resolve the strong bidi direction for all lines between
+   * start and end.
+  */
+  start_line = _gtk_text_iter_get_text_line (start);
+  start_line_prev = _gtk_text_line_previous (start_line);
+  end_line = _gtk_text_iter_get_text_line (end);
+  end_line_next = _gtk_text_line_next (end_line);
+  
+  line = start_line;
+  while (line && line != end_line_next)
+    {
+      /* Loop through the segments and search for a strong character
+       */
+      GtkTextLineSegment *seg = line->segments;
+      line->dir_strong = PANGO_DIRECTION_NEUTRAL;
+      
+      while (seg)
+        {
+          if (seg->type == &gtk_text_char_type && seg->byte_count > 0)
+            {
+             PangoDirection pango_dir;
+
+              pango_dir = pango_find_base_dir (seg->body.chars,
+                                              seg->byte_count);
+             
+              if (pango_dir != PANGO_DIRECTION_NEUTRAL)
+                {
+                  line->dir_strong = pango_dir;
+                  break;
+                }
+            }
+          seg = seg->next;
+        }
+
+      line = _gtk_text_line_next (line);
+    }
+
+  /* Sweep forward */
+
+  /* The variable dir_above_propagated contains the forward propagated
+   * direction before start. It is neutral if start is in the beginning
+   * of the buffer.
+   */
+  dir_above_propagated = PANGO_DIRECTION_NEUTRAL;
+  if (start_line_prev)
+    dir_above_propagated = start_line_prev->dir_propagated_forward;
+
+  /* Loop forward and propagate the direction of each paragraph 
+   * to all neutral lines.
+   */
+  line = start_line;
+  last_strong = dir_above_propagated;
+  while (line != end_line_next)
+    {
+      if (line->dir_strong != PANGO_DIRECTION_NEUTRAL)
+        last_strong = line->dir_strong;
+      
+      line->dir_propagated_forward = last_strong;
+      
+      line = _gtk_text_line_next (line);
+    }
+
+  /* Continue propagating as long as the previous resolved forward
+   * is different from last_strong.
+   */
+  {
+    GtkTextIter end_propagate;
+    
+    while (line &&
+          line->dir_strong == PANGO_DIRECTION_NEUTRAL &&
+          line->dir_propagated_forward != last_strong)
+      {
+        GtkTextLine *prev = line;
+        line->dir_propagated_forward = last_strong;
+        
+        line = _gtk_text_line_next(line);
+        if (!line)
+          {
+            line = prev;
+            break;
+          }
+      }
+
+    /* The last line to invalidate is the last line before the
+     * line with the strong character. Or in case of the end of the
+     * buffer, the last line of the buffer. (There seems to be an
+     * extra "virtual" last line in the buffer that must not be used
+     * calling _gtk_text_btree_get_iter_at_line (causes crash). Thus the
+     * _gtk_text_line_previous is ok in that case as well.)
+     */
+    line = _gtk_text_line_previous (line);
+    _gtk_text_btree_get_iter_at_line (tree, &end_propagate, line, 0);
+    _gtk_text_btree_invalidate_region (tree, end, &end_propagate);
+  }
+  
+  /* Sweep backward */
+
+  /* The variable dir_below_propagated contains the backward propagated
+   * direction after end. It is neutral if end is at the end of
+   * the buffer.
+  */
+  dir_below_propagated = PANGO_DIRECTION_NEUTRAL;
+  if (end_line_next)
+    dir_below_propagated = end_line_next->dir_propagated_back;
+
+  /* Loop backward and propagate the direction of each paragraph 
+   * to all neutral lines.
+   */
+  line = end_line;
+  last_strong = dir_below_propagated;
+  while (line != start_line_prev)
+    {
+      if (line->dir_strong != PANGO_DIRECTION_NEUTRAL)
+        last_strong = line->dir_strong;
+
+      line->dir_propagated_back = last_strong;
+
+      line = _gtk_text_line_previous (line);
+    }
+
+  /* Continue propagating as long as the resolved backward dir
+   * is different from last_strong.
+   */
+  {
+    GtkTextIter start_propagate;
+
+    while (line &&
+          line->dir_strong == PANGO_DIRECTION_NEUTRAL &&
+          line->dir_propagated_back != last_strong)
+      {
+        GtkTextLine *prev = line;
+        line->dir_propagated_back = last_strong;
+
+        line = _gtk_text_line_previous (line);
+        if (!line)
+          {
+            line = prev;
+            break;
+          }
+      }
+
+    /* We only need to invalidate for backwards propagation if the
+     * line we ended up on didn't get a direction from forwards
+     * propagation.
+     */
+    if (line && line->dir_propagated_forward == PANGO_DIRECTION_NEUTRAL)
+      {
+        _gtk_text_btree_get_iter_at_line (tree, &start_propagate, line, 0);
+        _gtk_text_btree_invalidate_region(tree, &start_propagate, start);
+      }
+  }
+}
+
 void
 _gtk_text_btree_delete (GtkTextIter *start,
                         GtkTextIter *end)
@@ -563,7 +732,7 @@ _gtk_text_btree_delete (GtkTextIter *start,
                                              * of the deletion range. */
   GtkTextLineSegment *last_seg;             /* The segment just after the end
                                              * of the deletion range. */
-  GtkTextLineSegment *seg, *next;
+  GtkTextLineSegment *seg, *next, *next2;
   GtkTextLine *curline;
   GtkTextBTreeNode *curnode, *node;
   GtkTextBTree *tree;
@@ -716,12 +885,30 @@ _gtk_text_btree_delete (GtkTextIter *start,
               seg->next = start_line->segments;
               start_line->segments = seg;
             }
-          else
-            {
+          else if (prev_seg->next &&
+                  prev_seg->next != last_seg &&
+                  seg->type == &gtk_text_toggle_off_type &&
+                  prev_seg->next->type == &gtk_text_toggle_on_type &&
+                  seg->body.toggle.info == prev_seg->next->body.toggle.info)
+           {
+             /* Try to match an off toggle with the matching on toggle
+              * if it immediately follows. This is a common case, and
+              * handling it here prevents quadratic blowup in
+              * cleanup_line() below. See bug 317125.
+              */
+             next2 = prev_seg->next->next;
+             g_free ((char *)prev_seg->next);
+             prev_seg->next = next2;
+             g_free ((char *)seg);
+             seg = NULL;
+           }
+         else
+           {
               seg->next = prev_seg->next;
               prev_seg->next = seg;
             }
-          if (seg->type->leftGravity)
+
+          if (seg && seg->type->leftGravity)
             {
               prev_seg = seg;
             }
@@ -885,6 +1072,8 @@ _gtk_text_btree_delete (GtkTextIter *start,
   /* Re-initialize our iterators */
   _gtk_text_btree_get_iter_at_line (tree, start, start_line, start_byte_offset);
   *end = *start;
+
+  gtk_text_btree_resolve_bidi (start, end);
 }
 
 void
@@ -1051,6 +1240,8 @@ _gtk_text_btree_insert (GtkTextIter *iter,
 
     /* Convenience for the user */
     *iter = end;
+
+    gtk_text_btree_resolve_bidi (&start, &end);
   }
 }
 
@@ -1470,7 +1661,7 @@ static IterStack*
 iter_stack_new (void)
 {
   IterStack *stack;
-  stack = g_new (IterStack, 1);
+  stack = g_slice_new (IterStack);
   stack->iters = NULL;
   stack->count = 0;
   stack->alloced = 0;
@@ -1478,20 +1669,22 @@ iter_stack_new (void)
 }
 
 static void
-iter_stack_push (IterStack *stack, const GtkTextIter *iter)
+iter_stack_push (IterStack         *stack, 
+                const GtkTextIter *iter)
 {
   stack->count += 1;
   if (stack->count > stack->alloced)
     {
       stack->alloced = stack->count*2;
       stack->iters = g_realloc (stack->iters,
-                                stack->alloced*sizeof (GtkTextIter));
+                                stack->alloced * sizeof (GtkTextIter));
     }
   stack->iters[stack->count-1] = *iter;
 }
 
 static gboolean
-iter_stack_pop (IterStack *stack, GtkTextIter *iter)
+iter_stack_pop (IterStack   *stack, 
+               GtkTextIter *iter)
 {
   if (stack->count == 0)
     return FALSE;
@@ -1507,7 +1700,7 @@ static void
 iter_stack_free (IterStack *stack)
 {
   g_free (stack->iters);
-  g_free (stack);
+  g_slice_free (IterStack, stack);
 }
 
 static void
@@ -1802,6 +1995,8 @@ _gtk_text_btree_tag (const GtkTextIter *start_orig,
 
   segments_changed (tree);
 
+  queue_tag_redisplay (tree, tag, &start, &end);
+
   if (gtk_debug_flags & GTK_DEBUG_TEXT)
     _gtk_text_btree_check (tree);
 }
@@ -1916,7 +2111,6 @@ _gtk_text_btree_get_line_at_char (GtkTextBTree      *tree,
   GtkTextLineSegment *seg;
   int chars_left;
   int chars_in_line;
-  int bytes_in_line;
 
   node = tree->root_node;
 
@@ -1962,7 +2156,6 @@ _gtk_text_btree_get_line_at_char (GtkTextBTree      *tree,
    */
 
   chars_in_line = 0;
-  bytes_in_line = 0;
   seg = NULL;
   for (line = node->children.line; line != NULL; line = line->next)
     {
@@ -2002,13 +2195,11 @@ _gtk_text_btree_get_tags (const GtkTextIter *iter,
   int src, dst, index;
   TagInfo tagInfo;
   GtkTextLine *line;
-  GtkTextBTree *tree;
   gint byte_index;
 
 #define NUM_TAG_INFOS 10
 
   line = _gtk_text_iter_get_text_line (iter);
-  tree = _gtk_text_iter_get_btree (iter);
   byte_index = gtk_text_iter_get_line_index (iter);
 
   tagInfo.numTags = 0;
@@ -2196,7 +2387,6 @@ _gtk_text_btree_get_text (const GtkTextIter *start_orig,
   GtkTextLineSegment *seg;
   GtkTextLineSegment *end_seg;
   GString *retval;
-  GtkTextBTree *tree;
   gchar *str;
   GtkTextIter iter;
   GtkTextIter start;
@@ -2212,9 +2402,7 @@ _gtk_text_btree_get_text (const GtkTextIter *start_orig,
 
   gtk_text_iter_order (&start, &end);
 
-  retval = g_string_new ("");
-
-  tree = _gtk_text_iter_get_btree (&start);
+  retval = g_string_new (NULL);
 
   end_seg = _gtk_text_iter_get_indexable_segment (&end);
   iter = start;
@@ -2259,7 +2447,7 @@ _gtk_text_btree_char_is_invisible (const GtkTextIter *iter)
 {
   gboolean invisible = FALSE;  /* if nobody says otherwise, it's visible */
 
-  int deftagCnts[LOTSA_TAGS];
+  int deftagCnts[LOTSA_TAGS] = { 0, };
   int *tagCnts = deftagCnts;
   GtkTextTag *deftags[LOTSA_TAGS];
   GtkTextTag **tags = deftags;
@@ -2282,15 +2470,10 @@ _gtk_text_btree_char_is_invisible (const GtkTextIter *iter)
   /* almost always avoid malloc, so stay out of system calls */
   if (LOTSA_TAGS < numTags)
     {
-      tagCnts = g_new (int, numTags);
+      tagCnts = g_new0 (int, numTags);
       tags = g_new (GtkTextTag*, numTags);
     }
 
-  for (i=0; i<numTags; i++)
-    {
-      tagCnts[i] = 0;
-    }
-
   /*
    * Record tag toggles within the line of indexPtr but preceding
    * indexPtr.
@@ -2481,8 +2664,7 @@ ensure_not_off_end (GtkTextBTree *tree,
                     GtkTextLineSegment *mark,
                     GtkTextIter *iter)
 {
-  if (gtk_text_iter_get_line (iter) ==
-      _gtk_text_btree_line_count (tree))
+  if (gtk_text_iter_get_line (iter) == _gtk_text_btree_line_count (tree))
     gtk_text_iter_backward_char (iter);
 }
 
@@ -2656,6 +2838,14 @@ _gtk_text_btree_get_selection_bounds (GtkTextBTree *tree,
 void
 _gtk_text_btree_place_cursor (GtkTextBTree      *tree,
                              const GtkTextIter *iter)
+{
+  _gtk_text_btree_select_range (tree, iter, iter);
+}
+
+void
+_gtk_text_btree_select_range (GtkTextBTree      *tree,
+                             const GtkTextIter *ins,
+                              const GtkTextIter *bound)
 {
   GtkTextIter start, end;
 
@@ -2664,11 +2854,14 @@ _gtk_text_btree_place_cursor (GtkTextBTree      *tree,
 
   /* Move insert AND selection_bound before we redisplay */
   real_set_mark (tree, tree->insert_mark,
-                 "insert", FALSE, iter, TRUE, FALSE);
+                 "insert", FALSE, ins, TRUE, FALSE);
   real_set_mark (tree, tree->selection_bound_mark,
-                 "selection_bound", FALSE, iter, TRUE, FALSE);
+                 "selection_bound", FALSE, bound, TRUE, FALSE);
+
+  redisplay_region (tree, ins, bound);
 }
 
+
 void
 _gtk_text_btree_remove_mark_by_name (GtkTextBTree *tree,
                                     const gchar *name)
@@ -2698,7 +2891,7 @@ _gtk_text_btree_release_mark_segment (GtkTextBTree       *tree,
   /* Remove the ref on the mark, which frees segment as a side effect
    * if this is the last reference.
    */
-  g_object_unref (G_OBJECT (segment->body.mark.obj));
+  g_object_unref (segment->body.mark.obj);
 }
 
 void
@@ -3150,13 +3343,10 @@ ensure_end_iter_line (GtkTextBTree *tree)
 {
   if (tree->end_iter_line_stamp != tree->chars_changed_stamp)
     {
-      int n_lines;
-      int real_line;
-
-      /* n_lines is without the magic line at the end */
-      n_lines = _gtk_text_btree_line_count (tree);
-      g_assert (n_lines >= 1);
+      gint real_line;
+       
+       /* n_lines is without the magic line at the end */
+      g_assert (_gtk_text_btree_line_count (tree) >= 1);
 
       tree->end_iter_line = _gtk_text_btree_get_line_no_last (tree, -1, &real_line);
       
@@ -3579,9 +3769,9 @@ _gtk_text_line_byte_to_segment (GtkTextLine *line,
 
   while (offset >= seg->byte_count)
     {
-      g_assert (seg != NULL); /* means an invalid byte index */
       offset -= seg->byte_count;
       seg = seg->next;
+      g_assert (seg != NULL); /* means an invalid byte index */
     }
 
   if (seg_offset)
@@ -3605,9 +3795,9 @@ _gtk_text_line_char_to_segment (GtkTextLine *line,
 
   while (offset >= seg->char_count)
     {
-      g_assert (seg != NULL); /* means an invalid char index */
       offset -= seg->char_count;
       seg = seg->next;
+      g_assert (seg != NULL); /* means an invalid char index */
     }
 
   if (seg_offset)
@@ -3631,9 +3821,9 @@ _gtk_text_line_byte_to_any_segment (GtkTextLine *line,
 
   while (offset > 0 && offset >= seg->byte_count)
     {
-      g_assert (seg != NULL); /* means an invalid byte index */
       offset -= seg->byte_count;
       seg = seg->next;
+      g_assert (seg != NULL); /* means an invalid byte index */
     }
 
   if (seg_offset)
@@ -3657,9 +3847,9 @@ _gtk_text_line_char_to_any_segment (GtkTextLine *line,
 
   while (offset > 0 && offset >= seg->char_count)
     {
-      g_assert (seg != NULL); /* means an invalid byte index */
       offset -= seg->char_count;
       seg = seg->next;
+      g_assert (seg != NULL); /* means an invalid byte index */
     }
 
   if (seg_offset)
@@ -3683,12 +3873,10 @@ _gtk_text_line_byte_to_char (GtkTextLine *line,
   while (byte_offset >= seg->byte_count) /* while (we need to go farther than
                                             the next segment) */
     {
-      g_assert (seg != NULL); /* our byte_index was bogus if this happens */
-
       byte_offset -= seg->byte_count;
       char_offset += seg->char_count;
-
       seg = seg->next;
+      g_assert (seg != NULL); /* our byte_index was bogus if this happens */
     }
 
   g_assert (seg != NULL);
@@ -3732,7 +3920,6 @@ _gtk_text_line_byte_locate (GtkTextLine *line,
                             gint *line_byte_offset)
 {
   GtkTextLineSegment *seg;
-  GtkTextLineSegment *after_prev_indexable;
   GtkTextLineSegment *after_last_indexable;
   GtkTextLineSegment *last_indexable;
   gint offset;
@@ -3749,7 +3936,6 @@ _gtk_text_line_byte_locate (GtkTextLine *line,
 
   last_indexable = NULL;
   after_last_indexable = line->segments;
-  after_prev_indexable = line->segments;
   seg = line->segments;
 
   /* The loop ends when we're inside a segment;
@@ -3762,7 +3948,6 @@ _gtk_text_line_byte_locate (GtkTextLine *line,
           offset -= seg->byte_count;
           bytes_in_line += seg->byte_count;
           last_indexable = seg;
-          after_prev_indexable = after_last_indexable;
           after_last_indexable = last_indexable->next;
         }
 
@@ -3812,7 +3997,6 @@ _gtk_text_line_char_locate     (GtkTextLine     *line,
                                 gint             *line_char_offset)
 {
   GtkTextLineSegment *seg;
-  GtkTextLineSegment *after_prev_indexable;
   GtkTextLineSegment *after_last_indexable;
   GtkTextLineSegment *last_indexable;
   gint offset;
@@ -3829,7 +4013,6 @@ _gtk_text_line_char_locate     (GtkTextLine     *line,
 
   last_indexable = NULL;
   after_last_indexable = line->segments;
-  after_prev_indexable = line->segments;
   seg = line->segments;
 
   /* The loop ends when we're inside a segment;
@@ -3842,7 +4025,6 @@ _gtk_text_line_char_locate     (GtkTextLine     *line,
           offset -= seg->char_count;
           chars_in_line += seg->char_count;
           last_indexable = seg;
-          after_prev_indexable = after_last_indexable;
           after_last_indexable = last_indexable->next;
         }
 
@@ -3959,16 +4141,16 @@ _gtk_text_line_char_to_byte_offsets (GtkTextLine *line,
 
   if (seg->type == &gtk_text_char_type)
     {
-      *seg_byte_offset = 0;
-      while (offset > 0)
-        {
-          gint bytes;
-          const char * start = seg->body.chars + *seg_byte_offset;
+      const char *p;
 
-          bytes = g_utf8_next_char (start) - start;
-          *seg_byte_offset += bytes;
-          offset -= 1;
-        }
+      /* if in the last fourth of the segment walk backwards */
+      if (seg->char_count - offset < seg->char_count / 4)
+        p = g_utf8_offset_to_pointer (seg->body.chars + seg->byte_count, 
+                                      offset - seg->char_count);
+      else
+        p = g_utf8_offset_to_pointer (seg->body.chars, offset);
+
+      *seg_byte_offset = p - seg->body.chars;
 
       g_assert (*seg_byte_offset < seg->byte_count);
 
@@ -4306,9 +4488,7 @@ _gtk_text_line_previous_could_contain_tag (GtkTextLine  *line,
       line_ancestor = line->parent;
       line_ancestor_parent = line->parent->parent;
 
-      node = line_ancestor_parent->children.node;
-      while (node != line_ancestor &&
-             line_ancestor != info->tag_root)
+      while (line_ancestor != info->tag_root)
         {
           GSList *child_nodes = NULL;
           GSList *tmp;
@@ -4316,8 +4496,12 @@ _gtk_text_line_previous_could_contain_tag (GtkTextLine  *line,
           /* Create reverse-order list of nodes before
            * line_ancestor
            */
-          while (node != line_ancestor
-                 && node != NULL)
+          if (line_ancestor_parent != NULL)
+           node = line_ancestor_parent->children.node;
+         else
+           node = line_ancestor;
+
+          while (node != line_ancestor && node != NULL)
             {
               child_nodes = g_slist_prepend (child_nodes, node);
 
@@ -4347,8 +4531,6 @@ _gtk_text_line_previous_could_contain_tag (GtkTextLine  *line,
           /* Didn't find anything on this level; go up one level. */
           line_ancestor = line_ancestor_parent;
           line_ancestor_parent = line_ancestor->parent;
-
-          node = line_ancestor_parent->children.node;
         }
 
       /* No dice. */
@@ -4446,13 +4628,7 @@ _gtk_text_line_previous_could_contain_tag (GtkTextLine  *line,
 static void
 summary_list_destroy (Summary *summary)
 {
-  Summary *next;
-  while (summary != NULL)
-    {
-      next = summary->next;
-      summary_destroy (summary);
-      summary = next;
-    }
+  g_slice_free_chain (Summary, summary, next);
 }
 
 static GtkTextLine*
@@ -4487,6 +4663,9 @@ gtk_text_line_new (void)
   GtkTextLine *line;
 
   line = g_new0(GtkTextLine, 1);
+  line->dir_strong = PANGO_DIRECTION_NEUTRAL;
+  line->dir_propagated_forward = PANGO_DIRECTION_NEUTRAL;
+  line->dir_propagated_back = PANGO_DIRECTION_NEUTRAL;
 
   return line;
 }
@@ -4547,16 +4726,20 @@ cleanup_line (GtkTextLine *line)
   while (changed)
     {
       changed = FALSE;
-      for (prev_p = &line->segments, seg = *prev_p;
-           seg != NULL;
-           prev_p = &(*prev_p)->next, seg = *prev_p)
+      prev_p = &line->segments;
+      for (seg = *prev_p; seg != NULL; seg = *prev_p)
         {
           if (seg->type->cleanupFunc != NULL)
             {
               *prev_p = (*seg->type->cleanupFunc)(seg, line);
               if (seg != *prev_p)
-                changed = TRUE;
+               {
+                 changed = TRUE;
+                 continue;
+               }
             }
+
+         prev_p = &(*prev_p)->next;
         }
     }
 }
@@ -4570,7 +4753,7 @@ node_data_new (gpointer view_id)
 {
   NodeData *nd;
   
-  nd = g_new (NodeData, 1);
+  nd = g_slice_new (NodeData);
 
   nd->view_id = view_id;
   nd->next = NULL;
@@ -4584,26 +4767,18 @@ node_data_new (gpointer view_id)
 static void
 node_data_destroy (NodeData *nd)
 {
-  g_free (nd);
+  g_slice_free (NodeData, nd);
 }
 
 static void
 node_data_list_destroy (NodeData *nd)
 {
-  NodeData *iter;
-  NodeData *next;
-
-  iter = nd;
-  while (iter != NULL)
-    {
-      next = iter->next;
-      node_data_destroy (iter);
-      iter = next;
-    }
+  g_slice_free_chain (NodeData, nd, next);
 }
 
 static NodeData*
-node_data_find (NodeData *nd, gpointer view_id)
+node_data_find (NodeData *nd, 
+               gpointer  view_id)
 {
   while (nd != NULL)
     {
@@ -4621,7 +4796,7 @@ summary_destroy (Summary *summary)
   summary->info = (void*)0x1;
   summary->toggle_count = 567;
   summary->next = (void*)0x1;
-  g_free (summary);
+  g_slice_free (Summary, summary);
 }
 
 static GtkTextBTreeNode*
@@ -4659,7 +4834,7 @@ gtk_text_btree_node_adjust_toggle_count (GtkTextBTreeNode  *node,
     {
       /* didn't find a summary for our tag. */
       g_return_if_fail (adjust > 0);
-      summary = g_new (Summary, 1);
+      summary = g_slice_new (Summary);
       summary->info = info;
       summary->toggle_count = adjust;
       summary->next = node->summary;
@@ -5775,10 +5950,10 @@ gtk_text_btree_get_tag_info (GtkTextBTree *tree,
     {
       /* didn't find it, create. */
 
-      info = g_new (GtkTextTagInfo, 1);
+      info = g_slice_new (GtkTextTagInfo);
 
       info->tag = tag;
-      g_object_ref (G_OBJECT (tag));
+      g_object_ref (tag);
       info->tag_root = NULL;
       info->toggle_count = 0;
 
@@ -5826,9 +6001,9 @@ gtk_text_btree_remove_tag_info (GtkTextBTree *tree,
           list->next = NULL;
           g_slist_free (list);
 
-          g_object_unref (G_OBJECT (info->tag));
+          g_object_unref (info->tag);
 
-          g_free (info);
+          g_slice_free (GtkTextTagInfo, info);
           return;
         }
 
@@ -6128,7 +6303,7 @@ _gtk_change_node_toggle_count (GtkTextBTreeNode *node,
                */
 
               GtkTextBTreeNode *rootnode = info->tag_root;
-              summary = (Summary *) g_malloc (sizeof (Summary));
+              summary = g_slice_new (Summary);
               summary->info = info;
               summary->toggle_count = info->toggle_count - delta;
               summary->next = rootnode->summary;
@@ -6137,7 +6312,7 @@ _gtk_change_node_toggle_count (GtkTextBTreeNode *node,
               rootLevel = rootnode->level;
               info->tag_root = rootnode;
             }
-          summary = (Summary *) g_malloc (sizeof (Summary));
+          summary = g_slice_new (Summary);
           summary->info = info;
           summary->toggle_count = delta;
           summary->next = node->summary;
@@ -6687,15 +6862,15 @@ _gtk_text_btree_check (GtkTextBTree *tree)
   GtkTextLine *line;
   GtkTextLineSegment *seg;
   GtkTextTag *tag;
-  GSList *taglist = NULL;
+  GSList *all_tags, *taglist = NULL;
   int count;
   GtkTextTagInfo *info;
 
   /*
    * Make sure that the tag toggle counts and the tag root pointers are OK.
    */
-  for (taglist = list_of_tags (tree->table);
-       taglist != NULL ; taglist = taglist->next)
+  all_tags = list_of_tags (tree->table);
+  for (taglist = all_tags; taglist != NULL ; taglist = taglist->next)
     {
       tag = taglist->data;
       info = gtk_text_btree_get_existing_tag_info (tree, tag);
@@ -6747,7 +6922,7 @@ _gtk_text_btree_check (GtkTextBTree *tree)
             }
           else
             {
-              GtkTextLineSegmentClass * last = NULL;
+              const GtkTextLineSegmentClass *last = NULL;
 
               for (line = node->children.line ; line != NULL ;
                    line = line->next)
@@ -6779,8 +6954,7 @@ _gtk_text_btree_check (GtkTextBTree *tree)
         }
     }
 
-  g_slist_free (taglist);
-  taglist = NULL;
+  g_slist_free (all_tags);
 
   /*
    * Call a recursive procedure to do the main body of checks.
@@ -7057,4 +7231,5 @@ _gtk_text_btree_spew_segment (GtkTextBTree* tree, GtkTextLineSegment * seg)
     }
 }
 
-
+#define __GTK_TEXT_BTREE_C__
+#include "gtkaliasdef.c"