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