gtktextiter.c 156 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
2 3 4 5 6 7 8 9 10
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 17 18 19 20 21
 */

/*
 * 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
22
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23 24
 */

25
#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
26
#include "config.h"
27 28
#include "gtktextiter.h"
#include "gtktextbtree.h"
29
#include "gtktextbufferprivate.h"
30
#include "gtktextiterprivate.h"
31
#include "gtkintl.h"
32
#include "gtkdebug.h"
33

34
#include <string.h>
35

36 37 38 39 40 41

/**
 * SECTION:gtktextiter
 * @Short_description: Text buffer iterator
 * @Title: GtkTextIter
 *
42 43 44
 * You may wish to begin by reading the
 * [text widget conceptual overview][TextWidget]
 * which gives an overview of all the objects and data
45 46 47 48
 * types related to the text widget and how they work together.
 */


49 50
#define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1

51 52
typedef struct _GtkTextRealIter GtkTextRealIter;

53
struct G_GNUC_MAY_ALIAS _GtkTextRealIter
54
{
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
  /* 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,
74
                                      maybe same as "segment" */
75 76 77 78 79 80 81
  /* 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;
82 83 84 85

  /* padding */
  gint pad1;
  gpointer pad2;
86 87 88 89 90 91
};

/* These "set" functions should not assume any fields
   other than the char stamp and the tree are valid.
*/
static void
92 93
iter_set_common (GtkTextRealIter *iter,
                 GtkTextLine *line)
94 95 96
{
  /* Update segments stamp */
  iter->segments_changed_stamp =
97
    _gtk_text_btree_get_segments_changed_stamp (iter->tree);
98

99 100 101 102 103 104 105 106 107 108 109
  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
110 111 112
iter_set_from_byte_offset (GtkTextRealIter *iter,
                           GtkTextLine *line,
                           gint byte_offset)
113
{
114
  iter_set_common (iter, line);
115

116 117 118 119 120 121 122 123
  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);
124 125 126
}

static void
127 128 129
iter_set_from_char_offset (GtkTextRealIter *iter,
                           GtkTextLine *line,
                           gint char_offset)
130
{
131
  iter_set_common (iter, line);
132

133 134 135 136 137 138 139 140
  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);
141 142 143
}

static void
144 145 146
iter_set_from_segment (GtkTextRealIter *iter,
                       GtkTextLine *line,
                       GtkTextLineSegment *segment)
147 148 149 150 151 152 153 154 155 156 157 158 159 160
{
  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;
    }

161
  iter_set_from_byte_offset (iter, line, byte_offset);
162 163 164 165
}

/* This function ensures that the segment-dependent information is
   truly computed lazily; often we don't need to do the full make_real
166 167
   work. This ensures the btree and line are valid, but doesn't
   update the segments. */
168
static GtkTextRealIter*
169
gtk_text_iter_make_surreal (const GtkTextIter *_iter)
170 171
{
  GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
172

173
  if (iter->chars_changed_stamp !=
174
      _gtk_text_btree_get_chars_changed_stamp (iter->tree))
175 176 177 178 179 180 181 182 183 184 185
    {
      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");
186 187 188 189 190 191 192 193 194
      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 !=
195
      _gtk_text_btree_get_segments_changed_stamp (iter->tree))
196 197 198 199 200 201 202
    {
      iter->segment = NULL;
      iter->any_segment = NULL;
      /* set to segfault-causing values. */
      iter->segment_byte_offset = -10000;
      iter->segment_char_offset = -10000;
    }
203

204 205 206 207
  return iter;
}

static GtkTextRealIter*
208
gtk_text_iter_make_real (const GtkTextIter *_iter)
209 210
{
  GtkTextRealIter *iter;
211 212 213

  iter = gtk_text_iter_make_surreal (_iter);

214
  if (iter->segments_changed_stamp !=
215
      _gtk_text_btree_get_segments_changed_stamp (iter->tree))
216 217 218
    {
      if (iter->line_byte_offset >= 0)
        {
219 220 221
          iter_set_from_byte_offset (iter,
                                     iter->line,
                                     iter->line_byte_offset);
222 223 224
        }
      else
        {
225 226 227 228 229
          g_assert (iter->line_char_offset >= 0);

          iter_set_from_char_offset (iter,
                                     iter->line,
                                     iter->line_char_offset);
230 231 232
        }
    }

233 234 235 236
  g_assert (iter->segment != NULL);
  g_assert (iter->any_segment != NULL);
  g_assert (iter->segment->char_count > 0);

237 238 239 240
  return iter;
}

static GtkTextRealIter*
241 242
iter_init_common (GtkTextIter *_iter,
                  GtkTextBTree *tree)
243 244 245
{
  GtkTextRealIter *iter = (GtkTextRealIter*)_iter;

246 247
  g_return_val_if_fail (iter != NULL, NULL);
  g_return_val_if_fail (tree != NULL, NULL);
248 249 250 251

  iter->tree = tree;

  iter->chars_changed_stamp =
252
    _gtk_text_btree_get_chars_changed_stamp (iter->tree);
253

254 255 256 257
  return iter;
}

static GtkTextRealIter*
258 259 260 261
iter_init_from_segment (GtkTextIter *iter,
                        GtkTextBTree *tree,
                        GtkTextLine *line,
                        GtkTextLineSegment *segment)
262 263 264
{
  GtkTextRealIter *real;

265 266 267 268 269 270
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_segment (real, line, segment);

271 272 273 274
  return real;
}

static GtkTextRealIter*
275 276 277 278
iter_init_from_byte_offset (GtkTextIter *iter,
                            GtkTextBTree *tree,
                            GtkTextLine *line,
                            gint line_byte_offset)
279 280 281
{
  GtkTextRealIter *real;

282 283 284 285 286 287
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_byte_offset (real, line, line_byte_offset);

288 289 290 291 292 293 294
  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);
  
295 296 297 298
  return real;
}

static GtkTextRealIter*
299 300 301 302
iter_init_from_char_offset (GtkTextIter *iter,
                            GtkTextBTree *tree,
                            GtkTextLine *line,
                            gint line_char_offset)
303 304 305
{
  GtkTextRealIter *real;

306 307 308 309 310 311
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_char_offset (real, line, line_char_offset);

312 313 314 315
  return real;
}

static inline void
316
invalidate_char_index (GtkTextRealIter *iter)
317 318 319 320 321
{
  iter->cached_char_index = -1;
}

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

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

static inline void
336
ensure_char_offsets (GtkTextRealIter *iter)
337 338 339
{
  if (iter->line_char_offset < 0)
    {
340
      g_assert (iter->line_byte_offset >= 0);
341

342
      _gtk_text_line_byte_to_char_offsets (iter->line,
343 344 345
                                          iter->line_byte_offset,
                                          &iter->line_char_offset,
                                          &iter->segment_char_offset);
346 347 348 349
    }
}

static inline void
350
ensure_byte_offsets (GtkTextRealIter *iter)
351 352 353
{
  if (iter->line_byte_offset < 0)
    {
354
      g_assert (iter->line_char_offset >= 0);
355

356
      _gtk_text_line_char_to_byte_offsets (iter->line,
357 358 359
                                          iter->line_char_offset,
                                          &iter->line_byte_offset,
                                          &iter->segment_byte_offset);
360 361 362
    }
}

363 364 365 366 367 368
static inline gboolean
is_segment_start (GtkTextRealIter *real)
{
  return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
}

369
#ifdef G_ENABLE_DEBUG
370
static void
371
check_invariants (const GtkTextIter *iter)
372
{
373
  if (GTK_DEBUG_CHECK (TEXT))
374
    _gtk_text_iter_check (iter);
375 376
}
#else
Matthias Clasen's avatar
Matthias Clasen committed
377
#define check_invariants(x)
378 379
#endif

380 381 382
/**
 * gtk_text_iter_get_buffer:
 * @iter: an iterator
383
 *
384
 * Returns the #GtkTextBuffer this iterator is associated with.
385
 *
386
 * Returns: (transfer none): the buffer
387
 **/
388
GtkTextBuffer*
389
gtk_text_iter_get_buffer (const GtkTextIter *iter)
390 391 392
{
  GtkTextRealIter *real;

393 394 395
  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_surreal (iter);
396 397 398 399

  if (real == NULL)
    return NULL;

400 401
  check_invariants (iter);

402
  return _gtk_text_btree_get_buffer (real->tree);
403 404
}

405 406 407
/**
 * gtk_text_iter_copy:
 * @iter: an iterator
408
 *
409
 * Creates a dynamically-allocated copy of an iterator. This function
410
 * is not useful in applications, because iterators can be copied with a
411
 * simple assignment (`GtkTextIter i = j;`). The
412
 * function is used by language bindings.
413
 *
414
 * Returns: a copy of the @iter, free with gtk_text_iter_free()
415
 **/
416
GtkTextIter*
417
gtk_text_iter_copy (const GtkTextIter *iter)
418 419 420
{
  GtkTextIter *new_iter;

421 422
  g_return_val_if_fail (iter != NULL, NULL);

423
  new_iter = g_slice_new (GtkTextIter);
424 425

  *new_iter = *iter;
426

427 428 429
  return new_iter;
}

430 431 432 433 434 435 436 437 438
/**
 * 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.
 **/
439
void
440
gtk_text_iter_free (GtkTextIter *iter)
441
{
442
  g_return_if_fail (iter != NULL);
443

444
  g_slice_free (GtkTextIter, iter);
445 446
}

447 448 449 450 451 452 453
/**
 * gtk_text_iter_assign:
 * @iter: a #GtkTextIter
 * @other: another #GtkTextIter
 *
 * Assigns the value of @other to @iter.  This function
 * is not useful in applications, because iterators can be assigned
454
 * with `GtkTextIter i = j;`. The
455 456 457 458 459 460 461 462 463 464 465 466 467 468
 * function is used by language bindings.
 *
 * Since: 3.2
 **/
void
gtk_text_iter_assign (GtkTextIter       *iter,
                      const GtkTextIter *other)
{
  g_return_if_fail (iter != NULL);
  g_return_if_fail (other != NULL);

  *iter = *other;
}

469 470 471
G_DEFINE_BOXED_TYPE (GtkTextIter, gtk_text_iter,
                     gtk_text_iter_copy,
                     gtk_text_iter_free)
472

473
GtkTextLineSegment*
474
_gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
475 476 477
{
  GtkTextRealIter *real;

478
  g_return_val_if_fail (iter != NULL, NULL);
479 480

  real = gtk_text_iter_make_real (iter);
481 482 483 484

  if (real == NULL)
    return NULL;

485 486 487 488
  check_invariants (iter);

  g_assert (real->segment != NULL);

489 490 491 492
  return real->segment;
}

GtkTextLineSegment*
493
_gtk_text_iter_get_any_segment (const GtkTextIter *iter)
494 495 496
{
  GtkTextRealIter *real;

497
  g_return_val_if_fail (iter != NULL, NULL);
498 499

  real = gtk_text_iter_make_real (iter);
500 501 502 503

  if (real == NULL)
    return NULL;

504 505 506 507
  check_invariants (iter);

  g_assert (real->any_segment != NULL);

508 509 510 511
  return real->any_segment;
}

gint
512
_gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
513 514 515
{
  GtkTextRealIter *real;

516
  g_return_val_if_fail (iter != NULL, 0);
517 518

  real = gtk_text_iter_make_real (iter);
519 520 521 522

  if (real == NULL)
    return 0;

523 524 525
  ensure_byte_offsets (real);

  check_invariants (iter);
526 527 528 529 530

  return real->segment_byte_offset;
}

gint
531
_gtk_text_iter_get_segment_char (const GtkTextIter *iter)
532 533 534
{
  GtkTextRealIter *real;

535
  g_return_val_if_fail (iter != NULL, 0);
536 537

  real = gtk_text_iter_make_real (iter);
538 539 540 541

  if (real == NULL)
    return 0;

542 543 544
  ensure_char_offsets (real);

  check_invariants (iter);
545 546 547 548 549 550 551

  return real->segment_char_offset;
}

/* This function does not require a still-valid
   iterator */
GtkTextLine*
552
_gtk_text_iter_get_text_line (const GtkTextIter *iter)
553 554 555
{
  const GtkTextRealIter *real;

556
  g_return_val_if_fail (iter != NULL, NULL);
557

558 559 560 561 562 563 564 565
  real = (const GtkTextRealIter*)iter;

  return real->line;
}

/* This function does not require a still-valid
   iterator */
GtkTextBTree*
566
_gtk_text_iter_get_btree (const GtkTextIter *iter)
567 568 569
{
  const GtkTextRealIter *real;

570
  g_return_val_if_fail (iter != NULL, NULL);
571

572 573 574 575 576 577 578 579 580
  real = (const GtkTextRealIter*)iter;

  return real->tree;
}

/*
 * Conversions
 */

581 582 583
/**
 * gtk_text_iter_get_offset:
 * @iter: an iterator
584
 *
585 586 587
 * 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.
588
 * Use gtk_text_buffer_get_iter_at_offset() to convert an
589
 * offset back into an iterator.
590
 *
591
 * Returns: a character offset
592
 **/
593
gint
594
gtk_text_iter_get_offset (const GtkTextIter *iter)
595 596 597
{
  GtkTextRealIter *real;

598 599 600
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
601 602 603 604

  if (real == NULL)
    return 0;

605 606
  check_invariants (iter);
  
607 608
  if (real->cached_char_index < 0)
    {
609 610
      ensure_char_offsets (real);
      
611
      real->cached_char_index =
612
        _gtk_text_line_char_index (real->line);
613 614 615
      real->cached_char_index += real->line_char_offset;
    }

616 617
  check_invariants (iter);

618 619 620
  return real->cached_char_index;
}

621 622 623
/**
 * gtk_text_iter_get_line:
 * @iter: an iterator
624
 *
625 626 627
 * Returns the line number containing the iterator. Lines in
 * a #GtkTextBuffer are numbered beginning with 0 for the first
 * line in the buffer.
628
 *
629
 * Returns: a line number
630
 **/
631
gint
632
gtk_text_iter_get_line (const GtkTextIter *iter)
633 634 635
{
  GtkTextRealIter *real;

636 637 638
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
639 640 641 642 643 644

  if (real == NULL)
    return 0;

  if (real->cached_line_number < 0)
    real->cached_line_number =
645
      _gtk_text_line_get_number (real->line);
646 647

  check_invariants (iter);
648 649 650 651

  return real->cached_line_number;
}

652 653 654
/**
 * gtk_text_iter_get_line_offset:
 * @iter: an iterator
655
 *
656 657 658
 * 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.
659
 *
660
 * Returns: offset from start of line
661
 **/
662
gint
663
gtk_text_iter_get_line_offset (const GtkTextIter *iter)
664 665 666
{
  GtkTextRealIter *real;

667 668 669
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
670 671 672 673

  if (real == NULL)
    return 0;

674 675 676
  ensure_char_offsets (real);

  check_invariants (iter);
677 678 679 680

  return real->line_char_offset;
}

681 682 683
/**
 * gtk_text_iter_get_line_index:
 * @iter: an iterator
684
 *
685 686 687 688 689
 * 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.
690
 *
691
 * Returns: distance from start of line, in bytes
692
 **/
693
gint
694
gtk_text_iter_get_line_index (const GtkTextIter *iter)
695 696
{
  GtkTextRealIter *real;
697
  
698 699 700
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
701 702 703 704

  if (real == NULL)
    return 0;

705 706 707
  ensure_byte_offsets (real);

  check_invariants (iter);
708 709 710 711

  return real->line_byte_offset;
}

712 713 714 715 716 717
/**
 * 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
718
 * are invisible due to tags with the “invisible” flag
719 720
 * toggled on.
 * 
721
 * Returns: offset in visible characters from the start of the line 
722
 **/
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
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);
741
  
742 743
  vis_offset = real->line_char_offset;

744 745
  g_assert (vis_offset >= 0);
  
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
  _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;
}

776 777 778 779 780 781 782

/**
 * 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
783
 * are invisible due to tags with the “invisible” flag
784 785
 * toggled on.
 * 
786
 * Returns: byte index of @iter with respect to the start of the line
787
 **/
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
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;

803
  ensure_byte_offsets (real);
804 805 806 807 808

  check_invariants (iter);

  vis_offset = real->line_byte_offset;

809 810
  g_assert (vis_offset >= 0);
  
811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
  _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;
}

841 842 843 844
/*
 * Dereferencing
 */

845 846 847
/**
 * gtk_text_iter_get_char:
 * @iter: an iterator
848
 *
Sébastien Wilmet's avatar
Sébastien Wilmet committed
849
 * The Unicode character at this iterator is returned.  (Equivalent to
850
 * operator* on a C++ iterator.)  If the element at this iterator is a
851
 * non-character element, such as an image embedded in the buffer, the
852
 * Unicode “unknown” character 0xFFFC is returned. If invoked on
853
 * the end iterator, zero is returned; zero is not a valid Unicode character.
Sébastien Wilmet's avatar
Sébastien Wilmet committed
854
 * So you can write a loop which ends when gtk_text_iter_get_char()
855
 * returns 0.
856
 *
Sébastien Wilmet's avatar
Sébastien Wilmet committed
857 858
 * Returns: a Unicode character, or 0 if @iter is not dereferenceable
 */
859
gunichar
860
gtk_text_iter_get_char (const GtkTextIter *iter)
861 862 863
{
  GtkTextRealIter *real;

864 865 866
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);
867 868 869 870

  if (real == NULL)
    return 0;

871
  check_invariants (iter);
872

873
  if (gtk_text_iter_is_end (iter))
874 875
    return 0;
  else if (real->segment->type == &gtk_text_char_type)
876
    {
877
      ensure_byte_offsets (real);
878
      
879 880
      return g_utf8_get_char (real->segment->body.chars +
                              real->segment_byte_offset);
881 882 883
    }
  else
    {
884 885
      /* Unicode "unknown character" 0xFFFC */
      return GTK_TEXT_UNKNOWN_CHAR;
886 887 888
    }
}

889 890 891 892
/**
 * gtk_text_iter_get_slice:
 * @start: iterator at start of a range
 * @end: iterator at end of a range
893
 *
894 895
 * Returns the text in the given range. A “slice” is an array of
 * characters encoded in UTF-8 format, including the Unicode “unknown”
896
 * character 0xFFFC for iterable non-character elements in the buffer,
897 898
 * such as images.  Because images are encoded in the slice, byte and
 * character offsets in the returned array will correspond to byte
899
 * offsets in the text buffer. Note that 0xFFFC can occur in normal
900 901
 * text as well, so it is not a reliable indicator that a pixbuf or
 * widget is in the buffer.
902
 *
903
 * Returns: (transfer full): slice of text from the buffer
904
 **/
905 906
gchar*
gtk_text_iter_get_slice       (const GtkTextIter *start,
907
                               const GtkTextIter *end)
908
{
909 910 911 912 913
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);
914

915
  return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
916 917
}

918 919 920 921
/**
 * gtk_text_iter_get_text:
 * @start: iterator at start of a range
 * @end: iterator at end of a range
922
 *
923
 * Returns text in the given range.  If the range
924 925 926
 * 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
927
 * gtk_text_iter_get_slice().
928
 *
929
 * Returns: (transfer full): array of characters from the buffer
930
 **/
931 932
gchar*
gtk_text_iter_get_text       (const GtkTextIter *start,
933
                              const GtkTextIter *end)
934
{
935 936 937 938 939
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);
940

941
  return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
942 943
}

944 945 946 947
/**
 * gtk_text_iter_get_visible_slice:
 * @start: iterator at start of range
 * @end: iterator at end of range
948
 *
949
 * Like gtk_text_iter_get_slice(), but invisible text is not included.
950
 * Invisible text is usually invisible because a #GtkTextTag with the
951
 * “invisible” attribute turned on has been applied to it.
952
 *
953
 * Returns: (transfer full): slice of text from the buffer
954
 **/
955 956
gchar*
gtk_text_iter_get_visible_slice (const GtkTextIter  *start,
957
                                 const GtkTextIter  *end)
958
{
959 960
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);
961

962 963 964
  check_invariants (start);
  check_invariants (end);

965
  return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
966 967
}

968 969 970 971
/**
 * gtk_text_iter_get_visible_text:
 * @start: iterator at start of range
 * @end: iterator at end of range
972
 *
973
 * Like gtk_text_iter_get_text(), but invisible text is not included.
974
 * Invisible text is usually invisible because a #GtkTextTag with the
975
 * “invisible” attribute turned on has been applied to it.
976
 *
977 978
 * Returns: (transfer full): string containing visible text in the
 * range
979
 **/
980 981
gchar*
gtk_text_iter_get_visible_text (const GtkTextIter  *start,
982
                                const GtkTextIter  *end)
983
{
984 985 986 987 988 989
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);

990
  return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
991 992
}

993
/**
Havoc Pennington's avatar
Havoc Pennington committed
994
 * gtk_text_iter_get_pixbuf:
995
 * @iter: an iterator
996
 *
997 998
 * If the element at @iter is a pixbuf, the pixbuf is returned
 * (with no new reference count added). Otherwise,
999
 * %NULL is returned.
1000
 *
1001
 * Returns: (transfer none): the pixbuf at @iter
1002
 **/
Havoc Pennington's avatar
Havoc Pennington committed
1003 1004
GdkPixbuf*
gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
1005 1006 1007
{
  GtkTextRealIter *real;

1008
  g_return_val_if_fail (iter != NULL, NULL);
1009 1010

  real = gtk_text_iter_make_real (iter);
1011 1012

  if (real == NULL)
1013
    return NULL;
1014 1015 1016

  check_invariants (iter);

Havoc Pennington's avatar
Havoc Pennington committed
1017
  if (real->segment->type != &gtk_text_pixbuf_type)
1018
    return NULL;
1019
  else
Havoc Pennington's avatar
Havoc Pennington committed
1020
    return real->segment->body.pixbuf.pixbuf;
1021 1022
}

1023 1024 1025 1026
/**
 * gtk_text_iter_get_child_anchor:
 * @iter: an iterator
 *
1027
 * If the location at @iter contains a child anchor, the
1028
 * anchor is returned (with no new reference count added). Otherwise,
1029
 * %NULL is returned.
1030
 *
1031
 * Returns: (transfer none): the anchor at @iter
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052
 **/
GtkTextChildAnchor*
gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
{
  GtkTextRealIter *real;

  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_real (iter);

  if (real == NULL)
    return NULL;

  check_invariants (iter);

  if (real->segment->type != &gtk_text_child_type)
    return NULL;
  else
    return real->segment->body.child.obj;
}

1053 1054 1055
/**
 * gtk_text_iter_get_marks:
 * @iter: an iterator
1056
 *
1057
 * Returns a list of all #GtkTextMark at this location. Because marks
1058
 * are not iterable (they don’t take up any "space" in the buffer,
1059 1060 1061
 * they are just marks in between iterable locations), multiple marks
 * can exist in the same place. The returned list is not in any
 * meaningful order.
1062
 *
1063
 * Returns: (element-type GtkTextMark) (transfer container): list of #GtkTextMark
1064
 **/
1065 1066 1067 1068 1069 1070
GSList*
gtk_text_iter_get_marks (const GtkTextIter *iter)
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
  GSList *retval;
1071 1072 1073 1074

  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_real (iter);
1075 1076 1077 1078

  if (real == NULL)
    return NULL;

1079 1080
  check_invariants (iter);

1081 1082 1083 1084 1085 1086
  retval = NULL;
  seg = real->any_segment;
  while (seg != real->segment)
    {
      if (seg->type == &gtk_text_left_mark_type ||
          seg->type == &gtk_text_right_mark_type)
1087
        retval = g_slist_prepend (retval, seg->body.mark.obj);
1088

1089 1090 1091 1092 1093 1094 1095 1096
      seg = seg->next;
    }

  /* The returned list isn't guaranteed to be in any special order,
     and it isn't. */
  return retval;
}

1097 1098 1099
/**
 * gtk_text_iter_get_toggled_tags:
 * @iter: an iterator
1100
 * @toggled_on: %TRUE to get toggled-on tags
1101
 *
1102
 * Returns a list of #GtkTextTag that are toggled on or off at this
1103
 * point.  (If @toggled_on is %TRUE, the list contains tags that are
1104 1105 1106
 * toggled on.) If a tag is toggled on at @iter, then some non-empty
 * range of characters following @iter has that tag applied to it.  If
 * a tag is toggled off, then some non-empty range following @iter
1107
 * does not have the tag applied to it.
1108
 *
1109
 * Returns: (element-type GtkTextTag) (transfer container): tags toggled at this point
1110
 **/
1111 1112
GSList*
gtk_text_iter_get_toggled_tags  (const GtkTextIter  *iter,
1113
                                 gboolean            toggled_on)
1114 1115 1116 1117
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
  GSList *retval;
1118 1119 1120 1121

  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_real (iter);
1122 1123 1124 1125

  if (real == NULL)
    return NULL;

1126 1127
  check_invariants (iter);

1128 1129 1130 1131 1132 1133 1134 1135
  retval = NULL;
  seg = real->any_segment;
  while (seg != real->segment)
    {
      if (toggled_on)
        {
          if (seg->type == &gtk_text_toggle_on_type)
            {
1136
              retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1137 1138 1139 1140 1141 1142
            }
        }
      else
        {
          if (seg->type == &gtk_text_toggle_off_type)
            {
1143
              retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1144 1145
            }
        }
1146

1147 1148 1149 1150 1151 1152 1153 1154
      seg = seg->next;
    }

  /* The returned list isn't guaranteed to be in any special order,
     and it isn't. */
  return retval;
}

1155
/**
1156
 * gtk_text_iter_starts_tag:
1157
 * @iter: an iterator
1158
 * @tag: (nullable): a #GtkTextTag, or %NULL
1159
 *
1160
 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1161 1162
 * is %NULL, returns %TRUE if any tag is toggled on at this point.
 *
1163
 * Note that if gtk_text_iter_starts_tag() returns %TRUE, it means that @iter is
1164
 * at the beginning of the tagged range, and that the
1165
 * character at @iter is inside the tagged range. In other
1166
 * words, unlike gtk_text_iter_ends_tag(), if gtk_text_iter_starts_tag() returns
1167 1168
 * %TRUE, gtk_text_iter_has_tag() will also return %TRUE for the same
 * parameters.
1169
 *
1170
 * Returns: whether @iter is the start of a range tagged with @tag
1171
 * Since: 3.20
1172
 **/
1173
gboolean
1174 1175
gtk_text_iter_starts_tag (const GtkTextIter *iter,
                          GtkTextTag        *tag)
1176 1177 1178
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
1179 1180 1181 1182

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1183 1184 1185 1186

  if (real == NULL)
    return FALSE;

1187 1188
  check_invariants (iter);

1189 1190 1191 1192 1193 1194 1195 1196 1197
  seg = real->any_segment;
  while (seg != real->segment)
    {
      if (seg->type == &gtk_text_toggle_on_type)
        {
          if (tag == NULL ||
              seg->body.toggle.info->tag == tag)
            return TRUE;
        }
1198

1199 1200 1201 1202 1203 1204
      seg = seg->next;
    }

  return FALSE;
}

1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229
/**
 * gtk_text_iter_begins_tag:
 * @iter: an iterator
 * @tag: (nullable): a #GtkTextTag, or %NULL
 *
 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
 * is %NULL, returns %TRUE if any tag is toggled on at this point.
 *
 * Note that if gtk_text_iter_begins_tag() returns %TRUE, it means that @iter is
 * at the beginning of the tagged range, and that the
 * character at @iter is inside the tagged range. In other
 * words, unlike gtk_text_iter_ends_tag(), if gtk_text_iter_begins_tag() returns
 * %TRUE, gtk_text_iter_has_tag() will also return %TRUE for the same
 * parameters.
 *
 * Returns: whether @iter is the start of a range tagged with @tag
 * Deprecated: 3.20: Use gtk_text_iter_starts_tag() instead.
 **/
gboolean
gtk_text_iter_begins_tag (const GtkTextIter *iter,
                          GtkTextTag        *tag)
{
  return gtk_text_iter_starts_tag (iter, tag);
}

1230 1231 1232
/**
 * gtk_text_iter_ends_tag:
 * @iter: an iterator
1233
 * @tag: (allow-none): a #GtkTextTag, or %NULL
1234
 *
1235
 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1236
 * is %NULL, returns %TRUE if any tag is toggled off at this point.
1237
 *
1238
 * Note that if gtk_text_iter_ends_tag() returns %TRUE, it means that @iter is
1239 1240
 * at the end of the tagged range, but that the character
 * at @iter is outside the tagged range. In other words,
1241
 * unlike gtk_text_iter_starts_tag(), if gtk_text_iter_ends_tag() returns %TRUE,
1242
 * gtk_text_iter_has_tag() will return %FALSE for the same parameters.
1243
 *
1244
 * Returns: whether @iter is the end of a range tagged with @tag
1245
 **/
1246 1247
gboolean
gtk_text_iter_ends_tag   (const GtkTextIter  *iter,
1248
                          GtkTextTag         *tag)
1249 1250 1251
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
1252 1253 1254 1255

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1256 1257 1258 1259

  if (real == NULL)
    return FALSE;

1260 1261
  check_invariants (iter);

1262 1263 1264 1265 1266 1267 1268 1269 1270
  seg = real->any_segment;
  while (seg != real->segment)
    {
      if (seg->type == &gtk_text_toggle_off_type)
        {
          if (tag == NULL ||
              seg->body.toggle.info->tag == tag)
            return TRUE;
        }
1271

1272 1273 1274 1275 1276 1277
      seg = seg->next;
    }

  return FALSE;
}

1278 1279 1280
/**
 * gtk_text_iter_toggles_tag:
 * @iter: an iterator
1281
 * @tag: (allow-none): a #GtkTextTag, or %NULL
1282
 *
1283
 * This is equivalent to (gtk_text_iter_starts_tag() ||
1284
 * gtk_text_iter_ends_tag()), i.e. it tells you whether a range with
1285
 * @tag applied to it begins or ends at @iter.
1286
 *
1287
 * Returns: whether @tag is toggled on or off at @iter
1288
 **/
1289
gboolean
1290 1291
gtk_text_iter_toggles_tag (const GtkTextIter  *iter,
                           GtkTextTag         *tag)
1292 1293 1294
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
1295 1296 1297 1298

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1299 1300 1301 1302

  if (real == NULL)
    return FALSE;

1303 1304
  check_invariants (iter);

1305 1306 1307 1308 1309 1310 1311 1312
  seg = real->any_segment;
  while (seg != real->segment)
    {
      if ( (seg->type == &gtk_text_toggle_off_type ||
            seg->type == &gtk_text_toggle_on_type) &&
           (tag == NULL ||
            seg->body.toggle.info->tag == tag) )
        return TRUE;
1313

1314 1315 1316 1317 1318 1319
      seg = seg->next;
    }

  return FALSE;
}

1320 1321 1322 1323
/**
 * gtk_text_iter_has_tag:
 * @iter: an iterator
 * @tag: a #GtkTextTag
1324
 *
1325
 * Returns %TRUE if @iter points to a character that is part of a range tagged
1326
 * with @tag. See also gtk_text_iter_starts_tag() and gtk_text_iter_ends_tag().
1327
 *
1328
 * Returns: whether @iter is tagged with @tag
1329
 **/
1330
gboolean
1331 1332
gtk_text_iter_has_tag (const GtkTextIter   *iter,
                       GtkTextTag          *tag)
1333 1334
{
  GtkTextRealIter *real;
1335 1336 1337 1338 1339

  g_return_val_if_fail (iter != NULL, FALSE);
  g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);

  real = gtk_text_iter_make_surreal (iter);
1340 1341

  if (real == NULL)
1342 1343 1344
    return FALSE;

  check_invariants (iter);
1345 1346 1347

  if (real->line_byte_offset >= 0)
    {
1348
      return _gtk_text_line_byte_has_tag (real->line, real->tree,
1349
                                          real->line_byte_offset, tag);
1350 1351 1352
    }
  else
    {
1353
      g_assert (real->line_char_offset >= 0);
1354
      return _gtk_text_line_char_has_tag (real->line, real->tree,
1355
                                          real->line_char_offset, tag);
1356 1357 1358
    }
}

1359 1360 1361 1362 1363 1364
/**
 * gtk_text_iter_get_tags:
 * @iter: a #GtkTextIter
 * 
 * Returns a list of tags that apply to @iter, in ascending order of
 * priority (highest-priority tags are last). The #GtkTextTag in the
1365
 * list don’t have a reference added, but you have to free the list
1366
 * itself.
1367
 *
1368
 * Returns: (element-type GtkTextTag) (transfer container): list of #GtkTextTag
1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380
 **/
GSList*
gtk_text_iter_get_tags (const GtkTextIter *iter)
{
  GtkTextTag** tags;
  gint tag_count = 0;
  gint i;
  GSList *retval;
  
  g_return_val_if_fail (iter != NULL, NULL);
  
  /* Get the tags at this spot */
1381
  tags = _gtk_text_btree_get_tags (iter, &tag_count);
1382 1383 1384 1385

  /* No tags, use default style */
  if (tags == NULL || tag_count == 0)
    {