gtktextiter.c 147 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/* GTK - The GIMP Toolkit
 * gtktextiter.c Copyright (C) 2000 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 13 14 15 16 17 18 19 20 21 22 23
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
24
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25 26
 */

27
#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
28
#include <config.h>
29 30 31 32
#include "gtktextiter.h"
#include "gtktextbtree.h"
#include "gtktextiterprivate.h"
#include "gtkdebug.h"
33
#include "gtkalias.h"
34
#include <string.h>
35

36 37
#define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1

38 39
typedef struct _GtkTextRealIter GtkTextRealIter;

40 41
struct _GtkTextRealIter
{
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
  /* Always-valid information */
  GtkTextBTree *tree;
  GtkTextLine *line;
  /* At least one of these is always valid;
     if invalid, they are -1.

     If the line byte offset is valid, so is the segment byte offset;
     and ditto for char offsets. */
  gint line_byte_offset;
  gint line_char_offset;
  /* These two are valid if >= 0 */
  gint cached_char_index;
  gint cached_line_number;
  /* Stamps to detect the buffer changing under us */
  gint chars_changed_stamp;
  gint segments_changed_stamp;
  /* Valid if the segments_changed_stamp is up-to-date */
  GtkTextLineSegment *segment;     /* indexable segment we index */
  GtkTextLineSegment *any_segment; /* first segment in our location,
61
                                      maybe same as "segment" */
62 63 64 65 66 67 68
  /* One of these will always be valid if segments_changed_stamp is
     up-to-date. If invalid, they are -1.

     If the line byte offset is valid, so is the segment byte offset;
     and ditto for char offsets. */
  gint segment_byte_offset;
  gint segment_char_offset;
69 70 71 72

  /* padding */
  gint pad1;
  gpointer pad2;
73 74 75 76 77 78
};

/* These "set" functions should not assume any fields
   other than the char stamp and the tree are valid.
*/
static void
79 80
iter_set_common (GtkTextRealIter *iter,
                 GtkTextLine *line)
81 82 83
{
  /* Update segments stamp */
  iter->segments_changed_stamp =
84
    _gtk_text_btree_get_segments_changed_stamp (iter->tree);
85

86 87 88 89 90 91 92 93 94 95 96
  iter->line = line;

  iter->line_byte_offset = -1;
  iter->line_char_offset = -1;
  iter->segment_byte_offset = -1;
  iter->segment_char_offset = -1;
  iter->cached_char_index = -1;
  iter->cached_line_number = -1;
}

static void
97 98 99
iter_set_from_byte_offset (GtkTextRealIter *iter,
                           GtkTextLine *line,
                           gint byte_offset)
100
{
101
  iter_set_common (iter, line);
102

103 104 105 106 107 108 109 110
  if (!_gtk_text_line_byte_locate (iter->line,
                                   byte_offset,
                                   &iter->segment,
                                   &iter->any_segment,
                                   &iter->segment_byte_offset,
                                   &iter->line_byte_offset))
    g_error ("Byte index %d is off the end of the line",
             byte_offset);
111 112 113
}

static void
114 115 116
iter_set_from_char_offset (GtkTextRealIter *iter,
                           GtkTextLine *line,
                           gint char_offset)
117
{
118
  iter_set_common (iter, line);
119

120 121 122 123 124 125 126 127
  if (!_gtk_text_line_char_locate (iter->line,
                                   char_offset,
                                   &iter->segment,
                                   &iter->any_segment,
                                   &iter->segment_char_offset,
                                   &iter->line_char_offset))
    g_error ("Char offset %d is off the end of the line",
             char_offset);
128 129 130
}

static void
131 132 133
iter_set_from_segment (GtkTextRealIter *iter,
                       GtkTextLine *line,
                       GtkTextLineSegment *segment)
134 135 136 137 138 139 140 141 142 143 144 145 146 147
{
  GtkTextLineSegment *seg;
  gint byte_offset;

  /* This could theoretically be optimized by computing all the iter
     fields in this same loop, but I'm skipping it for now. */
  byte_offset = 0;
  seg = line->segments;
  while (seg != segment)
    {
      byte_offset += seg->byte_count;
      seg = seg->next;
    }

Havoc Pennington's avatar
Havoc Pennington committed
148
  iter_set_from_byte_offset (iter, line, byte_offset);
149 150 151 152
}

/* This function ensures that the segment-dependent information is
   truly computed lazily; often we don't need to do the full make_real
153 154
   work. This ensures the btree and line are valid, but doesn't
   update the segments. */
155
static GtkTextRealIter*
156
gtk_text_iter_make_surreal (const GtkTextIter *_iter)
157 158
{
  GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
159

160
  if (iter->chars_changed_stamp !=
161
      _gtk_text_btree_get_chars_changed_stamp (iter->tree))
162 163 164 165 166 167 168 169 170 171 172
    {
      g_warning ("Invalid text buffer iterator: either the iterator "
                 "is uninitialized, or the characters/pixbufs/widgets "
                 "in the buffer have been modified since the iterator "
                 "was created.\nYou must use marks, character numbers, "
                 "or line numbers to preserve a position across buffer "
                 "modifications.\nYou can apply tags and insert marks "
                 "without invalidating your iterators,\n"
                 "but any mutation that affects 'indexable' buffer contents "
                 "(contents that can be referred to by character offset)\n"
                 "will invalidate all outstanding iterators");
173 174 175 176 177 178 179 180 181
      return NULL;
    }

  /* We don't update the segments information since we are becoming
     only surreal. However we do invalidate the segments information
     if appropriate, to be sure we segfault if we try to use it and we
     should have used make_real. */

  if (iter->segments_changed_stamp !=
182
      _gtk_text_btree_get_segments_changed_stamp (iter->tree))
183 184 185 186 187 188 189
    {
      iter->segment = NULL;
      iter->any_segment = NULL;
      /* set to segfault-causing values. */
      iter->segment_byte_offset = -10000;
      iter->segment_char_offset = -10000;
    }
190

191 192 193 194
  return iter;
}

static GtkTextRealIter*
195
gtk_text_iter_make_real (const GtkTextIter *_iter)
196 197
{
  GtkTextRealIter *iter;
198 199 200

  iter = gtk_text_iter_make_surreal (_iter);

201
  if (iter->segments_changed_stamp !=
202
      _gtk_text_btree_get_segments_changed_stamp (iter->tree))
203 204 205
    {
      if (iter->line_byte_offset >= 0)
        {
206 207 208
          iter_set_from_byte_offset (iter,
                                     iter->line,
                                     iter->line_byte_offset);
209 210 211
        }
      else
        {
212 213 214 215 216
          g_assert (iter->line_char_offset >= 0);

          iter_set_from_char_offset (iter,
                                     iter->line,
                                     iter->line_char_offset);
217 218 219
        }
    }

220 221 222 223
  g_assert (iter->segment != NULL);
  g_assert (iter->any_segment != NULL);
  g_assert (iter->segment->char_count > 0);

224 225 226 227
  return iter;
}

static GtkTextRealIter*
228 229
iter_init_common (GtkTextIter *_iter,
                  GtkTextBTree *tree)
230 231 232
{
  GtkTextRealIter *iter = (GtkTextRealIter*)_iter;

233 234
  g_return_val_if_fail (iter != NULL, NULL);
  g_return_val_if_fail (tree != NULL, NULL);
235 236 237 238

  iter->tree = tree;

  iter->chars_changed_stamp =
239
    _gtk_text_btree_get_chars_changed_stamp (iter->tree);
240

241 242 243 244
  return iter;
}

static GtkTextRealIter*
245 246 247 248
iter_init_from_segment (GtkTextIter *iter,
                        GtkTextBTree *tree,
                        GtkTextLine *line,
                        GtkTextLineSegment *segment)
249 250 251
{
  GtkTextRealIter *real;

252 253 254 255 256 257
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_segment (real, line, segment);

258 259 260 261
  return real;
}

static GtkTextRealIter*
262 263 264 265
iter_init_from_byte_offset (GtkTextIter *iter,
                            GtkTextBTree *tree,
                            GtkTextLine *line,
                            gint line_byte_offset)
266 267 268
{
  GtkTextRealIter *real;

269 270 271 272 273 274
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_byte_offset (real, line, line_byte_offset);

275 276 277 278 279 280 281
  if (real->segment->type == &gtk_text_char_type &&
      (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
    g_warning ("Incorrect line byte index %d falls in the middle of a UTF-8 "
               "character; this will crash the text buffer. "
               "Byte indexes must refer to the start of a character.",
               line_byte_offset);
  
282 283 284 285
  return real;
}

static GtkTextRealIter*
286 287 288 289
iter_init_from_char_offset (GtkTextIter *iter,
                            GtkTextBTree *tree,
                            GtkTextLine *line,
                            gint line_char_offset)
290 291 292
{
  GtkTextRealIter *real;

293 294 295 296 297 298
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_char_offset (real, line, line_char_offset);

299 300 301 302
  return real;
}

static inline void
303
invalidate_segment (GtkTextRealIter *iter)
304 305 306 307 308
{
  iter->segments_changed_stamp -= 1;
}

static inline void
309
invalidate_char_index (GtkTextRealIter *iter)
310 311 312 313 314
{
  iter->cached_char_index = -1;
}

static inline void
315
invalidate_line_number (GtkTextRealIter *iter)
316 317 318 319 320
{
  iter->cached_line_number = -1;
}

static inline void
321
adjust_char_index (GtkTextRealIter *iter, gint count)
322 323 324 325 326 327
{
  if (iter->cached_char_index >= 0)
    iter->cached_char_index += count;
}

static inline void
328
adjust_line_number (GtkTextRealIter *iter, gint count)
329 330 331 332 333 334
{
  if (iter->cached_line_number >= 0)
    iter->cached_line_number += count;
}

static inline void
335
adjust_char_offsets (GtkTextRealIter *iter, gint count)
336 337 338 339
{
  if (iter->line_char_offset >= 0)
    {
      iter->line_char_offset += count;
340
      g_assert (iter->segment_char_offset >= 0);
341 342 343 344 345
      iter->segment_char_offset += count;
    }
}

static inline void
346
adjust_byte_offsets (GtkTextRealIter *iter, gint count)
347 348 349 350
{
  if (iter->line_byte_offset >= 0)
    {
      iter->line_byte_offset += count;
351
      g_assert (iter->segment_byte_offset >= 0);
352 353 354 355 356
      iter->segment_byte_offset += count;
    }
}

static inline void
357
ensure_char_offsets (GtkTextRealIter *iter)
358 359 360
{
  if (iter->line_char_offset < 0)
    {
361
      g_assert (iter->line_byte_offset >= 0);
362

363
      _gtk_text_line_byte_to_char_offsets (iter->line,
364 365 366
                                          iter->line_byte_offset,
                                          &iter->line_char_offset,
                                          &iter->segment_char_offset);
367 368 369 370
    }
}

static inline void
371
ensure_byte_offsets (GtkTextRealIter *iter)
372 373 374
{
  if (iter->line_byte_offset < 0)
    {
375
      g_assert (iter->line_char_offset >= 0);
376

377
      _gtk_text_line_char_to_byte_offsets (iter->line,
378 379 380
                                          iter->line_char_offset,
                                          &iter->line_byte_offset,
                                          &iter->segment_byte_offset);
381 382 383
    }
}

384 385 386 387 388 389
static inline gboolean
is_segment_start (GtkTextRealIter *real)
{
  return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
}

390
#ifdef G_ENABLE_DEBUG
391
static void
392
check_invariants (const GtkTextIter *iter)
393 394
{
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
395
    _gtk_text_iter_check (iter);
396 397
}
#else
398
#define check_invariants (x)
399 400
#endif

401 402 403
/**
 * gtk_text_iter_get_buffer:
 * @iter: an iterator
404
 *
405
 * Returns the #GtkTextBuffer this iterator is associated with.
406
 *
407 408
 * Return value: the buffer
 **/
409
GtkTextBuffer*
410
gtk_text_iter_get_buffer (const GtkTextIter *iter)
411 412 413
{
  GtkTextRealIter *real;

414 415 416
  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_surreal (iter);
417 418 419 420

  if (real == NULL)
    return NULL;

421 422
  check_invariants (iter);

423
  return _gtk_text_btree_get_buffer (real->tree);
424 425
}

426 427 428
/**
 * gtk_text_iter_copy:
 * @iter: an iterator
429
 *
430
 * Creates a dynamically-allocated copy of an iterator. This function
431 432 433
 * is not useful in applications, because iterators can be copied with a
 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
 * function is used by language bindings.
434 435
 *
 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
436
 **/
437
GtkTextIter*
438
gtk_text_iter_copy (const GtkTextIter *iter)
439 440 441
{
  GtkTextIter *new_iter;

442 443
  g_return_val_if_fail (iter != NULL, NULL);

444
  new_iter = g_slice_new (GtkTextIter);
445 446

  *new_iter = *iter;
447

448 449 450
  return new_iter;
}

451 452 453 454 455 456 457 458 459
/**
 * gtk_text_iter_free:
 * @iter: a dynamically-allocated iterator
 *
 * Free an iterator allocated on the heap. This function
 * is intended for use in language bindings, and is not
 * especially useful for applications, because iterators can
 * simply be allocated on the stack.
 **/
460
void
461
gtk_text_iter_free (GtkTextIter *iter)
462
{
463
  g_return_if_fail (iter != NULL);
464

465
  g_slice_free (GtkTextIter, iter);
466 467
}

468 469 470 471 472 473
GType
gtk_text_iter_get_type (void)
{
  static GType our_type = 0;
  
  if (our_type == 0)
474
    our_type = g_boxed_type_register_static ("GtkTextIter",
475 476 477 478 479 480
					     (GBoxedCopyFunc) gtk_text_iter_copy,
					     (GBoxedFreeFunc) gtk_text_iter_free);

  return our_type;
}

481
GtkTextLineSegment*
482
_gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
483 484 485
{
  GtkTextRealIter *real;

486
  g_return_val_if_fail (iter != NULL, NULL);
487 488

  real = gtk_text_iter_make_real (iter);
489 490 491 492

  if (real == NULL)
    return NULL;

493 494 495 496
  check_invariants (iter);

  g_assert (real->segment != NULL);

497 498 499 500
  return real->segment;
}

GtkTextLineSegment*
501
_gtk_text_iter_get_any_segment (const GtkTextIter *iter)
502 503 504
{
  GtkTextRealIter *real;

505
  g_return_val_if_fail (iter != NULL, NULL);
506 507

  real = gtk_text_iter_make_real (iter);
508 509 510 511

  if (real == NULL)
    return NULL;

512 513 514 515
  check_invariants (iter);

  g_assert (real->any_segment != NULL);

516 517 518 519
  return real->any_segment;
}

gint
520
_gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
521 522 523
{
  GtkTextRealIter *real;

524
  g_return_val_if_fail (iter != NULL, 0);
525 526

  real = gtk_text_iter_make_real (iter);
527 528 529 530

  if (real == NULL)
    return 0;

531 532 533
  ensure_byte_offsets (real);

  check_invariants (iter);
534 535 536 537 538

  return real->segment_byte_offset;
}

gint
539
_gtk_text_iter_get_segment_char (const GtkTextIter *iter)
540 541 542
{
  GtkTextRealIter *real;

543
  g_return_val_if_fail (iter != NULL, 0);
544 545

  real = gtk_text_iter_make_real (iter);
546 547 548 549

  if (real == NULL)
    return 0;

550 551 552
  ensure_char_offsets (real);

  check_invariants (iter);
553 554 555 556 557 558 559

  return real->segment_char_offset;
}

/* This function does not require a still-valid
   iterator */
GtkTextLine*
560
_gtk_text_iter_get_text_line (const GtkTextIter *iter)
561 562 563
{
  const GtkTextRealIter *real;

564
  g_return_val_if_fail (iter != NULL, NULL);
565

566 567 568 569 570 571 572 573
  real = (const GtkTextRealIter*)iter;

  return real->line;
}

/* This function does not require a still-valid
   iterator */
GtkTextBTree*
574
_gtk_text_iter_get_btree (const GtkTextIter *iter)
575 576 577
{
  const GtkTextRealIter *real;

578
  g_return_val_if_fail (iter != NULL, NULL);
579

580 581 582 583 584 585 586 587 588
  real = (const GtkTextRealIter*)iter;

  return real->tree;
}

/*
 * Conversions
 */

589 590 591
/**
 * gtk_text_iter_get_offset:
 * @iter: an iterator
592
 *
593 594 595
 * Returns the character offset of an iterator.
 * Each character in a #GtkTextBuffer has an offset,
 * starting with 0 for the first character in the buffer.
596
 * Use gtk_text_buffer_get_iter_at_offset () to convert an
597
 * offset back into an iterator.
598
 *
599 600
 * Return value: a character offset
 **/
601
gint
602
gtk_text_iter_get_offset (const GtkTextIter *iter)
603 604 605
{
  GtkTextRealIter *real;

606 607 608
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
609 610 611 612

  if (real == NULL)
    return 0;

613 614
  check_invariants (iter);
  
615 616
  if (real->cached_char_index < 0)
    {
617 618
      ensure_char_offsets (real);
      
619
      real->cached_char_index =
620
        _gtk_text_line_char_index (real->line);
621 622 623
      real->cached_char_index += real->line_char_offset;
    }

624 625
  check_invariants (iter);

626 627 628
  return real->cached_char_index;
}

629 630 631
/**
 * gtk_text_iter_get_line:
 * @iter: an iterator
632
 *
633 634 635
 * Returns the line number containing the iterator. Lines in
 * a #GtkTextBuffer are numbered beginning with 0 for the first
 * line in the buffer.
636
 *
637 638
 * Return value: a line number
 **/
639
gint
640
gtk_text_iter_get_line (const GtkTextIter *iter)
641 642 643
{
  GtkTextRealIter *real;

644 645 646
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
647 648 649 650 651 652

  if (real == NULL)
    return 0;

  if (real->cached_line_number < 0)
    real->cached_line_number =
653
      _gtk_text_line_get_number (real->line);
654 655

  check_invariants (iter);
656 657 658 659

  return real->cached_line_number;
}

660 661 662
/**
 * gtk_text_iter_get_line_offset:
 * @iter: an iterator
663
 *
664 665 666
 * Returns the character offset of the iterator,
 * counting from the start of a newline-terminated line.
 * The first character on the line has offset 0.
667
 *
668 669
 * Return value: offset from start of line
 **/
670
gint
671
gtk_text_iter_get_line_offset (const GtkTextIter *iter)
672 673 674
{
  GtkTextRealIter *real;

675 676 677
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
678 679 680 681

  if (real == NULL)
    return 0;

682 683 684
  ensure_char_offsets (real);

  check_invariants (iter);
685 686 687 688

  return real->line_char_offset;
}

689 690 691
/**
 * gtk_text_iter_get_line_index:
 * @iter: an iterator
692
 *
693 694 695 696 697
 * Returns the byte index of the iterator, counting
 * from the start of a newline-terminated line.
 * Remember that #GtkTextBuffer encodes text in
 * UTF-8, and that characters can require a variable
 * number of bytes to represent.
698
 *
699 700
 * Return value: distance from start of line, in bytes
 **/
701
gint
Havoc Pennington's avatar
Havoc Pennington committed
702
gtk_text_iter_get_line_index (const GtkTextIter *iter)
703 704
{
  GtkTextRealIter *real;
705
  
706 707 708
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
709 710 711 712

  if (real == NULL)
    return 0;

713 714 715
  ensure_byte_offsets (real);

  check_invariants (iter);
716 717 718 719

  return real->line_byte_offset;
}

720 721 722 723 724 725 726 727 728 729 730
/**
 * gtk_text_iter_get_visible_line_offset:
 * @iter: a #GtkTextIter
 * 
 * Returns the offset in characters from the start of the
 * line to the given @iter, not counting characters that
 * are invisible due to tags with the "invisible" flag
 * toggled on.
 * 
 * Return value: offset in visible characters from the start of the line 
 **/
731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
gint
gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
{
  GtkTextRealIter *real;
  gint vis_offset;
  GtkTextLineSegment *seg;
  GtkTextIter pos;
  
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);

  if (real == NULL)
    return 0;

  ensure_char_offsets (real);

  check_invariants (iter);
749
  
750 751
  vis_offset = real->line_char_offset;

752 753
  g_assert (vis_offset >= 0);
  
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
  _gtk_text_btree_get_iter_at_line (real->tree,
                                    &pos,
                                    real->line,
                                    0);

  seg = _gtk_text_iter_get_indexable_segment (&pos);

  while (seg != real->segment)
    {
      /* This is a pretty expensive call, making the
       * whole function pretty lame; we could keep track
       * of current invisibility state by looking at toggle
       * segments as we loop, and then call this function
       * only once per line, in order to speed up the loop
       * quite a lot.
       */
      if (_gtk_text_btree_char_is_invisible (&pos))
        vis_offset -= seg->char_count;

      _gtk_text_iter_forward_indexable_segment (&pos);

      seg = _gtk_text_iter_get_indexable_segment (&pos);
    }

  if (_gtk_text_btree_char_is_invisible (&pos))
    vis_offset -= real->segment_char_offset;
  
  return vis_offset;
}

784 785 786 787 788 789 790 791 792 793 794 795

/**
 * gtk_text_iter_get_visible_line_index:
 * @iter: a #GtkTextIter
 * 
 * Returns the number of bytes from the start of the
 * line to the given @iter, not counting bytes that
 * are invisible due to tags with the "invisible" flag
 * toggled on.
 * 
 * Return value: byte index of @iter with respect to the start of the line
 **/
796 797 798 799 800 801 802 803 804 805 806 807 808 809 810
gint
gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
{
  GtkTextRealIter *real;
  gint vis_offset;
  GtkTextLineSegment *seg;
  GtkTextIter pos;
  
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);

  if (real == NULL)
    return 0;

811
  ensure_byte_offsets (real);
812 813 814 815 816

  check_invariants (iter);

  vis_offset = real->line_byte_offset;

817 818
  g_assert (vis_offset >= 0);
  
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
  _gtk_text_btree_get_iter_at_line (real->tree,
                                    &pos,
                                    real->line,
                                    0);

  seg = _gtk_text_iter_get_indexable_segment (&pos);

  while (seg != real->segment)
    {
      /* This is a pretty expensive call, making the
       * whole function pretty lame; we could keep track
       * of current invisibility state by looking at toggle
       * segments as we loop, and then call this function
       * only once per line, in order to speed up the loop
       * quite a lot.
       */
      if (_gtk_text_btree_char_is_invisible (&pos))
        vis_offset -= seg->byte_count;

      _gtk_text_iter_forward_indexable_segment (&pos);

      seg = _gtk_text_iter_get_indexable_segment (&pos);
    }

  if (_gtk_text_btree_char_is_invisible (&pos))
    vis_offset -= real->segment_byte_offset;
  
  return vis_offset;
}

849 850 851 852
/*
 * Dereferencing
 */

853 854 855
/**
 * gtk_text_iter_get_char:
 * @iter: an iterator
856
 *
857
 * Returns the Unicode character at this iterator.  (Equivalent to
Soren Sandmann's avatar
Soren Sandmann committed
858
 * operator* on a C++ iterator.)  If the element at this iterator is a
859
 * non-character element, such as an image embedded in the buffer, the
Havoc Pennington's avatar
Havoc Pennington committed
860
 * Unicode "unknown" character 0xFFFC is returned. If invoked on
861
 * the end iterator, zero is returned; zero is not a valid Unicode character.
862
 * So you can write a loop which ends when gtk_text_iter_get_char ()
863
 * returns 0.
864
 *
865
 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
866
 **/
867
gunichar
868
gtk_text_iter_get_char (const GtkTextIter *iter)
869 870 871
{
  GtkTextRealIter *real;

872 873 874
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);
875 876 877 878

  if (real == NULL)
    return 0;

879
  check_invariants (iter);
880

881
  if (gtk_text_iter_is_end (iter))
882 883
    return 0;
  else if (real->segment->type == &gtk_text_char_type)
884
    {
885
      ensure_byte_offsets (real);
886
      
887 888
      return g_utf8_get_char (real->segment->body.chars +
                              real->segment_byte_offset);
889 890 891
    }
  else
    {
Havoc Pennington's avatar
Havoc Pennington committed
892 893
      /* Unicode "unknown character" 0xFFFC */
      return GTK_TEXT_UNKNOWN_CHAR;
894 895 896
    }
}

897 898 899 900
/**
 * gtk_text_iter_get_slice:
 * @start: iterator at start of a range
 * @end: iterator at end of a range
901
 *
902 903
 * Returns the text in the given range. A "slice" is an array of
 * characters encoded in UTF-8 format, including the Unicode "unknown"
Havoc Pennington's avatar
Havoc Pennington committed
904
 * character 0xFFFC for iterable non-character elements in the buffer,
905 906
 * such as images.  Because images are encoded in the slice, byte and
 * character offsets in the returned array will correspond to byte
Havoc Pennington's avatar
Havoc Pennington committed
907
 * offsets in the text buffer. Note that 0xFFFC can occur in normal
908 909
 * text as well, so it is not a reliable indicator that a pixbuf or
 * widget is in the buffer.
910
 *
911 912
 * Return value: slice of text from the buffer
 **/
913 914
gchar*
gtk_text_iter_get_slice       (const GtkTextIter *start,
915
                               const GtkTextIter *end)
916
{
917 918 919 920 921
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);
922

923
  return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
924 925
}

926 927 928 929
/**
 * gtk_text_iter_get_text:
 * @start: iterator at start of a range
 * @end: iterator at end of a range
930
 *
931 932 933 934
 * Returns <emphasis>text</emphasis> in the given range.  If the range
 * contains non-text elements such as images, the character and byte
 * offsets in the returned string will not correspond to character and
 * byte offsets in the buffer. If you want offsets to correspond, see
935 936
 * gtk_text_iter_get_slice ().
 *
937 938
 * Return value: array of characters from the buffer
 **/
939 940
gchar*
gtk_text_iter_get_text       (const GtkTextIter *start,
941
                              const GtkTextIter *end)
942
{
943 944 945 946 947
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);
948

949
  return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
950 951
}

952 953 954 955
/**
 * gtk_text_iter_get_visible_slice:
 * @start: iterator at start of range
 * @end: iterator at end of range
956 957
 *
 * Like gtk_text_iter_get_slice (), but invisible text is not included.
958 959
 * Invisible text is usually invisible because a #GtkTextTag with the
 * "invisible" attribute turned on has been applied to it.
960
 *
961 962
 * Return value: slice of text from the buffer
 **/
963 964
gchar*
gtk_text_iter_get_visible_slice (const GtkTextIter  *start,
965
                                 const GtkTextIter  *end)
966
{
967 968
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);
969

970 971 972
  check_invariants (start);
  check_invariants (end);

973
  return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
974 975
}

976 977 978 979
/**
 * gtk_text_iter_get_visible_text:
 * @start: iterator at start of range
 * @end: iterator at end of range
980 981
 *
 * Like gtk_text_iter_get_text (), but invisible text is not included.
982 983
 * Invisible text is usually invisible because a #GtkTextTag with the
 * "invisible" attribute turned on has been applied to it.
984
 *
985 986
 * Return value: string containing visible text in the range
 **/
987 988
gchar*
gtk_text_iter_get_visible_text (const GtkTextIter  *start,
989
                                const GtkTextIter  *end)
990
{
991 992 993 994 995 996
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);

997
  return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
998 999
}

1000
/**
Havoc Pennington's avatar
Havoc Pennington committed
1001
 * gtk_text_iter_get_pixbuf:
1002
 * @iter: an iterator
1003
 *
Soren Sandmann's avatar
Soren Sandmann committed
1004 1005
 * If the element at @iter is a pixbuf, the pixbuf is returned
 * (with no new reference count added). Otherwise,
1006
 * %NULL is returned.
1007
 *
Havoc Pennington's avatar
Havoc Pennington committed
1008
 * Return value: the pixbuf at @iter