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