hb-buffer.cc revision e1ac38f8dd04c29d2d4140f5a492cdaf25d72901
1/* 2 * Copyright © 1998-2004 David Turner and Werner Lemberg 3 * Copyright © 2004,2007,2009,2010 Red Hat, Inc. 4 * Copyright © 2011 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 32#include <string.h> 33 34 35 36#ifndef HB_DEBUG_BUFFER 37#define HB_DEBUG_BUFFER (HB_DEBUG+0) 38#endif 39 40#define _HB_BUFFER_UNICODE_FUNCS_DEFAULT (const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_default)) 41#define _HB_BUFFER_PROPS_DEFAULT { HB_DIRECTION_INVALID, HB_SCRIPT_INVALID, HB_LANGUAGE_INVALID } 42 43/* Here is how the buffer works internally: 44 * 45 * There are two info pointers: info and out_info. They always have 46 * the same allocated size, but different lengths. 47 * 48 * As an optimization, both info and out_info may point to the 49 * same piece of memory, which is owned by info. This remains the 50 * case as long as out_len doesn't exceed i at any time. 51 * In that case, swap_buffers() is no-op and the glyph operations operate 52 * mostly in-place. 53 * 54 * As soon as out_info gets longer than info, out_info is moved over 55 * to an alternate buffer (which we reuse the pos buffer for!), and its 56 * current contents (out_len entries) are copied to the new place. 57 * This should all remain transparent to the user. swap_buffers() then 58 * switches info and out_info. 59 */ 60 61 62 63/* Internal API */ 64 65bool 66hb_buffer_t::enlarge (unsigned int size) 67{ 68 if (unlikely (in_error)) 69 return FALSE; 70 71 unsigned int new_allocated = allocated; 72 hb_glyph_position_t *new_pos = NULL; 73 hb_glyph_info_t *new_info = NULL; 74 bool separate_out = out_info != info; 75 76 if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0])))) 77 goto done; 78 79 while (size > new_allocated) 80 new_allocated += (new_allocated >> 1) + 32; 81 82 ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0])); 83 if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0])))) 84 goto done; 85 86 new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0])); 87 new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0])); 88 89done: 90 if (unlikely (!new_pos || !new_info)) 91 in_error = TRUE; 92 93 if (likely (new_pos)) 94 pos = new_pos; 95 96 if (likely (new_info)) 97 info = new_info; 98 99 out_info = separate_out ? (hb_glyph_info_t *) pos : info; 100 if (likely (!in_error)) 101 allocated = new_allocated; 102 103 return likely (!in_error); 104} 105 106bool 107hb_buffer_t::make_room_for (unsigned int num_in, 108 unsigned int num_out) 109{ 110 if (unlikely (!ensure (out_len + num_out))) return FALSE; 111 112 if (out_info == info && 113 out_len + num_out > idx + num_in) 114 { 115 assert (have_output); 116 117 out_info = (hb_glyph_info_t *) pos; 118 memcpy (out_info, info, out_len * sizeof (out_info[0])); 119 } 120 121 return TRUE; 122} 123 124void * 125hb_buffer_t::get_scratch_buffer (unsigned int *size) 126{ 127 have_output = FALSE; 128 have_positions = FALSE; 129 out_len = 0; 130 *size = allocated * sizeof (pos[0]); 131 return pos; 132} 133 134 135/* HarfBuzz-Internal API */ 136 137void 138hb_buffer_t::reset (void) 139{ 140 if (unlikely (hb_object_is_inert (this))) 141 return; 142 143 hb_unicode_funcs_destroy (unicode); 144 unicode = _HB_BUFFER_UNICODE_FUNCS_DEFAULT; 145 146 hb_segment_properties_t default_props = _HB_BUFFER_PROPS_DEFAULT; 147 props = default_props; 148 149 in_error = FALSE; 150 have_output = FALSE; 151 have_positions = FALSE; 152 153 idx = 0; 154 len = 0; 155 out_len = 0; 156 157 serial = 0; 158 memset (allocated_var_bytes, 0, sizeof allocated_var_bytes); 159 memset (allocated_var_owner, 0, sizeof allocated_var_owner); 160 161 out_info = info; 162} 163 164void 165hb_buffer_t::add (hb_codepoint_t codepoint, 166 hb_mask_t mask, 167 unsigned int cluster) 168{ 169 hb_glyph_info_t *glyph; 170 171 if (unlikely (!ensure (len + 1))) return; 172 173 glyph = &info[len]; 174 175 memset (glyph, 0, sizeof (*glyph)); 176 glyph->codepoint = codepoint; 177 glyph->mask = mask; 178 glyph->cluster = cluster; 179 180 len++; 181} 182 183void 184hb_buffer_t::clear_output (void) 185{ 186 if (unlikely (hb_object_is_inert (this))) 187 return; 188 189 have_output = TRUE; 190 have_positions = FALSE; 191 192 out_len = 0; 193 out_info = info; 194} 195 196void 197hb_buffer_t::clear_positions (void) 198{ 199 if (unlikely (hb_object_is_inert (this))) 200 return; 201 202 have_output = FALSE; 203 have_positions = TRUE; 204 205 memset (pos, 0, sizeof (pos[0]) * len); 206} 207 208void 209hb_buffer_t::swap_buffers (void) 210{ 211 if (unlikely (in_error)) return; 212 213 assert (have_output); 214 have_output = FALSE; 215 216 if (out_info != info) 217 { 218 hb_glyph_info_t *tmp_string; 219 tmp_string = info; 220 info = out_info; 221 out_info = tmp_string; 222 pos = (hb_glyph_position_t *) out_info; 223 } 224 225 unsigned int tmp; 226 tmp = len; 227 len = out_len; 228 out_len = tmp; 229 230 idx = 0; 231} 232 233void 234hb_buffer_t::replace_glyphs_be16 (unsigned int num_in, 235 unsigned int num_out, 236 const uint16_t *glyph_data_be) 237{ 238 if (!make_room_for (num_in, num_out)) return; 239 240 hb_glyph_info_t orig_info = info[idx]; 241 for (unsigned int i = 1; i < num_in; i++) 242 { 243 hb_glyph_info_t *inf = &info[idx + i]; 244 orig_info.cluster = MIN (orig_info.cluster, inf->cluster); 245 } 246 247 hb_glyph_info_t *pinfo = &out_info[out_len]; 248 for (unsigned int i = 0; i < num_out; i++) 249 { 250 *pinfo = orig_info; 251 pinfo->codepoint = hb_be_uint16 (glyph_data_be[i]); 252 pinfo++; 253 } 254 255 idx += num_in; 256 out_len += num_out; 257} 258 259void 260hb_buffer_t::replace_glyphs (unsigned int num_in, 261 unsigned int num_out, 262 const uint32_t *glyph_data) 263{ 264 if (!make_room_for (num_in, num_out)) return; 265 266 hb_glyph_info_t orig_info = info[idx]; 267 for (unsigned int i = 1; i < num_in; i++) 268 { 269 hb_glyph_info_t *inf = &info[idx + i]; 270 orig_info.cluster = MIN (orig_info.cluster, inf->cluster); 271 } 272 273 hb_glyph_info_t *pinfo = &out_info[out_len]; 274 for (unsigned int i = 0; i < num_out; i++) 275 { 276 *pinfo = orig_info; 277 pinfo->codepoint = glyph_data[i]; 278 pinfo++; 279 } 280 281 idx += num_in; 282 out_len += num_out; 283} 284 285void 286hb_buffer_t::output_glyph (hb_codepoint_t glyph_index) 287{ 288 if (!make_room_for (0, 1)) return; 289 290 out_info[out_len] = info[idx]; 291 out_info[out_len].codepoint = glyph_index; 292 293 out_len++; 294} 295 296void 297hb_buffer_t::copy_glyph (void) 298{ 299 if (!make_room_for (0, 1)) return; 300 301 out_info[out_len] = info[idx]; 302 303 out_len++; 304} 305 306void 307hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index) 308{ 309 if (!make_room_for (1, 1)) return; 310 311 out_info[out_len] = info[idx]; 312 out_info[out_len].codepoint = glyph_index; 313 314 idx++; 315 out_len++; 316} 317 318void 319hb_buffer_t::next_glyph (void) 320{ 321 if (have_output) 322 { 323 if (out_info != info) 324 { 325 if (unlikely (!ensure (out_len + 1))) return; 326 out_info[out_len] = info[idx]; 327 } 328 else if (out_len != idx) 329 out_info[out_len] = info[idx]; 330 331 out_len++; 332 } 333 334 idx++; 335} 336 337void 338hb_buffer_t::set_masks (hb_mask_t value, 339 hb_mask_t mask, 340 unsigned int cluster_start, 341 unsigned int cluster_end) 342{ 343 hb_mask_t not_mask = ~mask; 344 value &= mask; 345 346 if (!mask) 347 return; 348 349 if (cluster_start == 0 && cluster_end == (unsigned int)-1) { 350 unsigned int count = len; 351 for (unsigned int i = 0; i < count; i++) 352 info[i].mask = (info[i].mask & not_mask) | value; 353 return; 354 } 355 356 unsigned int count = len; 357 for (unsigned int i = 0; i < count; i++) 358 if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end) 359 info[i].mask = (info[i].mask & not_mask) | value; 360} 361 362void 363hb_buffer_t::reverse_range (unsigned int start, 364 unsigned int end) 365{ 366 unsigned int i, j; 367 368 if (start == end - 1) 369 return; 370 371 for (i = start, j = end - 1; i < j; i++, j--) { 372 hb_glyph_info_t t; 373 374 t = info[i]; 375 info[i] = info[j]; 376 info[j] = t; 377 } 378 379 if (pos) { 380 for (i = start, j = end - 1; i < j; i++, j--) { 381 hb_glyph_position_t t; 382 383 t = pos[i]; 384 pos[i] = pos[j]; 385 pos[j] = t; 386 } 387 } 388} 389 390void 391hb_buffer_t::reverse (void) 392{ 393 if (unlikely (!len)) 394 return; 395 396 reverse_range (0, len); 397} 398 399void 400hb_buffer_t::reverse_clusters (void) 401{ 402 unsigned int i, start, count, last_cluster; 403 404 if (unlikely (!len)) 405 return; 406 407 reverse (); 408 409 count = len; 410 start = 0; 411 last_cluster = info[0].cluster; 412 for (i = 1; i < count; i++) { 413 if (last_cluster != info[i].cluster) { 414 reverse_range (start, i); 415 start = i; 416 last_cluster = info[i].cluster; 417 } 418 } 419 reverse_range (start, i); 420} 421 422void 423hb_buffer_t::merge_clusters (unsigned int start, 424 unsigned int end) 425{ 426 unsigned int cluster = this->info[start].cluster; 427 428 for (unsigned int i = start + 1; i < end; i++) 429 cluster = MIN (cluster, this->info[i].cluster); 430 for (unsigned int i = start; i < end; i++) 431 this->info[i].cluster = cluster; 432} 433void 434hb_buffer_t::merge_out_clusters (unsigned int start, 435 unsigned int end) 436{ 437 unsigned int cluster = this->out_info[start].cluster; 438 439 for (unsigned int i = start + 1; i < end; i++) 440 cluster = MIN (cluster, this->out_info[i].cluster); 441 for (unsigned int i = start; i < end; i++) 442 this->out_info[i].cluster = cluster; 443} 444 445void 446hb_buffer_t::guess_properties (void) 447{ 448 /* If script is set to INVALID, guess from buffer contents */ 449 if (props.script == HB_SCRIPT_INVALID) { 450 for (unsigned int i = 0; i < len; i++) { 451 hb_script_t script = hb_unicode_script (unicode, info[i].codepoint); 452 if (likely (script != HB_SCRIPT_COMMON && 453 script != HB_SCRIPT_INHERITED && 454 script != HB_SCRIPT_UNKNOWN)) { 455 props.script = script; 456 break; 457 } 458 } 459 } 460 461 /* If direction is set to INVALID, guess from script */ 462 if (props.direction == HB_DIRECTION_INVALID) { 463 props.direction = hb_script_get_horizontal_direction (props.script); 464 } 465 466 /* If language is not set, use default language from locale */ 467 if (props.language == HB_LANGUAGE_INVALID) { 468 /* TODO get_default_for_script? using $LANGUAGE */ 469 props.language = hb_language_get_default (); 470 } 471} 472 473 474static inline void 475dump_var_allocation (const hb_buffer_t *buffer) 476{ 477 char buf[80]; 478 for (unsigned int i = 0; i < 8; i++) 479 buf[i] = '0' + buffer->allocated_var_bytes[7 - i]; 480 buf[8] = '\0'; 481 DEBUG_MSG (BUFFER, buffer, 482 "Current var allocation: %s", 483 buf); 484} 485 486void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner) 487{ 488 assert (byte_i < 8 && byte_i + count <= 8); 489 490 if (DEBUG (BUFFER)) 491 dump_var_allocation (this); 492 DEBUG_MSG (BUFFER, this, 493 "Allocating var bytes %d..%d for %s", 494 byte_i, byte_i + count - 1, owner); 495 496 for (unsigned int i = byte_i; i < byte_i + count; i++) { 497 assert (!allocated_var_bytes[i]); 498 allocated_var_bytes[i]++; 499 allocated_var_owner[i] = owner; 500 } 501} 502 503void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner) 504{ 505 if (DEBUG (BUFFER)) 506 dump_var_allocation (this); 507 508 DEBUG_MSG (BUFFER, this, 509 "Deallocating var bytes %d..%d for %s", 510 byte_i, byte_i + count - 1, owner); 511 512 assert (byte_i < 8 && byte_i + count <= 8); 513 for (unsigned int i = byte_i; i < byte_i + count; i++) { 514 assert (allocated_var_bytes[i]); 515 assert (0 == strcmp (allocated_var_owner[i], owner)); 516 allocated_var_bytes[i]--; 517 } 518} 519 520void hb_buffer_t::deallocate_var_all (void) 521{ 522 memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes)); 523 memset (allocated_var_owner, 0, sizeof (allocated_var_owner)); 524} 525 526/* Public API */ 527 528hb_buffer_t * 529hb_buffer_create () 530{ 531 hb_buffer_t *buffer; 532 533 if (!(buffer = hb_object_create<hb_buffer_t> ())) 534 return hb_buffer_get_empty (); 535 536 buffer->reset (); 537 538 return buffer; 539} 540 541hb_buffer_t * 542hb_buffer_get_empty (void) 543{ 544 static const hb_buffer_t _hb_buffer_nil = { 545 HB_OBJECT_HEADER_STATIC, 546 547 _HB_BUFFER_UNICODE_FUNCS_DEFAULT, 548 _HB_BUFFER_PROPS_DEFAULT, 549 550 TRUE, /* in_error */ 551 TRUE, /* have_output */ 552 TRUE /* have_positions */ 553 }; 554 555 return const_cast<hb_buffer_t *> (&_hb_buffer_nil); 556} 557 558hb_buffer_t * 559hb_buffer_reference (hb_buffer_t *buffer) 560{ 561 return hb_object_reference (buffer); 562} 563 564void 565hb_buffer_destroy (hb_buffer_t *buffer) 566{ 567 if (!hb_object_destroy (buffer)) return; 568 569 hb_unicode_funcs_destroy (buffer->unicode); 570 571 free (buffer->info); 572 free (buffer->pos); 573 574 free (buffer); 575} 576 577hb_bool_t 578hb_buffer_set_user_data (hb_buffer_t *buffer, 579 hb_user_data_key_t *key, 580 void * data, 581 hb_destroy_func_t destroy, 582 hb_bool_t replace) 583{ 584 return hb_object_set_user_data (buffer, key, data, destroy, replace); 585} 586 587void * 588hb_buffer_get_user_data (hb_buffer_t *buffer, 589 hb_user_data_key_t *key) 590{ 591 return hb_object_get_user_data (buffer, key); 592} 593 594 595void 596hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, 597 hb_unicode_funcs_t *unicode) 598{ 599 if (unlikely (hb_object_is_inert (buffer))) 600 return; 601 602 if (!unicode) 603 unicode = _HB_BUFFER_UNICODE_FUNCS_DEFAULT; 604 605 hb_unicode_funcs_reference (unicode); 606 hb_unicode_funcs_destroy (buffer->unicode); 607 buffer->unicode = unicode; 608} 609 610hb_unicode_funcs_t * 611hb_buffer_get_unicode_funcs (hb_buffer_t *buffer) 612{ 613 return buffer->unicode; 614} 615 616void 617hb_buffer_set_direction (hb_buffer_t *buffer, 618 hb_direction_t direction) 619 620{ 621 if (unlikely (hb_object_is_inert (buffer))) 622 return; 623 624 buffer->props.direction = direction; 625} 626 627hb_direction_t 628hb_buffer_get_direction (hb_buffer_t *buffer) 629{ 630 return buffer->props.direction; 631} 632 633void 634hb_buffer_set_script (hb_buffer_t *buffer, 635 hb_script_t script) 636{ 637 if (unlikely (hb_object_is_inert (buffer))) 638 return; 639 640 buffer->props.script = script; 641} 642 643hb_script_t 644hb_buffer_get_script (hb_buffer_t *buffer) 645{ 646 return buffer->props.script; 647} 648 649void 650hb_buffer_set_language (hb_buffer_t *buffer, 651 hb_language_t language) 652{ 653 if (unlikely (hb_object_is_inert (buffer))) 654 return; 655 656 buffer->props.language = language; 657} 658 659hb_language_t 660hb_buffer_get_language (hb_buffer_t *buffer) 661{ 662 return buffer->props.language; 663} 664 665 666void 667hb_buffer_reset (hb_buffer_t *buffer) 668{ 669 buffer->reset (); 670} 671 672hb_bool_t 673hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size) 674{ 675 return buffer->ensure (size); 676} 677 678hb_bool_t 679hb_buffer_allocation_successful (hb_buffer_t *buffer) 680{ 681 return !buffer->in_error; 682} 683 684void 685hb_buffer_add (hb_buffer_t *buffer, 686 hb_codepoint_t codepoint, 687 hb_mask_t mask, 688 unsigned int cluster) 689{ 690 buffer->add (codepoint, mask, cluster); 691} 692 693hb_bool_t 694hb_buffer_set_length (hb_buffer_t *buffer, 695 unsigned int length) 696{ 697 if (unlikely (hb_object_is_inert (buffer))) 698 return length == 0; 699 700 if (!buffer->ensure (length)) 701 return FALSE; 702 703 /* Wipe the new space */ 704 if (length > buffer->len) { 705 memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len)); 706 if (buffer->have_positions) 707 memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len)); 708 } 709 710 buffer->len = length; 711 return TRUE; 712} 713 714unsigned int 715hb_buffer_get_length (hb_buffer_t *buffer) 716{ 717 return buffer->len; 718} 719 720/* Return value valid as long as buffer not modified */ 721hb_glyph_info_t * 722hb_buffer_get_glyph_infos (hb_buffer_t *buffer, 723 unsigned int *length) 724{ 725 if (length) 726 *length = buffer->len; 727 728 return (hb_glyph_info_t *) buffer->info; 729} 730 731/* Return value valid as long as buffer not modified */ 732hb_glyph_position_t * 733hb_buffer_get_glyph_positions (hb_buffer_t *buffer, 734 unsigned int *length) 735{ 736 if (!buffer->have_positions) 737 buffer->clear_positions (); 738 739 if (length) 740 *length = buffer->len; 741 742 return (hb_glyph_position_t *) buffer->pos; 743} 744 745void 746hb_buffer_reverse (hb_buffer_t *buffer) 747{ 748 buffer->reverse (); 749} 750 751void 752hb_buffer_reverse_clusters (hb_buffer_t *buffer) 753{ 754 buffer->reverse_clusters (); 755} 756 757void 758hb_buffer_guess_properties (hb_buffer_t *buffer) 759{ 760 buffer->guess_properties (); 761} 762 763#define ADD_UTF(T) \ 764 HB_STMT_START { \ 765 if (text_length == -1) { \ 766 text_length = 0; \ 767 const T *p = (const T *) text; \ 768 while (*p) { \ 769 text_length++; \ 770 p++; \ 771 } \ 772 } \ 773 if (item_length == -1) \ 774 item_length = text_length - item_offset; \ 775 buffer->ensure (buffer->len + item_length * sizeof (T) / 4); \ 776 const T *next = (const T *) text + item_offset; \ 777 const T *end = next + item_length; \ 778 while (next < end) { \ 779 hb_codepoint_t u; \ 780 const T *old_next = next; \ 781 next = UTF_NEXT (next, end, u); \ 782 hb_buffer_add (buffer, u, 1, old_next - (const T *) text); \ 783 } \ 784 } HB_STMT_END 785 786 787#define UTF8_COMPUTE(Char, Mask, Len) \ 788 if (Char < 128) { Len = 1; Mask = 0x7f; } \ 789 else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \ 790 else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \ 791 else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \ 792 else Len = 0; 793 794static inline const uint8_t * 795hb_utf8_next (const uint8_t *text, 796 const uint8_t *end, 797 hb_codepoint_t *unicode) 798{ 799 uint8_t c = *text; 800 unsigned int mask, len; 801 802 /* TODO check for overlong sequences? */ 803 804 UTF8_COMPUTE (c, mask, len); 805 if (unlikely (!len || (unsigned int) (end - text) < len)) { 806 *unicode = -1; 807 return text + 1; 808 } else { 809 hb_codepoint_t result; 810 unsigned int i; 811 result = c & mask; 812 for (i = 1; i < len; i++) 813 { 814 if (unlikely ((text[i] & 0xc0) != 0x80)) 815 { 816 *unicode = -1; 817 return text + 1; 818 } 819 result <<= 6; 820 result |= (text[i] & 0x3f); 821 } 822 *unicode = result; 823 return text + len; 824 } 825} 826 827void 828hb_buffer_add_utf8 (hb_buffer_t *buffer, 829 const char *text, 830 int text_length, 831 unsigned int item_offset, 832 int item_length) 833{ 834#define UTF_NEXT(S, E, U) hb_utf8_next (S, E, &(U)) 835 ADD_UTF (uint8_t); 836#undef UTF_NEXT 837} 838 839static inline const uint16_t * 840hb_utf16_next (const uint16_t *text, 841 const uint16_t *end, 842 hb_codepoint_t *unicode) 843{ 844 uint16_t c = *text++; 845 846 if (unlikely (c >= 0xd800 && c < 0xdc00)) { 847 /* high surrogate */ 848 uint16_t l; 849 if (text < end && ((l = *text), likely (l >= 0xdc00 && l < 0xe000))) { 850 /* low surrogate */ 851 *unicode = ((hb_codepoint_t) ((c) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000); 852 text++; 853 } else 854 *unicode = -1; 855 } else 856 *unicode = c; 857 858 return text; 859} 860 861void 862hb_buffer_add_utf16 (hb_buffer_t *buffer, 863 const uint16_t *text, 864 int text_length, 865 unsigned int item_offset, 866 int item_length) 867{ 868#define UTF_NEXT(S, E, U) hb_utf16_next (S, E, &(U)) 869 ADD_UTF (uint16_t); 870#undef UTF_NEXT 871} 872 873void 874hb_buffer_add_utf32 (hb_buffer_t *buffer, 875 const uint32_t *text, 876 int text_length, 877 unsigned int item_offset, 878 int item_length) 879{ 880#define UTF_NEXT(S, E, U) ((U) = *(S), (S)+1) 881 ADD_UTF (uint32_t); 882#undef UTF_NEXT 883} 884 885 886