]> Pileus Git - ~andy/gtk/blob - gtk/gtktextbtree.c
Don't stop the iteration up to the tag_root too early. (#109945, Dongho
[~andy/gtk] / gtk / gtktextbtree.c
1 /*
2  * gtktextbtree.c --
3  *
4  *      This file contains code that manages the B-tree representation
5  *      of text for the text buffer and implements character and
6  *      toggle segment types.
7  *
8  * Copyright (c) 1992-1994 The Regents of the University of California.
9  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
10  * Copyright (c) 2000      Red Hat, Inc.
11  * Tk -> Gtk port by Havoc Pennington <hp@redhat.com>
12  *
13  * This software is copyrighted by the Regents of the University of
14  * California, Sun Microsystems, Inc., and other parties.  The
15  * following terms apply to all files associated with the software
16  * unless explicitly disclaimed in individual files.
17  *
18  * The authors hereby grant permission to use, copy, modify,
19  * distribute, and license this software and its documentation for any
20  * purpose, provided that existing copyright notices are retained in
21  * all copies and that this notice is included verbatim in any
22  * distributions. No written agreement, license, or royalty fee is
23  * required for any of the authorized uses.  Modifications to this
24  * software may be copyrighted by their authors and need not follow
25  * the licensing terms described here, provided that the new terms are
26  * clearly indicated on the first page of each file where they apply.
27  *
28  * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
29  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
30  * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION,
31  * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED
32  * OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
35  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
36  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
37  * NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
38  * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
39  * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
40  *
41  * GOVERNMENT USE: If you are acquiring this software on behalf of the
42  * U.S. government, the Government shall have only "Restricted Rights"
43  * in the software and related documentation as defined in the Federal
44  * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
45  * are acquiring the software on behalf of the Department of Defense,
46  * the software shall be classified as "Commercial Computer Software"
47  * and the Government shall have only "Restricted Rights" as defined
48  * in Clause 252.227-7013 (c) (1) of DFARs.  Notwithstanding the
49  * foregoing, the authors grant the U.S. Government and others acting
50  * in its behalf permission to use and distribute the software in
51  * accordance with the terms specified in this license.
52  *
53  */
54
55 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
56 #include <config.h>
57 #include "gtktextbtree.h"
58 #include <string.h>
59 #include <stdlib.h>
60 #include <stdio.h>
61 #include "gtktexttag.h"
62 #include "gtktexttagtable.h"
63 #include "gtktextlayout.h"
64 #include "gtktextiterprivate.h"
65 #include "gtkdebug.h"
66 #include "gtktextmarkprivate.h"
67
68 /*
69  * Types
70  */
71
72
73 /*
74  * The structure below is used to pass information between
75  * _gtk_text_btree_get_tags and inc_count:
76  */
77
78 typedef struct TagInfo {
79   int numTags;                  /* Number of tags for which there
80                                  * is currently information in
81                                  * tags and counts. */
82   int arraySize;                        /* Number of entries allocated for
83                                          * tags and counts. */
84   GtkTextTag **tags;           /* Array of tags seen so far.
85                                 * Malloc-ed. */
86   int *counts;                  /* Toggle count (so far) for each
87                                  * entry in tags.  Malloc-ed. */
88 } TagInfo;
89
90
91 /*
92  * This is used to store per-view width/height info at the tree nodes.
93  */
94
95 typedef struct _NodeData NodeData;
96
97 struct _NodeData {
98   gpointer view_id;
99   NodeData *next;
100
101   /* Height and width of this node */
102   gint height;
103   signed int width : 24;
104
105   /* boolean indicating whether the lines below this node are in need of validation.
106    * However, width/height should always represent the current total width and
107    * max height for lines below this node; the valid flag indicates whether the
108    * width/height on the lines needs recomputing, not whether the totals
109    * need recomputing.
110    */
111   guint valid : 8;              /* Actually a boolean */
112 };
113
114
115 /*
116  * The data structure below keeps summary information about one tag as part
117  * of the tag information in a node.
118  */
119
120 typedef struct Summary {
121   GtkTextTagInfo *info;                     /* Handle for tag. */
122   int toggle_count;                     /* Number of transitions into or
123                                          * out of this tag that occur in
124                                          * the subtree rooted at this node. */
125   struct Summary *next;         /* Next in list of all tags for same
126                                  * node, or NULL if at end of list. */
127 } Summary;
128
129 /*
130  * The data structure below defines a node in the B-tree.
131  */
132
133 struct _GtkTextBTreeNode {
134   GtkTextBTreeNode *parent;         /* Pointer to parent node, or NULL if
135                                      * this is the root. */
136   GtkTextBTreeNode *next;           /* Next in list of siblings with the
137                                      * same parent node, or NULL for end
138                                      * of list. */
139   Summary *summary;             /* First in malloc-ed list of info
140                                  * about tags in this subtree (NULL if
141                                  * no tag info in the subtree). */
142   int level;                            /* Level of this node in the B-tree.
143                                          * 0 refers to the bottom of the tree
144                                          * (children are lines, not nodes). */
145   union {                               /* First in linked list of children. */
146     struct _GtkTextBTreeNode *node;         /* Used if level > 0. */
147     GtkTextLine *line;         /* Used if level == 0. */
148   } children;
149   int num_children;                     /* Number of children of this node. */
150   int num_lines;                        /* Total number of lines (leaves) in
151                                          * the subtree rooted here. */
152   int num_chars;                        /* Number of chars below here */
153
154   NodeData *node_data;
155 };
156
157
158 /*
159  * Used to store the list of views in our btree
160  */
161
162 typedef struct _BTreeView BTreeView;
163
164 struct _BTreeView {
165   gpointer view_id;
166   GtkTextLayout *layout;
167   BTreeView *next;
168   BTreeView *prev;
169 };
170
171 /*
172  * And the tree itself
173  */
174
175 struct _GtkTextBTree {
176   GtkTextBTreeNode *root_node;          /* Pointer to root of B-tree. */
177   GtkTextTagTable *table;
178   GHashTable *mark_table;
179   guint refcount;
180   GtkTextMark *insert_mark;
181   GtkTextMark *selection_bound_mark;
182   GtkTextBuffer *buffer;
183   BTreeView *views;
184   GSList *tag_infos;
185   gulong tag_changed_handler;
186
187   /* Incremented when a segment with a byte size > 0
188    * is added to or removed from the tree (i.e. the
189    * length of a line may have changed, and lines may
190    * have been added or removed). This invalidates
191    * all outstanding iterators.
192    */
193   guint chars_changed_stamp;
194   /* Incremented when any segments are added or deleted;
195    * this makes outstanding iterators recalculate their
196    * pointed-to segment and segment offset.
197    */
198   guint segments_changed_stamp;
199
200   /* Cache the last line in the buffer */
201   GtkTextLine *last_line;
202   guint last_line_stamp;
203
204   /* Cache the next-to-last line in the buffer,
205    * containing the end iterator
206    */
207   GtkTextLine *end_iter_line;
208   GtkTextLineSegment *end_iter_segment;
209   int end_iter_segment_byte_index;
210   int end_iter_segment_char_offset;
211   guint end_iter_line_stamp;
212   guint end_iter_segment_stamp;
213   
214   GHashTable *child_anchor_table;
215 };
216
217
218 /*
219  * Upper and lower bounds on how many children a node may have:
220  * rebalance when either of these limits is exceeded.  MAX_CHILDREN
221  * should be twice MIN_CHILDREN and MIN_CHILDREN must be >= 2.
222  */
223
224 /* Tk used MAX of 12 and MIN of 6. This makes the tree wide and
225    shallow. It appears to be faster to locate a particular line number
226    if the tree is narrow and deep, since it is more finely sorted.  I
227    guess this may increase memory use though, and make it slower to
228    walk the tree in order, or locate a particular byte index (which
229    is done by walking the tree in order).
230
231    There's basically a tradeoff here. However I'm thinking we want to
232    add pixels, byte counts, and char counts to the tree nodes,
233    at that point narrow and deep should speed up all operations,
234    not just the line number searches.
235 */
236
237 #if 1
238 #define MAX_CHILDREN 12
239 #define MIN_CHILDREN 6
240 #else
241 #define MAX_CHILDREN 6
242 #define MIN_CHILDREN 3
243 #endif
244
245 /*
246  * Prototypes
247  */
248
249 static BTreeView        *gtk_text_btree_get_view                 (GtkTextBTree     *tree,
250                                                                   gpointer          view_id);
251 static void              gtk_text_btree_rebalance                (GtkTextBTree     *tree,
252                                                                   GtkTextBTreeNode *node);
253 static GtkTextLine     * get_last_line                           (GtkTextBTree     *tree);
254 static void              post_insert_fixup                       (GtkTextBTree     *tree,
255                                                                   GtkTextLine      *insert_line,
256                                                                   gint              char_count_delta,
257                                                                   gint              line_count_delta);
258 static void              gtk_text_btree_node_adjust_toggle_count (GtkTextBTreeNode *node,
259                                                                   GtkTextTagInfo   *info,
260                                                                   gint              adjust);
261 static gboolean          gtk_text_btree_node_has_tag             (GtkTextBTreeNode *node,
262                                                                   GtkTextTag       *tag);
263
264 static void             segments_changed                (GtkTextBTree     *tree);
265 static void             chars_changed                   (GtkTextBTree     *tree);
266 static void             summary_list_destroy            (Summary          *summary);
267 static GtkTextLine     *gtk_text_line_new               (void);
268 static void             gtk_text_line_destroy           (GtkTextBTree     *tree,
269                                                          GtkTextLine      *line);
270 static void             gtk_text_line_set_parent        (GtkTextLine      *line,
271                                                          GtkTextBTreeNode *node);
272 static void             gtk_text_btree_node_remove_data (GtkTextBTreeNode *node,
273                                                          gpointer          view_id);
274
275
276 static NodeData         *node_data_new          (gpointer  view_id);
277 static void              node_data_destroy      (NodeData *nd);
278 static void              node_data_list_destroy (NodeData *nd);
279 static NodeData         *node_data_find         (NodeData *nd,
280                                                  gpointer  view_id);
281
282 static GtkTextBTreeNode     *gtk_text_btree_node_new                  (void);
283 static void                  gtk_text_btree_node_invalidate_downward  (GtkTextBTreeNode *node);
284 static void                  gtk_text_btree_node_invalidate_upward    (GtkTextBTreeNode *node,
285                                                                        gpointer          view_id);
286 static NodeData *            gtk_text_btree_node_check_valid          (GtkTextBTreeNode *node,
287                                                                        gpointer          view_id);
288 static NodeData *            gtk_text_btree_node_check_valid_downward (GtkTextBTreeNode *node,
289                                                                        gpointer          view_id);
290 static void                  gtk_text_btree_node_check_valid_upward   (GtkTextBTreeNode *node,
291                                                                        gpointer          view_id);
292
293 static void                  gtk_text_btree_node_remove_view         (BTreeView        *view,
294                                                                       GtkTextBTreeNode *node,
295                                                                       gpointer          view_id);
296 static void                  gtk_text_btree_node_destroy             (GtkTextBTree     *tree,
297                                                                       GtkTextBTreeNode *node);
298 static void                  gtk_text_btree_node_free_empty          (GtkTextBTree *tree,
299                                                                       GtkTextBTreeNode *node);
300 static NodeData         *    gtk_text_btree_node_ensure_data         (GtkTextBTreeNode *node,
301                                                                       gpointer          view_id);
302 static void                  gtk_text_btree_node_remove_data         (GtkTextBTreeNode *node,
303                                                                       gpointer          view_id);
304 static void                  gtk_text_btree_node_get_size            (GtkTextBTreeNode *node,
305                                                                       gpointer          view_id,
306                                                                       gint             *width,
307                                                                       gint             *height);
308 static GtkTextBTreeNode *    gtk_text_btree_node_common_parent       (GtkTextBTreeNode *node1,
309                                                                       GtkTextBTreeNode *node2);
310 static void get_tree_bounds       (GtkTextBTree     *tree,
311                                    GtkTextIter      *start,
312                                    GtkTextIter      *end);
313 static void tag_changed_cb        (GtkTextTagTable  *table,
314                                    GtkTextTag       *tag,
315                                    gboolean          size_changed,
316                                    GtkTextBTree     *tree);
317 static void cleanup_line          (GtkTextLine      *line);
318 static void recompute_node_counts (GtkTextBTree     *tree,
319                                    GtkTextBTreeNode *node);
320 static void inc_count             (GtkTextTag       *tag,
321                                    int               inc,
322                                    TagInfo          *tagInfoPtr);
323
324 static void summary_destroy       (Summary          *summary);
325
326 static void gtk_text_btree_link_segment   (GtkTextLineSegment *seg,
327                                            const GtkTextIter  *iter);
328 static void gtk_text_btree_unlink_segment (GtkTextBTree       *tree,
329                                            GtkTextLineSegment *seg,
330                                            GtkTextLine        *line);
331
332
333 static GtkTextTagInfo *gtk_text_btree_get_tag_info          (GtkTextBTree   *tree,
334                                                              GtkTextTag     *tag);
335 static GtkTextTagInfo *gtk_text_btree_get_existing_tag_info (GtkTextBTree   *tree,
336                                                              GtkTextTag     *tag);
337 static void            gtk_text_btree_remove_tag_info       (GtkTextBTree   *tree,
338                                                              GtkTextTag     *tag);
339
340 static void redisplay_region (GtkTextBTree      *tree,
341                               const GtkTextIter *start,
342                               const GtkTextIter *end);
343
344 /* Inline thingies */
345
346 static inline void
347 segments_changed (GtkTextBTree *tree)
348 {
349   tree->segments_changed_stamp += 1;
350 }
351
352 static inline void
353 chars_changed (GtkTextBTree *tree)
354 {
355   tree->chars_changed_stamp += 1;
356 }
357
358 /*
359  * BTree operations
360  */
361
362 GtkTextBTree*
363 _gtk_text_btree_new (GtkTextTagTable *table,
364                      GtkTextBuffer *buffer)
365 {
366   GtkTextBTree *tree;
367   GtkTextBTreeNode *root_node;
368   GtkTextLine *line, *line2;
369
370   g_return_val_if_fail (GTK_IS_TEXT_TAG_TABLE (table), NULL);
371   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
372
373   /*
374    * The tree will initially have two empty lines.  The second line
375    * isn't actually part of the tree's contents, but its presence
376    * makes several operations easier.  The tree will have one GtkTextBTreeNode,
377    * which is also the root of the tree.
378    */
379
380   /* Create the root node. */
381
382   root_node = gtk_text_btree_node_new ();
383
384   line = gtk_text_line_new ();
385   line2 = gtk_text_line_new ();
386
387   root_node->parent = NULL;
388   root_node->next = NULL;
389   root_node->summary = NULL;
390   root_node->level = 0;
391   root_node->children.line = line;
392   root_node->num_children = 2;
393   root_node->num_lines = 2;
394   root_node->num_chars = 2;
395
396   line->parent = root_node;
397   line->next = line2;
398
399   line->segments = _gtk_char_segment_new ("\n", 1);
400
401   line2->parent = root_node;
402   line2->next = NULL;
403   line2->segments = _gtk_char_segment_new ("\n", 1);
404
405   /* Create the tree itself */
406
407   tree = g_new0(GtkTextBTree, 1);
408   tree->root_node = root_node;
409   tree->table = table;
410   tree->views = NULL;
411
412   /* Set these to values that are unlikely to be found
413    * in random memory garbage, and also avoid
414    * duplicates between tree instances.
415    */
416   tree->chars_changed_stamp = g_random_int ();
417   tree->segments_changed_stamp = g_random_int ();
418
419   tree->last_line_stamp = tree->chars_changed_stamp - 1;
420   tree->last_line = NULL;
421
422   tree->end_iter_line_stamp = tree->chars_changed_stamp - 1;
423   tree->end_iter_segment_stamp = tree->segments_changed_stamp - 1;
424   tree->end_iter_line = NULL;
425   tree->end_iter_segment_byte_index = 0;
426   tree->end_iter_segment_char_offset = 0;
427   
428   g_object_ref (tree->table);
429
430   tree->tag_changed_handler = g_signal_connect (tree->table,
431                                                 "tag_changed",
432                                                 G_CALLBACK (tag_changed_cb),
433                                                 tree);
434
435   tree->mark_table = g_hash_table_new (g_str_hash, g_str_equal);
436   tree->child_anchor_table = NULL;
437   
438   /* We don't ref the buffer, since the buffer owns us;
439    * we'd have some circularity issues. The buffer always
440    * lasts longer than the BTree
441    */
442   tree->buffer = buffer;
443
444   {
445     GtkTextIter start;
446     GtkTextLineSegment *seg;
447
448     _gtk_text_btree_get_iter_at_line_char (tree, &start, 0, 0);
449
450
451     tree->insert_mark = _gtk_text_btree_set_mark (tree,
452                                                  NULL,
453                                                  "insert",
454                                                  FALSE,
455                                                  &start,
456                                                  FALSE);
457
458     seg = tree->insert_mark->segment;
459
460     seg->body.mark.not_deleteable = TRUE;
461     seg->body.mark.visible = TRUE;
462
463     tree->selection_bound_mark = _gtk_text_btree_set_mark (tree,
464                                                           NULL,
465                                                           "selection_bound",
466                                                           FALSE,
467                                                           &start,
468                                                           FALSE);
469
470     seg = tree->selection_bound_mark->segment;
471
472     seg->body.mark.not_deleteable = TRUE;
473
474     g_object_ref (tree->insert_mark);
475     g_object_ref (tree->selection_bound_mark);
476   }
477
478   tree->refcount = 1;
479
480   return tree;
481 }
482
483 void
484 _gtk_text_btree_ref (GtkTextBTree *tree)
485 {
486   g_return_if_fail (tree != NULL);
487   g_return_if_fail (tree->refcount > 0);
488
489   tree->refcount += 1;
490 }
491
492 void
493 _gtk_text_btree_unref (GtkTextBTree *tree)
494 {
495   g_return_if_fail (tree != NULL);
496   g_return_if_fail (tree->refcount > 0);
497
498   tree->refcount -= 1;
499
500   if (tree->refcount == 0)
501     {      
502       g_signal_handler_disconnect (tree->table,
503                                    tree->tag_changed_handler);
504
505       g_object_unref (tree->table);
506       tree->table = NULL;
507       
508       gtk_text_btree_node_destroy (tree, tree->root_node);
509       tree->root_node = NULL;
510       
511       g_assert (g_hash_table_size (tree->mark_table) == 0);
512       g_hash_table_destroy (tree->mark_table);
513       tree->mark_table = NULL;
514       if (tree->child_anchor_table != NULL) 
515         {
516           g_hash_table_destroy (tree->child_anchor_table);
517           tree->child_anchor_table = NULL;
518         }
519
520       g_object_unref (tree->insert_mark);
521       tree->insert_mark = NULL;
522       g_object_unref (tree->selection_bound_mark);
523       tree->selection_bound_mark = NULL;
524
525       g_free (tree);
526     }
527 }
528
529 GtkTextBuffer*
530 _gtk_text_btree_get_buffer (GtkTextBTree *tree)
531 {
532   return tree->buffer;
533 }
534
535 guint
536 _gtk_text_btree_get_chars_changed_stamp (GtkTextBTree *tree)
537 {
538   return tree->chars_changed_stamp;
539 }
540
541 guint
542 _gtk_text_btree_get_segments_changed_stamp (GtkTextBTree *tree)
543 {
544   return tree->segments_changed_stamp;
545 }
546
547 void
548 _gtk_text_btree_segments_changed (GtkTextBTree *tree)
549 {
550   g_return_if_fail (tree != NULL);
551   segments_changed (tree);
552 }
553
554 /*
555  * Indexable segment mutation
556  */
557
558 /*
559  *  The following function is responsible for resolving the bidi direction
560  *  for the lines between start and end. But it also calculates any
561  *  dependent bidi direction for surrounding lines that change as a result
562  *  of the bidi direction decisions within the range. The function is
563  *  trying to do as little propagation as is needed.
564  */
565 static void
566 gtk_text_btree_resolve_bidi (GtkTextIter *start,
567                              GtkTextIter *end)
568 {
569   GtkTextBTree *tree = _gtk_text_iter_get_btree (start);
570   GtkTextLine *start_line, *end_line, *start_line_prev, *end_line_next, *line;
571   PangoDirection last_strong, dir_above_propagated, dir_below_propagated;
572
573   /* Resolve the strong bidi direction for all lines between
574    * start and end.
575   */
576   start_line = _gtk_text_iter_get_text_line (start);
577   start_line_prev = _gtk_text_line_previous (start_line);
578   end_line = _gtk_text_iter_get_text_line (end);
579   end_line_next = _gtk_text_line_next (end_line);
580   
581   line = start_line;
582   while (line && line != end_line_next)
583     {
584       /* Loop through the segments and search for a strong character
585        */
586       GtkTextLineSegment *seg = line->segments;
587       line->dir_strong = PANGO_DIRECTION_NEUTRAL;
588       
589       while (seg)
590         {
591           if (seg->byte_count > 0)
592             {
593               PangoDirection pango_dir;
594
595               pango_dir = pango_find_base_dir (seg->body.chars,
596                                                seg->byte_count);
597               
598               if (pango_dir != PANGO_DIRECTION_NEUTRAL)
599                 {
600                   line->dir_strong = pango_dir;
601                   break;
602                 }
603             }
604           seg = seg->next;
605         }
606
607       line = _gtk_text_line_next (line);
608     }
609
610   /* Sweep forward */
611
612   /* The variable dir_above_propagated contains the forward propagated
613    * direction before start. It is neutral if start is in the beginning
614    * of the buffer.
615    */
616   dir_above_propagated = PANGO_DIRECTION_NEUTRAL;
617   if (start_line_prev)
618     dir_above_propagated = start_line_prev->dir_propagated_forward;
619
620   /* Loop forward and propagate the direction of each paragraph 
621    * to all neutral lines.
622    */
623   line = start_line;
624   last_strong = dir_above_propagated;
625   while (line != end_line_next)
626     {
627       if (line->dir_strong != PANGO_DIRECTION_NEUTRAL)
628         last_strong = line->dir_strong;
629       
630       line->dir_propagated_forward = last_strong;
631       
632       line = _gtk_text_line_next (line);
633     }
634
635   /* Continue propagating as long as the previous resolved forward
636    * is different from last_strong.
637    */
638   {
639     GtkTextIter end_propagate;
640     
641     while (line &&
642            line->dir_strong == PANGO_DIRECTION_NEUTRAL &&
643            line->dir_propagated_forward != last_strong)
644       {
645         GtkTextLine *prev = line;
646         line->dir_propagated_forward = last_strong;
647         
648         line = _gtk_text_line_next(line);
649         if (!line)
650           {
651             line = prev;
652             break;
653           }
654       }
655
656     /* The last line to invalidate is the last line before the
657      * line with the strong character. Or in case of the end of the
658      * buffer, the last line of the buffer. (There seems to be an
659      * extra "virtual" last line in the buffer that must not be used
660      * calling _gtk_text_btree_get_iter_at_line (causes crash). Thus the
661      * _gtk_text_line_previous is ok in that case as well.)
662      */
663     line = _gtk_text_line_previous (line);
664     _gtk_text_btree_get_iter_at_line (tree, &end_propagate, line, 0);
665     _gtk_text_btree_invalidate_region (tree, end, &end_propagate);
666   }
667   
668   /* Sweep backward */
669
670   /* The variable dir_below_propagated contains the backward propagated
671    * direction after end. It is neutral if end is at the end of
672    * the buffer.
673   */
674   dir_below_propagated = PANGO_DIRECTION_NEUTRAL;
675   if (end_line_next)
676     dir_below_propagated = end_line_next->dir_propagated_back;
677
678   /* Loop backward and propagate the direction of each paragraph 
679    * to all neutral lines.
680    */
681   line = end_line;
682   last_strong = dir_below_propagated;
683   while (line != start_line_prev)
684     {
685       if (line->dir_strong != PANGO_DIRECTION_NEUTRAL)
686         last_strong = line->dir_strong;
687
688       line->dir_propagated_back = last_strong;
689
690       line = _gtk_text_line_previous (line);
691     }
692
693   /* Continue propagating as long as the resolved backward dir
694    * is different from last_strong.
695    */
696   {
697     GtkTextIter start_propagate;
698
699     while (line &&
700            line->dir_strong == PANGO_DIRECTION_NEUTRAL &&
701            line->dir_propagated_back != last_strong)
702       {
703         GtkTextLine *prev = line;
704         line->dir_propagated_back = last_strong;
705
706         line = _gtk_text_line_previous (line);
707         if (!line)
708           {
709             line = prev;
710             break;
711           }
712       }
713
714     /* We only need to invalidate for backwards propagation if the
715      * line we ended up on didn't get a direction from forwards
716      * propagation.
717      */
718     if (line && line->dir_propagated_forward == PANGO_DIRECTION_NEUTRAL)
719       {
720         _gtk_text_btree_get_iter_at_line (tree, &start_propagate, line, 0);
721         _gtk_text_btree_invalidate_region(tree, &start_propagate, start);
722       }
723   }
724 }
725
726 void
727 _gtk_text_btree_delete (GtkTextIter *start,
728                         GtkTextIter *end)
729 {
730   GtkTextLineSegment *prev_seg;             /* The segment just before the start
731                                              * of the deletion range. */
732   GtkTextLineSegment *last_seg;             /* The segment just after the end
733                                              * of the deletion range. */
734   GtkTextLineSegment *seg, *next;
735   GtkTextLine *curline;
736   GtkTextBTreeNode *curnode, *node;
737   GtkTextBTree *tree;
738   GtkTextLine *start_line;
739   GtkTextLine *end_line;
740   GtkTextLine *deleted_lines = NULL;        /* List of lines we've deleted */
741   gint start_byte_offset;
742
743   g_return_if_fail (start != NULL);
744   g_return_if_fail (end != NULL);
745   g_return_if_fail (_gtk_text_iter_get_btree (start) ==
746                     _gtk_text_iter_get_btree (end));
747
748   gtk_text_iter_order (start, end);
749
750   tree = _gtk_text_iter_get_btree (start);
751  
752   if (gtk_debug_flags & GTK_DEBUG_TEXT)
753     _gtk_text_btree_check (tree);
754   
755   /* Broadcast the need for redisplay before we break the iterators */
756   DV (g_print ("invalidating due to deleting some text (%s)\n", G_STRLOC));
757   _gtk_text_btree_invalidate_region (tree, start, end);
758
759   /* Save the byte offset so we can reset the iterators */
760   start_byte_offset = gtk_text_iter_get_line_index (start);
761
762   start_line = _gtk_text_iter_get_text_line (start);
763   end_line = _gtk_text_iter_get_text_line (end);
764
765   /*
766    * Split the start and end segments, so we have a place
767    * to insert our new text.
768    *
769    * Tricky point:  split at end first;  otherwise the split
770    * at end may invalidate seg and/or prev_seg. This allows
771    * us to avoid invalidating segments for start.
772    */
773
774   last_seg = gtk_text_line_segment_split (end);
775   if (last_seg != NULL)
776     last_seg = last_seg->next;
777   else
778     last_seg = end_line->segments;
779
780   prev_seg = gtk_text_line_segment_split (start);
781   if (prev_seg != NULL)
782     {
783       seg = prev_seg->next;
784       prev_seg->next = last_seg;
785     }
786   else
787     {
788       seg = start_line->segments;
789       start_line->segments = last_seg;
790     }
791
792   /* notify iterators that their segments need recomputation,
793      just for robustness. */
794   segments_changed (tree);
795
796   /*
797    * Delete all of the segments between prev_seg and last_seg.
798    */
799
800   curline = start_line;
801   curnode = curline->parent;
802   while (seg != last_seg)
803     {
804       gint char_count = 0;
805
806       if (seg == NULL)
807         {
808           GtkTextLine *nextline;
809
810           /*
811            * We just ran off the end of a line.  First find the
812            * next line, then go back to the old line and delete it
813            * (unless it's the starting line for the range).
814            */
815
816           nextline = _gtk_text_line_next (curline);
817           if (curline != start_line)
818             {
819               if (curnode == start_line->parent)
820                 start_line->next = curline->next;
821               else
822                 curnode->children.line = curline->next;
823
824               for (node = curnode; node != NULL;
825                    node = node->parent)
826                 {
827                   /* Don't update node->num_chars, because
828                    * that was done when we deleted the segments.
829                    */
830                   node->num_lines -= 1;
831                 }
832
833               curnode->num_children -= 1;
834               curline->next = deleted_lines;
835               deleted_lines = curline;
836             }
837
838           curline = nextline;
839           seg = curline->segments;
840
841           /*
842            * If the GtkTextBTreeNode is empty then delete it and its parents,
843            * recursively upwards until a non-empty GtkTextBTreeNode is found.
844            */
845
846           while (curnode->num_children == 0)
847             {
848               GtkTextBTreeNode *parent;
849
850               parent = curnode->parent;
851               if (parent->children.node == curnode)
852                 {
853                   parent->children.node = curnode->next;
854                 }
855               else
856                 {
857                   GtkTextBTreeNode *prevnode = parent->children.node;
858                   while (prevnode->next != curnode)
859                     {
860                       prevnode = prevnode->next;
861                     }
862                   prevnode->next = curnode->next;
863                 }
864               parent->num_children--;
865               gtk_text_btree_node_free_empty (tree, curnode);
866               curnode = parent;
867             }
868           curnode = curline->parent;
869           continue;
870         }
871
872       next = seg->next;
873       char_count = seg->char_count;
874
875       if ((*seg->type->deleteFunc)(seg, curline, FALSE) != 0)
876         {
877           /*
878            * This segment refuses to die.  Move it to prev_seg and
879            * advance prev_seg if the segment has left gravity.
880            */
881
882           if (prev_seg == NULL)
883             {
884               seg->next = start_line->segments;
885               start_line->segments = seg;
886             }
887           else
888             {
889               seg->next = prev_seg->next;
890               prev_seg->next = seg;
891             }
892           if (seg->type->leftGravity)
893             {
894               prev_seg = seg;
895             }
896         }
897       else
898         {
899           /* Segment is gone. Decrement the char count of the node and
900              all its parents. */
901           for (node = curnode; node != NULL;
902                node = node->parent)
903             {
904               node->num_chars -= char_count;
905             }
906         }
907
908       seg = next;
909     }
910
911   /*
912    * If the beginning and end of the deletion range are in different
913    * lines, join the two lines together and discard the ending line.
914    */
915
916   if (start_line != end_line)
917     {
918       BTreeView *view;
919       GtkTextBTreeNode *ancestor_node;
920       GtkTextLine *prevline;
921       int chars_moved;      
922
923       /* last_seg was appended to start_line up at the top of this function */
924       chars_moved = 0;
925       for (seg = last_seg; seg != NULL;
926            seg = seg->next)
927         {
928           chars_moved += seg->char_count;
929           if (seg->type->lineChangeFunc != NULL)
930             {
931               (*seg->type->lineChangeFunc)(seg, end_line);
932             }
933         }
934
935       for (node = start_line->parent; node != NULL;
936            node = node->parent)
937         {
938           node->num_chars += chars_moved;
939         }
940       
941       curnode = end_line->parent;
942       for (node = curnode; node != NULL;
943            node = node->parent)
944         {
945           node->num_chars -= chars_moved;
946           node->num_lines--;
947         }
948       curnode->num_children--;
949       prevline = curnode->children.line;
950       if (prevline == end_line)
951         {
952           curnode->children.line = end_line->next;
953         }
954       else
955         {
956           while (prevline->next != end_line)
957             {
958               prevline = prevline->next;
959             }
960           prevline->next = end_line->next;
961         }
962       end_line->next = deleted_lines;
963       deleted_lines = end_line;
964
965       /* We now fix up the per-view aggregates. We add all the height and
966        * width for the deleted lines to the start line, so that when revalidation
967        * occurs, the correct change in size is seen.
968        */
969       ancestor_node = gtk_text_btree_node_common_parent (curnode, start_line->parent);
970       view = tree->views;
971       while (view)
972         {
973           GtkTextLine *line;
974           GtkTextLineData *ld;
975
976           gint deleted_width = 0;
977           gint deleted_height = 0;
978
979           line = deleted_lines;
980           while (line)
981             {
982               GtkTextLine *next_line = line->next;
983               ld = _gtk_text_line_get_data (line, view->view_id);
984
985               if (ld)
986                 {
987                   deleted_width = MAX (deleted_width, ld->width);
988                   deleted_height += ld->height;
989                 }
990
991               if (!view->next)
992                 gtk_text_line_destroy (tree, line);
993
994               line = next_line;
995             }
996
997           if (deleted_width > 0 || deleted_height > 0)
998             {
999               ld = _gtk_text_line_get_data (start_line, view->view_id);
1000               
1001               if (ld == NULL)
1002                 {
1003                   /* This means that start_line has never been validated.
1004                    * We don't really want to do the validation here but
1005                    * we do need to store our temporary sizes. So we
1006                    * create the line data and assume a line w/h of 0.
1007                    */
1008                   ld = _gtk_text_line_data_new (view->layout, start_line);
1009                   _gtk_text_line_add_data (start_line, ld);
1010                   ld->width = 0;
1011                   ld->height = 0;
1012                   ld->valid = FALSE;
1013                 }
1014               
1015               ld->width = MAX (deleted_width, ld->width);
1016               ld->height += deleted_height;
1017               ld->valid = FALSE;
1018             }
1019
1020           gtk_text_btree_node_check_valid_downward (ancestor_node, view->view_id);
1021           if (ancestor_node->parent)
1022             gtk_text_btree_node_check_valid_upward (ancestor_node->parent, view->view_id);
1023
1024           view = view->next;
1025         }
1026
1027       /* avoid dangling pointer */
1028       deleted_lines = NULL;
1029       
1030       gtk_text_btree_rebalance (tree, curnode);
1031     }
1032
1033   /*
1034    * Cleanup the segments in the new line.
1035    */
1036
1037   cleanup_line (start_line);
1038
1039   /*
1040    * Lastly, rebalance the first GtkTextBTreeNode of the range.
1041    */
1042
1043   gtk_text_btree_rebalance (tree, start_line->parent);
1044
1045   /* Notify outstanding iterators that they
1046      are now hosed */
1047   chars_changed (tree);
1048   segments_changed (tree);
1049
1050   if (gtk_debug_flags & GTK_DEBUG_TEXT)
1051     _gtk_text_btree_check (tree);
1052
1053   /* Re-initialize our iterators */
1054   _gtk_text_btree_get_iter_at_line (tree, start, start_line, start_byte_offset);
1055   *end = *start;
1056
1057   gtk_text_btree_resolve_bidi (start, end);
1058 }
1059
1060 void
1061 _gtk_text_btree_insert (GtkTextIter *iter,
1062                         const gchar *text,
1063                         gint         len)
1064 {
1065   GtkTextLineSegment *prev_seg;     /* The segment just before the first
1066                                      * new segment (NULL means new segment
1067                                      * is at beginning of line). */
1068   GtkTextLineSegment *cur_seg;              /* Current segment;  new characters
1069                                              * are inserted just after this one.
1070                                              * NULL means insert at beginning of
1071                                              * line. */
1072   GtkTextLine *line;           /* Current line (new segments are
1073                                 * added to this line). */
1074   GtkTextLineSegment *seg;
1075   GtkTextLine *newline;
1076   int chunk_len;                        /* # characters in current chunk. */
1077   gint sol;                           /* start of line */
1078   gint eol;                           /* Pointer to character just after last
1079                                        * one in current chunk.
1080                                        */
1081   gint delim;                          /* index of paragraph delimiter */
1082   int line_count_delta;                /* Counts change to total number of
1083                                         * lines in file.
1084                                         */
1085
1086   int char_count_delta;                /* change to number of chars */
1087   GtkTextBTree *tree;
1088   gint start_byte_index;
1089   GtkTextLine *start_line;
1090
1091   g_return_if_fail (text != NULL);
1092   g_return_if_fail (iter != NULL);
1093
1094   if (len < 0)
1095     len = strlen (text);
1096
1097   /* extract iterator info */
1098   tree = _gtk_text_iter_get_btree (iter);
1099   line = _gtk_text_iter_get_text_line (iter);
1100   
1101   start_line = line;
1102   start_byte_index = gtk_text_iter_get_line_index (iter);
1103
1104   /* Get our insertion segment split. Note this assumes line allows
1105    * char insertions, which isn't true of the "last" line. But iter
1106    * should not be on that line, as we assert here.
1107    */
1108   g_assert (!_gtk_text_line_is_last (line, tree));
1109   prev_seg = gtk_text_line_segment_split (iter);
1110   cur_seg = prev_seg;
1111
1112   /* Invalidate all iterators */
1113   chars_changed (tree);
1114   segments_changed (tree);
1115   
1116   /*
1117    * Chop the text up into lines and create a new segment for
1118    * each line, plus a new line for the leftovers from the
1119    * previous line.
1120    */
1121
1122   eol = 0;
1123   sol = 0;
1124   line_count_delta = 0;
1125   char_count_delta = 0;
1126   while (eol < len)
1127     {
1128       sol = eol;
1129       
1130       pango_find_paragraph_boundary (text + sol,
1131                                      len - sol,
1132                                      &delim,
1133                                      &eol);      
1134
1135       /* make these relative to the start of the text */
1136       delim += sol;
1137       eol += sol;
1138
1139       g_assert (eol >= sol);
1140       g_assert (delim >= sol);
1141       g_assert (eol >= delim);
1142       g_assert (sol >= 0);
1143       g_assert (eol <= len);
1144       
1145       chunk_len = eol - sol;
1146
1147       g_assert (g_utf8_validate (&text[sol], chunk_len, NULL));
1148       seg = _gtk_char_segment_new (&text[sol], chunk_len);
1149
1150       char_count_delta += seg->char_count;
1151
1152       if (cur_seg == NULL)
1153         {
1154           seg->next = line->segments;
1155           line->segments = seg;
1156         }
1157       else
1158         {
1159           seg->next = cur_seg->next;
1160           cur_seg->next = seg;
1161         }
1162
1163       if (delim == eol)
1164         {
1165           /* chunk didn't end with a paragraph separator */
1166           g_assert (eol == len);
1167           break;
1168         }
1169
1170       /*
1171        * The chunk ended with a newline, so create a new GtkTextLine
1172        * and move the remainder of the old line to it.
1173        */
1174
1175       newline = gtk_text_line_new ();
1176       gtk_text_line_set_parent (newline, line->parent);
1177       newline->next = line->next;
1178       line->next = newline;
1179       newline->segments = seg->next;
1180       seg->next = NULL;
1181       line = newline;
1182       cur_seg = NULL;
1183       line_count_delta++;
1184     }
1185
1186   /*
1187    * Cleanup the starting line for the insertion, plus the ending
1188    * line if it's different.
1189    */
1190
1191   cleanup_line (start_line);
1192   if (line != start_line)
1193     {
1194       cleanup_line (line);
1195     }
1196
1197   post_insert_fixup (tree, line, line_count_delta, char_count_delta);
1198
1199   /* Invalidate our region, and reset the iterator the user
1200      passed in to point to the end of the inserted text. */
1201   {
1202     GtkTextIter start;
1203     GtkTextIter end;
1204
1205
1206     _gtk_text_btree_get_iter_at_line (tree,
1207                                       &start,
1208                                       start_line,
1209                                       start_byte_index);
1210     end = start;
1211
1212     /* We could almost certainly be more efficient here
1213        by saving the information from the insertion loop
1214        above. FIXME */
1215     gtk_text_iter_forward_chars (&end, char_count_delta);
1216
1217     DV (g_print ("invalidating due to inserting some text (%s)\n", G_STRLOC));
1218     _gtk_text_btree_invalidate_region (tree,
1219                                       &start, &end);
1220
1221
1222     /* Convenience for the user */
1223     *iter = end;
1224
1225     gtk_text_btree_resolve_bidi (&start, &end);
1226   }
1227 }
1228
1229 static void
1230 insert_pixbuf_or_widget_segment (GtkTextIter        *iter,
1231                                  GtkTextLineSegment *seg)
1232
1233 {
1234   GtkTextIter start;
1235   GtkTextLineSegment *prevPtr;
1236   GtkTextLine *line;
1237   GtkTextBTree *tree;
1238   gint start_byte_offset;
1239
1240   line = _gtk_text_iter_get_text_line (iter);
1241   tree = _gtk_text_iter_get_btree (iter);
1242   start_byte_offset = gtk_text_iter_get_line_index (iter);
1243
1244   prevPtr = gtk_text_line_segment_split (iter);
1245   if (prevPtr == NULL)
1246     {
1247       seg->next = line->segments;
1248       line->segments = seg;
1249     }
1250   else
1251     {
1252       seg->next = prevPtr->next;
1253       prevPtr->next = seg;
1254     }
1255
1256   post_insert_fixup (tree, line, 0, seg->char_count);
1257
1258   chars_changed (tree);
1259   segments_changed (tree);
1260
1261   /* reset *iter for the user, and invalidate tree nodes */
1262
1263   _gtk_text_btree_get_iter_at_line (tree, &start, line, start_byte_offset);
1264
1265   *iter = start;
1266   gtk_text_iter_forward_char (iter); /* skip forward past the segment */
1267
1268   DV (g_print ("invalidating due to inserting pixbuf/widget (%s)\n", G_STRLOC));
1269   _gtk_text_btree_invalidate_region (tree, &start, iter);
1270 }
1271      
1272 void
1273 _gtk_text_btree_insert_pixbuf (GtkTextIter *iter,
1274                               GdkPixbuf   *pixbuf)
1275 {
1276   GtkTextLineSegment *seg;
1277   
1278   seg = _gtk_pixbuf_segment_new (pixbuf);
1279
1280   insert_pixbuf_or_widget_segment (iter, seg);
1281 }
1282
1283 void
1284 _gtk_text_btree_insert_child_anchor (GtkTextIter        *iter,
1285                                      GtkTextChildAnchor *anchor)
1286 {
1287   GtkTextLineSegment *seg;
1288   GtkTextBTree *tree;
1289
1290   if (anchor->segment != NULL)
1291     {
1292       g_warning (G_STRLOC": Same child anchor can't be inserted twice");
1293       return;
1294     }
1295   
1296   seg = _gtk_widget_segment_new (anchor);
1297
1298   tree = seg->body.child.tree = _gtk_text_iter_get_btree (iter);
1299   seg->body.child.line = _gtk_text_iter_get_text_line (iter);
1300   
1301   insert_pixbuf_or_widget_segment (iter, seg);
1302
1303   if (tree->child_anchor_table == NULL)
1304     tree->child_anchor_table = g_hash_table_new (NULL, NULL);
1305
1306   g_hash_table_insert (tree->child_anchor_table,
1307                        seg->body.child.obj,
1308                        seg->body.child.obj);
1309 }
1310
1311 void
1312 _gtk_text_btree_unregister_child_anchor (GtkTextChildAnchor *anchor)
1313 {
1314   GtkTextLineSegment *seg;
1315
1316   seg = anchor->segment;
1317   
1318   g_hash_table_remove (seg->body.child.tree->child_anchor_table,
1319                        anchor);
1320 }
1321
1322 /*
1323  * View stuff
1324  */
1325
1326 static GtkTextLine*
1327 find_line_by_y (GtkTextBTree *tree, BTreeView *view,
1328                 GtkTextBTreeNode *node, gint y, gint *line_top,
1329                 GtkTextLine *last_line)
1330 {
1331   gint current_y = 0;
1332
1333   if (gtk_debug_flags & GTK_DEBUG_TEXT)
1334     _gtk_text_btree_check (tree);
1335
1336   if (node->level == 0)
1337     {
1338       GtkTextLine *line;
1339
1340       line = node->children.line;
1341
1342       while (line != NULL && line != last_line)
1343         {
1344           GtkTextLineData *ld;
1345
1346           ld = _gtk_text_line_get_data (line, view->view_id);
1347
1348           if (ld)
1349             {
1350               if (y < (current_y + (ld ? ld->height : 0)))
1351                 return line;
1352
1353               current_y += ld->height;
1354               *line_top += ld->height;
1355             }
1356
1357           line = line->next;
1358         }
1359       return NULL;
1360     }
1361   else
1362     {
1363       GtkTextBTreeNode *child;
1364
1365       child = node->children.node;
1366
1367       while (child != NULL)
1368         {
1369           gint width;
1370           gint height;
1371
1372           gtk_text_btree_node_get_size (child, view->view_id,
1373                                         &width, &height);
1374
1375           if (y < (current_y + height))
1376             return find_line_by_y (tree, view, child,
1377                                    y - current_y, line_top,
1378                                    last_line);
1379
1380           current_y += height;
1381           *line_top += height;
1382
1383           child = child->next;
1384         }
1385
1386       return NULL;
1387     }
1388 }
1389
1390 GtkTextLine *
1391 _gtk_text_btree_find_line_by_y (GtkTextBTree *tree,
1392                                 gpointer      view_id,
1393                                 gint          ypixel,
1394                                 gint         *line_top_out)
1395 {
1396   GtkTextLine *line;
1397   BTreeView *view;
1398   GtkTextLine *last_line;
1399   gint line_top = 0;
1400
1401   view = gtk_text_btree_get_view (tree, view_id);
1402   g_return_val_if_fail (view != NULL, NULL);
1403
1404   last_line = get_last_line (tree);
1405
1406   line = find_line_by_y (tree, view, tree->root_node, ypixel, &line_top,
1407                          last_line);
1408
1409   if (line_top_out)
1410     *line_top_out = line_top;
1411
1412   return line;
1413 }
1414
1415 static gint
1416 find_line_top_in_line_list (GtkTextBTree *tree,
1417                             BTreeView *view,
1418                             GtkTextLine *line,
1419                             GtkTextLine *target_line,
1420                             gint y)
1421 {
1422   while (line != NULL)
1423     {
1424       GtkTextLineData *ld;
1425
1426       if (line == target_line)
1427         return y;
1428
1429       ld = _gtk_text_line_get_data (line, view->view_id);
1430       if (ld)
1431         y += ld->height;
1432
1433       line = line->next;
1434     }
1435
1436   g_assert_not_reached (); /* If we get here, our
1437                               target line didn't exist
1438                               under its parent node */
1439   return 0;
1440 }
1441
1442 gint
1443 _gtk_text_btree_find_line_top (GtkTextBTree *tree,
1444                               GtkTextLine *target_line,
1445                               gpointer view_id)
1446 {
1447   gint y = 0;
1448   BTreeView *view;
1449   GSList *nodes;
1450   GSList *iter;
1451   GtkTextBTreeNode *node;
1452
1453   view = gtk_text_btree_get_view (tree, view_id);
1454
1455   g_return_val_if_fail (view != NULL, 0);
1456
1457   nodes = NULL;
1458   node = target_line->parent;
1459   while (node != NULL)
1460     {
1461       nodes = g_slist_prepend (nodes, node);
1462       node = node->parent;
1463     }
1464
1465   iter = nodes;
1466   while (iter != NULL)
1467     {
1468       node = iter->data;
1469
1470       if (node->level == 0)
1471         {
1472           g_slist_free (nodes);
1473           return find_line_top_in_line_list (tree, view,
1474                                              node->children.line,
1475                                              target_line, y);
1476         }
1477       else
1478         {
1479           GtkTextBTreeNode *child;
1480           GtkTextBTreeNode *target_node;
1481
1482           g_assert (iter->next != NULL); /* not at level 0 */
1483           target_node = iter->next->data;
1484
1485           child = node->children.node;
1486
1487           while (child != NULL)
1488             {
1489               gint width;
1490               gint height;
1491
1492               if (child == target_node)
1493                 break;
1494               else
1495                 {
1496                   gtk_text_btree_node_get_size (child, view->view_id,
1497                                                 &width, &height);
1498                   y += height;
1499                 }
1500               child = child->next;
1501             }
1502           g_assert (child != NULL); /* should have broken out before we
1503                                        ran out of nodes */
1504         }
1505
1506       iter = g_slist_next (iter);
1507     }
1508
1509   g_assert_not_reached (); /* we return when we find the target line */
1510   return 0;
1511 }
1512
1513 void
1514 _gtk_text_btree_add_view (GtkTextBTree *tree,
1515                          GtkTextLayout *layout)
1516 {
1517   BTreeView *view;
1518   GtkTextLine *last_line;
1519   GtkTextLineData *line_data;
1520
1521   g_return_if_fail (tree != NULL);
1522   
1523   view = g_new (BTreeView, 1);
1524
1525   view->view_id = layout;
1526   view->layout = layout;
1527
1528   view->next = tree->views;
1529   view->prev = NULL;
1530
1531   if (tree->views)
1532     {
1533       g_assert (tree->views->prev == NULL);
1534       tree->views->prev = view;
1535     }
1536   
1537   tree->views = view;
1538
1539   /* The last line in the buffer has identity values for the per-view
1540    * data so that we can avoid special case checks for it in a large
1541    * number of loops
1542    */
1543   last_line = get_last_line (tree);
1544
1545   line_data = g_new (GtkTextLineData, 1);
1546   line_data->view_id = layout;
1547   line_data->next = NULL;
1548   line_data->width = 0;
1549   line_data->height = 0;
1550   line_data->valid = TRUE;
1551
1552   _gtk_text_line_add_data (last_line, line_data);
1553 }
1554
1555 void
1556 _gtk_text_btree_remove_view (GtkTextBTree *tree,
1557                              gpointer      view_id)
1558 {
1559   BTreeView *view;
1560   GtkTextLine *last_line;
1561   GtkTextLineData *line_data;
1562
1563   g_return_if_fail (tree != NULL);
1564   
1565   view = tree->views;
1566
1567   while (view != NULL)
1568     {
1569       if (view->view_id == view_id)
1570         break;
1571
1572       view = view->next;
1573     }
1574
1575   g_return_if_fail (view != NULL);
1576
1577   if (view->next)
1578     view->next->prev = view->prev;
1579
1580   if (view->prev)
1581     view->prev->next = view->next;
1582
1583   if (view == tree->views)
1584     tree->views = view->next;
1585
1586   /* Remove the line data for the last line which we added ourselves.
1587    * (Do this first, so that we don't try to call the view's line data destructor on it.)
1588    */
1589   last_line = get_last_line (tree);
1590   line_data = _gtk_text_line_remove_data (last_line, view_id);
1591   g_free (line_data);
1592
1593   gtk_text_btree_node_remove_view (view, tree->root_node, view_id);
1594
1595   view->layout = (gpointer) 0xdeadbeef;
1596   view->view_id = (gpointer) 0xdeadbeef;
1597   
1598   g_free (view);
1599 }
1600
1601 void
1602 _gtk_text_btree_invalidate_region (GtkTextBTree      *tree,
1603                                    const GtkTextIter *start,
1604                                    const GtkTextIter *end)
1605 {
1606   BTreeView *view;
1607
1608   view = tree->views;
1609
1610   while (view != NULL)
1611     {
1612       gtk_text_layout_invalidate (view->layout, start, end);
1613
1614       view = view->next;
1615     }
1616 }
1617
1618 void
1619 _gtk_text_btree_get_view_size (GtkTextBTree *tree,
1620                               gpointer view_id,
1621                               gint *width,
1622                               gint *height)
1623 {
1624   g_return_if_fail (tree != NULL);
1625   g_return_if_fail (view_id != NULL);
1626
1627   gtk_text_btree_node_get_size (tree->root_node, view_id,
1628                                 width, height);
1629 }
1630
1631 /*
1632  * Tag
1633  */
1634
1635 typedef struct {
1636   GtkTextIter *iters;
1637   guint count;
1638   guint alloced;
1639 } IterStack;
1640
1641 static IterStack*
1642 iter_stack_new (void)
1643 {
1644   IterStack *stack;
1645   stack = g_new (IterStack, 1);
1646   stack->iters = NULL;
1647   stack->count = 0;
1648   stack->alloced = 0;
1649   return stack;
1650 }
1651
1652 static void
1653 iter_stack_push (IterStack *stack, const GtkTextIter *iter)
1654 {
1655   stack->count += 1;
1656   if (stack->count > stack->alloced)
1657     {
1658       stack->alloced = stack->count*2;
1659       stack->iters = g_realloc (stack->iters,
1660                                 stack->alloced*sizeof (GtkTextIter));
1661     }
1662   stack->iters[stack->count-1] = *iter;
1663 }
1664
1665 static gboolean
1666 iter_stack_pop (IterStack *stack, GtkTextIter *iter)
1667 {
1668   if (stack->count == 0)
1669     return FALSE;
1670   else
1671     {
1672       stack->count -= 1;
1673       *iter = stack->iters[stack->count];
1674       return TRUE;
1675     }
1676 }
1677
1678 static void
1679 iter_stack_free (IterStack *stack)
1680 {
1681   g_free (stack->iters);
1682   g_free (stack);
1683 }
1684
1685 static void
1686 iter_stack_invert (IterStack *stack)
1687 {
1688   if (stack->count > 0)
1689     {
1690       guint i = 0;
1691       guint j = stack->count - 1;
1692       while (i < j)
1693         {
1694           GtkTextIter tmp;
1695
1696           tmp = stack->iters[i];
1697           stack->iters[i] = stack->iters[j];
1698           stack->iters[j] = tmp;
1699
1700           ++i;
1701           --j;
1702         }
1703     }
1704 }
1705
1706 static void
1707 queue_tag_redisplay (GtkTextBTree      *tree,
1708                      GtkTextTag        *tag,
1709                      const GtkTextIter *start,
1710                      const GtkTextIter *end)
1711 {
1712   if (_gtk_text_tag_affects_size (tag))
1713     {
1714       DV (g_print ("invalidating due to size-affecting tag (%s)\n", G_STRLOC));
1715       _gtk_text_btree_invalidate_region (tree, start, end);
1716     }
1717   else if (_gtk_text_tag_affects_nonsize_appearance (tag))
1718     {
1719       /* We only need to queue a redraw, not a relayout */
1720       redisplay_region (tree, start, end);
1721     }
1722
1723   /* We don't need to do anything if the tag doesn't affect display */
1724 }
1725
1726 void
1727 _gtk_text_btree_tag (const GtkTextIter *start_orig,
1728                      const GtkTextIter *end_orig,
1729                      GtkTextTag        *tag,
1730                      gboolean           add)
1731 {
1732   GtkTextLineSegment *seg, *prev;
1733   GtkTextLine *cleanupline;
1734   gboolean toggled_on;
1735   GtkTextLine *start_line;
1736   GtkTextLine *end_line;
1737   GtkTextIter iter;
1738   GtkTextIter start, end;
1739   GtkTextBTree *tree;
1740   IterStack *stack;
1741   GtkTextTagInfo *info;
1742
1743   g_return_if_fail (start_orig != NULL);
1744   g_return_if_fail (end_orig != NULL);
1745   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
1746   g_return_if_fail (_gtk_text_iter_get_btree (start_orig) ==
1747                     _gtk_text_iter_get_btree (end_orig));
1748   g_return_if_fail (tag->table == _gtk_text_iter_get_btree (start_orig)->table);
1749   
1750 #if 0
1751   printf ("%s tag %s from %d to %d\n",
1752           add ? "Adding" : "Removing",
1753           tag->name,
1754           gtk_text_buffer_get_offset (start_orig),
1755           gtk_text_buffer_get_offset (end_orig));
1756 #endif
1757
1758   if (gtk_text_iter_equal (start_orig, end_orig))
1759     return;
1760
1761   start = *start_orig;
1762   end = *end_orig;
1763
1764   gtk_text_iter_order (&start, &end);
1765
1766   tree = _gtk_text_iter_get_btree (&start);
1767
1768   queue_tag_redisplay (tree, tag, &start, &end);
1769
1770   info = gtk_text_btree_get_tag_info (tree, tag);
1771
1772   start_line = _gtk_text_iter_get_text_line (&start);
1773   end_line = _gtk_text_iter_get_text_line (&end);
1774
1775   /* Find all tag toggles in the region; we are going to delete them.
1776      We need to find them in advance, because
1777      forward_find_tag_toggle () won't work once we start playing around
1778      with the tree. */
1779   stack = iter_stack_new ();
1780   iter = start;
1781
1782   /* forward_to_tag_toggle() skips a toggle at the start iterator,
1783    * which is deliberate - we don't want to delete a toggle at the
1784    * start.
1785    */
1786   while (gtk_text_iter_forward_to_tag_toggle (&iter, tag))
1787     {
1788       if (gtk_text_iter_compare (&iter, &end) >= 0)
1789         break;
1790       else
1791         iter_stack_push (stack, &iter);
1792     }
1793
1794   /* We need to traverse the toggles in order. */
1795   iter_stack_invert (stack);
1796
1797   /*
1798    * See whether the tag is present at the start of the range.  If
1799    * the state doesn't already match what we want then add a toggle
1800    * there.
1801    */
1802
1803   toggled_on = gtk_text_iter_has_tag (&start, tag);
1804   if ( (add && !toggled_on) ||
1805        (!add && toggled_on) )
1806     {
1807       /* This could create a second toggle at the start position;
1808          cleanup_line () will remove it if so. */
1809       seg = _gtk_toggle_segment_new (info, add);
1810
1811       prev = gtk_text_line_segment_split (&start);
1812       if (prev == NULL)
1813         {
1814           seg->next = start_line->segments;
1815           start_line->segments = seg;
1816         }
1817       else
1818         {
1819           seg->next = prev->next;
1820           prev->next = seg;
1821         }
1822
1823       /* cleanup_line adds the new toggle to the node counts. */
1824 #if 0
1825       printf ("added toggle at start\n");
1826 #endif
1827       /* we should probably call segments_changed, but in theory
1828          any still-cached segments in the iters we are about to
1829          use are still valid, since they're in front
1830          of this spot. */
1831     }
1832
1833   /*
1834    *
1835    * Scan the range of characters and delete any internal tag
1836    * transitions.  Keep track of what the old state was at the end
1837    * of the range, and add a toggle there if it's needed.
1838    *
1839    */
1840
1841   cleanupline = start_line;
1842   while (iter_stack_pop (stack, &iter))
1843     {
1844       GtkTextLineSegment *indexable_seg;
1845       GtkTextLine *line;
1846
1847       line = _gtk_text_iter_get_text_line (&iter);
1848       seg = _gtk_text_iter_get_any_segment (&iter);
1849       indexable_seg = _gtk_text_iter_get_indexable_segment (&iter);
1850
1851       g_assert (seg != NULL);
1852       g_assert (indexable_seg != NULL);
1853       g_assert (seg != indexable_seg);
1854
1855       prev = line->segments;
1856
1857       /* Find the segment that actually toggles this tag. */
1858       while (seg != indexable_seg)
1859         {
1860           g_assert (seg != NULL);
1861           g_assert (indexable_seg != NULL);
1862           g_assert (seg != indexable_seg);
1863           
1864           if ( (seg->type == &gtk_text_toggle_on_type ||
1865                 seg->type == &gtk_text_toggle_off_type) &&
1866                (seg->body.toggle.info == info) )
1867             break;
1868           else
1869             seg = seg->next;
1870         }
1871
1872       g_assert (seg != NULL);
1873       g_assert (indexable_seg != NULL);
1874
1875       g_assert (seg != indexable_seg); /* If this happens, then
1876                                           forward_to_tag_toggle was
1877                                           full of shit. */
1878       g_assert (seg->body.toggle.info->tag == tag);
1879
1880       /* If this happens, when previously tagging we didn't merge
1881          overlapping tags. */
1882       g_assert ( (toggled_on && seg->type == &gtk_text_toggle_off_type) ||
1883                  (!toggled_on && seg->type == &gtk_text_toggle_on_type) );
1884
1885       toggled_on = !toggled_on;
1886
1887 #if 0
1888       printf ("deleting %s toggle\n",
1889               seg->type == &gtk_text_toggle_on_type ? "on" : "off");
1890 #endif
1891       /* Remove toggle segment from the list. */
1892       if (prev == seg)
1893         {
1894           line->segments = seg->next;
1895         }
1896       else
1897         {
1898           while (prev->next != seg)
1899             {
1900               prev = prev->next;
1901             }
1902           prev->next = seg->next;
1903         }
1904
1905       /* Inform iterators we've hosed them. This actually reflects a
1906          bit of inefficiency; if you have the same tag toggled on and
1907          off a lot in a single line, we keep having the rescan from
1908          the front of the line. Of course we have to do that to get
1909          "prev" anyway, but here we are doing it an additional
1910          time. FIXME */
1911       segments_changed (tree);
1912
1913       /* Update node counts */
1914       if (seg->body.toggle.inNodeCounts)
1915         {
1916           _gtk_change_node_toggle_count (line->parent,
1917                                          info, -1);
1918           seg->body.toggle.inNodeCounts = FALSE;
1919         }
1920
1921       g_free (seg);
1922
1923       /* We only clean up lines when we're done with them, saves some
1924          gratuitous line-segment-traversals */
1925
1926       if (cleanupline != line)
1927         {
1928           cleanup_line (cleanupline);
1929           cleanupline = line;
1930         }
1931     }
1932
1933   iter_stack_free (stack);
1934
1935   /* toggled_on now reflects the toggle state _just before_ the
1936      end iterator. The end iterator could already have a toggle
1937      on or a toggle off. */
1938   if ( (add && !toggled_on) ||
1939        (!add && toggled_on) )
1940     {
1941       /* This could create a second toggle at the start position;
1942          cleanup_line () will remove it if so. */
1943
1944       seg = _gtk_toggle_segment_new (info, !add);
1945
1946       prev = gtk_text_line_segment_split (&end);
1947       if (prev == NULL)
1948         {
1949           seg->next = end_line->segments;
1950           end_line->segments = seg;
1951         }
1952       else
1953         {
1954           seg->next = prev->next;
1955           prev->next = seg;
1956         }
1957       /* cleanup_line adds the new toggle to the node counts. */
1958       g_assert (seg->body.toggle.inNodeCounts == FALSE);
1959 #if 0
1960       printf ("added toggle at end\n");
1961 #endif
1962     }
1963
1964   /*
1965    * Cleanup cleanupline and the last line of the range, if
1966    * these are different.
1967    */
1968
1969   cleanup_line (cleanupline);
1970   if (cleanupline != end_line)
1971     {
1972       cleanup_line (end_line);
1973     }
1974
1975   segments_changed (tree);
1976
1977   if (gtk_debug_flags & GTK_DEBUG_TEXT)
1978     _gtk_text_btree_check (tree);
1979 }
1980
1981
1982 /*
1983  * "Getters"
1984  */
1985
1986 static GtkTextLine*
1987 get_line_internal (GtkTextBTree *tree,
1988                    gint          line_number,
1989                    gint         *real_line_number,
1990                    gboolean      include_last)
1991 {
1992   GtkTextBTreeNode *node;
1993   GtkTextLine *line;
1994   int lines_left;
1995   int line_count;
1996
1997   line_count = _gtk_text_btree_line_count (tree);
1998   if (!include_last)
1999     line_count -= 1;
2000   
2001   if (line_number < 0)
2002     {
2003       line_number = line_count;
2004     }
2005   else if (line_number > line_count)
2006     {
2007       line_number = line_count;
2008     }
2009
2010   if (real_line_number)
2011     *real_line_number = line_number;
2012
2013   node = tree->root_node;
2014   lines_left = line_number;
2015
2016   /*
2017    * Work down through levels of the tree until a GtkTextBTreeNode is found at
2018    * level 0.
2019    */
2020
2021   while (node->level != 0)
2022     {
2023       for (node = node->children.node;
2024            node->num_lines <= lines_left;
2025            node = node->next)
2026         {
2027 #if 0
2028           if (node == NULL)
2029             {
2030               g_error ("gtk_text_btree_find_line ran out of GtkTextBTreeNodes");
2031             }
2032 #endif
2033           lines_left -= node->num_lines;
2034         }
2035     }
2036
2037   /*
2038    * Work through the lines attached to the level-0 GtkTextBTreeNode.
2039    */
2040
2041   for (line = node->children.line; lines_left > 0;
2042        line = line->next)
2043     {
2044 #if 0
2045       if (line == NULL)
2046         {
2047           g_error ("gtk_text_btree_find_line ran out of lines");
2048         }
2049 #endif
2050       lines_left -= 1;
2051     }
2052   return line;
2053 }
2054
2055 GtkTextLine*
2056 _gtk_text_btree_get_end_iter_line (GtkTextBTree *tree)
2057 {
2058   return
2059     _gtk_text_btree_get_line (tree,
2060                               _gtk_text_btree_line_count (tree) - 1,
2061                               NULL);
2062 }
2063
2064 GtkTextLine*
2065 _gtk_text_btree_get_line (GtkTextBTree *tree,
2066                           gint          line_number,
2067                           gint         *real_line_number)
2068 {
2069   return get_line_internal (tree, line_number, real_line_number, TRUE);
2070 }
2071
2072 GtkTextLine*
2073 _gtk_text_btree_get_line_no_last (GtkTextBTree      *tree,
2074                                   gint               line_number,
2075                                   gint              *real_line_number)
2076 {
2077   return get_line_internal (tree, line_number, real_line_number, FALSE);
2078 }
2079
2080 GtkTextLine*
2081 _gtk_text_btree_get_line_at_char (GtkTextBTree      *tree,
2082                                   gint               char_index,
2083                                   gint              *line_start_index,
2084                                   gint              *real_char_index)
2085 {
2086   GtkTextBTreeNode *node;
2087   GtkTextLine *line;
2088   GtkTextLineSegment *seg;
2089   int chars_left;
2090   int chars_in_line;
2091   int bytes_in_line;
2092
2093   node = tree->root_node;
2094
2095   /* Clamp to valid indexes (-1 is magic for "highest index"),
2096    * node->num_chars includes the two newlines that aren't really
2097    * in the buffer.
2098    */
2099   if (char_index < 0 || char_index >= (node->num_chars - 1))
2100     {
2101       char_index = node->num_chars - 2;
2102     }
2103
2104   *real_char_index = char_index;
2105
2106   /*
2107    * Work down through levels of the tree until a GtkTextBTreeNode is found at
2108    * level 0.
2109    */
2110
2111   chars_left = char_index;
2112   while (node->level != 0)
2113     {
2114       for (node = node->children.node;
2115            chars_left >= node->num_chars;
2116            node = node->next)
2117         {
2118           chars_left -= node->num_chars;
2119
2120           g_assert (chars_left >= 0);
2121         }
2122     }
2123
2124   if (chars_left == 0)
2125     {
2126       /* Start of a line */
2127
2128       *line_start_index = char_index;
2129       return node->children.line;
2130     }
2131
2132   /*
2133    * Work through the lines attached to the level-0 GtkTextBTreeNode.
2134    */
2135
2136   chars_in_line = 0;
2137   bytes_in_line = 0;
2138   seg = NULL;
2139   for (line = node->children.line; line != NULL; line = line->next)
2140     {
2141       seg = line->segments;
2142       while (seg != NULL)
2143         {
2144           if (chars_in_line + seg->char_count > chars_left)
2145             goto found; /* found our line/segment */
2146
2147           chars_in_line += seg->char_count;
2148
2149           seg = seg->next;
2150         }
2151
2152       chars_left -= chars_in_line;
2153
2154       chars_in_line = 0;
2155       seg = NULL;
2156     }
2157
2158  found:
2159
2160   g_assert (line != NULL); /* hosage, ran out of lines */
2161   g_assert (seg != NULL);
2162
2163   *line_start_index = char_index - chars_left;
2164   return line;
2165 }
2166
2167 GtkTextTag**
2168 _gtk_text_btree_get_tags (const GtkTextIter *iter,
2169                          gint *num_tags)
2170 {
2171   GtkTextBTreeNode *node;
2172   GtkTextLine *siblingline;
2173   GtkTextLineSegment *seg;
2174   int src, dst, index;
2175   TagInfo tagInfo;
2176   GtkTextLine *line;
2177   GtkTextBTree *tree;
2178   gint byte_index;
2179
2180 #define NUM_TAG_INFOS 10
2181
2182   line = _gtk_text_iter_get_text_line (iter);
2183   tree = _gtk_text_iter_get_btree (iter);
2184   byte_index = gtk_text_iter_get_line_index (iter);
2185
2186   tagInfo.numTags = 0;
2187   tagInfo.arraySize = NUM_TAG_INFOS;
2188   tagInfo.tags = g_new (GtkTextTag*, NUM_TAG_INFOS);
2189   tagInfo.counts = g_new (int, NUM_TAG_INFOS);
2190
2191   /*
2192    * Record tag toggles within the line of indexPtr but preceding
2193    * indexPtr. Note that if this loop segfaults, your
2194    * byte_index probably points past the sum of all
2195    * seg->byte_count */
2196
2197   for (index = 0, seg = line->segments;
2198        (index + seg->byte_count) <= byte_index;
2199        index += seg->byte_count, seg = seg->next)
2200     {
2201       if ((seg->type == &gtk_text_toggle_on_type)
2202           || (seg->type == &gtk_text_toggle_off_type))
2203         {
2204           inc_count (seg->body.toggle.info->tag, 1, &tagInfo);
2205         }
2206     }
2207
2208   /*
2209    * Record toggles for tags in lines that are predecessors of
2210    * line but under the same level-0 GtkTextBTreeNode.
2211    */
2212
2213   for (siblingline = line->parent->children.line;
2214        siblingline != line;
2215        siblingline = siblingline->next)
2216     {
2217       for (seg = siblingline->segments; seg != NULL;
2218            seg = seg->next)
2219         {
2220           if ((seg->type == &gtk_text_toggle_on_type)
2221               || (seg->type == &gtk_text_toggle_off_type))
2222             {
2223               inc_count (seg->body.toggle.info->tag, 1, &tagInfo);
2224             }
2225         }
2226     }
2227
2228   /*
2229    * For each GtkTextBTreeNode in the ancestry of this line, record tag
2230    * toggles for all siblings that precede that GtkTextBTreeNode.
2231    */
2232
2233   for (node = line->parent; node->parent != NULL;
2234        node = node->parent)
2235     {
2236       GtkTextBTreeNode *siblingPtr;
2237       Summary *summary;
2238
2239       for (siblingPtr = node->parent->children.node;
2240            siblingPtr != node; siblingPtr = siblingPtr->next)
2241         {
2242           for (summary = siblingPtr->summary; summary != NULL;
2243                summary = summary->next)
2244             {
2245               if (summary->toggle_count & 1)
2246                 {
2247                   inc_count (summary->info->tag, summary->toggle_count,
2248                              &tagInfo);
2249                 }
2250             }
2251         }
2252     }
2253
2254   /*
2255    * Go through the tag information and squash out all of the tags
2256    * that have even toggle counts (these tags exist before the point
2257    * of interest, but not at the desired character itself).
2258    */
2259
2260   for (src = 0, dst = 0; src < tagInfo.numTags; src++)
2261     {
2262       if (tagInfo.counts[src] & 1)
2263         {
2264           g_assert (GTK_IS_TEXT_TAG (tagInfo.tags[src]));
2265           tagInfo.tags[dst] = tagInfo.tags[src];
2266           dst++;
2267         }
2268     }
2269
2270   *num_tags = dst;
2271   g_free (tagInfo.counts);
2272   if (dst == 0)
2273     {
2274       g_free (tagInfo.tags);
2275       return NULL;
2276     }
2277   return tagInfo.tags;
2278 }
2279
2280 static void
2281 copy_segment (GString *string,
2282               gboolean include_hidden,
2283               gboolean include_nonchars,
2284               const GtkTextIter *start,
2285               const GtkTextIter *end)
2286 {
2287   GtkTextLineSegment *end_seg;
2288   GtkTextLineSegment *seg;
2289
2290   if (gtk_text_iter_equal (start, end))
2291     return;
2292
2293   seg = _gtk_text_iter_get_indexable_segment (start);
2294   end_seg = _gtk_text_iter_get_indexable_segment (end);
2295
2296   if (seg->type == &gtk_text_char_type)
2297     {
2298       gboolean copy = TRUE;
2299       gint copy_bytes = 0;
2300       gint copy_start = 0;
2301
2302       /* Don't copy if we're invisible; segments are invisible/not
2303          as a whole, no need to check each char */
2304       if (!include_hidden &&
2305           _gtk_text_btree_char_is_invisible (start))
2306         {
2307           copy = FALSE;
2308           /* printf (" <invisible>\n"); */
2309         }
2310
2311       copy_start = _gtk_text_iter_get_segment_byte (start);
2312
2313       if (seg == end_seg)
2314         {
2315           /* End is in the same segment; need to copy fewer bytes. */
2316           gint end_byte = _gtk_text_iter_get_segment_byte (end);
2317
2318           copy_bytes = end_byte - copy_start;
2319         }
2320       else
2321         copy_bytes = seg->byte_count - copy_start;
2322
2323       g_assert (copy_bytes != 0); /* Due to iter equality check at
2324                                      front of this function. */
2325
2326       if (copy)
2327         {
2328           g_assert ((copy_start + copy_bytes) <= seg->byte_count);
2329
2330           g_string_append_len (string,
2331                                seg->body.chars + copy_start,
2332                                copy_bytes);
2333         }
2334
2335       /* printf ("  :%s\n", string->str); */
2336     }
2337   else if (seg->type == &gtk_text_pixbuf_type ||
2338            seg->type == &gtk_text_child_type)
2339     {
2340       gboolean copy = TRUE;
2341
2342       if (!include_nonchars)
2343         {
2344           copy = FALSE;
2345         }
2346       else if (!include_hidden &&
2347                _gtk_text_btree_char_is_invisible (start))
2348         {
2349           copy = FALSE;
2350         }
2351
2352       if (copy)
2353         {
2354           g_string_append_len (string,
2355                                gtk_text_unknown_char_utf8,
2356                                3);
2357
2358         }
2359     }
2360 }
2361
2362 gchar*
2363 _gtk_text_btree_get_text (const GtkTextIter *start_orig,
2364                          const GtkTextIter *end_orig,
2365                          gboolean include_hidden,
2366                          gboolean include_nonchars)
2367 {
2368   GtkTextLineSegment *seg;
2369   GtkTextLineSegment *end_seg;
2370   GString *retval;
2371   GtkTextBTree *tree;
2372   gchar *str;
2373   GtkTextIter iter;
2374   GtkTextIter start;
2375   GtkTextIter end;
2376
2377   g_return_val_if_fail (start_orig != NULL, NULL);
2378   g_return_val_if_fail (end_orig != NULL, NULL);
2379   g_return_val_if_fail (_gtk_text_iter_get_btree (start_orig) ==
2380                         _gtk_text_iter_get_btree (end_orig), NULL);
2381
2382   start = *start_orig;
2383   end = *end_orig;
2384
2385   gtk_text_iter_order (&start, &end);
2386
2387   retval = g_string_new (NULL);
2388
2389   tree = _gtk_text_iter_get_btree (&start);
2390
2391   end_seg = _gtk_text_iter_get_indexable_segment (&end);
2392   iter = start;
2393   seg = _gtk_text_iter_get_indexable_segment (&iter);
2394   while (seg != end_seg)
2395     {
2396       copy_segment (retval, include_hidden, include_nonchars,
2397                     &iter, &end);
2398
2399       _gtk_text_iter_forward_indexable_segment (&iter);
2400
2401       seg = _gtk_text_iter_get_indexable_segment (&iter);
2402     }
2403
2404   copy_segment (retval, include_hidden, include_nonchars, &iter, &end);
2405
2406   str = retval->str;
2407   g_string_free (retval, FALSE);
2408   return str;
2409 }
2410
2411 gint
2412 _gtk_text_btree_line_count (GtkTextBTree *tree)
2413 {
2414   /* Subtract bogus line at the end; we return a count
2415      of usable lines. */
2416   return tree->root_node->num_lines - 1;
2417 }
2418
2419 gint
2420 _gtk_text_btree_char_count (GtkTextBTree *tree)
2421 {
2422   /* Exclude newline in bogus last line and the
2423    * one in the last line that is after the end iterator
2424    */
2425   return tree->root_node->num_chars - 2;
2426 }
2427
2428 #define LOTSA_TAGS 1000
2429 gboolean
2430 _gtk_text_btree_char_is_invisible (const GtkTextIter *iter)
2431 {
2432   gboolean invisible = FALSE;  /* if nobody says otherwise, it's visible */
2433
2434   int deftagCnts[LOTSA_TAGS];
2435   int *tagCnts = deftagCnts;
2436   GtkTextTag *deftags[LOTSA_TAGS];
2437   GtkTextTag **tags = deftags;
2438   int numTags;
2439   GtkTextBTreeNode *node;
2440   GtkTextLine *siblingline;
2441   GtkTextLineSegment *seg;
2442   GtkTextTag *tag;
2443   int i, index;
2444   GtkTextLine *line;
2445   GtkTextBTree *tree;
2446   gint byte_index;
2447
2448   line = _gtk_text_iter_get_text_line (iter);
2449   tree = _gtk_text_iter_get_btree (iter);
2450   byte_index = gtk_text_iter_get_line_index (iter);
2451
2452   numTags = gtk_text_tag_table_get_size (tree->table);
2453
2454   /* almost always avoid malloc, so stay out of system calls */
2455   if (LOTSA_TAGS < numTags)
2456     {
2457       tagCnts = g_new (int, numTags);
2458       tags = g_new (GtkTextTag*, numTags);
2459     }
2460
2461   for (i=0; i<numTags; i++)
2462     {
2463       tagCnts[i] = 0;
2464     }
2465
2466   /*
2467    * Record tag toggles within the line of indexPtr but preceding
2468    * indexPtr.
2469    */
2470
2471   for (index = 0, seg = line->segments;
2472        (index + seg->byte_count) <= byte_index; /* segfault here means invalid index */
2473        index += seg->byte_count, seg = seg->next)
2474     {
2475       if ((seg->type == &gtk_text_toggle_on_type)
2476           || (seg->type == &gtk_text_toggle_off_type))
2477         {
2478           tag = seg->body.toggle.info->tag;
2479           if (tag->invisible_set && tag->values->invisible)
2480             {
2481               tags[tag->priority] = tag;
2482               tagCnts[tag->priority]++;
2483             }
2484         }
2485     }
2486
2487   /*
2488    * Record toggles for tags in lines that are predecessors of
2489    * line but under the same level-0 GtkTextBTreeNode.
2490    */
2491
2492   for (siblingline = line->parent->children.line;
2493        siblingline != line;
2494        siblingline = siblingline->next)
2495     {
2496       for (seg = siblingline->segments; seg != NULL;
2497            seg = seg->next)
2498         {
2499           if ((seg->type == &gtk_text_toggle_on_type)
2500               || (seg->type == &gtk_text_toggle_off_type))
2501             {
2502               tag = seg->body.toggle.info->tag;
2503               if (tag->invisible_set && tag->values->invisible)
2504                 {
2505                   tags[tag->priority] = tag;
2506                   tagCnts[tag->priority]++;
2507                 }
2508             }
2509         }
2510     }
2511
2512   /*
2513    * For each GtkTextBTreeNode in the ancestry of this line, record tag toggles
2514    * for all siblings that precede that GtkTextBTreeNode.
2515    */
2516
2517   for (node = line->parent; node->parent != NULL;
2518        node = node->parent)
2519     {
2520       GtkTextBTreeNode *siblingPtr;
2521       Summary *summary;
2522
2523       for (siblingPtr = node->parent->children.node;
2524            siblingPtr != node; siblingPtr = siblingPtr->next)
2525         {
2526           for (summary = siblingPtr->summary; summary != NULL;
2527                summary = summary->next)
2528             {
2529               if (summary->toggle_count & 1)
2530                 {
2531                   tag = summary->info->tag;
2532                   if (tag->invisible_set && tag->values->invisible)
2533                     {
2534                       tags[tag->priority] = tag;
2535                       tagCnts[tag->priority] += summary->toggle_count;
2536                     }
2537                 }
2538             }
2539         }
2540     }
2541
2542   /*
2543    * Now traverse from highest priority to lowest,
2544    * take invisible value from first odd count (= on)
2545    */
2546
2547   for (i = numTags-1; i >=0; i--)
2548     {
2549       if (tagCnts[i] & 1)
2550         {
2551           /* FIXME not sure this should be if 0 */
2552 #if 0
2553 #ifndef ALWAYS_SHOW_SELECTION
2554           /* who would make the selection invisible? */
2555           if ((tag == tkxt->seltag)
2556               && !(tkxt->flags & GOT_FOCUS))
2557             {
2558               continue;
2559             }
2560 #endif
2561 #endif
2562           invisible = tags[i]->values->invisible;
2563           break;
2564         }
2565     }
2566
2567   if (LOTSA_TAGS < numTags)
2568     {
2569       g_free (tagCnts);
2570       g_free (tags);
2571     }
2572
2573   return invisible;
2574 }
2575
2576
2577 /*
2578  * Manipulate marks
2579  */
2580
2581 static void
2582 redisplay_region (GtkTextBTree      *tree,
2583                   const GtkTextIter *start,
2584                   const GtkTextIter *end)
2585 {
2586   BTreeView *view;
2587   GtkTextLine *start_line, *end_line;
2588
2589   if (gtk_text_iter_compare (start, end) > 0)
2590     {
2591       const GtkTextIter *tmp = start;
2592       start = end;
2593       end = tmp;
2594     }
2595
2596   start_line = _gtk_text_iter_get_text_line (start);
2597   end_line = _gtk_text_iter_get_text_line (end);
2598
2599   view = tree->views;
2600   while (view != NULL)
2601     {
2602       gint start_y, end_y;
2603       GtkTextLineData *ld;
2604
2605       start_y = _gtk_text_btree_find_line_top (tree, start_line, view->view_id);
2606
2607       if (end_line == start_line)
2608         end_y = start_y;
2609       else
2610         end_y = _gtk_text_btree_find_line_top (tree, end_line, view->view_id);
2611
2612       ld = _gtk_text_line_get_data (end_line, view->view_id);
2613       if (ld)
2614         end_y += ld->height;
2615
2616       gtk_text_layout_changed (view->layout, start_y,
2617                                end_y - start_y,
2618                                end_y - start_y);
2619
2620       view = view->next;
2621     }
2622 }
2623
2624 static void
2625 redisplay_mark (GtkTextLineSegment *mark)
2626 {
2627   GtkTextIter iter;
2628   GtkTextIter end;
2629
2630   _gtk_text_btree_get_iter_at_mark (mark->body.mark.tree,
2631                                    &iter,
2632                                    mark->body.mark.obj);
2633
2634   end = iter;
2635   gtk_text_iter_forward_char (&end);
2636
2637   DV (g_print ("invalidating due to moving visible mark (%s)\n", G_STRLOC));
2638   _gtk_text_btree_invalidate_region (mark->body.mark.tree,
2639                                     &iter, &end);
2640 }
2641
2642 static void
2643 redisplay_mark_if_visible (GtkTextLineSegment *mark)
2644 {
2645   if (!mark->body.mark.visible)
2646     return;
2647   else
2648     redisplay_mark (mark);
2649 }
2650
2651 static void
2652 ensure_not_off_end (GtkTextBTree *tree,
2653                     GtkTextLineSegment *mark,
2654                     GtkTextIter *iter)
2655 {
2656   if (gtk_text_iter_get_line (iter) ==
2657       _gtk_text_btree_line_count (tree))
2658     gtk_text_iter_backward_char (iter);
2659 }
2660
2661 static GtkTextLineSegment*
2662 real_set_mark (GtkTextBTree      *tree,
2663                GtkTextMark       *existing_mark,
2664                const gchar       *name,
2665                gboolean           left_gravity,
2666                const GtkTextIter *where,
2667                gboolean           should_exist,
2668                gboolean           redraw_selections)
2669 {
2670   GtkTextLineSegment *mark;
2671   GtkTextIter iter;
2672
2673   g_return_val_if_fail (tree != NULL, NULL);
2674   g_return_val_if_fail (where != NULL, NULL);
2675   g_return_val_if_fail (_gtk_text_iter_get_btree (where) == tree, NULL);
2676
2677   if (existing_mark)
2678     mark = existing_mark->segment;
2679   else if (name != NULL)
2680     mark = g_hash_table_lookup (tree->mark_table,
2681                                 name);
2682   else
2683     mark = NULL;
2684
2685   if (should_exist && mark == NULL)
2686     {
2687       g_warning ("No mark `%s' exists!", name);
2688       return NULL;
2689     }
2690
2691   /* OK if !should_exist and it does already exist, in that case
2692    * we just move it.
2693    */
2694   
2695   iter = *where;
2696
2697   if (gtk_debug_flags & GTK_DEBUG_TEXT)
2698     _gtk_text_iter_check (&iter);
2699   
2700   if (mark != NULL)
2701     {
2702       if (redraw_selections &&
2703           (mark == tree->insert_mark->segment ||
2704            mark == tree->selection_bound_mark->segment))
2705         {
2706           GtkTextIter old_pos;
2707
2708           _gtk_text_btree_get_iter_at_mark (tree, &old_pos,
2709                                            mark->body.mark.obj);
2710           redisplay_region (tree, &old_pos, where);
2711         }
2712
2713       /*
2714        * don't let visible marks be after the final newline of the
2715        *  file.
2716        */
2717
2718       if (mark->body.mark.visible)
2719         {
2720           ensure_not_off_end (tree, mark, &iter);
2721         }
2722
2723       /* Redraw the mark's old location. */
2724       redisplay_mark_if_visible (mark);
2725
2726       /* Unlink mark from its current location.
2727          This could hose our iterator... */
2728       gtk_text_btree_unlink_segment (tree, mark,
2729                                      mark->body.mark.line);
2730       mark->body.mark.line = _gtk_text_iter_get_text_line (&iter);
2731       g_assert (mark->body.mark.line == _gtk_text_iter_get_text_line (&iter));
2732
2733       segments_changed (tree); /* make sure the iterator recomputes its
2734                                   segment */
2735     }
2736   else
2737     {
2738       mark = _gtk_mark_segment_new (tree,
2739                                     left_gravity,
2740                                     name);
2741
2742       mark->body.mark.line = _gtk_text_iter_get_text_line (&iter);
2743
2744       if (mark->body.mark.name)
2745         g_hash_table_insert (tree->mark_table,
2746                              mark->body.mark.name,
2747                              mark);
2748     }
2749
2750   if (gtk_debug_flags & GTK_DEBUG_TEXT)
2751     _gtk_text_iter_check (&iter);
2752   
2753   /* Link mark into new location */
2754   gtk_text_btree_link_segment (mark, &iter);
2755
2756   /* Invalidate some iterators. */
2757   segments_changed (tree);
2758
2759   /*
2760    * update the screen at the mark's new location.
2761    */
2762
2763   redisplay_mark_if_visible (mark);
2764
2765   if (gtk_debug_flags & GTK_DEBUG_TEXT)
2766     _gtk_text_iter_check (&iter);
2767
2768   if (gtk_debug_flags & GTK_DEBUG_TEXT)
2769     _gtk_text_btree_check (tree);
2770   
2771   return mark;
2772 }
2773
2774
2775 GtkTextMark*
2776 _gtk_text_btree_set_mark (GtkTextBTree *tree,
2777                          GtkTextMark  *existing_mark,
2778                          const gchar *name,
2779                          gboolean left_gravity,
2780                          const GtkTextIter *iter,
2781                          gboolean should_exist)
2782 {
2783   GtkTextLineSegment *seg;
2784
2785   seg = real_set_mark (tree, existing_mark,
2786                        name, left_gravity, iter, should_exist,
2787                        TRUE);
2788
2789   return seg ? seg->body.mark.obj : NULL;
2790 }
2791
2792 gboolean
2793 _gtk_text_btree_get_selection_bounds (GtkTextBTree *tree,
2794                                      GtkTextIter  *start,
2795                                      GtkTextIter  *end)
2796 {
2797   GtkTextIter tmp_start, tmp_end;
2798
2799   _gtk_text_btree_get_iter_at_mark (tree, &tmp_start,
2800                                    tree->insert_mark);
2801   _gtk_text_btree_get_iter_at_mark (tree, &tmp_end,
2802                                    tree->selection_bound_mark);
2803
2804   if (gtk_text_iter_equal (&tmp_start, &tmp_end))
2805     {
2806       if (start)
2807         *start = tmp_start;
2808
2809       if (end)
2810         *end = tmp_end;
2811
2812       return FALSE;
2813     }
2814   else
2815     {
2816       gtk_text_iter_order (&tmp_start, &tmp_end);
2817
2818       if (start)
2819         *start = tmp_start;
2820
2821       if (end)
2822         *end = tmp_end;
2823
2824       return TRUE;
2825     }
2826 }
2827
2828 void
2829 _gtk_text_btree_place_cursor (GtkTextBTree      *tree,
2830                              const GtkTextIter *iter)
2831 {
2832   _gtk_text_btree_select_range (tree, iter, iter);
2833 }
2834
2835 void
2836 _gtk_text_btree_select_range (GtkTextBTree      *tree,
2837                               const GtkTextIter *ins,
2838                               const GtkTextIter *bound)
2839 {
2840   GtkTextIter start, end;
2841
2842   if (_gtk_text_btree_get_selection_bounds (tree, &start, &end))
2843     redisplay_region (tree, &start, &end);
2844
2845   /* Move insert AND selection_bound before we redisplay */
2846   real_set_mark (tree, tree->insert_mark,
2847                  "insert", FALSE, ins, TRUE, FALSE);
2848   real_set_mark (tree, tree->selection_bound_mark,
2849                  "selection_bound", FALSE, bound, TRUE, FALSE);
2850 }
2851
2852
2853 void
2854 _gtk_text_btree_remove_mark_by_name (GtkTextBTree *tree,
2855                                     const gchar *name)
2856 {
2857   GtkTextMark *mark;
2858
2859   g_return_if_fail (tree != NULL);
2860   g_return_if_fail (name != NULL);
2861
2862   mark = g_hash_table_lookup (tree->mark_table,
2863                               name);
2864
2865   _gtk_text_btree_remove_mark (tree, mark);
2866 }
2867
2868 void
2869 _gtk_text_btree_release_mark_segment (GtkTextBTree       *tree,
2870                                       GtkTextLineSegment *segment)
2871 {
2872
2873   if (segment->body.mark.name)
2874     g_hash_table_remove (tree->mark_table, segment->body.mark.name);
2875
2876   segment->body.mark.tree = NULL;
2877   segment->body.mark.line = NULL;
2878   
2879   /* Remove the ref on the mark, which frees segment as a side effect
2880    * if this is the last reference.
2881    */
2882   g_object_unref (segment->body.mark.obj);
2883 }
2884
2885 void
2886 _gtk_text_btree_remove_mark (GtkTextBTree *tree,
2887                              GtkTextMark *mark)
2888 {
2889   GtkTextLineSegment *segment;
2890
2891   g_return_if_fail (mark != NULL);
2892   g_return_if_fail (tree != NULL);
2893
2894   segment = mark->segment;
2895
2896   if (segment->body.mark.not_deleteable)
2897     {
2898       g_warning ("Can't delete special mark `%s'", segment->body.mark.name);
2899       return;
2900     }
2901
2902   /* This calls cleanup_line and segments_changed */
2903   gtk_text_btree_unlink_segment (tree, segment, segment->body.mark.line);
2904   
2905   _gtk_text_btree_release_mark_segment (tree, segment);
2906 }
2907
2908 gboolean
2909 _gtk_text_btree_mark_is_insert (GtkTextBTree *tree,
2910                                 GtkTextMark *segment)
2911 {
2912   return segment == tree->insert_mark;
2913 }
2914
2915 gboolean
2916 _gtk_text_btree_mark_is_selection_bound (GtkTextBTree *tree,
2917                                          GtkTextMark *segment)
2918 {
2919   return segment == tree->selection_bound_mark;
2920 }
2921
2922 GtkTextMark*
2923 _gtk_text_btree_get_mark_by_name (GtkTextBTree *tree,
2924                                   const gchar *name)
2925 {
2926   GtkTextLineSegment *seg;
2927
2928   g_return_val_if_fail (tree != NULL, NULL);
2929   g_return_val_if_fail (name != NULL, NULL);
2930
2931   seg = g_hash_table_lookup (tree->mark_table, name);
2932
2933   return seg ? seg->body.mark.obj : NULL;
2934 }
2935
2936 /**
2937  * gtk_text_mark_set_visible:
2938  * @mark: a #GtkTextMark
2939  * @setting: visibility of mark
2940  * 
2941  * Sets the visibility of @mark; the insertion point is normally
2942  * visible, i.e. you can see it as a vertical bar. Also, the text
2943  * widget uses a visible mark to indicate where a drop will occur when
2944  * dragging-and-dropping text. Most other marks are not visible.
2945  * Marks are not visible by default.
2946  * 
2947  **/
2948 void
2949 gtk_text_mark_set_visible (GtkTextMark       *mark,
2950                            gboolean           setting)
2951 {
2952   GtkTextLineSegment *seg;
2953
2954   g_return_if_fail (mark != NULL);
2955
2956   seg = mark->segment;
2957
2958   if (seg->body.mark.visible == setting)
2959     return;
2960   else
2961     {
2962       seg->body.mark.visible = setting;
2963
2964       redisplay_mark (seg);
2965     }
2966 }
2967
2968 GtkTextLine*
2969 _gtk_text_btree_first_could_contain_tag (GtkTextBTree *tree,
2970                                         GtkTextTag *tag)
2971 {
2972   GtkTextBTreeNode *node;
2973   GtkTextTagInfo *info;
2974
2975   g_return_val_if_fail (tree != NULL, NULL);
2976
2977   if (tag != NULL)
2978     {
2979       info = gtk_text_btree_get_existing_tag_info (tree, tag);
2980
2981       if (info == NULL)
2982         return NULL;
2983
2984       if (info->tag_root == NULL)
2985         return NULL;
2986
2987       node = info->tag_root;
2988
2989       /* We know the tag root has instances of the given
2990          tag below it */
2991
2992     continue_outer_loop:
2993       g_assert (node != NULL);
2994       while (node->level > 0)
2995         {
2996           g_assert (node != NULL); /* Failure probably means bad tag summaries. */
2997           node = node->children.node;
2998           while (node != NULL)
2999             {
3000               if (gtk_text_btree_node_has_tag (node, tag))
3001                 goto continue_outer_loop;
3002
3003               node = node->next;
3004             }
3005           g_assert (node != NULL);
3006         }
3007
3008       g_assert (node != NULL); /* The tag summaries said some node had
3009                                   tag toggles... */
3010
3011       g_assert (node->level == 0);
3012
3013       return node->children.line;
3014     }
3015   else
3016     {
3017       /* Looking for any tag at all (tag == NULL).
3018          Unfortunately this can't be done in a simple and efficient way
3019          right now; so I'm just going to return the
3020          first line in the btree. FIXME */
3021       return _gtk_text_btree_get_line (tree, 0, NULL);
3022     }
3023 }
3024
3025 GtkTextLine*
3026 _gtk_text_btree_last_could_contain_tag (GtkTextBTree *tree,
3027                                        GtkTextTag *tag)
3028 {
3029   GtkTextBTreeNode *node;
3030   GtkTextBTreeNode *last_node;
3031   GtkTextLine *line;
3032   GtkTextTagInfo *info;
3033
3034   g_return_val_if_fail (tree != NULL, NULL);
3035
3036   if (tag != NULL)
3037     {
3038       info = gtk_text_btree_get_existing_tag_info (tree, tag);
3039
3040       if (info->tag_root == NULL)
3041         return NULL;
3042
3043       node = info->tag_root;
3044       /* We know the tag root has instances of the given
3045          tag below it */
3046
3047       while (node->level > 0)
3048         {
3049           g_assert (node != NULL); /* Failure probably means bad tag summaries. */
3050           last_node = NULL;
3051           node = node->children.node;
3052           while (node != NULL)
3053             {
3054               if (gtk_text_btree_node_has_tag (node, tag))
3055                 last_node = node;
3056               node = node->next;
3057             }
3058
3059           node = last_node;
3060         }
3061
3062       g_assert (node != NULL); /* The tag summaries said some node had
3063                                   tag toggles... */
3064
3065       g_assert (node->level == 0);
3066
3067       /* Find the last line in this node */
3068       line = node->children.line;
3069       while (line->next != NULL)
3070         line = line->next;
3071
3072       return line;
3073     }
3074   else
3075     {
3076       /* This search can't be done efficiently at the moment,
3077          at least not without complexity.
3078          So, we just return the last line.
3079       */
3080       return _gtk_text_btree_get_end_iter_line (tree);
3081     }
3082 }
3083
3084
3085 /*
3086  * Lines
3087  */
3088
3089 gint
3090 _gtk_text_line_get_number (GtkTextLine *line)
3091 {
3092   GtkTextLine *line2;
3093   GtkTextBTreeNode *node, *parent, *node2;
3094   int index;
3095
3096   /*
3097    * First count how many lines precede this one in its level-0
3098    * GtkTextBTreeNode.
3099    */
3100
3101   node = line->parent;
3102   index = 0;
3103   for (line2 = node->children.line; line2 != line;
3104        line2 = line2->next)
3105     {
3106       if (line2 == NULL)
3107         {
3108           g_error ("gtk_text_btree_line_number couldn't find line");
3109         }
3110       index += 1;
3111     }
3112
3113   /*
3114    * Now work up through the levels of the tree one at a time,
3115    * counting how many lines are in GtkTextBTreeNodes preceding the current
3116    * GtkTextBTreeNode.
3117    */
3118
3119   for (parent = node->parent ; parent != NULL;
3120        node = parent, parent = parent->parent)
3121     {
3122       for (node2 = parent->children.node; node2 != node;
3123            node2 = node2->next)
3124         {
3125           if (node2 == NULL)
3126             {
3127               g_error ("gtk_text_btree_line_number couldn't find GtkTextBTreeNode");
3128             }
3129           index += node2->num_lines;
3130         }
3131     }
3132   return index;
3133 }
3134
3135 static GtkTextLineSegment*
3136 find_toggle_segment_before_char (GtkTextLine *line,
3137                                  gint char_in_line,
3138                                  GtkTextTag *tag)
3139 {
3140   GtkTextLineSegment *seg;
3141   GtkTextLineSegment *toggle_seg;
3142   int index;
3143
3144   toggle_seg = NULL;
3145   index = 0;
3146   seg = line->segments;
3147   while ( (index + seg->char_count) <= char_in_line )
3148     {
3149       if (((seg->type == &gtk_text_toggle_on_type)
3150            || (seg->type == &gtk_text_toggle_off_type))
3151           && (seg->body.toggle.info->tag == tag))
3152         toggle_seg = seg;
3153
3154       index += seg->char_count;
3155       seg = seg->next;
3156     }
3157
3158   return toggle_seg;
3159 }
3160
3161 static GtkTextLineSegment*
3162 find_toggle_segment_before_byte (GtkTextLine *line,
3163                                  gint byte_in_line,
3164                                  GtkTextTag *tag)
3165 {
3166   GtkTextLineSegment *seg;
3167   GtkTextLineSegment *toggle_seg;
3168   int index;
3169
3170   toggle_seg = NULL;
3171   index = 0;
3172   seg = line->segments;
3173   while ( (index + seg->byte_count) <= byte_in_line )
3174     {
3175       if (((seg->type == &gtk_text_toggle_on_type)
3176            || (seg->type == &gtk_text_toggle_off_type))
3177           && (seg->body.toggle.info->tag == tag))
3178         toggle_seg = seg;
3179
3180       index += seg->byte_count;
3181       seg = seg->next;
3182     }
3183
3184   return toggle_seg;
3185 }
3186
3187 static gboolean
3188 find_toggle_outside_current_line (GtkTextLine *line,
3189                                   GtkTextBTree *tree,
3190                                   GtkTextTag *tag)
3191 {
3192   GtkTextBTreeNode *node;
3193   GtkTextLine *sibling_line;
3194   GtkTextLineSegment *seg;
3195   GtkTextLineSegment *toggle_seg;
3196   int toggles;
3197   GtkTextTagInfo *info = NULL;
3198
3199   /*
3200    * No toggle in this line.  Look for toggles for the tag in lines
3201    * that are predecessors of line but under the same
3202    * level-0 GtkTextBTreeNode.
3203    */
3204   toggle_seg = NULL;
3205   sibling_line = line->parent->children.line;
3206   while (sibling_line != line)
3207     {
3208       seg = sibling_line->segments;
3209       while (seg != NULL)
3210         {
3211           if (((seg->type == &gtk_text_toggle_on_type)
3212                || (seg->type == &gtk_text_toggle_off_type))
3213               && (seg->body.toggle.info->tag == tag))
3214             toggle_seg = seg;
3215
3216           seg = seg->next;
3217         }
3218
3219       sibling_line = sibling_line->next;
3220     }
3221
3222   if (toggle_seg != NULL)
3223     return (toggle_seg->type == &gtk_text_toggle_on_type);
3224
3225   /*
3226    * No toggle in this GtkTextBTreeNode.  Scan upwards through the ancestors of
3227    * this GtkTextBTreeNode, counting the number of toggles of the given tag in
3228    * siblings that precede that GtkTextBTreeNode.
3229    */
3230
3231   info = gtk_text_btree_get_existing_tag_info (tree, tag);
3232
3233   if (info == NULL)
3234     return FALSE;
3235
3236   toggles = 0;
3237   node = line->parent;
3238   while (node->parent != NULL)
3239     {
3240       GtkTextBTreeNode *sibling_node;
3241
3242       sibling_node = node->parent->children.node;
3243       while (sibling_node != node)
3244         {
3245           Summary *summary;
3246
3247           summary = sibling_node->summary;
3248           while (summary != NULL)
3249             {
3250               if (summary->info == info)
3251                 toggles += summary->toggle_count;
3252
3253               summary = summary->next;
3254             }
3255
3256           sibling_node = sibling_node->next;
3257         }
3258
3259       if (node == info->tag_root)
3260         break;
3261
3262       node = node->parent;
3263     }
3264
3265   /*
3266    * An odd number of toggles means that the tag is present at the
3267    * given point.
3268    */
3269
3270   return (toggles & 1) != 0;
3271 }
3272
3273 /* FIXME this function is far too slow, for no good reason. */
3274 gboolean
3275 _gtk_text_line_char_has_tag (GtkTextLine *line,
3276                              GtkTextBTree *tree,
3277                              gint char_in_line,
3278                              GtkTextTag *tag)
3279 {
3280   GtkTextLineSegment *toggle_seg;
3281
3282   g_return_val_if_fail (line != NULL, FALSE);
3283
3284   /*
3285    * Check for toggles for the tag in the line but before
3286    * the char.  If there is one, its type indicates whether or
3287    * not the character is tagged.
3288    */
3289
3290   toggle_seg = find_toggle_segment_before_char (line, char_in_line, tag);
3291
3292   if (toggle_seg != NULL)
3293     return (toggle_seg->type == &gtk_text_toggle_on_type);
3294   else
3295     return find_toggle_outside_current_line (line, tree, tag);
3296 }
3297
3298 gboolean
3299 _gtk_text_line_byte_has_tag (GtkTextLine *line,
3300                              GtkTextBTree *tree,
3301                              gint byte_in_line,
3302                              GtkTextTag *tag)
3303 {
3304   GtkTextLineSegment *toggle_seg;
3305
3306   g_return_val_if_fail (line != NULL, FALSE);
3307
3308   /*
3309    * Check for toggles for the tag in the line but before
3310    * the char.  If there is one, its type indicates whether or
3311    * not the character is tagged.
3312    */
3313
3314   toggle_seg = find_toggle_segment_before_byte (line, byte_in_line, tag);
3315
3316   if (toggle_seg != NULL)
3317     return (toggle_seg->type == &gtk_text_toggle_on_type);
3318   else
3319     return find_toggle_outside_current_line (line, tree, tag);
3320 }
3321
3322 gboolean
3323 _gtk_text_line_is_last (GtkTextLine *line,
3324                         GtkTextBTree *tree)
3325 {
3326   return line == get_last_line (tree);
3327 }
3328
3329 static void
3330 ensure_end_iter_line (GtkTextBTree *tree)
3331 {
3332   if (tree->end_iter_line_stamp != tree->chars_changed_stamp)
3333     {
3334       int n_lines;
3335       int real_line;
3336
3337       /* n_lines is without the magic line at the end */
3338       n_lines = _gtk_text_btree_line_count (tree);
3339  
3340       g_assert (n_lines >= 1);
3341
3342       tree->end_iter_line = _gtk_text_btree_get_line_no_last (tree, -1, &real_line);
3343       
3344       tree->end_iter_line_stamp = tree->chars_changed_stamp;
3345     }
3346 }
3347
3348 static void
3349 ensure_end_iter_segment (GtkTextBTree *tree)
3350 {
3351   if (tree->end_iter_segment_stamp != tree->segments_changed_stamp)
3352     {
3353       GtkTextLineSegment *seg;
3354       GtkTextLineSegment *last_with_chars;
3355
3356       ensure_end_iter_line (tree);
3357
3358       last_with_chars = NULL;
3359       
3360       seg = tree->end_iter_line->segments;
3361       while (seg != NULL)
3362         {
3363           if (seg->char_count > 0)
3364             last_with_chars = seg;
3365           seg = seg->next;
3366         }
3367
3368       tree->end_iter_segment = last_with_chars;
3369
3370       /* We know the last char in the last line is '\n' */
3371       tree->end_iter_segment_byte_index = last_with_chars->byte_count - 1;
3372       tree->end_iter_segment_char_offset = last_with_chars->char_count - 1;
3373       
3374       tree->end_iter_segment_stamp = tree->segments_changed_stamp;
3375
3376       g_assert (tree->end_iter_segment->type == &gtk_text_char_type);
3377       g_assert (tree->end_iter_segment->body.chars[tree->end_iter_segment_byte_index] == '\n');
3378     }
3379 }
3380
3381 gboolean
3382 _gtk_text_line_contains_end_iter (GtkTextLine  *line,
3383                                   GtkTextBTree *tree)
3384 {
3385   ensure_end_iter_line (tree);
3386
3387   return line == tree->end_iter_line;
3388 }
3389
3390 gboolean
3391 _gtk_text_btree_is_end (GtkTextBTree       *tree,
3392                         GtkTextLine        *line,
3393                         GtkTextLineSegment *seg,
3394                         int                 byte_index,
3395                         int                 char_offset)
3396 {
3397   g_return_val_if_fail (byte_index >= 0 || char_offset >= 0, FALSE);
3398   
3399   /* Do this first to avoid walking segments in most cases */
3400   if (!_gtk_text_line_contains_end_iter (line, tree))
3401     return FALSE;
3402
3403   ensure_end_iter_segment (tree);
3404
3405   if (seg != tree->end_iter_segment)
3406     return FALSE;
3407
3408   if (byte_index >= 0)
3409     return byte_index == tree->end_iter_segment_byte_index;
3410   else
3411     return char_offset == tree->end_iter_segment_char_offset;
3412 }
3413
3414 GtkTextLine*
3415 _gtk_text_line_next (GtkTextLine *line)
3416 {
3417   GtkTextBTreeNode *node;
3418
3419   if (line->next != NULL)
3420     return line->next;
3421   else
3422     {
3423       /*
3424        * This was the last line associated with the particular parent
3425        * GtkTextBTreeNode.  Search up the tree for the next GtkTextBTreeNode,
3426        * then search down from that GtkTextBTreeNode to find the first
3427        * line.
3428        */
3429
3430       node = line->parent;
3431       while (node != NULL && node->next == NULL)
3432         node = node->parent;
3433
3434       if (node == NULL)
3435         return NULL;
3436
3437       node = node->next;
3438       while (node->level > 0)
3439         {
3440           node = node->children.node;
3441         }
3442
3443       g_assert (node->children.line != line);
3444
3445       return node->children.line;
3446     }
3447 }
3448
3449 GtkTextLine*
3450 _gtk_text_line_next_excluding_last (GtkTextLine *line)
3451 {
3452   GtkTextLine *next;
3453   
3454   next = _gtk_text_line_next (line);
3455
3456   /* If we were on the end iter line, we can't go to
3457    * the last line
3458    */
3459   if (next && next->next == NULL && /* these checks are optimization only */
3460       _gtk_text_line_next (next) == NULL)
3461     return NULL;
3462
3463   return next;
3464 }
3465
3466 GtkTextLine*
3467 _gtk_text_line_previous (GtkTextLine *line)
3468 {
3469   GtkTextBTreeNode *node;
3470   GtkTextBTreeNode *node2;
3471   GtkTextLine *prev;
3472
3473   /*
3474    * Find the line under this GtkTextBTreeNode just before the starting line.
3475    */
3476   prev = line->parent->children.line;        /* First line at leaf */
3477   while (prev != line)
3478     {
3479       if (prev->next == line)
3480         return prev;
3481
3482       prev = prev->next;
3483
3484       if (prev == NULL)
3485         g_error ("gtk_text_btree_previous_line ran out of lines");
3486     }
3487
3488   /*
3489    * This was the first line associated with the particular parent
3490    * GtkTextBTreeNode.  Search up the tree for the previous GtkTextBTreeNode,
3491    * then search down from that GtkTextBTreeNode to find its last line.
3492    */
3493   for (node = line->parent; ; node = node->parent)
3494     {
3495       if (node == NULL || node->parent == NULL)
3496         return NULL;
3497       else if (node != node->parent->children.node)
3498         break;
3499     }
3500
3501   for (node2 = node->parent->children.node; ;
3502        node2 = node2->children.node)
3503     {
3504       while (node2->next != node)
3505         node2 = node2->next;
3506
3507       if (node2->level == 0)
3508         break;
3509
3510       node = NULL;
3511     }
3512
3513   for (prev = node2->children.line ; ; prev = prev->next)
3514     {
3515       if (prev->next == NULL)
3516         return prev;
3517     }
3518
3519   g_assert_not_reached ();
3520   return NULL;
3521 }
3522
3523
3524 GtkTextLineData*
3525 _gtk_text_line_data_new (GtkTextLayout *layout,
3526                          GtkTextLine   *line)
3527 {
3528   GtkTextLineData *line_data;
3529
3530   line_data = g_new (GtkTextLineData, 1);
3531
3532   line_data->view_id = layout;
3533   line_data->next = NULL;
3534   line_data->width = 0;
3535   line_data->height = 0;
3536   line_data->valid = FALSE;
3537
3538   return line_data;
3539 }
3540
3541 void
3542 _gtk_text_line_add_data (GtkTextLine     *line,
3543                          GtkTextLineData *data)
3544 {
3545   g_return_if_fail (line != NULL);
3546   g_return_if_fail (data != NULL);
3547   g_return_if_fail (data->view_id != NULL);
3548
3549   if (line->views)
3550     {
3551       data->next = line->views;
3552       line->views = data;
3553     }
3554   else
3555     {
3556       line->views = data;
3557     }
3558 }
3559
3560 gpointer
3561 _gtk_text_line_remove_data (GtkTextLine *line,
3562                            gpointer view_id)
3563 {
3564   GtkTextLineData *prev;
3565   GtkTextLineData *iter;
3566
3567   g_return_val_if_fail (line != NULL, NULL);
3568   g_return_val_if_fail (view_id != NULL, NULL);
3569
3570   prev = NULL;
3571   iter = line->views;
3572   while (iter != NULL)
3573     {
3574       if (iter->view_id == view_id)
3575         break;
3576       prev = iter;
3577       iter = iter->next;
3578     }
3579
3580   if (iter)
3581     {
3582       if (prev)
3583         prev->next = iter->next;
3584       else
3585         line->views = iter->next;
3586
3587       return iter;
3588     }
3589   else
3590     return NULL;
3591 }
3592
3593 gpointer
3594 _gtk_text_line_get_data (GtkTextLine *line,
3595                          gpointer view_id)
3596 {
3597   GtkTextLineData *iter;
3598
3599   g_return_val_if_fail (line != NULL, NULL);
3600   g_return_val_if_fail (view_id != NULL, NULL);
3601
3602   iter = line->views;
3603   while (iter != NULL)
3604     {
3605       if (iter->view_id == view_id)
3606         break;
3607       iter = iter->next;
3608     }
3609
3610   return iter;
3611 }
3612
3613 void
3614 _gtk_text_line_invalidate_wrap (GtkTextLine *line,
3615                                 GtkTextLineData *ld)
3616 {
3617   /* For now this is totally unoptimized. FIXME?
3618
3619      We could probably optimize the case where the width removed
3620      is less than the max width for the parent node,
3621      and the case where the height is unchanged when we re-wrap.
3622   */
3623   
3624   g_return_if_fail (ld != NULL);
3625   
3626   ld->valid = FALSE;
3627   gtk_text_btree_node_invalidate_upward (line->parent, ld->view_id);
3628 }
3629
3630 gint
3631 _gtk_text_line_char_count (GtkTextLine *line)
3632 {
3633   GtkTextLineSegment *seg;
3634   gint size;
3635
3636   size = 0;
3637   seg = line->segments;
3638   while (seg != NULL)
3639     {
3640       size += seg->char_count;
3641       seg = seg->next;
3642     }
3643   return size;
3644 }
3645
3646 gint
3647 _gtk_text_line_byte_count (GtkTextLine *line)
3648 {
3649   GtkTextLineSegment *seg;
3650   gint size;
3651
3652   size = 0;
3653   seg = line->segments;
3654   while (seg != NULL)
3655     {
3656       size += seg->byte_count;
3657       seg = seg->next;
3658     }
3659
3660   return size;
3661 }
3662
3663 gint
3664 _gtk_text_line_char_index (GtkTextLine *target_line)
3665 {
3666   GSList *node_stack = NULL;
3667   GtkTextBTreeNode *iter;
3668   GtkTextLine *line;
3669   gint num_chars;
3670
3671   /* Push all our parent nodes onto a stack */
3672   iter = target_line->parent;
3673
3674   g_assert (iter != NULL);
3675
3676   while (iter != NULL)
3677     {
3678       node_stack = g_slist_prepend (node_stack, iter);
3679
3680       iter = iter->parent;
3681     }
3682
3683   /* Check that we have the root node on top of the stack. */
3684   g_assert (node_stack != NULL &&
3685             node_stack->data != NULL &&
3686             ((GtkTextBTreeNode*)node_stack->data)->parent == NULL);
3687
3688   /* Add up chars in all nodes before the nodes in our stack.
3689    */
3690
3691   num_chars = 0;
3692   iter = node_stack->data;
3693   while (iter != NULL)
3694     {
3695       GtkTextBTreeNode *child_iter;
3696       GtkTextBTreeNode *next_node;
3697
3698       next_node = node_stack->next ?
3699         node_stack->next->data : NULL;
3700       node_stack = g_slist_remove (node_stack, node_stack->data);
3701
3702       if (iter->level == 0)
3703         {
3704           /* stack should be empty when we're on the last node */
3705           g_assert (node_stack == NULL);
3706           break; /* Our children are now lines */
3707         }
3708
3709       g_assert (next_node != NULL);
3710       g_assert (iter != NULL);
3711       g_assert (next_node->parent == iter);
3712
3713       /* Add up chars before us in the tree */
3714       child_iter = iter->children.node;
3715       while (child_iter != next_node)
3716         {
3717           g_assert (child_iter != NULL);
3718
3719           num_chars += child_iter->num_chars;
3720
3721           child_iter = child_iter->next;
3722         }
3723
3724       iter = next_node;
3725     }
3726
3727   g_assert (iter != NULL);
3728   g_assert (iter == target_line->parent);
3729
3730   /* Since we don't store char counts in lines, only in segments, we
3731      have to iterate over the lines adding up segment char counts
3732      until we find our line.  */
3733   line = iter->children.line;
3734   while (line != target_line)
3735     {
3736       g_assert (line != NULL);
3737
3738       num_chars += _gtk_text_line_char_count (line);
3739
3740       line = line->next;
3741     }
3742
3743   g_assert (line == target_line);
3744
3745   return num_chars;
3746 }
3747
3748 GtkTextLineSegment*
3749 _gtk_text_line_byte_to_segment (GtkTextLine *line,
3750                                gint byte_offset,
3751                                gint *seg_offset)
3752 {
3753   GtkTextLineSegment *seg;
3754   int offset;
3755
3756   g_return_val_if_fail (line != NULL, NULL);
3757
3758   offset = byte_offset;
3759   seg = line->segments;
3760
3761   while (offset >= seg->byte_count)
3762     {
3763       g_assert (seg != NULL); /* means an invalid byte index */
3764       offset -= seg->byte_count;
3765       seg = seg->next;
3766     }
3767
3768   if (seg_offset)
3769     *seg_offset = offset;
3770
3771   return seg;
3772 }
3773
3774 GtkTextLineSegment*
3775 _gtk_text_line_char_to_segment (GtkTextLine *line,
3776                                gint char_offset,
3777                                gint *seg_offset)
3778 {
3779   GtkTextLineSegment *seg;
3780   int offset;
3781
3782   g_return_val_if_fail (line != NULL, NULL);
3783
3784   offset = char_offset;
3785   seg = line->segments;
3786
3787   while (offset >= seg->char_count)
3788     {
3789       g_assert (seg != NULL); /* means an invalid char index */
3790       offset -= seg->char_count;
3791       seg = seg->next;
3792     }
3793
3794   if (seg_offset)
3795     *seg_offset = offset;
3796
3797   return seg;
3798 }
3799
3800 GtkTextLineSegment*
3801 _gtk_text_line_byte_to_any_segment (GtkTextLine *line,
3802                                    gint byte_offset,
3803                                    gint *seg_offset)
3804 {
3805   GtkTextLineSegment *seg;
3806   int offset;
3807
3808   g_return_val_if_fail (line != NULL, NULL);
3809
3810   offset = byte_offset;
3811   seg = line->segments;
3812
3813   while (offset > 0 && offset >= seg->byte_count)
3814     {
3815       g_assert (seg != NULL); /* means an invalid byte index */
3816       offset -= seg->byte_count;
3817       seg = seg->next;
3818     }
3819
3820   if (seg_offset)
3821     *seg_offset = offset;
3822
3823   return seg;
3824 }
3825
3826 GtkTextLineSegment*
3827 _gtk_text_line_char_to_any_segment (GtkTextLine *line,
3828                                    gint char_offset,
3829                                    gint *seg_offset)
3830 {
3831   GtkTextLineSegment *seg;
3832   int offset;
3833
3834   g_return_val_if_fail (line != NULL, NULL);
3835
3836   offset = char_offset;
3837   seg = line->segments;
3838
3839   while (offset > 0 && offset >= seg->char_count)
3840     {
3841       g_assert (seg != NULL); /* means an invalid byte index */
3842       offset -= seg->char_count;
3843       seg = seg->next;
3844     }
3845
3846   if (seg_offset)
3847     *seg_offset = offset;
3848
3849   return seg;
3850 }
3851
3852 gint
3853 _gtk_text_line_byte_to_char (GtkTextLine *line,
3854                             gint byte_offset)
3855 {
3856   gint char_offset;
3857   GtkTextLineSegment *seg;
3858
3859   g_return_val_if_fail (line != NULL, 0);
3860   g_return_val_if_fail (byte_offset >= 0, 0);
3861
3862   char_offset = 0;
3863   seg = line->segments;
3864   while (byte_offset >= seg->byte_count) /* while (we need to go farther than
3865                                             the next segment) */
3866     {
3867       g_assert (seg != NULL); /* our byte_index was bogus if this happens */
3868
3869       byte_offset -= seg->byte_count;
3870       char_offset += seg->char_count;
3871
3872       seg = seg->next;
3873     }
3874
3875   g_assert (seg != NULL);
3876
3877   /* Now byte_offset is the offset into the current segment,
3878      and char_offset is the start of the current segment.
3879      Optimize the case where no chars use > 1 byte */
3880   if (seg->byte_count == seg->char_count)
3881     return char_offset + byte_offset;
3882   else
3883     {
3884       if (seg->type == &gtk_text_char_type)
3885         return char_offset + g_utf8_strlen (seg->body.chars, byte_offset);
3886       else
3887         {
3888           g_assert (seg->char_count == 1);
3889           g_assert (byte_offset == 0);
3890
3891           return char_offset;
3892         }
3893     }
3894 }
3895
3896 gint
3897 _gtk_text_line_char_to_byte (GtkTextLine *line,
3898                             gint         char_offset)
3899 {
3900   g_warning ("FIXME not implemented");
3901
3902   return 0;
3903 }
3904
3905 /* FIXME sync with char_locate (or figure out a clean
3906    way to merge the two functions) */
3907 gboolean
3908 _gtk_text_line_byte_locate (GtkTextLine *line,
3909                             gint byte_offset,
3910                             GtkTextLineSegment **segment,
3911                             GtkTextLineSegment **any_segment,
3912                             gint *seg_byte_offset,
3913                             gint *line_byte_offset)
3914 {
3915   GtkTextLineSegment *seg;
3916   GtkTextLineSegment *after_prev_indexable;
3917   GtkTextLineSegment *after_last_indexable;
3918   GtkTextLineSegment *last_indexable;
3919   gint offset;
3920   gint bytes_in_line;
3921
3922   g_return_val_if_fail (line != NULL, FALSE);
3923   g_return_val_if_fail (byte_offset >= 0, FALSE);
3924
3925   *segment = NULL;
3926   *any_segment = NULL;
3927   bytes_in_line = 0;
3928
3929   offset = byte_offset;
3930
3931   last_indexable = NULL;
3932   after_last_indexable = line->segments;
3933   after_prev_indexable = line->segments;
3934   seg = line->segments;
3935
3936   /* The loop ends when we're inside a segment;
3937      last_indexable refers to the last segment
3938      we passed entirely. */
3939   while (seg && offset >= seg->byte_count)
3940     {
3941       if (seg->char_count > 0)
3942         {
3943           offset -= seg->byte_count;
3944           bytes_in_line += seg->byte_count;
3945           last_indexable = seg;
3946           after_prev_indexable = after_last_indexable;
3947           after_last_indexable = last_indexable->next;
3948         }
3949
3950       seg = seg->next;
3951     }
3952
3953   if (seg == NULL)
3954     {
3955       /* We went off the end of the line */
3956       if (offset != 0)
3957         g_warning ("%s: byte index off the end of the line", G_STRLOC);
3958
3959       return FALSE;
3960     }
3961   else
3962     {
3963       *segment = seg;
3964       if (after_last_indexable != NULL)
3965         *any_segment = after_last_indexable;
3966       else
3967         *any_segment = *segment;
3968     }
3969
3970   /* Override any_segment if we're in the middle of a segment. */
3971   if (offset > 0)
3972     *any_segment = *segment;
3973
3974   *seg_byte_offset = offset;
3975
3976   g_assert (*segment != NULL);
3977   g_assert (*any_segment != NULL);
3978   g_assert (*seg_byte_offset < (*segment)->byte_count);
3979
3980   *line_byte_offset = bytes_in_line + *seg_byte_offset;
3981
3982   return TRUE;
3983 }
3984
3985 /* FIXME sync with byte_locate (or figure out a clean
3986    way to merge the two functions) */
3987 gboolean
3988 _gtk_text_line_char_locate     (GtkTextLine     *line,
3989                                 gint              char_offset,
3990                                 GtkTextLineSegment **segment,
3991                                 GtkTextLineSegment **any_segment,
3992                                 gint             *seg_char_offset,
3993                                 gint             *line_char_offset)
3994 {
3995   GtkTextLineSegment *seg;
3996   GtkTextLineSegment *after_prev_indexable;
3997   GtkTextLineSegment *after_last_indexable;
3998   GtkTextLineSegment *last_indexable;
3999   gint offset;
4000   gint chars_in_line;
4001
4002   g_return_val_if_fail (line != NULL, FALSE);
4003   g_return_val_if_fail (char_offset >= 0, FALSE);
4004   
4005   *segment = NULL;
4006   *any_segment = NULL;
4007   chars_in_line = 0;
4008
4009   offset = char_offset;
4010
4011   last_indexable = NULL;
4012   after_last_indexable = line->segments;
4013   after_prev_indexable = line->segments;
4014   seg = line->segments;
4015
4016   /* The loop ends when we're inside a segment;
4017      last_indexable refers to the last segment
4018      we passed entirely. */
4019   while (seg && offset >= seg->char_count)
4020     {
4021       if (seg->char_count > 0)
4022         {
4023           offset -= seg->char_count;
4024           chars_in_line += seg->char_count;
4025           last_indexable = seg;
4026           after_prev_indexable = after_last_indexable;
4027           after_last_indexable = last_indexable->next;
4028         }
4029
4030       seg = seg->next;
4031     }
4032
4033   if (seg == NULL)
4034     {
4035       /* end of the line */
4036       if (offset != 0)
4037         g_warning ("%s: char offset off the end of the line", G_STRLOC);
4038
4039       return FALSE;
4040     }
4041   else
4042     {
4043       *segment = seg;
4044       if (after_last_indexable != NULL)
4045         *any_segment = after_last_indexable;
4046       else
4047         *any_segment = *segment;
4048     }
4049
4050   /* Override any_segment if we're in the middle of a segment. */
4051   if (offset > 0)
4052     *any_segment = *segment;
4053
4054   *seg_char_offset = offset;
4055
4056   g_assert (*segment != NULL);
4057   g_assert (*any_segment != NULL);
4058   g_assert (*seg_char_offset < (*segment)->char_count);
4059
4060   *line_char_offset = chars_in_line + *seg_char_offset;
4061
4062   return TRUE;
4063 }
4064
4065 void
4066 _gtk_text_line_byte_to_char_offsets (GtkTextLine *line,
4067                                     gint byte_offset,
4068                                     gint *line_char_offset,
4069                                     gint *seg_char_offset)
4070 {
4071   GtkTextLineSegment *seg;
4072   int offset;
4073
4074   g_return_if_fail (line != NULL);
4075   g_return_if_fail (byte_offset >= 0);
4076
4077   *line_char_offset = 0;
4078
4079   offset = byte_offset;
4080   seg = line->segments;
4081
4082   while (offset >= seg->byte_count)
4083     {
4084       offset -= seg->byte_count;
4085       *line_char_offset += seg->char_count;
4086       seg = seg->next;
4087       g_assert (seg != NULL); /* means an invalid char offset */
4088     }
4089
4090   g_assert (seg->char_count > 0); /* indexable. */
4091
4092   /* offset is now the number of bytes into the current segment we
4093    * want to go. Count chars into the current segment.
4094    */
4095
4096   if (seg->type == &gtk_text_char_type)
4097     {
4098       *seg_char_offset = g_utf8_strlen (seg->body.chars, offset);
4099
4100       g_assert (*seg_char_offset < seg->char_count);
4101
4102       *line_char_offset += *seg_char_offset;
4103     }
4104   else
4105     {
4106       g_assert (offset == 0);
4107       *seg_char_offset = 0;
4108     }
4109 }
4110
4111 void
4112 _gtk_text_line_char_to_byte_offsets (GtkTextLine *line,
4113                                     gint char_offset,
4114                                     gint *line_byte_offset,
4115                                     gint *seg_byte_offset)
4116 {
4117   GtkTextLineSegment *seg;
4118   int offset;
4119
4120   g_return_if_fail (line != NULL);
4121   g_return_if_fail (char_offset >= 0);
4122
4123   *line_byte_offset = 0;
4124
4125   offset = char_offset;
4126   seg = line->segments;
4127
4128   while (offset >= seg->char_count)
4129     {
4130       offset -= seg->char_count;
4131       *line_byte_offset += seg->byte_count;
4132       seg = seg->next;
4133       g_assert (seg != NULL); /* means an invalid char offset */
4134     }
4135
4136   g_assert (seg->char_count > 0); /* indexable. */
4137
4138   /* offset is now the number of chars into the current segment we
4139      want to go. Count bytes into the current segment. */
4140
4141   if (seg->type == &gtk_text_char_type)
4142     {
4143       *seg_byte_offset = 0;
4144       while (offset > 0)
4145         {
4146           gint bytes;
4147           const char * start = seg->body.chars + *seg_byte_offset;
4148
4149           bytes = g_utf8_next_char (start) - start;
4150           *seg_byte_offset += bytes;
4151           offset -= 1;
4152         }
4153
4154       g_assert (*seg_byte_offset < seg->byte_count);
4155
4156       *line_byte_offset += *seg_byte_offset;
4157     }
4158   else
4159     {
4160       g_assert (offset == 0);
4161       *seg_byte_offset = 0;
4162     }
4163 }
4164
4165 static gint
4166 node_compare (GtkTextBTreeNode *lhs,
4167               GtkTextBTreeNode *rhs)
4168 {
4169   GtkTextBTreeNode *iter;
4170   GtkTextBTreeNode *node;
4171   GtkTextBTreeNode *common_parent;
4172   GtkTextBTreeNode *parent_of_lower;
4173   GtkTextBTreeNode *parent_of_higher;
4174   gboolean lhs_is_lower;
4175   GtkTextBTreeNode *lower;
4176   GtkTextBTreeNode *higher;
4177
4178   /* This function assumes that lhs and rhs are not underneath each
4179    * other.
4180    */
4181
4182   if (lhs == rhs)
4183     return 0;
4184
4185   if (lhs->level < rhs->level)
4186     {
4187       lhs_is_lower = TRUE;
4188       lower = lhs;
4189       higher = rhs;
4190     }
4191   else
4192     {
4193       lhs_is_lower = FALSE;
4194       lower = rhs;
4195       higher = lhs;
4196     }
4197
4198   /* Algorithm: find common parent of lhs/rhs. Save the child nodes
4199    * of the common parent we used to reach the common parent; the
4200    * ordering of these child nodes in the child list is the ordering
4201    * of lhs and rhs.
4202    */
4203
4204   /* Get on the same level (may be on same level already) */
4205   node = lower;
4206   while (node->level < higher->level)
4207     node = node->parent;
4208
4209   g_assert (node->level == higher->level);
4210
4211   g_assert (node != higher); /* Happens if lower is underneath higher */
4212
4213   /* Go up until we have two children with a common parent.
4214    */
4215   parent_of_lower = node;
4216   parent_of_higher = higher;
4217
4218   while (parent_of_lower->parent != parent_of_higher->parent)
4219     {
4220       parent_of_lower = parent_of_lower->parent;
4221       parent_of_higher = parent_of_higher->parent;
4222     }
4223
4224   g_assert (parent_of_lower->parent == parent_of_higher->parent);
4225
4226   common_parent = parent_of_lower->parent;
4227
4228   g_assert (common_parent != NULL);
4229
4230   /* See which is first in the list of common_parent's children */
4231   iter = common_parent->children.node;
4232   while (iter != NULL)
4233     {
4234       if (iter == parent_of_higher)
4235         {
4236           /* higher is less than lower */
4237
4238           if (lhs_is_lower)
4239             return 1; /* lhs > rhs */
4240           else
4241             return -1;
4242         }
4243       else if (iter == parent_of_lower)
4244         {
4245           /* lower is less than higher */
4246
4247           if (lhs_is_lower)
4248             return -1; /* lhs < rhs */
4249           else
4250             return 1;
4251         }
4252
4253       iter = iter->next;
4254     }
4255
4256   g_assert_not_reached ();
4257   return 0;
4258 }
4259
4260 /* remember that tag == NULL means "any tag" */
4261 GtkTextLine*
4262 _gtk_text_line_next_could_contain_tag (GtkTextLine  *line,
4263                                        GtkTextBTree *tree,
4264                                        GtkTextTag   *tag)
4265 {
4266   GtkTextBTreeNode *node;
4267   GtkTextTagInfo *info;
4268   gboolean below_tag_root;
4269
4270   g_return_val_if_fail (line != NULL, NULL);
4271
4272   if (gtk_debug_flags & GTK_DEBUG_TEXT)
4273     _gtk_text_btree_check (tree);
4274
4275   if (tag == NULL)
4276     {
4277       /* Right now we can only offer linear-search if the user wants
4278        * to know about any tag toggle at all.
4279        */
4280       return _gtk_text_line_next_excluding_last (line);
4281     }
4282
4283   /* Our tag summaries only have node precision, not line
4284    * precision. This means that if any line under a node could contain a
4285    * tag, then any of the others could also contain a tag.
4286    * 
4287    * In the future we could have some mechanism to keep track of how
4288    * many toggles we've found under a node so far, since we have a
4289    * count of toggles under the node. But for now I'm going with KISS.
4290    */
4291
4292   /* return same-node line, if any. */
4293   if (line->next)
4294     return line->next;
4295
4296   info = gtk_text_btree_get_existing_tag_info (tree, tag);
4297   if (info == NULL)
4298     return NULL;
4299
4300   if (info->tag_root == NULL)
4301     return NULL;
4302
4303   if (info->tag_root == line->parent)
4304     return NULL; /* we were at the last line under the tag root */
4305
4306   /* We need to go up out of this node, and on to the next one with
4307      toggles for the target tag. If we're below the tag root, we need to
4308      find the next node below the tag root that has tag summaries. If
4309      we're not below the tag root, we need to see if the tag root is
4310      after us in the tree, and if so, return the first line underneath
4311      the tag root. */
4312
4313   node = line->parent;
4314   below_tag_root = FALSE;
4315   while (node != NULL)
4316     {
4317       if (node == info->tag_root)
4318         {
4319           below_tag_root = TRUE;
4320           break;
4321         }
4322
4323       node = node->parent;
4324     }
4325
4326   if (below_tag_root)
4327     {
4328       node = line->parent;
4329       while (node != info->tag_root)
4330         {
4331           if (node->next == NULL)
4332             node = node->parent;
4333           else
4334             {
4335               node = node->next;
4336
4337               if (gtk_text_btree_node_has_tag (node, tag))
4338                 goto found;
4339             }
4340         }
4341       return NULL;
4342     }
4343   else
4344     {
4345       gint ordering;
4346
4347       ordering = node_compare (line->parent, info->tag_root);
4348
4349       if (ordering < 0)
4350         {
4351           /* Tag root is ahead of us, so search there. */
4352           node = info->tag_root;
4353           goto found;
4354         }
4355       else
4356         {
4357           /* Tag root is after us, so no more lines that
4358            * could contain the tag.
4359            */
4360           return NULL;
4361         }
4362
4363       g_assert_not_reached ();
4364     }
4365
4366  found:
4367
4368   g_assert (node != NULL);
4369
4370   /* We have to find the first sub-node of this node that contains
4371    * the target tag.
4372    */
4373
4374   while (node->level > 0)
4375     {
4376       g_assert (node != NULL); /* If this fails, it likely means an
4377                                   incorrect tag summary led us on a
4378                                   wild goose chase down this branch of
4379                                   the tree. */
4380       node = node->children.node;
4381       while (node != NULL)
4382         {
4383           if (gtk_text_btree_node_has_tag (node, tag))
4384             break;
4385           node = node->next;
4386         }
4387     }
4388
4389   g_assert (node != NULL);
4390   g_assert (node->level == 0);
4391
4392   return node->children.line;
4393 }
4394
4395 static GtkTextLine*
4396 prev_line_under_node (GtkTextBTreeNode *node,
4397                       GtkTextLine      *line)
4398 {
4399   GtkTextLine *prev;
4400
4401   prev = node->children.line;
4402
4403   g_assert (prev);
4404
4405   if (prev != line)
4406     {
4407       while (prev->next != line)
4408         prev = prev->next;
4409
4410       return prev;
4411     }
4412
4413   return NULL;
4414 }
4415
4416 GtkTextLine*
4417 _gtk_text_line_previous_could_contain_tag (GtkTextLine  *line,
4418                                           GtkTextBTree *tree,
4419                                           GtkTextTag   *tag)
4420 {
4421   GtkTextBTreeNode *node;
4422   GtkTextBTreeNode *found_node = NULL;
4423   GtkTextTagInfo *info;
4424   gboolean below_tag_root;
4425   GtkTextLine *prev;
4426   GtkTextBTreeNode *line_ancestor;
4427   GtkTextBTreeNode *line_ancestor_parent;
4428
4429   /* See next_could_contain_tag () for more extensive comments
4430    * on what's going on here.
4431    */
4432
4433   g_return_val_if_fail (line != NULL, NULL);
4434
4435   if (gtk_debug_flags & GTK_DEBUG_TEXT)
4436     _gtk_text_btree_check (tree);
4437
4438   if (tag == NULL)
4439     {
4440       /* Right now we can only offer linear-search if the user wants
4441        * to know about any tag toggle at all.
4442        */
4443       return _gtk_text_line_previous (line);
4444     }
4445
4446   /* Return same-node line, if any. */
4447   prev = prev_line_under_node (line->parent, line);
4448   if (prev)
4449     return prev;
4450
4451   info = gtk_text_btree_get_existing_tag_info (tree, tag);
4452   if (info == NULL)
4453     return NULL;
4454
4455   if (info->tag_root == NULL)
4456     return NULL;
4457
4458   if (info->tag_root == line->parent)
4459     return NULL; /* we were at the first line under the tag root */
4460
4461   /* Are we below the tag root */
4462   node = line->parent;
4463   below_tag_root = FALSE;
4464   while (node != NULL)
4465     {
4466       if (node == info->tag_root)
4467         {
4468           below_tag_root = TRUE;
4469           break;
4470         }
4471
4472       node = node->parent;
4473     }
4474
4475   if (below_tag_root)
4476     {
4477       /* Look for a previous node under this tag root that has our
4478        * tag.
4479        */
4480
4481       /* this assertion holds because line->parent is not the
4482        * tag root, we are below the tag root, and the tag
4483        * root exists.
4484        */
4485       g_assert (line->parent->parent != NULL);
4486
4487       line_ancestor = line->parent;
4488       line_ancestor_parent = line->parent->parent;
4489
4490       node = line_ancestor_parent->children.node;
4491       while (node != line_ancestor || line_ancestor != info->tag_root)
4492         {
4493           GSList *child_nodes = NULL;
4494           GSList *tmp;
4495
4496           /* Create reverse-order list of nodes before
4497            * line_ancestor
4498            */
4499           while (node != line_ancestor && node != NULL)
4500             {
4501               child_nodes = g_slist_prepend (child_nodes, node);
4502
4503               node = node->next;
4504             }
4505
4506           /* Try to find a node with our tag on it in the list */
4507           tmp = child_nodes;
4508           while (tmp != NULL)
4509             {
4510               GtkTextBTreeNode *this_node = tmp->data;
4511
4512               g_assert (this_node != line_ancestor);
4513
4514               if (gtk_text_btree_node_has_tag (this_node, tag))
4515                 {
4516                   found_node = this_node;
4517                   g_slist_free (child_nodes);
4518                   goto found;
4519                 }
4520
4521               tmp = g_slist_next (tmp);
4522             }
4523
4524           g_slist_free (child_nodes);
4525
4526           /* Didn't find anything on this level; go up one level. */
4527           line_ancestor = line_ancestor_parent;
4528           line_ancestor_parent = line_ancestor->parent;
4529
4530           if (line_ancestor_parent != NULL)
4531             {
4532               node = line_ancestor_parent->children.node;
4533             }
4534         }
4535
4536       /* No dice. */
4537       return NULL;
4538     }
4539   else
4540     {
4541       gint ordering;
4542
4543       ordering = node_compare (line->parent, info->tag_root);
4544
4545       if (ordering < 0)
4546         {
4547           /* Tag root is ahead of us, so no more lines
4548            * with this tag.
4549            */
4550           return NULL;
4551         }
4552       else
4553         {
4554           /* Tag root is after us, so grab last tagged
4555            * line underneath the tag root.
4556            */
4557           found_node = info->tag_root;
4558           goto found;
4559         }
4560
4561       g_assert_not_reached ();
4562     }
4563
4564  found:
4565
4566   g_assert (found_node != NULL);
4567
4568   /* We have to find the last sub-node of this node that contains
4569    * the target tag.
4570    */
4571   node = found_node;
4572
4573   while (node->level > 0)
4574     {
4575       GSList *child_nodes = NULL;
4576       GSList *iter;
4577       g_assert (node != NULL); /* If this fails, it likely means an
4578                                   incorrect tag summary led us on a
4579                                   wild goose chase down this branch of
4580                                   the tree. */
4581
4582       node = node->children.node;
4583       while (node != NULL)
4584         {
4585           child_nodes = g_slist_prepend (child_nodes, node);
4586           node = node->next;
4587         }
4588
4589       node = NULL; /* detect failure to find a child node. */
4590
4591       iter = child_nodes;
4592       while (iter != NULL)
4593         {
4594           if (gtk_text_btree_node_has_tag (iter->data, tag))
4595             {
4596               /* recurse into this node. */
4597               node = iter->data;
4598               break;
4599             }
4600
4601           iter = g_slist_next (iter);
4602         }
4603
4604       g_slist_free (child_nodes);
4605
4606       g_assert (node != NULL);
4607     }
4608
4609   g_assert (node != NULL);
4610   g_assert (node->level == 0);
4611
4612   /* this assertion is correct, but slow. */
4613   /* g_assert (node_compare (node, line->parent) < 0); */
4614
4615   /* Return last line in this node. */
4616
4617   prev = node->children.line;
4618   while (prev->next)
4619     prev = prev->next;
4620
4621   return prev;
4622 }
4623
4624 /*
4625  * Non-public function implementations
4626  */
4627
4628 static void
4629 summary_list_destroy (Summary *summary)
4630 {
4631   Summary *next;
4632   while (summary != NULL)
4633     {
4634       next = summary->next;
4635       summary_destroy (summary);
4636       summary = next;
4637     }
4638 }
4639
4640 static GtkTextLine*
4641 get_last_line (GtkTextBTree *tree)
4642 {
4643   if (tree->last_line_stamp != tree->chars_changed_stamp)
4644     {
4645       gint n_lines;
4646       GtkTextLine *line;
4647       gint real_line;
4648
4649       n_lines = _gtk_text_btree_line_count (tree);
4650
4651       g_assert (n_lines >= 1); /* num_lines doesn't return bogus last line. */
4652
4653       line = _gtk_text_btree_get_line (tree, n_lines, &real_line);
4654
4655       tree->last_line_stamp = tree->chars_changed_stamp;
4656       tree->last_line = line;
4657     }
4658
4659   return tree->last_line;
4660 }
4661
4662 /*
4663  * Lines
4664  */
4665
4666 static GtkTextLine*
4667 gtk_text_line_new (void)
4668 {
4669   GtkTextLine *line;
4670
4671   line = g_new0(GtkTextLine, 1);
4672   line->dir_strong = PANGO_DIRECTION_NEUTRAL;
4673   line->dir_propagated_forward = PANGO_DIRECTION_NEUTRAL;
4674   line->dir_propagated_back = PANGO_DIRECTION_NEUTRAL;
4675
4676   return line;
4677 }
4678
4679 static void
4680 gtk_text_line_destroy (GtkTextBTree *tree, GtkTextLine *line)
4681 {
4682   GtkTextLineData *ld;
4683   GtkTextLineData *next;
4684
4685   g_return_if_fail (line != NULL);
4686
4687   ld = line->views;
4688   while (ld != NULL)
4689     {
4690       BTreeView *view;
4691
4692       view = gtk_text_btree_get_view (tree, ld->view_id);
4693
4694       g_assert (view != NULL);
4695
4696       next = ld->next;
4697       gtk_text_layout_free_line_data (view->layout, line, ld);
4698
4699       ld = next;
4700     }
4701
4702   g_free (line);
4703 }
4704
4705 static void
4706 gtk_text_line_set_parent (GtkTextLine *line,
4707                           GtkTextBTreeNode *node)
4708 {
4709   if (line->parent == node)
4710     return;
4711   line->parent = node;
4712   gtk_text_btree_node_invalidate_upward (node, NULL);
4713 }
4714
4715 static void
4716 cleanup_line (GtkTextLine *line)
4717 {
4718   GtkTextLineSegment *seg, **prev_p;
4719   gboolean changed;
4720
4721   /*
4722    * Make a pass over all of the segments in the line, giving each
4723    * a chance to clean itself up.  This could potentially change
4724    * the structure of the line, e.g. by merging two segments
4725    * together or having two segments cancel themselves;  if so,
4726    * then repeat the whole process again, since the first structure
4727    * change might make other structure changes possible.  Repeat
4728    * until eventually there are no changes.
4729    */
4730
4731   changed = TRUE;
4732   while (changed)
4733     {
4734       changed = FALSE;
4735       for (prev_p = &line->segments, seg = *prev_p;
4736            seg != NULL;
4737            prev_p = &(*prev_p)->next, seg = *prev_p)
4738         {
4739           if (seg->type->cleanupFunc != NULL)
4740             {
4741               *prev_p = (*seg->type->cleanupFunc)(seg, line);
4742               if (seg != *prev_p)
4743                 changed = TRUE;
4744             }
4745         }
4746     }
4747 }
4748
4749 /*
4750  * Nodes
4751  */
4752
4753 static NodeData*
4754 node_data_new (gpointer view_id)
4755 {
4756   NodeData *nd;
4757   
4758   nd = g_new (NodeData, 1);
4759
4760   nd->view_id = view_id;
4761   nd->next = NULL;
4762   nd->width = 0;
4763   nd->height = 0;
4764   nd->valid = FALSE;
4765
4766   return nd;
4767 }
4768
4769 static void
4770 node_data_destroy (NodeData *nd)
4771 {
4772   g_free (nd);
4773 }
4774
4775 static void
4776 node_data_list_destroy (NodeData *nd)
4777 {
4778   NodeData *iter;
4779   NodeData *next;
4780
4781   iter = nd;
4782   while (iter != NULL)
4783     {
4784       next = iter->next;
4785       node_data_destroy (iter);
4786       iter = next;
4787     }
4788 }
4789
4790 static NodeData*
4791 node_data_find (NodeData *nd, gpointer view_id)
4792 {
4793   while (nd != NULL)
4794     {
4795       if (nd->view_id == view_id)
4796         break;
4797       nd = nd->next;
4798     }
4799   return nd;
4800 }
4801
4802 static void
4803 summary_destroy (Summary *summary)
4804 {
4805   /* Fill with error-triggering garbage */
4806   summary->info = (void*)0x1;
4807   summary->toggle_count = 567;
4808   summary->next = (void*)0x1;
4809   g_free (summary);
4810 }
4811
4812 static GtkTextBTreeNode*
4813 gtk_text_btree_node_new (void)
4814 {
4815   GtkTextBTreeNode *node;
4816
4817   node = g_new (GtkTextBTreeNode, 1);
4818
4819   node->node_data = NULL;
4820
4821   return node;
4822 }
4823
4824 static void
4825 gtk_text_btree_node_adjust_toggle_count (GtkTextBTreeNode  *node,
4826                                          GtkTextTagInfo  *info,
4827                                          gint adjust)
4828 {
4829   Summary *summary;
4830
4831   summary = node->summary;
4832   while (summary != NULL)
4833     {
4834       if (summary->info == info)
4835         {
4836           summary->toggle_count += adjust;
4837           break;
4838         }
4839
4840       summary = summary->next;
4841     }
4842
4843   if (summary == NULL)
4844     {
4845       /* didn't find a summary for our tag. */
4846       g_return_if_fail (adjust > 0);
4847       summary = g_new (Summary, 1);
4848       summary->info = info;
4849       summary->toggle_count = adjust;
4850       summary->next = node->summary;
4851       node->summary = summary;
4852     }
4853 }
4854
4855 /* Note that the tag root and above do not have summaries
4856    for the tag; only nodes below the tag root have
4857    the summaries. */
4858 static gboolean
4859 gtk_text_btree_node_has_tag (GtkTextBTreeNode *node, GtkTextTag *tag)
4860 {
4861   Summary *summary;
4862
4863   summary = node->summary;
4864   while (summary != NULL)
4865     {
4866       if (tag == NULL ||
4867           summary->info->tag == tag)
4868         return TRUE;
4869
4870       summary = summary->next;
4871     }
4872
4873   return FALSE;
4874 }
4875
4876 /* Add node and all children to the damage region. */
4877 static void
4878 gtk_text_btree_node_invalidate_downward (GtkTextBTreeNode *node)
4879 {
4880   NodeData *nd;
4881
4882   nd = node->node_data;
4883   while (nd != NULL)
4884     {
4885       nd->valid = FALSE;
4886       nd = nd->next;
4887     }
4888
4889   if (node->level == 0)
4890     {
4891       GtkTextLine *line;
4892
4893       line = node->children.line;
4894       while (line != NULL)
4895         {
4896           GtkTextLineData *ld;
4897
4898           ld = line->views;
4899           while (ld != NULL)
4900             {
4901               ld->valid = FALSE;
4902               ld = ld->next;
4903             }
4904
4905           line = line->next;
4906         }
4907     }
4908   else
4909     {
4910       GtkTextBTreeNode *child;
4911
4912       child = node->children.node;
4913
4914       while (child != NULL)
4915         {
4916           gtk_text_btree_node_invalidate_downward (child);
4917
4918           child = child->next;
4919         }
4920     }
4921 }
4922
4923 static void
4924 gtk_text_btree_node_invalidate_upward (GtkTextBTreeNode *node, gpointer view_id)
4925 {
4926   GtkTextBTreeNode *iter;
4927
4928   iter = node;
4929   while (iter != NULL)
4930     {
4931       NodeData *nd;
4932
4933       if (view_id)
4934         {
4935           nd = node_data_find (iter->node_data, view_id);
4936
4937           if (nd == NULL || !nd->valid)
4938             break; /* Once a node is invalid, we know its parents are as well. */
4939
4940           nd->valid = FALSE;
4941         }
4942       else
4943         {
4944           gboolean should_continue = FALSE;
4945
4946           nd = iter->node_data;
4947           while (nd != NULL)
4948             {
4949               if (nd->valid)
4950                 {
4951                   should_continue = TRUE;
4952                   nd->valid = FALSE;
4953                 }
4954
4955               nd = nd->next;
4956             }
4957
4958           if (!should_continue)
4959             break; /* This node was totally invalidated, so are its
4960                       parents */
4961         }
4962
4963       iter = iter->parent;
4964     }
4965 }
4966
4967
4968 /**
4969  * _gtk_text_btree_is_valid:
4970  * @tree: a #GtkTextBTree
4971  * @view_id: ID for the view
4972  *
4973  * Check to see if the entire #GtkTextBTree is valid or not for
4974  * the given view.
4975  *
4976  * Return value: %TRUE if the entire #GtkTextBTree is valid
4977  **/
4978 gboolean
4979 _gtk_text_btree_is_valid (GtkTextBTree *tree,
4980                          gpointer      view_id)
4981 {
4982   NodeData *nd;
4983   g_return_val_if_fail (tree != NULL, FALSE);
4984
4985   nd = node_data_find (tree->root_node->node_data, view_id);
4986   return (nd && nd->valid);
4987 }
4988
4989 typedef struct _ValidateState ValidateState;
4990
4991 struct _ValidateState
4992 {
4993   gint remaining_pixels;
4994   gboolean in_validation;
4995   gint y;
4996   gint old_height;
4997   gint new_height;
4998 };
4999
5000 static void
5001 gtk_text_btree_node_validate (BTreeView         *view,
5002                               GtkTextBTreeNode  *node,
5003                               gpointer           view_id,
5004                               ValidateState     *state)
5005 {
5006   gint node_valid = TRUE;
5007   gint node_width = 0;
5008   gint node_height = 0;
5009
5010   NodeData *nd = gtk_text_btree_node_ensure_data (node, view_id);
5011   g_return_if_fail (!nd->valid);
5012
5013   if (node->level == 0)
5014     {
5015       GtkTextLine *line = node->children.line;
5016       GtkTextLineData *ld;
5017
5018       /* Iterate over leading valid lines */
5019       while (line != NULL)
5020         {
5021           ld = _gtk_text_line_get_data (line, view_id);
5022
5023           if (!ld || !ld->valid)
5024             break;
5025           else if (state->in_validation)
5026             {
5027               state->in_validation = FALSE;
5028               return;
5029             }
5030           else
5031             {
5032               state->y += ld->height;
5033               node_width = MAX (ld->width, node_width);
5034               node_height += ld->height;
5035             }
5036
5037           line = line->next;
5038         }
5039
5040       state->in_validation = TRUE;
5041
5042       /* Iterate over invalid lines */
5043       while (line != NULL)
5044         {
5045           ld = _gtk_text_line_get_data (line, view_id);
5046
5047           if (ld && ld->valid)
5048             break;
5049           else
5050             {
5051               if (ld)
5052                 state->old_height += ld->height;
5053               ld = gtk_text_layout_wrap (view->layout, line, ld);
5054               state->new_height += ld->height;
5055
5056               node_width = MAX (ld->width, node_width);
5057               node_height += ld->height;
5058
5059               state->remaining_pixels -= ld->height;
5060               if (state->remaining_pixels <= 0)
5061                 {
5062                   line = line->next;
5063                   break;
5064                 }
5065             }
5066
5067           line = line->next;
5068         }
5069
5070       /* Iterate over the remaining lines */
5071       while (line != NULL)
5072         {
5073           ld = _gtk_text_line_get_data (line, view_id);
5074           state->in_validation = FALSE;
5075
5076           if (!ld || !ld->valid)
5077             node_valid = FALSE;
5078
5079           if (ld)
5080             {
5081               node_width = MAX (ld->width, node_width);
5082               node_height += ld->height;
5083             }
5084
5085           line = line->next;
5086         }
5087     }
5088   else
5089     {
5090       GtkTextBTreeNode *child;
5091       NodeData *child_nd;
5092
5093       child = node->children.node;
5094
5095       /* Iterate over leading valid nodes */
5096       while (child)
5097         {
5098           child_nd = gtk_text_btree_node_ensure_data (child, view_id);
5099
5100           if (!child_nd->valid)
5101             break;
5102           else if (state->in_validation)
5103             {
5104               state->in_validation = FALSE;
5105               return;
5106             }
5107           else
5108             {
5109               state->y += child_nd->height;
5110               node_width = MAX (node_width, child_nd->width);
5111               node_height += child_nd->height;
5112             }
5113
5114           child = child->next;
5115         }
5116
5117       /* Iterate over invalid nodes */
5118       while (child)
5119         {
5120           child_nd = gtk_text_btree_node_ensure_data (child, view_id);
5121
5122           if (child_nd->valid)
5123             break;
5124           else
5125             {
5126               gtk_text_btree_node_validate (view, child, view_id, state);
5127
5128               if (!child_nd->valid)
5129                 node_valid = FALSE;
5130               node_width = MAX (node_width, child_nd->width);
5131               node_height += child_nd->height;
5132
5133               if (!state->in_validation || state->remaining_pixels <= 0)
5134                 {
5135                   child = child->next;
5136                   break;
5137                 }
5138             }
5139
5140           child = child->next;
5141         }
5142
5143       /* Iterate over the remaining lines */
5144       while (child)
5145         {
5146           child_nd = gtk_text_btree_node_ensure_data (child, view_id);
5147           state->in_validation = FALSE;
5148
5149           if (!child_nd->valid)
5150             node_valid = FALSE;
5151
5152           node_width = MAX (child_nd->width, node_width);
5153           node_height += child_nd->height;
5154
5155           child = child->next;
5156         }
5157     }
5158
5159   nd->width = node_width;
5160   nd->height = node_height;
5161   nd->valid = node_valid;
5162 }
5163
5164 /**
5165  * _gtk_text_btree_validate:
5166  * @tree: a #GtkTextBTree
5167  * @view_id: view id
5168  * @max_pixels: the maximum number of pixels to validate. (No more
5169  *              than one paragraph beyond this limit will be validated)
5170  * @y: location to store starting y coordinate of validated region
5171  * @old_height: location to store old height of validated region
5172  * @new_height: location to store new height of validated region
5173  *
5174  * Validate a single contiguous invalid region of a #GtkTextBTree for
5175  * a given view.
5176  *
5177  * Return value: %TRUE if a region has been validated, %FALSE if the
5178  * entire tree was already valid.
5179  **/
5180 gboolean
5181 _gtk_text_btree_validate (GtkTextBTree *tree,
5182                          gpointer      view_id,
5183                          gint          max_pixels,
5184                          gint         *y,
5185                          gint         *old_height,
5186                          gint         *new_height)
5187 {
5188   BTreeView *view;
5189
5190   g_return_val_if_fail (tree != NULL, FALSE);
5191
5192   view = gtk_text_btree_get_view (tree, view_id);
5193   g_return_val_if_fail (view != NULL, FALSE);
5194
5195   if (!_gtk_text_btree_is_valid (tree, view_id))
5196     {
5197       ValidateState state;
5198
5199       state.remaining_pixels = max_pixels;
5200       state.in_validation = FALSE;
5201       state.y = 0;
5202       state.old_height = 0;
5203       state.new_height = 0;
5204
5205       gtk_text_btree_node_validate (view,
5206                                     tree->root_node,
5207                                     view_id, &state);
5208
5209       if (y)
5210         *y = state.y;
5211       if (old_height)
5212         *old_height = state.old_height;
5213       if (new_height)
5214         *new_height = state.new_height;
5215
5216       if (gtk_debug_flags & GTK_DEBUG_TEXT)
5217         _gtk_text_btree_check (tree);
5218
5219       return TRUE;
5220     }
5221   else
5222     return FALSE;
5223 }
5224
5225 static void
5226 gtk_text_btree_node_compute_view_aggregates (GtkTextBTreeNode *node,
5227                                              gpointer          view_id,
5228                                              gint             *width_out,
5229                                              gint             *height_out,
5230                                              gboolean         *valid_out)
5231 {
5232   gint width = 0;
5233   gint height = 0;
5234   gboolean valid = TRUE;
5235
5236   if (node->level == 0)
5237     {
5238       GtkTextLine *line = node->children.line;
5239
5240       while (line != NULL)
5241         {
5242           GtkTextLineData *ld = _gtk_text_line_get_data (line, view_id);
5243
5244           if (!ld || !ld->valid)
5245             valid = FALSE;
5246
5247           if (ld)
5248             {
5249               width = MAX (ld->width, width);
5250               height += ld->height;
5251             }
5252
5253           line = line->next;
5254         }
5255     }
5256   else
5257     {
5258       GtkTextBTreeNode *child = node->children.node;
5259
5260       while (child)
5261         {
5262           NodeData *child_nd = node_data_find (child->node_data, view_id);
5263
5264           if (!child_nd || !child_nd->valid)
5265             valid = FALSE;
5266
5267           if (child_nd)
5268             {
5269               width = MAX (child_nd->width, width);
5270               height += child_nd->height;
5271             }
5272
5273           child = child->next;
5274         }
5275     }
5276
5277   *width_out = width;
5278   *height_out = height;
5279   *valid_out = valid;
5280 }
5281
5282
5283 /* Recompute the validity and size of the view data for a given
5284  * view at this node from the immediate children of the node
5285  */
5286 static NodeData *
5287 gtk_text_btree_node_check_valid (GtkTextBTreeNode *node,
5288                                  gpointer          view_id)
5289 {
5290   NodeData *nd = gtk_text_btree_node_ensure_data (node, view_id);
5291   gboolean valid;
5292   gint width;
5293   gint height;
5294
5295   gtk_text_btree_node_compute_view_aggregates (node, view_id,
5296                                                &width, &height, &valid);
5297   nd->width = width;
5298   nd->height = height;
5299   nd->valid = valid;
5300
5301   return nd;
5302 }
5303
5304 static void
5305 gtk_text_btree_node_check_valid_upward (GtkTextBTreeNode *node,
5306                                         gpointer          view_id)
5307 {
5308   while (node)
5309     {
5310       gtk_text_btree_node_check_valid (node, view_id);
5311       node = node->parent;
5312     }
5313 }
5314
5315 static NodeData *
5316 gtk_text_btree_node_check_valid_downward (GtkTextBTreeNode *node,
5317                                           gpointer          view_id)
5318 {
5319   if (node->level == 0)
5320     {
5321       return gtk_text_btree_node_check_valid (node, view_id);
5322     }
5323   else
5324     {
5325       GtkTextBTreeNode *child = node->children.node;
5326
5327       NodeData *nd = gtk_text_btree_node_ensure_data (node, view_id);
5328
5329       nd->valid = TRUE;
5330       nd->width = 0;
5331       nd->height = 0;
5332
5333       while (child)
5334         {
5335           NodeData *child_nd = gtk_text_btree_node_check_valid_downward (child, view_id);
5336
5337           if (!child_nd->valid)
5338             nd->valid = FALSE;
5339           nd->width = MAX (child_nd->width, nd->width);
5340           nd->height += child_nd->height;
5341
5342           child = child->next;
5343         }
5344       return nd;
5345     }
5346 }
5347
5348
5349
5350 /**
5351  * _gtk_text_btree_validate_line:
5352  * @tree: a #GtkTextBTree
5353  * @line: line to validate
5354  * @view_id: view ID for the view to validate
5355  *
5356  * Revalidate a single line of the btree for the given view, propagate
5357  * results up through the entire tree.
5358  **/
5359 void
5360 _gtk_text_btree_validate_line (GtkTextBTree     *tree,
5361                                GtkTextLine      *line,
5362                                gpointer          view_id)
5363 {
5364   GtkTextLineData *ld;
5365   BTreeView *view;
5366
5367   g_return_if_fail (tree != NULL);
5368   g_return_if_fail (line != NULL);
5369
5370   view = gtk_text_btree_get_view (tree, view_id);
5371   g_return_if_fail (view != NULL);
5372   
5373   ld = _gtk_text_line_get_data (line, view_id);
5374   if (!ld || !ld->valid)
5375     {
5376       ld = gtk_text_layout_wrap (view->layout, line, ld);
5377       
5378       gtk_text_btree_node_check_valid_upward (line->parent, view_id);
5379     }
5380 }
5381
5382 static void
5383 gtk_text_btree_node_remove_view (BTreeView *view, GtkTextBTreeNode *node, gpointer view_id)
5384 {
5385   if (node->level == 0)
5386     {
5387       GtkTextLine *line;
5388
5389       line = node->children.line;
5390       while (line != NULL)
5391         {
5392           GtkTextLineData *ld;
5393
5394           ld = _gtk_text_line_remove_data (line, view_id);
5395
5396           if (ld)
5397             gtk_text_layout_free_line_data (view->layout, line, ld);
5398
5399           line = line->next;
5400         }
5401     }
5402   else
5403     {
5404       GtkTextBTreeNode *child;
5405
5406       child = node->children.node;
5407
5408       while (child != NULL)
5409         {
5410           /* recurse */
5411           gtk_text_btree_node_remove_view (view, child, view_id);
5412
5413           child = child->next;
5414         }
5415     }
5416
5417   gtk_text_btree_node_remove_data (node, view_id);
5418 }
5419
5420 static void
5421 gtk_text_btree_node_destroy (GtkTextBTree *tree, GtkTextBTreeNode *node)
5422 {
5423   if (node->level == 0)
5424     {
5425       GtkTextLine *line;
5426       GtkTextLineSegment *seg;
5427
5428       while (node->children.line != NULL)
5429         {
5430           line = node->children.line;
5431           node->children.line = line->next;
5432           while (line->segments != NULL)
5433             {
5434               seg = line->segments;
5435               line->segments = seg->next;
5436
5437               (*seg->type->deleteFunc) (seg, line, TRUE);
5438             }
5439           gtk_text_line_destroy (tree, line);
5440         }
5441     }
5442   else
5443     {
5444       GtkTextBTreeNode *childPtr;
5445
5446       while (node->children.node != NULL)
5447         {
5448           childPtr = node->children.node;
5449           node->children.node = childPtr->next;
5450           gtk_text_btree_node_destroy (tree, childPtr);
5451         }
5452     }
5453
5454   gtk_text_btree_node_free_empty (tree, node);
5455 }
5456
5457 static void
5458 gtk_text_btree_node_free_empty (GtkTextBTree *tree,
5459                                 GtkTextBTreeNode *node)
5460 {
5461   g_return_if_fail ((node->level > 0 && node->children.node == NULL) ||
5462                     (node->level == 0 && node->children.line == NULL));
5463
5464   summary_list_destroy (node->summary);
5465   node_data_list_destroy (node->node_data);
5466   g_free (node);
5467 }
5468
5469 static NodeData*
5470 gtk_text_btree_node_ensure_data (GtkTextBTreeNode *node, gpointer view_id)
5471 {
5472   NodeData *nd;
5473
5474   nd = node->node_data;
5475   while (nd != NULL)
5476     {
5477       if (nd->view_id == view_id)
5478         break;
5479
5480       nd = nd->next;
5481     }
5482
5483   if (nd == NULL)
5484     {
5485       nd = node_data_new (view_id);
5486       
5487       if (node->node_data)
5488         nd->next = node->node_data;
5489       
5490       node->node_data = nd;
5491     }
5492
5493   return nd;
5494 }
5495
5496 static void
5497 gtk_text_btree_node_remove_data (GtkTextBTreeNode *node, gpointer view_id)
5498 {
5499   NodeData *nd;
5500   NodeData *prev;
5501
5502   prev = NULL;
5503   nd = node->node_data;
5504   while (nd != NULL)
5505     {
5506       if (nd->view_id == view_id)
5507         break;
5508
5509       prev = nd;
5510       nd = nd->next;
5511     }
5512
5513   if (nd == NULL)
5514     return;
5515
5516   if (prev != NULL)
5517     prev->next = nd->next;
5518
5519   if (node->node_data == nd)
5520     node->node_data = nd->next;
5521
5522   nd->next = NULL;
5523
5524   node_data_destroy (nd);
5525 }
5526
5527 static void
5528 gtk_text_btree_node_get_size (GtkTextBTreeNode *node, gpointer view_id,
5529                               gint *width, gint *height)
5530 {
5531   NodeData *nd;
5532
5533   g_return_if_fail (width != NULL);
5534   g_return_if_fail (height != NULL);
5535
5536   nd = gtk_text_btree_node_ensure_data (node, view_id);
5537
5538   if (width)
5539     *width = nd->width;
5540   if (height)
5541     *height = nd->height;
5542 }
5543
5544 /* Find the closest common ancestor of the two nodes. FIXME: The interface
5545  * here isn't quite right, since for a lot of operations we want to
5546  * know which children of the common parent correspond to the two nodes
5547  * (e.g., when computing the order of two iters)
5548  */
5549 static GtkTextBTreeNode *
5550 gtk_text_btree_node_common_parent (GtkTextBTreeNode *node1,
5551                                    GtkTextBTreeNode *node2)
5552 {
5553   while (node1->level < node2->level)
5554     node1 = node1->parent;
5555   while (node2->level < node1->level)
5556     node2 = node2->parent;
5557   while (node1 != node2)
5558     {
5559       node1 = node1->parent;
5560       node2 = node2->parent;
5561     }
5562
5563   return node1;
5564 }
5565
5566 /*
5567  * BTree
5568  */
5569
5570 static BTreeView*
5571 gtk_text_btree_get_view (GtkTextBTree *tree, gpointer view_id)
5572 {
5573   BTreeView *view;
5574
5575   view = tree->views;
5576   while (view != NULL)
5577     {
5578       if (view->view_id == view_id)
5579         break;
5580       view = view->next;
5581     }
5582
5583   return view;
5584 }
5585
5586 static void
5587 get_tree_bounds (GtkTextBTree *tree,
5588                  GtkTextIter *start,
5589                  GtkTextIter *end)
5590 {
5591   _gtk_text_btree_get_iter_at_line_char (tree, start, 0, 0);
5592   _gtk_text_btree_get_end_iter (tree, end);
5593 }
5594
5595 static void
5596 tag_changed_cb (GtkTextTagTable *table,
5597                 GtkTextTag      *tag,
5598                 gboolean         size_changed,
5599                 GtkTextBTree    *tree)
5600 {
5601   if (size_changed)
5602     {
5603       /* We need to queue a relayout on all regions that are tagged with
5604        * this tag.
5605        */
5606
5607       GtkTextIter start;
5608       GtkTextIter end;
5609
5610       if (_gtk_text_btree_get_iter_at_first_toggle (tree, &start, tag))
5611         {
5612           /* Must be a last toggle if there was a first one. */
5613           _gtk_text_btree_get_iter_at_last_toggle (tree, &end, tag);
5614           DV (g_print ("invalidating due to tag change (%s)\n", G_STRLOC));
5615           _gtk_text_btree_invalidate_region (tree,
5616                                             &start, &end);
5617
5618         }
5619     }
5620   else
5621     {
5622       /* We only need to queue a redraw, not a relayout */
5623       BTreeView *view;
5624
5625       view = tree->views;
5626
5627       while (view != NULL)
5628         {
5629           gint width, height;
5630
5631           _gtk_text_btree_get_view_size (tree, view->view_id, &width, &height);
5632           gtk_text_layout_changed (view->layout, 0, height, height);
5633
5634           view = view->next;
5635         }
5636     }
5637 }
5638
5639 void
5640 _gtk_text_btree_notify_will_remove_tag (GtkTextBTree    *tree,
5641                                         GtkTextTag      *tag)
5642 {
5643   /* Remove the tag from the tree */
5644
5645   GtkTextIter start;
5646   GtkTextIter end;
5647
5648   get_tree_bounds (tree, &start, &end);
5649
5650   _gtk_text_btree_tag (&start, &end, tag, FALSE);
5651   gtk_text_btree_remove_tag_info (tree, tag);
5652 }
5653
5654
5655 /* Rebalance the out-of-whack node "node" */
5656 static void
5657 gtk_text_btree_rebalance (GtkTextBTree *tree,
5658                           GtkTextBTreeNode *node)
5659 {
5660   /*
5661    * Loop over the entire ancestral chain of the GtkTextBTreeNode, working
5662    * up through the tree one GtkTextBTreeNode at a time until the root
5663    * GtkTextBTreeNode has been processed.
5664    */
5665
5666   while (node != NULL)
5667     {
5668       GtkTextBTreeNode *new_node, *child;
5669       GtkTextLine *line;
5670       int i;
5671
5672       /*
5673        * Check to see if the GtkTextBTreeNode has too many children.  If it does,
5674        * then split off all but the first MIN_CHILDREN into a separate
5675        * GtkTextBTreeNode following the original one.  Then repeat until the
5676        * GtkTextBTreeNode has a decent size.
5677        */
5678
5679       if (node->num_children > MAX_CHILDREN)
5680         {
5681           while (1)
5682             {
5683               /*
5684                * If the GtkTextBTreeNode being split is the root
5685                * GtkTextBTreeNode, then make a new root GtkTextBTreeNode above
5686                * it first.
5687                */
5688
5689               if (node->parent == NULL)
5690                 {
5691                   new_node = gtk_text_btree_node_new ();
5692                   new_node->parent = NULL;
5693                   new_node->next = NULL;
5694                   new_node->summary = NULL;
5695                   new_node->level = node->level + 1;
5696                   new_node->children.node = node;
5697                   recompute_node_counts (tree, new_node);
5698                   tree->root_node = new_node;
5699                 }
5700               new_node = gtk_text_btree_node_new ();
5701               new_node->parent = node->parent;
5702               new_node->next = node->next;
5703               node->next = new_node;
5704               new_node->summary = NULL;
5705               new_node->level = node->level;
5706               new_node->num_children = node->num_children - MIN_CHILDREN;
5707               if (node->level == 0)
5708                 {
5709                   for (i = MIN_CHILDREN-1,
5710                          line = node->children.line;
5711                        i > 0; i--, line = line->next)
5712                     {
5713                       /* Empty loop body. */
5714                     }
5715                   new_node->children.line = line->next;
5716                   line->next = NULL;
5717                 }
5718               else
5719                 {
5720                   for (i = MIN_CHILDREN-1,
5721                          child = node->children.node;
5722                        i > 0; i--, child = child->next)
5723                     {
5724                       /* Empty loop body. */
5725                     }
5726                   new_node->children.node = child->next;
5727                   child->next = NULL;
5728                 }
5729               recompute_node_counts (tree, node);
5730               node->parent->num_children++;
5731               node = new_node;
5732               if (node->num_children <= MAX_CHILDREN)
5733                 {
5734                   recompute_node_counts (tree, node);
5735                   break;
5736                 }
5737             }
5738         }
5739
5740       while (node->num_children < MIN_CHILDREN)
5741         {
5742           GtkTextBTreeNode *other;
5743           GtkTextBTreeNode *halfwaynode = NULL; /* Initialization needed only */
5744           GtkTextLine *halfwayline = NULL; /* to prevent cc warnings. */
5745           int total_children, first_children, i;
5746
5747           /*
5748            * Too few children for this GtkTextBTreeNode.  If this is the root then,
5749            * it's OK for it to have less than MIN_CHILDREN children
5750            * as long as it's got at least two.  If it has only one
5751            * (and isn't at level 0), then chop the root GtkTextBTreeNode out of
5752            * the tree and use its child as the new root.
5753            */
5754
5755           if (node->parent == NULL)
5756             {
5757               if ((node->num_children == 1) && (node->level > 0))
5758                 {
5759                   tree->root_node = node->children.node;
5760                   tree->root_node->parent = NULL;
5761
5762                   node->children.node = NULL;
5763                   gtk_text_btree_node_free_empty (tree, node);
5764                 }
5765               return;
5766             }
5767
5768           /*
5769            * Not the root.  Make sure that there are siblings to
5770            * balance with.
5771            */
5772
5773           if (node->parent->num_children < 2)
5774             {
5775               gtk_text_btree_rebalance (tree, node->parent);
5776               continue;
5777             }
5778
5779           /*
5780            * Find a sibling neighbor to borrow from, and arrange for
5781            * node to be the earlier of the pair.
5782            */
5783
5784           if (node->next == NULL)
5785             {
5786               for (other = node->parent->children.node;
5787                    other->next != node;
5788                    other = other->next)
5789                 {
5790                   /* Empty loop body. */
5791                 }
5792               node = other;
5793             }
5794           other = node->next;
5795
5796           /*
5797            * We're going to either merge the two siblings together
5798            * into one GtkTextBTreeNode or redivide the children among them to
5799            * balance their loads.  As preparation, join their two
5800            * child lists into a single list and remember the half-way
5801            * point in the list.
5802            */
5803
5804           total_children = node->num_children + other->num_children;
5805           first_children = total_children/2;
5806           if (node->children.node == NULL)
5807             {
5808               node->children = other->children;
5809               other->children.node = NULL;
5810               other->children.line = NULL;
5811             }
5812           if (node->level == 0)
5813             {
5814               GtkTextLine *line;
5815
5816               for (line = node->children.line, i = 1;
5817                    line->next != NULL;
5818                    line = line->next, i++)
5819                 {
5820                   if (i == first_children)
5821                     {
5822                       halfwayline = line;
5823                     }
5824                 }
5825               line->next = other->children.line;
5826               while (i <= first_children)
5827                 {
5828                   halfwayline = line;
5829                   line = line->next;
5830                   i++;
5831                 }
5832             }
5833           else
5834             {
5835               GtkTextBTreeNode *child;
5836
5837               for (child = node->children.node, i = 1;
5838                    child->next != NULL;
5839                    child = child->next, i++)
5840                 {
5841                   if (i <= first_children)
5842                     {
5843                       if (i == first_children)
5844                         {
5845                           halfwaynode = child;
5846                         }
5847                     }
5848                 }
5849               child->next = other->children.node;
5850               while (i <= first_children)
5851                 {
5852                   halfwaynode = child;
5853                   child = child->next;
5854                   i++;
5855                 }
5856             }
5857
5858           /*
5859            * If the two siblings can simply be merged together, do it.
5860            */
5861
5862           if (total_children <= MAX_CHILDREN)
5863             {
5864               recompute_node_counts (tree, node);
5865               node->next = other->next;
5866               node->parent->num_children--;
5867
5868               other->children.node = NULL;
5869               other->children.line = NULL;
5870               gtk_text_btree_node_free_empty (tree, other);
5871               continue;
5872             }
5873
5874           /*
5875            * The siblings can't be merged, so just divide their
5876            * children evenly between them.
5877            */
5878
5879           if (node->level == 0)
5880             {
5881               other->children.line = halfwayline->next;
5882               halfwayline->next = NULL;
5883             }
5884           else
5885             {
5886               other->children.node = halfwaynode->next;
5887               halfwaynode->next = NULL;
5888             }
5889
5890           recompute_node_counts (tree, node);
5891           recompute_node_counts (tree, other);
5892         }
5893
5894       node = node->parent;
5895     }
5896 }
5897
5898 static void
5899 post_insert_fixup (GtkTextBTree *tree,
5900                    GtkTextLine *line,
5901                    gint line_count_delta,
5902                    gint char_count_delta)
5903
5904 {
5905   GtkTextBTreeNode *node;
5906
5907   /*
5908    * Increment the line counts in all the parent GtkTextBTreeNodes of the insertion
5909    * point, then rebalance the tree if necessary.
5910    */
5911
5912   for (node = line->parent ; node != NULL;
5913        node = node->parent)
5914     {
5915       node->num_lines += line_count_delta;
5916       node->num_chars += char_count_delta;
5917     }
5918   node = line->parent;
5919   node->num_children += line_count_delta;
5920
5921   if (node->num_children > MAX_CHILDREN)
5922     {
5923       gtk_text_btree_rebalance (tree, node);
5924     }
5925
5926   if (gtk_debug_flags & GTK_DEBUG_TEXT)
5927     _gtk_text_btree_check (tree);
5928 }
5929
5930 static GtkTextTagInfo*
5931 gtk_text_btree_get_existing_tag_info (GtkTextBTree *tree,
5932                                       GtkTextTag   *tag)
5933 {
5934   GtkTextTagInfo *info;
5935   GSList *list;
5936
5937
5938   list = tree->tag_infos;
5939   while (list != NULL)
5940     {
5941       info = list->data;
5942       if (info->tag == tag)
5943         return info;
5944
5945       list = g_slist_next (list);
5946     }
5947
5948   return NULL;
5949 }
5950
5951 static GtkTextTagInfo*
5952 gtk_text_btree_get_tag_info (GtkTextBTree *tree,
5953                              GtkTextTag   *tag)
5954 {
5955   GtkTextTagInfo *info;
5956
5957   info = gtk_text_btree_get_existing_tag_info (tree, tag);
5958
5959   if (info == NULL)
5960     {
5961       /* didn't find it, create. */
5962
5963       info = g_new (GtkTextTagInfo, 1);
5964
5965       info->tag = tag;
5966       g_object_ref (tag);
5967       info->tag_root = NULL;
5968       info->toggle_count = 0;
5969
5970       tree->tag_infos = g_slist_prepend (tree->tag_infos, info);
5971
5972 #if 0
5973       g_print ("Created tag info %p for tag %s(%p)\n",
5974                info, info->tag->name ? info->tag->name : "anon",
5975                info->tag);
5976 #endif
5977     }
5978
5979   return info;
5980 }
5981
5982 static void
5983 gtk_text_btree_remove_tag_info (GtkTextBTree *tree,
5984                                 GtkTextTag   *tag)
5985 {
5986   GtkTextTagInfo *info;
5987   GSList *list;
5988   GSList *prev;
5989
5990   prev = NULL;
5991   list = tree->tag_infos;
5992   while (list != NULL)
5993     {
5994       info = list->data;
5995       if (info->tag == tag)
5996         {
5997 #if 0
5998           g_print ("Removing tag info %p for tag %s(%p)\n",
5999                    info, info->tag->name ? info->tag->name : "anon",
6000                    info->tag);
6001 #endif
6002           
6003           if (prev != NULL)
6004             {
6005               prev->next = list->next;
6006             }
6007           else
6008             {
6009               tree->tag_infos = list->next;
6010             }
6011           list->next = NULL;
6012           g_slist_free (list);
6013
6014           g_object_unref (info->tag);
6015
6016           g_free (info);
6017           return;
6018         }
6019
6020       prev = list;
6021       list = g_slist_next (list);
6022     }
6023 }
6024
6025 static void
6026 recompute_level_zero_counts (GtkTextBTreeNode *node)
6027 {
6028   GtkTextLine *line;
6029   GtkTextLineSegment *seg;
6030
6031   g_assert (node->level == 0);
6032
6033   line = node->children.line;
6034   while (line != NULL)
6035     {
6036       node->num_children++;
6037       node->num_lines++;
6038
6039       if (line->parent != node)
6040         gtk_text_line_set_parent (line, node);
6041
6042       seg = line->segments;
6043       while (seg != NULL)
6044         {
6045
6046           node->num_chars += seg->char_count;
6047
6048           if (((seg->type != &gtk_text_toggle_on_type)
6049                && (seg->type != &gtk_text_toggle_off_type))
6050               || !(seg->body.toggle.inNodeCounts))
6051             {
6052               ; /* nothing */
6053             }
6054           else
6055             {
6056               GtkTextTagInfo *info;
6057
6058               info = seg->body.toggle.info;
6059
6060               gtk_text_btree_node_adjust_toggle_count (node, info, 1);
6061             }
6062
6063           seg = seg->next;
6064         }
6065
6066       line = line->next;
6067     }
6068 }
6069
6070 static void
6071 recompute_level_nonzero_counts (GtkTextBTreeNode *node)
6072 {
6073   Summary *summary;
6074   GtkTextBTreeNode *child;
6075
6076   g_assert (node->level > 0);
6077
6078   child = node->children.node;
6079   while (child != NULL)
6080     {
6081       node->num_children += 1;
6082       node->num_lines += child->num_lines;
6083       node->num_chars += child->num_chars;
6084
6085       if (child->parent != node)
6086         {
6087           child->parent = node;
6088           gtk_text_btree_node_invalidate_upward (node, NULL);
6089         }
6090
6091       summary = child->summary;
6092       while (summary != NULL)
6093         {
6094           gtk_text_btree_node_adjust_toggle_count (node,
6095                                                    summary->info,
6096                                                    summary->toggle_count);
6097
6098           summary = summary->next;
6099         }
6100
6101       child = child->next;
6102     }
6103 }
6104
6105 /*
6106  *----------------------------------------------------------------------
6107  *
6108  * recompute_node_counts --
6109  *
6110  *      This procedure is called to recompute all the counts in a GtkTextBTreeNode
6111  *      (tags, child information, etc.) by scanning the information in
6112  *      its descendants.  This procedure is called during rebalancing
6113  *      when a GtkTextBTreeNode's child structure has changed.
6114  *
6115  * Results:
6116  *      None.
6117  *
6118  * Side effects:
6119  *      The tag counts for node are modified to reflect its current
6120  *      child structure, as are its num_children, num_lines, num_chars fields.
6121  *      Also, all of the childrens' parent fields are made to point
6122  *      to node.
6123  *
6124  *----------------------------------------------------------------------
6125  */
6126
6127 static void
6128 recompute_node_counts (GtkTextBTree *tree, GtkTextBTreeNode *node)
6129 {
6130   BTreeView *view;
6131   Summary *summary, *summary2;
6132
6133   /*
6134    * Zero out all the existing counts for the GtkTextBTreeNode, but don't delete
6135    * the existing Summary records (most of them will probably be reused).
6136    */
6137
6138   summary = node->summary;
6139   while (summary != NULL)
6140     {
6141       summary->toggle_count = 0;
6142       summary = summary->next;
6143     }
6144
6145   node->num_children = 0;
6146   node->num_lines = 0;
6147   node->num_chars = 0;
6148
6149   /*
6150    * Scan through the children, adding the childrens' tag counts into
6151    * the GtkTextBTreeNode's tag counts and adding new Summary structures if
6152    * necessary.
6153    */
6154
6155   if (node->level == 0)
6156     recompute_level_zero_counts (node);
6157   else
6158     recompute_level_nonzero_counts (node);
6159
6160   view = tree->views;
6161   while (view)
6162     {
6163       gtk_text_btree_node_check_valid (node, view->view_id);
6164       view = view->next;
6165     }
6166   
6167   /*
6168    * Scan through the GtkTextBTreeNode's tag records again and delete any Summary
6169    * records that still have a zero count, or that have all the toggles.
6170    * The GtkTextBTreeNode with the children that account for all the tags toggles
6171    * have no summary information, and they become the tag_root for the tag.
6172    */
6173
6174   summary2 = NULL;
6175   for (summary = node->summary; summary != NULL; )
6176     {
6177       if (summary->toggle_count > 0 &&
6178           summary->toggle_count < summary->info->toggle_count)
6179         {
6180           if (node->level == summary->info->tag_root->level)
6181             {
6182               /*
6183                * The tag's root GtkTextBTreeNode split and some toggles left.
6184                * The tag root must move up a level.
6185                */
6186               summary->info->tag_root = node->parent;
6187             }
6188           summary2 = summary;
6189           summary = summary->next;
6190           continue;
6191         }
6192       if (summary->toggle_count == summary->info->toggle_count)
6193         {
6194           /*
6195            * A GtkTextBTreeNode merge has collected all the toggles under
6196            * one GtkTextBTreeNode.  Push the root down to this level.
6197            */
6198           summary->info->tag_root = node;
6199         }
6200       if (summary2 != NULL)
6201         {
6202           summary2->next = summary->next;
6203           summary_destroy (summary);
6204           summary = summary2->next;
6205         }
6206       else
6207         {
6208           node->summary = summary->next;
6209           summary_destroy (summary);
6210           summary = node->summary;
6211         }
6212     }
6213 }
6214
6215 void
6216 _gtk_change_node_toggle_count (GtkTextBTreeNode *node,
6217                                GtkTextTagInfo   *info,
6218                                gint              delta) /* may be negative */
6219 {
6220   Summary *summary, *prevPtr;
6221   GtkTextBTreeNode *node2Ptr;
6222   int rootLevel;                        /* Level of original tag root */
6223
6224   info->toggle_count += delta;
6225
6226   if (info->tag_root == (GtkTextBTreeNode *) NULL)
6227     {
6228       info->tag_root = node;
6229       return;
6230     }
6231
6232   /*
6233    * Note the level of the existing root for the tag so we can detect
6234    * if it needs to be moved because of the toggle count change.
6235    */
6236
6237   rootLevel = info->tag_root->level;
6238
6239   /*
6240    * Iterate over the GtkTextBTreeNode and its ancestors up to the tag root, adjusting
6241    * summary counts at each GtkTextBTreeNode and moving the tag's root upwards if
6242    * necessary.
6243    */
6244
6245   for ( ; node != info->tag_root; node = node->parent)
6246     {
6247       /*
6248        * See if there's already an entry for this tag for this GtkTextBTreeNode.  If so,
6249        * perhaps all we have to do is adjust its count.
6250        */
6251
6252       for (prevPtr = NULL, summary = node->summary;
6253            summary != NULL;
6254            prevPtr = summary, summary = summary->next)
6255         {
6256           if (summary->info == info)
6257             {
6258               break;
6259             }
6260         }
6261       if (summary != NULL)
6262         {
6263           summary->toggle_count += delta;
6264           if (summary->toggle_count > 0 &&
6265               summary->toggle_count < info->toggle_count)
6266             {
6267               continue;
6268             }
6269           if (summary->toggle_count != 0)
6270             {
6271               /*
6272                * Should never find a GtkTextBTreeNode with max toggle count at this
6273                * point (there shouldn't have been a summary entry in the
6274                * first place).
6275                */
6276
6277               g_error ("%s: bad toggle count (%d) max (%d)",
6278                        G_STRLOC, summary->toggle_count, info->toggle_count);
6279             }
6280
6281           /*
6282            * Zero toggle count;  must remove this tag from the list.
6283            */
6284
6285           if (prevPtr == NULL)
6286             {
6287               node->summary = summary->next;
6288             }
6289           else
6290             {
6291               prevPtr->next = summary->next;
6292             }
6293           summary_destroy (summary);
6294         }
6295       else
6296         {
6297           /*
6298            * This tag isn't currently in the summary information list.
6299            */
6300
6301           if (rootLevel == node->level)
6302             {
6303
6304               /*
6305                * The old tag root is at the same level in the tree as this
6306                * GtkTextBTreeNode, but it isn't at this GtkTextBTreeNode.  Move the tag root up
6307                * a level, in the hopes that it will now cover this GtkTextBTreeNode
6308                * as well as the old root (if not, we'll move it up again
6309                * the next time through the loop).  To push it up one level
6310                * we copy the original toggle count into the summary
6311                * information at the old root and change the root to its
6312                * parent GtkTextBTreeNode.
6313                */
6314
6315               GtkTextBTreeNode *rootnode = info->tag_root;
6316               summary = (Summary *) g_malloc (sizeof (Summary));
6317               summary->info = info;
6318               summary->toggle_count = info->toggle_count - delta;
6319               summary->next = rootnode->summary;
6320               rootnode->summary = summary;
6321               rootnode = rootnode->parent;
6322               rootLevel = rootnode->level;
6323               info->tag_root = rootnode;
6324             }
6325           summary = (Summary *) g_malloc (sizeof (Summary));
6326           summary->info = info;
6327           summary->toggle_count = delta;
6328           summary->next = node->summary;
6329           node->summary = summary;
6330         }
6331     }
6332
6333   /*
6334    * If we've decremented the toggle count, then it may be necessary
6335    * to push the tag root down one or more levels.
6336    */
6337
6338   if (delta >= 0)
6339     {
6340       return;
6341     }
6342   if (info->toggle_count == 0)
6343     {
6344       info->tag_root = (GtkTextBTreeNode *) NULL;
6345       return;
6346     }
6347   node = info->tag_root;
6348   while (node->level > 0)
6349     {
6350       /*
6351        * See if a single child GtkTextBTreeNode accounts for all of the tag's
6352        * toggles.  If so, push the root down one level.
6353        */
6354
6355       for (node2Ptr = node->children.node;
6356            node2Ptr != (GtkTextBTreeNode *)NULL ;
6357            node2Ptr = node2Ptr->next)
6358         {
6359           for (prevPtr = NULL, summary = node2Ptr->summary;
6360                summary != NULL;
6361                prevPtr = summary, summary = summary->next)
6362             {
6363               if (summary->info == info)
6364                 {
6365                   break;
6366                 }
6367             }
6368           if (summary == NULL)
6369             {
6370               continue;
6371             }
6372           if (summary->toggle_count != info->toggle_count)
6373             {
6374               /*
6375                * No GtkTextBTreeNode has all toggles, so the root is still valid.
6376                */
6377
6378               return;
6379             }
6380
6381           /*
6382            * This GtkTextBTreeNode has all the toggles, so push down the root.
6383            */
6384
6385           if (prevPtr == NULL)
6386             {
6387               node2Ptr->summary = summary->next;
6388             }
6389           else
6390             {
6391               prevPtr->next = summary->next;
6392             }
6393           summary_destroy (summary);
6394           info->tag_root = node2Ptr;
6395           break;
6396         }
6397       node = info->tag_root;
6398     }
6399 }
6400
6401 /*
6402  *----------------------------------------------------------------------
6403  *
6404  * inc_count --
6405  *
6406  *      This is a utility procedure used by _gtk_text_btree_get_tags.  It
6407  *      increments the count for a particular tag, adding a new
6408  *      entry for that tag if there wasn't one previously.
6409  *
6410  * Results:
6411  *      None.
6412  *
6413  * Side effects:
6414  *      The information at *tagInfoPtr may be modified, and the arrays
6415  *      may be reallocated to make them larger.
6416  *
6417  *----------------------------------------------------------------------
6418  */
6419
6420 static void
6421 inc_count (GtkTextTag *tag, int inc, TagInfo *tagInfoPtr)
6422 {
6423   GtkTextTag **tag_p;
6424   int count;
6425
6426   for (tag_p = tagInfoPtr->tags, count = tagInfoPtr->numTags;
6427        count > 0; tag_p++, count--)
6428     {
6429       if (*tag_p == tag)
6430         {
6431           tagInfoPtr->counts[tagInfoPtr->numTags-count] += inc;
6432           return;
6433         }
6434     }
6435
6436   /*
6437    * There isn't currently an entry for this tag, so we have to
6438    * make a new one.  If the arrays are full, then enlarge the
6439    * arrays first.
6440    */
6441
6442   if (tagInfoPtr->numTags == tagInfoPtr->arraySize)
6443     {
6444       GtkTextTag **newTags;
6445       int *newCounts, newSize;
6446
6447       newSize = 2*tagInfoPtr->arraySize;
6448       newTags = (GtkTextTag **) g_malloc ((unsigned)
6449                                           (newSize*sizeof (GtkTextTag *)));
6450       memcpy ((void *) newTags, (void *) tagInfoPtr->tags,
6451               tagInfoPtr->arraySize  *sizeof (GtkTextTag *));
6452       g_free ((char *) tagInfoPtr->tags);
6453       tagInfoPtr->tags = newTags;
6454       newCounts = (int *) g_malloc ((unsigned) (newSize*sizeof (int)));
6455       memcpy ((void *) newCounts, (void *) tagInfoPtr->counts,
6456               tagInfoPtr->arraySize  *sizeof (int));
6457       g_free ((char *) tagInfoPtr->counts);
6458       tagInfoPtr->counts = newCounts;
6459       tagInfoPtr->arraySize = newSize;
6460     }
6461
6462   tagInfoPtr->tags[tagInfoPtr->numTags] = tag;
6463   tagInfoPtr->counts[tagInfoPtr->numTags] = inc;
6464   tagInfoPtr->numTags++;
6465 }
6466
6467 static void
6468 gtk_text_btree_link_segment (GtkTextLineSegment *seg,
6469                              const GtkTextIter *iter)
6470 {
6471   GtkTextLineSegment *prev;
6472   GtkTextLine *line;
6473   GtkTextBTree *tree;
6474
6475   line = _gtk_text_iter_get_text_line (iter);
6476   tree = _gtk_text_iter_get_btree (iter);
6477
6478   prev = gtk_text_line_segment_split (iter);
6479   if (prev == NULL)
6480     {
6481       seg->next = line->segments;
6482       line->segments = seg;
6483     }
6484   else
6485     {
6486       seg->next = prev->next;
6487       prev->next = seg;
6488     }
6489   cleanup_line (line);
6490   segments_changed (tree);
6491
6492   if (gtk_debug_flags & GTK_DEBUG_TEXT)
6493     _gtk_text_btree_check (tree);
6494 }
6495
6496 static void
6497 gtk_text_btree_unlink_segment (GtkTextBTree *tree,
6498                                GtkTextLineSegment *seg,
6499                                GtkTextLine *line)
6500 {
6501   GtkTextLineSegment *prev;
6502
6503   if (line->segments == seg)
6504     {
6505       line->segments = seg->next;
6506     }
6507   else
6508     {
6509       for (prev = line->segments; prev->next != seg;
6510            prev = prev->next)
6511         {
6512           /* Empty loop body. */
6513         }
6514       prev->next = seg->next;
6515     }
6516   cleanup_line (line);
6517   segments_changed (tree);
6518 }
6519
6520 /*
6521  * This is here because it requires BTree internals, it logically
6522  * belongs in gtktextsegment.c
6523  */
6524
6525
6526 /*
6527  *--------------------------------------------------------------
6528  *
6529  * _gtk_toggle_segment_check_func --
6530  *
6531  *      This procedure is invoked to perform consistency checks
6532  *      on toggle segments.
6533  *
6534  * Results:
6535  *      None.
6536  *
6537  * Side effects:
6538  *      If a consistency problem is found the procedure g_errors.
6539  *
6540  *--------------------------------------------------------------
6541  */
6542
6543 void
6544 _gtk_toggle_segment_check_func (GtkTextLineSegment *segPtr,
6545                                 GtkTextLine *line)
6546 {
6547   Summary *summary;
6548   int needSummary;
6549
6550   if (segPtr->byte_count != 0)
6551     {
6552       g_error ("toggle_segment_check_func: segment had non-zero size");
6553     }
6554   if (!segPtr->body.toggle.inNodeCounts)
6555     {
6556       g_error ("toggle_segment_check_func: toggle counts not updated in GtkTextBTreeNodes");
6557     }
6558   needSummary = (segPtr->body.toggle.info->tag_root != line->parent);
6559   for (summary = line->parent->summary; ;
6560        summary = summary->next)
6561     {
6562       if (summary == NULL)
6563         {
6564           if (needSummary)
6565             {
6566               g_error ("toggle_segment_check_func: tag not present in GtkTextBTreeNode");
6567             }
6568           else
6569             {
6570               break;
6571             }
6572         }
6573       if (summary->info == segPtr->body.toggle.info)
6574         {
6575           if (!needSummary)
6576             {
6577               g_error ("toggle_segment_check_func: tag present in root GtkTextBTreeNode summary");
6578             }
6579           break;
6580         }
6581     }
6582 }
6583
6584 /*
6585  * Debug
6586  */
6587
6588 static void
6589 gtk_text_btree_node_view_check_consistency (GtkTextBTree     *tree,
6590                                             GtkTextBTreeNode *node,
6591                                             NodeData         *nd)
6592 {
6593   gint width;
6594   gint height;
6595   gboolean valid;
6596   BTreeView *view;
6597   
6598   view = tree->views;
6599
6600   while (view != NULL)
6601     {
6602       if (view->view_id == nd->view_id)
6603         break;
6604
6605       view = view->next;
6606     }
6607
6608   if (view == NULL)
6609     g_error ("Node has data for a view %p no longer attached to the tree",
6610              nd->view_id);
6611   
6612   gtk_text_btree_node_compute_view_aggregates (node, nd->view_id,
6613                                                &width, &height, &valid);
6614
6615   /* valid aggregate not checked the same as width/height, because on
6616    * btree rebalance we can have invalid nodes where all lines below
6617    * them are actually valid, due to moving lines around between
6618    * nodes.
6619    *
6620    * The guarantee is that if there are invalid lines the node is
6621    * invalid - we don't guarantee that if the node is invalid there
6622    * are invalid lines.
6623    */
6624   
6625   if (nd->width != width ||
6626       nd->height != height ||
6627       (nd->valid && !valid))
6628     {
6629       g_error ("Node aggregates for view %p are invalid:\n"
6630                "Are (%d,%d,%s), should be (%d,%d,%s)",
6631                nd->view_id,
6632                nd->width, nd->height, nd->valid ? "TRUE" : "FALSE",
6633                width, height, valid ? "TRUE" : "FALSE");
6634     }
6635 }
6636
6637 static void
6638 gtk_text_btree_node_check_consistency (GtkTextBTree     *tree,
6639                                        GtkTextBTreeNode *node)
6640 {
6641   GtkTextBTreeNode *childnode;
6642   Summary *summary, *summary2;
6643   GtkTextLine *line;
6644   GtkTextLineSegment *segPtr;
6645   int num_children, num_lines, num_chars, toggle_count, min_children;
6646   GtkTextLineData *ld;
6647   NodeData *nd;
6648
6649   if (node->parent != NULL)
6650     {
6651       min_children = MIN_CHILDREN;
6652     }
6653   else if (node->level > 0)
6654     {
6655       min_children = 2;
6656     }
6657   else  {
6658     min_children = 1;
6659   }
6660   if ((node->num_children < min_children)
6661       || (node->num_children > MAX_CHILDREN))
6662     {
6663       g_error ("gtk_text_btree_node_check_consistency: bad child count (%d)",
6664                node->num_children);
6665     }
6666
6667   nd = node->node_data;
6668   while (nd != NULL)
6669     {
6670       gtk_text_btree_node_view_check_consistency (tree, node, nd);
6671       nd = nd->next;
6672     }
6673
6674   num_children = 0;
6675   num_lines = 0;
6676   num_chars = 0;
6677   if (node->level == 0)
6678     {
6679       for (line = node->children.line; line != NULL;
6680            line = line->next)
6681         {
6682           if (line->parent != node)
6683             {
6684               g_error ("gtk_text_btree_node_check_consistency: line doesn't point to parent");
6685             }
6686           if (line->segments == NULL)
6687             {
6688               g_error ("gtk_text_btree_node_check_consistency: line has no segments");
6689             }
6690
6691           ld = line->views;
6692           while (ld != NULL)
6693             {
6694               /* Just ensuring we don't segv while doing this loop */
6695
6696               ld = ld->next;
6697             }
6698
6699           for (segPtr = line->segments; segPtr != NULL; segPtr = segPtr->next)
6700             {
6701               if (segPtr->type->checkFunc != NULL)
6702                 {
6703                   (*segPtr->type->checkFunc)(segPtr, line);
6704                 }
6705               if ((segPtr->byte_count == 0) && (!segPtr->type->leftGravity)
6706                   && (segPtr->next != NULL)
6707                   && (segPtr->next->byte_count == 0)
6708                   && (segPtr->next->type->leftGravity))
6709                 {
6710                   g_error ("gtk_text_btree_node_check_consistency: wrong segment order for gravity");
6711                 }
6712               if ((segPtr->next == NULL)
6713                   && (segPtr->type != &gtk_text_char_type))
6714                 {
6715                   g_error ("gtk_text_btree_node_check_consistency: line ended with wrong type");
6716                 }
6717
6718               num_chars += segPtr->char_count;
6719             }
6720
6721           num_children++;
6722           num_lines++;
6723         }
6724     }
6725   else
6726     {
6727       for (childnode = node->children.node; childnode != NULL;
6728            childnode = childnode->next)
6729         {
6730           if (childnode->parent != node)
6731             {
6732               g_error ("gtk_text_btree_node_check_consistency: GtkTextBTreeNode doesn't point to parent");
6733             }
6734           if (childnode->level != (node->level-1))
6735             {
6736               g_error ("gtk_text_btree_node_check_consistency: level mismatch (%d %d)",
6737                        node->level, childnode->level);
6738             }
6739           gtk_text_btree_node_check_consistency (tree, childnode);
6740           for (summary = childnode->summary; summary != NULL;
6741                summary = summary->next)
6742             {
6743               for (summary2 = node->summary; ;
6744                    summary2 = summary2->next)
6745                 {
6746                   if (summary2 == NULL)
6747                     {
6748                       if (summary->info->tag_root == node)
6749                         {
6750                           break;
6751                         }
6752                       g_error ("gtk_text_btree_node_check_consistency: GtkTextBTreeNode tag \"%s\" not %s",
6753                                summary->info->tag->name,
6754                                "present in parent summaries");
6755                     }
6756                   if (summary->info == summary2->info)
6757                     {
6758                       break;
6759                     }
6760                 }
6761             }
6762           num_children++;
6763           num_lines += childnode->num_lines;
6764           num_chars += childnode->num_chars;
6765         }
6766     }
6767   if (num_children != node->num_children)
6768     {
6769       g_error ("gtk_text_btree_node_check_consistency: mismatch in num_children (%d %d)",
6770                num_children, node->num_children);
6771     }
6772   if (num_lines != node->num_lines)
6773     {
6774       g_error ("gtk_text_btree_node_check_consistency: mismatch in num_lines (%d %d)",
6775                num_lines, node->num_lines);
6776     }
6777   if (num_chars != node->num_chars)
6778     {
6779       g_error ("gtk_text_btree_node_check_consistency: mismatch in num_chars (%d %d)",
6780                num_chars, node->num_chars);
6781     }
6782
6783   for (summary = node->summary; summary != NULL;
6784        summary = summary->next)
6785     {
6786       if (summary->info->toggle_count == summary->toggle_count)
6787         {
6788           g_error ("gtk_text_btree_node_check_consistency: found unpruned root for \"%s\"",
6789                    summary->info->tag->name);
6790         }
6791       toggle_count = 0;
6792       if (node->level == 0)
6793         {
6794           for (line = node->children.line; line != NULL;
6795                line = line->next)
6796             {
6797               for (segPtr = line->segments; segPtr != NULL;
6798                    segPtr = segPtr->next)
6799                 {
6800                   if ((segPtr->type != &gtk_text_toggle_on_type)
6801                       && (segPtr->type != &gtk_text_toggle_off_type))
6802                     {
6803                       continue;
6804                     }
6805                   if (segPtr->body.toggle.info == summary->info)
6806                     {
6807                       if (!segPtr->body.toggle.inNodeCounts)
6808                         g_error ("Toggle segment not in the node counts");
6809
6810                       toggle_count ++;
6811                     }
6812                 }
6813             }
6814         }
6815       else
6816         {
6817           for (childnode = node->children.node;
6818                childnode != NULL;
6819                childnode = childnode->next)
6820             {
6821               for (summary2 = childnode->summary;
6822                    summary2 != NULL;
6823                    summary2 = summary2->next)
6824                 {
6825                   if (summary2->info == summary->info)
6826                     {
6827                       toggle_count += summary2->toggle_count;
6828                     }
6829                 }
6830             }
6831         }
6832       if (toggle_count != summary->toggle_count)
6833         {
6834           g_error ("gtk_text_btree_node_check_consistency: mismatch in toggle_count (%d %d)",
6835                    toggle_count, summary->toggle_count);
6836         }
6837       for (summary2 = summary->next; summary2 != NULL;
6838            summary2 = summary2->next)
6839         {
6840           if (summary2->info == summary->info)
6841             {
6842               g_error ("gtk_text_btree_node_check_consistency: duplicated GtkTextBTreeNode tag: %s",
6843                        summary->info->tag->name);
6844             }
6845         }
6846     }
6847 }
6848
6849 static void
6850 listify_foreach (GtkTextTag *tag, gpointer user_data)
6851 {
6852   GSList** listp = user_data;
6853
6854   *listp = g_slist_prepend (*listp, tag);
6855 }
6856
6857 static GSList*
6858 list_of_tags (GtkTextTagTable *table)
6859 {
6860   GSList *list = NULL;
6861
6862   gtk_text_tag_table_foreach (table, listify_foreach, &list);
6863
6864   return list;
6865 }
6866
6867 void
6868 _gtk_text_btree_check (GtkTextBTree *tree)
6869 {
6870   Summary *summary;
6871   GtkTextBTreeNode *node;
6872   GtkTextLine *line;
6873   GtkTextLineSegment *seg;
6874   GtkTextTag *tag;
6875   GSList *all_tags, *taglist = NULL;
6876   int count;
6877   GtkTextTagInfo *info;
6878
6879   /*
6880    * Make sure that the tag toggle counts and the tag root pointers are OK.
6881    */
6882   all_tags = list_of_tags (tree->table);
6883   for (taglist = all_tags; taglist != NULL ; taglist = taglist->next)
6884     {
6885       tag = taglist->data;
6886       info = gtk_text_btree_get_existing_tag_info (tree, tag);
6887       if (info != NULL)
6888         {
6889           node = info->tag_root;
6890           if (node == NULL)
6891             {
6892               if (info->toggle_count != 0)
6893                 {
6894                   g_error ("_gtk_text_btree_check found \"%s\" with toggles (%d) but no root",
6895                            tag->name, info->toggle_count);
6896                 }
6897               continue;         /* no ranges for the tag */
6898             }
6899           else if (info->toggle_count == 0)
6900             {
6901               g_error ("_gtk_text_btree_check found root for \"%s\" with no toggles",
6902                        tag->name);
6903             }
6904           else if (info->toggle_count & 1)
6905             {
6906               g_error ("_gtk_text_btree_check found odd toggle count for \"%s\" (%d)",
6907                        tag->name, info->toggle_count);
6908             }
6909           for (summary = node->summary; summary != NULL;
6910                summary = summary->next)
6911             {
6912               if (summary->info->tag == tag)
6913                 {
6914                   g_error ("_gtk_text_btree_check found root GtkTextBTreeNode with summary info");
6915                 }
6916             }
6917           count = 0;
6918           if (node->level > 0)
6919             {
6920               for (node = node->children.node ; node != NULL ;
6921                    node = node->next)
6922                 {
6923                   for (summary = node->summary; summary != NULL;
6924                        summary = summary->next)
6925                     {
6926                       if (summary->info->tag == tag)
6927                         {
6928                           count += summary->toggle_count;
6929                         }
6930                     }
6931                 }
6932             }
6933           else
6934             {
6935               GtkTextLineSegmentClass * last = NULL;
6936
6937               for (line = node->children.line ; line != NULL ;
6938                    line = line->next)
6939                 {
6940                   for (seg = line->segments; seg != NULL;
6941                        seg = seg->next)
6942                     {
6943                       if ((seg->type == &gtk_text_toggle_on_type ||
6944                            seg->type == &gtk_text_toggle_off_type) &&
6945                           seg->body.toggle.info->tag == tag)
6946                         {
6947                           if (last == seg->type)
6948                             g_error ("Two consecutive toggles on or off weren't merged");
6949                           if (!seg->body.toggle.inNodeCounts)
6950                             g_error ("Toggle segment not in the node counts");
6951
6952                           last = seg->type;
6953
6954                           count++;
6955                         }
6956                     }
6957                 }
6958             }
6959           if (count != info->toggle_count)
6960             {
6961               g_error ("_gtk_text_btree_check toggle_count (%d) wrong for \"%s\" should be (%d)",
6962                        info->toggle_count, tag->name, count);
6963             }
6964         }
6965     }
6966
6967   g_slist_free (all_tags);
6968
6969   /*
6970    * Call a recursive procedure to do the main body of checks.
6971    */
6972
6973   node = tree->root_node;
6974   gtk_text_btree_node_check_consistency (tree, tree->root_node);
6975
6976   /*
6977    * Make sure that there are at least two lines in the text and
6978    * that the last line has no characters except a newline.
6979    */
6980
6981   if (node->num_lines < 2)
6982     {
6983       g_error ("_gtk_text_btree_check: less than 2 lines in tree");
6984     }
6985   if (node->num_chars < 2)
6986     {
6987       g_error ("_gtk_text_btree_check: less than 2 chars in tree");
6988     }
6989   while (node->level > 0)
6990     {
6991       node = node->children.node;
6992       while (node->next != NULL)
6993         {
6994           node = node->next;
6995         }
6996     }
6997   line = node->children.line;
6998   while (line->next != NULL)
6999     {
7000       line = line->next;
7001     }
7002   seg = line->segments;
7003   while ((seg->type == &gtk_text_toggle_off_type)
7004          || (seg->type == &gtk_text_right_mark_type)
7005          || (seg->type == &gtk_text_left_mark_type))
7006     {
7007       /*
7008        * It's OK to toggle a tag off in the last line, but
7009        * not to start a new range.  It's also OK to have marks
7010        * in the last line.
7011        */
7012
7013       seg = seg->next;
7014     }
7015   if (seg->type != &gtk_text_char_type)
7016     {
7017       g_error ("_gtk_text_btree_check: last line has bogus segment type");
7018     }
7019   if (seg->next != NULL)
7020     {
7021       g_error ("_gtk_text_btree_check: last line has too many segments");
7022     }
7023   if (seg->byte_count != 1)
7024     {
7025       g_error ("_gtk_text_btree_check: last line has wrong # characters: %d",
7026                seg->byte_count);
7027     }
7028   if ((seg->body.chars[0] != '\n') || (seg->body.chars[1] != 0))
7029     {
7030       g_error ("_gtk_text_btree_check: last line had bad value: %s",
7031                seg->body.chars);
7032     }
7033 }
7034
7035 void _gtk_text_btree_spew_line (GtkTextBTree* tree, GtkTextLine* line);
7036 void _gtk_text_btree_spew_segment (GtkTextBTree* tree, GtkTextLineSegment* seg);
7037 void _gtk_text_btree_spew_node (GtkTextBTreeNode *node, int indent);
7038 void _gtk_text_btree_spew_line_short (GtkTextLine *line, int indent);
7039
7040 void
7041 _gtk_text_btree_spew (GtkTextBTree *tree)
7042 {
7043   GtkTextLine * line;
7044   int real_line;
7045
7046   printf ("%d lines in tree %p\n",
7047           _gtk_text_btree_line_count (tree), tree);
7048
7049   line = _gtk_text_btree_get_line (tree, 0, &real_line);
7050
7051   while (line != NULL)
7052     {
7053       _gtk_text_btree_spew_line (tree, line);
7054       line = _gtk_text_line_next (line);
7055     }
7056
7057   printf ("=================== Tag information\n");
7058
7059   {
7060     GSList * list;
7061
7062     list = tree->tag_infos;
7063
7064     while (list != NULL)
7065       {
7066         GtkTextTagInfo *info;
7067
7068         info = list->data;
7069
7070         printf ("  tag `%s': root at %p, toggle count %d\n",
7071                 info->tag->name, info->tag_root, info->toggle_count);
7072
7073         list = g_slist_next (list);
7074       }
7075
7076     if (tree->tag_infos == NULL)
7077       {
7078         printf ("  (no tags in the tree)\n");
7079       }
7080   }
7081
7082   printf ("=================== Tree nodes\n");
7083
7084   {
7085     _gtk_text_btree_spew_node (tree->root_node, 0);
7086   }
7087 }
7088
7089 void
7090 _gtk_text_btree_spew_line_short (GtkTextLine *line, int indent)
7091 {
7092   gchar * spaces;
7093   GtkTextLineSegment *seg;
7094
7095   spaces = g_strnfill (indent, ' ');
7096
7097   printf ("%sline %p chars %d bytes %d\n",
7098           spaces, line,
7099           _gtk_text_line_char_count (line),
7100           _gtk_text_line_byte_count (line));
7101
7102   seg = line->segments;
7103   while (seg != NULL)
7104     {
7105       if (seg->type == &gtk_text_char_type)
7106         {
7107           gchar* str = g_strndup (seg->body.chars, MIN (seg->byte_count, 10));
7108           gchar* s;
7109           s = str;
7110           while (*s)
7111             {
7112               if (*s == '\n' || *s == '\r')
7113                 *s = '\\';
7114               ++s;
7115             }
7116           printf ("%s chars `%s'...\n", spaces, str);
7117           g_free (str);
7118         }
7119       else if (seg->type == &gtk_text_right_mark_type)
7120         {
7121           printf ("%s right mark `%s' visible: %d\n",
7122                   spaces,
7123                   seg->body.mark.name,
7124                   seg->body.mark.visible);
7125         }
7126       else if (seg->type == &gtk_text_left_mark_type)
7127         {
7128           printf ("%s left mark `%s' visible: %d\n",
7129                   spaces,
7130                   seg->body.mark.name,
7131                   seg->body.mark.visible);
7132         }
7133       else if (seg->type == &gtk_text_toggle_on_type ||
7134                seg->type == &gtk_text_toggle_off_type)
7135         {
7136           printf ("%s tag `%s' %s\n",
7137                   spaces, seg->body.toggle.info->tag->name,
7138                   seg->type == &gtk_text_toggle_off_type ? "off" : "on");
7139         }
7140
7141       seg = seg->next;
7142     }
7143
7144   g_free (spaces);
7145 }
7146
7147 void
7148 _gtk_text_btree_spew_node (GtkTextBTreeNode *node, int indent)
7149 {
7150   gchar * spaces;
7151   GtkTextBTreeNode *iter;
7152   Summary *s;
7153
7154   spaces = g_strnfill (indent, ' ');
7155
7156   printf ("%snode %p level %d children %d lines %d chars %d\n",
7157           spaces, node, node->level,
7158           node->num_children, node->num_lines, node->num_chars);
7159
7160   s = node->summary;
7161   while (s)
7162     {
7163       printf ("%s %d toggles of `%s' below this node\n",
7164               spaces, s->toggle_count, s->info->tag->name);
7165       s = s->next;
7166     }
7167
7168   g_free (spaces);
7169
7170   if (node->level > 0)
7171     {
7172       iter = node->children.node;
7173       while (iter != NULL)
7174         {
7175           _gtk_text_btree_spew_node (iter, indent + 2);
7176
7177           iter = iter->next;
7178         }
7179     }
7180   else
7181     {
7182       GtkTextLine *line = node->children.line;
7183       while (line != NULL)
7184         {
7185           _gtk_text_btree_spew_line_short (line, indent + 2);
7186
7187           line = line->next;
7188         }
7189     }
7190 }
7191
7192 void
7193 _gtk_text_btree_spew_line (GtkTextBTree* tree, GtkTextLine* line)
7194 {
7195   GtkTextLineSegment * seg;
7196
7197   printf ("%4d| line: %p parent: %p next: %p\n",
7198           _gtk_text_line_get_number (line), line, line->parent, line->next);
7199
7200   seg = line->segments;
7201
7202   while (seg != NULL)
7203     {
7204       _gtk_text_btree_spew_segment (tree, seg);
7205       seg = seg->next;
7206     }
7207 }
7208
7209 void
7210 _gtk_text_btree_spew_segment (GtkTextBTree* tree, GtkTextLineSegment * seg)
7211 {
7212   printf ("     segment: %p type: %s bytes: %d chars: %d\n",
7213           seg, seg->type->name, seg->byte_count, seg->char_count);
7214
7215   if (seg->type == &gtk_text_char_type)
7216     {
7217       gchar* str = g_strndup (seg->body.chars, seg->byte_count);
7218       printf ("       `%s'\n", str);
7219       g_free (str);
7220     }
7221   else if (seg->type == &gtk_text_right_mark_type)
7222     {
7223       printf ("       right mark `%s' visible: %d not_deleteable: %d\n",
7224               seg->body.mark.name,
7225               seg->body.mark.visible,
7226               seg->body.mark.not_deleteable);
7227     }
7228   else if (seg->type == &gtk_text_left_mark_type)
7229     {
7230       printf ("       left mark `%s' visible: %d not_deleteable: %d\n",
7231               seg->body.mark.name,
7232               seg->body.mark.visible,
7233               seg->body.mark.not_deleteable);
7234     }
7235   else if (seg->type == &gtk_text_toggle_on_type ||
7236            seg->type == &gtk_text_toggle_off_type)
7237     {
7238       printf ("       tag `%s' priority %d\n",
7239               seg->body.toggle.info->tag->name,
7240               seg->body.toggle.info->tag->priority);
7241     }
7242 }
7243
7244