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