]> Pileus Git - ~andy/gtk/blob - gtk/gtktextlayout.c
marshaller fixes.
[~andy/gtk] / gtk / gtktextlayout.c
1 /* GTK - The GIMP Toolkit
2  * gtktextlayout.c - calculate the layout of the text
3  *
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
9  *
10  * This file can be used under your choice of two licenses, the LGPL
11  * and the original Tk license.
12  *
13  * LGPL:
14  *
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.
19  *
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.
24  *
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.
28  *
29  * Original Tk license:
30  *
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.
35  *
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.
45  *
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.
51  *
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.
58  *
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.
70  *
71  */
72 /*
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/.
77  */
78
79 #include "gtksignal.h"
80 #include "gtktextlayout.h"
81 #include "gtktextbtree.h"
82 #include "gtktextiterprivate.h"
83
84 #include <stdlib.h>
85 #include <string.h>
86
87 static GtkTextLineData    *gtk_text_line_data_new                 (GtkTextLayout     *layout,
88                                                                    GtkTextLine       *line);
89
90 static GtkTextLineData *gtk_text_layout_real_wrap (GtkTextLayout *layout,
91                                                    GtkTextLine *line,
92                                                    /* may be NULL */
93                                                    GtkTextLineData *line_data);
94
95 static void gtk_text_layout_invalidated     (GtkTextLayout     *layout);
96
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,
101                                                  GtkTextLine       *line);
102 static void gtk_text_layout_real_free_line_data (GtkTextLayout     *layout,
103                                                  GtkTextLine       *line,
104                                                  GtkTextLineData   *line_data);
105
106 static void gtk_text_layout_invalidate_all (GtkTextLayout *layout);
107
108 static PangoAttribute *gtk_text_attr_appearance_new (const GtkTextAppearance *appearance);
109
110 enum {
111   INVALIDATED,
112   CHANGED,
113   ALLOCATE_CHILD,
114   LAST_SIGNAL
115 };
116
117 enum {
118   ARG_0,
119   LAST_ARG
120 };
121
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_finalize   (GObject            *object);
125
126
127 static GtkObjectClass *parent_class = NULL;
128 static guint signals[LAST_SIGNAL] = { 0 };
129
130 PangoAttrType gtk_text_attr_appearance_type = 0;
131
132 GType
133 gtk_text_layout_get_type (void)
134 {
135   static GType our_type = 0;
136
137   if (our_type == 0)
138     {
139       static const GTypeInfo our_info =
140       {
141         sizeof (GtkTextLayoutClass),
142         (GBaseInitFunc) NULL,
143         (GBaseFinalizeFunc) NULL,
144         (GClassInitFunc) gtk_text_layout_class_init,
145         NULL,           /* class_finalize */
146         NULL,           /* class_data */
147         sizeof (GtkTextLayout),
148         0,              /* n_preallocs */
149         (GInstanceInitFunc) gtk_text_layout_init
150       };
151
152       our_type = g_type_register_static (G_TYPE_OBJECT,
153                                          "GtkTextLayout",
154                                          &our_info,
155                                          0);
156     }
157
158   return our_type;
159 }
160
161 static void
162 gtk_text_layout_class_init (GtkTextLayoutClass *klass)
163 {
164   GObjectClass *object_class = G_OBJECT_CLASS (klass);
165
166   parent_class = g_type_class_peek_parent (klass);
167   
168   object_class->finalize = gtk_text_layout_finalize;
169
170   klass->wrap = gtk_text_layout_real_wrap;
171   klass->invalidate = gtk_text_layout_real_invalidate;
172   klass->free_line_data = gtk_text_layout_real_free_line_data;
173
174   signals[INVALIDATED] =
175     g_signal_newc ("invalidated",
176                    G_OBJECT_CLASS_TYPE (object_class),
177                    G_SIGNAL_RUN_LAST,
178                    G_STRUCT_OFFSET (GtkTextLayoutClass, invalidated),
179                    NULL,
180                    gtk_marshal_VOID__VOID,
181                    GTK_TYPE_NONE,
182                    0);
183
184   signals[CHANGED] =
185     g_signal_newc ("changed",
186                    G_OBJECT_CLASS_TYPE (object_class),
187                    G_SIGNAL_RUN_LAST,
188                    G_STRUCT_OFFSET (GtkTextLayoutClass, changed),
189                    NULL,
190                    gtk_marshal_VOID__INT_INT_INT,
191                    GTK_TYPE_NONE,
192                    3,
193                    GTK_TYPE_INT,
194                    GTK_TYPE_INT,
195                    GTK_TYPE_INT);
196
197   signals[ALLOCATE_CHILD] =
198     g_signal_newc ("allocate_child",
199                    G_OBJECT_CLASS_TYPE (object_class),
200                    G_SIGNAL_RUN_LAST,
201                    G_STRUCT_OFFSET (GtkTextLayoutClass, allocate_child),
202                    NULL,
203                    gtk_marshal_VOID__OBJECT_INT_INT,
204                    GTK_TYPE_NONE,
205                    3,
206                    GTK_TYPE_OBJECT,
207                    GTK_TYPE_INT,
208                    GTK_TYPE_INT);
209 }
210
211 void
212 gtk_text_layout_init (GtkTextLayout *text_layout)
213 {
214   text_layout->cursor_visible = TRUE;
215 }
216
217 GtkTextLayout*
218 gtk_text_layout_new (void)
219 {
220   return GTK_TEXT_LAYOUT (g_object_new (gtk_text_layout_get_type (), NULL));
221 }
222
223 static void
224 free_style_cache (GtkTextLayout *text_layout)
225 {
226   if (text_layout->one_style_cache)
227     {
228       gtk_text_attributes_unref (text_layout->one_style_cache);
229       text_layout->one_style_cache = NULL;
230     }
231 }
232
233 static void
234 gtk_text_layout_finalize (GObject *object)
235 {
236   GtkTextLayout *layout;
237
238   layout = GTK_TEXT_LAYOUT (object);
239
240   gtk_text_layout_set_buffer (layout, NULL);
241
242   if (layout->default_style)
243     gtk_text_attributes_unref (layout->default_style);
244   layout->default_style = NULL;
245
246   if (layout->ltr_context)
247     {
248       g_object_unref (G_OBJECT (layout->ltr_context));
249       layout->ltr_context = NULL;
250     }
251   if (layout->rtl_context)
252     {
253       g_object_unref (G_OBJECT (layout->rtl_context));
254       layout->rtl_context = NULL;
255     }
256   
257   (* G_OBJECT_CLASS (parent_class)->finalize) (object);
258 }
259
260 void
261 gtk_text_layout_set_buffer (GtkTextLayout *layout,
262                             GtkTextBuffer *buffer)
263 {
264   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
265   g_return_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer));
266
267   if (layout->buffer == buffer)
268     return;
269
270   free_style_cache (layout);
271
272   if (layout->buffer)
273     {
274       _gtk_text_btree_remove_view (_gtk_text_buffer_get_btree (layout->buffer),
275                                   layout);
276
277       g_object_unref (G_OBJECT (layout->buffer));
278       layout->buffer = NULL;
279     }
280
281   if (buffer)
282     {
283       layout->buffer = buffer;
284
285       g_object_ref (G_OBJECT (buffer));
286
287       _gtk_text_btree_add_view (_gtk_text_buffer_get_btree (buffer), layout);
288     }
289 }
290
291 void
292 gtk_text_layout_default_style_changed (GtkTextLayout *layout)
293 {
294   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
295
296   gtk_text_layout_invalidate_all (layout);
297 }
298
299 void
300 gtk_text_layout_set_default_style (GtkTextLayout *layout,
301                                    GtkTextAttributes *values)
302 {
303   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
304   g_return_if_fail (values != NULL);
305
306   if (values == layout->default_style)
307     return;
308
309   gtk_text_attributes_ref (values);
310
311   if (layout->default_style)
312     gtk_text_attributes_unref (layout->default_style);
313
314   layout->default_style = values;
315
316   gtk_text_layout_default_style_changed (layout);
317 }
318
319 void
320 gtk_text_layout_set_contexts (GtkTextLayout *layout,
321                               PangoContext  *ltr_context,
322                               PangoContext  *rtl_context)
323 {
324   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
325
326   if (layout->ltr_context)
327     g_object_unref (G_OBJECT (ltr_context));
328
329   layout->ltr_context = ltr_context;
330   g_object_ref (G_OBJECT (ltr_context));
331
332   if (layout->rtl_context)
333     g_object_unref (G_OBJECT (rtl_context));
334
335   layout->rtl_context = rtl_context;
336   g_object_ref (G_OBJECT (rtl_context));
337
338   gtk_text_layout_invalidate_all (layout);
339 }
340
341 void
342 gtk_text_layout_set_screen_width (GtkTextLayout *layout, gint width)
343 {
344   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
345   g_return_if_fail (width >= 0);
346   g_return_if_fail (layout->wrap_loop_count == 0);
347
348   if (layout->screen_width == width)
349     return;
350
351   layout->screen_width = width;
352
353   gtk_text_layout_invalidate_all (layout);
354 }
355
356 /**
357  * gtk_text_layout_set_cursor_visible:
358  * @layout: a #GtkTextLayout
359  * @cursor_visible: If %FALSE, then the insertion cursor will not
360  *   be shown, even if the text is editable.
361  *
362  * Sets whether the insertion cursor should be shown. Generally,
363  * widgets using #GtkTextLayout will hide the cursor when the
364  * widget does not have the input focus.
365  **/
366 void
367 gtk_text_layout_set_cursor_visible (GtkTextLayout *layout,
368                                     gboolean       cursor_visible)
369 {
370   cursor_visible = (cursor_visible != FALSE);
371
372   if (layout->cursor_visible != cursor_visible)
373     {
374       GtkTextIter iter;
375       gint y, height;
376
377       layout->cursor_visible = cursor_visible;
378
379       /* Now queue a redraw on the paragraph containing the cursor
380        */
381       gtk_text_buffer_get_iter_at_mark (layout->buffer, &iter,
382                                         gtk_text_buffer_get_mark (layout->buffer, "insert"));
383
384       gtk_text_layout_get_line_yrange (layout, &iter, &y, &height);
385       gtk_text_layout_changed (layout, y, height, height);
386
387       gtk_text_layout_invalidate_cache (layout, _gtk_text_iter_get_text_line (&iter));
388     }
389 }
390
391 /**
392  * gtk_text_layout_get_cursor_visible:
393  * @layout: a #GtkTextLayout
394  *
395  * Returns whether the insertion cursor will be shown.
396  *
397  * Return value: if %FALSE, the insertion cursor will not be
398     shown, even if the text is editable.
399  **/
400 gboolean
401 gtk_text_layout_get_cursor_visible (GtkTextLayout *layout)
402 {
403   return layout->cursor_visible;
404 }
405
406 /**
407  * gtk_text_layout_set_preedit_string:
408  * @layout: a #PangoLayout
409  * @preedit_string: a string to display at the insertion point
410  * @preedit_attrs: a #PangoAttrList of attributes that apply to @preedit_string
411  * @cursor_pos: position of cursor within preedit string in chars
412  * 
413  * Set the preedit string and attributes. The preedit string is a
414  * string showing text that is currently being edited and not
415  * yet committed into the buffer.
416  **/
417 void
418 gtk_text_layout_set_preedit_string (GtkTextLayout *layout,
419                                     const gchar   *preedit_string,
420                                     PangoAttrList *preedit_attrs,
421                                     gint           cursor_pos)
422 {
423   GtkTextIter iter;
424   GtkTextLine *line;
425   GtkTextLineData *line_data;
426
427   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
428   g_return_if_fail (preedit_attrs != NULL || preedit_string == NULL);
429
430   if (layout->preedit_string)
431     g_free (layout->preedit_string);
432
433   if (layout->preedit_attrs)
434     pango_attr_list_unref (layout->preedit_attrs);
435
436   if (preedit_string)
437     {
438       layout->preedit_string = g_strdup (preedit_string);
439       layout->preedit_len = strlen (layout->preedit_string);
440       pango_attr_list_ref (preedit_attrs);
441       layout->preedit_attrs = preedit_attrs;
442
443       cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (layout->preedit_string, -1));
444       layout->preedit_cursor = g_utf8_offset_to_pointer (layout->preedit_string, cursor_pos) - layout->preedit_string;
445     }
446   else
447     {
448       layout->preedit_string = NULL;
449       layout->preedit_len = 0;
450       layout->preedit_attrs = NULL;
451       layout->preedit_cursor = 0;
452     }
453
454   /* Now invalidate the paragraph containing the cursor
455    */
456   gtk_text_buffer_get_iter_at_mark (layout->buffer, &iter,
457                                     gtk_text_buffer_get_mark (layout->buffer, "insert"));
458   
459   line = _gtk_text_iter_get_text_line (&iter);
460   line_data = _gtk_text_line_get_data (line, layout);
461   if (line_data)
462     {
463       gtk_text_layout_invalidate_cache (layout, line);
464       _gtk_text_line_invalidate_wrap (line, line_data);
465       gtk_text_layout_invalidated (layout);
466     }
467 }
468
469 void
470 gtk_text_layout_get_size (GtkTextLayout *layout,
471                           gint *width,
472                           gint *height)
473 {
474   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
475
476   if (width)
477     *width = layout->width;
478
479   if (height)
480     *height = layout->height;
481 }
482
483 static void
484 gtk_text_layout_invalidated (GtkTextLayout *layout)
485 {
486   g_signal_emit (G_OBJECT (layout), signals[INVALIDATED], 0);
487 }
488
489 void
490 gtk_text_layout_changed (GtkTextLayout *layout,
491                          gint           y,
492                          gint           old_height,
493                          gint           new_height)
494 {
495   g_signal_emit (G_OBJECT (layout), signals[CHANGED], 0,
496                  y, old_height, new_height);
497 }
498
499 void
500 gtk_text_layout_free_line_data (GtkTextLayout     *layout,
501                                 GtkTextLine       *line,
502                                 GtkTextLineData   *line_data)
503 {
504   (* GTK_TEXT_LAYOUT_GET_CLASS (layout)->free_line_data)
505     (layout, line, line_data);
506 }
507
508 void
509 gtk_text_layout_invalidate (GtkTextLayout *layout,
510                             const GtkTextIter *start_index,
511                             const GtkTextIter *end_index)
512 {
513   (* GTK_TEXT_LAYOUT_GET_CLASS (layout)->invalidate)
514     (layout, start_index, end_index);
515 }
516
517 GtkTextLineData*
518 gtk_text_layout_wrap (GtkTextLayout *layout,
519                       GtkTextLine  *line,
520                       /* may be NULL */
521                       GtkTextLineData *line_data)
522 {
523   return (* GTK_TEXT_LAYOUT_GET_CLASS (layout)->wrap) (layout, line, line_data);
524 }
525
526 GSList*
527 gtk_text_layout_get_lines (GtkTextLayout *layout,
528                            /* [top_y, bottom_y) */
529                            gint top_y,
530                            gint bottom_y,
531                            gint *first_line_y)
532 {
533   GtkTextLine *first_btree_line;
534   GtkTextLine *last_btree_line;
535   GtkTextLine *line;
536   GSList *retval;
537
538   g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), NULL);
539   g_return_val_if_fail (bottom_y > top_y, NULL);
540
541   retval = NULL;
542
543   first_btree_line =
544     _gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer),
545                                    layout, top_y, first_line_y);
546   if (first_btree_line == NULL)
547     {
548       g_assert (top_y > 0);
549       /* off the bottom */
550       return NULL;
551     }
552
553   /* -1 since bottom_y is one past */
554   last_btree_line =
555     _gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer),
556                                    layout, bottom_y - 1, NULL);
557
558   if (!last_btree_line)
559     last_btree_line =
560       _gtk_text_btree_get_line (_gtk_text_buffer_get_btree (layout->buffer),
561                                _gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1,
562                                NULL);
563
564   {
565     GtkTextLineData *ld = _gtk_text_line_get_data (last_btree_line, layout);
566     if (ld->height == 0)
567       G_BREAKPOINT ();
568   }
569
570   g_assert (last_btree_line != NULL);
571
572   line = first_btree_line;
573   while (TRUE)
574     {
575       retval = g_slist_prepend (retval, line);
576
577       if (line == last_btree_line)
578         break;
579
580       line = _gtk_text_line_next (line);
581     }
582
583   retval = g_slist_reverse (retval);
584
585   return retval;
586 }
587
588 static void
589 invalidate_cached_style (GtkTextLayout *layout)
590 {
591   free_style_cache (layout);
592 }
593
594 /* These should be called around a loop which wraps a CONTIGUOUS bunch
595  * of display lines. If the lines aren't contiguous you can't call
596  * these.
597  */
598 void
599 gtk_text_layout_wrap_loop_start (GtkTextLayout *layout)
600 {
601   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
602   g_return_if_fail (layout->one_style_cache == NULL);
603
604   layout->wrap_loop_count += 1;
605 }
606
607 void
608 gtk_text_layout_wrap_loop_end (GtkTextLayout *layout)
609 {
610   g_return_if_fail (layout->wrap_loop_count > 0);
611
612   layout->wrap_loop_count -= 1;
613
614   if (layout->wrap_loop_count == 0)
615     {
616       /* We cache a some stuff if we're iterating over some lines wrapping
617        * them. This cleans it up.
618        */
619       /* Nuke our cached style */
620       invalidate_cached_style (layout);
621       g_assert (layout->one_style_cache == NULL);
622     }
623 }
624
625 static void
626 gtk_text_layout_invalidate_all (GtkTextLayout *layout)
627 {
628   GtkTextIter start;
629   GtkTextIter end;
630
631   if (layout->buffer == NULL)
632     return;
633
634   gtk_text_buffer_get_bounds (layout->buffer, &start, &end);
635
636   gtk_text_layout_invalidate (layout, &start, &end);
637 }
638
639 static void
640 gtk_text_layout_invalidate_cache (GtkTextLayout *layout,
641                                   GtkTextLine   *line)
642 {
643   if (layout->one_display_cache && line == layout->one_display_cache->line)
644     {
645       GtkTextLineDisplay *tmp_display = layout->one_display_cache;
646       layout->one_display_cache = NULL;
647       gtk_text_layout_free_line_display (layout, tmp_display);
648     }
649 }
650
651 static void
652 gtk_text_layout_real_invalidate (GtkTextLayout *layout,
653                                  const GtkTextIter *start,
654                                  const GtkTextIter *end)
655 {
656   GtkTextLine *line;
657   GtkTextLine *last_line;
658
659   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
660   g_return_if_fail (layout->wrap_loop_count == 0);
661
662 #if 0
663   gtk_text_view_index_spew (start_index, "invalidate start");
664   gtk_text_view_index_spew (end_index, "invalidate end");
665 #endif
666
667   last_line = _gtk_text_iter_get_text_line (end);
668   line = _gtk_text_iter_get_text_line (start);
669
670   while (TRUE)
671     {
672       GtkTextLineData *line_data = _gtk_text_line_get_data (line, layout);
673
674       if (line_data &&
675           (line != last_line || !gtk_text_iter_starts_line (end)))
676         {
677           gtk_text_layout_invalidate_cache (layout, line);
678           _gtk_text_line_invalidate_wrap (line, line_data);
679         }
680
681       if (line == last_line)
682         break;
683
684       line = _gtk_text_line_next (line);
685     }
686
687   gtk_text_layout_invalidated (layout);
688 }
689
690 static void
691 gtk_text_layout_real_free_line_data (GtkTextLayout     *layout,
692                                      GtkTextLine       *line,
693                                      GtkTextLineData   *line_data)
694 {
695   if (layout->one_display_cache && line == layout->one_display_cache->line)
696     {
697       GtkTextLineDisplay *tmp_display = layout->one_display_cache;
698       layout->one_display_cache = NULL;
699       gtk_text_layout_free_line_display (layout, tmp_display);
700     }
701
702   g_free (line_data);
703 }
704
705
706
707 /**
708  * gtk_text_layout_is_valid:
709  * @layout: a #GtkTextLayout
710  *
711  * Check if there are any invalid regions in a #GtkTextLayout's buffer
712  *
713  * Return value: #TRUE if any invalid regions were found
714  **/
715 gboolean
716 gtk_text_layout_is_valid (GtkTextLayout *layout)
717 {
718   g_return_val_if_fail (layout != NULL, FALSE);
719   g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), FALSE);
720
721   return _gtk_text_btree_is_valid (_gtk_text_buffer_get_btree (layout->buffer),
722                                   layout);
723 }
724
725 static void
726 update_layout_size (GtkTextLayout *layout)
727 {
728   _gtk_text_btree_get_view_size (_gtk_text_buffer_get_btree (layout->buffer),
729                                 layout,
730                                 &layout->width, &layout->height);
731 }
732
733 /**
734  * gtk_text_layout_validate_yrange:
735  * @layout: a #GtkTextLayout
736  * @anchor: iter pointing into a line that will be used as the
737  *          coordinate origin
738  * @y0: offset from the top of the line pointed to by @anchor at
739  *      which to begin validation. (The offset here is in pixels
740  *      after validation.)
741  * @y1: offset from the top of the line pointed to by @anchor at
742  *      which to end validation. (The offset here is in pixels
743  *      after validation.)
744  *
745  * Ensure that a region of a #GtkTextLayout is valid. The ::changed
746  * signal will be emitted if any lines are validated.
747  **/
748 void
749 gtk_text_layout_validate_yrange (GtkTextLayout *layout,
750                                  GtkTextIter   *anchor,
751                                  gint           y0,
752                                  gint           y1)
753 {
754   GtkTextLine *line;
755   GtkTextLine *first_line = NULL;
756   GtkTextLine *last_line = NULL;
757   gint seen;
758   gint delta_height = 0;
759   gint first_line_y = 0;        /* Quiet GCC */
760   gint last_line_y = 0;         /* Quiet GCC */
761
762   g_return_if_fail (layout != NULL);
763   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
764
765   if (y0 > 0)
766     y0 = 0;
767   if (y1 < 0)
768     y1 = 0;
769   
770   /* Validate backwards from the anchor line to y0
771    */
772   line = _gtk_text_iter_get_text_line (anchor);
773   seen = 0;
774   while (line && seen < -y0)
775     {
776       GtkTextLineData *line_data = _gtk_text_line_get_data (line, layout);
777       if (!line_data || !line_data->valid)
778         {
779           gint old_height = line_data ? line_data->height : 0;
780
781           _gtk_text_btree_validate_line (_gtk_text_buffer_get_btree (layout->buffer),
782                                          line, layout);
783           line_data = _gtk_text_line_get_data (line, layout);
784
785           delta_height += line_data->height - old_height;
786           
787           first_line = line;
788           first_line_y = -seen;
789           if (!last_line)
790             {
791               last_line = line;
792               last_line_y = -seen + line_data->height;
793             }
794         }
795
796       seen += line_data->height;
797       line = _gtk_text_line_previous (line);
798     }
799
800   /* Validate forwards to y1 */
801   line = _gtk_text_iter_get_text_line (anchor);
802   seen = 0;
803   while (line && seen < y1)
804     {
805       GtkTextLineData *line_data = _gtk_text_line_get_data (line, layout);
806       if (!line_data || !line_data->valid)
807         {
808           gint old_height = line_data ? line_data->height : 0;
809
810           _gtk_text_btree_validate_line (_gtk_text_buffer_get_btree (layout->buffer),
811                                          line, layout);
812           line_data = _gtk_text_line_get_data (line, layout);
813
814           delta_height += line_data->height - old_height;
815           
816           if (!first_line)
817             {
818               first_line = line;
819               first_line_y = seen;
820             }
821           last_line = line;
822           last_line_y = seen + line_data->height;
823         }
824
825       seen += line_data->height;
826       line = _gtk_text_line_next (line);
827     }
828
829   /* If we found and validated any invalid lines, update size and
830    * emit the changed signal
831    */
832   if (first_line)
833     {
834       gint line_top;
835
836       update_layout_size (layout);
837
838       line_top = _gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer),
839                                                 first_line, layout);
840
841       gtk_text_layout_changed (layout,
842                                line_top,
843                                last_line_y - first_line_y - delta_height,
844                                last_line_y - first_line_y);
845     }
846 }
847
848 /**
849  * gtk_text_layout_validate:
850  * @tree: a #GtkTextLayout
851  * @max_pixels: the maximum number of pixels to validate. (No more
852  *              than one paragraph beyond this limit will be validated)
853  *
854  * Validate regions of a #GtkTextLayout. The ::changed signal will
855  * be emitted for each region validated.
856  **/
857 void
858 gtk_text_layout_validate (GtkTextLayout *layout,
859                           gint           max_pixels)
860 {
861   gint y, old_height, new_height;
862
863   g_return_if_fail (layout != NULL);
864   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
865
866   while (max_pixels > 0 &&
867          _gtk_text_btree_validate (_gtk_text_buffer_get_btree (layout->buffer),
868                                    layout,  max_pixels,
869                                    &y, &old_height, &new_height))
870     {
871       max_pixels -= new_height;
872
873       update_layout_size (layout);
874       gtk_text_layout_changed (layout, y, old_height, new_height);
875     }
876 }
877
878 static GtkTextLineData*
879 gtk_text_layout_real_wrap (GtkTextLayout   *layout,
880                            GtkTextLine     *line,
881                            /* may be NULL */
882                            GtkTextLineData *line_data)
883 {
884   GtkTextLineDisplay *display;
885
886   g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), NULL);
887
888   if (line_data == NULL)
889     {
890       line_data = gtk_text_line_data_new (layout, line);
891       _gtk_text_line_add_data (line, line_data);
892     }
893
894   display = gtk_text_layout_get_line_display (layout, line, TRUE);
895   line_data->width = display->width;
896   line_data->height = display->height;
897   line_data->valid = TRUE;
898   gtk_text_layout_free_line_display (layout, display);
899
900   return line_data;
901 }
902
903 /*
904  * Layout utility functions
905  */
906
907 /* If you get the style with get_style () you need to call
908    release_style () to free it. */
909 static GtkTextAttributes*
910 get_style (GtkTextLayout *layout,
911            const GtkTextIter *iter)
912 {
913   GtkTextTag** tags;
914   gint tag_count = 0;
915   GtkTextAttributes *style;
916
917   /* If we have the one-style cache, then it means
918      that we haven't seen a toggle since we filled in the
919      one-style cache.
920   */
921   if (layout->one_style_cache != NULL)
922     {
923       gtk_text_attributes_ref (layout->one_style_cache);
924       return layout->one_style_cache;
925     }
926
927   g_assert (layout->one_style_cache == NULL);
928
929   /* Get the tags at this spot */
930   tags = _gtk_text_btree_get_tags (iter, &tag_count);
931
932   /* No tags, use default style */
933   if (tags == NULL || tag_count == 0)
934     {
935       /* One ref for the return value, one ref for the
936          layout->one_style_cache reference */
937       gtk_text_attributes_ref (layout->default_style);
938       gtk_text_attributes_ref (layout->default_style);
939       layout->one_style_cache = layout->default_style;
940
941       if (tags)
942         g_free (tags);
943
944       return layout->default_style;
945     }
946
947   /* Sort tags in ascending order of priority */
948   _gtk_text_tag_array_sort (tags, tag_count);
949
950   style = gtk_text_attributes_new ();
951
952   gtk_text_attributes_copy_values (layout->default_style,
953                                    style);
954
955   _gtk_text_attributes_fill_from_tags (style,
956                                        tags,
957                                        tag_count);
958
959   g_free (tags);
960
961   g_assert (style->refcount == 1);
962
963   /* Leave this style as the last one seen */
964   g_assert (layout->one_style_cache == NULL);
965   gtk_text_attributes_ref (style); /* ref held by layout->one_style_cache */
966   layout->one_style_cache = style;
967
968   /* Returning yet another refcount */
969   return style;
970 }
971
972 static void
973 release_style (GtkTextLayout *layout,
974                GtkTextAttributes *style)
975 {
976   g_return_if_fail (style != NULL);
977   g_return_if_fail (style->refcount > 0);
978
979   gtk_text_attributes_unref (style);
980 }
981
982 /*
983  * Lines
984  */
985
986 /* This function tries to optimize the case where a line
987    is completely invisible */
988 static gboolean
989 totally_invisible_line (GtkTextLayout *layout,
990                         GtkTextLine   *line,
991                         GtkTextIter   *iter)
992 {
993   GtkTextLineSegment *seg;
994   int bytes = 0;
995
996   /* If we have a cached style, then we know it does actually apply
997      and we can just see if it is invisible. */
998   if (layout->one_style_cache &&
999       !layout->one_style_cache->invisible)
1000     return FALSE;
1001   /* Without the cache, we check if the first char is visible, if so
1002      we are partially visible.  Note that we have to check this since
1003      we don't know the current invisible/noninvisible toggle state; this
1004      function can use the whole btree to get it right. */
1005   else
1006     {
1007       _gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
1008                                        iter, line, 0);
1009
1010       if (!_gtk_text_btree_char_is_invisible (iter))
1011         return FALSE;
1012     }
1013
1014   bytes = 0;
1015   seg = line->segments;
1016
1017   while (seg != NULL)
1018     {
1019       if (seg->byte_count > 0)
1020         bytes += seg->byte_count;
1021
1022       /* Note that these two tests can cause us to bail out
1023          when we shouldn't, because a higher-priority tag
1024          may override these settings. However the important
1025          thing is to only invisible really-invisible lines, rather
1026          than to invisible all really-invisible lines. */
1027
1028       else if (seg->type == &gtk_text_toggle_on_type)
1029         {
1030           invalidate_cached_style (layout);
1031
1032           /* Bail out if an elision-unsetting tag begins */
1033           if (seg->body.toggle.info->tag->invisible_set &&
1034               !seg->body.toggle.info->tag->values->invisible)
1035             break;
1036         }
1037       else if (seg->type == &gtk_text_toggle_off_type)
1038         {
1039           invalidate_cached_style (layout);
1040
1041           /* Bail out if an elision-setting tag ends */
1042           if (seg->body.toggle.info->tag->invisible_set &&
1043               seg->body.toggle.info->tag->values->invisible)
1044             break;
1045         }
1046
1047       seg = seg->next;
1048     }
1049
1050   if (seg != NULL)       /* didn't reach line end */
1051     return FALSE;
1052
1053   return TRUE;
1054 }
1055
1056 static void
1057 set_para_values (GtkTextLayout      *layout,
1058                  GtkTextAttributes *style,
1059                  GtkTextLineDisplay *display,
1060                  gdouble            *align)
1061 {
1062   PangoAlignment pango_align = PANGO_ALIGN_LEFT;
1063   int layout_width;
1064
1065   display->direction = style->direction;
1066
1067   if (display->direction == GTK_TEXT_DIR_LTR)
1068     display->layout = pango_layout_new (layout->ltr_context);
1069   else
1070     display->layout = pango_layout_new (layout->rtl_context);
1071
1072   switch (style->justification)
1073     {
1074     case GTK_JUSTIFY_LEFT:
1075       pango_align = (style->direction == GTK_TEXT_DIR_LTR) ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
1076       break;
1077     case GTK_JUSTIFY_RIGHT:
1078       pango_align = (style->direction == GTK_TEXT_DIR_LTR) ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
1079       break;
1080     case GTK_JUSTIFY_CENTER:
1081       pango_align = PANGO_ALIGN_CENTER;
1082       break;
1083     case GTK_JUSTIFY_FILL:
1084       g_warning ("FIXME we don't support GTK_JUSTIFY_FILL yet");
1085       break;
1086     default:
1087       g_assert_not_reached ();
1088       break;
1089     }
1090
1091   switch (pango_align)
1092     {
1093     case PANGO_ALIGN_LEFT:
1094       *align = 0.0;
1095       break;
1096     case PANGO_ALIGN_RIGHT:
1097       *align = 1.0;
1098       break;
1099     case PANGO_ALIGN_CENTER:
1100       *align = 0.5;
1101       break;
1102     }
1103
1104   pango_layout_set_alignment (display->layout, pango_align);
1105   pango_layout_set_spacing (display->layout,
1106                             style->pixels_inside_wrap * PANGO_SCALE);
1107
1108   if (style->tabs)
1109     pango_layout_set_tabs (display->layout, style->tabs);
1110
1111   display->top_margin = style->pixels_above_lines;
1112   display->height = style->pixels_above_lines + style->pixels_below_lines;
1113   display->bottom_margin = style->pixels_below_lines;
1114   display->left_margin = style->left_margin;
1115   display->right_margin = style->right_margin;
1116   
1117   display->x_offset = display->left_margin;
1118
1119   pango_layout_set_indent (display->layout,
1120                            style->indent * PANGO_SCALE);
1121
1122   switch (style->wrap_mode)
1123     {
1124     case GTK_WRAP_CHAR:
1125       layout_width = layout->screen_width - display->left_margin - display->right_margin;
1126       pango_layout_set_width (display->layout, layout_width * PANGO_SCALE);
1127       pango_layout_set_wrap (display->layout, PANGO_WRAP_CHAR);
1128       break;
1129
1130     case GTK_WRAP_WORD:
1131       layout_width = layout->screen_width - display->left_margin - display->right_margin;
1132       pango_layout_set_width (display->layout, layout_width * PANGO_SCALE);
1133       pango_layout_set_wrap (display->layout, PANGO_WRAP_WORD);
1134       break;
1135
1136     case GTK_WRAP_NONE:
1137       break;
1138     }
1139   
1140   display->total_width = MAX (layout->screen_width, layout->width) - display->left_margin - display->right_margin;
1141 }
1142
1143 static PangoAttribute *
1144 gtk_text_attr_appearance_copy (const PangoAttribute *attr)
1145 {
1146   const GtkTextAttrAppearance *appearance_attr = (const GtkTextAttrAppearance *)attr;
1147
1148   return gtk_text_attr_appearance_new (&appearance_attr->appearance);
1149 }
1150
1151 static void
1152 gtk_text_attr_appearance_destroy (PangoAttribute *attr)
1153 {
1154   GtkTextAppearance *appearance = &((GtkTextAttrAppearance *)attr)->appearance;
1155
1156   if (appearance->bg_stipple)
1157     gdk_drawable_unref (appearance->bg_stipple);
1158   if (appearance->fg_stipple)
1159     gdk_drawable_unref (appearance->fg_stipple);
1160
1161   g_free (attr);
1162 }
1163
1164 static gboolean
1165 gtk_text_attr_appearance_compare (const PangoAttribute *attr1,
1166                                   const PangoAttribute *attr2)
1167 {
1168   const GtkTextAppearance *appearance1 = &((const GtkTextAttrAppearance *)attr1)->appearance;
1169   const GtkTextAppearance *appearance2 = &((const GtkTextAttrAppearance *)attr2)->appearance;
1170
1171   return (gdk_color_equal (&appearance1->fg_color, &appearance2->fg_color) &&
1172           gdk_color_equal (&appearance1->bg_color, &appearance2->bg_color) &&
1173           appearance1->fg_stipple ==  appearance2->fg_stipple &&
1174           appearance1->bg_stipple ==  appearance2->bg_stipple &&
1175           appearance1->underline == appearance2->underline &&
1176           appearance1->strikethrough == appearance2->strikethrough &&
1177           appearance1->draw_bg == appearance2->draw_bg);
1178
1179 }
1180
1181 /**
1182  * gtk_text_attr_appearance_new:
1183  * @desc:
1184  *
1185  * Create a new font description attribute. (This attribute
1186  * allows setting family, style, weight, variant, stretch,
1187  * and size simultaneously.)
1188  *
1189  * Return value:
1190  **/
1191 static PangoAttribute *
1192 gtk_text_attr_appearance_new (const GtkTextAppearance *appearance)
1193 {
1194   static PangoAttrClass klass = {
1195     0,
1196     gtk_text_attr_appearance_copy,
1197     gtk_text_attr_appearance_destroy,
1198     gtk_text_attr_appearance_compare
1199   };
1200
1201   GtkTextAttrAppearance *result;
1202
1203   if (!klass.type)
1204     klass.type = gtk_text_attr_appearance_type =
1205       pango_attr_type_register ("GtkTextAttrAppearance");
1206
1207   result = g_new (GtkTextAttrAppearance, 1);
1208   result->attr.klass = &klass;
1209
1210   result->appearance = *appearance;
1211
1212   if (appearance->bg_stipple)
1213     gdk_drawable_ref (appearance->bg_stipple);
1214   if (appearance->fg_stipple)
1215     gdk_drawable_ref (appearance->fg_stipple);
1216
1217   return (PangoAttribute *)result;
1218 }
1219
1220
1221 static void
1222 add_generic_attrs (GtkTextLayout      *layout,
1223                    GtkTextAppearance  *appearance,
1224                    gint                byte_count,
1225                    PangoAttrList      *attrs,
1226                    gint                start,
1227                    gboolean            size_only,
1228                    gboolean            is_text)
1229 {
1230   PangoAttribute *attr;
1231
1232   if (appearance->underline != PANGO_UNDERLINE_NONE)
1233     {
1234       attr = pango_attr_underline_new (appearance->underline);
1235       
1236       attr->start_index = start;
1237       attr->end_index = start + byte_count;
1238       
1239       pango_attr_list_insert (attrs, attr);
1240     }
1241
1242   if (appearance->rise != 0)
1243     {
1244       attr = pango_attr_rise_new (appearance->rise);
1245       
1246       attr->start_index = start;
1247       attr->end_index = start + byte_count;
1248       
1249       pango_attr_list_insert (attrs, attr);
1250     }
1251   
1252   if (!size_only)
1253     {
1254       attr = gtk_text_attr_appearance_new (appearance);
1255       
1256       attr->start_index = start;
1257       attr->end_index = start + byte_count;
1258
1259       ((GtkTextAttrAppearance *)attr)->appearance.is_text = is_text;
1260       
1261       pango_attr_list_insert (attrs, attr);
1262     }
1263 }
1264
1265 static void
1266 add_text_attrs (GtkTextLayout      *layout,
1267                 GtkTextAttributes  *style,
1268                 gint                byte_count,
1269                 PangoAttrList      *attrs,
1270                 gint                start,
1271                 gboolean            size_only)
1272 {
1273   PangoAttribute *attr;
1274
1275   attr = pango_attr_font_desc_new (&style->font);
1276   attr->start_index = start;
1277   attr->end_index = start + byte_count;
1278
1279   pango_attr_list_insert (attrs, attr);
1280 }
1281
1282 static void
1283 add_pixbuf_attrs (GtkTextLayout      *layout,
1284                   GtkTextLineDisplay *display,
1285                   GtkTextAttributes  *style,
1286                   GtkTextLineSegment *seg,
1287                   PangoAttrList      *attrs,
1288                   gint                start)
1289 {
1290   PangoAttribute *attr;
1291   PangoRectangle logical_rect;
1292   GtkTextPixbuf *pixbuf = &seg->body.pixbuf;
1293   gint width, height;
1294
1295   width = gdk_pixbuf_get_width (pixbuf->pixbuf);
1296   height = gdk_pixbuf_get_height (pixbuf->pixbuf);
1297
1298   logical_rect.x = 0;
1299   logical_rect.y = -height * PANGO_SCALE;
1300   logical_rect.width = width * PANGO_SCALE;
1301   logical_rect.height = height * PANGO_SCALE;
1302
1303   attr = pango_attr_shape_new (&logical_rect, &logical_rect);
1304   attr->start_index = start;
1305   attr->end_index = start + seg->byte_count;
1306   pango_attr_list_insert (attrs, attr);
1307
1308   display->shaped_objects =
1309     g_slist_append (display->shaped_objects, pixbuf->pixbuf);
1310 }
1311
1312 static void
1313 add_child_attrs (GtkTextLayout      *layout,
1314                  GtkTextLineDisplay *display,
1315                  GtkTextAttributes  *style,
1316                  GtkTextLineSegment *seg,
1317                  PangoAttrList      *attrs,
1318                  gint                start)
1319 {
1320   PangoAttribute *attr;
1321   PangoRectangle logical_rect;
1322   GtkTextChildAnchor *anchor;
1323   gint width, height;
1324   GSList *tmp_list;
1325
1326   width = 1;
1327   height = 1;
1328   
1329   anchor = seg->body.child.obj;
1330
1331   tmp_list = seg->body.child.widgets;
1332   while (tmp_list != NULL)
1333     {
1334       GtkWidget *child = tmp_list->data;
1335
1336       if (_gtk_anchored_child_get_layout (child) == layout)
1337         {
1338           /* Found it */
1339           GtkRequisition req;
1340
1341           gtk_widget_get_child_requisition (child, &req);
1342           
1343           width = req.width;
1344           height = req.height;
1345
1346           display->shaped_objects =
1347             g_slist_append (display->shaped_objects, child);
1348           
1349           break;
1350         }
1351       
1352       tmp_list = g_slist_next (tmp_list);
1353     }
1354
1355   if (tmp_list == NULL)
1356     {
1357       /* No widget at this anchor in this display;
1358        * not an error.
1359        */
1360
1361       return;
1362     }
1363
1364   if (layout->preedit_string)
1365     {
1366       g_free (layout->preedit_string);
1367       layout->preedit_string = NULL;
1368     }
1369
1370   if (layout->preedit_attrs)
1371     {
1372       pango_attr_list_unref (layout->preedit_attrs);
1373       layout->preedit_attrs = NULL;
1374     }
1375   
1376   logical_rect.x = 0;
1377   logical_rect.y = -height * PANGO_SCALE;
1378   logical_rect.width = width * PANGO_SCALE;
1379   logical_rect.height = height * PANGO_SCALE;
1380
1381   attr = pango_attr_shape_new (&logical_rect, &logical_rect);
1382   attr->start_index = start;
1383   attr->end_index = start + seg->byte_count;
1384   pango_attr_list_insert (attrs, attr);
1385 }
1386
1387 static void
1388 add_cursor (GtkTextLayout      *layout,
1389             GtkTextLineDisplay *display,
1390             GtkTextLineSegment *seg,
1391             gint                start)
1392 {
1393   PangoRectangle strong_pos, weak_pos;
1394   GtkTextCursorDisplay *cursor;
1395
1396   /* Hide insertion cursor when we have a selection or the layout
1397    * user has hidden the cursor.
1398    */
1399   if (_gtk_text_btree_mark_is_insert (_gtk_text_buffer_get_btree (layout->buffer),
1400                                      seg->body.mark.obj) &&
1401       (!layout->cursor_visible ||
1402        gtk_text_buffer_get_selection_bounds (layout->buffer, NULL, NULL)))
1403     return;
1404
1405   pango_layout_get_cursor_pos (display->layout, start, &strong_pos, &weak_pos);
1406
1407   cursor = g_new (GtkTextCursorDisplay, 1);
1408
1409   cursor->x = PANGO_PIXELS (strong_pos.x);
1410   cursor->y = PANGO_PIXELS (strong_pos.y);
1411   cursor->height = PANGO_PIXELS (strong_pos.height);
1412   cursor->is_strong = TRUE;
1413   display->cursors = g_slist_prepend (display->cursors, cursor);
1414
1415   if (weak_pos.x == strong_pos.x)
1416     cursor->is_weak = TRUE;
1417   else
1418     {
1419       cursor->is_weak = FALSE;
1420
1421       cursor = g_new (GtkTextCursorDisplay, 1);
1422
1423       cursor->x = PANGO_PIXELS (weak_pos.x);
1424       cursor->y = PANGO_PIXELS (weak_pos.y);
1425       cursor->height = PANGO_PIXELS (weak_pos.height);
1426       cursor->is_strong = FALSE;
1427       cursor->is_weak = TRUE;
1428       display->cursors = g_slist_prepend (display->cursors, cursor);
1429     }
1430 }
1431
1432 static gboolean
1433 is_shape (PangoLayoutRun *run)
1434 {
1435   GSList *tmp_list = run->item->extra_attrs;
1436     
1437   while (tmp_list)
1438     {
1439       PangoAttribute *attr = tmp_list->data;
1440
1441       if (attr->klass->type == PANGO_ATTR_SHAPE)
1442         return TRUE;
1443
1444       tmp_list = tmp_list->next;
1445     }
1446
1447   return FALSE;
1448 }
1449
1450 static void
1451 allocate_child_widgets (GtkTextLayout      *text_layout,
1452                         GtkTextLineDisplay *display)
1453 {
1454   GSList *shaped = display->shaped_objects;
1455   PangoLayout *layout = display->layout;
1456   PangoLayoutIter *iter;
1457   
1458   iter = pango_layout_get_iter (layout);
1459   
1460   do
1461     {
1462       PangoLayoutRun *run = pango_layout_iter_get_run (iter);
1463
1464       if (run && is_shape (run))
1465         {
1466           GObject *shaped_object = shaped->data;
1467           shaped = shaped->next;
1468
1469           if (GTK_IS_WIDGET (shaped_object))
1470             {
1471               PangoRectangle extents;
1472
1473               /* We emit "allocate_child" with the x,y of
1474                * the widget with respect to the top of the line
1475                * and the left side of the buffer
1476                */
1477               
1478               pango_layout_iter_get_run_extents (iter,
1479                                                  NULL,
1480                                                  &extents);
1481
1482               g_print ("extents at %d,%d\n", extents.x, extents.y);
1483               
1484               g_signal_emit (G_OBJECT (text_layout),
1485                              signals[ALLOCATE_CHILD],
1486                              0,
1487                              shaped_object,
1488                              PANGO_PIXELS (extents.x) + display->x_offset,
1489                              PANGO_PIXELS (extents.y) + display->top_margin);
1490             }
1491         }
1492     }
1493   while (pango_layout_iter_next_run (iter));
1494   
1495   pango_layout_iter_free (iter);
1496 }
1497
1498 static void
1499 convert_color (GdkColor       *result,
1500                PangoAttrColor *attr)
1501 {
1502   result->red = attr->color.red;
1503   result->blue = attr->color.blue;
1504   result->green = attr->color.green;
1505 }
1506
1507 /* This function is used to convert the preedit string attributes, which are
1508  * standard PangoAttributes, into the custom attributes used by the text
1509  * widget and insert them into a attr list with a given offset.
1510  */
1511 static void
1512 add_preedit_attrs (GtkTextLayout     *layout,
1513                    GtkTextAttributes *style,
1514                    PangoAttrList     *attrs,
1515                    gint               offset,
1516                    gboolean           size_only)
1517 {
1518   PangoAttrIterator *iter = pango_attr_list_get_iterator (layout->preedit_attrs);
1519
1520   do
1521     {
1522       GtkTextAppearance appearance = style->appearance;
1523       PangoFontDescription font_desc;
1524       PangoAttribute *insert_attr;
1525       GSList *extra_attrs = NULL;
1526       GSList *tmp_list;
1527       gint start, end;
1528
1529       pango_attr_iterator_range (iter, &start, &end);
1530
1531       if (end == G_MAXINT)
1532         end = layout->preedit_len;
1533       
1534       pango_attr_iterator_get_font (iter, &style->font,
1535                                     &font_desc, &extra_attrs);
1536       
1537       tmp_list = extra_attrs;
1538       while (tmp_list)
1539         {
1540           PangoAttribute *attr = tmp_list->data;
1541           
1542           switch (attr->klass->type)
1543             {
1544             case PANGO_ATTR_FOREGROUND:
1545               convert_color (&appearance.fg_color, (PangoAttrColor *)attr);
1546               break;
1547             case PANGO_ATTR_BACKGROUND:
1548               convert_color (&appearance.bg_color, (PangoAttrColor *)attr);
1549               appearance.draw_bg = TRUE;
1550               break;
1551             case PANGO_ATTR_UNDERLINE:
1552               appearance.underline = ((PangoAttrInt *)attr)->value;
1553               break;
1554             case PANGO_ATTR_STRIKETHROUGH:
1555               appearance.strikethrough = ((PangoAttrInt *)attr)->value;
1556               break;
1557             case PANGO_ATTR_RISE:
1558               appearance.rise = ((PangoAttrInt *)attr)->value;
1559               break;
1560             default:
1561               break;
1562             }
1563           
1564           pango_attribute_destroy (attr);
1565           tmp_list = tmp_list->next;
1566         }
1567       
1568       g_slist_free (extra_attrs);
1569       
1570       insert_attr = pango_attr_font_desc_new (&font_desc);
1571       insert_attr->start_index = start + offset;
1572       insert_attr->end_index = end + offset;
1573       
1574       pango_attr_list_insert (attrs, insert_attr);
1575
1576       add_generic_attrs (layout, &appearance, end - start,
1577                          attrs, start + offset,
1578                          size_only, TRUE);
1579     }
1580   while (pango_attr_iterator_next (iter));
1581
1582   pango_attr_iterator_destroy (iter);
1583 }
1584
1585 GtkTextLineDisplay *
1586 gtk_text_layout_get_line_display (GtkTextLayout *layout,
1587                                   GtkTextLine   *line,
1588                                   gboolean       size_only)
1589 {
1590   GtkTextLineDisplay *display;
1591   GtkTextLineSegment *seg;
1592   GtkTextIter iter;
1593   GtkTextAttributes *style;
1594   gchar *text;
1595   PangoAttrList *attrs;
1596   gint byte_count, layout_byte_offset, layout_only_bytes;
1597   gdouble align;
1598   PangoRectangle extents;
1599   gboolean para_values_set = FALSE;
1600   GSList *cursor_byte_offsets = NULL;
1601   GSList *cursor_segs = NULL;
1602   GSList *tmp_list1, *tmp_list2;
1603   gboolean saw_widget = FALSE;
1604   
1605   g_return_val_if_fail (line != NULL, NULL);
1606
1607   if (layout->one_display_cache)
1608     {
1609       if (line == layout->one_display_cache->line &&
1610           (size_only || !layout->one_display_cache->size_only))
1611         return layout->one_display_cache;
1612       else
1613         {
1614           GtkTextLineDisplay *tmp_display = layout->one_display_cache;
1615           layout->one_display_cache = NULL;
1616           gtk_text_layout_free_line_display (layout, tmp_display);
1617         }
1618     }
1619
1620   display = g_new0 (GtkTextLineDisplay, 1);
1621
1622   display->size_only = size_only;
1623   display->line = line;
1624   display->insert_index = -1;
1625
1626   _gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
1627                                     &iter, line, 0);
1628
1629   /* Special-case optimization for completely
1630    * invisible lines; makes it faster to deal
1631    * with sequences of invisible lines.
1632    */
1633   if (totally_invisible_line (layout, line, &iter))
1634     return display;
1635
1636   /* Allocate space for flat text for buffer
1637    */
1638   byte_count = _gtk_text_line_byte_count (line);
1639   text = g_malloc (byte_count);
1640
1641   attrs = pango_attr_list_new ();
1642
1643   /* Iterate over segments, creating display chunks for them. */
1644   layout_byte_offset = 0; /* current length of layout text (includes preedit) */
1645   layout_only_bytes = 0; /* bytes in layout_byte_offset not in buffer */
1646   seg = _gtk_text_iter_get_any_segment (&iter);
1647   while (seg != NULL)
1648     {
1649       /* Displayable segments */
1650       if (seg->type == &gtk_text_char_type ||
1651           seg->type == &gtk_text_pixbuf_type ||
1652           seg->type == &gtk_text_child_type)
1653         {
1654           _gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
1655                                             &iter, line,
1656                                             layout_byte_offset - layout_only_bytes);
1657           style = get_style (layout, &iter);
1658
1659           /* We have to delay setting the paragraph values until we
1660            * hit the first pixbuf or text segment because toggles at
1661            * the beginning of the paragraph should affect the
1662            * paragraph-global values
1663            */
1664           if (!para_values_set)
1665             {
1666               set_para_values (layout, style, display, &align);
1667               para_values_set = TRUE;
1668             }
1669
1670           /* First see if the chunk is invisible, and ignore it if so. Tk
1671            * looked at tabs, wrap mode, etc. before doing this, but
1672            * that made no sense to me, so I am just skipping the
1673            * invisible chunks
1674            */
1675           if (!style->invisible)
1676             {
1677               if (seg->type == &gtk_text_char_type)
1678                 {
1679                   /* We don't want to split segments because of marks,
1680                    * so we scan forward for more segments only
1681                    * separated from us by marks. In theory, we should
1682                    * also merge segments with identical styles, even
1683                    * if there are toggles in-between
1684                    */
1685
1686                   gint bytes = 0;
1687                   GtkTextLineSegment *prev_seg = NULL;
1688   
1689                   while (seg)
1690                     {
1691                       if (seg->type == &gtk_text_char_type)
1692                         {
1693                           memcpy (text + layout_byte_offset, seg->body.chars, seg->byte_count);
1694                           layout_byte_offset += seg->byte_count;
1695                           bytes += seg->byte_count;
1696                         }
1697                       else if (seg->type == &gtk_text_right_mark_type ||
1698                                seg->type == &gtk_text_left_mark_type)
1699                         {
1700                           /* If we have preedit string, break out of this loop - we'll almost
1701                            * certainly have different attributes on the preedit string
1702                            */
1703
1704                           if (layout->preedit_len > 0 &&
1705                               _gtk_text_btree_mark_is_insert (_gtk_text_buffer_get_btree (layout->buffer),
1706                                                              seg->body.mark.obj))
1707                             break;
1708
1709                           if (seg->body.mark.visible)
1710                             {
1711                               cursor_byte_offsets = g_slist_prepend (cursor_byte_offsets, GINT_TO_POINTER (layout_byte_offset));
1712                               cursor_segs = g_slist_prepend (cursor_segs, seg);
1713                             }
1714                         }
1715                       else
1716                         break;
1717
1718                       prev_seg = seg;
1719                       seg = seg->next;
1720                     }
1721
1722                   seg = prev_seg; /* Back up one */
1723                   add_generic_attrs (layout, &style->appearance,
1724                                      bytes,
1725                                      attrs, layout_byte_offset - bytes,
1726                                      size_only, TRUE);
1727                   add_text_attrs (layout, style, bytes, attrs,
1728                                   layout_byte_offset - bytes, size_only);
1729                 }
1730               else if (seg->type == &gtk_text_pixbuf_type)
1731                 {
1732                   add_generic_attrs (layout,
1733                                      &style->appearance,
1734                                      seg->byte_count,
1735                                      attrs, layout_byte_offset,
1736                                      size_only, FALSE);
1737                   add_pixbuf_attrs (layout, display, style,
1738                                     seg, attrs, layout_byte_offset);
1739                   memcpy (text + layout_byte_offset, gtk_text_unknown_char_utf8,
1740                           seg->byte_count);
1741                   layout_byte_offset += seg->byte_count;
1742                 }
1743               else if (seg->type == &gtk_text_child_type)
1744                 {
1745                   saw_widget = TRUE;
1746                   
1747                   add_generic_attrs (layout, &style->appearance,
1748                                      seg->byte_count,
1749                                      attrs, layout_byte_offset,
1750                                      size_only, FALSE);
1751                   add_child_attrs (layout, display, style,
1752                                    seg, attrs, layout_byte_offset);
1753                   memcpy (text + layout_byte_offset, gtk_text_unknown_char_utf8,
1754                           seg->byte_count);
1755                   layout_byte_offset += seg->byte_count;
1756                 }
1757               else
1758                 {
1759                   g_assert_not_reached ();
1760                 }
1761             }
1762
1763           release_style (layout, style);
1764         }
1765
1766       /* Toggles */
1767       else if (seg->type == &gtk_text_toggle_on_type ||
1768                seg->type == &gtk_text_toggle_off_type)
1769         {
1770           /* Style may have changed, drop our
1771              current cached style */
1772           invalidate_cached_style (layout);
1773         }
1774
1775       /* Marks */
1776       else if (seg->type == &gtk_text_right_mark_type ||
1777                seg->type == &gtk_text_left_mark_type)
1778         {
1779           gint cursor_offset = 0;
1780           
1781           /* At the insertion point, add the preedit string, if any */
1782           
1783           if (_gtk_text_btree_mark_is_insert (_gtk_text_buffer_get_btree (layout->buffer),
1784                                              seg->body.mark.obj))
1785             {
1786               display->insert_index = layout_byte_offset;
1787               
1788               if (layout->preedit_len > 0)
1789                 {
1790                   byte_count += layout->preedit_len;
1791                   text = g_realloc (text, byte_count);
1792
1793                   style = get_style (layout, &iter);
1794                   add_preedit_attrs (layout, style, attrs, layout_byte_offset, size_only);
1795                   release_style (layout, style);
1796                   
1797                   memcpy (text + layout_byte_offset, layout->preedit_string, layout->preedit_len);
1798                   layout_byte_offset += layout->preedit_len;
1799                   layout_only_bytes += layout->preedit_len;
1800                   
1801                   cursor_offset = layout->preedit_cursor - layout->preedit_len;
1802                 }
1803             }
1804           
1805
1806           /* Display visible marks */
1807
1808           if (seg->body.mark.visible)
1809             {
1810               cursor_byte_offsets = g_slist_prepend (cursor_byte_offsets,
1811                                                      GINT_TO_POINTER (layout_byte_offset + cursor_offset));
1812               cursor_segs = g_slist_prepend (cursor_segs, seg);
1813             }
1814         }
1815
1816       else
1817         g_error ("Unknown segment type: %s", seg->type->name);
1818
1819       seg = seg->next;
1820     }
1821   
1822   if (!para_values_set)
1823     {
1824       style = get_style (layout, &iter);
1825       set_para_values (layout, style, display, &align);
1826       release_style (layout, style);
1827     }
1828
1829   g_assert (layout_byte_offset == byte_count);
1830   
1831   /* Pango doesn't want the trailing paragraph delimiters */
1832
1833   {
1834     /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1835      * Unicode 3.0; update this if that changes.
1836      */
1837 #define PARAGRAPH_SEPARATOR 0x2029
1838     gunichar ch = 0;
1839
1840     if (layout_byte_offset > 0)
1841       {
1842         const char *prev = g_utf8_prev_char (text + layout_byte_offset);
1843         ch = g_utf8_get_char (prev);
1844         if (ch == PARAGRAPH_SEPARATOR || ch == '\r' || ch == '\n')
1845           layout_byte_offset = prev - text; /* chop off */
1846
1847         if (ch == '\n' && layout_byte_offset > 0)
1848           {
1849             /* Possibly chop a CR as well */
1850             prev = g_utf8_prev_char (text + layout_byte_offset);
1851             if (*prev == '\r')
1852               --layout_byte_offset;
1853           }
1854       }
1855   }
1856   
1857   pango_layout_set_text (display->layout, text, layout_byte_offset);
1858   pango_layout_set_attributes (display->layout, attrs);
1859
1860   tmp_list1 = cursor_byte_offsets;
1861   tmp_list2 = cursor_segs;
1862   while (tmp_list1)
1863     {
1864       add_cursor (layout, display, tmp_list2->data,
1865                   GPOINTER_TO_INT (tmp_list1->data));
1866       tmp_list1 = tmp_list1->next;
1867       tmp_list2 = tmp_list2->next;
1868     }
1869   g_slist_free (cursor_byte_offsets);
1870   g_slist_free (cursor_segs);
1871
1872   pango_layout_get_extents (display->layout, NULL, &extents);
1873
1874   display->x_offset += (display->total_width - PANGO_PIXELS (extents.x + extents.width)) * align;
1875
1876   display->width = PANGO_PIXELS (extents.width) + display->left_margin + display->right_margin;
1877   display->height += PANGO_PIXELS (extents.height);
1878   
1879   /* Free this if we aren't in a loop */
1880   if (layout->wrap_loop_count == 0)
1881     invalidate_cached_style (layout);
1882
1883   g_free (text);
1884   pango_attr_list_unref (attrs);
1885
1886   layout->one_display_cache = display;
1887
1888   if (saw_widget)
1889     allocate_child_widgets (layout, display);
1890   
1891   return display;
1892 }
1893
1894 void
1895 gtk_text_layout_free_line_display (GtkTextLayout      *layout,
1896                                    GtkTextLineDisplay *display)
1897 {
1898   if (display != layout->one_display_cache)
1899     {
1900       g_object_unref (G_OBJECT (display->layout));
1901
1902       if (display->cursors)
1903         {
1904           g_slist_foreach (display->cursors, (GFunc)g_free, NULL);
1905           g_slist_free (display->cursors);
1906         }
1907       g_slist_free (display->shaped_objects);
1908
1909       g_free (display);
1910     }
1911 }
1912
1913 /* Functions to convert iter <=> index for the line of a GtkTextLineDisplay
1914  * taking into account the preedit string, if necessary.
1915  */
1916 static gint
1917 line_display_iter_to_index (GtkTextLayout      *layout,
1918                             GtkTextLineDisplay *display,
1919                             const GtkTextIter  *iter)
1920 {
1921   gint index;
1922
1923   g_return_val_if_fail (_gtk_text_iter_get_text_line (iter) == display->line, 0);
1924
1925   index = gtk_text_iter_get_line_index (iter);
1926
1927   if (index >= display->insert_index)
1928     index += layout->preedit_len;
1929
1930   return index;
1931 }
1932
1933 static void
1934 line_display_index_to_iter (GtkTextLayout      *layout,
1935                             GtkTextLineDisplay *display,
1936                             GtkTextIter        *iter,
1937                             gint                index,
1938                             gint                trailing)
1939 {
1940   gint line_len;
1941   
1942   if (index >= display->insert_index + layout->preedit_len)
1943     index -= layout->preedit_len;
1944   else if (index > display->insert_index)
1945     {
1946       index = display->insert_index;
1947       trailing = 0;
1948     }
1949   
1950   line_len = _gtk_text_line_byte_count (display->line);
1951   g_assert (index <= line_len);
1952
1953   if (index < line_len)
1954     _gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
1955                                       iter, display->line, index);
1956   else
1957     {
1958       /* Clamp to end of line - really this clamping should have been done
1959        * before here, maybe in Pango, this is a broken band-aid I think
1960        */
1961       g_assert (index == line_len);
1962       
1963       _gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
1964                                         iter, display->line, 0);
1965
1966       if (!gtk_text_iter_ends_line (iter))
1967         gtk_text_iter_forward_to_line_end (iter);
1968     }
1969
1970   /* FIXME should this be cursor positions? */
1971   gtk_text_iter_forward_chars (iter, trailing);
1972 }
1973
1974 /* FIXME: This really doesn't belong in this file ... */
1975 static GtkTextLineData*
1976 gtk_text_line_data_new (GtkTextLayout *layout,
1977                         GtkTextLine   *line)
1978 {
1979   GtkTextLineData *line_data;
1980
1981   line_data = g_new (GtkTextLineData, 1);
1982
1983   line_data->view_id = layout;
1984   line_data->next = NULL;
1985   line_data->width = 0;
1986   line_data->height = 0;
1987   line_data->valid = FALSE;
1988
1989   return line_data;
1990 }
1991
1992 static void
1993 get_line_at_y (GtkTextLayout *layout,
1994                gint           y,
1995                GtkTextLine  **line,
1996                gint          *line_top)
1997 {
1998   if (y < 0)
1999     y = 0;
2000   if (y > layout->height)
2001     y = layout->height;
2002
2003   *line = _gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer),
2004                                          layout, y, line_top);
2005   if (*line == NULL)
2006     {
2007       *line = _gtk_text_btree_get_line (_gtk_text_buffer_get_btree (layout->buffer),
2008                                        _gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1, NULL);
2009       if (line_top)
2010         *line_top =
2011           _gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer),
2012                                         *line, layout);
2013     }
2014 }
2015
2016 /**
2017  * gtk_text_layout_get_line_at_y:
2018  * @layout: a #GtkLayout
2019  * @target_iter: the iterator in which the result is stored
2020  * @y: the y positition
2021  * @line_top: location to store the y coordinate of the
2022  *            top of the line. (Can by %NULL.)
2023  *
2024  * Get the iter at the beginning of the line which is displayed
2025  * at the given y.
2026  **/
2027 void
2028 gtk_text_layout_get_line_at_y (GtkTextLayout *layout,
2029                                GtkTextIter   *target_iter,
2030                                gint           y,
2031                                gint          *line_top)
2032 {
2033   GtkTextLine *line;
2034
2035   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
2036   g_return_if_fail (target_iter != NULL);
2037
2038   get_line_at_y (layout, y, &line, line_top);
2039   _gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
2040                                    target_iter, line, 0);
2041 }
2042
2043 void
2044 gtk_text_layout_get_iter_at_pixel (GtkTextLayout *layout,
2045                                    GtkTextIter *target_iter,
2046                                    gint x, gint y)
2047 {
2048   GtkTextLine *line;
2049   gint byte_index, trailing;
2050   gint line_top;
2051   GtkTextLineDisplay *display;
2052
2053   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
2054   g_return_if_fail (target_iter != NULL);
2055
2056   /* Adjust pixels to be on-screen. This gives nice
2057      behavior if the user is dragging with a pointer grab.
2058   */
2059   if (x < 0)
2060     x = 0;
2061   if (x > layout->width)
2062     x = layout->width;
2063
2064   get_line_at_y (layout, y, &line, &line_top);
2065
2066   display = gtk_text_layout_get_line_display (layout, line, FALSE);
2067
2068   x -= display->x_offset;
2069   y -= line_top + display->top_margin;
2070
2071   /* We clamp y to the area of the actual layout so that the layouts
2072    * hit testing works OK on the space above and below the layout
2073    */
2074   y = CLAMP (y, 0, display->height - display->top_margin - display->bottom_margin - 1);
2075
2076   if (!pango_layout_xy_to_index (display->layout, x * PANGO_SCALE, y * PANGO_SCALE,
2077                                  &byte_index, &trailing))
2078     {
2079       byte_index = _gtk_text_line_byte_count (line);
2080       trailing = 0;
2081     }
2082
2083   line_display_index_to_iter (layout, display, target_iter, byte_index, trailing);
2084
2085   gtk_text_layout_free_line_display (layout, display);
2086 }
2087
2088 /**
2089  * gtk_text_layout_get_cursor_locations
2090  * @layout: a #GtkTextLayout
2091  * @iter: a #GtkTextIter
2092  * @strong_pos: location to store the strong cursor position (may be %NULL)
2093  * @weak_pos: location to store the weak cursor position (may be %NULL)
2094  *
2095  * Given an iterator within a text laout, determine the positions that of the
2096  * strong and weak cursors if the insertion point is at that
2097  * iterator. The position of each cursor is stored as a zero-width
2098  * rectangle. The strong cursor location is the location where
2099  * characters of the directionality equal to the base direction of the
2100  * paragraph are inserted.  The weak cursor location is the location
2101  * where characters of the directionality opposite to the base
2102  * direction of the paragraph are inserted.
2103  **/
2104 void
2105 gtk_text_layout_get_cursor_locations (GtkTextLayout  *layout,
2106                                       GtkTextIter    *iter,
2107                                       GdkRectangle   *strong_pos,
2108                                       GdkRectangle   *weak_pos)
2109 {
2110   GtkTextLine *line;
2111   GtkTextLineDisplay *display;
2112   gint line_top;
2113   gint index;
2114
2115   PangoRectangle pango_strong_pos;
2116   PangoRectangle pango_weak_pos;
2117
2118   g_return_if_fail (layout != NULL);
2119   g_return_if_fail (iter != NULL);
2120
2121   line = _gtk_text_iter_get_text_line (iter);
2122   display = gtk_text_layout_get_line_display (layout, line, FALSE);
2123   index = line_display_iter_to_index (layout, display, iter);
2124   
2125   line_top = _gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer),
2126                                            line, layout);
2127   
2128   pango_layout_get_cursor_pos (display->layout, index,
2129                                strong_pos ? &pango_strong_pos : NULL,
2130                                weak_pos ? &pango_weak_pos : NULL);
2131
2132   if (strong_pos)
2133     {
2134       strong_pos->x = display->x_offset + pango_strong_pos.x / PANGO_SCALE;
2135       strong_pos->y = line_top + display->top_margin + pango_strong_pos.y / PANGO_SCALE;
2136       strong_pos->width = 0;
2137       strong_pos->height = pango_strong_pos.height / PANGO_SCALE;
2138     }
2139
2140   if (weak_pos)
2141     {
2142       weak_pos->x = display->x_offset + pango_weak_pos.x / PANGO_SCALE;
2143       weak_pos->y = line_top + display->top_margin + pango_weak_pos.y / PANGO_SCALE;
2144       weak_pos->width = 0;
2145       weak_pos->height = pango_weak_pos.height / PANGO_SCALE;
2146     }
2147
2148   gtk_text_layout_free_line_display (layout, display);
2149 }
2150
2151 /**
2152  * gtk_text_layout_get_line_yrange:
2153  * @layout: a #GtkTextLayout
2154  * @iter:   a #GtkTextIter
2155  * @y:      location to store the top of the paragraph in pixels,
2156  *          or %NULL.
2157  * @height  location to store the height of the paragraph in pixels,
2158  *          or %NULL.
2159  *
2160  * Find the range of y coordinates for the paragraph containing
2161  * the given iter.
2162  **/
2163 void
2164 gtk_text_layout_get_line_yrange (GtkTextLayout     *layout,
2165                                  const GtkTextIter *iter,
2166                                  gint              *y,
2167                                  gint              *height)
2168 {
2169   GtkTextLine *line;
2170
2171   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
2172   g_return_if_fail (_gtk_text_iter_get_btree (iter) == _gtk_text_buffer_get_btree (layout->buffer));
2173
2174   line = _gtk_text_iter_get_text_line (iter);
2175
2176   if (y)
2177     *y = _gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer),
2178                                        line, layout);
2179   if (height)
2180     {
2181       GtkTextLineData *line_data = _gtk_text_line_get_data (line, layout);
2182       if (line_data)
2183         *height = line_data->height;
2184       else
2185         *height = 0;
2186     }
2187 }
2188
2189 void
2190 gtk_text_layout_get_iter_location (GtkTextLayout     *layout,
2191                                    const GtkTextIter *iter,
2192                                    GdkRectangle      *rect)
2193 {
2194   PangoRectangle pango_rect;
2195   GtkTextLine *line;
2196   GtkTextBTree *tree;
2197   GtkTextLineDisplay *display;
2198   gint byte_index;
2199   gint x_offset;
2200   
2201   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
2202   g_return_if_fail (_gtk_text_iter_get_btree (iter) == _gtk_text_buffer_get_btree (layout->buffer));
2203   g_return_if_fail (rect != NULL);
2204
2205   tree = _gtk_text_iter_get_btree (iter);
2206   line = _gtk_text_iter_get_text_line (iter);
2207
2208   display = gtk_text_layout_get_line_display (layout, line, FALSE);
2209
2210   rect->y = _gtk_text_btree_find_line_top (tree, line, layout);
2211
2212   x_offset = display->x_offset * PANGO_SCALE;
2213
2214   byte_index = gtk_text_iter_get_line_index (iter);
2215   
2216   pango_layout_index_to_pos (display->layout, byte_index, &pango_rect);
2217   
2218   rect->x = PANGO_PIXELS (x_offset + pango_rect.x);
2219   rect->y += PANGO_PIXELS (pango_rect.y) + display->top_margin;
2220   rect->width = PANGO_PIXELS (pango_rect.width);
2221   rect->height = PANGO_PIXELS (pango_rect.height);
2222
2223   gtk_text_layout_free_line_display (layout, display);
2224 }
2225
2226 /* FFIXX */
2227
2228 /* Find the iter for the logical beginning of the first display line whose
2229  * top y is >= y. If none exists, move the iter to the logical beginning
2230  * of the last line in the buffer.
2231  */
2232 static void
2233 find_display_line_below (GtkTextLayout *layout,
2234                          GtkTextIter   *iter,
2235                          gint           y)
2236 {
2237   GtkTextLine *line, *next;
2238   GtkTextLine *found_line = NULL;
2239   gint line_top;
2240   gint found_byte = 0;
2241
2242   line = _gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer),
2243                                         layout, y, &line_top);
2244   if (!line)
2245     {
2246       line =
2247         _gtk_text_btree_get_line (_gtk_text_buffer_get_btree (layout->buffer),
2248                                  _gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1,
2249                                  NULL);
2250       line_top =
2251         _gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer),
2252                                       line, layout);
2253     }
2254
2255   while (line && !found_line)
2256     {
2257       GtkTextLineDisplay *display = gtk_text_layout_get_line_display (layout, line, FALSE);
2258       PangoLayoutIter *layout_iter;
2259
2260       layout_iter = pango_layout_get_iter (display->layout);
2261
2262       line_top += display->top_margin;
2263
2264       do
2265         {
2266           gint first_y, last_y;
2267           PangoLayoutLine *layout_line = pango_layout_iter_get_line (layout_iter);
2268
2269           found_byte = layout_line->start_index;
2270           
2271           if (line_top >= y)
2272             {
2273               found_line = line;
2274               break;
2275             }
2276
2277           pango_layout_iter_get_line_yrange (layout_iter, &first_y, &last_y);
2278           line_top += (last_y - first_y) / PANGO_SCALE;
2279         }
2280       while (pango_layout_iter_next_line (layout_iter));
2281
2282       pango_layout_iter_free (layout_iter);
2283       
2284       line_top += display->bottom_margin;
2285       gtk_text_layout_free_line_display (layout, display);
2286
2287       next = _gtk_text_line_next (line);
2288       if (!next)
2289         found_line = line;
2290
2291       line = next;
2292     }
2293
2294   _gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
2295                                    iter, found_line, found_byte);
2296 }
2297
2298 /* Find the iter for the logical beginning of the last display line whose
2299  * top y is >= y. If none exists, move the iter to the logical beginning
2300  * of the first line in the buffer.
2301  */
2302 static void
2303 find_display_line_above (GtkTextLayout *layout,
2304                          GtkTextIter   *iter,
2305                          gint           y)
2306 {
2307   GtkTextLine *line;
2308   GtkTextLine *found_line = NULL;
2309   gint line_top;
2310   gint found_byte = 0;
2311
2312   line = _gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer), layout, y, &line_top);
2313   if (!line)
2314     {
2315       line = _gtk_text_btree_get_line (_gtk_text_buffer_get_btree (layout->buffer),
2316                                       _gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1, NULL);
2317       line_top = _gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer), line, layout);
2318     }
2319
2320   while (line && !found_line)
2321     {
2322       GtkTextLineDisplay *display = gtk_text_layout_get_line_display (layout, line, FALSE);
2323       PangoRectangle logical_rect;
2324       PangoLayoutIter *layout_iter;
2325       gint tmp_top;
2326
2327       layout_iter = pango_layout_get_iter (display->layout);
2328       
2329       line_top -= display->top_margin + display->bottom_margin;
2330       pango_layout_iter_get_layout_extents (layout_iter, NULL, &logical_rect);
2331       line_top -= logical_rect.height / PANGO_SCALE;
2332
2333       tmp_top = line_top + display->top_margin;
2334
2335       do
2336         {
2337           gint first_y, last_y;
2338           PangoLayoutLine *layout_line = pango_layout_iter_get_line (layout_iter);
2339
2340           found_byte = layout_line->start_index;
2341
2342           pango_layout_iter_get_line_yrange (layout_iter, &first_y, &last_y);
2343           
2344           tmp_top -= (last_y - first_y) / PANGO_SCALE;
2345
2346           if (tmp_top < y)
2347             {
2348               found_line = line;
2349               goto done;
2350             }
2351         }
2352       while (pango_layout_iter_next_line (layout_iter));
2353
2354       pango_layout_iter_free (layout_iter);
2355       
2356       gtk_text_layout_free_line_display (layout, display);
2357
2358       line = _gtk_text_line_previous (line);
2359     }
2360
2361  done:
2362   
2363   if (found_line)
2364     _gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
2365                                      iter, found_line, found_byte);
2366   else
2367     gtk_text_buffer_get_iter_at_offset (layout->buffer, iter, 0);
2368 }
2369
2370 /**
2371  * gtk_text_layout_clamp_iter_to_vrange:
2372  * @layout: a #GtkTextLayout
2373  * @iter:   a #GtkTextIter
2374  * @top:    the top of the range
2375  * @bottom: the bottom the range
2376  *
2377  * If the iterator is not fully in the range @top <= y < @bottom,
2378  * then, if possible, move it the minimum distance so that the
2379  * iterator in this range.
2380  *
2381  * Returns: %TRUE if the iterator was moved, otherwise %FALSE.
2382  **/
2383 gboolean
2384 gtk_text_layout_clamp_iter_to_vrange (GtkTextLayout *layout,
2385                                       GtkTextIter   *iter,
2386                                       gint           top,
2387                                       gint           bottom)
2388 {
2389   GdkRectangle iter_rect;
2390
2391   gtk_text_layout_get_iter_location (layout, iter, &iter_rect);
2392
2393   /* If the iter is at least partially above the range, put the iter
2394    * at the first fully visible line after the range.
2395    */
2396   if (iter_rect.y < top)
2397     {
2398       find_display_line_below (layout, iter, top);
2399
2400       return TRUE;
2401     }
2402   /* Otherwise, if the iter is at least partially below the screen, put the
2403    * iter on the last logical position of the last completely visible
2404    * line on screen
2405    */
2406   else if (iter_rect.y + iter_rect.height > bottom)
2407     {
2408       find_display_line_above (layout, iter, bottom);
2409
2410       return TRUE;
2411     }
2412   else
2413     return FALSE;
2414 }
2415
2416 /**
2417  * gtk_text_layout_move_iter_to_next_line:
2418  * @layout: a #GtkLayout
2419  * @iter:   a #GtkTextIter
2420  *
2421  * Move the iterator to the beginning of the previous line. The lines
2422  * of a wrapped paragraph are treated as distinct for this operation.
2423  **/
2424 gboolean
2425 gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout,
2426                                             GtkTextIter   *iter)
2427 {
2428   GtkTextLine *line;
2429   GtkTextLineDisplay *display;
2430   gint line_byte;
2431   GSList *tmp_list;
2432   PangoLayoutLine *layout_line;
2433   GtkTextIter orig;
2434   
2435   g_return_val_if_fail (layout != NULL, FALSE);
2436   g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), FALSE);
2437   g_return_val_if_fail (iter != NULL, FALSE);
2438
2439   orig = *iter;
2440   
2441   line = _gtk_text_iter_get_text_line (iter);
2442   display = gtk_text_layout_get_line_display (layout, line, FALSE);
2443   line_byte = line_display_iter_to_index (layout, display, iter);
2444
2445   tmp_list = pango_layout_get_lines (display->layout);
2446   layout_line = tmp_list->data;
2447
2448   if (line_byte < layout_line->length || !tmp_list->next) /* first line of paragraph */
2449     {
2450       GtkTextLine *prev_line = _gtk_text_line_previous (line);
2451
2452       if (prev_line)
2453         {
2454           gtk_text_layout_free_line_display (layout, display);
2455           display = gtk_text_layout_get_line_display (layout, prev_line, FALSE);
2456           tmp_list = g_slist_last (pango_layout_get_lines (display->layout));
2457           layout_line = tmp_list->data;
2458
2459           line_display_index_to_iter (layout, display, iter,
2460                                       layout_line->start_index + layout_line->length, 0);
2461         }
2462       else
2463         line_display_index_to_iter (layout, display, iter, 0, 0);
2464     }
2465   else
2466     {
2467       gint prev_offset = layout_line->start_index;
2468
2469       tmp_list = tmp_list->next;
2470       while (tmp_list)
2471         {
2472           layout_line = tmp_list->data;
2473
2474           if (line_byte < layout_line->start_index + layout_line->length ||
2475               !tmp_list->next)
2476             {
2477               line_display_index_to_iter (layout, display, iter, prev_offset, 0);
2478               break;
2479             }
2480
2481           prev_offset = layout_line->start_index;
2482           tmp_list = tmp_list->next;
2483         }
2484     }
2485
2486   gtk_text_layout_free_line_display (layout, display);
2487
2488   return
2489     !gtk_text_iter_equal (iter, &orig) &&
2490     !gtk_text_iter_is_end (iter);
2491 }
2492
2493 /**
2494  * gtk_text_layout_move_iter_to_next_line:
2495  * @layout: a #GtkLayout
2496  * @iter:   a #GtkTextIter
2497  *
2498  * Move the iterator to the beginning of the next line. The
2499  * lines of a wrapped paragraph are treated as distinct for
2500  * this operation.
2501  **/
2502 gboolean
2503 gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout,
2504                                         GtkTextIter   *iter)
2505 {
2506   GtkTextLine *line;
2507   GtkTextLineDisplay *display;
2508   gint line_byte;
2509   GtkTextIter orig;
2510   gboolean found = FALSE;
2511   gboolean found_after = FALSE;
2512   gboolean first = TRUE;
2513
2514   g_return_val_if_fail (layout != NULL, FALSE);
2515   g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), FALSE);
2516   g_return_val_if_fail (iter != NULL, FALSE);
2517
2518   orig = *iter;
2519   
2520   line = _gtk_text_iter_get_text_line (iter);
2521
2522   while (line && !found_after)
2523     {
2524       GSList *tmp_list;
2525
2526       display = gtk_text_layout_get_line_display (layout, line, FALSE);
2527
2528       if (first)
2529         {
2530           line_byte = line_display_iter_to_index (layout, display, iter);
2531           first = FALSE;
2532         }
2533       else
2534         line_byte = 0;
2535         
2536       tmp_list = pango_layout_get_lines (display->layout);
2537       while (tmp_list && !found_after)
2538         {
2539           PangoLayoutLine *layout_line = tmp_list->data;
2540
2541           if (found)
2542             {
2543               line_display_index_to_iter (layout, display, iter,
2544                                           layout_line->start_index, 0);
2545               found_after = TRUE;
2546             }
2547           else if (line_byte < layout_line->start_index + layout_line->length || !tmp_list->next)
2548             found = TRUE;
2549           
2550           tmp_list = tmp_list->next;
2551         }
2552
2553       gtk_text_layout_free_line_display (layout, display);
2554
2555       line = _gtk_text_line_next (line);
2556     }
2557
2558   return
2559     !gtk_text_iter_equal (iter, &orig) &&
2560     !gtk_text_iter_is_end (iter);
2561 }
2562
2563 /**
2564  * gtk_text_layout_move_iter_to_line_end:
2565  * @layout: a #GtkTextLayout
2566  * @direction: if negative, move to beginning of line, otherwise
2567                move to end of line.
2568  *
2569  * Move to the beginning or end of a display line.
2570  **/
2571 gboolean
2572 gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout,
2573                                        GtkTextIter   *iter,
2574                                        gint           direction)
2575 {
2576   GtkTextLine *line;
2577   GtkTextLineDisplay *display;
2578   gint line_byte;
2579   GSList *tmp_list;
2580   GtkTextIter orig;
2581   
2582   g_return_val_if_fail (layout != NULL, FALSE);
2583   g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), FALSE);
2584   g_return_val_if_fail (iter != NULL, FALSE);
2585
2586   orig = *iter;
2587   
2588   line = _gtk_text_iter_get_text_line (iter);
2589   display = gtk_text_layout_get_line_display (layout, line, FALSE);
2590   line_byte = line_display_iter_to_index (layout, display, iter);
2591
2592   tmp_list = pango_layout_get_lines (display->layout);
2593   while (tmp_list)
2594     {
2595       PangoLayoutLine *layout_line = tmp_list->data;
2596
2597       if (line_byte < layout_line->start_index + layout_line->length || !tmp_list->next)
2598         {
2599           line_display_index_to_iter (layout, display, iter,
2600                                       direction < 0 ? layout_line->start_index : layout_line->start_index + layout_line->length,
2601                                       0);
2602
2603           /* FIXME: As a bad hack, we move back one position when we
2604            * are inside a paragraph to avoid going to next line on a
2605            * forced break not at whitespace. Real fix is to keep track
2606            * of whether marks are at leading or trailing edge?  */
2607           if (direction > 0 && layout_line->length > 0 && !gtk_text_iter_ends_line (iter))
2608             gtk_text_iter_backward_char (iter);
2609
2610           break;
2611         }
2612       
2613       tmp_list = tmp_list->next;
2614     }
2615
2616   gtk_text_layout_free_line_display (layout, display);
2617
2618   return
2619     !gtk_text_iter_equal (iter, &orig) &&
2620     !gtk_text_iter_is_end (iter);
2621 }
2622
2623
2624 /**
2625  * gtk_text_layout_iter_starts_line:
2626  * @layout: a #GtkTextLayout
2627  * @iter: iterator to test
2628  *
2629  * Tests whether an iterator is at the start of a display line.
2630  **/
2631 gboolean
2632 gtk_text_layout_iter_starts_line (GtkTextLayout       *layout,
2633                                   const GtkTextIter   *iter)
2634 {
2635   GtkTextLine *line;
2636   GtkTextLineDisplay *display;
2637   gint line_byte;
2638   GSList *tmp_list;
2639   
2640   g_return_val_if_fail (layout != NULL, FALSE);
2641   g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), FALSE);
2642   g_return_val_if_fail (iter != NULL, FALSE);
2643
2644   line = _gtk_text_iter_get_text_line (iter);
2645   display = gtk_text_layout_get_line_display (layout, line, FALSE);
2646   line_byte = line_display_iter_to_index (layout, display, iter);
2647
2648   tmp_list = pango_layout_get_lines (display->layout);
2649   while (tmp_list)
2650     {
2651       PangoLayoutLine *layout_line = tmp_list->data;
2652
2653       if (line_byte < layout_line->start_index + layout_line->length ||
2654           !tmp_list->next)
2655         {
2656           /* We're located on this line of the para delimiters before
2657            * it
2658            */
2659           gtk_text_layout_free_line_display (layout, display);
2660           
2661           if (line_byte == layout_line->start_index)
2662             return TRUE;
2663           else
2664             return FALSE;
2665         }
2666       
2667       tmp_list = tmp_list->next;
2668     }
2669
2670   g_assert_not_reached ();
2671   return FALSE;
2672 }
2673
2674 void
2675 gtk_text_layout_get_iter_at_line (GtkTextLayout  *layout,
2676                                   GtkTextIter    *iter,
2677                                   GtkTextLine    *line,
2678                                   gint            byte_offset)
2679 {
2680   _gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
2681                                     iter, line, byte_offset);
2682 }
2683
2684
2685 /**
2686  * gtk_text_layout_move_iter_to_x:
2687  * @layout: a #GtkTextLayout
2688  * @iter:   a #GtkTextIter
2689  * @x:      X coordinate
2690  *
2691  * Keeping the iterator on the same line of the layout, move it to the
2692  * specified X coordinate. The lines of a wrapped paragraph are
2693  * treated as distinct for this operation.
2694  **/
2695 void
2696 gtk_text_layout_move_iter_to_x (GtkTextLayout *layout,
2697                                 GtkTextIter   *iter,
2698                                 gint           x)
2699 {
2700   GtkTextLine *line;
2701   GtkTextLineDisplay *display;
2702   gint line_byte;
2703   PangoLayoutIter *layout_iter;
2704   
2705   g_return_if_fail (layout != NULL);
2706   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
2707   g_return_if_fail (iter != NULL);
2708
2709   line = _gtk_text_iter_get_text_line (iter);
2710
2711   display = gtk_text_layout_get_line_display (layout, line, FALSE);
2712   line_byte = line_display_iter_to_index (layout, display, iter);
2713
2714   layout_iter = pango_layout_get_iter (display->layout);
2715
2716   do
2717     {
2718       PangoLayoutLine *layout_line = pango_layout_iter_get_line (layout_iter);
2719
2720       if (line_byte < layout_line->start_index + layout_line->length ||
2721           pango_layout_iter_at_last_line (layout_iter))
2722         {
2723           PangoRectangle logical_rect;
2724           gint byte_index, trailing;
2725           gint x_offset = display->x_offset * PANGO_SCALE;
2726
2727           pango_layout_iter_get_line_extents (layout_iter, NULL, &logical_rect);
2728
2729           pango_layout_line_x_to_index (layout_line,
2730                                         x * PANGO_SCALE - x_offset - logical_rect.x,
2731                                         &byte_index, &trailing);
2732
2733           line_display_index_to_iter (layout, display, iter, byte_index, trailing);
2734
2735           break;
2736         }
2737     }
2738   while (pango_layout_iter_next_line (layout_iter));
2739
2740   pango_layout_iter_free (layout_iter);
2741   
2742   gtk_text_layout_free_line_display (layout, display);
2743 }
2744
2745 /**
2746  * gtk_text_layout_move_iter_visually:
2747  * @layout:  a #GtkTextLayout
2748  * @iter:    a #GtkTextIter
2749  * @count:   number of characters to move (negative moves left, positive moves right)
2750  *
2751  * Move the iterator a given number of characters visually, treating
2752  * it as the strong cursor position. If @count is positive, then the
2753  * new strong cursor position will be @count positions to the right of
2754  * the old cursor position. If @count is negative then the new strong
2755  * cursor position will be @count positions to the left of the old
2756  * cursor position.
2757  *
2758  * In the presence of bidirection text, the correspondence
2759  * between logical and visual order will depend on the direction
2760  * of the current run, and there may be jumps when the cursor
2761  * is moved off of the end of a run.
2762  **/
2763
2764 gboolean
2765 gtk_text_layout_move_iter_visually (GtkTextLayout *layout,
2766                                     GtkTextIter   *iter,
2767                                     gint           count)
2768 {
2769   GtkTextLineDisplay *display = NULL;
2770   GtkTextIter orig;
2771   
2772   g_return_val_if_fail (layout != NULL, FALSE);
2773   g_return_val_if_fail (iter != NULL, FALSE);
2774
2775   orig = *iter;
2776   
2777   while (count != 0)
2778     {
2779       GtkTextLine *line = _gtk_text_iter_get_text_line (iter);
2780       gint line_byte;
2781       gint extra_back = 0;
2782
2783       int byte_count = _gtk_text_line_byte_count (line);
2784
2785       int new_index;
2786       int new_trailing;
2787
2788  
2789       if (!display)
2790         display = gtk_text_layout_get_line_display (layout, line, FALSE);
2791       line_byte = line_display_iter_to_index (layout, display, iter);
2792
2793       if (count > 0)
2794         {
2795           pango_layout_move_cursor_visually (display->layout, line_byte, 0, 1, &new_index, &new_trailing);
2796           count--;
2797         }
2798       else
2799         {
2800           pango_layout_move_cursor_visually (display->layout, line_byte, 0, -1, &new_index, &new_trailing);
2801           count++;
2802         }
2803
2804       /* We need to handle the preedit string specially. Well, we don't really need to
2805        * handle it specially, since hopefully calling gtk_im_context_reset() will
2806        * remove the preedit string; but if we start off in front of the preedit
2807        * string (logically) and end up in or on the back edge of the preedit string,
2808        * we should move the iter one place farther.
2809        */
2810       if (layout->preedit_len > 0 && display->insert_index >= 0)
2811         {
2812           if (line_byte == display->insert_index + layout->preedit_len &&
2813               new_index < display->insert_index + layout->preedit_len)
2814             {
2815               line_byte = display->insert_index;
2816               extra_back = 1;
2817             }
2818         }
2819       
2820       if (new_index < 0 || (new_index == 0 && extra_back))
2821         {
2822           line = _gtk_text_line_previous (line);
2823
2824           if (!line)
2825             goto done;
2826           
2827           gtk_text_layout_free_line_display (layout, display);
2828           display = gtk_text_layout_get_line_display (layout, line, FALSE);
2829           new_index = _gtk_text_line_byte_count (line);
2830         }
2831       else if (new_index > byte_count)
2832         {
2833           line = _gtk_text_line_next (line);
2834           if (!line)
2835             goto done;
2836
2837           gtk_text_layout_free_line_display (layout, display);
2838           display = gtk_text_layout_get_line_display (layout, line, FALSE);
2839           new_index = 0;
2840         }
2841       
2842        line_display_index_to_iter (layout, display, iter, new_index, new_trailing);
2843        if (extra_back)
2844          gtk_text_iter_backward_char (iter);
2845     }
2846
2847   gtk_text_layout_free_line_display (layout, display);
2848
2849  done:
2850   
2851   return
2852     !gtk_text_iter_equal (iter, &orig) &&
2853     !gtk_text_iter_is_end (iter);
2854 }
2855
2856 void
2857 gtk_text_layout_spew (GtkTextLayout *layout)
2858 {
2859 #if 0
2860   GtkTextDisplayLine *iter;
2861   guint wrapped = 0;
2862   guint paragraphs = 0;
2863   GtkTextLine *last_line = NULL;
2864
2865   iter = layout->line_list;
2866   while (iter != NULL)
2867     {
2868       if (iter->line != last_line)
2869         {
2870           printf ("%5u  paragraph (%p)\n", paragraphs, iter->line);
2871           ++paragraphs;
2872           last_line = iter->line;
2873         }
2874
2875       printf ("  %5u  y: %d len: %d start: %d bytes: %d\n",
2876               wrapped, iter->y, iter->length, iter->byte_offset,
2877               iter->byte_count);
2878
2879       ++wrapped;
2880       iter = iter->next;
2881     }
2882
2883   printf ("Layout %s recompute\n",
2884           layout->need_recompute ? "needs" : "doesn't need");
2885
2886   printf ("Layout pars: %u lines: %u size: %d x %d Screen width: %d\n",
2887           paragraphs, wrapped, layout->width,
2888           layout->height, layout->screen_width);
2889 #endif
2890 }