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