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