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