1 /* gtkpango.c - pango-related utilities
3 * Copyright (c) 2010 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.Free
19 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
27 #include <pango/pangocairo.h>
30 #define GTK_TYPE_FILL_LAYOUT_RENDERER (_gtk_fill_layout_renderer_get_type())
31 #define GTK_FILL_LAYOUT_RENDERER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GTK_TYPE_FILL_LAYOUT_RENDERER, GtkFillLayoutRenderer))
32 #define GTK_IS_FILL_LAYOUT_RENDERER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GTK_TYPE_FILL_LAYOUT_RENDERER))
33 #define GTK_FILL_LAYOUT_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILL_LAYOUT_RENDERER, GtkFillLayoutRendererClass))
34 #define GTK_IS_FILL_LAYOUT_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILL_LAYOUT_RENDERER))
35 #define GTK_FILL_LAYOUT_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILL_LAYOUT_RENDERER, GtkFillLayoutRendererClass))
37 typedef struct _GtkFillLayoutRenderer GtkFillLayoutRenderer;
38 typedef struct _GtkFillLayoutRendererClass GtkFillLayoutRendererClass;
40 struct _GtkFillLayoutRenderer
42 PangoRenderer parent_instance;
47 struct _GtkFillLayoutRendererClass
49 PangoRendererClass parent_class;
52 G_DEFINE_TYPE (GtkFillLayoutRenderer, _gtk_fill_layout_renderer, PANGO_TYPE_RENDERER)
55 gtk_fill_layout_renderer_draw_glyphs (PangoRenderer *renderer,
57 PangoGlyphString *glyphs,
61 GtkFillLayoutRenderer *text_renderer = GTK_FILL_LAYOUT_RENDERER (renderer);
63 cairo_move_to (text_renderer->cr, (double)x / PANGO_SCALE, (double)y / PANGO_SCALE);
64 pango_cairo_show_glyph_string (text_renderer->cr, font, glyphs);
68 gtk_fill_layout_renderer_draw_glyph_item (PangoRenderer *renderer,
70 PangoGlyphItem *glyph_item,
74 GtkFillLayoutRenderer *text_renderer = GTK_FILL_LAYOUT_RENDERER (renderer);
76 cairo_move_to (text_renderer->cr, (double)x / PANGO_SCALE, (double)y / PANGO_SCALE);
77 pango_cairo_show_glyph_item (text_renderer->cr, text, glyph_item);
81 gtk_fill_layout_renderer_draw_rectangle (PangoRenderer *renderer,
88 GtkFillLayoutRenderer *text_renderer = GTK_FILL_LAYOUT_RENDERER (renderer);
90 if (part == PANGO_RENDER_PART_BACKGROUND)
93 cairo_rectangle (text_renderer->cr,
94 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
95 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
96 cairo_fill (text_renderer->cr);
100 gtk_fill_layout_renderer_draw_trapezoid (PangoRenderer *renderer,
101 PangoRenderPart part,
109 GtkFillLayoutRenderer *text_renderer = GTK_FILL_LAYOUT_RENDERER (renderer);
110 cairo_matrix_t matrix;
113 cr = text_renderer->cr;
117 /* use identity scale, but keep translation */
118 cairo_get_matrix (cr, &matrix);
119 matrix.xx = matrix.yy = 1;
120 matrix.xy = matrix.yx = 0;
121 cairo_set_matrix (cr, &matrix);
123 cairo_move_to (cr, x11, y1_);
124 cairo_line_to (cr, x21, y1_);
125 cairo_line_to (cr, x22, y2);
126 cairo_line_to (cr, x12, y2);
127 cairo_close_path (cr);
135 gtk_fill_layout_renderer_draw_error_underline (PangoRenderer *renderer,
141 GtkFillLayoutRenderer *text_renderer = GTK_FILL_LAYOUT_RENDERER (renderer);
143 pango_cairo_show_error_underline (text_renderer->cr,
144 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
145 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
149 gtk_fill_layout_renderer_draw_shape (PangoRenderer *renderer,
150 PangoAttrShape *attr,
154 GtkFillLayoutRenderer *text_renderer = GTK_FILL_LAYOUT_RENDERER (renderer);
155 cairo_t *cr = text_renderer->cr;
157 PangoCairoShapeRendererFunc shape_renderer;
158 gpointer shape_renderer_data;
160 layout = pango_renderer_get_layout (renderer);
165 shape_renderer = pango_cairo_context_get_shape_renderer (pango_layout_get_context (layout),
166 &shape_renderer_data);
173 cairo_move_to (cr, (double)x / PANGO_SCALE, (double)y / PANGO_SCALE);
175 shape_renderer (cr, attr, FALSE, shape_renderer_data);
181 gtk_fill_layout_renderer_finalize (GObject *object)
183 G_OBJECT_CLASS (_gtk_fill_layout_renderer_parent_class)->finalize (object);
187 _gtk_fill_layout_renderer_init (GtkFillLayoutRenderer *renderer)
192 _gtk_fill_layout_renderer_class_init (GtkFillLayoutRendererClass *klass)
194 GObjectClass *object_class = G_OBJECT_CLASS (klass);
196 PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
198 renderer_class->draw_glyphs = gtk_fill_layout_renderer_draw_glyphs;
199 renderer_class->draw_glyph_item = gtk_fill_layout_renderer_draw_glyph_item;
200 renderer_class->draw_rectangle = gtk_fill_layout_renderer_draw_rectangle;
201 renderer_class->draw_trapezoid = gtk_fill_layout_renderer_draw_trapezoid;
202 renderer_class->draw_error_underline = gtk_fill_layout_renderer_draw_error_underline;
203 renderer_class->draw_shape = gtk_fill_layout_renderer_draw_shape;
205 object_class->finalize = gtk_fill_layout_renderer_finalize;
209 _gtk_pango_fill_layout (cairo_t *cr,
212 static GtkFillLayoutRenderer *renderer = NULL;
213 gboolean has_current_point;
214 double current_x, current_y;
216 has_current_point = cairo_has_current_point (cr);
217 cairo_get_current_point (cr, ¤t_x, ¤t_y);
219 if (renderer == NULL)
220 renderer = g_object_new (GTK_TYPE_FILL_LAYOUT_RENDERER, NULL);
223 cairo_translate (cr, current_x, current_y);
226 pango_renderer_draw_layout (PANGO_RENDERER (renderer), layout, 0, 0);
230 if (has_current_point)
231 cairo_move_to (cr, current_x, current_y);
234 static AtkAttributeSet *
235 add_attribute (AtkAttributeSet *attributes,
236 AtkTextAttribute attr,
241 at = g_new (AtkAttribute, 1);
242 at->name = g_strdup (atk_text_attribute_get_name (attr));
243 at->value = g_strdup (value);
245 return g_slist_prepend (attributes, at);
249 * _gtk_pango_get_default_attributes:
250 * @attributes: a #AtkAttributeSet to add the attributes to
251 * @layout: the #PangoLayout from which to get attributes
253 * Adds the default text attributes from @layout to @attributes,
254 * after translating them from Pango attributes to ATK attributes.
256 * This is a convenience function that can be used to implement
257 * support for the #AtkText interface in widgets using Pango
260 * Returns: the modified @attributes
263 _gtk_pango_get_default_attributes (AtkAttributeSet *attributes,
266 PangoContext *context;
270 context = pango_layout_get_context (layout);
273 PangoLanguage *language;
274 PangoFontDescription *font;
276 language = pango_context_get_language (context);
278 attributes = add_attribute (attributes, ATK_TEXT_ATTR_LANGUAGE,
279 pango_language_to_string (language));
281 font = pango_context_get_font_description (context);
285 attributes = add_attribute (attributes, ATK_TEXT_ATTR_STYLE,
286 atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE,
287 pango_font_description_get_style (font)));
288 attributes = add_attribute (attributes, ATK_TEXT_ATTR_VARIANT,
289 atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT,
290 pango_font_description_get_variant (font)));
291 attributes = add_attribute (attributes, ATK_TEXT_ATTR_STRETCH,
292 atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH,
293 pango_font_description_get_stretch (font)));
294 attributes = add_attribute (attributes, ATK_TEXT_ATTR_FAMILY_NAME,
295 pango_font_description_get_family (font));
296 g_snprintf (buf, 60, "%d", pango_font_description_get_weight (font));
297 attributes = add_attribute (attributes, ATK_TEXT_ATTR_WEIGHT, buf);
298 g_snprintf (buf, 60, "%i", pango_font_description_get_size (font) / PANGO_SCALE);
299 attributes = add_attribute (attributes, ATK_TEXT_ATTR_SIZE, buf);
302 if (pango_layout_get_justify (layout))
308 PangoAlignment align;
310 align = pango_layout_get_alignment (layout);
311 if (align == PANGO_ALIGN_LEFT)
313 else if (align == PANGO_ALIGN_CENTER)
315 else /* PANGO_ALIGN_RIGHT */
318 attributes = add_attribute (attributes, ATK_TEXT_ATTR_JUSTIFICATION,
319 atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, i));
320 mode = pango_layout_get_wrap (layout);
321 if (mode == PANGO_WRAP_WORD)
323 else /* PANGO_WRAP_CHAR */
325 attributes = add_attribute (attributes, ATK_TEXT_ATTR_WRAP_MODE,
326 atk_text_attribute_get_value (ATK_TEXT_ATTR_WRAP_MODE, i));
328 attributes = add_attribute (attributes, ATK_TEXT_ATTR_STRIKETHROUGH,
329 atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, 0));
330 attributes = add_attribute (attributes, ATK_TEXT_ATTR_UNDERLINE,
331 atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, 0));
332 attributes = add_attribute (attributes, ATK_TEXT_ATTR_RISE, "0");
333 attributes = add_attribute (attributes, ATK_TEXT_ATTR_SCALE, "1");
334 attributes = add_attribute (attributes, ATK_TEXT_ATTR_BG_FULL_HEIGHT, "0");
335 attributes = add_attribute (attributes, ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP, "0");
336 attributes = add_attribute (attributes, ATK_TEXT_ATTR_PIXELS_BELOW_LINES, "0");
337 attributes = add_attribute (attributes, ATK_TEXT_ATTR_PIXELS_ABOVE_LINES, "0");
338 attributes = add_attribute (attributes, ATK_TEXT_ATTR_EDITABLE,
339 atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, 0));
340 attributes = add_attribute (attributes, ATK_TEXT_ATTR_INVISIBLE,
341 atk_text_attribute_get_value (ATK_TEXT_ATTR_INVISIBLE, 0));
342 attributes = add_attribute (attributes, ATK_TEXT_ATTR_INDENT, "0");
343 attributes = add_attribute (attributes, ATK_TEXT_ATTR_RIGHT_MARGIN, "0");
344 attributes = add_attribute (attributes, ATK_TEXT_ATTR_LEFT_MARGIN, "0");
350 * _gtk_pango_get_run_attributes:
351 * @attributes: a #AtkAttributeSet to add attributes to
352 * @layout: the #PangoLayout to get the attributes from
353 * @offset: the offset at which the attributes are wanted
354 * @start_offset: return location for the starting offset
356 * @end_offset: return location for the ending offset of the
359 * Finds the 'run' around index (i.e. the maximal range of characters
360 * where the set of applicable attributes remains constant) and
361 * returns the starting and ending offsets for it.
363 * The attributes for the run are added to @attributes, after
364 * translating them from Pango attributes to ATK attributes.
366 * This is a convenience function that can be used to implement
367 * support for the #AtkText interface in widgets using Pango
370 * Returns: the modified #AtkAttributeSet
373 _gtk_pango_get_run_attributes (AtkAttributeSet *attributes,
379 PangoAttrIterator *iter;
381 PangoAttrString *pango_string;
382 PangoAttrInt *pango_int;
383 PangoAttrColor *pango_color;
384 PangoAttrLanguage *pango_lang;
385 PangoAttrFloat *pango_float;
386 gint index, start_index, end_index;
392 text = pango_layout_get_text (layout);
393 len = g_utf8_strlen (text, -1);
395 /* Grab the attributes of the PangoLayout, if any */
396 attr = pango_layout_get_attributes (layout);
405 iter = pango_attr_list_get_iterator (attr);
406 /* Get invariant range offsets */
407 /* If offset out of range, set offset in range */
413 index = g_utf8_offset_to_pointer (text, offset) - text;
414 pango_attr_iterator_range (iter, &start_index, &end_index);
418 if (index >= start_index && index < end_index)
420 *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
421 if (end_index == G_MAXINT) /* Last iterator */
424 *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
427 is_next = pango_attr_iterator_next (iter);
428 pango_attr_iterator_range (iter, &start_index, &end_index);
432 pango_string = (PangoAttrString*) pango_attr_iterator_get (iter, PANGO_ATTR_FAMILY);
433 if (pango_string != NULL)
435 value = g_strdup_printf ("%s", pango_string->value);
436 attributes = add_attribute (attributes, ATK_TEXT_ATTR_FAMILY_NAME, value);
439 pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_STYLE);
440 if (pango_int != NULL)
442 attributes = add_attribute (attributes, ATK_TEXT_ATTR_STYLE,
443 atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE, pango_int->value));
445 pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_WEIGHT);
446 if (pango_int != NULL)
448 value = g_strdup_printf ("%i", pango_int->value);
449 attributes = add_attribute (attributes, ATK_TEXT_ATTR_WEIGHT, value);
452 pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_VARIANT);
453 if (pango_int != NULL)
455 attributes = add_attribute (attributes, ATK_TEXT_ATTR_VARIANT,
456 atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT, pango_int->value));
458 pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_STRETCH);
459 if (pango_int != NULL)
461 attributes = add_attribute (attributes, ATK_TEXT_ATTR_STRETCH,
462 atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH, pango_int->value));
464 pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_SIZE);
465 if (pango_int != NULL)
467 value = g_strdup_printf ("%i", pango_int->value / PANGO_SCALE);
468 attributes = add_attribute (attributes, ATK_TEXT_ATTR_SIZE, value);
471 pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_UNDERLINE);
472 if (pango_int != NULL)
474 attributes = add_attribute (attributes, ATK_TEXT_ATTR_UNDERLINE,
475 atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, pango_int->value));
477 pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_STRIKETHROUGH);
478 if (pango_int != NULL)
480 attributes = add_attribute (attributes, ATK_TEXT_ATTR_STRIKETHROUGH,
481 atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, pango_int->value));
483 pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, PANGO_ATTR_RISE);
484 if (pango_int != NULL)
486 value = g_strdup_printf ("%i", pango_int->value);
487 attributes = add_attribute (attributes, ATK_TEXT_ATTR_RISE, value);
490 pango_lang = (PangoAttrLanguage*) pango_attr_iterator_get (iter, PANGO_ATTR_LANGUAGE);
491 if (pango_lang != NULL)
493 attributes = add_attribute (attributes, ATK_TEXT_ATTR_LANGUAGE,
494 pango_language_to_string (pango_lang->value));
496 pango_float = (PangoAttrFloat*) pango_attr_iterator_get (iter, PANGO_ATTR_SCALE);
497 if (pango_float != NULL)
499 value = g_strdup_printf ("%g", pango_float->value);
500 attributes = add_attribute (attributes, ATK_TEXT_ATTR_SCALE, value);
503 pango_color = (PangoAttrColor*) pango_attr_iterator_get (iter, PANGO_ATTR_FOREGROUND);
504 if (pango_color != NULL)
506 value = g_strdup_printf ("%u,%u,%u",
507 pango_color->color.red,
508 pango_color->color.green,
509 pango_color->color.blue);
510 attributes = add_attribute (attributes, ATK_TEXT_ATTR_FG_COLOR, value);
513 pango_color = (PangoAttrColor*) pango_attr_iterator_get (iter, PANGO_ATTR_BACKGROUND);
514 if (pango_color != NULL)
516 value = g_strdup_printf ("%u,%u,%u",
517 pango_color->color.red,
518 pango_color->color.green,
519 pango_color->color.blue);
520 attributes = add_attribute (attributes, ATK_TEXT_ATTR_BG_COLOR, value);
523 pango_attr_iterator_destroy (iter);
529 * _gtk_pango_move_chars:
530 * @layout: a #PangoLayout
531 * @offset: a character offset in @layout
532 * @count: the number of characters to move from @offset
534 * Returns the position that is @count characters from the
535 * given @offset. @count may be positive or negative.
537 * For the purpose of this function, characters are defined
538 * by what Pango considers cursor positions.
540 * Returns: the new position
543 _gtk_pango_move_chars (PangoLayout *layout,
547 const PangoLogAttr *attrs;
550 attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs);
552 while (count > 0 && offset < n_attrs - 1)
556 while (offset < n_attrs - 1 && !attrs[offset].is_cursor_position);
560 while (count < 0 && offset > 0)
564 while (offset > 0 && !attrs[offset].is_cursor_position);
573 * _gtk_pango_move_words:
574 * @layout: a #PangoLayout
575 * @offset: a character offset in @layout
576 * @count: the number of words to move from @offset
578 * Returns the position that is @count words from the
579 * given @offset. @count may be positive or negative.
581 * If @count is positive, the returned position will
582 * be a word end, otherwise it will be a word start.
583 * See the Pango documentation for details on how
584 * word starts and ends are defined.
586 * Returns: the new position
589 _gtk_pango_move_words (PangoLayout *layout,
593 const PangoLogAttr *attrs;
596 attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs);
598 while (count > 0 && offset < n_attrs - 1)
602 while (offset < n_attrs - 1 && !attrs[offset].is_word_end);
606 while (count < 0 && offset > 0)
610 while (offset > 0 && !attrs[offset].is_word_start);
619 * _gtk_pango_move_sentences:
620 * @layout: a #PangoLayout
621 * @offset: a character offset in @layout
622 * @count: the number of sentences to move from @offset
624 * Returns the position that is @count sentences from the
625 * given @offset. @count may be positive or negative.
627 * If @count is positive, the returned position will
628 * be a sentence end, otherwise it will be a sentence start.
629 * See the Pango documentation for details on how
630 * sentence starts and ends are defined.
632 * Returns: the new position
635 _gtk_pango_move_sentences (PangoLayout *layout,
639 const PangoLogAttr *attrs;
642 attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs);
644 while (count > 0 && offset < n_attrs - 1)
648 while (offset < n_attrs - 1 && !attrs[offset].is_sentence_end);
652 while (count < 0 && offset > 0)
656 while (offset > 0 && !attrs[offset].is_sentence_start);
665 * _gtk_pango_move_lines:
666 * @layout: a #PangoLayout
667 * @offset: a character offset in @layout
668 * @count: the number of lines to move from @offset
670 * Returns the position that is @count lines from the
671 * given @offset. @count may be positive or negative.
673 * If @count is negative, the returned position will
674 * be the start of a line, else it will be the end of
677 * Returns: the new position
680 _gtk_pango_move_lines (PangoLayout *layout,
685 PangoLayoutLine *line;
692 text = pango_layout_get_text (layout);
693 index = g_utf8_offset_to_pointer (text, offset) - text;
694 lines = pango_layout_get_lines (layout);
698 for (l = lines; l; l = l->next)
701 if (index < line->start_index + line->length)
712 line = g_slist_nth_data (lines, num);
714 return g_utf8_pointer_to_offset (text, text + line->start_index);
718 line_pos = index - line->start_index;
720 len = g_slist_length (lines);
722 if (num >= len || (count == 0 && num == len - 1))
723 return g_utf8_strlen (text, -1) - 1;
726 pos = line->start_index + line_pos;
727 if (pos >= line->start_index + line->length)
728 pos = line->start_index + line->length - 1;
730 return g_utf8_pointer_to_offset (text, text + pos);
735 * _gtk_pango_is_inside_word:
736 * @layout: a #PangoLayout
737 * @offset: a character offset in @layout
739 * Returns whether the given position is inside
742 * Returns: %TRUE if @offset is inside a word
745 _gtk_pango_is_inside_word (PangoLayout *layout,
748 const PangoLogAttr *attrs;
751 attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs);
753 while (offset >= 0 &&
754 !(attrs[offset].is_word_start || attrs[offset].is_word_end))
758 return attrs[offset].is_word_start;
764 * _gtk_pango_is_inside_sentence:
765 * @layout: a #PangoLayout
766 * @offset: a character offset in @layout
768 * Returns whether the given position is inside
771 * Returns: %TRUE if @offset is inside a sentence
774 _gtk_pango_is_inside_sentence (PangoLayout *layout,
777 const PangoLogAttr *attrs;
780 attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs);
782 while (offset >= 0 &&
783 !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
787 return attrs[offset].is_sentence_start;
793 pango_layout_get_line_before (PangoLayout *layout,
794 AtkTextBoundary boundary_type,
799 PangoLayoutIter *iter;
800 PangoLayoutLine *line, *prev_line = NULL, *prev_prev_line = NULL;
801 gint index, start_index, end_index;
803 gboolean found = FALSE;
805 text = pango_layout_get_text (layout);
806 index = g_utf8_offset_to_pointer (text, offset) - text;
807 iter = pango_layout_get_iter (layout);
810 line = pango_layout_iter_get_line (iter);
811 start_index = line->start_index;
812 end_index = start_index + line->length;
814 if (index >= start_index && index <= end_index)
816 /* Found line for offset */
819 switch (boundary_type)
821 case ATK_TEXT_BOUNDARY_LINE_START:
822 end_index = start_index;
823 start_index = prev_line->start_index;
825 case ATK_TEXT_BOUNDARY_LINE_END:
827 start_index = prev_prev_line->start_index + prev_prev_line->length;
830 end_index = prev_line->start_index + prev_line->length;
833 g_assert_not_reached();
837 start_index = end_index = 0;
843 prev_prev_line = prev_line;
846 while (pango_layout_iter_next_line (iter));
850 start_index = prev_line->start_index + prev_line->length;
851 end_index = start_index;
853 pango_layout_iter_free (iter);
855 *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
856 *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
860 pango_layout_get_line_at (PangoLayout *layout,
861 AtkTextBoundary boundary_type,
866 PangoLayoutIter *iter;
867 PangoLayoutLine *line, *prev_line = NULL;
868 gint index, start_index, end_index;
870 gboolean found = FALSE;
872 text = pango_layout_get_text (layout);
873 index = g_utf8_offset_to_pointer (text, offset) - text;
874 iter = pango_layout_get_iter (layout);
877 line = pango_layout_iter_get_line (iter);
878 start_index = line->start_index;
879 end_index = start_index + line->length;
881 if (index >= start_index && index <= end_index)
883 /* Found line for offset */
884 switch (boundary_type)
886 case ATK_TEXT_BOUNDARY_LINE_START:
887 if (pango_layout_iter_next_line (iter))
888 end_index = pango_layout_iter_get_line (iter)->start_index;
890 case ATK_TEXT_BOUNDARY_LINE_END:
892 start_index = prev_line->start_index + prev_line->length;
895 g_assert_not_reached();
904 while (pango_layout_iter_next_line (iter));
908 start_index = prev_line->start_index + prev_line->length;
909 end_index = start_index;
911 pango_layout_iter_free (iter);
913 *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
914 *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
918 pango_layout_get_line_after (PangoLayout *layout,
919 AtkTextBoundary boundary_type,
924 PangoLayoutIter *iter;
925 PangoLayoutLine *line, *prev_line = NULL;
926 gint index, start_index, end_index;
928 gboolean found = FALSE;
930 text = pango_layout_get_text (layout);
931 index = g_utf8_offset_to_pointer (text, offset) - text;
932 iter = pango_layout_get_iter (layout);
935 line = pango_layout_iter_get_line (iter);
936 start_index = line->start_index;
937 end_index = start_index + line->length;
939 if (index >= start_index && index <= end_index)
941 /* Found line for offset */
942 if (pango_layout_iter_next_line (iter))
944 line = pango_layout_iter_get_line (iter);
945 switch (boundary_type)
947 case ATK_TEXT_BOUNDARY_LINE_START:
948 start_index = line->start_index;
949 if (pango_layout_iter_next_line (iter))
950 end_index = pango_layout_iter_get_line (iter)->start_index;
952 end_index = start_index + line->length;
954 case ATK_TEXT_BOUNDARY_LINE_END:
955 start_index = end_index;
956 end_index = line->start_index + line->length;
959 g_assert_not_reached();
963 start_index = end_index;
971 while (pango_layout_iter_next_line (iter));
975 start_index = prev_line->start_index + prev_line->length;
976 end_index = start_index;
978 pango_layout_iter_free (iter);
980 *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
981 *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
985 * _gtk_pango_get_text_before:
986 * @layout: a #PangoLayout
987 * @boundary_type: a #AtkTextBoundary
988 * @offset: a character offset in @layout
989 * @start_offset: return location for the start of the returned text
990 * @end_offset: return location for the end of the return text
992 * Gets a slice of the text from @layout before @offset.
994 * The @boundary_type determines the size of the returned slice of
995 * text. For the exact semantics of this function, see
996 * atk_text_get_text_before_offset().
998 * Returns: a newly allocated string containing a slice of text
999 * from layout. Free with g_free().
1002 _gtk_pango_get_text_before (PangoLayout *layout,
1003 AtkTextBoundary boundary_type,
1010 const PangoLogAttr *attrs;
1013 text = pango_layout_get_text (layout);
1019 return g_strdup ("");
1022 attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs);
1027 switch (boundary_type)
1029 case ATK_TEXT_BOUNDARY_CHAR:
1030 start = _gtk_pango_move_chars (layout, start, -1);
1033 case ATK_TEXT_BOUNDARY_WORD_START:
1034 if (!attrs[start].is_word_start)
1035 start = _gtk_pango_move_words (layout, start, -1);
1037 start = _gtk_pango_move_words (layout, start, -1);
1040 case ATK_TEXT_BOUNDARY_WORD_END:
1041 if (_gtk_pango_is_inside_word (layout, start) &&
1042 !attrs[start].is_word_start)
1043 start = _gtk_pango_move_words (layout, start, -1);
1044 while (!attrs[start].is_word_end && start > 0)
1045 start = _gtk_pango_move_chars (layout, start, -1);
1047 start = _gtk_pango_move_words (layout, start, -1);
1048 while (!attrs[start].is_word_end && start > 0)
1049 start = _gtk_pango_move_chars (layout, start, -1);
1052 case ATK_TEXT_BOUNDARY_SENTENCE_START:
1053 if (!attrs[start].is_sentence_start)
1054 start = _gtk_pango_move_sentences (layout, start, -1);
1056 start = _gtk_pango_move_sentences (layout, start, -1);
1059 case ATK_TEXT_BOUNDARY_SENTENCE_END:
1060 if (_gtk_pango_is_inside_sentence (layout, start) &&
1061 !attrs[start].is_sentence_start)
1062 start = _gtk_pango_move_sentences (layout, start, -1);
1063 while (!attrs[start].is_sentence_end && start > 0)
1064 start = _gtk_pango_move_chars (layout, start, -1);
1066 start = _gtk_pango_move_sentences (layout, start, -1);
1067 while (!attrs[start].is_sentence_end && start > 0)
1068 start = _gtk_pango_move_chars (layout, start, -1);
1071 case ATK_TEXT_BOUNDARY_LINE_START:
1072 case ATK_TEXT_BOUNDARY_LINE_END:
1073 pango_layout_get_line_before (layout, boundary_type, offset, &start, &end);
1077 *start_offset = start;
1080 g_assert (start <= end);
1082 return g_utf8_substring (text, start, end);
1086 * _gtk_pango_get_text_after:
1087 * @layout: a #PangoLayout
1088 * @boundary_type: a #AtkTextBoundary
1089 * @offset: a character offset in @layout
1090 * @start_offset: return location for the start of the returned text
1091 * @end_offset: return location for the end of the return text
1093 * Gets a slice of the text from @layout after @offset.
1095 * The @boundary_type determines the size of the returned slice of
1096 * text. For the exact semantics of this function, see
1097 * atk_text_get_text_after_offset().
1099 * Returns: a newly allocated string containing a slice of text
1100 * from layout. Free with g_free().
1103 _gtk_pango_get_text_after (PangoLayout *layout,
1104 AtkTextBoundary boundary_type,
1111 const PangoLogAttr *attrs;
1114 text = pango_layout_get_text (layout);
1120 return g_strdup ("");
1123 attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs);
1128 switch (boundary_type)
1130 case ATK_TEXT_BOUNDARY_CHAR:
1131 start = _gtk_pango_move_chars (layout, start, 1);
1133 end = _gtk_pango_move_chars (layout, end, 1);
1136 case ATK_TEXT_BOUNDARY_WORD_START:
1137 if (_gtk_pango_is_inside_word (layout, end))
1138 end = _gtk_pango_move_words (layout, end, 1);
1139 while (!attrs[end].is_word_start && end < n_attrs - 1)
1140 end = _gtk_pango_move_chars (layout, end, 1);
1142 if (end < n_attrs - 1)
1144 end = _gtk_pango_move_words (layout, end, 1);
1145 while (!attrs[end].is_word_start && end < n_attrs - 1)
1146 end = _gtk_pango_move_chars (layout, end, 1);
1150 case ATK_TEXT_BOUNDARY_WORD_END:
1151 end = _gtk_pango_move_words (layout, end, 1);
1153 if (end < n_attrs - 1)
1154 end = _gtk_pango_move_words (layout, end, 1);
1157 case ATK_TEXT_BOUNDARY_SENTENCE_START:
1158 if (_gtk_pango_is_inside_sentence (layout, end))
1159 end = _gtk_pango_move_sentences (layout, end, 1);
1160 while (!attrs[end].is_sentence_start && end < n_attrs - 1)
1161 end = _gtk_pango_move_chars (layout, end, 1);
1163 if (end < n_attrs - 1)
1165 end = _gtk_pango_move_sentences (layout, end, 1);
1166 while (!attrs[end].is_sentence_start && end < n_attrs - 1)
1167 end = _gtk_pango_move_chars (layout, end, 1);
1171 case ATK_TEXT_BOUNDARY_SENTENCE_END:
1172 end = _gtk_pango_move_sentences (layout, end, 1);
1174 if (end < n_attrs - 1)
1175 end = _gtk_pango_move_sentences (layout, end, 1);
1178 case ATK_TEXT_BOUNDARY_LINE_START:
1179 case ATK_TEXT_BOUNDARY_LINE_END:
1180 pango_layout_get_line_after (layout, boundary_type, offset, &start, &end);
1184 *start_offset = start;
1187 g_assert (start <= end);
1189 return g_utf8_substring (text, start, end);
1193 * _gtk_pango_get_text_at:
1194 * @layout: a #PangoLayout
1195 * @boundary_type: a #AtkTextBoundary
1196 * @offset: a character offset in @layout
1197 * @start_offset: return location for the start of the returned text
1198 * @end_offset: return location for the end of the return text
1200 * Gets a slice of the text from @layout at @offset.
1202 * The @boundary_type determines the size of the returned slice of
1203 * text. For the exact semantics of this function, see
1204 * atk_text_get_text_after_offset().
1206 * Returns: a newly allocated string containing a slice of text
1207 * from layout. Free with g_free().
1210 _gtk_pango_get_text_at (PangoLayout *layout,
1211 AtkTextBoundary boundary_type,
1218 const PangoLogAttr *attrs;
1221 text = pango_layout_get_text (layout);
1227 return g_strdup ("");
1230 attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs);
1235 switch (boundary_type)
1237 case ATK_TEXT_BOUNDARY_CHAR:
1238 end = _gtk_pango_move_chars (layout, end, 1);
1241 case ATK_TEXT_BOUNDARY_WORD_START:
1242 if (!attrs[start].is_word_start)
1243 start = _gtk_pango_move_words (layout, start, -1);
1244 if (_gtk_pango_is_inside_word (layout, end))
1245 end = _gtk_pango_move_words (layout, end, 1);
1246 while (!attrs[end].is_word_start && end < n_attrs - 1)
1247 end = _gtk_pango_move_chars (layout, end, 1);
1250 case ATK_TEXT_BOUNDARY_WORD_END:
1251 if (_gtk_pango_is_inside_word (layout, start) &&
1252 !attrs[start].is_word_start)
1253 start = _gtk_pango_move_words (layout, start, -1);
1254 while (!attrs[start].is_word_end && start > 0)
1255 start = _gtk_pango_move_chars (layout, start, -1);
1256 end = _gtk_pango_move_words (layout, end, 1);
1259 case ATK_TEXT_BOUNDARY_SENTENCE_START:
1260 if (!attrs[start].is_sentence_start)
1261 start = _gtk_pango_move_sentences (layout, start, -1);
1262 if (_gtk_pango_is_inside_sentence (layout, end))
1263 end = _gtk_pango_move_sentences (layout, end, 1);
1264 while (!attrs[end].is_sentence_start && end < n_attrs - 1)
1265 end = _gtk_pango_move_chars (layout, end, 1);
1268 case ATK_TEXT_BOUNDARY_SENTENCE_END:
1269 if (_gtk_pango_is_inside_sentence (layout, start) &&
1270 !attrs[start].is_sentence_start)
1271 start = _gtk_pango_move_sentences (layout, start, -1);
1272 while (!attrs[start].is_sentence_end && start > 0)
1273 start = _gtk_pango_move_chars (layout, start, -1);
1274 end = _gtk_pango_move_sentences (layout, end, 1);
1277 case ATK_TEXT_BOUNDARY_LINE_START:
1278 case ATK_TEXT_BOUNDARY_LINE_END:
1279 pango_layout_get_line_at (layout, boundary_type, offset, &start, &end);
1283 *start_offset = start;
1286 g_assert (start <= end);
1288 return g_utf8_substring (text, start, end);