1 /* GTK - The GIMP Toolkit
2 * gtktextlayout.c - calculate the layout of the text
4 * Copyright (c) 1992-1994 The Regents of the University of California.
5 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
6 * Copyright (c) 2000 Red Hat, Inc.
7 * Tk->Gtk port by Havoc Pennington
8 * Pango support by Owen Taylor
10 * This file can be used under your choice of two licenses, the LGPL
11 * and the original Tk license.
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2 of the License, or (at your option) any later version.
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free
27 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 * Original Tk license:
31 * This software is copyrighted by the Regents of the University of
32 * California, Sun Microsystems, Inc., and other parties. The
33 * following terms apply to all files associated with the software
34 * unless explicitly disclaimed in individual files.
36 * The authors hereby grant permission to use, copy, modify,
37 * distribute, and license this software and its documentation for any
38 * purpose, provided that existing copyright notices are retained in
39 * all copies and that this notice is included verbatim in any
40 * distributions. No written agreement, license, or royalty fee is
41 * required for any of the authorized uses. Modifications to this
42 * software may be copyrighted by their authors and need not follow
43 * the licensing terms described here, provided that the new terms are
44 * clearly indicated on the first page of each file where they apply.
46 * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
47 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
48 * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION,
49 * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED
50 * OF THE POSSIBILITY OF SUCH DAMAGE.
52 * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
53 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
54 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
55 * NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
56 * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
57 * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
59 * GOVERNMENT USE: If you are acquiring this software on behalf of the
60 * U.S. government, the Government shall have only "Restricted Rights"
61 * in the software and related documentation as defined in the Federal
62 * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
63 * are acquiring the software on behalf of the Department of Defense,
64 * the software shall be classified as "Commercial Computer Software"
65 * and the Government shall have only "Restricted Rights" as defined
66 * in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the
67 * foregoing, the authors grant the U.S. Government and others acting
68 * in its behalf permission to use and distribute the software in
69 * accordance with the terms specified in this license.
73 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
74 * file for a list of people on the GTK+ Team. See the ChangeLog
75 * files for a list of changes. These files are distributed with
76 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
79 #include "gtksignal.h"
80 #include "gtktextlayout.h"
81 #include "gtktextbtree.h"
82 #include "gtktextiterprivate.h"
87 static GtkTextLineData *gtk_text_line_data_new (GtkTextLayout *layout,
90 static GtkTextLineData *gtk_text_layout_real_wrap (GtkTextLayout *layout,
93 GtkTextLineData *line_data);
95 static void gtk_text_layout_invalidated (GtkTextLayout *layout);
97 static void gtk_text_layout_real_invalidate (GtkTextLayout *layout,
98 const GtkTextIter *start,
99 const GtkTextIter *end);
100 static void gtk_text_layout_invalidate_cache (GtkTextLayout *layout,
102 static void gtk_text_layout_real_free_line_data (GtkTextLayout *layout,
104 GtkTextLineData *line_data);
106 static void gtk_text_layout_invalidate_all (GtkTextLayout *layout);
108 static PangoAttribute *gtk_text_attr_appearance_new (const GtkTextAppearance *appearance);
122 static void gtk_text_layout_init (GtkTextLayout *text_layout);
123 static void gtk_text_layout_class_init (GtkTextLayoutClass *klass);
124 static void gtk_text_layout_destroy (GtkObject *object);
125 static void gtk_text_layout_finalize (GObject *object);
128 static GtkObjectClass *parent_class = NULL;
129 static guint signals[LAST_SIGNAL] = { 0 };
131 PangoAttrType gtk_text_attr_appearance_type = 0;
134 gtk_text_layout_get_type (void)
136 static GtkType our_type = 0;
140 static const GtkTypeInfo our_info =
143 sizeof (GtkTextLayout),
144 sizeof (GtkTextLayoutClass),
145 (GtkClassInitFunc) gtk_text_layout_class_init,
146 (GtkObjectInitFunc) gtk_text_layout_init,
147 /* reserved_1 */ NULL,
148 /* reserved_2 */ NULL,
149 (GtkClassInitFunc) NULL
152 our_type = gtk_type_unique (GTK_TYPE_OBJECT, &our_info);
159 gtk_text_layout_class_init (GtkTextLayoutClass *klass)
161 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
162 GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
164 parent_class = gtk_type_class (GTK_TYPE_OBJECT);
166 signals[INVALIDATED] =
167 gtk_signal_new ("invalidated",
169 GTK_CLASS_TYPE (object_class),
170 GTK_SIGNAL_OFFSET (GtkTextLayoutClass, invalidated),
171 gtk_marshal_VOID__VOID,
176 gtk_signal_new ("changed",
178 GTK_CLASS_TYPE (object_class),
179 GTK_SIGNAL_OFFSET (GtkTextLayoutClass, changed),
180 gtk_marshal_VOID__INT_INT_INT,
187 signals[ALLOCATE_CHILD] =
188 gtk_signal_new ("allocate_child",
190 GTK_CLASS_TYPE (object_class),
191 GTK_SIGNAL_OFFSET (GtkTextLayoutClass, allocate_child),
192 gtk_marshal_VOID__OBJECT_INT_INT,
199 gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
201 object_class->destroy = gtk_text_layout_destroy;
202 gobject_class->finalize = gtk_text_layout_finalize;
204 klass->wrap = gtk_text_layout_real_wrap;
205 klass->invalidate = gtk_text_layout_real_invalidate;
206 klass->free_line_data = gtk_text_layout_real_free_line_data;
210 gtk_text_layout_init (GtkTextLayout *text_layout)
212 text_layout->cursor_visible = TRUE;
216 gtk_text_layout_new (void)
218 return GTK_TEXT_LAYOUT (gtk_type_new (gtk_text_layout_get_type ()));
222 free_style_cache (GtkTextLayout *text_layout)
224 if (text_layout->one_style_cache)
226 gtk_text_attributes_unref (text_layout->one_style_cache);
227 text_layout->one_style_cache = NULL;
232 gtk_text_layout_destroy (GtkObject *object)
234 GtkTextLayout *layout;
236 layout = GTK_TEXT_LAYOUT (object);
238 gtk_text_layout_set_buffer (layout, NULL);
240 if (layout->default_style)
241 gtk_text_attributes_unref (layout->default_style);
242 layout->default_style = NULL;
244 if (layout->ltr_context)
246 g_object_unref (G_OBJECT (layout->ltr_context));
247 layout->ltr_context = NULL;
249 if (layout->rtl_context)
251 g_object_unref (G_OBJECT (layout->rtl_context));
252 layout->rtl_context = NULL;
255 (* parent_class->destroy) (object);
259 gtk_text_layout_finalize (GObject *object)
261 GtkTextLayout *text_layout;
263 text_layout = GTK_TEXT_LAYOUT (object);
265 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
269 gtk_text_layout_set_buffer (GtkTextLayout *layout,
270 GtkTextBuffer *buffer)
272 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
273 g_return_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer));
275 if (layout->buffer == buffer)
278 free_style_cache (layout);
282 gtk_text_btree_remove_view (_gtk_text_buffer_get_btree (layout->buffer),
285 gtk_object_unref (GTK_OBJECT (layout->buffer));
286 layout->buffer = NULL;
291 layout->buffer = buffer;
293 gtk_object_sink (GTK_OBJECT (buffer));
294 gtk_object_ref (GTK_OBJECT (buffer));
296 gtk_text_btree_add_view (_gtk_text_buffer_get_btree (buffer), layout);
301 gtk_text_layout_default_style_changed (GtkTextLayout *layout)
303 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
305 gtk_text_layout_invalidate_all (layout);
309 gtk_text_layout_set_default_style (GtkTextLayout *layout,
310 GtkTextAttributes *values)
312 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
313 g_return_if_fail (values != NULL);
315 if (values == layout->default_style)
318 gtk_text_attributes_ref (values);
320 if (layout->default_style)
321 gtk_text_attributes_unref (layout->default_style);
323 layout->default_style = values;
325 gtk_text_layout_default_style_changed (layout);
329 gtk_text_layout_set_contexts (GtkTextLayout *layout,
330 PangoContext *ltr_context,
331 PangoContext *rtl_context)
333 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
335 if (layout->ltr_context)
336 g_object_unref (G_OBJECT (ltr_context));
338 layout->ltr_context = ltr_context;
339 g_object_ref (G_OBJECT (ltr_context));
341 if (layout->rtl_context)
342 g_object_unref (G_OBJECT (rtl_context));
344 layout->rtl_context = rtl_context;
345 g_object_ref (G_OBJECT (rtl_context));
347 gtk_text_layout_invalidate_all (layout);
351 gtk_text_layout_set_screen_width (GtkTextLayout *layout, gint width)
353 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
354 g_return_if_fail (width >= 0);
355 g_return_if_fail (layout->wrap_loop_count == 0);
357 if (layout->screen_width == width)
360 layout->screen_width = width;
362 gtk_text_layout_invalidate_all (layout);
366 * gtk_text_layout_set_cursor_visible:
367 * @layout: a #GtkTextLayout
368 * @cursor_visible: If %FALSE, then the insertion cursor will not
369 * be shown, even if the text is editable.
371 * Sets whether the insertion cursor should be shown. Generally,
372 * widgets using #GtkTextLayout will hide the cursor when the
373 * widget does not have the input focus.
376 gtk_text_layout_set_cursor_visible (GtkTextLayout *layout,
377 gboolean cursor_visible)
379 cursor_visible = (cursor_visible != FALSE);
381 if (layout->cursor_visible != cursor_visible)
386 layout->cursor_visible = cursor_visible;
388 /* Now queue a redraw on the paragraph containing the cursor
390 gtk_text_buffer_get_iter_at_mark (layout->buffer, &iter,
391 gtk_text_buffer_get_mark (layout->buffer, "insert"));
393 gtk_text_layout_get_line_yrange (layout, &iter, &y, &height);
394 gtk_text_layout_changed (layout, y, height, height);
396 gtk_text_layout_invalidate_cache (layout, gtk_text_iter_get_text_line (&iter));
401 * gtk_text_layout_get_cursor_visible:
402 * @layout: a #GtkTextLayout
404 * Returns whether the insertion cursor will be shown.
406 * Return value: if %FALSE, the insertion cursor will not be
407 shown, even if the text is editable.
410 gtk_text_layout_get_cursor_visible (GtkTextLayout *layout)
412 return layout->cursor_visible;
416 * gtk_text_layout_set_preedit_string:
417 * @layout: a #PangoLayout
418 * @preedit_string: a string to display at the insertion point
419 * @preedit_attrs: a #PangoAttrList of attributes that apply to @preedit_string
420 * @cursor_pos: position of cursor within preedit string in chars
422 * Set the preedit string and attributes. The preedit string is a
423 * string showing text that is currently being edited and not
424 * yet committed into the buffer.
427 gtk_text_layout_set_preedit_string (GtkTextLayout *layout,
428 const gchar *preedit_string,
429 PangoAttrList *preedit_attrs,
434 GtkTextLineData *line_data;
436 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
437 g_return_if_fail (preedit_attrs != NULL || preedit_string == NULL);
439 if (layout->preedit_string)
440 g_free (layout->preedit_string);
442 if (layout->preedit_attrs)
443 pango_attr_list_unref (layout->preedit_attrs);
447 layout->preedit_string = g_strdup (preedit_string);
448 layout->preedit_len = strlen (layout->preedit_string);
449 pango_attr_list_ref (preedit_attrs);
450 layout->preedit_attrs = preedit_attrs;
452 cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (layout->preedit_string, -1));
453 layout->preedit_cursor = g_utf8_offset_to_pointer (layout->preedit_string, cursor_pos) - layout->preedit_string;
457 layout->preedit_string = NULL;
458 layout->preedit_len = 0;
459 layout->preedit_attrs = NULL;
460 layout->preedit_cursor = 0;
463 /* Now invalidate the paragraph containing the cursor
465 gtk_text_buffer_get_iter_at_mark (layout->buffer, &iter,
466 gtk_text_buffer_get_mark (layout->buffer, "insert"));
468 line = gtk_text_iter_get_text_line (&iter);
469 line_data = gtk_text_line_get_data (line, layout);
472 gtk_text_layout_invalidate_cache (layout, line);
473 gtk_text_line_invalidate_wrap (line, line_data);
474 gtk_text_layout_invalidated (layout);
479 gtk_text_layout_get_size (GtkTextLayout *layout,
485 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
487 gtk_text_btree_get_view_size (_gtk_text_buffer_get_btree (layout->buffer),
495 *width = layout->width;
498 *height = layout->height;
502 gtk_text_layout_invalidated (GtkTextLayout *layout)
504 gtk_signal_emit (GTK_OBJECT (layout), signals[INVALIDATED]);
508 gtk_text_layout_changed (GtkTextLayout *layout,
513 gtk_signal_emit (GTK_OBJECT (layout), signals[CHANGED], y, old_height, new_height);
517 gtk_text_layout_free_line_data (GtkTextLayout *layout,
519 GtkTextLineData *line_data)
521 (* GTK_TEXT_LAYOUT_GET_CLASS (layout)->free_line_data)
522 (layout, line, line_data);
526 gtk_text_layout_invalidate (GtkTextLayout *layout,
527 const GtkTextIter *start_index,
528 const GtkTextIter *end_index)
530 (* GTK_TEXT_LAYOUT_GET_CLASS (layout)->invalidate)
531 (layout, start_index, end_index);
535 gtk_text_layout_wrap (GtkTextLayout *layout,
538 GtkTextLineData *line_data)
540 return (* GTK_TEXT_LAYOUT_GET_CLASS (layout)->wrap) (layout, line, line_data);
544 gtk_text_layout_get_lines (GtkTextLayout *layout,
545 /* [top_y, bottom_y) */
550 GtkTextLine *first_btree_line;
551 GtkTextLine *last_btree_line;
555 g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), NULL);
556 g_return_val_if_fail (bottom_y > top_y, NULL);
561 gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer),
562 layout, top_y, first_line_y);
563 if (first_btree_line == NULL)
565 g_assert (top_y > 0);
570 /* -1 since bottom_y is one past */
572 gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer),
573 layout, bottom_y - 1, NULL);
575 if (!last_btree_line)
577 gtk_text_btree_get_line (_gtk_text_buffer_get_btree (layout->buffer),
578 gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1,
582 GtkTextLineData *ld = gtk_text_line_get_data (last_btree_line, layout);
587 g_assert (last_btree_line != NULL);
589 line = first_btree_line;
592 retval = g_slist_prepend (retval, line);
594 if (line == last_btree_line)
597 line = gtk_text_line_next (line);
600 retval = g_slist_reverse (retval);
606 invalidate_cached_style (GtkTextLayout *layout)
608 free_style_cache (layout);
611 /* These should be called around a loop which wraps a CONTIGUOUS bunch
612 * of display lines. If the lines aren't contiguous you can't call
616 gtk_text_layout_wrap_loop_start (GtkTextLayout *layout)
618 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
619 g_return_if_fail (layout->one_style_cache == NULL);
621 layout->wrap_loop_count += 1;
625 gtk_text_layout_wrap_loop_end (GtkTextLayout *layout)
627 g_return_if_fail (layout->wrap_loop_count > 0);
629 layout->wrap_loop_count -= 1;
631 if (layout->wrap_loop_count == 0)
633 /* We cache a some stuff if we're iterating over some lines wrapping
634 * them. This cleans it up.
636 /* Nuke our cached style */
637 invalidate_cached_style (layout);
638 g_assert (layout->one_style_cache == NULL);
643 gtk_text_layout_invalidate_all (GtkTextLayout *layout)
648 if (layout->buffer == NULL)
651 gtk_text_buffer_get_bounds (layout->buffer, &start, &end);
653 gtk_text_layout_invalidate (layout, &start, &end);
657 gtk_text_layout_invalidate_cache (GtkTextLayout *layout,
660 if (layout->one_display_cache && line == layout->one_display_cache->line)
662 GtkTextLineDisplay *tmp_display = layout->one_display_cache;
663 layout->one_display_cache = NULL;
664 gtk_text_layout_free_line_display (layout, tmp_display);
669 gtk_text_layout_real_invalidate (GtkTextLayout *layout,
670 const GtkTextIter *start,
671 const GtkTextIter *end)
674 GtkTextLine *last_line;
676 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
677 g_return_if_fail (layout->wrap_loop_count == 0);
680 gtk_text_view_index_spew (start_index, "invalidate start");
681 gtk_text_view_index_spew (end_index, "invalidate end");
684 last_line = gtk_text_iter_get_text_line (end);
685 line = gtk_text_iter_get_text_line (start);
689 GtkTextLineData *line_data = gtk_text_line_get_data (line, layout);
692 (line != last_line || !gtk_text_iter_starts_line (end)))
694 gtk_text_layout_invalidate_cache (layout, line);
695 gtk_text_line_invalidate_wrap (line, line_data);
698 if (line == last_line)
701 line = gtk_text_line_next (line);
704 gtk_text_layout_invalidated (layout);
708 gtk_text_layout_real_free_line_data (GtkTextLayout *layout,
710 GtkTextLineData *line_data)
712 if (layout->one_display_cache && line == layout->one_display_cache->line)
714 GtkTextLineDisplay *tmp_display = layout->one_display_cache;
715 layout->one_display_cache = NULL;
716 gtk_text_layout_free_line_display (layout, tmp_display);
725 * gtk_text_layout_is_valid:
726 * @layout: a #GtkTextLayout
728 * Check if there are any invalid regions in a #GtkTextLayout's buffer
730 * Return value: #TRUE if any invalid regions were found
733 gtk_text_layout_is_valid (GtkTextLayout *layout)
735 g_return_val_if_fail (layout != NULL, FALSE);
736 g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), FALSE);
738 return gtk_text_btree_is_valid (_gtk_text_buffer_get_btree (layout->buffer),
743 * gtk_text_layout_validate_yrange:
744 * @layout: a #GtkTextLayout
745 * @anchor: iter pointing into a line that will be used as the
747 * @y0: offset from the top of the line pointed to by @anchor at
748 * which to begin validation. (The offset here is in pixels
750 * @y1: offset from the top of the line pointed to by @anchor at
751 * which to end validation. (The offset here is in pixels
754 * Ensure that a region of a #GtkTextLayout is valid. The ::changed
755 * signal will be emitted if any lines are validated.
758 gtk_text_layout_validate_yrange (GtkTextLayout *layout,
764 GtkTextLine *first_line = NULL;
765 GtkTextLine *last_line = NULL;
767 gint delta_height = 0;
768 gint first_line_y = 0; /* Quiet GCC */
769 gint last_line_y = 0; /* Quiet GCC */
771 g_return_if_fail (layout != NULL);
772 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
779 /* Validate backwards from the anchor line to y0
781 line = gtk_text_iter_get_text_line (anchor);
783 while (line && seen < -y0)
785 GtkTextLineData *line_data = gtk_text_line_get_data (line, layout);
786 if (!line_data || !line_data->valid)
788 gint old_height = line_data ? line_data->height : 0;
790 gtk_text_btree_validate_line (_gtk_text_buffer_get_btree (layout->buffer),
792 line_data = gtk_text_line_get_data (line, layout);
794 delta_height += line_data->height - old_height;
797 first_line_y = -seen;
801 last_line_y = -seen + line_data->height;
805 seen += line_data->height;
806 line = gtk_text_line_previous (line);
809 /* Validate forwards to y1 */
810 line = gtk_text_iter_get_text_line (anchor);
812 while (line && seen < y1)
814 GtkTextLineData *line_data = gtk_text_line_get_data (line, layout);
815 if (!line_data || !line_data->valid)
817 gint old_height = line_data ? line_data->height : 0;
819 gtk_text_btree_validate_line (_gtk_text_buffer_get_btree (layout->buffer),
821 line_data = gtk_text_line_get_data (line, layout);
823 delta_height += line_data->height - old_height;
831 last_line_y = seen + line_data->height;
834 seen += line_data->height;
835 line = gtk_text_line_next (line);
838 /* If we found and validated any invalid lines, emit the changed singal
843 gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer),
846 gtk_text_layout_changed (layout,
848 last_line_y - first_line_y - delta_height,
849 last_line_y - first_line_y);
854 * gtk_text_layout_validate:
855 * @tree: a #GtkTextLayout
856 * @max_pixels: the maximum number of pixels to validate. (No more
857 * than one paragraph beyond this limit will be validated)
859 * Validate regions of a #GtkTextLayout. The ::changed signal will
860 * be emitted for each region validated.
863 gtk_text_layout_validate (GtkTextLayout *layout,
866 gint y, old_height, new_height;
868 g_return_if_fail (layout != NULL);
869 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
871 while (max_pixels > 0 &&
872 gtk_text_btree_validate (_gtk_text_buffer_get_btree (layout->buffer),
874 &y, &old_height, &new_height))
876 max_pixels -= new_height;
877 gtk_text_layout_changed (layout, y, old_height, new_height);
881 static GtkTextLineData*
882 gtk_text_layout_real_wrap (GtkTextLayout *layout,
885 GtkTextLineData *line_data)
887 GtkTextLineDisplay *display;
889 g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), NULL);
891 if (line_data == NULL)
893 line_data = gtk_text_line_data_new (layout, line);
894 gtk_text_line_add_data (line, line_data);
897 display = gtk_text_layout_get_line_display (layout, line, TRUE);
898 line_data->width = display->width;
899 line_data->height = display->height;
900 line_data->valid = TRUE;
901 gtk_text_layout_free_line_display (layout, display);
907 * Layout utility functions
910 /* If you get the style with get_style () you need to call
911 release_style () to free it. */
912 static GtkTextAttributes*
913 get_style (GtkTextLayout *layout,
914 const GtkTextIter *iter)
918 GtkTextAttributes *style;
920 /* If we have the one-style cache, then it means
921 that we haven't seen a toggle since we filled in the
924 if (layout->one_style_cache != NULL)
926 gtk_text_attributes_ref (layout->one_style_cache);
927 return layout->one_style_cache;
930 g_assert (layout->one_style_cache == NULL);
932 /* Get the tags at this spot */
933 tags = gtk_text_btree_get_tags (iter, &tag_count);
935 /* No tags, use default style */
936 if (tags == NULL || tag_count == 0)
938 /* One ref for the return value, one ref for the
939 layout->one_style_cache reference */
940 gtk_text_attributes_ref (layout->default_style);
941 gtk_text_attributes_ref (layout->default_style);
942 layout->one_style_cache = layout->default_style;
947 return layout->default_style;
950 /* Sort tags in ascending order of priority */
951 gtk_text_tag_array_sort (tags, tag_count);
953 style = gtk_text_attributes_new ();
955 gtk_text_attributes_copy (layout->default_style,
958 gtk_text_attributes_fill_from_tags (style,
964 g_assert (style->refcount == 1);
966 /* Leave this style as the last one seen */
967 g_assert (layout->one_style_cache == NULL);
968 gtk_text_attributes_ref (style); /* ref held by layout->one_style_cache */
969 layout->one_style_cache = style;
971 /* Returning yet another refcount */
976 release_style (GtkTextLayout *layout,
977 GtkTextAttributes *style)
979 g_return_if_fail (style != NULL);
980 g_return_if_fail (style->refcount > 0);
982 gtk_text_attributes_unref (style);
989 /* This function tries to optimize the case where a line
990 is completely invisible */
992 totally_invisible_line (GtkTextLayout *layout,
996 GtkTextLineSegment *seg;
999 /* If we have a cached style, then we know it does actually apply
1000 and we can just see if it is invisible. */
1001 if (layout->one_style_cache &&
1002 !layout->one_style_cache->invisible)
1004 /* Without the cache, we check if the first char is visible, if so
1005 we are partially visible. Note that we have to check this since
1006 we don't know the current invisible/noninvisible toggle state; this
1007 function can use the whole btree to get it right. */
1010 gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
1013 if (!gtk_text_btree_char_is_invisible (iter))
1018 seg = line->segments;
1022 if (seg->byte_count > 0)
1023 bytes += seg->byte_count;
1025 /* Note that these two tests can cause us to bail out
1026 when we shouldn't, because a higher-priority tag
1027 may override these settings. However the important
1028 thing is to only invisible really-invisible lines, rather
1029 than to invisible all really-invisible lines. */
1031 else if (seg->type == >k_text_toggle_on_type)
1033 invalidate_cached_style (layout);
1035 /* Bail out if an elision-unsetting tag begins */
1036 if (seg->body.toggle.info->tag->invisible_set &&
1037 !seg->body.toggle.info->tag->values->invisible)
1040 else if (seg->type == >k_text_toggle_off_type)
1042 invalidate_cached_style (layout);
1044 /* Bail out if an elision-setting tag ends */
1045 if (seg->body.toggle.info->tag->invisible_set &&
1046 seg->body.toggle.info->tag->values->invisible)
1053 if (seg != NULL) /* didn't reach line end */
1060 set_para_values (GtkTextLayout *layout,
1061 GtkTextAttributes *style,
1062 GtkTextLineDisplay *display,
1065 PangoAlignment pango_align = PANGO_ALIGN_LEFT;
1068 display->direction = style->direction;
1070 if (display->direction == GTK_TEXT_DIR_LTR)
1071 display->layout = pango_layout_new (layout->ltr_context);
1073 display->layout = pango_layout_new (layout->rtl_context);
1075 switch (style->justify)
1077 case GTK_JUSTIFY_LEFT:
1078 pango_align = (style->direction == GTK_TEXT_DIR_LTR) ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
1080 case GTK_JUSTIFY_RIGHT:
1081 pango_align = (style->direction == GTK_TEXT_DIR_LTR) ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
1083 case GTK_JUSTIFY_CENTER:
1084 pango_align = PANGO_ALIGN_CENTER;
1086 case GTK_JUSTIFY_FILL:
1087 g_warning ("FIXME we don't support GTK_JUSTIFY_FILL yet");
1090 g_assert_not_reached ();
1094 switch (pango_align)
1096 case PANGO_ALIGN_LEFT:
1099 case PANGO_ALIGN_RIGHT:
1102 case PANGO_ALIGN_CENTER:
1107 pango_layout_set_alignment (display->layout, pango_align);
1108 pango_layout_set_spacing (display->layout,
1109 style->pixels_inside_wrap * PANGO_SCALE);
1112 pango_layout_set_tabs (display->layout, style->tabs);
1114 display->top_margin = style->pixels_above_lines;
1115 display->height = style->pixels_above_lines + style->pixels_below_lines;
1116 display->bottom_margin = style->pixels_below_lines;
1117 display->left_margin = style->left_margin;
1118 display->right_margin = style->right_margin;
1120 if (style->indent < 0)
1122 /* This means the margins can be negative. FIXME
1123 * test that things work if they are.
1126 if (pango_align == PANGO_ALIGN_LEFT)
1127 display->left_margin += style->indent;
1128 else if (pango_align == PANGO_ALIGN_RIGHT)
1129 display->right_margin += style->indent;
1132 display->x_offset = display->left_margin;
1135 pango_layout_set_indent (display->layout,
1136 style->indent * PANGO_SCALE);
1138 switch (style->wrap_mode)
1140 case GTK_WRAPMODE_CHAR:
1141 /* FIXME: Handle this; for now, fall-through */
1142 case GTK_WRAPMODE_WORD:
1143 display->total_width = -1;
1144 layout_width = layout->screen_width - display->left_margin - display->right_margin;
1145 pango_layout_set_width (display->layout, layout_width * PANGO_SCALE);
1147 case GTK_WRAPMODE_NONE:
1148 display->total_width = MAX (layout->screen_width, layout->width) - display->left_margin - display->right_margin;
1153 static PangoAttribute *
1154 gtk_text_attr_appearance_copy (const PangoAttribute *attr)
1156 const GtkTextAttrAppearance *appearance_attr = (const GtkTextAttrAppearance *)attr;
1158 return gtk_text_attr_appearance_new (&appearance_attr->appearance);
1162 gtk_text_attr_appearance_destroy (PangoAttribute *attr)
1164 GtkTextAppearance *appearance = &((GtkTextAttrAppearance *)attr)->appearance;
1166 if (appearance->bg_stipple)
1167 gdk_drawable_unref (appearance->bg_stipple);
1168 if (appearance->fg_stipple)
1169 gdk_drawable_unref (appearance->fg_stipple);
1175 gtk_text_attr_appearance_compare (const PangoAttribute *attr1,
1176 const PangoAttribute *attr2)
1178 const GtkTextAppearance *appearance1 = &((const GtkTextAttrAppearance *)attr1)->appearance;
1179 const GtkTextAppearance *appearance2 = &((const GtkTextAttrAppearance *)attr2)->appearance;
1181 return (gdk_color_equal (&appearance1->fg_color, &appearance2->fg_color) &&
1182 gdk_color_equal (&appearance1->bg_color, &appearance2->bg_color) &&
1183 appearance1->fg_stipple == appearance2->fg_stipple &&
1184 appearance1->bg_stipple == appearance2->bg_stipple &&
1185 appearance1->underline == appearance2->underline &&
1186 appearance1->strikethrough == appearance2->strikethrough &&
1187 appearance1->draw_bg == appearance2->draw_bg);
1192 * gtk_text_attr_appearance_new:
1195 * Create a new font description attribute. (This attribute
1196 * allows setting family, style, weight, variant, stretch,
1197 * and size simultaneously.)
1201 static PangoAttribute *
1202 gtk_text_attr_appearance_new (const GtkTextAppearance *appearance)
1204 static PangoAttrClass klass = {
1206 gtk_text_attr_appearance_copy,
1207 gtk_text_attr_appearance_destroy,
1208 gtk_text_attr_appearance_compare
1211 GtkTextAttrAppearance *result;
1214 klass.type = gtk_text_attr_appearance_type =
1215 pango_attr_type_register ("GtkTextAttrAppearance");
1217 result = g_new (GtkTextAttrAppearance, 1);
1218 result->attr.klass = &klass;
1220 result->appearance = *appearance;
1222 if (appearance->bg_stipple)
1223 gdk_drawable_ref (appearance->bg_stipple);
1224 if (appearance->fg_stipple)
1225 gdk_drawable_ref (appearance->fg_stipple);
1227 return (PangoAttribute *)result;
1232 add_generic_attrs (GtkTextLayout *layout,
1233 GtkTextAppearance *appearance,
1235 PangoAttrList *attrs,
1240 PangoAttribute *attr;
1242 if (appearance->underline != PANGO_UNDERLINE_NONE)
1244 attr = pango_attr_underline_new (appearance->underline);
1246 attr->start_index = start;
1247 attr->end_index = start + byte_count;
1249 pango_attr_list_insert (attrs, attr);
1252 if (appearance->rise != 0)
1254 attr = pango_attr_rise_new (appearance->rise);
1256 attr->start_index = start;
1257 attr->end_index = start + byte_count;
1259 pango_attr_list_insert (attrs, attr);
1264 attr = gtk_text_attr_appearance_new (appearance);
1266 attr->start_index = start;
1267 attr->end_index = start + byte_count;
1269 ((GtkTextAttrAppearance *)attr)->appearance.is_text = is_text;
1271 pango_attr_list_insert (attrs, attr);
1276 add_text_attrs (GtkTextLayout *layout,
1277 GtkTextAttributes *style,
1279 PangoAttrList *attrs,
1283 PangoAttribute *attr;
1285 attr = pango_attr_font_desc_new (&style->font);
1286 attr->start_index = start;
1287 attr->end_index = start + byte_count;
1289 pango_attr_list_insert (attrs, attr);
1293 add_pixbuf_attrs (GtkTextLayout *layout,
1294 GtkTextLineDisplay *display,
1295 GtkTextAttributes *style,
1296 GtkTextLineSegment *seg,
1297 PangoAttrList *attrs,
1300 PangoAttribute *attr;
1301 PangoRectangle logical_rect;
1302 GtkTextPixbuf *pixbuf = &seg->body.pixbuf;
1305 width = gdk_pixbuf_get_width (pixbuf->pixbuf);
1306 height = gdk_pixbuf_get_height (pixbuf->pixbuf);
1309 logical_rect.y = -height * PANGO_SCALE;
1310 logical_rect.width = width * PANGO_SCALE;
1311 logical_rect.height = height * PANGO_SCALE;
1313 attr = pango_attr_shape_new (&logical_rect, &logical_rect);
1314 attr->start_index = start;
1315 attr->end_index = start + seg->byte_count;
1316 pango_attr_list_insert (attrs, attr);
1318 display->shaped_objects =
1319 g_slist_append (display->shaped_objects, pixbuf->pixbuf);
1323 add_child_attrs (GtkTextLayout *layout,
1324 GtkTextLineDisplay *display,
1325 GtkTextAttributes *style,
1326 GtkTextLineSegment *seg,
1327 PangoAttrList *attrs,
1330 PangoAttribute *attr;
1331 PangoRectangle logical_rect;
1332 GtkTextChildAnchor *anchor;
1339 anchor = seg->body.child.obj;
1341 tmp_list = seg->body.child.widgets;
1342 while (tmp_list != NULL)
1344 GtkWidget *child = tmp_list->data;
1346 if (_gtk_anchored_child_get_layout (child) == layout)
1351 gtk_widget_get_child_requisition (child, &req);
1354 height = req.height;
1356 display->shaped_objects =
1357 g_slist_append (display->shaped_objects, child);
1361 tmp_list = g_slist_next (tmp_list);
1364 if (tmp_list == NULL)
1366 /* No widget at this anchor in this display;
1373 if (layout->preedit_string)
1375 g_free (layout->preedit_string);
1376 layout->preedit_string = NULL;
1379 if (layout->preedit_attrs)
1381 pango_attr_list_unref (layout->preedit_attrs);
1382 layout->preedit_attrs = NULL;
1386 logical_rect.y = -height * PANGO_SCALE;
1387 logical_rect.width = width * PANGO_SCALE;
1388 logical_rect.height = height * PANGO_SCALE;
1390 attr = pango_attr_shape_new (&logical_rect, &logical_rect);
1391 attr->start_index = start;
1392 attr->end_index = start + seg->byte_count;
1393 pango_attr_list_insert (attrs, attr);
1397 add_cursor (GtkTextLayout *layout,
1398 GtkTextLineDisplay *display,
1399 GtkTextLineSegment *seg,
1402 PangoRectangle strong_pos, weak_pos;
1403 GtkTextCursorDisplay *cursor;
1405 /* Hide insertion cursor when we have a selection or the layout
1406 * user has hidden the cursor.
1408 if (gtk_text_btree_mark_is_insert (_gtk_text_buffer_get_btree (layout->buffer),
1409 seg->body.mark.obj) &&
1410 (!layout->cursor_visible ||
1411 gtk_text_buffer_get_selection_bounds (layout->buffer, NULL, NULL)))
1414 pango_layout_get_cursor_pos (display->layout, start, &strong_pos, &weak_pos);
1416 cursor = g_new (GtkTextCursorDisplay, 1);
1418 cursor->x = PANGO_PIXELS (strong_pos.x);
1419 cursor->y = PANGO_PIXELS (strong_pos.y);
1420 cursor->height = PANGO_PIXELS (strong_pos.height);
1421 cursor->is_strong = TRUE;
1422 display->cursors = g_slist_prepend (display->cursors, cursor);
1424 if (weak_pos.x == strong_pos.x)
1425 cursor->is_weak = TRUE;
1428 cursor->is_weak = FALSE;
1430 cursor = g_new (GtkTextCursorDisplay, 1);
1432 cursor->x = PANGO_PIXELS (weak_pos.x);
1433 cursor->y = PANGO_PIXELS (weak_pos.y);
1434 cursor->height = PANGO_PIXELS (weak_pos.height);
1435 cursor->is_strong = FALSE;
1436 cursor->is_weak = TRUE;
1437 display->cursors = g_slist_prepend (display->cursors, cursor);
1442 allocate_child_widgets (GtkTextLayout *layout,
1443 GtkTextLineDisplay *display)
1447 gtk_signal_emit (GTK_OBJECT (layout),
1448 signals[ALLOCATE_CHILD],
1455 convert_color (GdkColor *result,
1456 PangoAttrColor *attr)
1458 result->red = attr->red;
1459 result->blue = attr->blue;
1460 result->green = attr->green;
1463 /* This function is used to convert the preedit string attributes, which are
1464 * standard PangoAttributes, into the custom attributes used by the text
1465 * widget and insert them into a attr list with a given offset.
1468 add_preedit_attrs (GtkTextLayout *layout,
1469 GtkTextAttributes *style,
1470 PangoAttrList *attrs,
1474 PangoAttrIterator *iter = pango_attr_list_get_iterator (layout->preedit_attrs);
1478 GtkTextAppearance appearance = style->appearance;
1479 PangoFontDescription font_desc;
1480 PangoAttribute *insert_attr;
1481 GSList *extra_attrs = NULL;
1485 pango_attr_iterator_range (iter, &start, &end);
1487 if (end == G_MAXINT)
1488 end = layout->preedit_len;
1490 pango_attr_iterator_get_font (iter, &style->font,
1491 &font_desc, size_only ? NULL : &extra_attrs);
1493 tmp_list = extra_attrs;
1496 PangoAttribute *attr = tmp_list->data;
1498 switch (attr->klass->type)
1500 case PANGO_ATTR_FOREGROUND:
1501 convert_color (&appearance.fg_color, (PangoAttrColor *)attr);
1503 case PANGO_ATTR_BACKGROUND:
1504 convert_color (&appearance.bg_color, (PangoAttrColor *)attr);
1505 appearance.draw_bg = TRUE;
1507 case PANGO_ATTR_UNDERLINE:
1508 appearance.underline = ((PangoAttrInt *)attr)->value;
1510 case PANGO_ATTR_STRIKETHROUGH:
1511 appearance.strikethrough = ((PangoAttrInt *)attr)->value;
1513 case PANGO_ATTR_RISE:
1514 appearance.rise = ((PangoAttrInt *)attr)->value;
1520 pango_attribute_destroy (attr);
1521 tmp_list = tmp_list->next;
1524 g_slist_free (extra_attrs);
1526 insert_attr = pango_attr_font_desc_new (&font_desc);
1527 insert_attr->start_index = start + offset;
1528 insert_attr->end_index = end + offset;
1530 pango_attr_list_insert (attrs, insert_attr);
1532 add_generic_attrs (layout, &appearance, end - start,
1533 attrs, start + offset,
1536 while (pango_attr_iterator_next (iter));
1538 pango_attr_iterator_destroy (iter);
1541 GtkTextLineDisplay *
1542 gtk_text_layout_get_line_display (GtkTextLayout *layout,
1546 GtkTextLineDisplay *display;
1547 GtkTextLineSegment *seg;
1549 GtkTextAttributes *style;
1551 PangoAttrList *attrs;
1552 gint byte_count, byte_offset;
1554 PangoRectangle extents;
1555 gboolean para_values_set = FALSE;
1556 GSList *cursor_byte_offsets = NULL;
1557 GSList *cursor_segs = NULL;
1558 GSList *tmp_list1, *tmp_list2;
1560 g_return_val_if_fail (line != NULL, NULL);
1562 if (layout->one_display_cache)
1564 if (line == layout->one_display_cache->line &&
1565 (size_only || !layout->one_display_cache->size_only))
1566 return layout->one_display_cache;
1569 GtkTextLineDisplay *tmp_display = layout->one_display_cache;
1570 layout->one_display_cache = NULL;
1571 gtk_text_layout_free_line_display (layout, tmp_display);
1575 display = g_new0 (GtkTextLineDisplay, 1);
1577 display->size_only = size_only;
1578 display->line = line;
1579 display->insert_index = -1;
1581 gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
1584 /* Special-case optimization for completely
1585 * invisible lines; makes it faster to deal
1586 * with sequences of invisible lines.
1588 if (totally_invisible_line (layout, line, &iter))
1591 /* Allocate space for flat text for buffer
1593 byte_count = gtk_text_line_byte_count (line);
1594 text = g_malloc (byte_count);
1596 attrs = pango_attr_list_new ();
1598 /* Iterate over segments, creating display chunks for them. */
1600 seg = gtk_text_iter_get_any_segment (&iter);
1603 /* Displayable segments */
1604 if (seg->type == >k_text_char_type ||
1605 seg->type == >k_text_pixbuf_type ||
1606 seg->type == >k_text_child_type)
1608 gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
1611 style = get_style (layout, &iter);
1613 /* We have to delay setting the paragraph values until we
1614 * hit the first pixbuf or text segment because toggles at
1615 * the beginning of the paragraph should affect the
1616 * paragraph-global values
1618 if (!para_values_set)
1620 set_para_values (layout, style, display, &align);
1621 para_values_set = TRUE;
1624 /* First see if the chunk is invisible, and ignore it if so. Tk
1625 * looked at tabs, wrap mode, etc. before doing this, but
1626 * that made no sense to me, so I am just skipping the
1629 if (!style->invisible)
1631 if (seg->type == >k_text_char_type)
1633 /* We don't want to split segments because of marks,
1634 * so we scan forward for more segments only
1635 * separated from us by marks. In theory, we should
1636 * also merge segments with identical styles, even
1637 * if there are toggles in-between
1640 gint byte_count = 0;
1641 GtkTextLineSegment *prev_seg = NULL;
1645 if (seg->type == >k_text_char_type)
1647 memcpy (text + byte_offset, seg->body.chars, seg->byte_count);
1648 byte_offset += seg->byte_count;
1649 byte_count += seg->byte_count;
1651 else if (seg->type == >k_text_right_mark_type ||
1652 seg->type == >k_text_left_mark_type)
1654 /* If we have preedit string, break out of this loop - we'll almost
1655 * certainly have different attributes on the preedit string
1658 if (layout->preedit_len > 0 &&
1659 gtk_text_btree_mark_is_insert (_gtk_text_buffer_get_btree (layout->buffer),
1660 seg->body.mark.obj))
1663 if (seg->body.mark.visible)
1665 cursor_byte_offsets = g_slist_prepend (cursor_byte_offsets, GINT_TO_POINTER (byte_offset));
1666 cursor_segs = g_slist_prepend (cursor_segs, seg);
1676 seg = prev_seg; /* Back up one */
1677 add_generic_attrs (layout, &style->appearance,
1679 attrs, byte_offset - byte_count,
1681 add_text_attrs (layout, style, byte_count, attrs,
1682 byte_offset - byte_count, size_only);
1684 else if (seg->type == >k_text_pixbuf_type)
1686 add_generic_attrs (layout,
1691 add_pixbuf_attrs (layout, display, style,
1692 seg, attrs, byte_offset);
1693 memcpy (text + byte_offset, gtk_text_unknown_char_utf8,
1695 byte_offset += seg->byte_count;
1697 else if (seg->type == >k_text_child_type)
1699 add_generic_attrs (layout, &style->appearance,
1703 add_child_attrs (layout, display, style,
1704 seg, attrs, byte_offset);
1705 memcpy (text + byte_offset, gtk_text_unknown_char_utf8,
1707 byte_offset += seg->byte_count;
1711 g_assert_not_reached ();
1715 release_style (layout, style);
1719 else if (seg->type == >k_text_toggle_on_type ||
1720 seg->type == >k_text_toggle_off_type)
1722 /* Style may have changed, drop our
1723 current cached style */
1724 invalidate_cached_style (layout);
1728 else if (seg->type == >k_text_right_mark_type ||
1729 seg->type == >k_text_left_mark_type)
1731 gint cursor_offset = 0;
1733 /* At the insertion point, add the preedit string, if any */
1735 if (gtk_text_btree_mark_is_insert (_gtk_text_buffer_get_btree (layout->buffer),
1736 seg->body.mark.obj))
1738 display->insert_index = byte_offset;
1740 if (layout->preedit_len > 0)
1742 byte_count += layout->preedit_len;
1743 text = g_realloc (text, byte_count);
1745 style = get_style (layout, &iter);
1746 add_preedit_attrs (layout, style, attrs, byte_offset, size_only);
1747 release_style (layout, style);
1749 memcpy (text + byte_offset, layout->preedit_string, layout->preedit_len);
1750 byte_offset += layout->preedit_len;
1752 cursor_offset = layout->preedit_cursor - layout->preedit_len;
1757 /* Display visible marks */
1759 if (seg->body.mark.visible)
1761 cursor_byte_offsets = g_slist_prepend (cursor_byte_offsets,
1762 GINT_TO_POINTER (byte_offset + cursor_offset));
1763 cursor_segs = g_slist_prepend (cursor_segs, seg);
1768 g_error ("Unknown segment type: %s", seg->type->name);
1773 if (!para_values_set)
1775 style = get_style (layout, &iter);
1776 set_para_values (layout, style, display, &align);
1777 release_style (layout, style);
1780 /* Pango doesn't want the trailing new line */
1781 if (byte_offset > 0 && text[byte_offset - 1] == '\n')
1784 pango_layout_set_text (display->layout, text, byte_offset);
1785 pango_layout_set_attributes (display->layout, attrs);
1787 tmp_list1 = cursor_byte_offsets;
1788 tmp_list2 = cursor_segs;
1791 add_cursor (layout, display, tmp_list2->data,
1792 GPOINTER_TO_INT (tmp_list1->data));
1793 tmp_list1 = tmp_list1->next;
1794 tmp_list2 = tmp_list2->next;
1796 g_slist_free (cursor_byte_offsets);
1797 g_slist_free (cursor_segs);
1799 pango_layout_get_extents (display->layout, NULL, &extents);
1801 if (display->total_width >= 0)
1802 display->x_offset += (display->total_width - PANGO_PIXELS (extents.width)) * align;
1804 display->width = PANGO_PIXELS (extents.width) + display->x_offset + display->right_margin;
1805 display->height += PANGO_PIXELS (extents.height);
1807 /* Free this if we aren't in a loop */
1808 if (layout->wrap_loop_count == 0)
1809 invalidate_cached_style (layout);
1812 pango_attr_list_unref (attrs);
1814 layout->one_display_cache = display;
1816 allocate_child_widgets (layout, display);
1822 gtk_text_layout_free_line_display (GtkTextLayout *layout,
1823 GtkTextLineDisplay *display)
1825 if (display != layout->one_display_cache)
1827 g_object_unref (G_OBJECT (display->layout));
1829 if (display->cursors)
1831 g_slist_foreach (display->cursors, (GFunc)g_free, NULL);
1832 g_slist_free (display->cursors);
1833 g_slist_free (display->shaped_objects);
1840 /* Functions to convert iter <=> index for the line of a GtkTextLineDisplay
1841 * taking into account the preedit string, if necessary.
1844 line_display_iter_to_index (GtkTextLayout *layout,
1845 GtkTextLineDisplay *display,
1846 const GtkTextIter *iter)
1850 g_return_val_if_fail (gtk_text_iter_get_text_line (iter) == display->line, 0);
1852 index = gtk_text_iter_get_line_index (iter);
1854 if (index >= display->insert_index)
1855 index += layout->preedit_len;
1861 line_display_index_to_iter (GtkTextLayout *layout,
1862 GtkTextLineDisplay *display,
1867 if (index >= display->insert_index + layout->preedit_len)
1868 index -= layout->preedit_len;
1869 else if (index > display->insert_index)
1871 index = display->insert_index;
1875 gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
1876 iter, display->line, index);
1877 gtk_text_iter_forward_chars (iter, trailing);
1880 /* FIXME: This really doesn't belong in this file ... */
1881 static GtkTextLineData*
1882 gtk_text_line_data_new (GtkTextLayout *layout,
1885 GtkTextLineData *line_data;
1887 line_data = g_new (GtkTextLineData, 1);
1889 line_data->view_id = layout;
1890 line_data->next = NULL;
1891 line_data->width = 0;
1892 line_data->height = 0;
1893 line_data->valid = FALSE;
1899 get_line_at_y (GtkTextLayout *layout,
1906 if (y > layout->height)
1909 *line = gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer),
1910 layout, y, line_top);
1913 *line = gtk_text_btree_get_line (_gtk_text_buffer_get_btree (layout->buffer),
1914 gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1, NULL);
1917 gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer),
1923 * gtk_text_layout_get_line_at_y:
1924 * @layout: a #GtkLayout
1925 * @target_iter: the iterator in which the result is stored
1926 * @y: the y positition
1927 * @line_top: location to store the y coordinate of the
1928 * top of the line. (Can by %NULL.)
1930 * Get the iter at the beginning of the line which is displayed
1934 gtk_text_layout_get_line_at_y (GtkTextLayout *layout,
1935 GtkTextIter *target_iter,
1941 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
1942 g_return_if_fail (target_iter != NULL);
1944 get_line_at_y (layout, y, &line, line_top);
1945 gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
1946 target_iter, line, 0);
1950 gtk_text_layout_get_iter_at_pixel (GtkTextLayout *layout,
1951 GtkTextIter *target_iter,
1955 gint byte_index, trailing;
1957 GtkTextLineDisplay *display;
1959 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
1960 g_return_if_fail (target_iter != NULL);
1962 /* Adjust pixels to be on-screen. This gives nice
1963 behavior if the user is dragging with a pointer grab.
1967 if (x > layout->width)
1970 get_line_at_y (layout, y, &line, &line_top);
1972 display = gtk_text_layout_get_line_display (layout, line, FALSE);
1974 x -= display->x_offset;
1975 y -= line_top + display->top_margin;
1977 /* We clamp y to the area of the actual layout so that the layouts
1978 * hit testing works OK on the space above and below the layout
1980 y = CLAMP (y, 0, display->height - display->top_margin - display->bottom_margin - 1);
1982 if (!pango_layout_xy_to_index (display->layout, x * PANGO_SCALE, y * PANGO_SCALE,
1983 &byte_index, &trailing))
1985 byte_index = gtk_text_line_byte_count (line);
1989 line_display_index_to_iter (layout, display, target_iter, byte_index, trailing);
1991 gtk_text_layout_free_line_display (layout, display);
1995 * gtk_text_layout_get_cursor_locations
1996 * @layout: a #GtkTextLayout
1997 * @iter: a #GtkTextIter
1998 * @strong_pos: location to store the strong cursor position (may be %NULL)
1999 * @weak_pos: location to store the weak cursor position (may be %NULL)
2001 * Given an iterator within a text laout, determine the positions that of the
2002 * strong and weak cursors if the insertion point is at that
2003 * iterator. The position of each cursor is stored as a zero-width
2004 * rectangle. The strong cursor location is the location where
2005 * characters of the directionality equal to the base direction of the
2006 * paragraph are inserted. The weak cursor location is the location
2007 * where characters of the directionality opposite to the base
2008 * direction of the paragraph are inserted.
2011 gtk_text_layout_get_cursor_locations (GtkTextLayout *layout,
2013 GdkRectangle *strong_pos,
2014 GdkRectangle *weak_pos)
2017 GtkTextLineDisplay *display;
2021 PangoRectangle pango_strong_pos;
2022 PangoRectangle pango_weak_pos;
2024 g_return_if_fail (layout != NULL);
2025 g_return_if_fail (iter != NULL);
2027 line = gtk_text_iter_get_text_line (iter);
2028 display = gtk_text_layout_get_line_display (layout, line, FALSE);
2029 index = line_display_iter_to_index (layout, display, iter);
2031 line_top = gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer),
2034 pango_layout_get_cursor_pos (display->layout, index,
2035 strong_pos ? &pango_strong_pos : NULL,
2036 weak_pos ? &pango_weak_pos : NULL);
2040 strong_pos->x = display->x_offset + pango_strong_pos.x / PANGO_SCALE;
2041 strong_pos->y = line_top + display->top_margin + pango_strong_pos.y / PANGO_SCALE;
2042 strong_pos->width = 0;
2043 strong_pos->height = pango_strong_pos.height / PANGO_SCALE;
2048 weak_pos->x = display->x_offset + pango_weak_pos.x / PANGO_SCALE;
2049 weak_pos->y = line_top + display->top_margin + pango_weak_pos.y / PANGO_SCALE;
2050 weak_pos->width = 0;
2051 weak_pos->height = pango_weak_pos.height / PANGO_SCALE;
2054 gtk_text_layout_free_line_display (layout, display);
2058 * gtk_text_layout_get_line_yrange:
2059 * @layout: a #GtkTextLayout
2060 * @iter: a #GtkTextIter
2061 * @y: location to store the top of the paragraph in pixels,
2063 * @height location to store the height of the paragraph in pixels,
2066 * Find the range of y coordinates for the paragraph containing
2070 gtk_text_layout_get_line_yrange (GtkTextLayout *layout,
2071 const GtkTextIter *iter,
2077 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
2078 g_return_if_fail (gtk_text_iter_get_btree (iter) == _gtk_text_buffer_get_btree (layout->buffer));
2080 line = gtk_text_iter_get_text_line (iter);
2083 *y = gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer),
2087 GtkTextLineData *line_data = gtk_text_line_get_data (line, layout);
2089 *height = line_data->height;
2096 gtk_text_layout_get_iter_location (GtkTextLayout *layout,
2097 const GtkTextIter *iter,
2100 PangoRectangle pango_rect;
2103 GtkTextLineDisplay *display;
2107 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
2108 g_return_if_fail (gtk_text_iter_get_btree (iter) == _gtk_text_buffer_get_btree (layout->buffer));
2109 g_return_if_fail (rect != NULL);
2111 tree = gtk_text_iter_get_btree (iter);
2112 line = gtk_text_iter_get_text_line (iter);
2114 display = gtk_text_layout_get_line_display (layout, line, FALSE);
2116 rect->y = gtk_text_btree_find_line_top (tree, line, layout);
2118 x_offset = display->x_offset * PANGO_SCALE;
2120 byte_index = gtk_text_iter_get_line_index (iter);
2122 pango_layout_index_to_pos (display->layout, byte_index, &pango_rect);
2124 rect->x = PANGO_PIXELS (x_offset + pango_rect.x);
2125 rect->y += PANGO_PIXELS (pango_rect.y) + display->top_margin;
2126 rect->width = PANGO_PIXELS (pango_rect.width);
2127 rect->height = PANGO_PIXELS (pango_rect.height);
2129 gtk_text_layout_free_line_display (layout, display);
2134 /* Find the iter for the logical beginning of the first display line whose
2135 * top y is >= y. If none exists, move the iter to the logical beginning
2136 * of the last line in the buffer.
2139 find_display_line_below (GtkTextLayout *layout,
2143 GtkTextLine *line, *next;
2144 GtkTextLine *found_line = NULL;
2146 gint found_byte = 0;
2148 line = gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer),
2149 layout, y, &line_top);
2153 gtk_text_btree_get_line (_gtk_text_buffer_get_btree (layout->buffer),
2154 gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1,
2157 gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer),
2161 while (line && !found_line)
2163 GtkTextLineDisplay *display = gtk_text_layout_get_line_display (layout, line, FALSE);
2164 gint byte_index = 0;
2165 PangoLayoutIter *layout_iter;
2167 layout_iter = pango_layout_get_iter (display->layout);
2169 line_top += display->top_margin;
2173 gint first_y, last_y;
2174 PangoLayoutLine *layout_line = pango_layout_iter_get_line (layout_iter);
2176 found_byte = byte_index;
2184 pango_layout_iter_get_line_yrange (layout_iter, &first_y, &last_y);
2185 line_top += (last_y - first_y) / PANGO_SCALE;
2187 byte_index += layout_line->length;
2189 while (pango_layout_iter_next_line (layout_iter));
2191 pango_layout_iter_free (layout_iter);
2193 line_top += display->bottom_margin;
2194 gtk_text_layout_free_line_display (layout, display);
2196 next = gtk_text_line_next (line);
2203 gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
2204 iter, found_line, found_byte);
2207 /* Find the iter for the logical beginning of the last display line whose
2208 * top y is >= y. If none exists, move the iter to the logical beginning
2209 * of the first line in the buffer.
2212 find_display_line_above (GtkTextLayout *layout,
2217 GtkTextLine *found_line = NULL;
2219 gint found_byte = 0;
2221 line = gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer), layout, y, &line_top);
2224 line = gtk_text_btree_get_line (_gtk_text_buffer_get_btree (layout->buffer),
2225 gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1, NULL);
2226 line_top = gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer), line, layout);
2229 while (line && !found_line)
2231 GtkTextLineDisplay *display = gtk_text_layout_get_line_display (layout, line, FALSE);
2232 PangoRectangle logical_rect;
2234 gint byte_index = 0;
2235 PangoLayoutIter *layout_iter;
2238 layout_iter = pango_layout_get_iter (display->layout);
2240 line_top -= display->top_margin + display->bottom_margin;
2241 pango_layout_iter_get_layout_extents (layout_iter, NULL, &logical_rect);
2242 line_top -= logical_rect.height / PANGO_SCALE;
2244 tmp_top = line_top + display->top_margin;
2248 gint first_y, last_y;
2249 PangoLayoutLine *layout_line = pango_layout_iter_get_line (layout_iter);
2251 found_byte = byte_index;
2253 pango_layout_iter_get_line_yrange (layout_iter, &first_y, &last_y);
2255 tmp_top -= (last_y - first_y) / PANGO_SCALE;
2260 found_byte = byte_index;
2264 byte_index += layout_line->length;
2266 while (pango_layout_iter_next_line (layout_iter));
2268 pango_layout_iter_free (layout_iter);
2270 gtk_text_layout_free_line_display (layout, display);
2272 line = gtk_text_line_previous (line);
2278 gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
2279 iter, found_line, found_byte);
2281 gtk_text_buffer_get_iter_at_offset (layout->buffer, iter, 0);
2285 * gtk_text_layout_clamp_iter_to_vrange:
2286 * @layout: a #GtkTextLayout
2287 * @iter: a #GtkTextIter
2288 * @top: the top of the range
2289 * @bottom: the bottom the range
2291 * If the iterator is not fully in the range @top <= y < @bottom,
2292 * then, if possible, move it the minimum distance so that the
2293 * iterator in this range.
2295 * Returns: %TRUE if the iterator was moved, otherwise %FALSE.
2298 gtk_text_layout_clamp_iter_to_vrange (GtkTextLayout *layout,
2303 GdkRectangle iter_rect;
2305 gtk_text_layout_get_iter_location (layout, iter, &iter_rect);
2307 /* If the iter is at least partially above the range, put the iter
2308 * at the first fully visible line after the range.
2310 if (iter_rect.y < top)
2312 find_display_line_below (layout, iter, top);
2316 /* Otherwise, if the iter is at least partially below the screen, put the
2317 * iter on the last logical position of the last completely visible
2320 else if (iter_rect.y + iter_rect.height > bottom)
2322 find_display_line_above (layout, iter, bottom);
2331 * gtk_text_layout_move_iter_to_next_line:
2332 * @layout: a #GtkLayout
2333 * @iter: a #GtkTextIter
2335 * Move the iterator to the beginning of the previous line. The lines
2336 * of a wrapped paragraph are treated as distinct for this operation.
2339 gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout,
2343 GtkTextLineDisplay *display;
2346 PangoLayoutLine *layout_line;
2348 g_return_if_fail (layout != NULL);
2349 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
2350 g_return_if_fail (iter != NULL);
2352 line = gtk_text_iter_get_text_line (iter);
2353 display = gtk_text_layout_get_line_display (layout, line, FALSE);
2354 line_byte = line_display_iter_to_index (layout, display, iter);
2356 tmp_list = pango_layout_get_lines (display->layout);
2357 layout_line = tmp_list->data;
2359 if (line_byte < layout_line->length || !tmp_list->next) /* first line of paragraph */
2361 GtkTextLine *prev_line = gtk_text_line_previous (line);
2365 gint byte_offset = 0;
2367 gtk_text_layout_free_line_display (layout, display);
2368 display = gtk_text_layout_get_line_display (layout, prev_line, FALSE);
2370 tmp_list = pango_layout_get_lines (display->layout);
2372 while (tmp_list->next)
2374 layout_line = tmp_list->data;
2375 tmp_list = tmp_list->next;
2377 byte_offset += layout_line->length;
2380 line_display_index_to_iter (layout, display, iter, byte_offset, 0);
2383 line_display_index_to_iter (layout, display, iter, 0, 0);
2387 gint prev_offset = 0;
2388 gint byte_offset = layout_line->length;
2390 tmp_list = tmp_list->next;
2393 layout_line = tmp_list->data;
2395 if (line_byte < byte_offset + layout_line->length || !tmp_list->next)
2397 line_display_index_to_iter (layout, display, iter, prev_offset, 0);
2401 prev_offset = byte_offset;
2402 byte_offset += layout_line->length;
2403 tmp_list = tmp_list->next;
2407 gtk_text_layout_free_line_display (layout, display);
2411 * gtk_text_layout_move_iter_to_next_line:
2412 * @layout: a #GtkLayout
2413 * @iter: a #GtkTextIter
2415 * Move the iterator to the beginning of the next line. The
2416 * lines of a wrapped paragraph are treated as distinct for
2420 gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout,
2424 GtkTextLineDisplay *display;
2427 gboolean found = FALSE;
2428 gboolean found_after = FALSE;
2429 gboolean first = TRUE;
2431 g_return_if_fail (layout != NULL);
2432 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
2433 g_return_if_fail (iter != NULL);
2435 line = gtk_text_iter_get_text_line (iter);
2437 while (line && !found_after)
2439 gint byte_offset = 0;
2442 display = gtk_text_layout_get_line_display (layout, line, FALSE);
2446 line_byte = line_display_iter_to_index (layout, display, iter);
2452 tmp_list = pango_layout_get_lines (display->layout);
2453 while (tmp_list && !found_after)
2455 PangoLayoutLine *layout_line = tmp_list->data;
2459 line_display_index_to_iter (layout, display, iter, byte_offset, 0);
2462 else if (line_byte < byte_offset + layout_line->length || !tmp_list->next)
2465 byte_offset += layout_line->length;
2466 tmp_list = tmp_list->next;
2469 gtk_text_layout_free_line_display (layout, display);
2471 line = gtk_text_line_next (line);
2476 * gtk_text_layout_move_iter_to_line_end:
2477 * @layout: a #GtkTextLayout
2478 * @direction: if negative, move to beginning of line, otherwise
2479 move to end of line.
2481 * Move to the beginning or end of a display line.
2484 gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout,
2489 GtkTextLineDisplay *display;
2491 gint byte_offset = 0;
2494 g_return_if_fail (layout != NULL);
2495 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
2496 g_return_if_fail (iter != NULL);
2498 line = gtk_text_iter_get_text_line (iter);
2499 display = gtk_text_layout_get_line_display (layout, line, FALSE);
2500 line_byte = line_display_iter_to_index (layout, display, iter);
2502 tmp_list = pango_layout_get_lines (display->layout);
2505 PangoLayoutLine *layout_line = tmp_list->data;
2507 if (line_byte < byte_offset + layout_line->length || !tmp_list->next)
2509 line_display_index_to_iter (layout, display, iter,
2510 direction < 0 ? byte_offset : byte_offset + layout_line->length,
2513 /* FIXME: As a bad hack, we move back one position to avoid going
2514 * to next line on a forced break not at whitespace. Real fix
2515 * is to keep track of whether marks are at leading or trailing edge?
2517 if (direction > 0 && layout_line->length > 0)
2518 gtk_text_iter_prev_char (iter);
2523 byte_offset += layout_line->length;
2524 tmp_list = tmp_list->next;
2527 gtk_text_layout_free_line_display (layout, display);
2531 * gtk_text_layout_move_iter_to_x:
2532 * @layout: a #GtkTextLayout
2533 * @iter: a #GtkTextIter
2536 * Keeping the iterator on the same line of the layout, move it to the
2537 * specified X coordinate. The lines of a wrapped paragraph are
2538 * treated as distinct for this operation.
2541 gtk_text_layout_move_iter_to_x (GtkTextLayout *layout,
2546 GtkTextLineDisplay *display;
2548 gint byte_offset = 0;
2549 PangoLayoutIter *layout_iter;
2551 g_return_if_fail (layout != NULL);
2552 g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
2553 g_return_if_fail (iter != NULL);
2555 line = gtk_text_iter_get_text_line (iter);
2557 display = gtk_text_layout_get_line_display (layout, line, FALSE);
2558 line_byte = line_display_iter_to_index (layout, display, iter);
2560 layout_iter = pango_layout_get_iter (display->layout);
2564 PangoLayoutLine *layout_line = pango_layout_iter_get_line (layout_iter);
2566 if (line_byte < byte_offset + layout_line->length ||
2567 pango_layout_iter_at_last_line (layout_iter))
2569 PangoRectangle logical_rect;
2570 gint byte_index, trailing;
2571 gint x_offset = display->x_offset * PANGO_SCALE;
2573 pango_layout_iter_get_line_extents (layout_iter, NULL, &logical_rect);
2575 pango_layout_line_x_to_index (layout_line,
2576 x * PANGO_SCALE - x_offset - logical_rect.x,
2577 &byte_index, &trailing);
2579 line_display_index_to_iter (layout, display, iter, byte_index, trailing);
2584 byte_offset += layout_line->length;
2586 while (pango_layout_iter_next_line (layout_iter));
2588 pango_layout_iter_free (layout_iter);
2590 gtk_text_layout_free_line_display (layout, display);
2594 * gtk_text_layout_move_iter_visually:
2595 * @layout: a #GtkTextLayout
2596 * @iter: a #GtkTextIter
2597 * @count: number of characters to move (negative moves left, positive moves right)
2599 * Move the iterator a given number of characters visually, treating
2600 * it as the strong cursor position. If @count is positive, then the
2601 * new strong cursor position will be @count positions to the right of
2602 * the old cursor position. If @count is negative then the new strong
2603 * cursor position will be @count positions to the left of the old
2606 * In the presence of bidirection text, the correspondence
2607 * between logical and visual order will depend on the direction
2608 * of the current run, and there may be jumps when the cursor
2609 * is moved off of the end of a run.
2613 gtk_text_layout_move_iter_visually (GtkTextLayout *layout,
2617 GtkTextLineDisplay *display = NULL;
2619 g_return_if_fail (layout != NULL);
2620 g_return_if_fail (iter != NULL);
2624 GtkTextLine *line = gtk_text_iter_get_text_line (iter);
2626 gint extra_back = 0;
2628 int byte_count = gtk_text_line_byte_count (line);
2635 display = gtk_text_layout_get_line_display (layout, line, FALSE);
2636 line_byte = line_display_iter_to_index (layout, display, iter);
2640 pango_layout_move_cursor_visually (display->layout, line_byte, 0, 1, &new_index, &new_trailing);
2645 pango_layout_move_cursor_visually (display->layout, line_byte, 0, -1, &new_index, &new_trailing);
2649 /* We need to handle the preedit string specially. Well, we don't really need to
2650 * handle it specially, since hopefully calling gtk_im_context_reset() will
2651 * remove the preedit string; but if we start off in front of the preedit
2652 * string (logically) and end up in or on the back edge of the preedit string,
2653 * we should move the iter one place farther.
2655 if (layout->preedit_len > 0 && display->insert_index >= 0)
2657 if (line_byte == display->insert_index + layout->preedit_len &&
2658 new_index < display->insert_index + layout->preedit_len)
2660 line_byte = display->insert_index;
2665 if (new_index < 0 || (new_index == 0 && extra_back))
2667 line = gtk_text_line_previous (line);
2672 gtk_text_layout_free_line_display (layout, display);
2673 display = gtk_text_layout_get_line_display (layout, line, FALSE);
2674 new_index = gtk_text_line_byte_count (line);
2676 else if (new_index > byte_count)
2678 line = gtk_text_line_next (line);
2682 gtk_text_layout_free_line_display (layout, display);
2683 display = gtk_text_layout_get_line_display (layout, line, FALSE);
2687 line_display_index_to_iter (layout, display, iter, new_index, new_trailing);
2689 gtk_text_iter_prev_char (iter);
2692 gtk_text_layout_free_line_display (layout, display);
2696 gtk_text_layout_spew (GtkTextLayout *layout)
2699 GtkTextDisplayLine *iter;
2701 guint paragraphs = 0;
2702 GtkTextLine *last_line = NULL;
2704 iter = layout->line_list;
2705 while (iter != NULL)
2707 if (iter->line != last_line)
2709 printf ("%5u paragraph (%p)\n", paragraphs, iter->line);
2711 last_line = iter->line;
2714 printf (" %5u y: %d len: %d start: %d bytes: %d\n",
2715 wrapped, iter->y, iter->length, iter->byte_offset,
2722 printf ("Layout %s recompute\n",
2723 layout->need_recompute ? "needs" : "doesn't need");
2725 printf ("Layout pars: %u lines: %u size: %d x %d Screen width: %d\n",
2726 paragraphs, wrapped, layout->width,
2727 layout->height, layout->screen_width);