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 142void * 143hb_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 159void 160hb_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 171void 172hb_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 199void 200hb_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 217void 218hb_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 228void 229hb_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 241void 242hb_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 254void 255hb_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 269void 270hb_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 295void 296hb_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 317void 318hb_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 328void 329hb_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 338void 339hb_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 348void 349hb_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 362void 363hb_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 387void 388hb_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 415void 416hb_buffer_t::reverse (void) 417{ 418 if (unlikely (!len)) 419 return; 420 421 reverse_range (0, len); 422} 423 424void 425hb_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 447void 448hb_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} 475void 476hb_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 504void 505hb_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 536static inline void 537dump_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 548void 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_ENABLED (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 565void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner) 566{ 567 if (DEBUG_ENABLED (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 582void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner) 583{ 584 if (DEBUG_ENABLED (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 598void 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 606hb_buffer_t * 607hb_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 619hb_buffer_t * 620hb_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 640hb_buffer_t * 641hb_buffer_reference (hb_buffer_t *buffer) 642{ 643 return hb_object_reference (buffer); 644} 645 646void 647hb_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 659hb_bool_t 660hb_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 669void * 670hb_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 677void 678hb_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 684hb_buffer_content_type_t 685hb_buffer_get_content_type (hb_buffer_t *buffer) 686{ 687 return buffer->content_type; 688} 689 690 691void 692hb_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 707hb_unicode_funcs_t * 708hb_buffer_get_unicode_funcs (hb_buffer_t *buffer) 709{ 710 return buffer->unicode; 711} 712 713void 714hb_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 724hb_direction_t 725hb_buffer_get_direction (hb_buffer_t *buffer) 726{ 727 return buffer->props.direction; 728} 729 730void 731hb_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 740hb_script_t 741hb_buffer_get_script (hb_buffer_t *buffer) 742{ 743 return buffer->props.script; 744} 745 746void 747hb_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 756hb_language_t 757hb_buffer_get_language (hb_buffer_t *buffer) 758{ 759 return buffer->props.language; 760} 761 762void 763hb_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 772void 773hb_buffer_get_segment_properties (hb_buffer_t *buffer, 774 hb_segment_properties_t *props) 775{ 776 *props = buffer->props; 777} 778 779 780void 781hb_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 790hb_buffer_flags_t 791hb_buffer_get_flags (hb_buffer_t *buffer) 792{ 793 return buffer->flags; 794} 795 796 797void 798hb_buffer_reset (hb_buffer_t *buffer) 799{ 800 buffer->reset (); 801} 802 803void 804hb_buffer_clear_contents (hb_buffer_t *buffer) 805{ 806 buffer->clear (); 807} 808 809hb_bool_t 810hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size) 811{ 812 return buffer->ensure (size); 813} 814 815hb_bool_t 816hb_buffer_allocation_successful (hb_buffer_t *buffer) 817{ 818 return !buffer->in_error; 819} 820 821void 822hb_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 830hb_bool_t 831hb_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 856unsigned int 857hb_buffer_get_length (hb_buffer_t *buffer) 858{ 859 return buffer->len; 860} 861 862/* Return value valid as long as buffer not modified */ 863hb_glyph_info_t * 864hb_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 */ 874hb_glyph_position_t * 875hb_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 887void 888hb_buffer_reverse (hb_buffer_t *buffer) 889{ 890 buffer->reverse (); 891} 892 893void 894hb_buffer_reverse_clusters (hb_buffer_t *buffer) 895{ 896 buffer->reverse_clusters (); 897} 898 899void 900hb_buffer_guess_segment_properties (hb_buffer_t *buffer) 901{ 902 buffer->guess_segment_properties (); 903} 904 905template <typename T> 906static inline void 907hb_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 971void 972hb_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 981void 982hb_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 991void 992hb_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 1002static int 1003compare_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 1009static inline void 1010normalize_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 1057void 1058hb_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