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