1 /* 2 * Copyright 1998-2004 David Turner and Werner Lemberg 3 * 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 * Permission is hereby granted, without written agreement and without 9 * license or royalty fees, to use, copy, modify, and distribute this 10 * software and its documentation for any purpose, provided that the 11 * above copyright notice and the following two paragraphs appear in 12 * all copies of this software. 13 * 14 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 15 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 16 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 17 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 18 * DAMAGE. 19 * 20 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 21 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 22 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 23 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 24 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 25 * 26 * 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 34 #ifndef HB_DEBUG_BUFFER 35 #define HB_DEBUG_BUFFER (HB_DEBUG+0) 36 #endif 37 38 39 hb_bool_t 40 hb_segment_properties_equal (const hb_segment_properties_t *a, 41 const hb_segment_properties_t *b) 42 { 43 return a->direction == b->direction && 44 a->script == b->script && 45 a->language == b->language && 46 a->reserved1 == b->reserved1 && 47 a->reserved2 == b->reserved2; 48 49 } 50 51 unsigned int 52 hb_segment_properties_hash (const hb_segment_properties_t *p) 53 { 54 return (unsigned int) p->direction ^ 55 (unsigned int) p->script ^ 56 (intptr_t) (p->language); 57 } 58 59 60 61 /* Here is how the buffer works internally: 62 * 63 * There are two info pointers: info and out_info. They always have 64 * the same allocated size, but different lengths. 65 * 66 * As an optimization, both info and out_info may point to the 67 * same piece of memory, which is owned by info. This remains the 68 * case as long as out_len doesn't exceed i at any time. 69 * In that case, swap_buffers() is no-op and the glyph operations operate 70 * mostly in-place. 71 * 72 * As soon as out_info gets longer than info, out_info is moved over 73 * to an alternate buffer (which we reuse the pos buffer for!), and its 74 * current contents (out_len entries) are copied to the new place. 75 * This should all remain transparent to the user. swap_buffers() then 76 * switches info and out_info. 77 */ 78 79 80 81 /* Internal API */ 82 83 bool 84 hb_buffer_t::enlarge (unsigned int size) 85 { 86 if (unlikely (in_error)) 87 return false; 88 89 unsigned int new_allocated = allocated; 90 hb_glyph_position_t *new_pos = NULL; 91 hb_glyph_info_t *new_info = NULL; 92 bool separate_out = out_info != info; 93 94 if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0])))) 95 goto done; 96 97 while (size >= new_allocated) 98 new_allocated += (new_allocated >> 1) + 32; 99 100 ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0])); 101 if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0])))) 102 goto done; 103 104 new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0])); 105 new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0])); 106 107 done: 108 if (unlikely (!new_pos || !new_info)) 109 in_error = true; 110 111 if (likely (new_pos)) 112 pos = new_pos; 113 114 if (likely (new_info)) 115 info = new_info; 116 117 out_info = separate_out ? (hb_glyph_info_t *) pos : info; 118 if (likely (!in_error)) 119 allocated = new_allocated; 120 121 return likely (!in_error); 122 } 123 124 bool 125 hb_buffer_t::make_room_for (unsigned int num_in, 126 unsigned int num_out) 127 { 128 if (unlikely (!ensure (out_len + num_out))) return false; 129 130 if (out_info == info && 131 out_len + num_out > idx + num_in) 132 { 133 assert (have_output); 134 135 out_info = (hb_glyph_info_t *) pos; 136 memcpy (out_info, info, out_len * sizeof (out_info[0])); 137 } 138 139 return true; 140 } 141 142 void * 143 hb_buffer_t::get_scratch_buffer (unsigned int *size) 144 { 145 have_output = false; 146 have_positions = false; 147 148 out_len = 0; 149 out_info = info; 150 151 *size = allocated * sizeof (pos[0]); 152 return pos; 153 } 154 155 156 157 /* HarfBuzz-Internal API */ 158 159 void 160 hb_buffer_t::reset (void) 161 { 162 if (unlikely (hb_object_is_inert (this))) 163 return; 164 165 hb_unicode_funcs_destroy (unicode); 166 unicode = hb_unicode_funcs_get_default (); 167 168 clear (); 169 } 170 171 void 172 hb_buffer_t::clear (void) 173 { 174 if (unlikely (hb_object_is_inert (this))) 175 return; 176 177 hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT; 178 props = default_props; 179 flags = HB_BUFFER_FLAGS_DEFAULT; 180 181 content_type = HB_BUFFER_CONTENT_TYPE_INVALID; 182 in_error = false; 183 have_output = false; 184 have_positions = false; 185 186 idx = 0; 187 len = 0; 188 out_len = 0; 189 out_info = info; 190 191 serial = 0; 192 memset (allocated_var_bytes, 0, sizeof allocated_var_bytes); 193 memset (allocated_var_owner, 0, sizeof allocated_var_owner); 194 195 memset (context, 0, sizeof context); 196 memset (context_len, 0, sizeof context_len); 197 } 198 199 void 200 hb_buffer_t::add (hb_codepoint_t codepoint, 201 unsigned int cluster) 202 { 203 hb_glyph_info_t *glyph; 204 205 if (unlikely (!ensure (len + 1))) return; 206 207 glyph = &info[len]; 208 209 memset (glyph, 0, sizeof (*glyph)); 210 glyph->codepoint = codepoint; 211 glyph->mask = 1; 212 glyph->cluster = cluster; 213 214 len++; 215 } 216 217 void 218 hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info) 219 { 220 if (unlikely (!ensure (len + 1))) return; 221 222 info[len] = glyph_info; 223 224 len++; 225 } 226 227 228 void 229 hb_buffer_t::remove_output (void) 230 { 231 if (unlikely (hb_object_is_inert (this))) 232 return; 233 234 have_output = false; 235 have_positions = false; 236 237 out_len = 0; 238 out_info = info; 239 } 240 241 void 242 hb_buffer_t::clear_output (void) 243 { 244 if (unlikely (hb_object_is_inert (this))) 245 return; 246 247 have_output = true; 248 have_positions = false; 249 250 out_len = 0; 251 out_info = info; 252 } 253 254 void 255 hb_buffer_t::clear_positions (void) 256 { 257 if (unlikely (hb_object_is_inert (this))) 258 return; 259 260 have_output = false; 261 have_positions = true; 262 263 out_len = 0; 264 out_info = info; 265 266 memset (pos, 0, sizeof (pos[0]) * len); 267 } 268 269 void 270 hb_buffer_t::swap_buffers (void) 271 { 272 if (unlikely (in_error)) return; 273 274 assert (have_output); 275 have_output = false; 276 277 if (out_info != info) 278 { 279 hb_glyph_info_t *tmp_string; 280 tmp_string = info; 281 info = out_info; 282 out_info = tmp_string; 283 pos = (hb_glyph_position_t *) out_info; 284 } 285 286 unsigned int tmp; 287 tmp = len; 288 len = out_len; 289 out_len = tmp; 290 291 idx = 0; 292 } 293 294 295 void 296 hb_buffer_t::replace_glyphs (unsigned int num_in, 297 unsigned int num_out, 298 const uint32_t *glyph_data) 299 { 300 if (unlikely (!make_room_for (num_in, num_out))) return; 301 302 merge_clusters (idx, idx + num_in); 303 304 hb_glyph_info_t orig_info = info[idx]; 305 hb_glyph_info_t *pinfo = &out_info[out_len]; 306 for (unsigned int i = 0; i < num_out; i++) 307 { 308 *pinfo = orig_info; 309 pinfo->codepoint = glyph_data[i]; 310 pinfo++; 311 } 312 313 idx += num_in; 314 out_len += num_out; 315 } 316 317 void 318 hb_buffer_t::output_glyph (hb_codepoint_t glyph_index) 319 { 320 if (unlikely (!make_room_for (0, 1))) return; 321 322 out_info[out_len] = info[idx]; 323 out_info[out_len].codepoint = glyph_index; 324 325 out_len++; 326 } 327 328 void 329 hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info) 330 { 331 if (unlikely (!make_room_for (0, 1))) return; 332 333 out_info[out_len] = glyph_info; 334 335 out_len++; 336 } 337 338 void 339 hb_buffer_t::copy_glyph (void) 340 { 341 if (unlikely (!make_room_for (0, 1))) return; 342 343 out_info[out_len] = info[idx]; 344 345 out_len++; 346 } 347 348 void 349 hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index) 350 { 351 if (unlikely (out_info != info || out_len != idx)) { 352 if (unlikely (!make_room_for (1, 1))) return; 353 out_info[out_len] = info[idx]; 354 } 355 out_info[out_len].codepoint = glyph_index; 356 357 idx++; 358 out_len++; 359 } 360 361 362 void 363 hb_buffer_t::set_masks (hb_mask_t value, 364 hb_mask_t mask, 365 unsigned int cluster_start, 366 unsigned int cluster_end) 367 { 368 hb_mask_t not_mask = ~mask; 369 value &= mask; 370 371 if (!mask) 372 return; 373 374 if (cluster_start == 0 && cluster_end == (unsigned int)-1) { 375 unsigned int count = len; 376 for (unsigned int i = 0; i < count; i++) 377 info[i].mask = (info[i].mask & not_mask) | value; 378 return; 379 } 380 381 unsigned int count = len; 382 for (unsigned int i = 0; i < count; i++) 383 if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end) 384 info[i].mask = (info[i].mask & not_mask) | value; 385 } 386 387 void 388 hb_buffer_t::reverse_range (unsigned int start, 389 unsigned int end) 390 { 391 unsigned int i, j; 392 393 if (start == end - 1) 394 return; 395 396 for (i = start, j = end - 1; i < j; i++, j--) { 397 hb_glyph_info_t t; 398 399 t = info[i]; 400 info[i] = info[j]; 401 info[j] = t; 402 } 403 404 if (pos) { 405 for (i = start, j = end - 1; i < j; i++, j--) { 406 hb_glyph_position_t t; 407 408 t = pos[i]; 409 pos[i] = pos[j]; 410 pos[j] = t; 411 } 412 } 413 } 414 415 void 416 hb_buffer_t::reverse (void) 417 { 418 if (unlikely (!len)) 419 return; 420 421 reverse_range (0, len); 422 } 423 424 void 425 hb_buffer_t::reverse_clusters (void) 426 { 427 unsigned int i, start, count, last_cluster; 428 429 if (unlikely (!len)) 430 return; 431 432 reverse (); 433 434 count = len; 435 start = 0; 436 last_cluster = info[0].cluster; 437 for (i = 1; i < count; i++) { 438 if (last_cluster != info[i].cluster) { 439 reverse_range (start, i); 440 start = i; 441 last_cluster = info[i].cluster; 442 } 443 } 444 reverse_range (start, i); 445 } 446 447 void 448 hb_buffer_t::merge_clusters (unsigned int start, 449 unsigned int end) 450 { 451 if (unlikely (end - start < 2)) 452 return; 453 454 unsigned int cluster = info[start].cluster; 455 456 for (unsigned int i = start + 1; i < end; i++) 457 cluster = MIN (cluster, info[i].cluster); 458 459 /* Extend end */ 460 while (end < len && info[end - 1].cluster == info[end].cluster) 461 end++; 462 463 /* Extend start */ 464 while (idx < start && info[start - 1].cluster == info[start].cluster) 465 start--; 466 467 /* If we hit the start of buffer, continue in out-buffer. */ 468 if (idx == start) 469 for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--) 470 out_info[i - 1].cluster = cluster; 471 472 for (unsigned int i = start; i < end; i++) 473 info[i].cluster = cluster; 474 } 475 void 476 hb_buffer_t::merge_out_clusters (unsigned int start, 477 unsigned int end) 478 { 479 if (unlikely (end - start < 2)) 480 return; 481 482 unsigned int cluster = out_info[start].cluster; 483 484 for (unsigned int i = start + 1; i < end; i++) 485 cluster = MIN (cluster, out_info[i].cluster); 486 487 /* Extend start */ 488 while (start && out_info[start - 1].cluster == out_info[start].cluster) 489 start--; 490 491 /* Extend end */ 492 while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster) 493 end++; 494 495 /* If we hit the end of out-buffer, continue in buffer. */ 496 if (end == out_len) 497 for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++) 498 info[i].cluster = cluster; 499 500 for (unsigned int i = start; i < end; i++) 501 out_info[i].cluster = cluster; 502 } 503 504 void 505 hb_buffer_t::guess_segment_properties (void) 506 { 507 assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || 508 (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); 509 510 /* If script is set to INVALID, guess from buffer contents */ 511 if (props.script == HB_SCRIPT_INVALID) { 512 for (unsigned int i = 0; i < len; i++) { 513 hb_script_t script = unicode->script (info[i].codepoint); 514 if (likely (script != HB_SCRIPT_COMMON && 515 script != HB_SCRIPT_INHERITED && 516 script != HB_SCRIPT_UNKNOWN)) { 517 props.script = script; 518 break; 519 } 520 } 521 } 522 523 /* If direction is set to INVALID, guess from script */ 524 if (props.direction == HB_DIRECTION_INVALID) { 525 props.direction = hb_script_get_horizontal_direction (props.script); 526 } 527 528 /* If language is not set, use default language from locale */ 529 if (props.language == HB_LANGUAGE_INVALID) { 530 /* TODO get_default_for_script? using $LANGUAGE */ 531 props.language = hb_language_get_default (); 532 } 533 } 534 535 536 static inline void 537 dump_var_allocation (const hb_buffer_t *buffer) 538 { 539 char buf[80]; 540 for (unsigned int i = 0; i < 8; i++) 541 buf[i] = '0' + buffer->allocated_var_bytes[7 - i]; 542 buf[8] = '\0'; 543 DEBUG_MSG (BUFFER, buffer, 544 "Current var allocation: %s", 545 buf); 546 } 547 548 void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner) 549 { 550 assert (byte_i < 8 && byte_i + count <= 8); 551 552 if (DEBUG (BUFFER)) 553 dump_var_allocation (this); 554 DEBUG_MSG (BUFFER, this, 555 "Allocating var bytes %d..%d for %s", 556 byte_i, byte_i + count - 1, owner); 557 558 for (unsigned int i = byte_i; i < byte_i + count; i++) { 559 assert (!allocated_var_bytes[i]); 560 allocated_var_bytes[i]++; 561 allocated_var_owner[i] = owner; 562 } 563 } 564 565 void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner) 566 { 567 if (DEBUG (BUFFER)) 568 dump_var_allocation (this); 569 570 DEBUG_MSG (BUFFER, this, 571 "Deallocating var bytes %d..%d for %s", 572 byte_i, byte_i + count - 1, owner); 573 574 assert (byte_i < 8 && byte_i + count <= 8); 575 for (unsigned int i = byte_i; i < byte_i + count; i++) { 576 assert (allocated_var_bytes[i]); 577 assert (0 == strcmp (allocated_var_owner[i], owner)); 578 allocated_var_bytes[i]--; 579 } 580 } 581 582 void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner) 583 { 584 if (DEBUG (BUFFER)) 585 dump_var_allocation (this); 586 587 DEBUG_MSG (BUFFER, this, 588 "Asserting var bytes %d..%d for %s", 589 byte_i, byte_i + count - 1, owner); 590 591 assert (byte_i < 8 && byte_i + count <= 8); 592 for (unsigned int i = byte_i; i < byte_i + count; i++) { 593 assert (allocated_var_bytes[i]); 594 assert (0 == strcmp (allocated_var_owner[i], owner)); 595 } 596 } 597 598 void hb_buffer_t::deallocate_var_all (void) 599 { 600 memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes)); 601 memset (allocated_var_owner, 0, sizeof (allocated_var_owner)); 602 } 603 604 /* Public API */ 605 606 hb_buffer_t * 607 hb_buffer_create (void) 608 { 609 hb_buffer_t *buffer; 610 611 if (!(buffer = hb_object_create<hb_buffer_t> ())) 612 return hb_buffer_get_empty (); 613 614 buffer->reset (); 615 616 return buffer; 617 } 618 619 hb_buffer_t * 620 hb_buffer_get_empty (void) 621 { 622 static const hb_buffer_t _hb_buffer_nil = { 623 HB_OBJECT_HEADER_STATIC, 624 625 const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil), 626 HB_SEGMENT_PROPERTIES_DEFAULT, 627 HB_BUFFER_FLAGS_DEFAULT, 628 629 HB_BUFFER_CONTENT_TYPE_INVALID, 630 true, /* in_error */ 631 true, /* have_output */ 632 true /* have_positions */ 633 634 /* Zero is good enough for everything else. */ 635 }; 636 637 return const_cast<hb_buffer_t *> (&_hb_buffer_nil); 638 } 639 640 hb_buffer_t * 641 hb_buffer_reference (hb_buffer_t *buffer) 642 { 643 return hb_object_reference (buffer); 644 } 645 646 void 647 hb_buffer_destroy (hb_buffer_t *buffer) 648 { 649 if (!hb_object_destroy (buffer)) return; 650 651 hb_unicode_funcs_destroy (buffer->unicode); 652 653 free (buffer->info); 654 free (buffer->pos); 655 656 free (buffer); 657 } 658 659 hb_bool_t 660 hb_buffer_set_user_data (hb_buffer_t *buffer, 661 hb_user_data_key_t *key, 662 void * data, 663 hb_destroy_func_t destroy, 664 hb_bool_t replace) 665 { 666 return hb_object_set_user_data (buffer, key, data, destroy, replace); 667 } 668 669 void * 670 hb_buffer_get_user_data (hb_buffer_t *buffer, 671 hb_user_data_key_t *key) 672 { 673 return hb_object_get_user_data (buffer, key); 674 } 675 676 677 void 678 hb_buffer_set_content_type (hb_buffer_t *buffer, 679 hb_buffer_content_type_t content_type) 680 { 681 buffer->content_type = content_type; 682 } 683 684 hb_buffer_content_type_t 685 hb_buffer_get_content_type (hb_buffer_t *buffer) 686 { 687 return buffer->content_type; 688 } 689 690 691 void 692 hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, 693 hb_unicode_funcs_t *unicode) 694 { 695 if (unlikely (hb_object_is_inert (buffer))) 696 return; 697 698 if (!unicode) 699 unicode = hb_unicode_funcs_get_default (); 700 701 702 hb_unicode_funcs_reference (unicode); 703 hb_unicode_funcs_destroy (buffer->unicode); 704 buffer->unicode = unicode; 705 } 706 707 hb_unicode_funcs_t * 708 hb_buffer_get_unicode_funcs (hb_buffer_t *buffer) 709 { 710 return buffer->unicode; 711 } 712 713 void 714 hb_buffer_set_direction (hb_buffer_t *buffer, 715 hb_direction_t direction) 716 717 { 718 if (unlikely (hb_object_is_inert (buffer))) 719 return; 720 721 buffer->props.direction = direction; 722 } 723 724 hb_direction_t 725 hb_buffer_get_direction (hb_buffer_t *buffer) 726 { 727 return buffer->props.direction; 728 } 729 730 void 731 hb_buffer_set_script (hb_buffer_t *buffer, 732 hb_script_t script) 733 { 734 if (unlikely (hb_object_is_inert (buffer))) 735 return; 736 737 buffer->props.script = script; 738 } 739 740 hb_script_t 741 hb_buffer_get_script (hb_buffer_t *buffer) 742 { 743 return buffer->props.script; 744 } 745 746 void 747 hb_buffer_set_language (hb_buffer_t *buffer, 748 hb_language_t language) 749 { 750 if (unlikely (hb_object_is_inert (buffer))) 751 return; 752 753 buffer->props.language = language; 754 } 755 756 hb_language_t 757 hb_buffer_get_language (hb_buffer_t *buffer) 758 { 759 return buffer->props.language; 760 } 761 762 void 763 hb_buffer_set_segment_properties (hb_buffer_t *buffer, 764 const hb_segment_properties_t *props) 765 { 766 if (unlikely (hb_object_is_inert (buffer))) 767 return; 768 769 buffer->props = *props; 770 } 771 772 void 773 hb_buffer_get_segment_properties (hb_buffer_t *buffer, 774 hb_segment_properties_t *props) 775 { 776 *props = buffer->props; 777 } 778 779 780 void 781 hb_buffer_set_flags (hb_buffer_t *buffer, 782 hb_buffer_flags_t flags) 783 { 784 if (unlikely (hb_object_is_inert (buffer))) 785 return; 786 787 buffer->flags = flags; 788 } 789 790 hb_buffer_flags_t 791 hb_buffer_get_flags (hb_buffer_t *buffer) 792 { 793 return buffer->flags; 794 } 795 796 797 void 798 hb_buffer_reset (hb_buffer_t *buffer) 799 { 800 buffer->reset (); 801 } 802 803 void 804 hb_buffer_clear_contents (hb_buffer_t *buffer) 805 { 806 buffer->clear (); 807 } 808 809 hb_bool_t 810 hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size) 811 { 812 return buffer->ensure (size); 813 } 814 815 hb_bool_t 816 hb_buffer_allocation_successful (hb_buffer_t *buffer) 817 { 818 return !buffer->in_error; 819 } 820 821 void 822 hb_buffer_add (hb_buffer_t *buffer, 823 hb_codepoint_t codepoint, 824 unsigned int cluster) 825 { 826 buffer->add (codepoint, cluster); 827 buffer->clear_context (1); 828 } 829 830 hb_bool_t 831 hb_buffer_set_length (hb_buffer_t *buffer, 832 unsigned int length) 833 { 834 if (unlikely (hb_object_is_inert (buffer))) 835 return length == 0; 836 837 if (!buffer->ensure (length)) 838 return false; 839 840 /* Wipe the new space */ 841 if (length > buffer->len) { 842 memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len)); 843 if (buffer->have_positions) 844 memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len)); 845 } 846 847 buffer->len = length; 848 849 if (!length) 850 buffer->clear_context (0); 851 buffer->clear_context (1); 852 853 return true; 854 } 855 856 unsigned int 857 hb_buffer_get_length (hb_buffer_t *buffer) 858 { 859 return buffer->len; 860 } 861 862 /* Return value valid as long as buffer not modified */ 863 hb_glyph_info_t * 864 hb_buffer_get_glyph_infos (hb_buffer_t *buffer, 865 unsigned int *length) 866 { 867 if (length) 868 *length = buffer->len; 869 870 return (hb_glyph_info_t *) buffer->info; 871 } 872 873 /* Return value valid as long as buffer not modified */ 874 hb_glyph_position_t * 875 hb_buffer_get_glyph_positions (hb_buffer_t *buffer, 876 unsigned int *length) 877 { 878 if (!buffer->have_positions) 879 buffer->clear_positions (); 880 881 if (length) 882 *length = buffer->len; 883 884 return (hb_glyph_position_t *) buffer->pos; 885 } 886 887 void 888 hb_buffer_reverse (hb_buffer_t *buffer) 889 { 890 buffer->reverse (); 891 } 892 893 void 894 hb_buffer_reverse_clusters (hb_buffer_t *buffer) 895 { 896 buffer->reverse_clusters (); 897 } 898 899 void 900 hb_buffer_guess_segment_properties (hb_buffer_t *buffer) 901 { 902 buffer->guess_segment_properties (); 903 } 904 905 template <typename T> 906 static inline void 907 hb_buffer_add_utf (hb_buffer_t *buffer, 908 const T *text, 909 int text_length, 910 unsigned int item_offset, 911 int item_length) 912 { 913 assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || 914 (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); 915 916 if (unlikely (hb_object_is_inert (buffer))) 917 return; 918 919 if (text_length == -1) 920 text_length = hb_utf_strlen (text); 921 922 if (item_length == -1) 923 item_length = text_length - item_offset; 924 925 buffer->ensure (buffer->len + item_length * sizeof (T) / 4); 926 927 /* If buffer is empty and pre-context provided, install it. 928 * This check is written this way, to make sure people can 929 * provide pre-context in one add_utf() call, then provide 930 * text in a follow-up call. See: 931 * 932 * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13 933 */ 934 if (!buffer->len && item_offset > 0) 935 { 936 /* Add pre-context */ 937 buffer->clear_context (0); 938 const T *prev = text + item_offset; 939 const T *start = text; 940 while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH) 941 { 942 hb_codepoint_t u; 943 prev = hb_utf_prev (prev, start, &u); 944 buffer->context[0][buffer->context_len[0]++] = u; 945 } 946 } 947 948 const T *next = text + item_offset; 949 const T *end = next + item_length; 950 while (next < end) 951 { 952 hb_codepoint_t u; 953 const T *old_next = next; 954 next = hb_utf_next (next, end, &u); 955 buffer->add (u, old_next - (const T *) text); 956 } 957 958 /* Add post-context */ 959 buffer->clear_context (1); 960 end = text + text_length; 961 while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH) 962 { 963 hb_codepoint_t u; 964 next = hb_utf_next (next, end, &u); 965 buffer->context[1][buffer->context_len[1]++] = u; 966 } 967 968 buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE; 969 } 970 971 void 972 hb_buffer_add_utf8 (hb_buffer_t *buffer, 973 const char *text, 974 int text_length, 975 unsigned int item_offset, 976 int item_length) 977 { 978 hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length); 979 } 980 981 void 982 hb_buffer_add_utf16 (hb_buffer_t *buffer, 983 const uint16_t *text, 984 int text_length, 985 unsigned int item_offset, 986 int item_length) 987 { 988 hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length); 989 } 990 991 void 992 hb_buffer_add_utf32 (hb_buffer_t *buffer, 993 const uint32_t *text, 994 int text_length, 995 unsigned int item_offset, 996 int item_length) 997 { 998 hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length); 999 } 1000 1001 1002 static int 1003 compare_info_codepoint (const hb_glyph_info_t *pa, 1004 const hb_glyph_info_t *pb) 1005 { 1006 return (int) pb->codepoint - (int) pa->codepoint; 1007 } 1008 1009 static inline void 1010 normalize_glyphs_cluster (hb_buffer_t *buffer, 1011 unsigned int start, 1012 unsigned int end, 1013 bool backward) 1014 { 1015 hb_glyph_position_t *pos = buffer->pos; 1016 1017 /* Total cluster advance */ 1018 hb_position_t total_x_advance = 0, total_y_advance = 0; 1019 for (unsigned int i = start; i < end; i++) 1020 { 1021 total_x_advance += pos[i].x_advance; 1022 total_y_advance += pos[i].y_advance; 1023 } 1024 1025 hb_position_t x_advance = 0, y_advance = 0; 1026 for (unsigned int i = start; i < end; i++) 1027 { 1028 pos[i].x_offset += x_advance; 1029 pos[i].y_offset += y_advance; 1030 1031 x_advance += pos[i].x_advance; 1032 y_advance += pos[i].y_advance; 1033 1034 pos[i].x_advance = 0; 1035 pos[i].y_advance = 0; 1036 } 1037 1038 if (backward) 1039 { 1040 /* Transfer all cluster advance to the last glyph. */ 1041 pos[end - 1].x_advance = total_x_advance; 1042 pos[end - 1].y_advance = total_y_advance; 1043 1044 hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start); 1045 } else { 1046 /* Transfer all cluster advance to the first glyph. */ 1047 pos[start].x_advance += total_x_advance; 1048 pos[start].y_advance += total_y_advance; 1049 for (unsigned int i = start + 1; i < end; i++) { 1050 pos[i].x_offset -= total_x_advance; 1051 pos[i].y_offset -= total_y_advance; 1052 } 1053 hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1); 1054 } 1055 } 1056 1057 void 1058 hb_buffer_normalize_glyphs (hb_buffer_t *buffer) 1059 { 1060 assert (buffer->have_positions); 1061 assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); 1062 1063 bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); 1064 1065 unsigned int count = buffer->len; 1066 if (unlikely (!count)) return; 1067 hb_glyph_info_t *info = buffer->info; 1068 1069 unsigned int start = 0; 1070 unsigned int end; 1071 for (end = start + 1; end < count; end++) 1072 if (info[start].cluster != info[end].cluster) { 1073 normalize_glyphs_cluster (buffer, start, end, backward); 1074 start = end; 1075 } 1076 normalize_glyphs_cluster (buffer, start, end, backward); 1077 } 1078