]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktextbtree.c
Bug 526987 - GtkCellRendererCombo should allow model to be NULL
[~andy/gtk] / gtk / gtktextbtree.c
index 1f06d59b23841fc26380613f893d8e2ed1753276..81038f427a8bafceba0625298874306e29628a6c 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
@@ -54,7 +54,6 @@
 
 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
 #include <config.h>
-#include "gtkalias.h"
 #include "gtktextbtree.h"
 #include <string.h>
 #include <stdlib.h>
@@ -65,6 +64,7 @@
 #include "gtktextiterprivate.h"
 #include "gtkdebug.h"
 #include "gtktextmarkprivate.h"
+#include "gtkalias.h"
 
 /*
  * Types
@@ -340,7 +340,8 @@ static void            gtk_text_btree_remove_tag_info       (GtkTextBTree   *tre
 
 static void redisplay_region (GtkTextBTree      *tree,
                               const GtkTextIter *start,
-                              const GtkTextIter *end);
+                              const GtkTextIter *end,
+                              gboolean           cursors_only);
 
 /* Inline thingies */
 
@@ -589,7 +590,7 @@ gtk_text_btree_resolve_bidi (GtkTextIter *start,
       
       while (seg)
         {
-          if (seg->byte_count > 0)
+          if (seg->type == &gtk_text_char_type && seg->byte_count > 0)
             {
              PangoDirection pango_dir;
 
@@ -663,7 +664,7 @@ gtk_text_btree_resolve_bidi (GtkTextIter *start,
      */
     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);
+    _gtk_text_btree_invalidate_region (tree, end, &end_propagate, FALSE);
   }
   
   /* Sweep backward */
@@ -719,7 +720,7 @@ gtk_text_btree_resolve_bidi (GtkTextIter *start,
     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);
+        _gtk_text_btree_invalidate_region (tree, &start_propagate, start, FALSE);
       }
   }
 }
@@ -732,12 +733,13 @@ _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;
   GtkTextLine *start_line;
   GtkTextLine *end_line;
+  GtkTextLine *line;
   GtkTextLine *deleted_lines = NULL;        /* List of lines we've deleted */
   gint start_byte_offset;
 
@@ -755,7 +757,7 @@ _gtk_text_btree_delete (GtkTextIter *start,
   
   /* Broadcast the need for redisplay before we break the iterators */
   DV (g_print ("invalidating due to deleting some text (%s)\n", G_STRLOC));
-  _gtk_text_btree_invalidate_region (tree, start, end);
+  _gtk_text_btree_invalidate_region (tree, start, end, FALSE);
 
   /* Save the byte offset so we can reset the iterators */
   start_byte_offset = gtk_text_iter_get_line_index (start);
@@ -885,12 +887,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;
             }
@@ -971,7 +991,6 @@ _gtk_text_btree_delete (GtkTextIter *start,
       view = tree->views;
       while (view)
         {
-          GtkTextLine *line;
           GtkTextLineData *ld;
 
           gint deleted_width = 0;
@@ -989,9 +1008,6 @@ _gtk_text_btree_delete (GtkTextIter *start,
                   deleted_height += ld->height;
                 }
 
-              if (!view->next)
-                gtk_text_line_destroy (tree, line);
-
               line = next_line;
             }
 
@@ -1025,6 +1041,16 @@ _gtk_text_btree_delete (GtkTextIter *start,
           view = view->next;
         }
 
+      line = deleted_lines;
+      while (line)
+        {
+          GtkTextLine *next_line = line->next;
+
+          gtk_text_line_destroy (tree, line);
+
+          line = next_line;
+        }
+
       /* avoid dangling pointer */
       deleted_lines = NULL;
       
@@ -1216,8 +1242,7 @@ _gtk_text_btree_insert (GtkTextIter *iter,
     gtk_text_iter_forward_chars (&end, char_count_delta);
 
     DV (g_print ("invalidating due to inserting some text (%s)\n", G_STRLOC));
-    _gtk_text_btree_invalidate_region (tree,
-                                      &start, &end);
+    _gtk_text_btree_invalidate_region (tree, &start, &end, FALSE);
 
 
     /* Convenience for the user */
@@ -1267,7 +1292,7 @@ insert_pixbuf_or_widget_segment (GtkTextIter        *iter,
   gtk_text_iter_forward_char (iter); /* skip forward past the segment */
 
   DV (g_print ("invalidating due to inserting pixbuf/widget (%s)\n", G_STRLOC));
-  _gtk_text_btree_invalidate_region (tree, &start, iter);
+  _gtk_text_btree_invalidate_region (tree, &start, iter, FALSE);
 }
      
 void
@@ -1602,7 +1627,8 @@ _gtk_text_btree_remove_view (GtkTextBTree *tree,
 void
 _gtk_text_btree_invalidate_region (GtkTextBTree      *tree,
                                    const GtkTextIter *start,
-                                   const GtkTextIter *end)
+                                   const GtkTextIter *end,
+                                   gboolean           cursors_only)
 {
   BTreeView *view;
 
@@ -1610,7 +1636,10 @@ _gtk_text_btree_invalidate_region (GtkTextBTree      *tree,
 
   while (view != NULL)
     {
-      gtk_text_layout_invalidate (view->layout, start, end);
+      if (cursors_only)
+       gtk_text_layout_invalidate_cursors (view->layout, start, end);
+      else
+       gtk_text_layout_invalidate (view->layout, start, end);
 
       view = view->next;
     }
@@ -1643,7 +1672,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;
@@ -1651,20 +1680,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;
@@ -1680,7 +1711,7 @@ static void
 iter_stack_free (IterStack *stack)
 {
   g_free (stack->iters);
-  g_free (stack);
+  g_slice_free (IterStack, stack);
 }
 
 static void
@@ -1713,12 +1744,12 @@ queue_tag_redisplay (GtkTextBTree      *tree,
   if (_gtk_text_tag_affects_size (tag))
     {
       DV (g_print ("invalidating due to size-affecting tag (%s)\n", G_STRLOC));
-      _gtk_text_btree_invalidate_region (tree, start, end);
+      _gtk_text_btree_invalidate_region (tree, start, end, FALSE);
     }
   else if (_gtk_text_tag_affects_nonsize_appearance (tag))
     {
       /* We only need to queue a redraw, not a relayout */
-      redisplay_region (tree, start, end);
+      redisplay_region (tree, start, end, FALSE);
     }
 
   /* We don't need to do anything if the tag doesn't affect display */
@@ -1975,6 +2006,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);
 }
@@ -2089,7 +2122,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;
 
@@ -2135,7 +2167,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)
     {
@@ -2165,6 +2196,8 @@ _gtk_text_btree_get_line_at_char (GtkTextBTree      *tree,
   return line;
 }
 
+/* It returns an array sorted by tags priority, ready to pass to
+ * _gtk_text_attributes_fill_from_tags() */
 GtkTextTag**
 _gtk_text_btree_get_tags (const GtkTextIter *iter,
                          gint *num_tags)
@@ -2175,13 +2208,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;
@@ -2275,6 +2306,10 @@ _gtk_text_btree_get_tags (const GtkTextIter *iter,
       g_free (tagInfo.tags);
       return NULL;
     }
+
+  /* Sort tags in ascending order of priority */
+  _gtk_text_tag_array_sort (tagInfo.tags, dst);
+
   return tagInfo.tags;
 }
 
@@ -2369,7 +2404,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;
@@ -2387,8 +2421,6 @@ _gtk_text_btree_get_text (const GtkTextIter *start_orig,
 
   retval = g_string_new (NULL);
 
-  tree = _gtk_text_iter_get_btree (&start);
-
   end_seg = _gtk_text_iter_get_indexable_segment (&end);
   iter = start;
   seg = _gtk_text_iter_get_indexable_segment (&iter);
@@ -2432,7 +2464,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;
@@ -2455,15 +2487,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.
@@ -2477,7 +2504,7 @@ _gtk_text_btree_char_is_invisible (const GtkTextIter *iter)
           || (seg->type == &gtk_text_toggle_off_type))
         {
           tag = seg->body.toggle.info->tag;
-          if (tag->invisible_set && tag->values->invisible)
+          if (tag->invisible_set)
             {
               tags[tag->priority] = tag;
               tagCnts[tag->priority]++;
@@ -2501,7 +2528,7 @@ _gtk_text_btree_char_is_invisible (const GtkTextIter *iter)
               || (seg->type == &gtk_text_toggle_off_type))
             {
               tag = seg->body.toggle.info->tag;
-              if (tag->invisible_set && tag->values->invisible)
+              if (tag->invisible_set)
                 {
                   tags[tag->priority] = tag;
                   tagCnts[tag->priority]++;
@@ -2530,7 +2557,7 @@ _gtk_text_btree_char_is_invisible (const GtkTextIter *iter)
               if (summary->toggle_count & 1)
                 {
                   tag = summary->info->tag;
-                  if (tag->invisible_set && tag->values->invisible)
+                  if (tag->invisible_set)
                     {
                       tags[tag->priority] = tag;
                       tagCnts[tag->priority] += summary->toggle_count;
@@ -2582,7 +2609,8 @@ _gtk_text_btree_char_is_invisible (const GtkTextIter *iter)
 static void
 redisplay_region (GtkTextBTree      *tree,
                   const GtkTextIter *start,
-                  const GtkTextIter *end)
+                  const GtkTextIter *end,
+                  gboolean           cursors_only)
 {
   BTreeView *view;
   GtkTextLine *start_line, *end_line;
@@ -2614,9 +2642,14 @@ redisplay_region (GtkTextBTree      *tree,
       if (ld)
         end_y += ld->height;
 
-      gtk_text_layout_changed (view->layout, start_y,
-                               end_y - start_y,
-                               end_y - start_y);
+      if (cursors_only)
+       gtk_text_layout_cursors_changed (view->layout, start_y,
+                                        end_y - start_y,
+                                         end_y - start_y);
+      else
+       gtk_text_layout_changed (view->layout, start_y,
+                                end_y - start_y,
+                                end_y - start_y);
 
       view = view->next;
     }
@@ -2636,8 +2669,7 @@ redisplay_mark (GtkTextLineSegment *mark)
   gtk_text_iter_forward_char (&end);
 
   DV (g_print ("invalidating due to moving visible mark (%s)\n", G_STRLOC));
-  _gtk_text_btree_invalidate_region (mark->body.mark.tree,
-                                    &iter, &end);
+  _gtk_text_btree_invalidate_region (mark->body.mark.tree, &iter, &end, TRUE);
 }
 
 static void
@@ -2654,8 +2686,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);
 }
 
@@ -2676,7 +2707,12 @@ real_set_mark (GtkTextBTree      *tree,
   g_return_val_if_fail (_gtk_text_iter_get_btree (where) == tree, NULL);
 
   if (existing_mark)
-    mark = existing_mark->segment;
+    {
+      if (gtk_text_mark_get_buffer (existing_mark) != NULL)
+       mark = existing_mark->segment;
+      else
+       mark = NULL;
+    }
   else if (name != NULL)
     mark = g_hash_table_lookup (tree->mark_table,
                                 name);
@@ -2708,7 +2744,7 @@ real_set_mark (GtkTextBTree      *tree,
 
           _gtk_text_btree_get_iter_at_mark (tree, &old_pos,
                                            mark->body.mark.obj);
-          redisplay_region (tree, &old_pos, where);
+          redisplay_region (tree, &old_pos, where, TRUE);
         }
 
       /*
@@ -2736,9 +2772,13 @@ real_set_mark (GtkTextBTree      *tree,
     }
   else
     {
-      mark = _gtk_mark_segment_new (tree,
-                                    left_gravity,
-                                    name);
+      if (existing_mark)
+       g_object_ref (existing_mark);
+      else
+       existing_mark = gtk_text_mark_new (name, left_gravity);
+
+      mark = existing_mark->segment;
+      _gtk_mark_segment_set_tree (mark, tree);
 
       mark->body.mark.line = _gtk_text_iter_get_text_line (&iter);
 
@@ -2838,16 +2878,28 @@ _gtk_text_btree_select_range (GtkTextBTree      *tree,
                              const GtkTextIter *ins,
                               const GtkTextIter *bound)
 {
-  GtkTextIter start, end;
+  GtkTextIter old_ins, old_bound;
+
+  _gtk_text_btree_get_iter_at_mark (tree, &old_ins,
+                                    tree->insert_mark);
+  _gtk_text_btree_get_iter_at_mark (tree, &old_bound,
+                                    tree->selection_bound_mark);
+
+  /* Check if it's no-op since gtk_text_buffer_place_cursor()
+   * also calls this, and this will redraw the cursor line. */
+  if (!gtk_text_iter_equal (&old_ins, ins) ||
+      !gtk_text_iter_equal (&old_bound, bound))
+    {
+      redisplay_region (tree, &old_ins, &old_bound, TRUE);
 
-  if (_gtk_text_btree_get_selection_bounds (tree, &start, &end))
-    redisplay_region (tree, &start, &end);
+      /* Move insert AND selection_bound before we redisplay */
+      real_set_mark (tree, tree->insert_mark,
+                    "insert", FALSE, ins, TRUE, FALSE);
+      real_set_mark (tree, tree->selection_bound_mark,
+                    "selection_bound", FALSE, bound, TRUE, FALSE);
 
-  /* Move insert AND selection_bound before we redisplay */
-  real_set_mark (tree, tree->insert_mark,
-                 "insert", FALSE, ins, TRUE, FALSE);
-  real_set_mark (tree, tree->selection_bound_mark,
-                 "selection_bound", FALSE, bound, TRUE, FALSE);
+      redisplay_region (tree, ins, bound, TRUE);
+    }
 }
 
 
@@ -2920,6 +2972,18 @@ _gtk_text_btree_mark_is_selection_bound (GtkTextBTree *tree,
   return segment == tree->selection_bound_mark;
 }
 
+GtkTextMark *
+_gtk_text_btree_get_insert (GtkTextBTree *tree)
+{
+  return tree->insert_mark;
+}
+
+GtkTextMark *
+_gtk_text_btree_get_selection_bound (GtkTextBTree *tree)
+{
+  return tree->selection_bound_mark;
+}
+
 GtkTextMark*
 _gtk_text_btree_get_mark_by_name (GtkTextBTree *tree,
                                   const gchar *name)
@@ -2962,7 +3026,8 @@ gtk_text_mark_set_visible (GtkTextMark       *mark,
     {
       seg->body.mark.visible = setting;
 
-      redisplay_mark (seg);
+      if (seg->body.mark.tree)
+       redisplay_mark (seg);
     }
 }
 
@@ -3332,13 +3397,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);
       
@@ -3761,9 +3823,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)
@@ -3787,9 +3849,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)
@@ -3813,9 +3875,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)
@@ -3839,9 +3901,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)
@@ -3865,12 +3927,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);
@@ -3914,7 +3974,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;
@@ -3931,7 +3990,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;
@@ -3944,7 +4002,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;
         }
 
@@ -3994,7 +4051,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;
@@ -4011,7 +4067,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;
@@ -4024,7 +4079,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;
         }
 
@@ -4141,16 +4195,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);
 
@@ -4628,13 +4682,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*
@@ -4732,16 +4780,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;
         }
     }
 }
@@ -4755,7 +4807,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;
@@ -4769,26 +4821,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)
     {
@@ -4806,7 +4850,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*
@@ -4844,7 +4888,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;
@@ -5612,8 +5656,7 @@ tag_changed_cb (GtkTextTagTable *table,
           /* Must be a last toggle if there was a first one. */
           _gtk_text_btree_get_iter_at_last_toggle (tree, &end, tag);
           DV (g_print ("invalidating due to tag change (%s)\n", G_STRLOC));
-          _gtk_text_btree_invalidate_region (tree,
-                                            &start, &end);
+          _gtk_text_btree_invalidate_region (tree, &start, &end, FALSE);
 
         }
     }
@@ -5960,7 +6003,7 @@ 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 (tag);
@@ -6013,7 +6056,7 @@ gtk_text_btree_remove_tag_info (GtkTextBTree *tree,
 
           g_object_unref (info->tag);
 
-          g_free (info);
+          g_slice_free (GtkTextTagInfo, info);
           return;
         }
 
@@ -6313,7 +6356,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;
@@ -6322,7 +6365,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;
@@ -6932,7 +6975,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)
@@ -7241,4 +7284,5 @@ _gtk_text_btree_spew_segment (GtkTextBTree* tree, GtkTextLineSegment * seg)
     }
 }
 
-
+#define __GTK_TEXT_BTREE_C__
+#include "gtkaliasdef.c"