+/**
+ * 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);
+}
+
+/**
+ * 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);
+}
+
+/**
+ * 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);
+}
+
+/**
+ * gtk_text_iter_starts_word:
+ * @iter: a #GtkTextIter
+ *
+ * Determines whether @iter begins a natural-language word. 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 is at the start of a word
+ **/
+gboolean
+gtk_text_iter_starts_word (const GtkTextIter *iter)
+{
+ return test_log_attrs (iter, is_word_start_func);
+}
+
+/**
+ * gtk_text_iter_ends_word:
+ * @iter: a #GtkTextIter
+ *
+ * Determines whether @iter ends a natural-language word. 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 is at the end of a word
+ **/
+gboolean
+gtk_text_iter_ends_word (const GtkTextIter *iter)
+{
+ return test_log_attrs (iter, is_word_end_func);
+}
+
+/**
+ * gtk_text_iter_inside_word:
+ * @iter: a #GtkTextIter
+ *
+ * Determines whether @iter is inside a natural-language word (as
+ * opposed to say inside some whitespace). 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 is inside a word
+ **/
+gboolean
+gtk_text_iter_inside_word (const GtkTextIter *iter)
+{
+ return test_log_attrs (iter, inside_word_func);
+}
+
+/**
+ * gtk_text_iter_starts_sentence:
+ * @iter: a #GtkTextIter
+ *
+ * Determines whether @iter begins a sentence. 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 boundary
+ * algorithms).
+ *
+ * Return value: %TRUE if @iter is at the start of a sentence.
+ **/
+gboolean
+gtk_text_iter_starts_sentence (const GtkTextIter *iter)
+{
+ return test_log_attrs (iter, is_sentence_start_func);
+}
+
+/**
+ * gtk_text_iter_ends_sentence:
+ * @iter: a #GtkTextIter
+ *
+ * Determines whether @iter ends a sentence. 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 boundary
+ * algorithms).
+ *
+ * Return value: %TRUE if @iter is at the end of a sentence.
+ **/
+gboolean
+gtk_text_iter_ends_sentence (const GtkTextIter *iter)
+{
+ return test_log_attrs (iter, is_sentence_end_func);
+}
+
+/**
+ * gtk_text_iter_inside_sentence:
+ * @iter: a #GtkTextIter
+ *
+ * Determines whether @iter is inside a sentence (as opposed to in
+ * between two sentences, e.g. after a period and before the first
+ * letter of the next sentence). 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 boundary algorithms).
+ *
+ * Return value: %TRUE if @iter is inside a sentence.
+ **/
+gboolean
+gtk_text_iter_inside_sentence (const GtkTextIter *iter)
+{
+ return test_log_attrs (iter, inside_sentence_func);
+}
+
+/**
+ * gtk_text_iter_forward_sentence_end:
+ * @iter: a #GtkTextIter
+ *
+ * Moves forward to the next sentence end. (If @iter is at the end of
+ * a sentence, moves to the next end of sentence.) 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
+ * boundary algorithms).
+ *
+ * Return value: %TRUE if @iter moved and is not the end iterator
+ **/
+gboolean
+gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
+{
+ return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
+}
+
+/**
+ * gtk_text_iter_backward_sentence_start:
+ * @iter: a #GtkTextIter
+ *
+ * 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
+ * boundary algorithms).
+ *
+ * Return value: %TRUE if @iter moved and is not the end iterator
+ **/
+gboolean
+gtk_text_iter_backward_sentence_start (GtkTextIter *iter)
+{
+ return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
+}
+
+/* FIXME a loop around a truly slow function means
+ * a truly spectacularly slow function.
+ */
+/**
+ * gtk_text_iter_forward_sentence_ends:
+ * @iter: a #GtkTextIter
+ * @count: number of sentences to move
+ *
+ * Calls gtk_text_iter_forward_sentence_end() @count times (or until
+ * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
+ * negative, moves backward instead of forward.
+ *
+ * Return value: %TRUE if @iter moved and is not the end iterator
+ **/
+gboolean
+gtk_text_iter_forward_sentence_ends (GtkTextIter *iter,
+ gint count)
+{
+ return move_multiple_steps (iter, count,
+ gtk_text_iter_forward_sentence_end,
+ gtk_text_iter_backward_sentence_starts);
+}
+
+/**
+ * gtk_text_iter_backward_sentence_starts:
+ * @iter: a #GtkTextIter
+ * @count: number of sentences to move
+ *
+ * Calls gtk_text_iter_backward_sentence_start() up to @count times,
+ * or until it returns %FALSE. If @count is negative, moves forward
+ * instead of backward.
+ *
+ * Return value: %TRUE if @iter moved and is not the end iterator
+ **/
+gboolean
+gtk_text_iter_backward_sentence_starts (GtkTextIter *iter,
+ gint count)
+{
+ return move_multiple_steps (iter, count,
+ gtk_text_iter_backward_sentence_start,
+ gtk_text_iter_forward_sentence_ends);
+}
+
+static gboolean
+find_forward_cursor_pos_func (const PangoLogAttr *attrs,
+ gint offset,
+ gint min_offset,