]> Pileus Git - ~andy/gtk/blob - gtk/a11y/libgail-util/gailtextutil.c
gail: Move from modules/other/gail to gtk/a11y
[~andy/gtk] / gtk / a11y / libgail-util / gailtextutil.c
1 /* GAIL - The GNOME Accessibility Implementation Library
2  * Copyright 2001 Sun Microsystems Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include <stdlib.h>
23 #include "gailtextutil.h"
24
25 /**
26  * SECTION:gailtextutil
27  * @Short_description: GailTextUtil is a utility class which can be used to
28  *   implement some of the #AtkText functions for accessible objects
29  *   which implement #AtkText.
30  * @Title: GailTextUtil
31  *
32  * GailTextUtil is a utility class which can be used to implement the
33  * #AtkText functions which get text for accessible objects which implement
34  * #AtkText.
35  *
36  * In GAIL it is used by the accsesible objects for #GnomeCanvasText, #GtkEntry,
37  * #GtkLabel, #GtkCellRendererText and #GtkTextView.
38  */
39
40 static void gail_text_util_class_init      (GailTextUtilClass *klass);
41
42 static void gail_text_util_init            (GailTextUtil      *textutil);
43 static void gail_text_util_finalize        (GObject           *object);
44
45
46 static void get_pango_text_offsets         (PangoLayout         *layout,
47                                             GtkTextBuffer       *buffer,
48                                             GailOffsetType      function,
49                                             AtkTextBoundary     boundary_type,
50                                             gint                offset,
51                                             gint                *start_offset,
52                                             gint                *end_offset,
53                                             GtkTextIter         *start_iter,
54                                             GtkTextIter         *end_iter);
55 static GObjectClass *parent_class = NULL;
56
57 GType
58 gail_text_util_get_type(void)
59 {
60   static GType type = 0;
61
62   if (!type)
63     {
64       const GTypeInfo tinfo =
65       {
66         sizeof (GailTextUtilClass),
67         (GBaseInitFunc) NULL, /* base init */
68         (GBaseFinalizeFunc) NULL, /* base finalize */
69         (GClassInitFunc) gail_text_util_class_init,
70         (GClassFinalizeFunc) NULL, /* class finalize */
71         NULL, /* class data */
72         sizeof(GailTextUtil),
73         0, /* nb preallocs */
74         (GInstanceInitFunc) gail_text_util_init,
75         NULL, /* value table */
76       };
77
78       type = g_type_register_static (G_TYPE_OBJECT, "GailTextUtil", &tinfo, 0);
79     }
80   return type;
81 }
82
83 /**
84  * gail_text_util_new:
85  *
86  * This function creates a new GailTextUtil object.
87  *
88  * Returns: the GailTextUtil object
89  **/
90 GailTextUtil*
91 gail_text_util_new (void)
92 {
93   return GAIL_TEXT_UTIL (g_object_new (GAIL_TYPE_TEXT_UTIL, NULL));
94 }
95
96 static void
97 gail_text_util_init (GailTextUtil *textutil)
98 {
99   textutil->buffer = NULL;
100 }
101
102 static void
103 gail_text_util_class_init (GailTextUtilClass *klass)
104 {
105   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
106
107   parent_class = g_type_class_peek_parent (klass);
108
109   gobject_class->finalize = gail_text_util_finalize;
110 }
111
112 static void
113 gail_text_util_finalize (GObject *object)
114 {
115   GailTextUtil *textutil = GAIL_TEXT_UTIL (object);
116
117   if (textutil->buffer)
118     g_object_unref (textutil->buffer);
119
120   G_OBJECT_CLASS (parent_class)->finalize (object);
121 }
122
123 /**
124  * gail_text_util_text_setup:
125  * @textutil: The #GailTextUtil to be initialized.
126  * @text: A gchar* which points to the text to be stored in the GailTextUtil
127  *
128  * This function initializes the GailTextUtil with the specified character string,
129  **/
130 void
131 gail_text_util_text_setup (GailTextUtil *textutil,
132                            const gchar  *text)
133 {
134   g_return_if_fail (GAIL_IS_TEXT_UTIL (textutil));
135
136   if (textutil->buffer)
137     {
138       if (!text)
139         {
140           g_object_unref (textutil->buffer);
141           textutil->buffer = NULL;
142           return;
143         }
144     }
145   else
146     {
147       textutil->buffer = gtk_text_buffer_new (NULL);
148     }
149
150   gtk_text_buffer_set_text (textutil->buffer, text, -1);
151 }
152
153 /**
154  * gail_text_util_buffer_setup:
155  * @textutil: A #GailTextUtil to be initialized
156  * @buffer: The #GtkTextBuffer which identifies the text to be stored in the GailUtil.
157  *
158  * This function initializes the GailTextUtil with the specified GtkTextBuffer
159  **/
160 void
161 gail_text_util_buffer_setup  (GailTextUtil  *textutil,
162                               GtkTextBuffer   *buffer)
163 {
164   g_return_if_fail (GAIL_IS_TEXT_UTIL (textutil));
165
166   textutil->buffer = g_object_ref (buffer);
167 }
168
169 /**
170  * gail_text_util_get_text:
171  * @textutil: A #GailTextUtil
172  * @layout: A gpointer which is a PangoLayout, a GtkTreeView of NULL
173  * @function: An enumeration specifying whether to return the text before, at, or
174  *   after the offset.
175  * @boundary_type: The boundary type.
176  * @offset: The offset of the text in the GailTextUtil 
177  * @start_offset: Address of location in which the start offset is returned
178  * @end_offset: Address of location in which the end offset is returned
179  *
180  * This function gets the requested substring from the text in the GtkTextUtil.
181  * The layout is used only for getting the text on a line. The value is NULL 
182  * for a GtkTextView which is not wrapped, is a GtkTextView for a GtkTextView 
183  * which is wrapped and is a PangoLayout otherwise.
184  *
185  * Returns: the substring requested
186  **/
187 gchar*
188 gail_text_util_get_text (GailTextUtil    *textutil,
189                          gpointer        layout,
190                          GailOffsetType  function,
191                          AtkTextBoundary boundary_type,
192                          gint            offset,
193                          gint            *start_offset,
194                          gint            *end_offset)
195 {
196   GtkTextIter start, end;
197   gint line_number;
198   GtkTextBuffer *buffer;
199
200   g_return_val_if_fail (GAIL_IS_TEXT_UTIL (textutil), NULL);
201
202   buffer = textutil->buffer;
203   if (buffer == NULL)
204     {
205       *start_offset = 0;
206       *end_offset = 0;
207       return NULL;
208     }
209
210   if (!gtk_text_buffer_get_char_count (buffer))
211     {
212       *start_offset = 0;
213       *end_offset = 0;
214       return g_strdup ("");
215     }
216   gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
217
218     
219   end = start;
220
221   switch (function)
222     {
223     case GAIL_BEFORE_OFFSET:
224       switch (boundary_type)
225         {
226         case ATK_TEXT_BOUNDARY_CHAR:
227           gtk_text_iter_backward_char(&start);
228           break;
229         case ATK_TEXT_BOUNDARY_WORD_START:
230           if (!gtk_text_iter_starts_word (&start))
231             gtk_text_iter_backward_word_start (&start);
232           end = start;
233           gtk_text_iter_backward_word_start(&start);
234           break;
235         case ATK_TEXT_BOUNDARY_WORD_END:
236           if (gtk_text_iter_inside_word (&start) &&
237               !gtk_text_iter_starts_word (&start))
238             gtk_text_iter_backward_word_start (&start);
239           while (!gtk_text_iter_ends_word (&start))
240             {
241               if (!gtk_text_iter_backward_char (&start))
242                 break;
243             }
244           end = start;
245           gtk_text_iter_backward_word_start(&start);
246           while (!gtk_text_iter_ends_word (&start))
247             {
248               if (!gtk_text_iter_backward_char (&start))
249                 break;
250             }
251           break;
252         case ATK_TEXT_BOUNDARY_SENTENCE_START:
253           if (!gtk_text_iter_starts_sentence (&start))
254             gtk_text_iter_backward_sentence_start (&start);
255           end = start;
256           gtk_text_iter_backward_sentence_start (&start);
257           break;
258         case ATK_TEXT_BOUNDARY_SENTENCE_END:
259           if (gtk_text_iter_inside_sentence (&start) &&
260               !gtk_text_iter_starts_sentence (&start))
261             gtk_text_iter_backward_sentence_start (&start);
262           while (!gtk_text_iter_ends_sentence (&start))
263             {
264               if (!gtk_text_iter_backward_char (&start))
265                 break;
266             }
267           end = start;
268           gtk_text_iter_backward_sentence_start (&start);
269           while (!gtk_text_iter_ends_sentence (&start))
270             {
271               if (!gtk_text_iter_backward_char (&start))
272                 break;
273             }
274           break;
275         case ATK_TEXT_BOUNDARY_LINE_START:
276           if (layout == NULL)
277             {
278               line_number = gtk_text_iter_get_line (&start);
279               if (line_number == 0)
280                 {
281                   gtk_text_buffer_get_iter_at_offset (buffer,
282                     &start, 0);
283                 }
284               else
285                 {
286                   gtk_text_iter_backward_line (&start);
287                   gtk_text_iter_forward_line (&start);
288                 }
289               end = start;
290               gtk_text_iter_backward_line (&start);
291             }
292           else if GTK_IS_TEXT_VIEW (layout)
293             {
294               GtkTextView *view = GTK_TEXT_VIEW (layout);
295
296               gtk_text_view_backward_display_line_start (view, &start);
297               end = start;
298               gtk_text_view_backward_display_line (view, &start);
299             }
300           else if (PANGO_IS_LAYOUT (layout))
301             get_pango_text_offsets (PANGO_LAYOUT (layout),
302                                     buffer,
303                                     function,
304                                     boundary_type,
305                                     offset,
306                                     start_offset,
307                                     end_offset,
308                                     &start,
309                                     &end);
310           break;
311         case ATK_TEXT_BOUNDARY_LINE_END:
312           if (layout == NULL)
313             {
314               line_number = gtk_text_iter_get_line (&start);
315               if (line_number == 0)
316                 {
317                   gtk_text_buffer_get_iter_at_offset (buffer,
318                     &start, 0);
319                   end = start;
320                 }
321               else
322                 {
323                   gtk_text_iter_backward_line (&start);
324                   end = start;
325                   while (!gtk_text_iter_ends_line (&start))
326                     {
327                       if (!gtk_text_iter_backward_char (&start))
328                         break;
329                     }
330                   gtk_text_iter_forward_to_line_end (&end);
331                 }
332             }
333           else if GTK_IS_TEXT_VIEW (layout)
334             {
335               GtkTextView *view = GTK_TEXT_VIEW (layout);
336
337               gtk_text_view_backward_display_line_start (view, &start);
338               if (!gtk_text_iter_is_start (&start))
339                 {
340                   gtk_text_view_backward_display_line (view, &start);
341                   end = start;
342                   if (!gtk_text_iter_is_start (&start))
343                     {
344                       gtk_text_view_backward_display_line (view, &start);
345                       gtk_text_view_forward_display_line_end (view, &start);
346                     }
347                   gtk_text_view_forward_display_line_end (view, &end);
348                 } 
349               else
350                 {
351                   end = start;
352                 }
353             }
354           else if (PANGO_IS_LAYOUT (layout))
355             get_pango_text_offsets (PANGO_LAYOUT (layout),
356                                     buffer,
357                                     function,
358                                     boundary_type,
359                                     offset,
360                                     start_offset,
361                                     end_offset,
362                                     &start,
363                                     &end);
364           break;
365         }
366       break;
367  
368     case GAIL_AT_OFFSET:
369       switch (boundary_type)
370         {
371         case ATK_TEXT_BOUNDARY_CHAR:
372           gtk_text_iter_forward_char (&end);
373           break;
374         case ATK_TEXT_BOUNDARY_WORD_START:
375           if (!gtk_text_iter_starts_word (&start))
376             gtk_text_iter_backward_word_start (&start);
377           if (gtk_text_iter_inside_word (&end))
378             gtk_text_iter_forward_word_end (&end);
379           while (!gtk_text_iter_starts_word (&end))
380             {
381               if (!gtk_text_iter_forward_char (&end))
382                 break;
383             }
384           break;
385         case ATK_TEXT_BOUNDARY_WORD_END:
386           if (gtk_text_iter_inside_word (&start) &&
387               !gtk_text_iter_starts_word (&start))
388             gtk_text_iter_backward_word_start (&start);
389           while (!gtk_text_iter_ends_word (&start))
390             {
391               if (!gtk_text_iter_backward_char (&start))
392                 break;
393             }
394           gtk_text_iter_forward_word_end (&end);
395           break;
396         case ATK_TEXT_BOUNDARY_SENTENCE_START:
397           if (!gtk_text_iter_starts_sentence (&start))
398             gtk_text_iter_backward_sentence_start (&start);
399           if (gtk_text_iter_inside_sentence (&end))
400             gtk_text_iter_forward_sentence_end (&end);
401           while (!gtk_text_iter_starts_sentence (&end))
402             {
403               if (!gtk_text_iter_forward_char (&end))
404                 break;
405             }
406           break;
407         case ATK_TEXT_BOUNDARY_SENTENCE_END:
408           if (gtk_text_iter_inside_sentence (&start) &&
409               !gtk_text_iter_starts_sentence (&start))
410             gtk_text_iter_backward_sentence_start (&start);
411           while (!gtk_text_iter_ends_sentence (&start))
412             {
413               if (!gtk_text_iter_backward_char (&start))
414                 break;
415             }
416           gtk_text_iter_forward_sentence_end (&end);
417           break;
418         case ATK_TEXT_BOUNDARY_LINE_START:
419           if (layout == NULL)
420             {
421               line_number = gtk_text_iter_get_line (&start);
422               if (line_number == 0)
423                 {
424                   gtk_text_buffer_get_iter_at_offset (buffer,
425                     &start, 0);
426                 }
427               else
428                 {
429                   gtk_text_iter_backward_line (&start);
430                   gtk_text_iter_forward_line (&start);
431                 }
432               gtk_text_iter_forward_line (&end);
433             }
434           else if GTK_IS_TEXT_VIEW (layout)
435             {
436               GtkTextView *view = GTK_TEXT_VIEW (layout);
437
438               gtk_text_view_backward_display_line_start (view, &start);
439               /*
440                * The call to gtk_text_iter_forward_to_end() is needed
441                * because of bug 81960
442                */
443               if (!gtk_text_view_forward_display_line (view, &end))
444                 gtk_text_iter_forward_to_end (&end);
445             }
446           else if PANGO_IS_LAYOUT (layout)
447             get_pango_text_offsets (PANGO_LAYOUT (layout),
448                                     buffer,
449                                     function,
450                                     boundary_type,
451                                     offset,
452                                     start_offset,
453                                     end_offset,
454                                     &start,
455                                     &end);
456
457           break;
458         case ATK_TEXT_BOUNDARY_LINE_END:
459           if (layout == NULL)
460             {
461               line_number = gtk_text_iter_get_line (&start);
462               if (line_number == 0)
463                 {
464                   gtk_text_buffer_get_iter_at_offset (buffer,
465                     &start, 0);
466                 }
467               else
468                 {
469                   gtk_text_iter_backward_line (&start);
470                   gtk_text_iter_forward_line (&start);
471                 }
472               while (!gtk_text_iter_ends_line (&start))
473                 {
474                   if (!gtk_text_iter_backward_char (&start))
475                     break;
476                 }
477               gtk_text_iter_forward_to_line_end (&end);
478             }
479           else if GTK_IS_TEXT_VIEW (layout)
480             {
481               GtkTextView *view = GTK_TEXT_VIEW (layout);
482
483               gtk_text_view_backward_display_line_start (view, &start);
484               if (!gtk_text_iter_is_start (&start))
485                 {
486                   gtk_text_view_backward_display_line (view, &start);
487                   gtk_text_view_forward_display_line_end (view, &start);
488                 } 
489               gtk_text_view_forward_display_line_end (view, &end);
490             }
491           else if PANGO_IS_LAYOUT (layout)
492             get_pango_text_offsets (PANGO_LAYOUT (layout),
493                                     buffer,
494                                     function,
495                                     boundary_type,
496                                     offset,
497                                     start_offset,
498                                     end_offset,
499                                     &start,
500                                     &end);
501           break;
502         }
503       break;
504   
505     case GAIL_AFTER_OFFSET:
506       switch (boundary_type)
507         {
508         case ATK_TEXT_BOUNDARY_CHAR:
509           gtk_text_iter_forward_char(&start);
510           gtk_text_iter_forward_chars(&end, 2);
511           break;
512         case ATK_TEXT_BOUNDARY_WORD_START:
513           if (gtk_text_iter_inside_word (&end))
514             gtk_text_iter_forward_word_end (&end);
515           while (!gtk_text_iter_starts_word (&end))
516             {
517               if (!gtk_text_iter_forward_char (&end))
518                 break;
519             }
520           start = end;
521           if (!gtk_text_iter_is_end (&end))
522             {
523               gtk_text_iter_forward_word_end (&end);
524               while (!gtk_text_iter_starts_word (&end))
525                 {
526                   if (!gtk_text_iter_forward_char (&end))
527                     break;
528                 }
529             }
530           break;
531         case ATK_TEXT_BOUNDARY_WORD_END:
532           gtk_text_iter_forward_word_end (&end);
533           start = end;
534           if (!gtk_text_iter_is_end (&end))
535             gtk_text_iter_forward_word_end (&end);
536           break;
537         case ATK_TEXT_BOUNDARY_SENTENCE_START:
538           if (gtk_text_iter_inside_sentence (&end))
539             gtk_text_iter_forward_sentence_end (&end);
540           while (!gtk_text_iter_starts_sentence (&end))
541             {
542               if (!gtk_text_iter_forward_char (&end))
543                 break;
544             }
545           start = end;
546           if (!gtk_text_iter_is_end (&end))
547             {
548               gtk_text_iter_forward_sentence_end (&end);
549               while (!gtk_text_iter_starts_sentence (&end))
550                 {
551                   if (!gtk_text_iter_forward_char (&end))
552                     break;
553                 }
554             }
555           break;
556         case ATK_TEXT_BOUNDARY_SENTENCE_END:
557           gtk_text_iter_forward_sentence_end (&end);
558           start = end;
559           if (!gtk_text_iter_is_end (&end))
560             gtk_text_iter_forward_sentence_end (&end);
561           break;
562         case ATK_TEXT_BOUNDARY_LINE_START:
563           if (layout == NULL)
564             {
565               gtk_text_iter_forward_line (&end);
566               start = end;
567               gtk_text_iter_forward_line (&end);
568             }
569           else if GTK_IS_TEXT_VIEW (layout)
570             {
571               GtkTextView *view = GTK_TEXT_VIEW (layout);
572
573               gtk_text_view_forward_display_line (view, &end);
574               start = end; 
575               gtk_text_view_forward_display_line (view, &end);
576             }
577           else if (PANGO_IS_LAYOUT (layout))
578             get_pango_text_offsets (PANGO_LAYOUT (layout),
579                                     buffer,
580                                     function,
581                                     boundary_type,
582                                     offset,
583                                     start_offset,
584                                     end_offset,
585                                     &start,
586                                     &end);
587           break;
588         case ATK_TEXT_BOUNDARY_LINE_END:
589           if (layout == NULL)
590             {
591               gtk_text_iter_forward_line (&start);
592               end = start;
593               if (!gtk_text_iter_is_end (&start))
594                 { 
595                   while (!gtk_text_iter_ends_line (&start))
596                   {
597                     if (!gtk_text_iter_backward_char (&start))
598                       break;
599                   }
600                   gtk_text_iter_forward_to_line_end (&end);
601                 }
602             }
603           else if GTK_IS_TEXT_VIEW (layout)
604             {
605               GtkTextView *view = GTK_TEXT_VIEW (layout);
606
607               gtk_text_view_forward_display_line_end (view, &end);
608               start = end; 
609               gtk_text_view_forward_display_line (view, &end);
610               gtk_text_view_forward_display_line_end (view, &end);
611             }
612           else if (PANGO_IS_LAYOUT (layout))
613             get_pango_text_offsets (PANGO_LAYOUT (layout),
614                                     buffer,
615                                     function,
616                                     boundary_type,
617                                     offset,
618                                     start_offset,
619                                     end_offset,
620                                     &start,
621                                     &end);
622           break;
623         }
624       break;
625     }
626   *start_offset = gtk_text_iter_get_offset (&start);
627   *end_offset = gtk_text_iter_get_offset (&end);
628
629   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
630 }
631
632 /**
633  * gail_text_util_get_substring:
634  * @textutil: A #GailTextUtil
635  * @start_pos: The start position of the substring
636  * @end_pos: The end position of the substring.
637  *
638  * Gets the substring indicated by @start_pos and @end_pos
639  *
640  * Returns: the substring indicated by @start_pos and @end_pos
641  **/
642 gchar*
643 gail_text_util_get_substring (GailTextUtil *textutil,
644                               gint         start_pos, 
645                               gint         end_pos)
646 {
647   GtkTextIter start, end;
648   GtkTextBuffer *buffer;
649
650   g_return_val_if_fail(GAIL_IS_TEXT_UTIL (textutil), NULL);
651
652   buffer = textutil->buffer;
653   if (buffer == NULL)
654      return NULL;
655
656   gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
657   if (end_pos < 0)
658     gtk_text_buffer_get_end_iter (buffer, &end);
659   else
660     gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
661
662   return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
663 }
664
665 static void
666 get_pango_text_offsets (PangoLayout         *layout,
667                         GtkTextBuffer       *buffer,
668                         GailOffsetType      function,
669                         AtkTextBoundary     boundary_type,
670                         gint                offset,
671                         gint                *start_offset,
672                         gint                *end_offset,
673                         GtkTextIter         *start_iter,
674                         GtkTextIter         *end_iter)
675 {
676   PangoLayoutIter *iter;
677   PangoLayoutLine *line, *prev_line = NULL, *prev_prev_line = NULL;
678   gint index, start_index, end_index;
679   const gchar *text;
680   gboolean found = FALSE;
681
682   text = pango_layout_get_text (layout);
683   index = g_utf8_offset_to_pointer (text, offset) - text;
684   iter = pango_layout_get_iter (layout);
685   do
686     {
687       line = pango_layout_iter_get_line (iter);
688       start_index = line->start_index;
689       end_index = start_index + line->length;
690
691       if (index >= start_index && index <= end_index)
692         {
693           /*
694            * Found line for offset
695            */
696           switch (function)
697             {
698             case GAIL_BEFORE_OFFSET:
699                   /*
700                    * We want the previous line
701                    */
702               if (prev_line)
703                 {
704                   switch (boundary_type)
705                     {
706                     case ATK_TEXT_BOUNDARY_LINE_START:
707                       end_index = start_index;
708                       start_index = prev_line->start_index;
709                       break;
710                     case ATK_TEXT_BOUNDARY_LINE_END:
711                       if (prev_prev_line)
712                         start_index = prev_prev_line->start_index + 
713                                   prev_prev_line->length;
714                       end_index = prev_line->start_index + prev_line->length;
715                       break;
716                     default:
717                       g_assert_not_reached();
718                     }
719                 }
720               else
721                 start_index = end_index = 0;
722               break;
723             case GAIL_AT_OFFSET:
724               switch (boundary_type)
725                 {
726                 case ATK_TEXT_BOUNDARY_LINE_START:
727                   if (pango_layout_iter_next_line (iter))
728                     end_index = pango_layout_iter_get_line (iter)->start_index;
729                   break;
730                 case ATK_TEXT_BOUNDARY_LINE_END:
731                   if (prev_line)
732                     start_index = prev_line->start_index + 
733                                   prev_line->length;
734                   break;
735                 default:
736                   g_assert_not_reached();
737                 }
738               break;
739             case GAIL_AFTER_OFFSET:
740                /*
741                 * We want the next line
742                 */
743               if (pango_layout_iter_next_line (iter))
744                 {
745                   line = pango_layout_iter_get_line (iter);
746                   switch (boundary_type)
747                     {
748                     case ATK_TEXT_BOUNDARY_LINE_START:
749                       start_index = line->start_index;
750                       if (pango_layout_iter_next_line (iter))
751                         end_index = pango_layout_iter_get_line (iter)->start_index;
752                       else
753                         end_index = start_index + line->length;
754                       break;
755                     case ATK_TEXT_BOUNDARY_LINE_END:
756                       start_index = end_index;
757                       end_index = line->start_index + line->length;
758                       break;
759                     default:
760                       g_assert_not_reached();
761                     }
762                 }
763               else
764                 start_index = end_index;
765               break;
766             }
767           found = TRUE;
768           break;
769         }
770       prev_prev_line = prev_line; 
771       prev_line = line; 
772     }
773   while (pango_layout_iter_next_line (iter));
774
775   if (!found)
776     {
777       start_index = prev_line->start_index + prev_line->length;
778       end_index = start_index;
779     }
780   pango_layout_iter_free (iter);
781   *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
782   *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
783  
784   gtk_text_buffer_get_iter_at_offset (buffer, start_iter, *start_offset);
785   gtk_text_buffer_get_iter_at_offset (buffer, end_iter, *end_offset);
786 }