hb-buffer.cc 22.4 KB
Newer Older
1
/*
B
Behdad Esfahbod 已提交
2 3
 * Copyright © 1998-2004  David Turner and Werner Lemberg
 * Copyright © 2004,2007,2009,2010  Red Hat, Inc.
4
 * Copyright © 2011,2012  Google, Inc.
5
 *
6
 *  This is part of HarfBuzz, a text shaping library.
7
 *
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
27
 * Google Author(s): Behdad Esfahbod
28 29
 */

30
#include "hb-buffer-private.hh"
31
#include "hb-utf-private.hh"
32

33

B
Behdad Esfahbod 已提交
34 35 36 37
#ifndef HB_DEBUG_BUFFER
#define HB_DEBUG_BUFFER (HB_DEBUG+0)
#endif

38 39
/* Here is how the buffer works internally:
 *
B
Behdad Esfahbod 已提交
40 41
 * There are two info pointers: info and out_info.  They always have
 * the same allocated size, but different lengths.
42
 *
43
 * As an optimization, both info and out_info may point to the
44
 * same piece of memory, which is owned by info.  This remains the
45
 * case as long as out_len doesn't exceed i at any time.
46
 * In that case, swap_buffers() is no-op and the glyph operations operate
B
Behdad Esfahbod 已提交
47
 * mostly in-place.
48
 *
49
 * As soon as out_info gets longer than info, out_info is moved over
B
Behdad Esfahbod 已提交
50 51
 * to an alternate buffer (which we reuse the pos buffer for!), and its
 * current contents (out_len entries) are copied to the new place.
52
 * This should all remain transparent to the user.  swap_buffers() then
B
Behdad Esfahbod 已提交
53
 * switches info and out_info.
54 55
 */

B
Behdad Esfahbod 已提交
56

57 58 59 60 61

/* Internal API */

bool
hb_buffer_t::enlarge (unsigned int size)
62
{
63
  if (unlikely (in_error))
64
    return false;
65

66
  unsigned int new_allocated = allocated;
B
Behdad Esfahbod 已提交
67 68
  hb_glyph_position_t *new_pos = NULL;
  hb_glyph_info_t *new_info = NULL;
69
  bool separate_out = out_info != info;
70

71
  if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
B
Behdad Esfahbod 已提交
72
    goto done;
73

74
  while (size >= new_allocated)
75
    new_allocated += (new_allocated >> 1) + 32;
76

77 78
  ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
  if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
B
Behdad Esfahbod 已提交
79 80
    goto done;

81 82
  new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
  new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
83

B
Behdad Esfahbod 已提交
84
done:
85
  if (unlikely (!new_pos || !new_info))
86
    in_error = true;
87 88

  if (likely (new_pos))
89
    pos = new_pos;
90 91

  if (likely (new_info))
92 93 94 95 96 97 98 99 100 101 102 103 104
    info = new_info;

  out_info = separate_out ? (hb_glyph_info_t *) pos : info;
  if (likely (!in_error))
    allocated = new_allocated;

  return likely (!in_error);
}

bool
hb_buffer_t::make_room_for (unsigned int num_in,
			    unsigned int num_out)
{
105
  if (unlikely (!ensure (out_len + num_out))) return false;
106 107 108 109 110 111 112 113 114 115

  if (out_info == info &&
      out_len + num_out > idx + num_in)
  {
    assert (have_output);

    out_info = (hb_glyph_info_t *) pos;
    memcpy (out_info, info, out_len * sizeof (out_info[0]));
  }

116
  return true;
117 118
}

119 120 121
void *
hb_buffer_t::get_scratch_buffer (unsigned int *size)
{
122 123
  have_output = false;
  have_positions = false;
124

125
  out_len = 0;
126 127
  out_info = info;

128 129 130 131
  *size = allocated * sizeof (pos[0]);
  return pos;
}

132

B
Behdad Esfahbod 已提交
133

134 135 136 137 138 139 140 141 142
/* HarfBuzz-Internal API */

void
hb_buffer_t::reset (void)
{
  if (unlikely (hb_object_is_inert (this)))
    return;

  hb_unicode_funcs_destroy (unicode);
143
  unicode = hb_unicode_funcs_get_default ();
144

145 146
  hb_segment_properties_t default_props = _HB_BUFFER_PROPS_DEFAULT;
  props = default_props;
147

148
  content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
149 150 151
  in_error = false;
  have_output = false;
  have_positions = false;
152

153 154 155
  idx = 0;
  len = 0;
  out_len = 0;
156
  out_info = info;
157

158
  serial = 0;
159 160
  memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
  memset (allocated_var_owner, 0, sizeof allocated_var_owner);
161 162 163

  memset (context, 0, sizeof context);
  memset (context_len, 0, sizeof context_len);
164 165
}

166 167 168 169
void
hb_buffer_t::add (hb_codepoint_t  codepoint,
		  hb_mask_t       mask,
		  unsigned int    cluster)
170
{
171 172 173 174 175 176 177 178 179 180 181 182
  hb_glyph_info_t *glyph;

  if (unlikely (!ensure (len + 1))) return;

  glyph = &info[len];

  memset (glyph, 0, sizeof (*glyph));
  glyph->codepoint = codepoint;
  glyph->mask = mask;
  glyph->cluster = cluster;

  len++;
183
}
184

B
Behdad Esfahbod 已提交
185 186 187 188 189 190 191 192 193 194 195 196 197
void
hb_buffer_t::remove_output (void)
{
  if (unlikely (hb_object_is_inert (this)))
    return;

  have_output = false;
  have_positions = false;

  out_len = 0;
  out_info = info;
}

198 199
void
hb_buffer_t::clear_output (void)
B
Behdad Esfahbod 已提交
200
{
201 202 203
  if (unlikely (hb_object_is_inert (this)))
    return;

204 205
  have_output = true;
  have_positions = false;
206

207 208 209 210 211 212 213 214 215 216
  out_len = 0;
  out_info = info;
}

void
hb_buffer_t::clear_positions (void)
{
  if (unlikely (hb_object_is_inert (this)))
    return;

217 218
  have_output = false;
  have_positions = true;
219

220 221 222
  out_len = 0;
  out_info = info;

223 224 225 226 227 228 229 230 231
  memset (pos, 0, sizeof (pos[0]) * len);
}

void
hb_buffer_t::swap_buffers (void)
{
  if (unlikely (in_error)) return;

  assert (have_output);
232
  have_output = false;
233 234

  if (out_info != info)
235
  {
236 237 238 239 240 241 242 243 244 245 246 247 248 249
    hb_glyph_info_t *tmp_string;
    tmp_string = info;
    info = out_info;
    out_info = tmp_string;
    pos = (hb_glyph_position_t *) out_info;
  }

  unsigned int tmp;
  tmp = len;
  len = out_len;
  out_len = tmp;

  idx = 0;
}
250

B
Behdad Esfahbod 已提交
251

B
Behdad Esfahbod 已提交
252 253 254
void
hb_buffer_t::replace_glyphs (unsigned int num_in,
			     unsigned int num_out,
B
Minor  
Behdad Esfahbod 已提交
255
			     const uint32_t *glyph_data)
B
Behdad Esfahbod 已提交
256
{
B
Behdad Esfahbod 已提交
257
  if (unlikely (!make_room_for (num_in, num_out))) return;
B
Behdad Esfahbod 已提交
258

259
  merge_clusters (idx, idx + num_in);
B
Behdad Esfahbod 已提交
260

261
  hb_glyph_info_t orig_info = info[idx];
B
Behdad Esfahbod 已提交
262 263 264 265 266 267 268 269 270 271 272 273
  hb_glyph_info_t *pinfo = &out_info[out_len];
  for (unsigned int i = 0; i < num_out; i++)
  {
    *pinfo = orig_info;
    pinfo->codepoint = glyph_data[i];
    pinfo++;
  }

  idx  += num_in;
  out_len += num_out;
}

274 275 276
void
hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
{
B
Behdad Esfahbod 已提交
277
  if (unlikely (!make_room_for (0, 1))) return;
278 279 280 281 282 283 284

  out_info[out_len] = info[idx];
  out_info[out_len].codepoint = glyph_index;

  out_len++;
}

285 286 287 288 289 290 291 292 293 294
void
hb_buffer_t::output_info (hb_glyph_info_t &glyph_info)
{
  if (unlikely (!make_room_for (0, 1))) return;

  out_info[out_len] = glyph_info;

  out_len++;
}

295 296 297
void
hb_buffer_t::copy_glyph (void)
{
B
Behdad Esfahbod 已提交
298
  if (unlikely (!make_room_for (0, 1))) return;
299 300 301 302 303 304 305 306 307

  out_info[out_len] = info[idx];

  out_len++;
}

void
hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
{
B
Behdad Esfahbod 已提交
308 309 310 311
  if (unlikely (out_info != info || out_len != idx)) {
    if (unlikely (!make_room_for (1, 1))) return;
    out_info[out_len] = info[idx];
  }
312 313 314 315 316 317
  out_info[out_len].codepoint = glyph_index;

  idx++;
  out_len++;
}

B
Behdad Esfahbod 已提交
318

319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
void
hb_buffer_t::set_masks (hb_mask_t    value,
			hb_mask_t    mask,
			unsigned int cluster_start,
			unsigned int cluster_end)
{
  hb_mask_t not_mask = ~mask;
  value &= mask;

  if (!mask)
    return;

  if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
    unsigned int count = len;
    for (unsigned int i = 0; i < count; i++)
      info[i].mask = (info[i].mask & not_mask) | value;
    return;
  }

  unsigned int count = len;
  for (unsigned int i = 0; i < count; i++)
    if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
      info[i].mask = (info[i].mask & not_mask) | value;
}

void
hb_buffer_t::reverse_range (unsigned int start,
			    unsigned int end)
{
  unsigned int i, j;

  if (start == end - 1)
    return;

  for (i = start, j = end - 1; i < j; i++, j--) {
    hb_glyph_info_t t;

    t = info[i];
    info[i] = info[j];
    info[j] = t;
  }

  if (pos) {
    for (i = start, j = end - 1; i < j; i++, j--) {
      hb_glyph_position_t t;

      t = pos[i];
      pos[i] = pos[j];
      pos[j] = t;
    }
  }
}

void
hb_buffer_t::reverse (void)
{
  if (unlikely (!len))
    return;

  reverse_range (0, len);
}

void
hb_buffer_t::reverse_clusters (void)
{
  unsigned int i, start, count, last_cluster;

  if (unlikely (!len))
    return;

  reverse ();

  count = len;
  start = 0;
  last_cluster = info[0].cluster;
  for (i = 1; i < count; i++) {
    if (last_cluster != info[i].cluster) {
      reverse_range (start, i);
      start = i;
      last_cluster = info[i].cluster;
    }
  }
  reverse_range (start, i);
402 403
}

404 405 406 407
void
hb_buffer_t::merge_clusters (unsigned int start,
			     unsigned int end)
{
B
Minor  
Behdad Esfahbod 已提交
408
  if (unlikely (end - start < 2))
409 410 411
    return;

  unsigned int cluster = info[start].cluster;
412 413

  for (unsigned int i = start + 1; i < end; i++)
414 415 416 417 418 419
    cluster = MIN (cluster, info[i].cluster);

  /* Extend end */
  while (end < len && info[end - 1].cluster == info[end].cluster)
    end++;

420 421 422 423 424 425 426 427 428
  /* Extend start */
  while (idx < start && info[start - 1].cluster == info[start].cluster)
    start--;

  /* If we hit the start of buffer, continue in out-buffer. */
  if (idx == start)
    for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
      out_info[i - 1].cluster = cluster;

429
  for (unsigned int i = start; i < end; i++)
430
    info[i].cluster = cluster;
431 432 433 434 435
}
void
hb_buffer_t::merge_out_clusters (unsigned int start,
				 unsigned int end)
{
B
Minor  
Behdad Esfahbod 已提交
436
  if (unlikely (end - start < 2))
437 438
    return;

439
  unsigned int cluster = out_info[start].cluster;
440 441

  for (unsigned int i = start + 1; i < end; i++)
442
    cluster = MIN (cluster, out_info[i].cluster);
443 444 445 446 447

  /* Extend start */
  while (start && out_info[start - 1].cluster == out_info[start].cluster)
    start--;

448 449 450 451
  /* Extend end */
  while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)
    end++;

452 453 454 455 456
  /* If we hit the end of out-buffer, continue in buffer. */
  if (end == out_len)
    for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
      info[i].cluster = cluster;

457
  for (unsigned int i = start; i < end; i++)
458
    out_info[i].cluster = cluster;
459 460
}

461 462 463
void
hb_buffer_t::guess_properties (void)
{
464 465 466
  if (unlikely (!len)) return;
  assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);

467 468 469
  /* If script is set to INVALID, guess from buffer contents */
  if (props.script == HB_SCRIPT_INVALID) {
    for (unsigned int i = 0; i < len; i++) {
470
      hb_script_t script = unicode->script (info[i].codepoint);
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
      if (likely (script != HB_SCRIPT_COMMON &&
		  script != HB_SCRIPT_INHERITED &&
		  script != HB_SCRIPT_UNKNOWN)) {
        props.script = script;
        break;
      }
    }
  }

  /* If direction is set to INVALID, guess from script */
  if (props.direction == HB_DIRECTION_INVALID) {
    props.direction = hb_script_get_horizontal_direction (props.script);
  }

  /* If language is not set, use default language from locale */
  if (props.language == HB_LANGUAGE_INVALID) {
    /* TODO get_default_for_script? using $LANGUAGE */
    props.language = hb_language_get_default ();
  }
}


B
Behdad Esfahbod 已提交
493 494 495 496 497
static inline void
dump_var_allocation (const hb_buffer_t *buffer)
{
  char buf[80];
  for (unsigned int i = 0; i < 8; i++)
498
    buf[i] = '0' + buffer->allocated_var_bytes[7 - i];
B
Behdad Esfahbod 已提交
499 500 501 502 503
  buf[8] = '\0';
  DEBUG_MSG (BUFFER, buffer,
	     "Current var allocation: %s",
	     buf);
}
504

505 506
void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner)
{
507
  assert (byte_i < 8 && byte_i + count <= 8);
B
Behdad Esfahbod 已提交
508 509 510 511 512 513 514

  if (DEBUG (BUFFER))
    dump_var_allocation (this);
  DEBUG_MSG (BUFFER, this,
	     "Allocating var bytes %d..%d for %s",
	     byte_i, byte_i + count - 1, owner);

515 516 517 518 519 520 521 522 523
  for (unsigned int i = byte_i; i < byte_i + count; i++) {
    assert (!allocated_var_bytes[i]);
    allocated_var_bytes[i]++;
    allocated_var_owner[i] = owner;
  }
}

void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
{
524 525 526
  if (DEBUG (BUFFER))
    dump_var_allocation (this);

B
Behdad Esfahbod 已提交
527 528 529 530
  DEBUG_MSG (BUFFER, this,
	     "Deallocating var bytes %d..%d for %s",
	     byte_i, byte_i + count - 1, owner);

531
  assert (byte_i < 8 && byte_i + count <= 8);
532
  for (unsigned int i = byte_i; i < byte_i + count; i++) {
533 534
    assert (allocated_var_bytes[i]);
    assert (0 == strcmp (allocated_var_owner[i], owner));
535 536 537 538
    allocated_var_bytes[i]--;
  }
}

B
Behdad Esfahbod 已提交
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner)
{
  if (DEBUG (BUFFER))
    dump_var_allocation (this);

  DEBUG_MSG (BUFFER, this,
	     "Asserting var bytes %d..%d for %s",
	     byte_i, byte_i + count - 1, owner);

  assert (byte_i < 8 && byte_i + count <= 8);
  for (unsigned int i = byte_i; i < byte_i + count; i++) {
    assert (allocated_var_bytes[i]);
    assert (0 == strcmp (allocated_var_owner[i], owner));
  }
}

B
Behdad Esfahbod 已提交
555 556 557 558 559
void hb_buffer_t::deallocate_var_all (void)
{
  memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
  memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
}
560

561 562
/* Public API */

563
hb_buffer_t *
564
hb_buffer_create ()
565
{
566 567
  hb_buffer_t *buffer;

568
  if (!(buffer = hb_object_create<hb_buffer_t> ()))
569
    return hb_buffer_get_empty ();
570

571
  buffer->reset ();
B
Behdad Esfahbod 已提交
572

573 574
  return buffer;
}
B
Behdad Esfahbod 已提交
575

576 577 578
hb_buffer_t *
hb_buffer_get_empty (void)
{
579 580 581
  static const hb_buffer_t _hb_buffer_nil = {
    HB_OBJECT_HEADER_STATIC,

582
    const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
583 584
    _HB_BUFFER_PROPS_DEFAULT,

585
    HB_BUFFER_CONTENT_TYPE_INVALID,
586 587 588
    true, /* in_error */
    true, /* have_output */
    true  /* have_positions */
589 590

    /* Zero is good enough for everything else. */
591 592 593
  };

  return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
594 595
}

596 597 598
hb_buffer_t *
hb_buffer_reference (hb_buffer_t *buffer)
{
599
  return hb_object_reference (buffer);
600
}
B
Behdad Esfahbod 已提交
601

B
Behdad Esfahbod 已提交
602
void
603
hb_buffer_destroy (hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
604
{
605
  if (!hb_object_destroy (buffer)) return;
606

B
Behdad Esfahbod 已提交
607 608
  hb_unicode_funcs_destroy (buffer->unicode);

609
  free (buffer->info);
610
  free (buffer->pos);
611

612
  free (buffer);
B
Behdad Esfahbod 已提交
613 614
}

615 616 617 618
hb_bool_t
hb_buffer_set_user_data (hb_buffer_t        *buffer,
			 hb_user_data_key_t *key,
			 void *              data,
619 620
			 hb_destroy_func_t   destroy,
			 hb_bool_t           replace)
621
{
622
  return hb_object_set_user_data (buffer, key, data, destroy, replace);
623 624 625 626 627 628 629 630 631
}

void *
hb_buffer_get_user_data (hb_buffer_t        *buffer,
			 hb_user_data_key_t *key)
{
  return hb_object_get_user_data (buffer, key);
}

B
Behdad Esfahbod 已提交
632

633 634 635 636 637 638 639 640 641 642 643 644 645 646
void
hb_buffer_set_content_type (hb_buffer_t              *buffer,
			    hb_buffer_content_type_t  content_type)
{
  buffer->content_type = content_type;
}

hb_buffer_content_type_t
hb_buffer_get_content_type (hb_buffer_t *buffer)
{
  return buffer->content_type;
}


B
Behdad Esfahbod 已提交
647 648 649 650
void
hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
			     hb_unicode_funcs_t *unicode)
{
B
Behdad Esfahbod 已提交
651 652 653
  if (unlikely (hb_object_is_inert (buffer)))
    return;

B
Behdad Esfahbod 已提交
654
  if (!unicode)
655 656
    unicode = hb_unicode_funcs_get_default ();

B
Behdad Esfahbod 已提交
657

B
Behdad Esfahbod 已提交
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
  hb_unicode_funcs_reference (unicode);
  hb_unicode_funcs_destroy (buffer->unicode);
  buffer->unicode = unicode;
}

hb_unicode_funcs_t *
hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
{
  return buffer->unicode;
}

void
hb_buffer_set_direction (hb_buffer_t    *buffer,
			 hb_direction_t  direction)

{
B
Behdad Esfahbod 已提交
674 675 676
  if (unlikely (hb_object_is_inert (buffer)))
    return;

677
  buffer->props.direction = direction;
B
Behdad Esfahbod 已提交
678 679 680 681 682
}

hb_direction_t
hb_buffer_get_direction (hb_buffer_t    *buffer)
{
683
  return buffer->props.direction;
B
Behdad Esfahbod 已提交
684 685
}

686 687 688 689
void
hb_buffer_set_script (hb_buffer_t *buffer,
		      hb_script_t  script)
{
B
Behdad Esfahbod 已提交
690 691 692
  if (unlikely (hb_object_is_inert (buffer)))
    return;

693
  buffer->props.script = script;
694 695 696 697 698
}

hb_script_t
hb_buffer_get_script (hb_buffer_t *buffer)
{
699
  return buffer->props.script;
700 701 702 703 704 705
}

void
hb_buffer_set_language (hb_buffer_t   *buffer,
			hb_language_t  language)
{
B
Behdad Esfahbod 已提交
706 707 708
  if (unlikely (hb_object_is_inert (buffer)))
    return;

709
  buffer->props.language = language;
710 711 712 713 714
}

hb_language_t
hb_buffer_get_language (hb_buffer_t *buffer)
{
715
  return buffer->props.language;
716 717
}

B
Behdad Esfahbod 已提交
718

719 720
void
hb_buffer_reset (hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
721
{
722
  buffer->reset ();
B
Behdad Esfahbod 已提交
723 724
}

725
hb_bool_t
726
hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
B
Behdad Esfahbod 已提交
727
{
728
  return buffer->ensure (size);
B
Behdad Esfahbod 已提交
729 730
}

731 732 733 734 735 736
hb_bool_t
hb_buffer_allocation_successful (hb_buffer_t  *buffer)
{
  return !buffer->in_error;
}

737
void
738 739 740 741
hb_buffer_add (hb_buffer_t    *buffer,
	       hb_codepoint_t  codepoint,
	       hb_mask_t       mask,
	       unsigned int    cluster)
742
{
743
  buffer->add (codepoint, mask, cluster);
744
  buffer->clear_context (1);
745 746
}

747 748 749 750
hb_bool_t
hb_buffer_set_length (hb_buffer_t  *buffer,
		      unsigned int  length)
{
751 752 753
  if (unlikely (hb_object_is_inert (buffer)))
    return length == 0;

754
  if (!buffer->ensure (length))
755
    return false;
756 757 758 759 760 761 762 763 764

  /* Wipe the new space */
  if (length > buffer->len) {
    memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
    if (buffer->have_positions)
      memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
  }

  buffer->len = length;
765 766 767 768 769

  if (!length)
    buffer->clear_context (0);
  buffer->clear_context (1);

770
  return true;
771 772
}

773
unsigned int
774
hb_buffer_get_length (hb_buffer_t *buffer)
775
{
776
  return buffer->len;
777 778 779 780
}

/* Return value valid as long as buffer not modified */
hb_glyph_info_t *
781 782
hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
                           unsigned int *length)
783
{
784 785 786
  if (length)
    *length = buffer->len;

787
  return (hb_glyph_info_t *) buffer->info;
788 789 790 791
}

/* Return value valid as long as buffer not modified */
hb_glyph_position_t *
792 793
hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
                               unsigned int *length)
794
{
795
  if (!buffer->have_positions)
796
    buffer->clear_positions ();
797

798 799 800
  if (length)
    *length = buffer->len;

801
  return (hb_glyph_position_t *) buffer->pos;
802
}
B
Behdad Esfahbod 已提交
803

804 805 806
void
hb_buffer_reverse (hb_buffer_t *buffer)
{
807
  buffer->reverse ();
808 809 810 811 812
}

void
hb_buffer_reverse_clusters (hb_buffer_t *buffer)
{
813
  buffer->reverse_clusters ();
814 815
}

816 817 818 819 820 821
void
hb_buffer_guess_properties (hb_buffer_t *buffer)
{
  buffer->guess_properties ();
}

822 823 824 825 826 827 828 829 830 831 832 833 834 835
template <typename T>
static inline void
hb_buffer_add_utf (hb_buffer_t  *buffer,
		   const T      *text,
		   int           text_length,
		   unsigned int  item_offset,
		   int           item_length)
{
  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
	  (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));

  if (unlikely (hb_object_is_inert (buffer)))
    return;

B
Behdad Esfahbod 已提交
836 837
  if (text_length == -1)
    text_length = hb_utf_strlen (text);
838 839 840 841 842 843

  if (item_length == -1)
    item_length = text_length - item_offset;

  buffer->ensure (buffer->len + item_length * sizeof (T) / 4);

844 845 846 847 848 849 850 851
  /* If buffer is empty and pre-context provided, install it.
   * This check is written this way, to make sure people can
   * provide pre-context in one add_utf() call, then provide
   * text in a follow-up call.  See:
   *
   * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
   */
  if (!buffer->len && item_offset > 0)
852 853 854 855 856 857 858 859 860 861 862 863 864 865
  {
    /* Add pre-context */
    buffer->clear_context (0);
    const T *prev = text + item_offset;
    const T *start = text;
    while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
    {
      hb_codepoint_t u;
      prev = hb_utf_prev (prev, start, &u);
      buffer->context[0][buffer->context_len[0]++] = u;
    }
  }

  const T *next = text + item_offset;
866
  const T *end = next + item_length;
867 868
  while (next < end)
  {
869 870 871
    hb_codepoint_t u;
    const T *old_next = next;
    next = hb_utf_next (next, end, &u);
872 873 874 875 876 877 878 879 880 881 882
    buffer->add (u, 1,  old_next - (const T *) text);
  }

  /* Add post-context */
  buffer->clear_context (1);
  end = text + text_length;
  while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
  {
    hb_codepoint_t u;
    next = hb_utf_next (next, end, &u);
    buffer->context[1][buffer->context_len[1]++] = u;
883 884 885
  }

  buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
886 887 888 889 890
}

void
hb_buffer_add_utf8 (hb_buffer_t  *buffer,
		    const char   *text,
891
		    int           text_length,
892
		    unsigned int  item_offset,
893
		    int           item_length)
894
{
895
  hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
896 897 898 899 900
}

void
hb_buffer_add_utf16 (hb_buffer_t    *buffer,
		     const uint16_t *text,
901
		     int             text_length,
902
		     unsigned int    item_offset,
903
		     int            item_length)
904
{
905
  hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
906 907
}

908 909 910
void
hb_buffer_add_utf32 (hb_buffer_t    *buffer,
		     const uint32_t *text,
911
		     int             text_length,
912
		     unsigned int    item_offset,
913
		     int             item_length)
914
{
915
  hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
916
}
B
Behdad Esfahbod 已提交
917 918


919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977
static int
compare_info_codepoint (const hb_glyph_info_t *pa,
			const hb_glyph_info_t *pb)
{
  return (int) pb->codepoint - (int) pa->codepoint;
}

static inline void
normalize_glyphs_cluster (hb_buffer_t *buffer,
			  unsigned int start,
			  unsigned int end,
			  bool backward)
{
  hb_glyph_position_t *pos = buffer->pos;

  /* Total cluster advance */
  hb_position_t total_x_advance = 0, total_y_advance = 0;
  for (unsigned int i = start; i < end; i++)
  {
    total_x_advance += pos[i].x_advance;
    total_y_advance += pos[i].y_advance;
  }

  hb_position_t x_advance = 0, y_advance = 0;
  for (unsigned int i = start; i < end; i++)
  {
    pos[i].x_offset += x_advance;
    pos[i].y_offset += y_advance;

    x_advance += pos[i].x_advance;
    y_advance += pos[i].y_advance;

    pos[i].x_advance = 0;
    pos[i].y_advance = 0;
  }

  if (backward)
  {
    /* Transfer all cluster advance to the last glyph. */
    pos[end - 1].x_advance = total_x_advance;
    pos[end - 1].y_advance = total_y_advance;

    hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
  } else {
    /* Transfer all cluster advance to the first glyph. */
    pos[start].x_advance += total_x_advance;
    pos[start].y_advance += total_y_advance;
    for (unsigned int i = start + 1; i < end; i++) {
      pos[i].x_offset -= total_x_advance;
      pos[i].y_offset -= total_y_advance;
    }
    hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
  }
}

void
hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
{
  assert (buffer->have_positions);
B
Minor  
Behdad Esfahbod 已提交
978
  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994

  bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);

  unsigned int count = buffer->len;
  if (unlikely (!count)) return;
  hb_glyph_info_t *info = buffer->info;

  unsigned int start = 0;
  unsigned int end;
  for (end = start + 1; end < count; end++)
    if (info[start].cluster != info[end].cluster) {
      normalize_glyphs_cluster (buffer, start, end, backward);
      start = end;
    }
  normalize_glyphs_cluster (buffer, start, end, backward);
}