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