]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktextiter.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtktextiter.c
index 97fc4b4ad6a1e330922aa6574f400fc0262f9490..2b41c34cfbb3b84eb03249a564bc8bc102f357b5 100644 (file)
@@ -12,9 +12,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 /*
  */
 
 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
+#include "config.h"
 #include "gtktextiter.h"
 #include "gtktextbtree.h"
 #include "gtktextiterprivate.h"
+#include "gtkintl.h"
 #include "gtkdebug.h"
+
 #include <string.h>
-#include <ctype.h>
+
+
+/**
+ * SECTION:gtktextiter
+ * @Short_description: Text buffer iterator
+ * @Title: GtkTextIter
+ *
+ * You may wish to begin by reading the <link linkend="TextWidget">text widget
+ * conceptual overview</link> which gives an overview of all the objects and data
+ * types related to the text widget and how they work together.
+ */
+
 
 #define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1
 
 typedef struct _GtkTextRealIter GtkTextRealIter;
 
-struct _GtkTextRealIter
+struct G_GNUC_MAY_ALIAS _GtkTextRealIter
 {
   /* Always-valid information */
   GtkTextBTree *tree;
@@ -65,6 +77,10 @@ struct _GtkTextRealIter
      and ditto for char offsets. */
   gint segment_byte_offset;
   gint segment_char_offset;
+
+  /* padding */
+  gint pad1;
+  gpointer pad2;
 };
 
 /* These "set" functions should not assume any fields
@@ -294,24 +310,12 @@ iter_init_from_char_offset (GtkTextIter *iter,
   return real;
 }
 
-static inline void
-invalidate_segment (GtkTextRealIter *iter)
-{
-  iter->segments_changed_stamp -= 1;
-}
-
 static inline void
 invalidate_char_index (GtkTextRealIter *iter)
 {
   iter->cached_char_index = -1;
 }
 
-static inline void
-invalidate_line_number (GtkTextRealIter *iter)
-{
-  iter->cached_line_number = -1;
-}
-
 static inline void
 adjust_char_index (GtkTextRealIter *iter, gint count)
 {
@@ -326,28 +330,6 @@ adjust_line_number (GtkTextRealIter *iter, gint count)
     iter->cached_line_number += count;
 }
 
-static inline void
-adjust_char_offsets (GtkTextRealIter *iter, gint count)
-{
-  if (iter->line_char_offset >= 0)
-    {
-      iter->line_char_offset += count;
-      g_assert (iter->segment_char_offset >= 0);
-      iter->segment_char_offset += count;
-    }
-}
-
-static inline void
-adjust_byte_offsets (GtkTextRealIter *iter, gint count)
-{
-  if (iter->line_byte_offset >= 0)
-    {
-      iter->line_byte_offset += count;
-      g_assert (iter->segment_byte_offset >= 0);
-      iter->segment_byte_offset += count;
-    }
-}
-
 static inline void
 ensure_char_offsets (GtkTextRealIter *iter)
 {
@@ -382,24 +364,24 @@ is_segment_start (GtkTextRealIter *real)
   return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
 }
 
-#if 1
+#ifdef G_ENABLE_DEBUG
 static void
 check_invariants (const GtkTextIter *iter)
 {
-  if (gtk_debug_flags & GTK_DEBUG_TEXT)
+  if (gtk_get_debug_flags () & GTK_DEBUG_TEXT)
     _gtk_text_iter_check (iter);
 }
 #else
-#define check_invariants (x)
+#define check_invariants(x)
 #endif
 
 /**
  * gtk_text_iter_get_buffer:
  * @iter: an iterator
  *
- * Return the #GtkTextBuffer this iterator is associated with
+ * Returns the #GtkTextBuffer this iterator is associated with.
  *
- * Return value: the buffer
+ * Return value: (transfer none): the buffer
  **/
 GtkTextBuffer*
 gtk_text_iter_get_buffer (const GtkTextIter *iter)
@@ -422,7 +404,7 @@ gtk_text_iter_get_buffer (const GtkTextIter *iter)
  * gtk_text_iter_copy:
  * @iter: an iterator
  *
- * Create a dynamically-allocated copy of an iterator. This function
+ * Creates a dynamically-allocated copy of an iterator. This function
  * is not useful in applications, because iterators can be copied with a
  * simple assignment (<literal>GtkTextIter i = j;</literal>). The
  * function is used by language bindings.
@@ -436,7 +418,7 @@ gtk_text_iter_copy (const GtkTextIter *iter)
 
   g_return_val_if_fail (iter != NULL, NULL);
 
-  new_iter = g_new (GtkTextIter, 1);
+  new_iter = g_slice_new (GtkTextIter);
 
   *new_iter = *iter;
 
@@ -451,22 +433,47 @@ gtk_text_iter_copy (const GtkTextIter *iter)
  * is intended for use in language bindings, and is not
  * especially useful for applications, because iterators can
  * simply be allocated on the stack.
- *
  **/
 void
 gtk_text_iter_free (GtkTextIter *iter)
 {
   g_return_if_fail (iter != NULL);
 
-  g_free (iter);
+  g_slice_free (GtkTextIter, iter);
+}
+
+/**
+ * gtk_text_iter_assign:
+ * @iter: a #GtkTextIter
+ * @other: another #GtkTextIter
+ *
+ * Assigns the value of @other to @iter.  This function
+ * is not useful in applications, because iterators can be assigned
+ * with <literal>GtkTextIter i = j;</literal>. The
+ * function is used by language bindings.
+ *
+ * Since: 3.2
+ **/
+void
+gtk_text_iter_assign (GtkTextIter       *iter,
+                      const GtkTextIter *other)
+{
+  g_return_if_fail (iter != NULL);
+  g_return_if_fail (other != NULL);
+
+  *iter = *other;
 }
 
+G_DEFINE_BOXED_TYPE (GtkTextIter, gtk_text_iter,
+                     gtk_text_iter_copy,
+                     gtk_text_iter_free)
+
 GtkTextLineSegment*
 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
 {
   GtkTextRealIter *real;
 
-  g_return_val_if_fail (iter != NULL, 0);
+  g_return_val_if_fail (iter != NULL, NULL);
 
   real = gtk_text_iter_make_real (iter);
 
@@ -485,7 +492,7 @@ _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
 {
   GtkTextRealIter *real;
 
-  g_return_val_if_fail (iter != NULL, 0);
+  g_return_val_if_fail (iter != NULL, NULL);
 
   real = gtk_text_iter_make_real (iter);
 
@@ -544,7 +551,7 @@ _gtk_text_iter_get_text_line (const GtkTextIter *iter)
 {
   const GtkTextRealIter *real;
 
-  g_return_val_if_fail (iter != NULL, 0);
+  g_return_val_if_fail (iter != NULL, NULL);
 
   real = (const GtkTextRealIter*)iter;
 
@@ -558,7 +565,7 @@ _gtk_text_iter_get_btree (const GtkTextIter *iter)
 {
   const GtkTextRealIter *real;
 
-  g_return_val_if_fail (iter != NULL, 0);
+  g_return_val_if_fail (iter != NULL, NULL);
 
   real = (const GtkTextRealIter*)iter;
 
@@ -729,9 +736,11 @@ gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
   ensure_char_offsets (real);
 
   check_invariants (iter);
-
+  
   vis_offset = real->line_char_offset;
 
+  g_assert (vis_offset >= 0);
+  
   _gtk_text_btree_get_iter_at_line (real->tree,
                                     &pos,
                                     real->line,
@@ -789,12 +798,14 @@ gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
   if (real == NULL)
     return 0;
 
-  ensure_char_offsets (real);
+  ensure_byte_offsets (real);
 
   check_invariants (iter);
 
   vis_offset = real->line_byte_offset;
 
+  g_assert (vis_offset >= 0);
+  
   _gtk_text_btree_get_iter_at_line (real->tree,
                                     &pos,
                                     real->line,
@@ -834,7 +845,7 @@ gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
  * @iter: an iterator
  *
  * Returns the Unicode character at this iterator.  (Equivalent to
- * operator* on a C++ iterator.)  If the iterator points at a
+ * operator* on a C++ iterator.)  If the element at this iterator is a
  * non-character element, such as an image embedded in the buffer, the
  * Unicode "unknown" character 0xFFFC is returned. If invoked on
  * the end iterator, zero is returned; zero is not a valid Unicode character.
@@ -980,11 +991,11 @@ gtk_text_iter_get_visible_text (const GtkTextIter  *start,
  * gtk_text_iter_get_pixbuf:
  * @iter: an iterator
  *
- * If the location pointed to by @iter contains a pixbuf, the pixbuf
- * is returned (with no new reference count added). Otherwise,
- * NULL is returned.
+ * If the element at @iter is a pixbuf, the pixbuf is returned
+ * (with no new reference count added). Otherwise,
+ * %NULL is returned.
  *
- * Return value: the pixbuf at @iter
+ * Return value: (transfer none): the pixbuf at @iter
  **/
 GdkPixbuf*
 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
@@ -1010,11 +1021,11 @@ gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
  * gtk_text_iter_get_child_anchor:
  * @iter: an iterator
  *
- * If the location pointed to by @iter contains a child anchor, the
+ * If the location at @iter contains a child anchor, the
  * anchor is returned (with no new reference count added). Otherwise,
- * NULL is returned.
+ * %NULL is returned.
  *
- * Return value: the anchor at @iter
+ * Return value: (transfer none): the anchor at @iter
  **/
 GtkTextChildAnchor*
 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
@@ -1046,7 +1057,7 @@ gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
  * can exist in the same place. The returned list is not in any
  * meaningful order.
  *
- * Return value: list of #GtkTextMark
+ * Return value: (element-type GtkTextMark) (transfer container): list of #GtkTextMark
  **/
 GSList*
 gtk_text_iter_get_marks (const GtkTextIter *iter)
@@ -1083,16 +1094,16 @@ gtk_text_iter_get_marks (const GtkTextIter *iter)
 /**
  * gtk_text_iter_get_toggled_tags:
  * @iter: an iterator
- * @toggled_on: TRUE to get toggled-on tags
+ * @toggled_on: %TRUE to get toggled-on tags
  *
  * Returns a list of #GtkTextTag that are toggled on or off at this
- * point.  (If @toggled_on is TRUE, the list contains tags that are
+ * point.  (If @toggled_on is %TRUE, the list contains tags that are
  * toggled on.) If a tag is toggled on at @iter, then some non-empty
  * range of characters following @iter has that tag applied to it.  If
  * a tag is toggled off, then some non-empty range following @iter
  * does <emphasis>not</emphasis> have the tag applied to it.
  *
- * Return value: tags toggled at this point
+ * Return value: (element-type GtkTextTag) (transfer container): tags toggled at this point
  **/
 GSList*
 gtk_text_iter_get_toggled_tags  (const GtkTextIter  *iter,
@@ -1141,11 +1152,11 @@ gtk_text_iter_get_toggled_tags  (const GtkTextIter  *iter,
 /**
  * gtk_text_iter_begins_tag:
  * @iter: an iterator
- * @tag: a #GtkTextTag, or NULL
+ * @tag: (allow-none): a #GtkTextTag, or %NULL
  *
- * Returns TRUE if @tag is toggled on at exactly this point. If @tag
- * is NULL, returns TRUE if any tag is toggled on at this point. Note
- * that the gtk_text_iter_begins_tag () returns TRUE if @iter is the
+ * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
+ * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
+ * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
  * <emphasis>start</emphasis> of the tagged range;
  * gtk_text_iter_has_tag () tells you whether an iterator is
  * <emphasis>within</emphasis> a tagged range.
@@ -1187,11 +1198,11 @@ gtk_text_iter_begins_tag    (const GtkTextIter  *iter,
 /**
  * gtk_text_iter_ends_tag:
  * @iter: an iterator
- * @tag: a #GtkTextTag, or NULL
+ * @tag: (allow-none): a #GtkTextTag, or %NULL
  *
- * Returns TRUE if @tag is toggled off at exactly this point. If @tag
- * is NULL, returns TRUE if any tag is toggled off at this point. Note
- * that the gtk_text_iter_ends_tag () returns TRUE if @iter is the
+ * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
+ * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
+ * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
  * <emphasis>end</emphasis> of the tagged range;
  * gtk_text_iter_has_tag () tells you whether an iterator is
  * <emphasis>within</emphasis> a tagged range.
@@ -1234,7 +1245,7 @@ gtk_text_iter_ends_tag   (const GtkTextIter  *iter,
 /**
  * gtk_text_iter_toggles_tag:
  * @iter: an iterator
- * @tag: a #GtkTextTag, or NULL
+ * @tag: (allow-none): a #GtkTextTag, or %NULL
  *
  * This is equivalent to (gtk_text_iter_begins_tag () ||
  * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
@@ -1278,7 +1289,7 @@ gtk_text_iter_toggles_tag (const GtkTextIter  *iter,
  * @iter: an iterator
  * @tag: a #GtkTextTag
  *
- * Returns TRUE if @iter is within a range tagged with @tag.
+ * Returns %TRUE if @iter is within a range tagged with @tag.
  *
  * Return value: whether @iter is tagged with @tag
  **/
@@ -1319,8 +1330,8 @@ gtk_text_iter_has_tag (const GtkTextIter   *iter,
  * priority (highest-priority tags are last). The #GtkTextTag in the
  * list don't have a reference added, but you have to free the list
  * itself.
- * 
- * Return value: list of #GtkTextTag
+ *
+ * Return value: (element-type GtkTextTag) (transfer container): list of #GtkTextTag
  **/
 GSList*
 gtk_text_iter_get_tags (const GtkTextIter *iter)
@@ -1338,15 +1349,11 @@ gtk_text_iter_get_tags (const GtkTextIter *iter)
   /* No tags, use default style */
   if (tags == NULL || tag_count == 0)
     {
-      if (tags)
-        g_free (tags);
+      g_free (tags);
 
       return NULL;
     }
 
-  /* Sort tags in ascending order of priority */
-  _gtk_text_tag_array_sort (tags, tag_count);
-
   retval = NULL;
   i = 0;
   while (i < tag_count)
@@ -1449,7 +1456,7 @@ gtk_text_iter_can_insert (const GtkTextIter *iter,
  *
  * A convenience wrapper around gtk_text_iter_get_attributes (),
  * which returns the language in effect at @iter. If no tags affecting
- * language apply to @iter, the return value is identical to that of
+ * language apply to @iter, the return value is identical to that of
  * gtk_get_default_language ().
  *
  * Return value: language in effect at @iter
@@ -1475,7 +1482,7 @@ gtk_text_iter_get_language (const GtkTextIter *iter)
  * gtk_text_iter_starts_line:
  * @iter: an iterator
  *
- * Returns TRUE if @iter begins a paragraph,
+ * Returns %TRUE if @iter begins a paragraph,
  * i.e. if gtk_text_iter_get_line_offset () would return 0.
  * However this function is potentially more efficient than
  * gtk_text_iter_get_line_offset () because it doesn't have to compute
@@ -1512,25 +1519,24 @@ gtk_text_iter_starts_line (const GtkTextIter   *iter)
  * gtk_text_iter_ends_line:
  * @iter: an iterator
  *
- * Returns TRUE if @iter points to the start of the paragraph delimiter
- * characters for a line (delimiters will be either a newline, a
- * carriage return, a carriage return followed by a newline, or a
- * Unicode paragraph separator character). Note that an iterator pointing
- * to the \n of a \r\n pair will not be counted as the end of a line,
- * the line ends before the \r.
+ * Returns %TRUE if @iter points to the start of the paragraph
+ * delimiter characters for a line (delimiters will be either a
+ * newline, a carriage return, a carriage return followed by a
+ * newline, or a Unicode paragraph separator character). Note that an
+ * iterator pointing to the \n of a \r\n pair will not be counted as
+ * the end of a line, the line ends before the \r. The end iterator is
+ * considered to be at the end of a line, even though there are no
+ * paragraph delimiter chars there.
  *
  * Return value: whether @iter is at the end of a line
  **/
 gboolean
 gtk_text_iter_ends_line (const GtkTextIter   *iter)
 {
-  GtkTextRealIter *real;
   gunichar wc;
   
   g_return_val_if_fail (iter != NULL, FALSE);
 
-  real = gtk_text_iter_make_real (iter);
-  
   check_invariants (iter);
 
   /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
@@ -1540,14 +1546,27 @@ gtk_text_iter_ends_line (const GtkTextIter   *iter)
 
   wc = gtk_text_iter_get_char (iter);
   
-  if (wc == '\r' || wc == PARAGRAPH_SEPARATOR)
+  if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
     return TRUE;
   else if (wc == '\n')
     {
+      GtkTextIter tmp = *iter;
+
       /* need to determine if a \r precedes the \n, in which case
-       * we aren't the end of the line
+       * we aren't the end of the line.
+       * Note however that if \r and \n are on different lines, they
+       * both are terminators. This for instance may happen after
+       * deleting some text:
+
+          1 some text\r    delete 'a'    1 some text\r
+          2 a\n            --------->    2 \n
+          3 ...                          3 ...
+
        */
-      GtkTextIter tmp = *iter;
+
+      if (gtk_text_iter_get_line_offset (&tmp) == 0)
+        return TRUE;
+
       if (!gtk_text_iter_backward_char (&tmp))
         return TRUE;
 
@@ -1561,7 +1580,7 @@ gtk_text_iter_ends_line (const GtkTextIter   *iter)
  * gtk_text_iter_is_end:
  * @iter: an iterator
  *
- * Returns TRUE if @iter is the end iterator, i.e. one past the last
+ * Returns %TRUE if @iter is the end iterator, i.e. one past the last
  * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
  * the most efficient way to check whether an iterator is the end
  * iterator.
@@ -1601,7 +1620,7 @@ gtk_text_iter_is_end (const GtkTextIter *iter)
  * gtk_text_iter_is_start:
  * @iter: an iterator
  *
- * Returns TRUE if @iter is the first iterator in the buffer, that is
+ * Returns %TRUE if @iter is the first iterator in the buffer, that is
  * if @iter has a character offset of 0.
  *
  * Return value: whether @iter is the first in the buffer
@@ -1628,7 +1647,7 @@ gtk_text_iter_get_chars_in_line (const GtkTextIter   *iter)
   gint count;
   GtkTextLineSegment *seg;
 
-  g_return_val_if_fail (iter != NULL, FALSE);
+  g_return_val_if_fail (iter != NULL, 0);
 
   real = gtk_text_iter_make_surreal (iter);
 
@@ -1658,6 +1677,9 @@ gtk_text_iter_get_chars_in_line (const GtkTextIter   *iter)
       seg = seg->next;
     }
 
+  if (_gtk_text_line_contains_end_iter (real->line, real->tree))
+    count -= 1; /* Dump the newline that was in the last segment of the end iter line */
+  
   return count;
 }
 
@@ -1677,7 +1699,7 @@ gtk_text_iter_get_bytes_in_line (const GtkTextIter   *iter)
   gint count;
   GtkTextLineSegment *seg;
 
-  g_return_val_if_fail (iter != NULL, FALSE);
+  g_return_val_if_fail (iter != NULL, 0);
 
   real = gtk_text_iter_make_surreal (iter);
 
@@ -1706,13 +1728,16 @@ gtk_text_iter_get_bytes_in_line (const GtkTextIter   *iter)
       seg = seg->next;
     }
 
+  if (_gtk_text_line_contains_end_iter (real->line, real->tree))
+    count -= 1; /* Dump the newline that was in the last segment of the end iter line */
+  
   return count;
 }
 
 /**
  * gtk_text_iter_get_attributes:
  * @iter: an iterator
- * @values: a #GtkTextAttributes to be filled in
+ * @values: (out): a #GtkTextAttributes to be filled in
  *
  * Computes the effect of any tags applied to this spot in the
  * text. The @values parameter should be initialized to the default
@@ -1738,15 +1763,11 @@ gtk_text_iter_get_attributes (const GtkTextIter  *iter,
   /* No tags, use default style */
   if (tags == NULL || tag_count == 0)
     {
-      if (tags)
-        g_free (tags);
+      g_free (tags);
 
       return FALSE;
     }
 
-  /* Sort tags in ascending order of priority */
-  _gtk_text_tag_array_sort (tags, tag_count);
-
   _gtk_text_attributes_fill_from_tags (values,
                                        tags,
                                        tag_count);
@@ -1807,10 +1828,14 @@ forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
     }
 }
 
-
+#if 0
 /* The return value of this indicates WHETHER WE MOVED.
  * The return value of public functions indicates
  * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
+ *
+ * This function is currently unused, thus it is #if-0-ed. It is
+ * left here, since it's non-trivial code that might be useful in
+ * the future.
  */
 static gboolean
 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
@@ -1851,6 +1876,7 @@ backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
       return FALSE;
     }
 }
+#endif 
 
 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
  * DEREFERENCEABLE)
@@ -1976,7 +2002,7 @@ _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
 
       check_invariants (iter);
 
-      return TRUE;
+      return !gtk_text_iter_is_end (iter);
     }
   else
     {
@@ -1995,21 +2021,23 @@ _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
 
           check_invariants (iter);
 
-          if (gtk_text_iter_is_end (iter))
-            return FALSE;
-          else
-            return TRUE;
+          return !gtk_text_iter_is_end (iter);
         }
       else
         {
-          /* End of buffer */
+          /* End of buffer, but iter is still at start of last segment,
+           * not at the end iterator. We put it on the end iterator.
+           */
+          
+          check_invariants (iter);
 
           g_assert (!_gtk_text_line_is_last (real->line, real->tree));
           g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
+
+          gtk_text_iter_forward_to_line_end (iter);
+
           g_assert (gtk_text_iter_is_end (iter));
           
-          check_invariants (iter);
-
           return FALSE;
         }
     }
@@ -2096,7 +2124,7 @@ _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
    * segment just before our current segment.
    */
   g_assert (seg != real->segment);
-  while (seg != real->segment)
+  do
     {
       prev_seg = seg;
       prev_any_seg = any_seg;
@@ -2106,6 +2134,7 @@ _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
       while (seg->char_count == 0)
         seg = seg->next;
     }
+  while (seg != real->segment);
 
   g_assert (prev_seg != NULL);
   g_assert (prev_any_seg != NULL);
@@ -2176,10 +2205,10 @@ _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
  * gtk_text_iter_forward_char () may actually move onto an image instead
  * of a character, if you have images in your buffer.  If @iter is the
  * end iterator or one character before it, @iter will now point at
- * the end iterator, and gtk_text_iter_forward_char () returns FALSE for
+ * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
  * convenience when writing loops.
  *
- * Return value: whether the new position is the end iterator
+ * Return value: whether @iter moved and is dereferenceable
  **/
 gboolean
 gtk_text_iter_forward_char (GtkTextIter *iter)
@@ -2203,9 +2232,9 @@ gtk_text_iter_forward_char (GtkTextIter *iter)
  * gtk_text_iter_backward_char:
  * @iter: an iterator
  *
- * Moves backward by one character offset. Returns TRUE if movement
+ * Moves backward by one character offset. Returns %TRUE if movement
  * was possible; if @iter was the first in the buffer (character
- * offset 0), gtk_text_iter_backward_char () returns FALSE for convenience when
+ * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
  * writing loops.
  *
  * Return value: whether movement was possible
@@ -2245,7 +2274,7 @@ gtk_text_iter_backward_char (GtkTextIter *iter)
  * buffer). The return value indicates whether the new position of
  * @iter is different from its original position, and dereferenceable
  * (the last iterator in the buffer is not dereferenceable). If @count
- * is 0, the function does nothing and returns FALSE.
+ * is 0, the function does nothing and returns %FALSE.
  *
  * Return value: whether @iter moved and is dereferenceable
  **/
@@ -2315,8 +2344,8 @@ gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
  * past the start or end of the buffer, moves to the start or end of
  * the buffer).  The return value indicates whether the iterator moved
  * onto a dereferenceable position; if the iterator didn't move, or
- * moved onto the end iterator, then FALSE is returned. If @count is 0,
- * the function does nothing and returns FALSE.
+ * moved onto the end iterator, then %FALSE is returned. If @count is 0,
+ * the function does nothing and returns %FALSE.
  *
  * Return value: whether @iter moved and is dereferenceable
  *
@@ -2342,34 +2371,35 @@ gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
   ensure_char_offsets (real);
   check_invariants (iter);
 
-  if (count <= real->segment_char_offset)
+  /* <, not <=, because if count == segment_char_offset
+   * we're going to the front of the segment and the any_segment
+   * might change
+   */
+  if (count < real->segment_char_offset)
     {
       /* Optimize the within-segment case */
       g_assert (real->segment->char_count > 0);
       g_assert (real->segment->type == &gtk_text_char_type);
 
-      real->segment_char_offset -= count;
-      g_assert (real->segment_char_offset >= 0);
-
       if (real->line_byte_offset >= 0)
         {
+          const char *p;
           gint new_byte_offset;
-          gint i;
-
-          new_byte_offset = 0;
-          i = 0;
-          while (i < real->segment_char_offset)
-            {
-              const char * start = real->segment->body.chars + new_byte_offset;
-              new_byte_offset += g_utf8_next_char (start) - start;
 
-              ++i;
-            }
+          /* if in the last fourth of the segment walk backwards */
+          if (count < real->segment_char_offset / 4)
+            p = g_utf8_offset_to_pointer (real->segment->body.chars + real->segment_byte_offset, 
+                                          -count);
+          else
+            p = g_utf8_offset_to_pointer (real->segment->body.chars,
+                                          real->segment_char_offset - count);
 
+          new_byte_offset = p - real->segment->body.chars;
           real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
           real->segment_byte_offset = new_byte_offset;
         }
 
+      real->segment_char_offset -= count;
       real->line_char_offset -= count;
 
       adjust_char_index (real, 0 - count);
@@ -2397,6 +2427,7 @@ gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
           new_char_index = current_char_index - count;
           if (new_char_index < 0)
             new_char_index = 0;
+
           gtk_text_iter_set_offset (iter, new_char_index);
 
           check_invariants (iter);
@@ -2441,7 +2472,7 @@ gtk_text_iter_forward_text_chars  (GtkTextIter *iter,
 }
 
 /**
- * gtk_text_iter_forward_text_chars:
+ * gtk_text_iter_backward_text_chars:
  * @iter: a #GtkTextIter
  * @count: number of chars to move
  *
@@ -2465,10 +2496,10 @@ gtk_text_iter_backward_text_chars (GtkTextIter *iter,
  * gtk_text_iter_forward_line:
  * @iter: an iterator
  *
- * Moves @iter to the start of the next line. Returns TRUE if there
- * was a next line to move to, and FALSE if @iter was simply moved to
- * the end of the buffer and is now not dereferenceable, or if @iter was
- * already at the end of the buffer.
+ * Moves @iter to the start of the next line. If the iter is already on the
+ * last line of the buffer, moves the iter to the end of the current line.
+ * If after the operation, the iter is at the end of the buffer and not
+ * dereferencable, returns %FALSE. Otherwise, returns %TRUE.
  *
  * Return value: whether @iter can be dereferenced
  **/
@@ -2514,11 +2545,11 @@ gtk_text_iter_forward_line (GtkTextIter *iter)
  * gtk_text_iter_backward_line:
  * @iter: an iterator
  *
- * Moves @iter to the start of the previous line. Returns TRUE if
+ * Moves @iter to the start of the previous line. Returns %TRUE if
  * @iter could be moved; i.e. if @iter was at character offset 0, this
- * function returns FALSE. Therefore if @iter was already on line 0,
+ * function returns %FALSE. Therefore if @iter was already on line 0,
  * but not at the start of the line, @iter is snapped to the start of
- * the line and the function returns TRUE. (Note that this implies that
+ * the line and the function returns %TRUE. (Note that this implies that
  * in a loop calling this function, the line number may not change on
  * every iteration, if your first iteration is on line 0.)
  *
@@ -2595,8 +2626,8 @@ gtk_text_iter_backward_line (GtkTextIter *iter)
  * past the start or end of the buffer, moves to the start or end of
  * the buffer).  The return value indicates whether the iterator moved
  * onto a dereferenceable position; if the iterator didn't move, or
- * moved onto the end iterator, then FALSE is returned. If @count is 0,
- * the function does nothing and returns FALSE. If @count is negative,
+ * moved onto the end iterator, then %FALSE is returned. If @count is 0,
+ * the function does nothing and returns %FALSE. If @count is negative,
  * moves backward by 0 - @count lines.
  *
  * Return value: whether @iter moved and is dereferenceable
@@ -2646,8 +2677,8 @@ gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
  * past the start or end of the buffer, moves to the start or end of
  * the buffer).  The return value indicates whether the iterator moved
  * onto a dereferenceable position; if the iterator didn't move, or
- * moved onto the end iterator, then FALSE is returned. If @count is 0,
- * the function does nothing and returns FALSE. If @count is negative,
+ * moved onto the end iterator, then %FALSE is returned. If @count is 0,
+ * the function does nothing and returns %FALSE. If @count is negative,
  * moves forward by 0 - @count lines.
  *
  * Return value: whether @iter moved and is dereferenceable
@@ -2677,6 +2708,162 @@ gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
     }
 }
 
+/**
+ * gtk_text_iter_forward_visible_line:
+ * @iter: an iterator
+ *
+ * Moves @iter to the start of the next visible line. Returns %TRUE if there
+ * was a next line to move to, and %FALSE if @iter was simply moved to
+ * the end of the buffer and is now not dereferenceable, or if @iter was
+ * already at the end of the buffer.
+ *
+ * Return value: whether @iter can be dereferenced
+ * 
+ * Since: 2.8
+ **/
+gboolean
+gtk_text_iter_forward_visible_line (GtkTextIter *iter)
+{
+  while (gtk_text_iter_forward_line (iter))
+    {
+      if (!_gtk_text_btree_char_is_invisible (iter))
+        return TRUE;
+      else
+        {
+          do
+            {
+              if (!gtk_text_iter_forward_char (iter))
+                return FALSE;
+          
+              if (!_gtk_text_btree_char_is_invisible (iter))
+                return TRUE;
+            }
+          while (!gtk_text_iter_ends_line (iter));
+        }
+    }
+    
+  return FALSE;
+}
+
+/**
+ * gtk_text_iter_backward_visible_line:
+ * @iter: an iterator
+ *
+ * Moves @iter to the start of the previous visible line. Returns %TRUE if
+ * @iter could be moved; i.e. if @iter was at character offset 0, this
+ * function returns %FALSE. Therefore if @iter was already on line 0,
+ * but not at the start of the line, @iter is snapped to the start of
+ * the line and the function returns %TRUE. (Note that this implies that
+ * in a loop calling this function, the line number may not change on
+ * every iteration, if your first iteration is on line 0.)
+ *
+ * Return value: whether @iter moved
+ *
+ * Since: 2.8
+ **/
+gboolean
+gtk_text_iter_backward_visible_line (GtkTextIter *iter)
+{
+  while (gtk_text_iter_backward_line (iter))
+    {
+      if (!_gtk_text_btree_char_is_invisible (iter))
+        return TRUE;
+      else
+        {
+          do
+            {
+              if (!gtk_text_iter_backward_char (iter))
+                return FALSE;
+          
+              if (!_gtk_text_btree_char_is_invisible (iter))
+                return TRUE;
+            }
+          while (!gtk_text_iter_starts_line (iter));
+        }
+    }
+    
+  return FALSE;
+}
+
+/**
+ * gtk_text_iter_forward_visible_lines:
+ * @iter: a #GtkTextIter
+ * @count: number of lines to move forward
+ *
+ * Moves @count visible lines forward, if possible (if @count would move
+ * past the start or end of the buffer, moves to the start or end of
+ * the buffer).  The return value indicates whether the iterator moved
+ * onto a dereferenceable position; if the iterator didn't move, or
+ * moved onto the end iterator, then %FALSE is returned. If @count is 0,
+ * the function does nothing and returns %FALSE. If @count is negative,
+ * moves backward by 0 - @count lines.
+ *
+ * Return value: whether @iter moved and is dereferenceable
+ * 
+ * Since: 2.8
+ **/
+gboolean
+gtk_text_iter_forward_visible_lines (GtkTextIter *iter,
+                                     gint         count)
+{
+  FIX_OVERFLOWS (count);
+  
+  if (count < 0)
+    return gtk_text_iter_backward_visible_lines (iter, 0 - count);
+  else if (count == 0)
+    return FALSE;
+  else if (count == 1)
+    {
+      check_invariants (iter);
+      return gtk_text_iter_forward_visible_line (iter);
+    }
+  else
+    {
+      while (gtk_text_iter_forward_visible_line (iter) && count > 0)
+        count--;
+      return count == 0;
+    }    
+}
+
+/**
+ * gtk_text_iter_backward_visible_lines:
+ * @iter: a #GtkTextIter
+ * @count: number of lines to move backward
+ *
+ * Moves @count visible lines backward, if possible (if @count would move
+ * past the start or end of the buffer, moves to the start or end of
+ * the buffer).  The return value indicates whether the iterator moved
+ * onto a dereferenceable position; if the iterator didn't move, or
+ * moved onto the end iterator, then %FALSE is returned. If @count is 0,
+ * the function does nothing and returns %FALSE. If @count is negative,
+ * moves forward by 0 - @count lines.
+ *
+ * Return value: whether @iter moved and is dereferenceable
+ *
+ * Since: 2.8
+ **/
+gboolean
+gtk_text_iter_backward_visible_lines (GtkTextIter *iter,
+                                      gint         count)
+{
+  FIX_OVERFLOWS (count);
+  
+  if (count < 0)
+    return gtk_text_iter_forward_visible_lines (iter, 0 - count);
+  else if (count == 0)
+    return FALSE;
+  else if (count == 1)
+    {
+      return gtk_text_iter_backward_visible_line (iter);
+    }
+  else
+    {
+      while (gtk_text_iter_backward_visible_line (iter) && count > 0)
+        count--;
+      return count == 0;
+    }
+}
+
 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
                                       gint                offset,
                                       gint                min_offset,
@@ -2762,7 +2949,10 @@ inside_word_func (const PangoLogAttr *attrs,
          !(attrs[offset].is_word_start || attrs[offset].is_word_end))
     --offset;
 
-  return attrs[offset].is_word_start;
+  if (offset >= 0)
+    return attrs[offset].is_word_start;
+  else
+    return FALSE;
 }
 
 /* Sentence funcs */
@@ -2864,7 +3054,7 @@ test_log_attrs (const GtkTextIter *iter,
    * for one past the end
    */
   
-  if (offset <= char_len)
+  if (attrs && offset <= char_len)
     result = (* func) (attrs, offset, 0, char_len);
 
   return result;
@@ -2955,6 +3145,64 @@ find_by_log_attrs (GtkTextIter    *iter,
     }
 }
 
+static gboolean 
+find_visible_by_log_attrs (GtkTextIter    *iter,
+                          FindLogAttrFunc func,
+                          gboolean        forward,
+                          gboolean        already_moved_initially)
+{
+  GtkTextIter pos;
+
+  g_return_val_if_fail (iter != NULL, FALSE);
+  
+  pos = *iter;
+  
+  while (find_by_log_attrs (&pos, func, forward, already_moved_initially)) 
+    {
+      if (!_gtk_text_btree_char_is_invisible (&pos)) 
+       {
+         *iter = pos;
+         return TRUE;
+       }
+  }
+
+  return FALSE;
+}
+
+typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
+typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
+                                 
+static gboolean 
+move_multiple_steps (GtkTextIter *iter, 
+                    gint count,
+                    OneStepFunc step_forward,
+                    MultipleStepFunc n_steps_backward)
+{
+  g_return_val_if_fail (iter != NULL, FALSE);
+
+  FIX_OVERFLOWS (count);
+  
+  if (count == 0)
+    return FALSE;
+  
+  if (count < 0)
+    return n_steps_backward (iter, -count);
+  
+  if (!step_forward (iter))
+    return FALSE;
+  --count;
+
+  while (count > 0)
+    {
+      if (!step_forward (iter))
+        break;
+      --count;
+    }
+  
+  return !gtk_text_iter_is_end (iter);  
+}
+              
+
 /**
  * gtk_text_iter_forward_word_end:
  * @iter: a #GtkTextIter
@@ -2977,7 +3225,7 @@ gtk_text_iter_forward_word_end (GtkTextIter *iter)
  * gtk_text_iter_backward_word_start:
  * @iter: a #GtkTextIter
  * 
- * Moves backward to the next word start. (If @iter is currently on a
+ * Moves backward to the previous word start. (If @iter is currently on a
  * word start, moves backward to the next one after that.) Word breaks
  * are determined by Pango and should be correct for nearly any
  * language (if not, the correct fix would be to the Pango word break
@@ -3008,35 +3256,17 @@ gboolean
 gtk_text_iter_forward_word_ends (GtkTextIter      *iter,
                                  gint              count)
 {
-  g_return_val_if_fail (iter != NULL, FALSE);
-
-  FIX_OVERFLOWS (count);
-  
-  if (count == 0)
-    return FALSE;
-
-  if (count < 0)
-    return gtk_text_iter_backward_word_starts (iter, -count);
-
-  if (!gtk_text_iter_forward_word_end (iter))
-    return FALSE;
-  --count;
-
-  while (count > 0)
-    {
-      if (!gtk_text_iter_forward_word_end (iter))
-        break;
-      --count;
-    }
-  return TRUE;
-}
+  return move_multiple_steps (iter, count, 
+                             gtk_text_iter_forward_word_end,
+                             gtk_text_iter_backward_word_starts);
+}
 
 /**
- * gtk_text_iter_backward_word_starts
+ * gtk_text_iter_backward_word_starts:
  * @iter: a #GtkTextIter
  * @count: number of times to move
  * 
- * Calls gtk_text_iter_backward_word_starts() up to @count times.
+ * Calls gtk_text_iter_backward_word_start() up to @count times.
  *
  * Return value: %TRUE if @iter moved and is not the end iterator 
  **/
@@ -3044,24 +3274,89 @@ gboolean
 gtk_text_iter_backward_word_starts (GtkTextIter      *iter,
                                     gint               count)
 {
-  g_return_val_if_fail (iter != NULL, FALSE);
+  return move_multiple_steps (iter, count, 
+                             gtk_text_iter_backward_word_start,
+                             gtk_text_iter_forward_word_ends);
+}
 
-  FIX_OVERFLOWS (count);
-  
-  if (count < 0)
-    return gtk_text_iter_forward_word_ends (iter, -count);
+/**
+ * gtk_text_iter_forward_visible_word_end:
+ * @iter: a #GtkTextIter
+ * 
+ * Moves forward to the next visible word end. (If @iter is currently on a
+ * word end, moves forward to the next one after that.) Word breaks
+ * are determined by Pango and should be correct for nearly any
+ * language (if not, the correct fix would be to the Pango word break
+ * algorithms).
+ * 
+ * Return value: %TRUE if @iter moved and is not the end iterator 
+ *
+ * Since: 2.4
+ **/
+gboolean
+gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
+{
+  return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
+}
 
-  if (!gtk_text_iter_backward_word_start (iter))
-    return FALSE;
-  --count;
+/**
+ * gtk_text_iter_backward_visible_word_start:
+ * @iter: a #GtkTextIter
+ * 
+ * Moves backward to the previous visible word start. (If @iter is currently 
+ * on a word start, moves backward to the next one after that.) Word breaks
+ * are determined by Pango and should be correct for nearly any
+ * language (if not, the correct fix would be to the Pango word break
+ * algorithms).
+ * 
+ * Return value: %TRUE if @iter moved and is not the end iterator 
+ * 
+ * Since: 2.4
+ **/
+gboolean
+gtk_text_iter_backward_visible_word_start (GtkTextIter      *iter)
+{
+  return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
+}
 
-  while (count > 0)
-    {
-      if (!gtk_text_iter_backward_word_start (iter))
-        break;
-      --count;
-    }
-  return TRUE;
+/**
+ * gtk_text_iter_forward_visible_word_ends:
+ * @iter: a #GtkTextIter
+ * @count: number of times to move
+ * 
+ * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
+ *
+ * Return value: %TRUE if @iter moved and is not the end iterator 
+ *
+ * Since: 2.4
+ **/
+gboolean
+gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
+                                        gint         count)
+{
+  return move_multiple_steps (iter, count, 
+                             gtk_text_iter_forward_visible_word_end,
+                             gtk_text_iter_backward_visible_word_starts);
+}
+
+/**
+ * gtk_text_iter_backward_visible_word_starts:
+ * @iter: a #GtkTextIter
+ * @count: number of times to move
+ * 
+ * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
+ *
+ * Return value: %TRUE if @iter moved and is not the end iterator 
+ * 
+ * Since: 2.4
+ **/
+gboolean
+gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
+                                           gint         count)
+{
+  return move_multiple_steps (iter, count, 
+                             gtk_text_iter_backward_visible_word_start,
+                             gtk_text_iter_forward_visible_word_ends);
 }
 
 /**
@@ -3189,7 +3484,7 @@ gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
  * gtk_text_iter_backward_sentence_start:
  * @iter: a #GtkTextIter
  * 
- * Moves backward to the next sentence start; if @iter is already at
+ * Moves backward to the previous sentence start; if @iter is already at
  * the start of a sentence, moves backward to the next one.  Sentence
  * boundaries are determined by Pango and should be correct for nearly
  * any language (if not, the correct fix would be to the Pango text
@@ -3221,25 +3516,9 @@ gboolean
 gtk_text_iter_forward_sentence_ends (GtkTextIter      *iter,
                                      gint              count)
 {
-  g_return_val_if_fail (iter != NULL, FALSE);
-
-  if (count == 0)
-    return FALSE;
-
-  if (count < 0)
-    return gtk_text_iter_backward_sentence_starts (iter, -count);
-
-  if (!gtk_text_iter_forward_sentence_end (iter))
-    return FALSE;
-  --count;
-
-  while (count > 0)
-    {
-      if (!gtk_text_iter_forward_sentence_end (iter))
-        break;
-      --count;
-    }
-  return TRUE;
+  return move_multiple_steps (iter, count, 
+                             gtk_text_iter_forward_sentence_end,
+                             gtk_text_iter_backward_sentence_starts);
 }
 
 /**
@@ -3257,22 +3536,9 @@ gboolean
 gtk_text_iter_backward_sentence_starts (GtkTextIter      *iter,
                                         gint               count)
 {
-  g_return_val_if_fail (iter != NULL, FALSE);
-
-  if (count < 0)
-    return gtk_text_iter_forward_sentence_ends (iter, -count);
-
-  if (!gtk_text_iter_backward_sentence_start (iter))
-    return FALSE;
-  --count;
-
-  while (count > 0)
-    {
-      if (!gtk_text_iter_backward_sentence_start (iter))
-        break;
-      --count;
-    }
-  return TRUE;
+  return move_multiple_steps (iter, count, 
+                             gtk_text_iter_backward_sentence_start,
+                             gtk_text_iter_forward_sentence_ends);
 }
 
 static gboolean
@@ -3353,7 +3619,7 @@ gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
  * 
  * Like gtk_text_iter_forward_cursor_position(), but moves backward.
  * 
- * Return value: %TRUE if we moved and the new position is dereferenceable
+ * Return value: %TRUE if we moved
  **/
 gboolean
 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
@@ -3375,27 +3641,9 @@ gboolean
 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
                                         gint         count)
 {
-  g_return_val_if_fail (iter != NULL, FALSE);
-
-  FIX_OVERFLOWS (count);
-  
-  if (count == 0)
-    return FALSE;
-  
-  if (count < 0)
-    return gtk_text_iter_backward_cursor_positions (iter, -count);
-  
-  if (!gtk_text_iter_forward_cursor_position (iter))
-    return FALSE;
-  --count;
-
-  while (count > 0)
-    {
-      if (!gtk_text_iter_forward_cursor_position (iter))
-        break;
-      --count;
-    }
-  return TRUE;
+  return move_multiple_steps (iter, count, 
+                             gtk_text_iter_forward_cursor_position,
+                             gtk_text_iter_backward_cursor_positions);
 }
 
 /**
@@ -3412,27 +3660,85 @@ gboolean
 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
                                          gint         count)
 {
-  g_return_val_if_fail (iter != NULL, FALSE);
+  return move_multiple_steps (iter, count, 
+                             gtk_text_iter_backward_cursor_position,
+                             gtk_text_iter_forward_cursor_positions);
+}
 
-  FIX_OVERFLOWS (count);
-  
-  if (count == 0)
-    return FALSE;
+/**
+ * gtk_text_iter_forward_visible_cursor_position:
+ * @iter: a #GtkTextIter
+ * 
+ * Moves @iter forward to the next visible cursor position. See 
+ * gtk_text_iter_forward_cursor_position() for details.
+ * 
+ * Return value: %TRUE if we moved and the new position is dereferenceable
+ * 
+ * Since: 2.4
+ **/
+gboolean
+gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
+{
+  return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
+}
 
-  if (count < 0)
-    return gtk_text_iter_forward_cursor_positions (iter, -count);
-  
-  if (!gtk_text_iter_backward_cursor_position (iter))
-    return FALSE;
-  --count;
+/**
+ * gtk_text_iter_backward_visible_cursor_position:
+ * @iter: a #GtkTextIter
+ * 
+ * Moves @iter forward to the previous visible cursor position. See 
+ * gtk_text_iter_backward_cursor_position() for details.
+ * 
+ * Return value: %TRUE if we moved and the new position is dereferenceable
+ * 
+ * Since: 2.4
+ **/
+gboolean
+gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
+{
+  return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
+}
 
-  while (count > 0)
-    {
-      if (!gtk_text_iter_backward_cursor_position (iter))
-        break;
-      --count;
-    }
-  return TRUE;
+/**
+ * gtk_text_iter_forward_visible_cursor_positions:
+ * @iter: a #GtkTextIter
+ * @count: number of positions to move
+ * 
+ * Moves up to @count visible cursor positions. See
+ * gtk_text_iter_forward_cursor_position() for details.
+ * 
+ * Return value: %TRUE if we moved and the new position is dereferenceable
+ * 
+ * Since: 2.4
+ **/
+gboolean
+gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
+                                               gint         count)
+{
+  return move_multiple_steps (iter, count, 
+                             gtk_text_iter_forward_visible_cursor_position,
+                             gtk_text_iter_backward_visible_cursor_positions);
+}
+
+/**
+ * gtk_text_iter_backward_visible_cursor_positions:
+ * @iter: a #GtkTextIter
+ * @count: number of positions to move
+ *
+ * Moves up to @count visible cursor positions. See
+ * gtk_text_iter_backward_cursor_position() for details.
+ * 
+ * Return value: %TRUE if we moved and the new position is dereferenceable
+ * 
+ * Since: 2.4
+ **/
+gboolean
+gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
+                                                gint         count)
+{
+  return move_multiple_steps (iter, count, 
+                             gtk_text_iter_backward_visible_cursor_position,
+                             gtk_text_iter_forward_visible_cursor_positions);
 }
 
 /**
@@ -3487,7 +3793,7 @@ gtk_text_iter_set_line_offset (GtkTextIter *iter,
     iter_set_from_char_offset (real, real->line, char_on_line);
   else
     gtk_text_iter_forward_line (iter); /* set to start of next line */
-
+  
   check_invariants (iter);
 }
 
@@ -3556,6 +3862,8 @@ gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
 
   g_return_if_fail (iter != NULL);
   
+  gtk_text_iter_set_line_offset (iter, 0);
+
   pos = *iter;
 
   /* For now we use a ludicrously slow implementation */
@@ -3577,12 +3885,6 @@ gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
     gtk_text_iter_forward_line (iter);
 }
 
-static gint
-bytes_in_char (GtkTextIter *iter)
-{
-  return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
-}
-
 /**
  * gtk_text_iter_set_visible_line_index:
  * @iter: a #GtkTextIter
@@ -3593,36 +3895,51 @@ bytes_in_char (GtkTextIter *iter)
  * in the index.
  **/
 void
-gtk_text_iter_set_visible_line_index  (GtkTextIter *iter,
-                                       gint         byte_on_line)
+gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
+                                      gint         byte_on_line)
 {
-  gint bytes_seen = 0;
+  GtkTextRealIter *real;
+  gint offset = 0;
   GtkTextIter pos;
-
-  g_return_if_fail (iter != NULL);
+  GtkTextLineSegment *seg;
   
+  g_return_if_fail (iter != NULL);
+
+  gtk_text_iter_set_line_offset (iter, 0);
+
   pos = *iter;
 
-  /* For now we use a ludicrously slow implementation */
-  while (bytes_seen < byte_on_line)
+  real = gtk_text_iter_make_real (&pos);
+
+  if (real == NULL)
+    return;
+
+  ensure_byte_offsets (real);
+
+  check_invariants (&pos);
+
+  seg = _gtk_text_iter_get_indexable_segment (&pos);
+
+  while (seg != NULL && byte_on_line > 0)
     {
       if (!_gtk_text_btree_char_is_invisible (&pos))
-        bytes_seen += bytes_in_char (&pos);
-
-      if (!gtk_text_iter_forward_char (&pos))
-        break;
+        {
+          if (byte_on_line < seg->byte_count)
+            {
+              iter_set_from_byte_offset (real, real->line, offset + byte_on_line);
+              byte_on_line = 0;
+              break;
+            }
+          else
+            byte_on_line -= seg->byte_count;
+        }
 
-      if (bytes_seen >= byte_on_line)
-        break;
+      offset += seg->byte_count;
+      _gtk_text_iter_forward_indexable_segment (&pos);
+      seg = _gtk_text_iter_get_indexable_segment (&pos);
     }
 
-  if (bytes_seen > byte_on_line)
-    g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
-               "character; this will crash the text buffer. "
-               "Byte indexes must refer to the start of a character.",
-               G_STRLOC, byte_on_line);
-  
-  if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
+  if (byte_on_line == 0)
     *iter = pos;
   else
     gtk_text_iter_forward_line (iter);
@@ -3672,7 +3989,6 @@ gtk_text_iter_set_line (GtkTextIter *iter,
  *
  * Sets @iter to point to @char_offset. @char_offset counts from the start
  * of the entire text buffer, starting with 0.
- * 
  **/
 void
 gtk_text_iter_set_offset (GtkTextIter *iter,
@@ -3716,7 +4032,6 @@ gtk_text_iter_set_offset (GtkTextIter *iter,
  * Moves @iter forward to the "end iterator," which points one past the last
  * valid character in the buffer. gtk_text_iter_get_char() called on the
  * end iterator returns 0, which is convenient for writing loops.
- * 
  **/
 void
 gtk_text_iter_forward_to_end  (GtkTextIter *iter)
@@ -3736,6 +4051,36 @@ gtk_text_iter_forward_to_end  (GtkTextIter *iter)
   gtk_text_buffer_get_end_iter (buffer, iter);
 }
 
+/* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
+ * and made faster. Look at iter_ends_line() for inspiration, perhaps.
+ * If all else fails we could cache the para delimiter pos in the iter.
+ * I think forward_to_line_end() actually gets called fairly often.
+ */
+static int
+find_paragraph_delimiter_for_line (GtkTextIter *iter)
+{
+  GtkTextIter end;
+  end = *iter;
+
+  if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
+                                        _gtk_text_iter_get_btree (&end)))
+    {
+      gtk_text_iter_forward_to_end (&end);
+    }
+  else
+    {
+      /* if we aren't on the last line, go forward to start of next line, then scan
+       * back for the delimiters on the previous line
+       */
+      gtk_text_iter_forward_line (&end);
+      gtk_text_iter_backward_char (&end);
+      while (!gtk_text_iter_ends_line (&end))
+        gtk_text_iter_backward_char (&end);
+    }
+
+  return gtk_text_iter_get_line_offset (&end);
+}
+
 /**
  * gtk_text_iter_forward_to_line_end:
  * @iter: a #GtkTextIter
@@ -3745,7 +4090,9 @@ gtk_text_iter_forward_to_end  (GtkTextIter *iter)
  * return/newline in sequence, or the Unicode paragraph separator
  * character. If the iterator is already at the paragraph delimiter
  * characters, moves to the paragraph delimiter characters for the
- * next line.
+ * next line. If @iter is on the last line in the buffer, which does
+ * not end in paragraph delimiters, moves to the end iterator (end of
+ * the last line), and returns %FALSE.
  * 
  * Return value: %TRUE if we moved and the new location is not the end iterator
  **/
@@ -3755,17 +4102,17 @@ gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
   gint current_offset;
   gint new_offset;
 
+  
   g_return_val_if_fail (iter != NULL, FALSE);
 
   current_offset = gtk_text_iter_get_line_offset (iter);
-  /* FIXME assumption that line ends in a newline; broken */
-  new_offset = gtk_text_iter_get_chars_in_line (iter) - 1;
-
+  new_offset = find_paragraph_delimiter_for_line (iter);
+  
   if (current_offset < new_offset)
     {
       /* Move to end of this line. */
       gtk_text_iter_set_line_offset (iter, new_offset);
-      return TRUE;
+      return !gtk_text_iter_is_end (iter);
     }
   else
     {
@@ -3777,7 +4124,7 @@ gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
            */
           if (!gtk_text_iter_ends_line (iter))
             gtk_text_iter_forward_to_line_end (iter);
-          return TRUE;
+          return !gtk_text_iter_is_end (iter);
         }
       else
         return FALSE;
@@ -3787,12 +4134,12 @@ gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
 /**
  * gtk_text_iter_forward_to_tag_toggle:
  * @iter: a #GtkTextIter
- * @tag: a #GtkTextTag, or NULL
+ * @tag: (allow-none): a #GtkTextTag, or %NULL
  *
  * Moves forward to the next toggle (on or off) of the
  * #GtkTextTag @tag, or to the next toggle of any tag if
- * @tag is NULL. If no matching tag toggles are found,
- * returns FALSE, otherwise TRUE. Does not return toggles
+ * @tag is %NULL. If no matching tag toggles are found,
+ * returns %FALSE, otherwise %TRUE. Does not return toggles
  * located at @iter, only toggles after @iter. Sets @iter to
  * the location of the toggle, or to the end of the buffer
  * if no toggle is found.
@@ -3869,12 +4216,12 @@ gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
 /**
  * gtk_text_iter_backward_to_tag_toggle:
  * @iter: a #GtkTextIter
- * @tag: a #GtkTextTag, or NULL
+ * @tag: (allow-none): a #GtkTextTag, or %NULL
  *
  * Moves backward to the next toggle (on or off) of the
  * #GtkTextTag @tag, or to the next toggle of any tag if
- * @tag is NULL. If no matching tag toggles are found,
- * returns FALSE, otherwise TRUE. Does not return toggles
+ * @tag is %NULL. If no matching tag toggles are found,
+ * returns %FALSE, otherwise %TRUE. Does not return toggles
  * located at @iter, only toggles before @iter. Sets @iter
  * to the location of the toggle, or the start of the buffer
  * if no toggle is found.
@@ -3982,9 +4329,9 @@ matches_pred (GtkTextIter *iter,
 /**
  * gtk_text_iter_forward_find_char:
  * @iter: a #GtkTextIter
- * @pred: a function to be called on each character
+ * @pred: (scope call): a function to be called on each character
  * @user_data: user data for @pred
- * @limit: search limit, or %NULL for none 
+ * @limit: (allow-none): search limit, or %NULL for none 
  * 
  * Advances @iter, calling @pred on each character. If
  * @pred returns %TRUE, returns %TRUE and stops scanning.
@@ -4020,9 +4367,9 @@ gtk_text_iter_forward_find_char (GtkTextIter         *iter,
 /**
  * gtk_text_iter_backward_find_char:
  * @iter: a #GtkTextIter
- * @pred: function to be called on each character
+ * @pred: (scope call): function to be called on each character
  * @user_data: user data for @pred
- * @limit: search limit, or %NULL for none
+ * @limit: (allow-none): search limit, or %NULL for none
  * 
  * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
  * 
@@ -4056,7 +4403,8 @@ static void
 forward_chars_with_skipping (GtkTextIter *iter,
                              gint         count,
                              gboolean     skip_invisible,
-                             gboolean     skip_nontext)
+                             gboolean     skip_nontext,
+                             gboolean     skip_decomp)
 {
 
   gint i;
@@ -4069,6 +4417,10 @@ forward_chars_with_skipping (GtkTextIter *iter,
     {
       gboolean ignored = FALSE;
 
+      /* minimal workaround to avoid the infinite loop of bug #168247. */
+       if (gtk_text_iter_is_end (iter))
+         return;
+
       if (skip_nontext &&
           gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
         ignored = TRUE;
@@ -4078,6 +4430,25 @@ forward_chars_with_skipping (GtkTextIter *iter,
           _gtk_text_btree_char_is_invisible (iter))
         ignored = TRUE;
 
+      if (!ignored && skip_decomp)
+        {
+          /* being UTF8 correct sucks: this accounts for extra
+             offsets coming from canonical decompositions of
+             UTF8 characters (e.g. accented characters) which
+             g_utf8_normalize() performs */
+          gchar *normal;
+          gchar *casefold;
+          gchar buffer[6];
+          gint buffer_len;
+
+          buffer_len = g_unichar_to_utf8 (gtk_text_iter_get_char (iter), buffer);
+          casefold = g_utf8_casefold (buffer, buffer_len);
+          normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
+          i -= (g_utf8_strlen (normal, -1) - 1);
+          g_free (normal);
+          g_free (casefold);
+        }
+
       gtk_text_iter_forward_char (iter);
 
       if (!ignored)
@@ -4085,11 +4456,209 @@ forward_chars_with_skipping (GtkTextIter *iter,
     }
 }
 
+static const gchar *
+pointer_from_offset_skipping_decomp (const gchar *str,
+                                     gint         offset)
+{
+  gchar *casefold, *normal;
+  const gchar *p, *q;
+
+  p = str;
+
+  while (offset > 0)
+    {
+      q = g_utf8_next_char (p);
+      casefold = g_utf8_casefold (p, q - p);
+      normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
+      offset -= g_utf8_strlen (normal, -1);
+      g_free (casefold);
+      g_free (normal);
+      p = q;
+    }
+
+  return p;
+}
+
+static gboolean
+exact_prefix_cmp (const gchar *string,
+                  const gchar *prefix,
+                  guint        prefix_len)
+{
+  GUnicodeType type;
+
+  if (strncmp (string, prefix, prefix_len) != 0)
+    return FALSE;
+  if (string[prefix_len] == '\0')
+    return TRUE;
+
+  type = g_unichar_type (g_utf8_get_char (string + prefix_len));
+
+  /* If string contains prefix, check that prefix is not followed
+   * by a unicode mark symbol, e.g. that trailing 'a' in prefix
+   * is not part of two-char a-with-hat symbol in string. */
+  return type != G_UNICODE_SPACING_MARK &&
+         type != G_UNICODE_ENCLOSING_MARK &&
+         type != G_UNICODE_NON_SPACING_MARK;
+}
+
+static const gchar *
+utf8_strcasestr (const gchar *haystack,
+                 const gchar *needle)
+{
+  gsize needle_len;
+  gsize haystack_len;
+  const gchar *ret = NULL;
+  gchar *p;
+  gchar *casefold;
+  gchar *caseless_haystack;
+  gint i;
+
+  g_return_val_if_fail (haystack != NULL, NULL);
+  g_return_val_if_fail (needle != NULL, NULL);
+
+  casefold = g_utf8_casefold (haystack, -1);
+  caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
+  g_free (casefold);
+
+  needle_len = g_utf8_strlen (needle, -1);
+  haystack_len = g_utf8_strlen (caseless_haystack, -1);
+
+  if (needle_len == 0)
+    {
+      ret = (gchar *)haystack;
+      goto finally;
+    }
+
+  if (haystack_len < needle_len)
+    {
+      ret = NULL;
+      goto finally;
+    }
+
+  p = (gchar *)caseless_haystack;
+  needle_len = strlen (needle);
+  i = 0;
+
+  while (*p)
+    {
+      if (exact_prefix_cmp (p, needle, needle_len))
+        {
+          ret = pointer_from_offset_skipping_decomp (haystack, i);
+          goto finally;
+        }
+
+      p = g_utf8_next_char (p);
+      i++;
+    }
+
+finally:
+  g_free (caseless_haystack);
+
+  return ret;
+}
+
+static const gchar *
+utf8_strrcasestr (const gchar *haystack,
+                  const gchar *needle)
+{
+  gsize needle_len;
+  gsize haystack_len;
+  const gchar *ret = NULL;
+  gchar *p;
+  gchar *casefold;
+  gchar *caseless_haystack;
+  gint i;
+
+  g_return_val_if_fail (haystack != NULL, NULL);
+  g_return_val_if_fail (needle != NULL, NULL);
+
+  casefold = g_utf8_casefold (haystack, -1);
+  caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
+  g_free (casefold);
+
+  needle_len = g_utf8_strlen (needle, -1);
+  haystack_len = g_utf8_strlen (caseless_haystack, -1);
+
+  if (needle_len == 0)
+    {
+      ret = (gchar *)haystack;
+      goto finally;
+    }
+
+  if (haystack_len < needle_len)
+    {
+      ret = NULL;
+      goto finally;
+    }
+
+  i = haystack_len - needle_len;
+  p = g_utf8_offset_to_pointer (caseless_haystack, i);
+  needle_len = strlen (needle);
+
+  while (p >= caseless_haystack)
+    {
+      if (exact_prefix_cmp (p, needle, needle_len))
+        {
+          ret = pointer_from_offset_skipping_decomp (haystack, i);
+          goto finally;
+        }
+
+      p = g_utf8_prev_char (p);
+      i--;
+    }
+
+finally:
+  g_free (caseless_haystack);
+
+  return ret;
+}
+
+/* normalizes caseless strings and returns true if @s2 matches
+   the start of @s1 */
+static gboolean
+utf8_caselessnmatch (const gchar *s1,
+                     const gchar *s2,
+                     gssize       n1,
+                     gssize       n2)
+{
+  gchar *casefold;
+  gchar *normalized_s1;
+  gchar *normalized_s2;
+  gint len_s1;
+  gint len_s2;
+  gboolean ret = FALSE;
+
+  g_return_val_if_fail (s1 != NULL, FALSE);
+  g_return_val_if_fail (s2 != NULL, FALSE);
+  g_return_val_if_fail (n1 > 0, FALSE);
+  g_return_val_if_fail (n2 > 0, FALSE);
+
+  casefold = g_utf8_casefold (s1, n1);
+  normalized_s1 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
+  g_free (casefold);
+
+  casefold = g_utf8_casefold (s2, n2);
+  normalized_s2 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
+  g_free (casefold);
+
+  len_s1 = strlen (normalized_s1);
+  len_s2 = strlen (normalized_s2);
+
+  if (len_s1 >= len_s2)
+    ret = (strncmp (normalized_s1, normalized_s2, len_s2) == 0);
+
+  g_free (normalized_s1);
+  g_free (normalized_s2);
+
+  return ret;
+}
+
 static gboolean
 lines_match (const GtkTextIter *start,
              const gchar **lines,
              gboolean visible_only,
              gboolean slice,
+             gboolean case_insensitive,
              GtkTextIter *match_start,
              GtkTextIter *match_end)
 {
@@ -4133,14 +4702,25 @@ lines_match (const GtkTextIter *start,
     }
 
   if (match_start) /* if this is the first line we're matching */
-    found = strstr (line_text, *lines);
+    {
+      if (!case_insensitive)
+        found = strstr (line_text, *lines);
+      else
+        found = utf8_strcasestr (line_text, *lines);
+    }
   else
     {
       /* If it's not the first line, we have to match from the
        * start of the line.
        */
-      if (strncmp (line_text, *lines, strlen (*lines)) == 0)
-        found = line_text;
+      if ((!case_insensitive &&
+           (strncmp (line_text, *lines, strlen (*lines)) == 0)) ||
+          (case_insensitive &&
+           utf8_caselessnmatch (line_text, *lines, strlen (line_text),
+                                strlen (*lines))))
+        {
+          found = line_text;
+        }
       else
         found = NULL;
     }
@@ -4159,19 +4739,14 @@ lines_match (const GtkTextIter *start,
   /* If match start needs to be returned, set it to the
    * start of the search string.
    */
+  forward_chars_with_skipping (&next, offset,
+                               visible_only, !slice, FALSE);
   if (match_start)
-    {
-      *match_start = next;
-
-      forward_chars_with_skipping (match_start, offset,
-                                   visible_only, !slice);
-    }
+    *match_start = next;
 
   /* Go to end of search string */
-  offset += g_utf8_strlen (*lines, -1);
-
-  forward_chars_with_skipping (&next, offset,
-                               visible_only, !slice);
+  forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1),
+                               visible_only, !slice, TRUE);
 
   g_free (line_text);
 
@@ -4183,17 +4758,20 @@ lines_match (const GtkTextIter *start,
   /* pass NULL for match_start, since we don't need to find the
    * start again.
    */
-  return lines_match (&next, lines, visible_only, slice, NULL, match_end);
+  return lines_match (&next, lines, visible_only, slice, case_insensitive, NULL, match_end);
 }
 
 /* strsplit () that retains the delimiter as part of the string. */
 static gchar **
 strbreakup (const char *string,
             const char *delimiter,
-            gint        max_tokens)
+            gint        max_tokens,
+            gint       *num_strings,
+            gboolean    case_insensitive)
 {
   GSList *string_list = NULL, *slist;
   gchar **str_array, *s;
+  gchar *casefold, *new_string;
   guint i, n = 1;
 
   g_return_val_if_fail (string != NULL, NULL);
@@ -4210,12 +4788,20 @@ strbreakup (const char *string,
       do
         {
           guint len;
-          gchar *new_string;
 
           len = s - string + delimiter_len;
           new_string = g_new (gchar, len + 1);
           strncpy (new_string, string, len);
           new_string[len] = 0;
+
+          if (case_insensitive)
+            {
+              casefold = g_utf8_casefold (new_string, -1);
+              g_free (new_string);
+              new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
+              g_free (casefold);
+            }
+
           string_list = g_slist_prepend (string_list, new_string);
           n++;
           string = s + delimiter_len;
@@ -4226,7 +4812,17 @@ strbreakup (const char *string,
   if (*string)
     {
       n++;
-      string_list = g_slist_prepend (string_list, g_strdup (string));
+
+      if (case_insensitive)
+        {
+          casefold = g_utf8_casefold (string, -1);
+          new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
+          g_free (casefold);
+        }
+      else
+        new_string = g_strdup (string);
+
+      string_list = g_slist_prepend (string_list, new_string);
     }
 
   str_array = g_new (gchar*, n);
@@ -4239,6 +4835,9 @@ strbreakup (const char *string,
 
   g_slist_free (string_list);
 
+  if (num_strings != NULL)
+    *num_strings = n - 1;
+
   return str_array;
 }
 
@@ -4247,12 +4846,13 @@ strbreakup (const char *string,
  * @iter: start of search
  * @str: a search string
  * @flags: flags affecting how the search is done
- * @match_start: return location for start of match, or %NULL
- * @match_end: return location for end of match, or %NULL
- * @limit: bound for the search, or %NULL for the end of the buffer
- * 
- * Searches forward for @str. Any match is returned as the range
- * @match_start, @match_end. The search will not continue past
+ * @match_start: (out caller-allocates) (allow-none): return location for start of match, or %NULL
+ * @match_end: (out caller-allocates) (allow-none): return location for end of match, or %NULL
+ * @limit: (allow-none): bound for the search, or %NULL for the end of the buffer
+ *
+ * Searches forward for @str. Any match is returned by setting
+ * @match_start to the first character of the match and @match_end to the
+ * first character after the match. The search will not continue past
  * @limit. Note that a search is a linear or O(n) operation, so you
  * may wish to use @limit to avoid locking up your UI on large
  * buffers.
@@ -4264,6 +4864,8 @@ strbreakup (const char *string,
  * pixbufs or child widgets mixed inside the matched range. If these
  * flags are not given, the match must be exact; the special 0xFFFC
  * character in @str will match embedded pixbufs or child widgets.
+ * If you specify the #GTK_TEXT_SEARCH_CASE_INSENSITIVE flag, the text will
+ * be matched regardless of what case it is in.
  *
  * Return value: whether a match was found
  **/
@@ -4281,7 +4883,8 @@ gtk_text_iter_forward_search (const GtkTextIter *iter,
   GtkTextIter search;
   gboolean visible_only;
   gboolean slice;
-  
+  gboolean case_insensitive;
+
   g_return_val_if_fail (iter != NULL, FALSE);
   g_return_val_if_fail (str != NULL, FALSE);
 
@@ -4312,10 +4915,11 @@ gtk_text_iter_forward_search (const GtkTextIter *iter,
 
   visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
   slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
-  
+  case_insensitive = (flags & GTK_TEXT_SEARCH_CASE_INSENSITIVE) != 0;
+
   /* locate all lines */
 
-  lines = strbreakup (str, "\n", -1);
+  lines = strbreakup (str, "\n", -1, NULL, case_insensitive);
 
   search = *iter;
 
@@ -4332,11 +4936,11 @@ gtk_text_iter_forward_search (const GtkTextIter *iter,
         break;
       
       if (lines_match (&search, (const gchar**)lines,
-                       visible_only, slice, &match, &end))
+                       visible_only, slice, case_insensitive, &match, &end))
         {
           if (limit == NULL ||
               (limit &&
-               gtk_text_iter_compare (&end, limit) < 0))
+               gtk_text_iter_compare (&end, limit) <= 0))
             {
               retval = TRUE;
               
@@ -4358,8 +4962,9 @@ gtk_text_iter_forward_search (const GtkTextIter *iter,
 }
 
 static gboolean
-vectors_equal_ignoring_trailing (gchar **vec1,
-                                 gchar **vec2)
+vectors_equal_ignoring_trailing (gchar    **vec1,
+                                 gchar    **vec2,
+                                 gboolean   case_insensitive)
 {
   /* Ignores trailing chars in vec2's last line */
 
@@ -4370,37 +4975,67 @@ vectors_equal_ignoring_trailing (gchar **vec1,
 
   while (*i1 && *i2)
     {
-      if (strcmp (*i1, *i2) != 0)
+      gint len1;
+      gint len2;
+
+      if (!case_insensitive)
         {
-          if (*(i2 + 1) == NULL) /* if this is the last line */
+          if (strcmp (*i1, *i2) != 0)
             {
-              gint len1 = strlen (*i1);
-              gint len2 = strlen (*i2);
-
-              if (len2 >= len1 &&
-                  strncmp (*i1, *i2, len1) == 0)
+              if (*(i2 + 1) == NULL) /* if this is the last line */
                 {
-                  /* We matched ignoring the trailing stuff in vec2 */
-                  return TRUE;
+                  len1 = strlen (*i1);
+                  len2 = strlen (*i2);
+
+                  if (len2 >= len1 &&
+                      strncmp (*i1, *i2, len1) == 0)
+                    {
+                      /* We matched ignoring the trailing stuff in vec2 */
+                      return TRUE;
+                    }
+                  else
+                    {
+                      return FALSE;
+                    }
                 }
               else
                 {
                   return FALSE;
                 }
             }
-          else
+        }
+      else
+        {
+          len1 = strlen (*i1);
+          len2 = strlen (*i2);
+
+          if (!utf8_caselessnmatch (*i1, *i2, len1, len2))
             {
-              return FALSE;
+              if (*(i2 + 1) == NULL) /* if this is the last line */
+                {
+                  if (utf8_caselessnmatch (*i2, *i1, len2, len1))
+                    {
+                      /* We matched ignoring the trailing stuff in vec2 */
+                      return TRUE;
+                    }
+                  else
+                    {
+                      return FALSE;
+                    }
+                }
+              else
+                {
+                  return FALSE;
+                }
             }
         }
+
       ++i1;
       ++i2;
     }
 
   if (*i1 || *i2)
-    {
-      return FALSE;
-    }
+    return FALSE;
   else
     return TRUE;
 }
@@ -4411,10 +5046,12 @@ struct _LinesWindow
 {
   gint n_lines;
   gchar **lines;
+
   GtkTextIter first_line_start;
   GtkTextIter first_line_end;
-  gboolean slice;
-  gboolean visible_only;
+
+  guint slice : 1;
+  guint visible_only : 1;
 };
 
 static void
@@ -4475,6 +5112,8 @@ lines_window_init (LinesWindow       *win,
         }
 
       win->lines[i] = line_text;
+      win->first_line_start = line_start;
+      win->first_line_end = line_end;
 
       line_end = line_start;
       gtk_text_iter_backward_line (&line_start);
@@ -4538,54 +5177,17 @@ lines_window_free (LinesWindow *win)
   g_strfreev (win->lines);
 }
 
-static gchar*
-my_strrstr (const gchar *haystack,
-            const gchar *needle)
-{
-  /* FIXME GLib should have a nice implementation in it, this
-   * is slow-ass crap.
-   */
-
-  gint haystack_len = strlen (haystack);
-  gint needle_len = strlen (needle);
-  const gchar *needle_end = needle + needle_len;
-  const gchar *haystack_rend = haystack - 1;
-  const gchar *needle_rend = needle - 1;
-  const gchar *p;
-
-  p = haystack + haystack_len;
-  while (p != haystack)
-    {
-      const gchar *n = needle_end - 1;
-      const gchar *s = p - 1;
-      while (s != haystack_rend &&
-             n != needle_rend &&
-             *s == *n)
-        {
-          --n;
-          --s;
-        }
-
-      if (n == needle_rend)
-        return (gchar*)++s;
-
-      --p;
-    }
-
-  return NULL;
-}
-
 /**
  * gtk_text_iter_backward_search:
  * @iter: a #GtkTextIter where the search begins
  * @str: search string
  * @flags: bitmask of flags affecting the search
- * @match_start: return location for start of match, or %NULL
- * @match_end: return location for end of match, or %NULL
- * @limit: location of last possible @match_start, or %NULL for start of buffer
- * 
+ * @match_start: (out caller-allocates) (allow-none): return location for start of match, or %NULL
+ * @match_end: (out caller-allocates) (allow-none): return location for end of match, or %NULL
+ * @limit: (allow-none): location of last possible @match_start, or %NULL for start of buffer
+ *
  * Same as gtk_text_iter_forward_search(), but moves backward.
- * 
+ *
  * Return value: whether a match was found
  **/
 gboolean
@@ -4603,6 +5205,7 @@ gtk_text_iter_backward_search (const GtkTextIter *iter,
   gboolean retval = FALSE;
   gboolean visible_only;
   gboolean slice;
+  gboolean case_insensitive;
   
   g_return_val_if_fail (iter != NULL, FALSE);
   g_return_val_if_fail (str != NULL, FALSE);
@@ -4633,18 +5236,11 @@ gtk_text_iter_backward_search (const GtkTextIter *iter,
 
   visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
   slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
-  
-  /* locate all lines */
+  case_insensitive = (flags & GTK_TEXT_SEARCH_CASE_INSENSITIVE) != 0;
 
-  lines = strbreakup (str, "\n", -1);
+  /* locate all lines */
 
-  l = lines;
-  n_lines = 0;
-  while (*l)
-    {
-      ++n_lines;
-      ++l;
-    }
+  lines = strbreakup (str, "\n", -1, &n_lines, case_insensitive);
 
   win.n_lines = n_lines;
   win.slice = slice;
@@ -4657,7 +5253,7 @@ gtk_text_iter_backward_search (const GtkTextIter *iter,
 
   do
     {
-      gchar *first_line_match;
+      const gchar *first_line_match;
 
       if (limit &&
           gtk_text_iter_compare (limit, &win.first_line_end) > 0)
@@ -4670,10 +5266,14 @@ gtk_text_iter_backward_search (const GtkTextIter *iter,
        * end in '\n', so this will only match at the
        * end of the first line, which is correct.
        */
-      first_line_match = my_strrstr (*win.lines, *lines);
+      if (!case_insensitive)
+        first_line_match = g_strrstr (*win.lines, *lines);
+      else
+        first_line_match = utf8_strrcasestr (*win.lines, *lines);
 
       if (first_line_match &&
-          vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
+          vectors_equal_ignoring_trailing (lines + 1, win.lines + 1,
+                                           case_insensitive))
         {
           /* Match! */
           gint offset;
@@ -4686,7 +5286,7 @@ gtk_text_iter_backward_search (const GtkTextIter *iter,
           next = win.first_line_start;
           start_tmp = next;
           forward_chars_with_skipping (&start_tmp, offset,
-                                       visible_only, !slice);
+                                       visible_only, !slice, FALSE);
 
           if (limit &&
               gtk_text_iter_compare (limit, &start_tmp) > 0)
@@ -4704,7 +5304,7 @@ gtk_text_iter_backward_search (const GtkTextIter *iter,
             }
 
           forward_chars_with_skipping (&next, offset,
-                                       visible_only, !slice);
+                                       visible_only, !slice, TRUE);
 
           if (match_end)
             *match_end = next;
@@ -5003,7 +5603,10 @@ _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree   *tree,
   else
     {
       iter_init_from_byte_offset (iter, tree, line, 0);
-      gtk_text_iter_forward_to_tag_toggle (iter, tag);
+
+      if (!gtk_text_iter_toggles_tag (iter, tag))
+        gtk_text_iter_forward_to_tag_toggle (iter, tag);
+
       check_invariants (iter);
       return TRUE;
     }
@@ -5075,8 +5678,10 @@ _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree       *tree,
   g_return_if_fail (iter != NULL);
   g_return_if_fail (tree != NULL);
   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
+  
+  seg = anchor->segment;  
 
-  seg = anchor->segment;
+  g_assert (seg->body.child.line != NULL);
   
   iter_init_from_segment (iter, tree,
                           seg->body.child.line, seg);
@@ -5279,4 +5884,3 @@ _gtk_text_iter_check (const GtkTextIter *iter)
   if (_gtk_text_line_is_last (real->line, real->tree))
     g_error ("Iterator was on last line (past the end iterator)");
 }
-