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