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 39hb_bool_t 40hb_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 51unsigned int 52hb_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 83bool 84hb_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 107done: 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 124bool 125hb_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 142bool 143hb_buffer_t::shift_forward (unsigned int count) 144{ 145 assert (have_output); 146 if (unlikely (!ensure (len + count))) return false; 147 148 memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0])); 149 len += count; 150 idx += count; 151 152 return true; 153} 154 155hb_buffer_t::scratch_buffer_t * 156hb_buffer_t::get_scratch_buffer (unsigned int *size) 157{ 158 have_output = false; 159 have_positions = false; 160 161 out_len = 0; 162 out_info = info; 163 164 assert ((uintptr_t) pos % sizeof (scratch_buffer_t) == 0); 165 *size = allocated * sizeof (pos[0]) / sizeof (scratch_buffer_t); 166 return (scratch_buffer_t *) (void *) pos; 167} 168 169 170 171/* HarfBuzz-Internal API */ 172 173void 174hb_buffer_t::reset (void) 175{ 176 if (unlikely (hb_object_is_inert (this))) 177 return; 178 179 hb_unicode_funcs_destroy (unicode); 180 unicode = hb_unicode_funcs_get_default (); 181 flags = HB_BUFFER_FLAG_DEFAULT; 182 replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT; 183 184 clear (); 185} 186 187void 188hb_buffer_t::clear (void) 189{ 190 if (unlikely (hb_object_is_inert (this))) 191 return; 192 193 hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT; 194 props = default_props; 195 196 content_type = HB_BUFFER_CONTENT_TYPE_INVALID; 197 in_error = false; 198 have_output = false; 199 have_positions = false; 200 201 idx = 0; 202 len = 0; 203 out_len = 0; 204 out_info = info; 205 206 serial = 0; 207 memset (allocated_var_bytes, 0, sizeof allocated_var_bytes); 208 memset (allocated_var_owner, 0, sizeof allocated_var_owner); 209 210 memset (context, 0, sizeof context); 211 memset (context_len, 0, sizeof context_len); 212} 213 214void 215hb_buffer_t::add (hb_codepoint_t codepoint, 216 unsigned int cluster) 217{ 218 hb_glyph_info_t *glyph; 219 220 if (unlikely (!ensure (len + 1))) return; 221 222 glyph = &info[len]; 223 224 memset (glyph, 0, sizeof (*glyph)); 225 glyph->codepoint = codepoint; 226 glyph->mask = 1; 227 glyph->cluster = cluster; 228 229 len++; 230} 231 232void 233hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info) 234{ 235 if (unlikely (!ensure (len + 1))) return; 236 237 info[len] = glyph_info; 238 239 len++; 240} 241 242 243void 244hb_buffer_t::remove_output (void) 245{ 246 if (unlikely (hb_object_is_inert (this))) 247 return; 248 249 have_output = false; 250 have_positions = false; 251 252 out_len = 0; 253 out_info = info; 254} 255 256void 257hb_buffer_t::clear_output (void) 258{ 259 if (unlikely (hb_object_is_inert (this))) 260 return; 261 262 have_output = true; 263 have_positions = false; 264 265 out_len = 0; 266 out_info = info; 267} 268 269void 270hb_buffer_t::clear_positions (void) 271{ 272 if (unlikely (hb_object_is_inert (this))) 273 return; 274 275 have_output = false; 276 have_positions = true; 277 278 out_len = 0; 279 out_info = info; 280 281 memset (pos, 0, sizeof (pos[0]) * len); 282} 283 284void 285hb_buffer_t::swap_buffers (void) 286{ 287 if (unlikely (in_error)) return; 288 289 assert (have_output); 290 have_output = false; 291 292 if (out_info != info) 293 { 294 hb_glyph_info_t *tmp_string; 295 tmp_string = info; 296 info = out_info; 297 out_info = tmp_string; 298 pos = (hb_glyph_position_t *) out_info; 299 } 300 301 unsigned int tmp; 302 tmp = len; 303 len = out_len; 304 out_len = tmp; 305 306 idx = 0; 307} 308 309 310void 311hb_buffer_t::replace_glyphs (unsigned int num_in, 312 unsigned int num_out, 313 const uint32_t *glyph_data) 314{ 315 if (unlikely (!make_room_for (num_in, num_out))) return; 316 317 merge_clusters (idx, idx + num_in); 318 319 hb_glyph_info_t orig_info = info[idx]; 320 hb_glyph_info_t *pinfo = &out_info[out_len]; 321 for (unsigned int i = 0; i < num_out; i++) 322 { 323 *pinfo = orig_info; 324 pinfo->codepoint = glyph_data[i]; 325 pinfo++; 326 } 327 328 idx += num_in; 329 out_len += num_out; 330} 331 332void 333hb_buffer_t::output_glyph (hb_codepoint_t glyph_index) 334{ 335 if (unlikely (!make_room_for (0, 1))) return; 336 337 out_info[out_len] = info[idx]; 338 out_info[out_len].codepoint = glyph_index; 339 340 out_len++; 341} 342 343void 344hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info) 345{ 346 if (unlikely (!make_room_for (0, 1))) return; 347 348 out_info[out_len] = glyph_info; 349 350 out_len++; 351} 352 353void 354hb_buffer_t::copy_glyph (void) 355{ 356 if (unlikely (!make_room_for (0, 1))) return; 357 358 out_info[out_len] = info[idx]; 359 360 out_len++; 361} 362 363bool 364hb_buffer_t::move_to (unsigned int i) 365{ 366 if (!have_output) 367 { 368 assert (i <= len); 369 idx = i; 370 return true; 371 } 372 373 assert (i <= out_len + (len - idx)); 374 375 if (out_len < i) 376 { 377 unsigned int count = i - out_len; 378 if (unlikely (!make_room_for (count, count))) return false; 379 380 memmove (out_info + out_len, info + idx, count * sizeof (out_info[0])); 381 idx += count; 382 out_len += count; 383 } 384 else if (out_len > i) 385 { 386 /* Tricky part: rewinding... */ 387 unsigned int count = out_len - i; 388 389 if (unlikely (idx < count && !shift_forward (count + 32))) return false; 390 391 assert (idx >= count); 392 393 idx -= count; 394 out_len -= count; 395 memmove (info + idx, out_info + out_len, count * sizeof (out_info[0])); 396 } 397 398 return true; 399} 400 401void 402hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index) 403{ 404 if (unlikely (out_info != info || out_len != idx)) { 405 if (unlikely (!make_room_for (1, 1))) return; 406 out_info[out_len] = info[idx]; 407 } 408 out_info[out_len].codepoint = glyph_index; 409 410 idx++; 411 out_len++; 412} 413 414 415void 416hb_buffer_t::set_masks (hb_mask_t value, 417 hb_mask_t mask, 418 unsigned int cluster_start, 419 unsigned int cluster_end) 420{ 421 hb_mask_t not_mask = ~mask; 422 value &= mask; 423 424 if (!mask) 425 return; 426 427 if (cluster_start == 0 && cluster_end == (unsigned int)-1) { 428 unsigned int count = len; 429 for (unsigned int i = 0; i < count; i++) 430 info[i].mask = (info[i].mask & not_mask) | value; 431 return; 432 } 433 434 unsigned int count = len; 435 for (unsigned int i = 0; i < count; i++) 436 if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end) 437 info[i].mask = (info[i].mask & not_mask) | value; 438} 439 440void 441hb_buffer_t::reverse_range (unsigned int start, 442 unsigned int end) 443{ 444 unsigned int i, j; 445 446 if (start == end - 1) 447 return; 448 449 for (i = start, j = end - 1; i < j; i++, j--) { 450 hb_glyph_info_t t; 451 452 t = info[i]; 453 info[i] = info[j]; 454 info[j] = t; 455 } 456 457 if (pos) { 458 for (i = start, j = end - 1; i < j; i++, j--) { 459 hb_glyph_position_t t; 460 461 t = pos[i]; 462 pos[i] = pos[j]; 463 pos[j] = t; 464 } 465 } 466} 467 468void 469hb_buffer_t::reverse (void) 470{ 471 if (unlikely (!len)) 472 return; 473 474 reverse_range (0, len); 475} 476 477void 478hb_buffer_t::reverse_clusters (void) 479{ 480 unsigned int i, start, count, last_cluster; 481 482 if (unlikely (!len)) 483 return; 484 485 reverse (); 486 487 count = len; 488 start = 0; 489 last_cluster = info[0].cluster; 490 for (i = 1; i < count; i++) { 491 if (last_cluster != info[i].cluster) { 492 reverse_range (start, i); 493 start = i; 494 last_cluster = info[i].cluster; 495 } 496 } 497 reverse_range (start, i); 498} 499 500void 501hb_buffer_t::merge_clusters (unsigned int start, 502 unsigned int end) 503{ 504#ifdef HB_NO_MERGE_CLUSTERS 505 return; 506#endif 507 508 if (unlikely (end - start < 2)) 509 return; 510 511 unsigned int cluster = info[start].cluster; 512 513 for (unsigned int i = start + 1; i < end; i++) 514 cluster = MIN (cluster, info[i].cluster); 515 516 /* Extend end */ 517 while (end < len && info[end - 1].cluster == info[end].cluster) 518 end++; 519 520 /* Extend start */ 521 while (idx < start && info[start - 1].cluster == info[start].cluster) 522 start--; 523 524 /* If we hit the start of buffer, continue in out-buffer. */ 525 if (idx == start) 526 for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--) 527 out_info[i - 1].cluster = cluster; 528 529 for (unsigned int i = start; i < end; i++) 530 info[i].cluster = cluster; 531} 532void 533hb_buffer_t::merge_out_clusters (unsigned int start, 534 unsigned int end) 535{ 536#ifdef HB_NO_MERGE_CLUSTERS 537 return; 538#endif 539 540 if (unlikely (end - start < 2)) 541 return; 542 543 unsigned int cluster = out_info[start].cluster; 544 545 for (unsigned int i = start + 1; i < end; i++) 546 cluster = MIN (cluster, out_info[i].cluster); 547 548 /* Extend start */ 549 while (start && out_info[start - 1].cluster == out_info[start].cluster) 550 start--; 551 552 /* Extend end */ 553 while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster) 554 end++; 555 556 /* If we hit the end of out-buffer, continue in buffer. */ 557 if (end == out_len) 558 for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++) 559 info[i].cluster = cluster; 560 561 for (unsigned int i = start; i < end; i++) 562 out_info[i].cluster = cluster; 563} 564 565void 566hb_buffer_t::guess_segment_properties (void) 567{ 568 assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || 569 (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); 570 571 /* If script is set to INVALID, guess from buffer contents */ 572 if (props.script == HB_SCRIPT_INVALID) { 573 for (unsigned int i = 0; i < len; i++) { 574 hb_script_t script = unicode->script (info[i].codepoint); 575 if (likely (script != HB_SCRIPT_COMMON && 576 script != HB_SCRIPT_INHERITED && 577 script != HB_SCRIPT_UNKNOWN)) { 578 props.script = script; 579 break; 580 } 581 } 582 } 583 584 /* If direction is set to INVALID, guess from script */ 585 if (props.direction == HB_DIRECTION_INVALID) { 586 props.direction = hb_script_get_horizontal_direction (props.script); 587 } 588 589 /* If language is not set, use default language from locale */ 590 if (props.language == HB_LANGUAGE_INVALID) { 591 /* TODO get_default_for_script? using $LANGUAGE */ 592 props.language = hb_language_get_default (); 593 } 594} 595 596 597static inline void 598dump_var_allocation (const hb_buffer_t *buffer) 599{ 600 char buf[80]; 601 for (unsigned int i = 0; i < 8; i++) 602 buf[i] = '0' + buffer->allocated_var_bytes[7 - i]; 603 buf[8] = '\0'; 604 DEBUG_MSG (BUFFER, buffer, 605 "Current var allocation: %s", 606 buf); 607} 608 609void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner) 610{ 611 assert (byte_i < 8 && byte_i + count <= 8); 612 613 if (DEBUG_ENABLED (BUFFER)) 614 dump_var_allocation (this); 615 DEBUG_MSG (BUFFER, this, 616 "Allocating var bytes %d..%d for %s", 617 byte_i, byte_i + count - 1, owner); 618 619 for (unsigned int i = byte_i; i < byte_i + count; i++) { 620 assert (!allocated_var_bytes[i]); 621 allocated_var_bytes[i]++; 622 allocated_var_owner[i] = owner; 623 } 624} 625 626void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner) 627{ 628 if (DEBUG_ENABLED (BUFFER)) 629 dump_var_allocation (this); 630 631 DEBUG_MSG (BUFFER, this, 632 "Deallocating var bytes %d..%d for %s", 633 byte_i, byte_i + count - 1, owner); 634 635 assert (byte_i < 8 && byte_i + count <= 8); 636 for (unsigned int i = byte_i; i < byte_i + count; i++) { 637 assert (allocated_var_bytes[i]); 638 assert (0 == strcmp (allocated_var_owner[i], owner)); 639 allocated_var_bytes[i]--; 640 } 641} 642 643void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner) 644{ 645 if (DEBUG_ENABLED (BUFFER)) 646 dump_var_allocation (this); 647 648 DEBUG_MSG (BUFFER, this, 649 "Asserting var bytes %d..%d for %s", 650 byte_i, byte_i + count - 1, owner); 651 652 assert (byte_i < 8 && byte_i + count <= 8); 653 for (unsigned int i = byte_i; i < byte_i + count; i++) { 654 assert (allocated_var_bytes[i]); 655 assert (0 == strcmp (allocated_var_owner[i], owner)); 656 } 657} 658 659void hb_buffer_t::deallocate_var_all (void) 660{ 661 memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes)); 662 memset (allocated_var_owner, 0, sizeof (allocated_var_owner)); 663} 664 665/* Public API */ 666 667/** 668 * hb_buffer_create: (Xconstructor) 669 * 670 * 671 * 672 * Return value: (transfer full) 673 * 674 * Since: 1.0 675 **/ 676hb_buffer_t * 677hb_buffer_create (void) 678{ 679 hb_buffer_t *buffer; 680 681 if (!(buffer = hb_object_create<hb_buffer_t> ())) 682 return hb_buffer_get_empty (); 683 684 buffer->reset (); 685 686 return buffer; 687} 688 689/** 690 * hb_buffer_get_empty: 691 * 692 * 693 * 694 * Return value: (transfer full): 695 * 696 * Since: 1.0 697 **/ 698hb_buffer_t * 699hb_buffer_get_empty (void) 700{ 701 static const hb_buffer_t _hb_buffer_nil = { 702 HB_OBJECT_HEADER_STATIC, 703 704 const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil), 705 HB_BUFFER_FLAG_DEFAULT, 706 HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT, 707 708 HB_BUFFER_CONTENT_TYPE_INVALID, 709 HB_SEGMENT_PROPERTIES_DEFAULT, 710 true, /* in_error */ 711 true, /* have_output */ 712 true /* have_positions */ 713 714 /* Zero is good enough for everything else. */ 715 }; 716 717 return const_cast<hb_buffer_t *> (&_hb_buffer_nil); 718} 719 720/** 721 * hb_buffer_reference: (skip) 722 * @buffer: a buffer. 723 * 724 * 725 * 726 * Return value: (transfer full): 727 * 728 * Since: 1.0 729 **/ 730hb_buffer_t * 731hb_buffer_reference (hb_buffer_t *buffer) 732{ 733 return hb_object_reference (buffer); 734} 735 736/** 737 * hb_buffer_destroy: (skip) 738 * @buffer: a buffer. 739 * 740 * 741 * 742 * Since: 1.0 743 **/ 744void 745hb_buffer_destroy (hb_buffer_t *buffer) 746{ 747 if (!hb_object_destroy (buffer)) return; 748 749 hb_unicode_funcs_destroy (buffer->unicode); 750 751 free (buffer->info); 752 free (buffer->pos); 753 754 free (buffer); 755} 756 757/** 758 * hb_buffer_set_user_data: (skip) 759 * @buffer: a buffer. 760 * @key: 761 * @data: 762 * @destroy: 763 * @replace: 764 * 765 * 766 * 767 * Return value: 768 * 769 * Since: 1.0 770 **/ 771hb_bool_t 772hb_buffer_set_user_data (hb_buffer_t *buffer, 773 hb_user_data_key_t *key, 774 void * data, 775 hb_destroy_func_t destroy, 776 hb_bool_t replace) 777{ 778 return hb_object_set_user_data (buffer, key, data, destroy, replace); 779} 780 781/** 782 * hb_buffer_get_user_data: (skip) 783 * @buffer: a buffer. 784 * @key: 785 * 786 * 787 * 788 * Return value: 789 * 790 * Since: 1.0 791 **/ 792void * 793hb_buffer_get_user_data (hb_buffer_t *buffer, 794 hb_user_data_key_t *key) 795{ 796 return hb_object_get_user_data (buffer, key); 797} 798 799 800/** 801 * hb_buffer_set_content_type: 802 * @buffer: a buffer. 803 * @content_type: 804 * 805 * 806 * 807 * Since: 1.0 808 **/ 809void 810hb_buffer_set_content_type (hb_buffer_t *buffer, 811 hb_buffer_content_type_t content_type) 812{ 813 buffer->content_type = content_type; 814} 815 816/** 817 * hb_buffer_get_content_type: 818 * @buffer: a buffer. 819 * 820 * 821 * 822 * Return value: 823 * 824 * Since: 1.0 825 **/ 826hb_buffer_content_type_t 827hb_buffer_get_content_type (hb_buffer_t *buffer) 828{ 829 return buffer->content_type; 830} 831 832 833/** 834 * hb_buffer_set_unicode_funcs: 835 * @buffer: a buffer. 836 * @unicode_funcs: 837 * 838 * 839 * 840 * Since: 1.0 841 **/ 842void 843hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, 844 hb_unicode_funcs_t *unicode_funcs) 845{ 846 if (unlikely (hb_object_is_inert (buffer))) 847 return; 848 849 if (!unicode_funcs) 850 unicode_funcs = hb_unicode_funcs_get_default (); 851 852 853 hb_unicode_funcs_reference (unicode_funcs); 854 hb_unicode_funcs_destroy (buffer->unicode); 855 buffer->unicode = unicode_funcs; 856} 857 858/** 859 * hb_buffer_get_unicode_funcs: 860 * @buffer: a buffer. 861 * 862 * 863 * 864 * Return value: 865 * 866 * Since: 1.0 867 **/ 868hb_unicode_funcs_t * 869hb_buffer_get_unicode_funcs (hb_buffer_t *buffer) 870{ 871 return buffer->unicode; 872} 873 874/** 875 * hb_buffer_set_direction: 876 * @buffer: a buffer. 877 * @direction: 878 * 879 * 880 * 881 * Since: 1.0 882 **/ 883void 884hb_buffer_set_direction (hb_buffer_t *buffer, 885 hb_direction_t direction) 886 887{ 888 if (unlikely (hb_object_is_inert (buffer))) 889 return; 890 891 buffer->props.direction = direction; 892} 893 894/** 895 * hb_buffer_get_direction: 896 * @buffer: a buffer. 897 * 898 * 899 * 900 * Return value: 901 * 902 * Since: 1.0 903 **/ 904hb_direction_t 905hb_buffer_get_direction (hb_buffer_t *buffer) 906{ 907 return buffer->props.direction; 908} 909 910/** 911 * hb_buffer_set_script: 912 * @buffer: a buffer. 913 * @script: 914 * 915 * 916 * 917 * Since: 1.0 918 **/ 919void 920hb_buffer_set_script (hb_buffer_t *buffer, 921 hb_script_t script) 922{ 923 if (unlikely (hb_object_is_inert (buffer))) 924 return; 925 926 buffer->props.script = script; 927} 928 929/** 930 * hb_buffer_get_script: 931 * @buffer: a buffer. 932 * 933 * 934 * 935 * Return value: 936 * 937 * Since: 1.0 938 **/ 939hb_script_t 940hb_buffer_get_script (hb_buffer_t *buffer) 941{ 942 return buffer->props.script; 943} 944 945/** 946 * hb_buffer_set_language: 947 * @buffer: a buffer. 948 * @language: 949 * 950 * 951 * 952 * Since: 1.0 953 **/ 954void 955hb_buffer_set_language (hb_buffer_t *buffer, 956 hb_language_t language) 957{ 958 if (unlikely (hb_object_is_inert (buffer))) 959 return; 960 961 buffer->props.language = language; 962} 963 964/** 965 * hb_buffer_get_language: 966 * @buffer: a buffer. 967 * 968 * 969 * 970 * Return value: 971 * 972 * Since: 1.0 973 **/ 974hb_language_t 975hb_buffer_get_language (hb_buffer_t *buffer) 976{ 977 return buffer->props.language; 978} 979 980/** 981 * hb_buffer_set_segment_properties: 982 * @buffer: a buffer. 983 * @props: 984 * 985 * 986 * 987 * Since: 1.0 988 **/ 989void 990hb_buffer_set_segment_properties (hb_buffer_t *buffer, 991 const hb_segment_properties_t *props) 992{ 993 if (unlikely (hb_object_is_inert (buffer))) 994 return; 995 996 buffer->props = *props; 997} 998 999/** 1000 * hb_buffer_get_segment_properties: 1001 * @buffer: a buffer. 1002 * @props: 1003 * 1004 * 1005 * 1006 * Since: 1.0 1007 **/ 1008void 1009hb_buffer_get_segment_properties (hb_buffer_t *buffer, 1010 hb_segment_properties_t *props) 1011{ 1012 *props = buffer->props; 1013} 1014 1015 1016/** 1017 * hb_buffer_set_flags: 1018 * @buffer: a buffer. 1019 * @flags: 1020 * 1021 * 1022 * 1023 * Since: 1.0 1024 **/ 1025void 1026hb_buffer_set_flags (hb_buffer_t *buffer, 1027 hb_buffer_flags_t flags) 1028{ 1029 if (unlikely (hb_object_is_inert (buffer))) 1030 return; 1031 1032 buffer->flags = flags; 1033} 1034 1035/** 1036 * hb_buffer_get_flags: 1037 * @buffer: a buffer. 1038 * 1039 * 1040 * 1041 * Return value: 1042 * 1043 * Since: 1.0 1044 **/ 1045hb_buffer_flags_t 1046hb_buffer_get_flags (hb_buffer_t *buffer) 1047{ 1048 return buffer->flags; 1049} 1050 1051 1052/** 1053 * hb_buffer_set_replacement_codepoint: 1054 * @buffer: a buffer. 1055 * @replacement: 1056 * 1057 * 1058 * 1059 * Since: 1.0 1060 **/ 1061void 1062hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer, 1063 hb_codepoint_t replacement) 1064{ 1065 if (unlikely (hb_object_is_inert (buffer))) 1066 return; 1067 1068 buffer->replacement = replacement; 1069} 1070 1071/** 1072 * hb_buffer_get_replacement_codepoint: 1073 * @buffer: a buffer. 1074 * 1075 * 1076 * 1077 * Return value: 1078 * 1079 * Since: 1.0 1080 **/ 1081hb_codepoint_t 1082hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer) 1083{ 1084 return buffer->replacement; 1085} 1086 1087 1088/** 1089 * hb_buffer_reset: 1090 * @buffer: a buffer. 1091 * 1092 * 1093 * 1094 * Since: 1.0 1095 **/ 1096void 1097hb_buffer_reset (hb_buffer_t *buffer) 1098{ 1099 buffer->reset (); 1100} 1101 1102/** 1103 * hb_buffer_clear_contents: 1104 * @buffer: a buffer. 1105 * 1106 * 1107 * 1108 * Since: 1.0 1109 **/ 1110void 1111hb_buffer_clear_contents (hb_buffer_t *buffer) 1112{ 1113 buffer->clear (); 1114} 1115 1116/** 1117 * hb_buffer_pre_allocate: 1118 * @buffer: a buffer. 1119 * @size: 1120 * 1121 * 1122 * 1123 * Return value: 1124 * 1125 * Since: 1.0 1126 **/ 1127hb_bool_t 1128hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size) 1129{ 1130 return buffer->ensure (size); 1131} 1132 1133/** 1134 * hb_buffer_allocation_successful: 1135 * @buffer: a buffer. 1136 * 1137 * 1138 * 1139 * Return value: 1140 * 1141 * Since: 1.0 1142 **/ 1143hb_bool_t 1144hb_buffer_allocation_successful (hb_buffer_t *buffer) 1145{ 1146 return !buffer->in_error; 1147} 1148 1149/** 1150 * hb_buffer_add: 1151 * @buffer: a buffer. 1152 * @codepoint: 1153 * @cluster: 1154 * 1155 * 1156 * 1157 * Since: 1.0 1158 **/ 1159void 1160hb_buffer_add (hb_buffer_t *buffer, 1161 hb_codepoint_t codepoint, 1162 unsigned int cluster) 1163{ 1164 buffer->add (codepoint, cluster); 1165 buffer->clear_context (1); 1166} 1167 1168/** 1169 * hb_buffer_set_length: 1170 * @buffer: a buffer. 1171 * @length: 1172 * 1173 * 1174 * 1175 * Return value: 1176 * 1177 * Since: 1.0 1178 **/ 1179hb_bool_t 1180hb_buffer_set_length (hb_buffer_t *buffer, 1181 unsigned int length) 1182{ 1183 if (unlikely (hb_object_is_inert (buffer))) 1184 return length == 0; 1185 1186 if (!buffer->ensure (length)) 1187 return false; 1188 1189 /* Wipe the new space */ 1190 if (length > buffer->len) { 1191 memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len)); 1192 if (buffer->have_positions) 1193 memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len)); 1194 } 1195 1196 buffer->len = length; 1197 1198 if (!length) 1199 { 1200 buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID; 1201 buffer->clear_context (0); 1202 } 1203 buffer->clear_context (1); 1204 1205 return true; 1206} 1207 1208/** 1209 * hb_buffer_get_length: 1210 * @buffer: a buffer. 1211 * 1212 * Returns the number of items in the buffer. 1213 * 1214 * Return value: buffer length. 1215 * 1216 * Since: 1.0 1217 **/ 1218unsigned int 1219hb_buffer_get_length (hb_buffer_t *buffer) 1220{ 1221 return buffer->len; 1222} 1223 1224/** 1225 * hb_buffer_get_glyph_infos: 1226 * @buffer: a buffer. 1227 * @length: (out): output array length. 1228 * 1229 * Returns buffer glyph information array. Returned pointer 1230 * is valid as long as buffer contents are not modified. 1231 * 1232 * Return value: (transfer none) (array length=length): buffer glyph information array. 1233 * 1234 * Since: 1.0 1235 **/ 1236hb_glyph_info_t * 1237hb_buffer_get_glyph_infos (hb_buffer_t *buffer, 1238 unsigned int *length) 1239{ 1240 if (length) 1241 *length = buffer->len; 1242 1243 return (hb_glyph_info_t *) buffer->info; 1244} 1245 1246/** 1247 * hb_buffer_get_glyph_positions: 1248 * @buffer: a buffer. 1249 * @length: (out): output length. 1250 * 1251 * Returns buffer glyph position array. Returned pointer 1252 * is valid as long as buffer contents are not modified. 1253 * 1254 * Return value: (transfer none) (array length=length): buffer glyph position array. 1255 * 1256 * Since: 1.0 1257 **/ 1258hb_glyph_position_t * 1259hb_buffer_get_glyph_positions (hb_buffer_t *buffer, 1260 unsigned int *length) 1261{ 1262 if (!buffer->have_positions) 1263 buffer->clear_positions (); 1264 1265 if (length) 1266 *length = buffer->len; 1267 1268 return (hb_glyph_position_t *) buffer->pos; 1269} 1270 1271/** 1272 * hb_buffer_reverse: 1273 * @buffer: a buffer. 1274 * 1275 * Reverses buffer contents. 1276 * 1277 * Since: 1.0 1278 **/ 1279void 1280hb_buffer_reverse (hb_buffer_t *buffer) 1281{ 1282 buffer->reverse (); 1283} 1284 1285/** 1286 * hb_buffer_reverse_clusters: 1287 * @buffer: a buffer. 1288 * 1289 * Reverses buffer clusters. That is, the buffer contents are 1290 * reversed, then each cluster (consecutive items having the 1291 * same cluster number) are reversed again. 1292 * 1293 * Since: 1.0 1294 **/ 1295void 1296hb_buffer_reverse_clusters (hb_buffer_t *buffer) 1297{ 1298 buffer->reverse_clusters (); 1299} 1300 1301/** 1302 * hb_buffer_guess_segment_properties: 1303 * @buffer: a buffer. 1304 * 1305 * Sets unset buffer segment properties based on buffer Unicode 1306 * contents. If buffer is not empty, it must have content type 1307 * %HB_BUFFER_CONTENT_TYPE_UNICODE. 1308 * 1309 * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it 1310 * will be set to the Unicode script of the first character in 1311 * the buffer that has a script other than %HB_SCRIPT_COMMON, 1312 * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN. 1313 * 1314 * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID), 1315 * it will be set to the natural horizontal direction of the 1316 * buffer script as returned by hb_script_get_horizontal_direction(). 1317 * 1318 * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID), 1319 * it will be set to the process's default language as returned by 1320 * hb_language_get_default(). This may change in the future by 1321 * taking buffer script into consideration when choosing a language. 1322 * 1323 * Since: 1.0 1324 **/ 1325void 1326hb_buffer_guess_segment_properties (hb_buffer_t *buffer) 1327{ 1328 buffer->guess_segment_properties (); 1329} 1330 1331template <bool validate, typename T> 1332static inline void 1333hb_buffer_add_utf (hb_buffer_t *buffer, 1334 const T *text, 1335 int text_length, 1336 unsigned int item_offset, 1337 int item_length) 1338{ 1339 typedef hb_utf_t<T, true> utf_t; 1340 const hb_codepoint_t replacement = buffer->replacement; 1341 1342 assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || 1343 (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); 1344 1345 if (unlikely (hb_object_is_inert (buffer))) 1346 return; 1347 1348 if (text_length == -1) 1349 text_length = utf_t::strlen (text); 1350 1351 if (item_length == -1) 1352 item_length = text_length - item_offset; 1353 1354 buffer->ensure (buffer->len + item_length * sizeof (T) / 4); 1355 1356 /* If buffer is empty and pre-context provided, install it. 1357 * This check is written this way, to make sure people can 1358 * provide pre-context in one add_utf() call, then provide 1359 * text in a follow-up call. See: 1360 * 1361 * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13 1362 */ 1363 if (!buffer->len && item_offset > 0) 1364 { 1365 /* Add pre-context */ 1366 buffer->clear_context (0); 1367 const T *prev = text + item_offset; 1368 const T *start = text; 1369 while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH) 1370 { 1371 hb_codepoint_t u; 1372 prev = utf_t::prev (prev, start, &u, replacement); 1373 buffer->context[0][buffer->context_len[0]++] = u; 1374 } 1375 } 1376 1377 const T *next = text + item_offset; 1378 const T *end = next + item_length; 1379 while (next < end) 1380 { 1381 hb_codepoint_t u; 1382 const T *old_next = next; 1383 next = utf_t::next (next, end, &u, replacement); 1384 buffer->add (u, old_next - (const T *) text); 1385 } 1386 1387 /* Add post-context */ 1388 buffer->clear_context (1); 1389 end = text + text_length; 1390 while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH) 1391 { 1392 hb_codepoint_t u; 1393 next = utf_t::next (next, end, &u, replacement); 1394 buffer->context[1][buffer->context_len[1]++] = u; 1395 } 1396 1397 buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE; 1398} 1399 1400/** 1401 * hb_buffer_add_utf8: 1402 * @buffer: a buffer. 1403 * @text: (array length=text_length): 1404 * @text_length: 1405 * @item_offset: 1406 * @item_length: 1407 * 1408 * 1409 * 1410 * Since: 1.0 1411 **/ 1412void 1413hb_buffer_add_utf8 (hb_buffer_t *buffer, 1414 const char *text, 1415 int text_length, 1416 unsigned int item_offset, 1417 int item_length) 1418{ 1419 hb_buffer_add_utf<true> (buffer, (const uint8_t *) text, text_length, item_offset, item_length); 1420} 1421 1422/** 1423 * hb_buffer_add_utf16: 1424 * @buffer: a buffer. 1425 * @text: (array length=text_length): 1426 * @text_length: 1427 * @item_offset: 1428 * @item_length: 1429 * 1430 * 1431 * 1432 * Since: 1.0 1433 **/ 1434void 1435hb_buffer_add_utf16 (hb_buffer_t *buffer, 1436 const uint16_t *text, 1437 int text_length, 1438 unsigned int item_offset, 1439 int item_length) 1440{ 1441 hb_buffer_add_utf<true> (buffer, text, text_length, item_offset, item_length); 1442} 1443 1444/** 1445 * hb_buffer_add_utf32: 1446 * @buffer: a buffer. 1447 * @text: (array length=text_length): 1448 * @text_length: 1449 * @item_offset: 1450 * @item_length: 1451 * 1452 * 1453 * 1454 * Since: 1.0 1455 **/ 1456void 1457hb_buffer_add_utf32 (hb_buffer_t *buffer, 1458 const uint32_t *text, 1459 int text_length, 1460 unsigned int item_offset, 1461 int item_length) 1462{ 1463 hb_buffer_add_utf<true> (buffer, text, text_length, item_offset, item_length); 1464} 1465 1466/** 1467 * hb_buffer_add_codepoints: 1468 * @buffer: a buffer. 1469 * @text: (array length=text_length): 1470 * @text_length: 1471 * @item_offset: 1472 * @item_length: 1473 * 1474 * 1475 * 1476 * Since: 1.0 1477 **/ 1478void 1479hb_buffer_add_codepoints (hb_buffer_t *buffer, 1480 const hb_codepoint_t *text, 1481 int text_length, 1482 unsigned int item_offset, 1483 int item_length) 1484{ 1485 hb_buffer_add_utf<false> (buffer, text, text_length, item_offset, item_length); 1486} 1487 1488 1489static int 1490compare_info_codepoint (const hb_glyph_info_t *pa, 1491 const hb_glyph_info_t *pb) 1492{ 1493 return (int) pb->codepoint - (int) pa->codepoint; 1494} 1495 1496static inline void 1497normalize_glyphs_cluster (hb_buffer_t *buffer, 1498 unsigned int start, 1499 unsigned int end, 1500 bool backward) 1501{ 1502 hb_glyph_position_t *pos = buffer->pos; 1503 1504 /* Total cluster advance */ 1505 hb_position_t total_x_advance = 0, total_y_advance = 0; 1506 for (unsigned int i = start; i < end; i++) 1507 { 1508 total_x_advance += pos[i].x_advance; 1509 total_y_advance += pos[i].y_advance; 1510 } 1511 1512 hb_position_t x_advance = 0, y_advance = 0; 1513 for (unsigned int i = start; i < end; i++) 1514 { 1515 pos[i].x_offset += x_advance; 1516 pos[i].y_offset += y_advance; 1517 1518 x_advance += pos[i].x_advance; 1519 y_advance += pos[i].y_advance; 1520 1521 pos[i].x_advance = 0; 1522 pos[i].y_advance = 0; 1523 } 1524 1525 if (backward) 1526 { 1527 /* Transfer all cluster advance to the last glyph. */ 1528 pos[end - 1].x_advance = total_x_advance; 1529 pos[end - 1].y_advance = total_y_advance; 1530 1531 hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start); 1532 } else { 1533 /* Transfer all cluster advance to the first glyph. */ 1534 pos[start].x_advance += total_x_advance; 1535 pos[start].y_advance += total_y_advance; 1536 for (unsigned int i = start + 1; i < end; i++) { 1537 pos[i].x_offset -= total_x_advance; 1538 pos[i].y_offset -= total_y_advance; 1539 } 1540 hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1); 1541 } 1542} 1543 1544/** 1545 * hb_buffer_normalize_glyphs: 1546 * @buffer: a buffer. 1547 * 1548 * 1549 * 1550 * Since: 1.0 1551 **/ 1552void 1553hb_buffer_normalize_glyphs (hb_buffer_t *buffer) 1554{ 1555 assert (buffer->have_positions); 1556 assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); 1557 1558 bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); 1559 1560 unsigned int count = buffer->len; 1561 if (unlikely (!count)) return; 1562 hb_glyph_info_t *info = buffer->info; 1563 1564 unsigned int start = 0; 1565 unsigned int end; 1566 for (end = start + 1; end < count; end++) 1567 if (info[start].cluster != info[end].cluster) { 1568 normalize_glyphs_cluster (buffer, start, end, backward); 1569 start = end; 1570 } 1571 normalize_glyphs_cluster (buffer, start, end, backward); 1572} 1573