hb-buffer.cc revision 3f82f8ff07a9d16a7c047129658c1bbedfdb5436
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::remove_output (void) 219{ 220 if (unlikely (hb_object_is_inert (this))) 221 return; 222 223 have_output = false; 224 have_positions = false; 225 226 out_len = 0; 227 out_info = info; 228} 229 230void 231hb_buffer_t::clear_output (void) 232{ 233 if (unlikely (hb_object_is_inert (this))) 234 return; 235 236 have_output = true; 237 have_positions = false; 238 239 out_len = 0; 240 out_info = info; 241} 242 243void 244hb_buffer_t::clear_positions (void) 245{ 246 if (unlikely (hb_object_is_inert (this))) 247 return; 248 249 have_output = false; 250 have_positions = true; 251 252 out_len = 0; 253 out_info = info; 254 255 memset (pos, 0, sizeof (pos[0]) * len); 256} 257 258void 259hb_buffer_t::swap_buffers (void) 260{ 261 if (unlikely (in_error)) return; 262 263 assert (have_output); 264 have_output = false; 265 266 if (out_info != info) 267 { 268 hb_glyph_info_t *tmp_string; 269 tmp_string = info; 270 info = out_info; 271 out_info = tmp_string; 272 pos = (hb_glyph_position_t *) out_info; 273 } 274 275 unsigned int tmp; 276 tmp = len; 277 len = out_len; 278 out_len = tmp; 279 280 idx = 0; 281} 282 283 284void 285hb_buffer_t::replace_glyphs (unsigned int num_in, 286 unsigned int num_out, 287 const uint32_t *glyph_data) 288{ 289 if (unlikely (!make_room_for (num_in, num_out))) return; 290 291 merge_clusters (idx, idx + num_in); 292 293 hb_glyph_info_t orig_info = info[idx]; 294 hb_glyph_info_t *pinfo = &out_info[out_len]; 295 for (unsigned int i = 0; i < num_out; i++) 296 { 297 *pinfo = orig_info; 298 pinfo->codepoint = glyph_data[i]; 299 pinfo++; 300 } 301 302 idx += num_in; 303 out_len += num_out; 304} 305 306void 307hb_buffer_t::output_glyph (hb_codepoint_t glyph_index) 308{ 309 if (unlikely (!make_room_for (0, 1))) return; 310 311 out_info[out_len] = info[idx]; 312 out_info[out_len].codepoint = glyph_index; 313 314 out_len++; 315} 316 317void 318hb_buffer_t::output_info (hb_glyph_info_t &glyph_info) 319{ 320 if (unlikely (!make_room_for (0, 1))) return; 321 322 out_info[out_len] = glyph_info; 323 324 out_len++; 325} 326 327void 328hb_buffer_t::copy_glyph (void) 329{ 330 if (unlikely (!make_room_for (0, 1))) return; 331 332 out_info[out_len] = info[idx]; 333 334 out_len++; 335} 336 337void 338hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index) 339{ 340 if (unlikely (out_info != info || out_len != idx)) { 341 if (unlikely (!make_room_for (1, 1))) return; 342 out_info[out_len] = info[idx]; 343 } 344 out_info[out_len].codepoint = glyph_index; 345 346 idx++; 347 out_len++; 348} 349 350 351void 352hb_buffer_t::set_masks (hb_mask_t value, 353 hb_mask_t mask, 354 unsigned int cluster_start, 355 unsigned int cluster_end) 356{ 357 hb_mask_t not_mask = ~mask; 358 value &= mask; 359 360 if (!mask) 361 return; 362 363 if (cluster_start == 0 && cluster_end == (unsigned int)-1) { 364 unsigned int count = len; 365 for (unsigned int i = 0; i < count; i++) 366 info[i].mask = (info[i].mask & not_mask) | value; 367 return; 368 } 369 370 unsigned int count = len; 371 for (unsigned int i = 0; i < count; i++) 372 if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end) 373 info[i].mask = (info[i].mask & not_mask) | value; 374} 375 376void 377hb_buffer_t::reverse_range (unsigned int start, 378 unsigned int end) 379{ 380 unsigned int i, j; 381 382 if (start == end - 1) 383 return; 384 385 for (i = start, j = end - 1; i < j; i++, j--) { 386 hb_glyph_info_t t; 387 388 t = info[i]; 389 info[i] = info[j]; 390 info[j] = t; 391 } 392 393 if (pos) { 394 for (i = start, j = end - 1; i < j; i++, j--) { 395 hb_glyph_position_t t; 396 397 t = pos[i]; 398 pos[i] = pos[j]; 399 pos[j] = t; 400 } 401 } 402} 403 404void 405hb_buffer_t::reverse (void) 406{ 407 if (unlikely (!len)) 408 return; 409 410 reverse_range (0, len); 411} 412 413void 414hb_buffer_t::reverse_clusters (void) 415{ 416 unsigned int i, start, count, last_cluster; 417 418 if (unlikely (!len)) 419 return; 420 421 reverse (); 422 423 count = len; 424 start = 0; 425 last_cluster = info[0].cluster; 426 for (i = 1; i < count; i++) { 427 if (last_cluster != info[i].cluster) { 428 reverse_range (start, i); 429 start = i; 430 last_cluster = info[i].cluster; 431 } 432 } 433 reverse_range (start, i); 434} 435 436void 437hb_buffer_t::merge_clusters (unsigned int start, 438 unsigned int end) 439{ 440 if (unlikely (end - start < 2)) 441 return; 442 443 unsigned int cluster = info[start].cluster; 444 445 for (unsigned int i = start + 1; i < end; i++) 446 cluster = MIN (cluster, info[i].cluster); 447 448 /* Extend end */ 449 while (end < len && info[end - 1].cluster == info[end].cluster) 450 end++; 451 452 /* Extend start */ 453 while (idx < start && info[start - 1].cluster == info[start].cluster) 454 start--; 455 456 /* If we hit the start of buffer, continue in out-buffer. */ 457 if (idx == start) 458 for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--) 459 out_info[i - 1].cluster = cluster; 460 461 for (unsigned int i = start; i < end; i++) 462 info[i].cluster = cluster; 463} 464void 465hb_buffer_t::merge_out_clusters (unsigned int start, 466 unsigned int end) 467{ 468 if (unlikely (end - start < 2)) 469 return; 470 471 unsigned int cluster = out_info[start].cluster; 472 473 for (unsigned int i = start + 1; i < end; i++) 474 cluster = MIN (cluster, out_info[i].cluster); 475 476 /* Extend start */ 477 while (start && out_info[start - 1].cluster == out_info[start].cluster) 478 start--; 479 480 /* Extend end */ 481 while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster) 482 end++; 483 484 /* If we hit the end of out-buffer, continue in buffer. */ 485 if (end == out_len) 486 for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++) 487 info[i].cluster = cluster; 488 489 for (unsigned int i = start; i < end; i++) 490 out_info[i].cluster = cluster; 491} 492 493void 494hb_buffer_t::guess_segment_properties (void) 495{ 496 if (unlikely (!len)) return; 497 assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE); 498 499 /* If script is set to INVALID, guess from buffer contents */ 500 if (props.script == HB_SCRIPT_INVALID) { 501 for (unsigned int i = 0; i < len; i++) { 502 hb_script_t script = unicode->script (info[i].codepoint); 503 if (likely (script != HB_SCRIPT_COMMON && 504 script != HB_SCRIPT_INHERITED && 505 script != HB_SCRIPT_UNKNOWN)) { 506 props.script = script; 507 break; 508 } 509 } 510 } 511 512 /* If direction is set to INVALID, guess from script */ 513 if (props.direction == HB_DIRECTION_INVALID) { 514 props.direction = hb_script_get_horizontal_direction (props.script); 515 } 516 517 /* If language is not set, use default language from locale */ 518 if (props.language == HB_LANGUAGE_INVALID) { 519 /* TODO get_default_for_script? using $LANGUAGE */ 520 props.language = hb_language_get_default (); 521 } 522} 523 524 525static inline void 526dump_var_allocation (const hb_buffer_t *buffer) 527{ 528 char buf[80]; 529 for (unsigned int i = 0; i < 8; i++) 530 buf[i] = '0' + buffer->allocated_var_bytes[7 - i]; 531 buf[8] = '\0'; 532 DEBUG_MSG (BUFFER, buffer, 533 "Current var allocation: %s", 534 buf); 535} 536 537void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner) 538{ 539 assert (byte_i < 8 && byte_i + count <= 8); 540 541 if (DEBUG (BUFFER)) 542 dump_var_allocation (this); 543 DEBUG_MSG (BUFFER, this, 544 "Allocating var bytes %d..%d for %s", 545 byte_i, byte_i + count - 1, owner); 546 547 for (unsigned int i = byte_i; i < byte_i + count; i++) { 548 assert (!allocated_var_bytes[i]); 549 allocated_var_bytes[i]++; 550 allocated_var_owner[i] = owner; 551 } 552} 553 554void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner) 555{ 556 if (DEBUG (BUFFER)) 557 dump_var_allocation (this); 558 559 DEBUG_MSG (BUFFER, this, 560 "Deallocating var bytes %d..%d for %s", 561 byte_i, byte_i + count - 1, owner); 562 563 assert (byte_i < 8 && byte_i + count <= 8); 564 for (unsigned int i = byte_i; i < byte_i + count; i++) { 565 assert (allocated_var_bytes[i]); 566 assert (0 == strcmp (allocated_var_owner[i], owner)); 567 allocated_var_bytes[i]--; 568 } 569} 570 571void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner) 572{ 573 if (DEBUG (BUFFER)) 574 dump_var_allocation (this); 575 576 DEBUG_MSG (BUFFER, this, 577 "Asserting var bytes %d..%d for %s", 578 byte_i, byte_i + count - 1, owner); 579 580 assert (byte_i < 8 && byte_i + count <= 8); 581 for (unsigned int i = byte_i; i < byte_i + count; i++) { 582 assert (allocated_var_bytes[i]); 583 assert (0 == strcmp (allocated_var_owner[i], owner)); 584 } 585} 586 587void hb_buffer_t::deallocate_var_all (void) 588{ 589 memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes)); 590 memset (allocated_var_owner, 0, sizeof (allocated_var_owner)); 591} 592 593/* Public API */ 594 595hb_buffer_t * 596hb_buffer_create (void) 597{ 598 hb_buffer_t *buffer; 599 600 if (!(buffer = hb_object_create<hb_buffer_t> ())) 601 return hb_buffer_get_empty (); 602 603 buffer->reset (); 604 605 return buffer; 606} 607 608hb_buffer_t * 609hb_buffer_get_empty (void) 610{ 611 static const hb_buffer_t _hb_buffer_nil = { 612 HB_OBJECT_HEADER_STATIC, 613 614 const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil), 615 HB_SEGMENT_PROPERTIES_DEFAULT, 616 HB_BUFFER_FLAGS_DEFAULT, 617 618 HB_BUFFER_CONTENT_TYPE_INVALID, 619 true, /* in_error */ 620 true, /* have_output */ 621 true /* have_positions */ 622 623 /* Zero is good enough for everything else. */ 624 }; 625 626 return const_cast<hb_buffer_t *> (&_hb_buffer_nil); 627} 628 629hb_buffer_t * 630hb_buffer_reference (hb_buffer_t *buffer) 631{ 632 return hb_object_reference (buffer); 633} 634 635void 636hb_buffer_destroy (hb_buffer_t *buffer) 637{ 638 if (!hb_object_destroy (buffer)) return; 639 640 hb_unicode_funcs_destroy (buffer->unicode); 641 642 free (buffer->info); 643 free (buffer->pos); 644 645 free (buffer); 646} 647 648hb_bool_t 649hb_buffer_set_user_data (hb_buffer_t *buffer, 650 hb_user_data_key_t *key, 651 void * data, 652 hb_destroy_func_t destroy, 653 hb_bool_t replace) 654{ 655 return hb_object_set_user_data (buffer, key, data, destroy, replace); 656} 657 658void * 659hb_buffer_get_user_data (hb_buffer_t *buffer, 660 hb_user_data_key_t *key) 661{ 662 return hb_object_get_user_data (buffer, key); 663} 664 665 666void 667hb_buffer_set_content_type (hb_buffer_t *buffer, 668 hb_buffer_content_type_t content_type) 669{ 670 buffer->content_type = content_type; 671} 672 673hb_buffer_content_type_t 674hb_buffer_get_content_type (hb_buffer_t *buffer) 675{ 676 return buffer->content_type; 677} 678 679 680void 681hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, 682 hb_unicode_funcs_t *unicode) 683{ 684 if (unlikely (hb_object_is_inert (buffer))) 685 return; 686 687 if (!unicode) 688 unicode = hb_unicode_funcs_get_default (); 689 690 691 hb_unicode_funcs_reference (unicode); 692 hb_unicode_funcs_destroy (buffer->unicode); 693 buffer->unicode = unicode; 694} 695 696hb_unicode_funcs_t * 697hb_buffer_get_unicode_funcs (hb_buffer_t *buffer) 698{ 699 return buffer->unicode; 700} 701 702void 703hb_buffer_set_direction (hb_buffer_t *buffer, 704 hb_direction_t direction) 705 706{ 707 if (unlikely (hb_object_is_inert (buffer))) 708 return; 709 710 buffer->props.direction = direction; 711} 712 713hb_direction_t 714hb_buffer_get_direction (hb_buffer_t *buffer) 715{ 716 return buffer->props.direction; 717} 718 719void 720hb_buffer_set_script (hb_buffer_t *buffer, 721 hb_script_t script) 722{ 723 if (unlikely (hb_object_is_inert (buffer))) 724 return; 725 726 buffer->props.script = script; 727} 728 729hb_script_t 730hb_buffer_get_script (hb_buffer_t *buffer) 731{ 732 return buffer->props.script; 733} 734 735void 736hb_buffer_set_language (hb_buffer_t *buffer, 737 hb_language_t language) 738{ 739 if (unlikely (hb_object_is_inert (buffer))) 740 return; 741 742 buffer->props.language = language; 743} 744 745hb_language_t 746hb_buffer_get_language (hb_buffer_t *buffer) 747{ 748 return buffer->props.language; 749} 750 751void 752hb_buffer_set_segment_properties (hb_buffer_t *buffer, 753 const hb_segment_properties_t *props) 754{ 755 if (unlikely (hb_object_is_inert (buffer))) 756 return; 757 758 buffer->props = *props; 759} 760 761void 762hb_buffer_get_segment_properties (hb_buffer_t *buffer, 763 hb_segment_properties_t *props) 764{ 765 *props = buffer->props; 766} 767 768 769void 770hb_buffer_set_flags (hb_buffer_t *buffer, 771 hb_buffer_flags_t flags) 772{ 773 if (unlikely (hb_object_is_inert (buffer))) 774 return; 775 776 buffer->flags = flags; 777} 778 779hb_buffer_flags_t 780hb_buffer_get_flags (hb_buffer_t *buffer) 781{ 782 return buffer->flags; 783} 784 785 786void 787hb_buffer_reset (hb_buffer_t *buffer) 788{ 789 buffer->reset (); 790} 791 792void 793hb_buffer_clear (hb_buffer_t *buffer) 794{ 795 buffer->clear (); 796} 797 798hb_bool_t 799hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size) 800{ 801 return buffer->ensure (size); 802} 803 804hb_bool_t 805hb_buffer_allocation_successful (hb_buffer_t *buffer) 806{ 807 return !buffer->in_error; 808} 809 810void 811hb_buffer_add (hb_buffer_t *buffer, 812 hb_codepoint_t codepoint, 813 unsigned int cluster) 814{ 815 buffer->add (codepoint, cluster); 816 buffer->clear_context (1); 817} 818 819hb_bool_t 820hb_buffer_set_length (hb_buffer_t *buffer, 821 unsigned int length) 822{ 823 if (unlikely (hb_object_is_inert (buffer))) 824 return length == 0; 825 826 if (!buffer->ensure (length)) 827 return false; 828 829 /* Wipe the new space */ 830 if (length > buffer->len) { 831 memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len)); 832 if (buffer->have_positions) 833 memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len)); 834 } 835 836 buffer->len = length; 837 838 if (!length) 839 buffer->clear_context (0); 840 buffer->clear_context (1); 841 842 return true; 843} 844 845unsigned int 846hb_buffer_get_length (hb_buffer_t *buffer) 847{ 848 return buffer->len; 849} 850 851/* Return value valid as long as buffer not modified */ 852hb_glyph_info_t * 853hb_buffer_get_glyph_infos (hb_buffer_t *buffer, 854 unsigned int *length) 855{ 856 if (length) 857 *length = buffer->len; 858 859 return (hb_glyph_info_t *) buffer->info; 860} 861 862/* Return value valid as long as buffer not modified */ 863hb_glyph_position_t * 864hb_buffer_get_glyph_positions (hb_buffer_t *buffer, 865 unsigned int *length) 866{ 867 if (!buffer->have_positions) 868 buffer->clear_positions (); 869 870 if (length) 871 *length = buffer->len; 872 873 return (hb_glyph_position_t *) buffer->pos; 874} 875 876void 877hb_buffer_reverse (hb_buffer_t *buffer) 878{ 879 buffer->reverse (); 880} 881 882void 883hb_buffer_reverse_clusters (hb_buffer_t *buffer) 884{ 885 buffer->reverse_clusters (); 886} 887 888void 889hb_buffer_guess_segment_properties (hb_buffer_t *buffer) 890{ 891 buffer->guess_segment_properties (); 892} 893 894template <typename T> 895static inline void 896hb_buffer_add_utf (hb_buffer_t *buffer, 897 const T *text, 898 int text_length, 899 unsigned int item_offset, 900 int item_length) 901{ 902 assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || 903 (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); 904 905 if (unlikely (hb_object_is_inert (buffer))) 906 return; 907 908 if (text_length == -1) 909 text_length = hb_utf_strlen (text); 910 911 if (item_length == -1) 912 item_length = text_length - item_offset; 913 914 buffer->ensure (buffer->len + item_length * sizeof (T) / 4); 915 916 /* If buffer is empty and pre-context provided, install it. 917 * This check is written this way, to make sure people can 918 * provide pre-context in one add_utf() call, then provide 919 * text in a follow-up call. See: 920 * 921 * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13 922 */ 923 if (!buffer->len && item_offset > 0) 924 { 925 /* Add pre-context */ 926 buffer->clear_context (0); 927 const T *prev = text + item_offset; 928 const T *start = text; 929 while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH) 930 { 931 hb_codepoint_t u; 932 prev = hb_utf_prev (prev, start, &u); 933 buffer->context[0][buffer->context_len[0]++] = u; 934 } 935 } 936 937 const T *next = text + item_offset; 938 const T *end = next + item_length; 939 while (next < end) 940 { 941 hb_codepoint_t u; 942 const T *old_next = next; 943 next = hb_utf_next (next, end, &u); 944 buffer->add (u, old_next - (const T *) text); 945 } 946 947 /* Add post-context */ 948 buffer->clear_context (1); 949 end = text + text_length; 950 while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH) 951 { 952 hb_codepoint_t u; 953 next = hb_utf_next (next, end, &u); 954 buffer->context[1][buffer->context_len[1]++] = u; 955 } 956 957 buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE; 958} 959 960void 961hb_buffer_add_utf8 (hb_buffer_t *buffer, 962 const char *text, 963 int text_length, 964 unsigned int item_offset, 965 int item_length) 966{ 967 hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length); 968} 969 970void 971hb_buffer_add_utf16 (hb_buffer_t *buffer, 972 const uint16_t *text, 973 int text_length, 974 unsigned int item_offset, 975 int item_length) 976{ 977 hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length); 978} 979 980void 981hb_buffer_add_utf32 (hb_buffer_t *buffer, 982 const uint32_t *text, 983 int text_length, 984 unsigned int item_offset, 985 int item_length) 986{ 987 hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length); 988} 989 990 991static int 992compare_info_codepoint (const hb_glyph_info_t *pa, 993 const hb_glyph_info_t *pb) 994{ 995 return (int) pb->codepoint - (int) pa->codepoint; 996} 997 998static inline void 999normalize_glyphs_cluster (hb_buffer_t *buffer, 1000 unsigned int start, 1001 unsigned int end, 1002 bool backward) 1003{ 1004 hb_glyph_position_t *pos = buffer->pos; 1005 1006 /* Total cluster advance */ 1007 hb_position_t total_x_advance = 0, total_y_advance = 0; 1008 for (unsigned int i = start; i < end; i++) 1009 { 1010 total_x_advance += pos[i].x_advance; 1011 total_y_advance += pos[i].y_advance; 1012 } 1013 1014 hb_position_t x_advance = 0, y_advance = 0; 1015 for (unsigned int i = start; i < end; i++) 1016 { 1017 pos[i].x_offset += x_advance; 1018 pos[i].y_offset += y_advance; 1019 1020 x_advance += pos[i].x_advance; 1021 y_advance += pos[i].y_advance; 1022 1023 pos[i].x_advance = 0; 1024 pos[i].y_advance = 0; 1025 } 1026 1027 if (backward) 1028 { 1029 /* Transfer all cluster advance to the last glyph. */ 1030 pos[end - 1].x_advance = total_x_advance; 1031 pos[end - 1].y_advance = total_y_advance; 1032 1033 hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start); 1034 } else { 1035 /* Transfer all cluster advance to the first glyph. */ 1036 pos[start].x_advance += total_x_advance; 1037 pos[start].y_advance += total_y_advance; 1038 for (unsigned int i = start + 1; i < end; i++) { 1039 pos[i].x_offset -= total_x_advance; 1040 pos[i].y_offset -= total_y_advance; 1041 } 1042 hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1); 1043 } 1044} 1045 1046void 1047hb_buffer_normalize_glyphs (hb_buffer_t *buffer) 1048{ 1049 assert (buffer->have_positions); 1050 assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); 1051 1052 bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); 1053 1054 unsigned int count = buffer->len; 1055 if (unlikely (!count)) return; 1056 hb_glyph_info_t *info = buffer->info; 1057 1058 unsigned int start = 0; 1059 unsigned int end; 1060 for (end = start + 1; end < count; end++) 1061 if (info[start].cluster != info[end].cluster) { 1062 normalize_glyphs_cluster (buffer, start, end, backward); 1063 start = end; 1064 } 1065 normalize_glyphs_cluster (buffer, start, end, backward); 1066} 1067 1068 1069/* 1070 * Serialize 1071 */ 1072 1073static const char *serialize_formats[] = { 1074 "TEXT", 1075 "JSON", 1076 NULL 1077}; 1078 1079const char ** 1080hb_buffer_serialize_list_formats (void) 1081{ 1082 return serialize_formats; 1083} 1084 1085hb_buffer_serialize_format_t 1086hb_buffer_serialize_format_from_string (const char *str, int len) 1087{ 1088 /* Upper-case it. */ 1089 return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020); 1090} 1091 1092const char * 1093hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format) 1094{ 1095 switch (format) 1096 { 1097 case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0]; 1098 case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1]; 1099 default: 1100 case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return NULL; 1101 } 1102} 1103 1104static unsigned int 1105_hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, 1106 unsigned int start, 1107 unsigned int end, 1108 char *buf, 1109 unsigned int buf_size, 1110 unsigned int *buf_consumed, 1111 hb_font_t *font, 1112 hb_buffer_serialize_flags_t flags) 1113{ 1114 hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); 1115 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL); 1116 1117 *buf_consumed = 0; 1118 for (unsigned int i = start; i < end; i++) 1119 { 1120 char b[1024]; 1121 char *p = b; 1122 1123 /* In the following code, we know b is large enough that no overflow can happen. */ 1124 1125#define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END 1126 1127 if (i) 1128 *p++ = ','; 1129 1130 *p++ = '{'; 1131 1132 APPEND ("\"g\":"); 1133 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) 1134 { 1135 char g[128]; 1136 hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g)); 1137 *p++ = '"'; 1138 for (char *q = g; *q; q++) { 1139 if (*q == '"') 1140 *p++ = '\\'; 1141 *p++ = *q; 1142 } 1143 *p++ = '"'; 1144 } 1145 else 1146 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint); 1147 1148 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { 1149 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster); 1150 } 1151 1152 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) 1153 { 1154 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d", 1155 pos[i].x_offset, pos[i].y_offset); 1156 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d", 1157 pos[i].x_advance, pos[i].y_advance); 1158 } 1159 1160 *p++ = '}'; 1161 1162 if (buf_size > (p - b)) 1163 { 1164 unsigned int l = p - b; 1165 memcpy (buf, b, l); 1166 buf += l; 1167 buf_size -= l; 1168 *buf_consumed += l; 1169 *buf = '\0'; 1170 } else 1171 return i - start; 1172 } 1173 1174 return end - start; 1175} 1176 1177static unsigned int 1178_hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, 1179 unsigned int start, 1180 unsigned int end, 1181 char *buf, 1182 unsigned int buf_size, 1183 unsigned int *buf_consumed, 1184 hb_font_t *font, 1185 hb_buffer_serialize_flags_t flags) 1186{ 1187 hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); 1188 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL); 1189 hb_direction_t direction = hb_buffer_get_direction (buffer); 1190 1191 *buf_consumed = 0; 1192 for (unsigned int i = start; i < end; i++) 1193 { 1194 char b[1024]; 1195 char *p = b; 1196 1197 /* In the following code, we know b is large enough that no overflow can happen. */ 1198 1199 if (i) 1200 *p++ = '|'; 1201 1202 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) 1203 { 1204 hb_font_glyph_to_string (font, info[i].codepoint, p, 128); 1205 p += strlen (p); 1206 } 1207 else 1208 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint); 1209 1210 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { 1211 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster); 1212 } 1213 1214 if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) 1215 { 1216 if (pos[i].x_offset || pos[i].y_offset) 1217 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset); 1218 1219 *p++ = '+'; 1220 if (HB_DIRECTION_IS_HORIZONTAL (direction) || pos[i].x_advance) 1221 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance); 1222 if (HB_DIRECTION_IS_VERTICAL (direction) || pos->y_advance) 1223 p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance); 1224 } 1225 1226 if (buf_size > (p - b)) 1227 { 1228 unsigned int l = p - b; 1229 memcpy (buf, b, l); 1230 buf += l; 1231 buf_size -= l; 1232 *buf_consumed += l; 1233 *buf = '\0'; 1234 } else 1235 return i - start; 1236 } 1237 1238 return end - start; 1239} 1240 1241/* Returns number of items, starting at start, that were serialized. */ 1242unsigned int 1243hb_buffer_serialize_glyphs (hb_buffer_t *buffer, 1244 unsigned int start, 1245 unsigned int end, 1246 char *buf, 1247 unsigned int buf_size, 1248 unsigned int *buf_consumed, 1249 hb_font_t *font, /* May be NULL */ 1250 hb_buffer_serialize_format_t format, 1251 hb_buffer_serialize_flags_t flags) 1252{ 1253 assert (start <= end && end <= buffer->len); 1254 1255 *buf_consumed = 0; 1256 1257 assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || 1258 buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); 1259 1260 if (unlikely (start == end)) 1261 return 0; 1262 1263 if (!font) 1264 font = hb_font_get_empty (); 1265 1266 switch (format) 1267 { 1268 case HB_BUFFER_SERIALIZE_FORMAT_TEXT: 1269 return _hb_buffer_serialize_glyphs_text (buffer, start, end, 1270 buf, buf_size, buf_consumed, 1271 font, flags); 1272 1273 case HB_BUFFER_SERIALIZE_FORMAT_JSON: 1274 return _hb_buffer_serialize_glyphs_json (buffer, start, end, 1275 buf, buf_size, buf_consumed, 1276 font, flags); 1277 1278 default: 1279 case HB_BUFFER_SERIALIZE_FORMAT_INVALID: 1280 return 0; 1281 1282 } 1283} 1284 1285hb_bool_t 1286hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, 1287 const char *buf, 1288 unsigned int buf_len, 1289 unsigned int *buf_consumed, 1290 hb_font_t *font, /* May be NULL */ 1291 hb_buffer_serialize_format_t format) 1292{ 1293 return false; 1294} 1295