hb-buffer.cc (60701B)
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.hh" 31 #include "hb-utf.hh" 32 33 34 /** 35 * SECTION: hb-buffer 36 * @title: hb-buffer 37 * @short_description: Input and output buffers 38 * @include: hb.h 39 * 40 * Buffers serve a dual role in HarfBuzz; before shaping, they hold 41 * the input characters that are passed to hb_shape(), and after 42 * shaping they hold the output glyphs. 43 * 44 * The input buffer is a sequence of Unicode codepoints, with 45 * associated attributes such as direction and script. The output 46 * buffer is a sequence of glyphs, with associated attributes such 47 * as position and cluster. 48 **/ 49 50 51 /** 52 * hb_segment_properties_equal: 53 * @a: first #hb_segment_properties_t to compare. 54 * @b: second #hb_segment_properties_t to compare. 55 * 56 * Checks the equality of two #hb_segment_properties_t's. 57 * 58 * Return value: 59 * `true` if all properties of @a equal those of @b, `false` otherwise. 60 * 61 * Since: 0.9.7 62 **/ 63 hb_bool_t 64 hb_segment_properties_equal (const hb_segment_properties_t *a, 65 const hb_segment_properties_t *b) 66 { 67 return a->direction == b->direction && 68 a->script == b->script && 69 a->language == b->language && 70 a->reserved1 == b->reserved1 && 71 a->reserved2 == b->reserved2; 72 73 } 74 75 /** 76 * hb_segment_properties_hash: 77 * @p: #hb_segment_properties_t to hash. 78 * 79 * Creates a hash representing @p. 80 * 81 * Return value: 82 * A hash of @p. 83 * 84 * Since: 0.9.7 85 **/ 86 unsigned int 87 hb_segment_properties_hash (const hb_segment_properties_t *p) 88 { 89 return ((unsigned int) p->direction * 31 + 90 (unsigned int) p->script) * 31 + 91 (intptr_t) (p->language); 92 } 93 94 /** 95 * hb_segment_properties_overlay: 96 * @p: #hb_segment_properties_t to fill in. 97 * @src: #hb_segment_properties_t to fill in from. 98 * 99 * Fills in missing fields of @p from @src in a considered manner. 100 * 101 * First, if @p does not have direction set, direction is copied from @src. 102 * 103 * Next, if @p and @src have the same direction (which can be unset), if @p 104 * does not have script set, script is copied from @src. 105 * 106 * Finally, if @p and @src have the same direction and script (which either 107 * can be unset), if @p does not have language set, language is copied from 108 * @src. 109 * 110 * Since: 3.3.0 111 **/ 112 void 113 hb_segment_properties_overlay (hb_segment_properties_t *p, 114 const hb_segment_properties_t *src) 115 { 116 if (unlikely (!p || !src)) 117 return; 118 119 if (!p->direction) 120 p->direction = src->direction; 121 122 if (p->direction != src->direction) 123 return; 124 125 if (!p->script) 126 p->script = src->script; 127 128 if (p->script != src->script) 129 return; 130 131 if (!p->language) 132 p->language = src->language; 133 } 134 135 /* Here is how the buffer works internally: 136 * 137 * There are two info pointers: info and out_info. They always have 138 * the same allocated size, but different lengths. 139 * 140 * As an optimization, both info and out_info may point to the 141 * same piece of memory, which is owned by info. This remains the 142 * case as long as out_len doesn't exceed i at any time. 143 * In that case, sync() is mostly no-op and the glyph operations 144 * operate mostly in-place. 145 * 146 * As soon as out_info gets longer than info, out_info is moved over 147 * to an alternate buffer (which we reuse the pos buffer for), and its 148 * current contents (out_len entries) are copied to the new place. 149 * 150 * This should all remain transparent to the user. sync() then 151 * switches info over to out_info and does housekeeping. 152 */ 153 154 155 156 /* Internal API */ 157 158 bool 159 hb_buffer_t::enlarge (unsigned int size) 160 { 161 if (unlikely (size > max_len)) 162 { 163 successful = false; 164 return false; 165 } 166 167 if (unlikely (!successful)) 168 return false; 169 170 unsigned int new_allocated = allocated; 171 hb_glyph_position_t *new_pos = nullptr; 172 hb_glyph_info_t *new_info = nullptr; 173 bool separate_out = out_info != info; 174 175 if (unlikely (hb_unsigned_mul_overflows (size, sizeof (info[0])))) 176 goto done; 177 178 while (size >= new_allocated) 179 new_allocated += (new_allocated >> 1) + 32; 180 181 unsigned new_bytes; 182 if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]), &new_bytes))) 183 goto done; 184 185 static_assert (sizeof (info[0]) == sizeof (pos[0]), ""); 186 new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_bytes); 187 new_info = (hb_glyph_info_t *) hb_realloc (info, new_bytes); 188 189 done: 190 if (unlikely (!new_pos || !new_info)) 191 successful = false; 192 193 if (likely (new_pos)) 194 pos = new_pos; 195 196 if (likely (new_info)) 197 info = new_info; 198 199 out_info = separate_out ? (hb_glyph_info_t *) pos : info; 200 if (likely (successful)) 201 allocated = new_allocated; 202 203 return likely (successful); 204 } 205 206 bool 207 hb_buffer_t::make_room_for (unsigned int num_in, 208 unsigned int num_out) 209 { 210 if (unlikely (!ensure (out_len + num_out))) return false; 211 212 if (out_info == info && 213 out_len + num_out > idx + num_in) 214 { 215 assert (have_output); 216 217 out_info = (hb_glyph_info_t *) pos; 218 hb_memcpy (out_info, info, out_len * sizeof (out_info[0])); 219 } 220 221 return true; 222 } 223 224 bool 225 hb_buffer_t::shift_forward (unsigned int count) 226 { 227 assert (have_output); 228 if (unlikely (!ensure (len + count))) return false; 229 230 max_ops -= len - idx; 231 if (unlikely (max_ops < 0)) 232 { 233 successful = false; 234 return false; 235 } 236 237 memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0])); 238 if (idx + count > len) 239 { 240 /* Under memory failure we might expose this area. At least 241 * clean it up. Oh well... 242 * 243 * Ideally, we should at least set Default_Ignorable bits on 244 * these, as well as consistent cluster values. But the former 245 * is layering violation... */ 246 hb_memset (info + len, 0, (idx + count - len) * sizeof (info[0])); 247 } 248 len += count; 249 idx += count; 250 251 return true; 252 } 253 254 hb_buffer_t::scratch_buffer_t * 255 hb_buffer_t::get_scratch_buffer (unsigned int *size) 256 { 257 have_output = false; 258 have_positions = false; 259 260 out_len = 0; 261 out_info = info; 262 263 assert ((uintptr_t) pos % sizeof (scratch_buffer_t) == 0); 264 *size = allocated * sizeof (pos[0]) / sizeof (scratch_buffer_t); 265 return (scratch_buffer_t *) (void *) pos; 266 } 267 268 269 270 /* HarfBuzz-Internal API */ 271 272 void 273 hb_buffer_t::similar (const hb_buffer_t &src) 274 { 275 hb_unicode_funcs_destroy (unicode); 276 unicode = hb_unicode_funcs_reference (src.unicode); 277 flags = src.flags; 278 cluster_level = src.cluster_level; 279 replacement = src.replacement; 280 invisible = src.invisible; 281 not_found = src.not_found; 282 not_found_variation_selector = src.not_found_variation_selector; 283 } 284 285 void 286 hb_buffer_t::reset () 287 { 288 hb_unicode_funcs_destroy (unicode); 289 unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ()); 290 flags = HB_BUFFER_FLAG_DEFAULT; 291 cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT; 292 replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT; 293 invisible = 0; 294 not_found = 0; 295 not_found_variation_selector = HB_CODEPOINT_INVALID; 296 297 clear (); 298 } 299 300 void 301 hb_buffer_t::clear () 302 { 303 content_type = HB_BUFFER_CONTENT_TYPE_INVALID; 304 hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT; 305 props = default_props; 306 307 successful = true; 308 have_output = false; 309 have_positions = false; 310 311 idx = 0; 312 len = 0; 313 out_len = 0; 314 out_info = info; 315 316 hb_memset (context, 0, sizeof context); 317 hb_memset (context_len, 0, sizeof context_len); 318 319 deallocate_var_all (); 320 serial = 0; 321 random_state = 1; 322 scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; 323 } 324 325 void 326 hb_buffer_t::enter () 327 { 328 deallocate_var_all (); 329 serial = 0; 330 scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; 331 unsigned mul; 332 if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR, &mul))) 333 { 334 max_len = hb_max (mul, (unsigned) HB_BUFFER_MAX_LEN_MIN); 335 } 336 if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR, &mul))) 337 { 338 max_ops = hb_max (mul, (unsigned) HB_BUFFER_MAX_OPS_MIN); 339 } 340 } 341 void 342 hb_buffer_t::leave () 343 { 344 max_len = HB_BUFFER_MAX_LEN_DEFAULT; 345 max_ops = HB_BUFFER_MAX_OPS_DEFAULT; 346 deallocate_var_all (); 347 serial = 0; 348 } 349 350 351 void 352 hb_buffer_t::add (hb_codepoint_t codepoint, 353 unsigned int cluster) 354 { 355 hb_glyph_info_t *glyph; 356 357 if (unlikely (!ensure (len + 1))) return; 358 359 glyph = &info[len]; 360 361 hb_memset (glyph, 0, sizeof (*glyph)); 362 glyph->codepoint = codepoint; 363 glyph->mask = 0; 364 glyph->cluster = cluster; 365 366 len++; 367 } 368 369 void 370 hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info) 371 { 372 if (unlikely (!ensure (len + 1))) return; 373 374 info[len] = glyph_info; 375 376 len++; 377 } 378 void 379 hb_buffer_t::add_info_and_pos (const hb_glyph_info_t &glyph_info, 380 const hb_glyph_position_t &glyph_pos) 381 { 382 if (unlikely (!ensure (len + 1))) return; 383 384 info[len] = glyph_info; 385 assert (have_positions); 386 pos[len] = glyph_pos; 387 388 len++; 389 } 390 391 392 void 393 hb_buffer_t::clear_output () 394 { 395 have_output = true; 396 have_positions = false; 397 398 idx = 0; 399 out_len = 0; 400 out_info = info; 401 } 402 403 void 404 hb_buffer_t::clear_positions () 405 { 406 have_output = false; 407 have_positions = true; 408 409 out_len = 0; 410 out_info = info; 411 412 hb_memset (pos, 0, sizeof (pos[0]) * len); 413 } 414 415 bool 416 hb_buffer_t::sync () 417 { 418 bool ret = false; 419 420 assert (have_output); 421 422 assert (idx <= len); 423 424 if (unlikely (!successful || !next_glyphs (len - idx))) 425 goto reset; 426 427 if (out_info != info) 428 { 429 pos = (hb_glyph_position_t *) info; 430 info = out_info; 431 } 432 len = out_len; 433 ret = true; 434 435 reset: 436 have_output = false; 437 out_len = 0; 438 out_info = info; 439 idx = 0; 440 441 return ret; 442 } 443 444 int 445 hb_buffer_t::sync_so_far () 446 { 447 bool had_output = have_output; 448 unsigned out_i = out_len; 449 unsigned i = idx; 450 unsigned old_idx = idx; 451 452 if (sync ()) 453 idx = out_i; 454 else 455 idx = i; 456 457 if (had_output) 458 { 459 have_output = true; 460 out_len = idx; 461 } 462 463 assert (idx <= len); 464 465 return idx - old_idx; 466 } 467 468 bool 469 hb_buffer_t::move_to (unsigned int i) 470 { 471 if (!have_output) 472 { 473 assert (i <= len); 474 idx = i; 475 return true; 476 } 477 if (unlikely (!successful)) 478 return false; 479 480 assert (i <= out_len + (len - idx)); 481 482 if (out_len < i) 483 { 484 unsigned int count = i - out_len; 485 if (unlikely (!make_room_for (count, count))) return false; 486 487 memmove (out_info + out_len, info + idx, count * sizeof (out_info[0])); 488 idx += count; 489 out_len += count; 490 } 491 else if (out_len > i) 492 { 493 /* Tricky part: rewinding... */ 494 unsigned int count = out_len - i; 495 496 /* This will blow in our face if memory allocation fails later 497 * in this same lookup... 498 * 499 * We used to shift with extra 32 items. 500 * But that would leave empty slots in the buffer in case of allocation 501 * failures. See comments in shift_forward(). This can cause O(N^2) 502 * behavior more severely than adding 32 empty slots can... */ 503 if (unlikely (idx < count && !shift_forward (count - idx))) return false; 504 505 assert (idx >= count); 506 507 idx -= count; 508 out_len -= count; 509 memmove (info + idx, out_info + out_len, count * sizeof (out_info[0])); 510 } 511 512 return true; 513 } 514 515 516 void 517 hb_buffer_t::set_masks (hb_mask_t value, 518 hb_mask_t mask, 519 unsigned int cluster_start, 520 unsigned int cluster_end) 521 { 522 if (!mask) 523 return; 524 525 hb_mask_t not_mask = ~mask; 526 value &= mask; 527 528 max_ops -= len; 529 if (unlikely (max_ops < 0)) 530 successful = false; 531 532 unsigned int count = len; 533 534 if (cluster_start == 0 && cluster_end == (unsigned int) -1) 535 { 536 for (unsigned int i = 0; i < count; i++) 537 info[i].mask = (info[i].mask & not_mask) | value; 538 return; 539 } 540 541 for (unsigned int i = 0; i < count; i++) 542 if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end) 543 info[i].mask = (info[i].mask & not_mask) | value; 544 } 545 546 void 547 hb_buffer_t::merge_clusters_impl (unsigned int start, 548 unsigned int end) 549 { 550 if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level)) 551 { 552 unsafe_to_break (start, end); 553 return; 554 } 555 556 max_ops -= end - start; 557 if (unlikely (max_ops < 0)) 558 successful = false; 559 560 unsigned int cluster = info[start].cluster; 561 562 for (unsigned int i = start + 1; i < end; i++) 563 cluster = hb_min (cluster, info[i].cluster); 564 565 /* Extend end */ 566 if (cluster != info[end - 1].cluster) 567 while (end < len && info[end - 1].cluster == info[end].cluster) 568 end++; 569 570 /* Extend start */ 571 if (cluster != info[start].cluster) 572 while (idx < start && info[start - 1].cluster == info[start].cluster) 573 start--; 574 575 /* If we hit the start of buffer, continue in out-buffer. */ 576 if (idx == start && info[start].cluster != cluster) 577 for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--) 578 set_cluster (out_info[i - 1], cluster); 579 580 for (unsigned int i = start; i < end; i++) 581 set_cluster (info[i], cluster); 582 } 583 void 584 hb_buffer_t::merge_out_clusters (unsigned int start, 585 unsigned int end) 586 { 587 if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level)) 588 return; 589 590 if (unlikely (end - start < 2)) 591 return; 592 593 max_ops -= end - start; 594 if (unlikely (max_ops < 0)) 595 successful = false; 596 597 unsigned int cluster = out_info[start].cluster; 598 599 for (unsigned int i = start + 1; i < end; i++) 600 cluster = hb_min (cluster, out_info[i].cluster); 601 602 /* Extend start */ 603 while (start && out_info[start - 1].cluster == out_info[start].cluster) 604 start--; 605 606 /* Extend end */ 607 while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster) 608 end++; 609 610 /* If we hit the end of out-buffer, continue in buffer. */ 611 if (end == out_len) 612 for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++) 613 set_cluster (info[i], cluster); 614 615 for (unsigned int i = start; i < end; i++) 616 set_cluster (out_info[i], cluster); 617 } 618 void 619 hb_buffer_t::delete_glyph () 620 { 621 /* The logic here is duplicated in hb_ot_hide_default_ignorables(). */ 622 623 unsigned int cluster = info[idx].cluster; 624 if ((idx + 1 < len && cluster == info[idx + 1].cluster) || 625 (out_len && cluster == out_info[out_len - 1].cluster)) 626 { 627 /* Cluster survives; do nothing. */ 628 goto done; 629 } 630 631 if (out_len) 632 { 633 /* Merge cluster backward. */ 634 if (cluster < out_info[out_len - 1].cluster) 635 { 636 unsigned int mask = info[idx].mask; 637 unsigned int old_cluster = out_info[out_len - 1].cluster; 638 for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--) 639 set_cluster (out_info[i - 1], cluster, mask); 640 } 641 goto done; 642 } 643 644 if (idx + 1 < len) 645 { 646 /* Merge cluster forward. */ 647 merge_clusters (idx, idx + 2); 648 goto done; 649 } 650 651 done: 652 skip_glyph (); 653 } 654 655 void 656 hb_buffer_t::delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info)) 657 { 658 /* Merge clusters and delete filtered glyphs. 659 * NOTE! We can't use out-buffer as we have positioning data. */ 660 unsigned int j = 0; 661 unsigned int count = len; 662 for (unsigned int i = 0; i < count; i++) 663 { 664 if (filter (&info[i])) 665 { 666 /* Merge clusters. 667 * Same logic as delete_glyph(), but for in-place removal. */ 668 669 unsigned int cluster = info[i].cluster; 670 if (i + 1 < count && cluster == info[i + 1].cluster) 671 continue; /* Cluster survives; do nothing. */ 672 673 if (j) 674 { 675 /* Merge cluster backward. */ 676 if (cluster < info[j - 1].cluster) 677 { 678 unsigned int mask = info[i].mask; 679 unsigned int old_cluster = info[j - 1].cluster; 680 for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--) 681 set_cluster (info[k - 1], cluster, mask); 682 } 683 continue; 684 } 685 686 if (i + 1 < count) 687 merge_clusters (i, i + 2); /* Merge cluster forward. */ 688 689 continue; 690 } 691 692 if (j != i) 693 { 694 info[j] = info[i]; 695 pos[j] = pos[i]; 696 } 697 j++; 698 } 699 len = j; 700 } 701 702 void 703 hb_buffer_t::guess_segment_properties () 704 { 705 assert_unicode (); 706 707 /* If script is set to INVALID, guess from buffer contents */ 708 if (props.script == HB_SCRIPT_INVALID) { 709 for (unsigned int i = 0; i < len; i++) { 710 hb_script_t script = unicode->script (info[i].codepoint); 711 if (likely (script != HB_SCRIPT_COMMON && 712 script != HB_SCRIPT_INHERITED && 713 script != HB_SCRIPT_UNKNOWN)) { 714 props.script = script; 715 break; 716 } 717 } 718 } 719 720 /* If direction is set to INVALID, guess from script */ 721 if (props.direction == HB_DIRECTION_INVALID) { 722 props.direction = hb_script_get_horizontal_direction (props.script); 723 if (props.direction == HB_DIRECTION_INVALID) 724 props.direction = HB_DIRECTION_LTR; 725 } 726 727 /* If language is not set, use default language from locale */ 728 if (props.language == HB_LANGUAGE_INVALID) { 729 /* TODO get_default_for_script? using $LANGUAGE */ 730 props.language = hb_language_get_default (); 731 } 732 } 733 734 735 /* Public API */ 736 737 DEFINE_NULL_INSTANCE (hb_buffer_t) = 738 { 739 HB_OBJECT_HEADER_STATIC, 740 741 const_cast<hb_unicode_funcs_t *> (&_hb_Null_hb_unicode_funcs_t), 742 HB_BUFFER_FLAG_DEFAULT, 743 HB_BUFFER_CLUSTER_LEVEL_DEFAULT, 744 HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT, 745 0, /* invisible */ 746 0, /* not_found */ 747 HB_CODEPOINT_INVALID, /* not_found_variation_selector */ 748 749 750 HB_BUFFER_CONTENT_TYPE_INVALID, 751 HB_SEGMENT_PROPERTIES_DEFAULT, 752 753 false, /* successful */ 754 false, /* have_output */ 755 true /* have_positions */ 756 757 /* Zero is good enough for everything else. */ 758 }; 759 760 761 /** 762 * hb_buffer_create: 763 * 764 * Creates a new #hb_buffer_t with all properties to defaults. 765 * 766 * Return value: (transfer full): 767 * A newly allocated #hb_buffer_t with a reference count of 1. The initial 768 * reference count should be released with hb_buffer_destroy() when you are done 769 * using the #hb_buffer_t. This function never returns `NULL`. If memory cannot 770 * be allocated, a special #hb_buffer_t object will be returned on which 771 * hb_buffer_allocation_successful() returns `false`. 772 * 773 * Since: 0.9.2 774 **/ 775 hb_buffer_t * 776 hb_buffer_create () 777 { 778 hb_buffer_t *buffer; 779 780 if (!(buffer = hb_object_create<hb_buffer_t> ())) 781 return hb_buffer_get_empty (); 782 783 buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT; 784 buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT; 785 786 buffer->reset (); 787 788 return buffer; 789 } 790 791 /** 792 * hb_buffer_create_similar: 793 * @src: An #hb_buffer_t 794 * 795 * Creates a new #hb_buffer_t, similar to hb_buffer_create(). The only 796 * difference is that the buffer is configured similarly to @src. 797 * 798 * Return value: (transfer full): 799 * A newly allocated #hb_buffer_t, similar to hb_buffer_create(). 800 * 801 * Since: 3.3.0 802 **/ 803 hb_buffer_t * 804 hb_buffer_create_similar (const hb_buffer_t *src) 805 { 806 hb_buffer_t *buffer = hb_buffer_create (); 807 808 buffer->similar (*src); 809 810 return buffer; 811 } 812 813 /** 814 * hb_buffer_reset: 815 * @buffer: An #hb_buffer_t 816 * 817 * Resets the buffer to its initial status, as if it was just newly created 818 * with hb_buffer_create(). 819 * 820 * Since: 0.9.2 821 **/ 822 void 823 hb_buffer_reset (hb_buffer_t *buffer) 824 { 825 if (unlikely (hb_object_is_immutable (buffer))) 826 return; 827 828 buffer->reset (); 829 } 830 831 /** 832 * hb_buffer_get_empty: 833 * 834 * Fetches an empty #hb_buffer_t. 835 * 836 * Return value: (transfer full): The empty buffer 837 * 838 * Since: 0.9.2 839 **/ 840 hb_buffer_t * 841 hb_buffer_get_empty () 842 { 843 return const_cast<hb_buffer_t *> (&Null (hb_buffer_t)); 844 } 845 846 /** 847 * hb_buffer_reference: (skip) 848 * @buffer: An #hb_buffer_t 849 * 850 * Increases the reference count on @buffer by one. This prevents @buffer from 851 * being destroyed until a matching call to hb_buffer_destroy() is made. 852 * 853 * Return value: (transfer full): 854 * The referenced #hb_buffer_t. 855 * 856 * Since: 0.9.2 857 **/ 858 hb_buffer_t * 859 hb_buffer_reference (hb_buffer_t *buffer) 860 { 861 return hb_object_reference (buffer); 862 } 863 864 /** 865 * hb_buffer_destroy: (skip) 866 * @buffer: An #hb_buffer_t 867 * 868 * Deallocate the @buffer. 869 * Decreases the reference count on @buffer by one. If the result is zero, then 870 * @buffer and all associated resources are freed. See hb_buffer_reference(). 871 * 872 * Since: 0.9.2 873 **/ 874 void 875 hb_buffer_destroy (hb_buffer_t *buffer) 876 { 877 if (!hb_object_destroy (buffer)) return; 878 879 hb_unicode_funcs_destroy (buffer->unicode); 880 881 hb_free (buffer->info); 882 hb_free (buffer->pos); 883 #ifndef HB_NO_BUFFER_MESSAGE 884 if (buffer->message_destroy) 885 buffer->message_destroy (buffer->message_data); 886 #endif 887 888 hb_free (buffer); 889 } 890 891 /** 892 * hb_buffer_set_user_data: (skip) 893 * @buffer: An #hb_buffer_t 894 * @key: The user-data key 895 * @data: A pointer to the user data 896 * @destroy: (nullable): A callback to call when @data is not needed anymore 897 * @replace: Whether to replace an existing data with the same key 898 * 899 * Attaches a user-data key/data pair to the specified buffer. 900 * 901 * Return value: `true` if success, `false` otherwise 902 * 903 * Since: 0.9.2 904 **/ 905 hb_bool_t 906 hb_buffer_set_user_data (hb_buffer_t *buffer, 907 hb_user_data_key_t *key, 908 void * data, 909 hb_destroy_func_t destroy, 910 hb_bool_t replace) 911 { 912 return hb_object_set_user_data (buffer, key, data, destroy, replace); 913 } 914 915 /** 916 * hb_buffer_get_user_data: (skip) 917 * @buffer: An #hb_buffer_t 918 * @key: The user-data key to query 919 * 920 * Fetches the user data associated with the specified key, 921 * attached to the specified buffer. 922 * 923 * Return value: (transfer none): A pointer to the user data 924 * 925 * Since: 0.9.2 926 **/ 927 void * 928 hb_buffer_get_user_data (const hb_buffer_t *buffer, 929 hb_user_data_key_t *key) 930 { 931 return hb_object_get_user_data (buffer, key); 932 } 933 934 935 /** 936 * hb_buffer_set_content_type: 937 * @buffer: An #hb_buffer_t 938 * @content_type: The type of buffer contents to set 939 * 940 * Sets the type of @buffer contents. Buffers are either empty, contain 941 * characters (before shaping), or contain glyphs (the result of shaping). 942 * 943 * You rarely need to call this function, since a number of other 944 * functions transition the content type for you. Namely: 945 * 946 * - A newly created buffer starts with content type 947 * %HB_BUFFER_CONTENT_TYPE_INVALID. Calling hb_buffer_reset(), 948 * hb_buffer_clear_contents(), as well as calling hb_buffer_set_length() 949 * with an argument of zero all set the buffer content type to invalid 950 * as well. 951 * 952 * - Calling hb_buffer_add_utf8(), hb_buffer_add_utf16(), 953 * hb_buffer_add_utf32(), hb_buffer_add_codepoints() and 954 * hb_buffer_add_latin1() expect that buffer is either empty and 955 * have a content type of invalid, or that buffer content type is 956 * %HB_BUFFER_CONTENT_TYPE_UNICODE, and they also set the content 957 * type to Unicode if they added anything to an empty buffer. 958 * 959 * - Finally hb_shape() and hb_shape_full() expect that the buffer 960 * is either empty and have content type of invalid, or that buffer 961 * content type is %HB_BUFFER_CONTENT_TYPE_UNICODE, and upon 962 * success they set the buffer content type to 963 * %HB_BUFFER_CONTENT_TYPE_GLYPHS. 964 * 965 * The above transitions are designed such that one can use a buffer 966 * in a loop of "reset : add-text : shape" without needing to ever 967 * modify the content type manually. 968 * 969 * Since: 0.9.5 970 **/ 971 void 972 hb_buffer_set_content_type (hb_buffer_t *buffer, 973 hb_buffer_content_type_t content_type) 974 { 975 buffer->content_type = content_type; 976 } 977 978 /** 979 * hb_buffer_get_content_type: 980 * @buffer: An #hb_buffer_t 981 * 982 * Fetches the type of @buffer contents. Buffers are either empty, contain 983 * characters (before shaping), or contain glyphs (the result of shaping). 984 * 985 * Return value: 986 * The type of @buffer contents 987 * 988 * Since: 0.9.5 989 **/ 990 hb_buffer_content_type_t 991 hb_buffer_get_content_type (const hb_buffer_t *buffer) 992 { 993 return buffer->content_type; 994 } 995 996 997 /** 998 * hb_buffer_set_unicode_funcs: 999 * @buffer: An #hb_buffer_t 1000 * @unicode_funcs: The Unicode-functions structure 1001 * 1002 * Sets the Unicode-functions structure of a buffer to 1003 * @unicode_funcs. 1004 * 1005 * Since: 0.9.2 1006 **/ 1007 void 1008 hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, 1009 hb_unicode_funcs_t *unicode_funcs) 1010 { 1011 if (unlikely (hb_object_is_immutable (buffer))) 1012 return; 1013 1014 if (!unicode_funcs) 1015 unicode_funcs = hb_unicode_funcs_get_default (); 1016 1017 hb_unicode_funcs_reference (unicode_funcs); 1018 hb_unicode_funcs_destroy (buffer->unicode); 1019 buffer->unicode = unicode_funcs; 1020 } 1021 1022 /** 1023 * hb_buffer_get_unicode_funcs: 1024 * @buffer: An #hb_buffer_t 1025 * 1026 * Fetches the Unicode-functions structure of a buffer. 1027 * 1028 * Return value: The Unicode-functions structure 1029 * 1030 * Since: 0.9.2 1031 **/ 1032 hb_unicode_funcs_t * 1033 hb_buffer_get_unicode_funcs (const hb_buffer_t *buffer) 1034 { 1035 return buffer->unicode; 1036 } 1037 1038 /** 1039 * hb_buffer_set_direction: 1040 * @buffer: An #hb_buffer_t 1041 * @direction: the #hb_direction_t of the @buffer 1042 * 1043 * Set the text flow direction of the buffer. No shaping can happen without 1044 * setting @buffer direction, and it controls the visual direction for the 1045 * output glyphs; for RTL direction the glyphs will be reversed. Many layout 1046 * features depend on the proper setting of the direction, for example, 1047 * reversing RTL text before shaping, then shaping with LTR direction is not 1048 * the same as keeping the text in logical order and shaping with RTL 1049 * direction. 1050 * 1051 * Since: 0.9.2 1052 **/ 1053 void 1054 hb_buffer_set_direction (hb_buffer_t *buffer, 1055 hb_direction_t direction) 1056 { 1057 if (unlikely (hb_object_is_immutable (buffer))) 1058 return; 1059 1060 buffer->props.direction = direction; 1061 } 1062 1063 /** 1064 * hb_buffer_get_direction: 1065 * @buffer: An #hb_buffer_t 1066 * 1067 * See hb_buffer_set_direction() 1068 * 1069 * Return value: 1070 * The direction of the @buffer. 1071 * 1072 * Since: 0.9.2 1073 **/ 1074 hb_direction_t 1075 hb_buffer_get_direction (const hb_buffer_t *buffer) 1076 { 1077 return buffer->props.direction; 1078 } 1079 1080 /** 1081 * hb_buffer_set_script: 1082 * @buffer: An #hb_buffer_t 1083 * @script: An #hb_script_t to set. 1084 * 1085 * Sets the script of @buffer to @script. 1086 * 1087 * Script is crucial for choosing the proper shaping behaviour for scripts that 1088 * require it (e.g. Arabic) and the which OpenType features defined in the font 1089 * to be applied. 1090 * 1091 * You can pass one of the predefined #hb_script_t values, or use 1092 * hb_script_from_string() or hb_script_from_iso15924_tag() to get the 1093 * corresponding script from an ISO 15924 script tag. 1094 * 1095 * Since: 0.9.2 1096 **/ 1097 void 1098 hb_buffer_set_script (hb_buffer_t *buffer, 1099 hb_script_t script) 1100 { 1101 if (unlikely (hb_object_is_immutable (buffer))) 1102 return; 1103 1104 buffer->props.script = script; 1105 } 1106 1107 /** 1108 * hb_buffer_get_script: 1109 * @buffer: An #hb_buffer_t 1110 * 1111 * Fetches the script of @buffer. 1112 * 1113 * Return value: 1114 * The #hb_script_t of the @buffer 1115 * 1116 * Since: 0.9.2 1117 **/ 1118 hb_script_t 1119 hb_buffer_get_script (const hb_buffer_t *buffer) 1120 { 1121 return buffer->props.script; 1122 } 1123 1124 /** 1125 * hb_buffer_set_language: 1126 * @buffer: An #hb_buffer_t 1127 * @language: An hb_language_t to set 1128 * 1129 * Sets the language of @buffer to @language. 1130 * 1131 * Languages are crucial for selecting which OpenType feature to apply to the 1132 * buffer which can result in applying language-specific behaviour. Languages 1133 * are orthogonal to the scripts, and though they are related, they are 1134 * different concepts and should not be confused with each other. 1135 * 1136 * Use hb_language_from_string() to convert from BCP 47 language tags to 1137 * #hb_language_t. 1138 * 1139 * Since: 0.9.2 1140 **/ 1141 void 1142 hb_buffer_set_language (hb_buffer_t *buffer, 1143 hb_language_t language) 1144 { 1145 if (unlikely (hb_object_is_immutable (buffer))) 1146 return; 1147 1148 buffer->props.language = language; 1149 } 1150 1151 /** 1152 * hb_buffer_get_language: 1153 * @buffer: An #hb_buffer_t 1154 * 1155 * See hb_buffer_set_language(). 1156 * 1157 * Return value: (transfer none): 1158 * The #hb_language_t of the buffer. Must not be freed by the caller. 1159 * 1160 * Since: 0.9.2 1161 **/ 1162 hb_language_t 1163 hb_buffer_get_language (const hb_buffer_t *buffer) 1164 { 1165 return buffer->props.language; 1166 } 1167 1168 /** 1169 * hb_buffer_set_segment_properties: 1170 * @buffer: An #hb_buffer_t 1171 * @props: An #hb_segment_properties_t to use 1172 * 1173 * Sets the segment properties of the buffer, a shortcut for calling 1174 * hb_buffer_set_direction(), hb_buffer_set_script() and 1175 * hb_buffer_set_language() individually. 1176 * 1177 * Since: 0.9.7 1178 **/ 1179 void 1180 hb_buffer_set_segment_properties (hb_buffer_t *buffer, 1181 const hb_segment_properties_t *props) 1182 { 1183 if (unlikely (hb_object_is_immutable (buffer))) 1184 return; 1185 1186 buffer->props = *props; 1187 } 1188 1189 /** 1190 * hb_buffer_get_segment_properties: 1191 * @buffer: An #hb_buffer_t 1192 * @props: (out): The output #hb_segment_properties_t 1193 * 1194 * Sets @props to the #hb_segment_properties_t of @buffer. 1195 * 1196 * Since: 0.9.7 1197 **/ 1198 void 1199 hb_buffer_get_segment_properties (const hb_buffer_t *buffer, 1200 hb_segment_properties_t *props) 1201 { 1202 *props = buffer->props; 1203 } 1204 1205 1206 /** 1207 * hb_buffer_set_flags: 1208 * @buffer: An #hb_buffer_t 1209 * @flags: The buffer flags to set 1210 * 1211 * Sets @buffer flags to @flags. See #hb_buffer_flags_t. 1212 * 1213 * Since: 0.9.7 1214 **/ 1215 void 1216 hb_buffer_set_flags (hb_buffer_t *buffer, 1217 hb_buffer_flags_t flags) 1218 { 1219 if (unlikely (hb_object_is_immutable (buffer))) 1220 return; 1221 1222 buffer->flags = flags; 1223 } 1224 1225 /** 1226 * hb_buffer_get_flags: 1227 * @buffer: An #hb_buffer_t 1228 * 1229 * Fetches the #hb_buffer_flags_t of @buffer. 1230 * 1231 * Return value: 1232 * The @buffer flags 1233 * 1234 * Since: 0.9.7 1235 **/ 1236 hb_buffer_flags_t 1237 hb_buffer_get_flags (const hb_buffer_t *buffer) 1238 { 1239 return buffer->flags; 1240 } 1241 1242 /** 1243 * hb_buffer_set_cluster_level: 1244 * @buffer: An #hb_buffer_t 1245 * @cluster_level: The cluster level to set on the buffer 1246 * 1247 * Sets the cluster level of a buffer. The #hb_buffer_cluster_level_t 1248 * dictates one aspect of how HarfBuzz will treat non-base characters 1249 * during shaping. 1250 * 1251 * Since: 0.9.42 1252 **/ 1253 void 1254 hb_buffer_set_cluster_level (hb_buffer_t *buffer, 1255 hb_buffer_cluster_level_t cluster_level) 1256 { 1257 if (unlikely (hb_object_is_immutable (buffer))) 1258 return; 1259 1260 buffer->cluster_level = cluster_level; 1261 } 1262 1263 /** 1264 * hb_buffer_get_cluster_level: 1265 * @buffer: An #hb_buffer_t 1266 * 1267 * Fetches the cluster level of a buffer. The #hb_buffer_cluster_level_t 1268 * dictates one aspect of how HarfBuzz will treat non-base characters 1269 * during shaping. 1270 * 1271 * Return value: The cluster level of @buffer 1272 * 1273 * Since: 0.9.42 1274 **/ 1275 hb_buffer_cluster_level_t 1276 hb_buffer_get_cluster_level (const hb_buffer_t *buffer) 1277 { 1278 return buffer->cluster_level; 1279 } 1280 1281 1282 /** 1283 * hb_buffer_set_replacement_codepoint: 1284 * @buffer: An #hb_buffer_t 1285 * @replacement: the replacement #hb_codepoint_t 1286 * 1287 * Sets the #hb_codepoint_t that replaces invalid entries for a given encoding 1288 * when adding text to @buffer. 1289 * 1290 * Default is #HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT. 1291 * 1292 * Since: 0.9.31 1293 **/ 1294 void 1295 hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer, 1296 hb_codepoint_t replacement) 1297 { 1298 if (unlikely (hb_object_is_immutable (buffer))) 1299 return; 1300 1301 buffer->replacement = replacement; 1302 } 1303 1304 /** 1305 * hb_buffer_get_replacement_codepoint: 1306 * @buffer: An #hb_buffer_t 1307 * 1308 * Fetches the #hb_codepoint_t that replaces invalid entries for a given encoding 1309 * when adding text to @buffer. 1310 * 1311 * Return value: 1312 * The @buffer replacement #hb_codepoint_t 1313 * 1314 * Since: 0.9.31 1315 **/ 1316 hb_codepoint_t 1317 hb_buffer_get_replacement_codepoint (const hb_buffer_t *buffer) 1318 { 1319 return buffer->replacement; 1320 } 1321 1322 1323 /** 1324 * hb_buffer_set_invisible_glyph: 1325 * @buffer: An #hb_buffer_t 1326 * @invisible: the invisible #hb_codepoint_t 1327 * 1328 * Sets the #hb_codepoint_t that replaces invisible characters in 1329 * the shaping result. If set to zero (default), the glyph for the 1330 * U+0020 SPACE character is used. Otherwise, this value is used 1331 * verbatim. 1332 * 1333 * Since: 2.0.0 1334 **/ 1335 void 1336 hb_buffer_set_invisible_glyph (hb_buffer_t *buffer, 1337 hb_codepoint_t invisible) 1338 { 1339 if (unlikely (hb_object_is_immutable (buffer))) 1340 return; 1341 1342 buffer->invisible = invisible; 1343 } 1344 1345 /** 1346 * hb_buffer_get_invisible_glyph: 1347 * @buffer: An #hb_buffer_t 1348 * 1349 * See hb_buffer_set_invisible_glyph(). 1350 * 1351 * Return value: 1352 * The @buffer invisible #hb_codepoint_t 1353 * 1354 * Since: 2.0.0 1355 **/ 1356 hb_codepoint_t 1357 hb_buffer_get_invisible_glyph (const hb_buffer_t *buffer) 1358 { 1359 return buffer->invisible; 1360 } 1361 1362 /** 1363 * hb_buffer_set_not_found_glyph: 1364 * @buffer: An #hb_buffer_t 1365 * @not_found: the not-found #hb_codepoint_t 1366 * 1367 * Sets the #hb_codepoint_t that replaces characters not found in 1368 * the font during shaping. 1369 * 1370 * The not-found glyph defaults to zero, sometimes known as the 1371 * ".notdef" glyph. This API allows for differentiating the two. 1372 * 1373 * Since: 3.1.0 1374 **/ 1375 void 1376 hb_buffer_set_not_found_glyph (hb_buffer_t *buffer, 1377 hb_codepoint_t not_found) 1378 { 1379 if (unlikely (hb_object_is_immutable (buffer))) 1380 return; 1381 1382 buffer->not_found = not_found; 1383 } 1384 1385 /** 1386 * hb_buffer_get_not_found_glyph: 1387 * @buffer: An #hb_buffer_t 1388 * 1389 * See hb_buffer_set_not_found_glyph(). 1390 * 1391 * Return value: 1392 * The @buffer not-found #hb_codepoint_t 1393 * 1394 * Since: 3.1.0 1395 **/ 1396 hb_codepoint_t 1397 hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer) 1398 { 1399 return buffer->not_found; 1400 } 1401 1402 /** 1403 * hb_buffer_set_not_found_variation_selector_glyph: 1404 * @buffer: An #hb_buffer_t 1405 * @not_found_variation_selector: the not-found-variation-selector #hb_codepoint_t 1406 * 1407 * Sets the #hb_codepoint_t that replaces variation-selector characters not resolved 1408 * in the font during shaping. 1409 * 1410 * The not-found-variation-selector glyph defaults to #HB_CODEPOINT_INVALID, 1411 * in which case an unresolved variation-selector will be removed from the glyph 1412 * string during shaping. This API allows for changing that and retaining a glyph, 1413 * such that the situation can be detected by the client and handled accordingly 1414 * (e.g. by using a different font). 1415 * 1416 * Since: 10.0.0 1417 **/ 1418 void 1419 hb_buffer_set_not_found_variation_selector_glyph (hb_buffer_t *buffer, 1420 hb_codepoint_t not_found_variation_selector) 1421 { 1422 buffer->not_found_variation_selector = not_found_variation_selector; 1423 } 1424 1425 /** 1426 * hb_buffer_get_not_found_variation_selector_glyph: 1427 * @buffer: An #hb_buffer_t 1428 * 1429 * See hb_buffer_set_not_found_variation_selector_glyph(). 1430 * 1431 * Return value: 1432 * The @buffer not-found-variation-selector #hb_codepoint_t 1433 * 1434 * Since: 10.0.0 1435 **/ 1436 hb_codepoint_t 1437 hb_buffer_get_not_found_variation_selector_glyph (const hb_buffer_t *buffer) 1438 { 1439 return buffer->not_found_variation_selector; 1440 } 1441 1442 /** 1443 * hb_buffer_set_random_state: 1444 * @buffer: An #hb_buffer_t 1445 * @state: the new random state 1446 * 1447 * Sets the random state of the buffer. The state changes 1448 * every time a glyph uses randomness (eg. the `rand` 1449 * OpenType feature). This function together with 1450 * hb_buffer_get_random_state() allow for transferring 1451 * the current random state to a subsequent buffer, to 1452 * get better randomness distribution. 1453 * 1454 * Defaults to 1 and when buffer contents are cleared. 1455 * A value of 0 disables randomness during shaping. 1456 * 1457 * Since: 8.4.0 1458 **/ 1459 void 1460 hb_buffer_set_random_state (hb_buffer_t *buffer, 1461 unsigned state) 1462 { 1463 if (unlikely (hb_object_is_immutable (buffer))) 1464 return; 1465 1466 buffer->random_state = state; 1467 } 1468 1469 /** 1470 * hb_buffer_get_random_state: 1471 * @buffer: An #hb_buffer_t 1472 * 1473 * See hb_buffer_set_random_state(). 1474 * 1475 * Return value: 1476 * The @buffer random state 1477 * 1478 * Since: 8.4.0 1479 **/ 1480 unsigned 1481 hb_buffer_get_random_state (const hb_buffer_t *buffer) 1482 { 1483 return buffer->random_state; 1484 } 1485 1486 /** 1487 * hb_buffer_clear_contents: 1488 * @buffer: An #hb_buffer_t 1489 * 1490 * Similar to hb_buffer_reset(), but does not clear the Unicode functions and 1491 * the replacement code point. 1492 * 1493 * Since: 0.9.11 1494 **/ 1495 void 1496 hb_buffer_clear_contents (hb_buffer_t *buffer) 1497 { 1498 if (unlikely (hb_object_is_immutable (buffer))) 1499 return; 1500 1501 buffer->clear (); 1502 } 1503 1504 /** 1505 * hb_buffer_pre_allocate: 1506 * @buffer: An #hb_buffer_t 1507 * @size: Number of items to pre allocate. 1508 * 1509 * Pre allocates memory for @buffer to fit at least @size number of items. 1510 * 1511 * Return value: 1512 * `true` if @buffer memory allocation succeeded, `false` otherwise 1513 * 1514 * Since: 0.9.2 1515 **/ 1516 hb_bool_t 1517 hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size) 1518 { 1519 return buffer->ensure (size); 1520 } 1521 1522 /** 1523 * hb_buffer_allocation_successful: 1524 * @buffer: An #hb_buffer_t 1525 * 1526 * Check if allocating memory for the buffer succeeded. 1527 * 1528 * Return value: 1529 * `true` if @buffer memory allocation succeeded, `false` otherwise. 1530 * 1531 * Since: 0.9.2 1532 **/ 1533 hb_bool_t 1534 hb_buffer_allocation_successful (hb_buffer_t *buffer) 1535 { 1536 return buffer->successful; 1537 } 1538 1539 /** 1540 * hb_buffer_add: 1541 * @buffer: An #hb_buffer_t 1542 * @codepoint: A Unicode code point. 1543 * @cluster: The cluster value of @codepoint. 1544 * 1545 * Appends a character with the Unicode value of @codepoint to @buffer, and 1546 * gives it the initial cluster value of @cluster. Clusters can be any thing 1547 * the client wants, they are usually used to refer to the index of the 1548 * character in the input text stream and are output in 1549 * #hb_glyph_info_t.cluster field. 1550 * 1551 * This function does not check the validity of @codepoint, it is up to the 1552 * caller to ensure it is a valid Unicode code point. 1553 * 1554 * Since: 0.9.7 1555 **/ 1556 void 1557 hb_buffer_add (hb_buffer_t *buffer, 1558 hb_codepoint_t codepoint, 1559 unsigned int cluster) 1560 { 1561 buffer->add (codepoint, cluster); 1562 buffer->clear_context (1); 1563 } 1564 1565 /** 1566 * hb_buffer_set_length: 1567 * @buffer: An #hb_buffer_t 1568 * @length: The new length of @buffer 1569 * 1570 * Similar to hb_buffer_pre_allocate(), but clears any new items added at the 1571 * end. 1572 * 1573 * Return value: 1574 * `true` if @buffer memory allocation succeeded, `false` otherwise. 1575 * 1576 * Since: 0.9.2 1577 **/ 1578 hb_bool_t 1579 hb_buffer_set_length (hb_buffer_t *buffer, 1580 unsigned int length) 1581 { 1582 if (unlikely (hb_object_is_immutable (buffer))) 1583 return length == 0; 1584 1585 if (unlikely (!buffer->ensure (length))) 1586 return false; 1587 1588 /* Wipe the new space */ 1589 if (length > buffer->len) { 1590 hb_memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len)); 1591 if (buffer->have_positions) 1592 hb_memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len)); 1593 } 1594 1595 buffer->len = length; 1596 1597 if (!length) 1598 { 1599 buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID; 1600 buffer->clear_context (0); 1601 } 1602 buffer->clear_context (1); 1603 1604 return true; 1605 } 1606 1607 /** 1608 * hb_buffer_get_length: 1609 * @buffer: An #hb_buffer_t 1610 * 1611 * Returns the number of items in the buffer. 1612 * 1613 * Return value: 1614 * The @buffer length. 1615 * The value valid as long as buffer has not been modified. 1616 * 1617 * Since: 0.9.2 1618 **/ 1619 unsigned int 1620 hb_buffer_get_length (const hb_buffer_t *buffer) 1621 { 1622 return buffer->len; 1623 } 1624 1625 /** 1626 * hb_buffer_get_glyph_infos: 1627 * @buffer: An #hb_buffer_t 1628 * @length: (out): The output-array length. 1629 * 1630 * Returns @buffer glyph information array. Returned pointer 1631 * is valid as long as @buffer contents are not modified. 1632 * 1633 * Return value: (transfer none) (array length=length): 1634 * The @buffer glyph information array. 1635 * The value valid as long as buffer has not been modified. 1636 * 1637 * Since: 0.9.2 1638 **/ 1639 hb_glyph_info_t * 1640 hb_buffer_get_glyph_infos (hb_buffer_t *buffer, 1641 unsigned int *length) 1642 { 1643 if (length) 1644 *length = buffer->len; 1645 1646 return (hb_glyph_info_t *) buffer->info; 1647 } 1648 1649 /** 1650 * hb_buffer_get_glyph_positions: 1651 * @buffer: An #hb_buffer_t 1652 * @length: (out): The output length 1653 * 1654 * Returns @buffer glyph position array. Returned pointer 1655 * is valid as long as @buffer contents are not modified. 1656 * 1657 * If buffer did not have positions before, the positions will be 1658 * initialized to zeros, unless this function is called from 1659 * within a buffer message callback (see hb_buffer_set_message_func()), 1660 * in which case `NULL` is returned. 1661 * 1662 * Return value: (transfer none) (array length=length): 1663 * The @buffer glyph position array. 1664 * The value valid as long as buffer has not been modified. 1665 * 1666 * Since: 0.9.2 1667 **/ 1668 hb_glyph_position_t * 1669 hb_buffer_get_glyph_positions (hb_buffer_t *buffer, 1670 unsigned int *length) 1671 { 1672 if (length) 1673 *length = buffer->len; 1674 1675 if (!buffer->have_positions) 1676 { 1677 if (unlikely (buffer->message_depth)) 1678 return nullptr; 1679 1680 buffer->clear_positions (); 1681 } 1682 1683 return (hb_glyph_position_t *) buffer->pos; 1684 } 1685 1686 /** 1687 * hb_buffer_has_positions: 1688 * @buffer: an #hb_buffer_t. 1689 * 1690 * Returns whether @buffer has glyph position data. 1691 * A buffer gains position data when hb_buffer_get_glyph_positions() is called on it, 1692 * and cleared of position data when hb_buffer_clear_contents() is called. 1693 * 1694 * Return value: 1695 * `true` if the @buffer has position array, `false` otherwise. 1696 * 1697 * Since: 2.7.3 1698 **/ 1699 HB_EXTERN hb_bool_t 1700 hb_buffer_has_positions (hb_buffer_t *buffer) 1701 { 1702 return buffer->have_positions; 1703 } 1704 1705 /** 1706 * hb_glyph_info_get_glyph_flags: 1707 * @info: a #hb_glyph_info_t 1708 * 1709 * Returns glyph flags encoded within a #hb_glyph_info_t. 1710 * 1711 * Return value: 1712 * The #hb_glyph_flags_t encoded within @info 1713 * 1714 * Since: 1.5.0 1715 **/ 1716 hb_glyph_flags_t 1717 (hb_glyph_info_get_glyph_flags) (const hb_glyph_info_t *info) 1718 { 1719 return hb_glyph_info_get_glyph_flags (info); 1720 } 1721 1722 /** 1723 * hb_buffer_reverse: 1724 * @buffer: An #hb_buffer_t 1725 * 1726 * Reverses buffer contents. 1727 * 1728 * Since: 0.9.2 1729 **/ 1730 void 1731 hb_buffer_reverse (hb_buffer_t *buffer) 1732 { 1733 buffer->reverse (); 1734 } 1735 1736 /** 1737 * hb_buffer_reverse_range: 1738 * @buffer: An #hb_buffer_t 1739 * @start: start index 1740 * @end: end index 1741 * 1742 * Reverses buffer contents between @start and @end. 1743 * 1744 * Since: 0.9.41 1745 **/ 1746 void 1747 hb_buffer_reverse_range (hb_buffer_t *buffer, 1748 unsigned int start, unsigned int end) 1749 { 1750 buffer->reverse_range (start, end); 1751 } 1752 1753 /** 1754 * hb_buffer_reverse_clusters: 1755 * @buffer: An #hb_buffer_t 1756 * 1757 * Reverses buffer clusters. That is, the buffer contents are 1758 * reversed, then each cluster (consecutive items having the 1759 * same cluster number) are reversed again. 1760 * 1761 * Since: 0.9.2 1762 **/ 1763 void 1764 hb_buffer_reverse_clusters (hb_buffer_t *buffer) 1765 { 1766 buffer->reverse_clusters (); 1767 } 1768 1769 /** 1770 * hb_buffer_guess_segment_properties: 1771 * @buffer: An #hb_buffer_t 1772 * 1773 * Sets unset buffer segment properties based on buffer Unicode 1774 * contents. If buffer is not empty, it must have content type 1775 * #HB_BUFFER_CONTENT_TYPE_UNICODE. 1776 * 1777 * If buffer script is not set (ie. is #HB_SCRIPT_INVALID), it 1778 * will be set to the Unicode script of the first character in 1779 * the buffer that has a script other than #HB_SCRIPT_COMMON, 1780 * #HB_SCRIPT_INHERITED, and #HB_SCRIPT_UNKNOWN. 1781 * 1782 * Next, if buffer direction is not set (ie. is #HB_DIRECTION_INVALID), 1783 * it will be set to the natural horizontal direction of the 1784 * buffer script as returned by hb_script_get_horizontal_direction(). 1785 * If hb_script_get_horizontal_direction() returns #HB_DIRECTION_INVALID, 1786 * then #HB_DIRECTION_LTR is used. 1787 * 1788 * Finally, if buffer language is not set (ie. is #HB_LANGUAGE_INVALID), 1789 * it will be set to the process's default language as returned by 1790 * hb_language_get_default(). This may change in the future by 1791 * taking buffer script into consideration when choosing a language. 1792 * Note that hb_language_get_default() is NOT threadsafe the first time 1793 * it is called. See documentation for that function for details. 1794 * 1795 * Since: 0.9.7 1796 **/ 1797 void 1798 hb_buffer_guess_segment_properties (hb_buffer_t *buffer) 1799 { 1800 buffer->guess_segment_properties (); 1801 } 1802 1803 template <typename utf_t> 1804 static inline void 1805 hb_buffer_add_utf (hb_buffer_t *buffer, 1806 const typename utf_t::codepoint_t *text, 1807 int text_length, 1808 unsigned int item_offset, 1809 int item_length) 1810 { 1811 typedef typename utf_t::codepoint_t T; 1812 const hb_codepoint_t replacement = buffer->replacement; 1813 1814 buffer->assert_unicode (); 1815 1816 if (unlikely (hb_object_is_immutable (buffer))) 1817 return; 1818 1819 if (text_length == -1) 1820 text_length = utf_t::strlen (text); 1821 1822 if (item_length == -1) 1823 item_length = text_length - item_offset; 1824 1825 if (unlikely (item_length < 0 || 1826 item_length > INT_MAX / 8 || 1827 !buffer->ensure (buffer->len + item_length * sizeof (T) / 4))) 1828 return; 1829 1830 /* If buffer is empty and pre-context provided, install it. 1831 * This check is written this way, to make sure people can 1832 * provide pre-context in one add_utf() call, then provide 1833 * text in a follow-up call. See: 1834 * 1835 * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13 1836 */ 1837 if (!buffer->len && item_offset > 0) 1838 { 1839 /* Add pre-context */ 1840 buffer->clear_context (0); 1841 const T *prev = text + item_offset; 1842 const T *start = text; 1843 while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH) 1844 { 1845 hb_codepoint_t u; 1846 prev = utf_t::prev (prev, start, &u, replacement); 1847 buffer->context[0][buffer->context_len[0]++] = u; 1848 } 1849 } 1850 1851 const T *next = text + item_offset; 1852 const T *end = next + item_length; 1853 while (next < end) 1854 { 1855 hb_codepoint_t u; 1856 const T *old_next = next; 1857 next = utf_t::next (next, end, &u, replacement); 1858 buffer->add (u, old_next - (const T *) text); 1859 } 1860 1861 /* Add post-context */ 1862 buffer->clear_context (1); 1863 end = text + text_length; 1864 while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH) 1865 { 1866 hb_codepoint_t u; 1867 next = utf_t::next (next, end, &u, replacement); 1868 buffer->context[1][buffer->context_len[1]++] = u; 1869 } 1870 1871 buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE; 1872 } 1873 1874 /** 1875 * hb_buffer_add_utf8: 1876 * @buffer: An #hb_buffer_t 1877 * @text: (array length=text_length) (element-type uint8_t): An array of UTF-8 1878 * characters to append. 1879 * @text_length: The length of the @text, or -1 if it is `NULL` terminated. 1880 * @item_offset: The offset of the first character to add to the @buffer. 1881 * @item_length: The number of characters to add to the @buffer, or -1 for the 1882 * end of @text (assuming it is `NULL` terminated). 1883 * 1884 * See hb_buffer_add_codepoints(). 1885 * 1886 * Replaces invalid UTF-8 characters with the @buffer replacement code point, 1887 * see hb_buffer_set_replacement_codepoint(). 1888 * 1889 * Since: 0.9.2 1890 **/ 1891 void 1892 hb_buffer_add_utf8 (hb_buffer_t *buffer, 1893 const char *text, 1894 int text_length, 1895 unsigned int item_offset, 1896 int item_length) 1897 { 1898 hb_buffer_add_utf<hb_utf8_t> (buffer, (const uint8_t *) text, text_length, item_offset, item_length); 1899 } 1900 1901 /** 1902 * hb_buffer_add_utf16: 1903 * @buffer: An #hb_buffer_t 1904 * @text: (array length=text_length): An array of UTF-16 characters to append 1905 * @text_length: The length of the @text, or -1 if it is `NULL` terminated 1906 * @item_offset: The offset of the first character to add to the @buffer 1907 * @item_length: The number of characters to add to the @buffer, or -1 for the 1908 * end of @text (assuming it is `NULL` terminated) 1909 * 1910 * See hb_buffer_add_codepoints(). 1911 * 1912 * Replaces invalid UTF-16 characters with the @buffer replacement code point, 1913 * see hb_buffer_set_replacement_codepoint(). 1914 * 1915 * Since: 0.9.2 1916 **/ 1917 void 1918 hb_buffer_add_utf16 (hb_buffer_t *buffer, 1919 const uint16_t *text, 1920 int text_length, 1921 unsigned int item_offset, 1922 int item_length) 1923 { 1924 hb_buffer_add_utf<hb_utf16_t> (buffer, text, text_length, item_offset, item_length); 1925 } 1926 1927 /** 1928 * hb_buffer_add_utf32: 1929 * @buffer: An #hb_buffer_t 1930 * @text: (array length=text_length): An array of UTF-32 characters to append 1931 * @text_length: The length of the @text, or -1 if it is `NULL` terminated 1932 * @item_offset: The offset of the first character to add to the @buffer 1933 * @item_length: The number of characters to add to the @buffer, or -1 for the 1934 * end of @text (assuming it is `NULL` terminated) 1935 * 1936 * See hb_buffer_add_codepoints(). 1937 * 1938 * Replaces invalid UTF-32 characters with the @buffer replacement code point, 1939 * see hb_buffer_set_replacement_codepoint(). 1940 * 1941 * Since: 0.9.2 1942 **/ 1943 void 1944 hb_buffer_add_utf32 (hb_buffer_t *buffer, 1945 const uint32_t *text, 1946 int text_length, 1947 unsigned int item_offset, 1948 int item_length) 1949 { 1950 hb_buffer_add_utf<hb_utf32_t> (buffer, text, text_length, item_offset, item_length); 1951 } 1952 1953 /** 1954 * hb_buffer_add_latin1: 1955 * @buffer: An #hb_buffer_t 1956 * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8 1957 * characters to append 1958 * @text_length: the length of the @text, or -1 if it is `NULL` terminated 1959 * @item_offset: the offset of the first character to add to the @buffer 1960 * @item_length: the number of characters to add to the @buffer, or -1 for the 1961 * end of @text (assuming it is `NULL` terminated) 1962 * 1963 * Similar to hb_buffer_add_codepoints(), but allows only access to first 256 1964 * Unicode code points that can fit in 8-bit strings. 1965 * 1966 * <note>Has nothing to do with non-Unicode Latin-1 encoding.</note> 1967 * 1968 * Since: 0.9.39 1969 **/ 1970 void 1971 hb_buffer_add_latin1 (hb_buffer_t *buffer, 1972 const uint8_t *text, 1973 int text_length, 1974 unsigned int item_offset, 1975 int item_length) 1976 { 1977 hb_buffer_add_utf<hb_latin1_t> (buffer, text, text_length, item_offset, item_length); 1978 } 1979 1980 /** 1981 * hb_buffer_add_codepoints: 1982 * @buffer: a #hb_buffer_t to append characters to. 1983 * @text: (array length=text_length): an array of Unicode code points to append. 1984 * @text_length: the length of the @text, or -1 if it is `NULL` terminated. 1985 * @item_offset: the offset of the first code point to add to the @buffer. 1986 * @item_length: the number of code points to add to the @buffer, or -1 for the 1987 * end of @text (assuming it is `NULL` terminated). 1988 * 1989 * Appends characters from @text array to @buffer. The @item_offset is the 1990 * position of the first character from @text that will be appended, and 1991 * @item_length is the number of character. When shaping part of a larger text 1992 * (e.g. a run of text from a paragraph), instead of passing just the substring 1993 * corresponding to the run, it is preferable to pass the whole 1994 * paragraph and specify the run start and length as @item_offset and 1995 * @item_length, respectively, to give HarfBuzz the full context to be able, 1996 * for example, to do cross-run Arabic shaping or properly handle combining 1997 * marks at stat of run. 1998 * 1999 * This function does not check the validity of @text, it is up to the caller 2000 * to ensure it contains a valid Unicode scalar values. In contrast, 2001 * hb_buffer_add_utf32() can be used that takes similar input but performs 2002 * sanity-check on the input. 2003 * 2004 * Since: 0.9.31 2005 **/ 2006 void 2007 hb_buffer_add_codepoints (hb_buffer_t *buffer, 2008 const hb_codepoint_t *text, 2009 int text_length, 2010 unsigned int item_offset, 2011 int item_length) 2012 { 2013 hb_buffer_add_utf<hb_utf32_novalidate_t> (buffer, text, text_length, item_offset, item_length); 2014 } 2015 2016 2017 /** 2018 * hb_buffer_append: 2019 * @buffer: An #hb_buffer_t 2020 * @source: source #hb_buffer_t 2021 * @start: start index into source buffer to copy. Use 0 to copy from start of buffer. 2022 * @end: end index into source buffer to copy. Use @UINT_MAX (or ((unsigned int) -1)) to copy to end of buffer. 2023 * 2024 * Append (part of) contents of another buffer to this buffer. 2025 * 2026 * Since: 1.5.0 2027 **/ 2028 HB_EXTERN void 2029 hb_buffer_append (hb_buffer_t *buffer, 2030 const hb_buffer_t *source, 2031 unsigned int start, 2032 unsigned int end) 2033 { 2034 assert (!buffer->have_output && !source->have_output); 2035 assert (buffer->have_positions == source->have_positions || 2036 !buffer->len || !source->len); 2037 assert (buffer->content_type == source->content_type || 2038 !buffer->len || !source->len); 2039 2040 if (end > source->len) 2041 end = source->len; 2042 if (start > end) 2043 start = end; 2044 if (start == end) 2045 return; 2046 2047 if (buffer->len + (end - start) < buffer->len) /* Overflows. */ 2048 { 2049 buffer->successful = false; 2050 return; 2051 } 2052 2053 unsigned int orig_len = buffer->len; 2054 hb_buffer_set_length (buffer, buffer->len + (end - start)); 2055 if (unlikely (!buffer->successful)) 2056 return; 2057 2058 if (!orig_len) 2059 buffer->content_type = source->content_type; 2060 if (!buffer->have_positions && source->have_positions) 2061 buffer->clear_positions (); 2062 2063 hb_segment_properties_overlay (&buffer->props, &source->props); 2064 2065 hb_memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0])); 2066 if (buffer->have_positions) 2067 hb_memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0])); 2068 2069 if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) 2070 { 2071 /* See similar logic in add_utf. */ 2072 2073 /* pre-context */ 2074 if (!orig_len && start + source->context_len[0] > 0) 2075 { 2076 buffer->clear_context (0); 2077 while (start > 0 && buffer->context_len[0] < buffer->CONTEXT_LENGTH) 2078 buffer->context[0][buffer->context_len[0]++] = source->info[--start].codepoint; 2079 for (auto i = 0u; i < source->context_len[0] && buffer->context_len[0] < buffer->CONTEXT_LENGTH; i++) 2080 buffer->context[0][buffer->context_len[0]++] = source->context[0][i]; 2081 } 2082 2083 /* post-context */ 2084 buffer->clear_context (1); 2085 while (end < source->len && buffer->context_len[1] < buffer->CONTEXT_LENGTH) 2086 buffer->context[1][buffer->context_len[1]++] = source->info[end++].codepoint; 2087 for (auto i = 0u; i < source->context_len[1] && buffer->context_len[1] < buffer->CONTEXT_LENGTH; i++) 2088 buffer->context[1][buffer->context_len[1]++] = source->context[1][i]; 2089 } 2090 } 2091 2092 2093 static int 2094 compare_info_codepoint (const hb_glyph_info_t *pa, 2095 const hb_glyph_info_t *pb) 2096 { 2097 return (int) pb->codepoint - (int) pa->codepoint; 2098 } 2099 2100 static inline void 2101 normalize_glyphs_cluster (hb_buffer_t *buffer, 2102 unsigned int start, 2103 unsigned int end, 2104 bool backward) 2105 { 2106 hb_glyph_position_t *pos = buffer->pos; 2107 2108 /* Total cluster advance */ 2109 hb_position_t total_x_advance = 0, total_y_advance = 0; 2110 for (unsigned int i = start; i < end; i++) 2111 { 2112 total_x_advance += pos[i].x_advance; 2113 total_y_advance += pos[i].y_advance; 2114 } 2115 2116 hb_position_t x_advance = 0, y_advance = 0; 2117 for (unsigned int i = start; i < end; i++) 2118 { 2119 pos[i].x_offset += x_advance; 2120 pos[i].y_offset += y_advance; 2121 2122 x_advance += pos[i].x_advance; 2123 y_advance += pos[i].y_advance; 2124 2125 pos[i].x_advance = 0; 2126 pos[i].y_advance = 0; 2127 } 2128 2129 if (backward) 2130 { 2131 /* Transfer all cluster advance to the last glyph. */ 2132 pos[end - 1].x_advance = total_x_advance; 2133 pos[end - 1].y_advance = total_y_advance; 2134 2135 hb_stable_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start); 2136 } else { 2137 /* Transfer all cluster advance to the first glyph. */ 2138 pos[start].x_advance += total_x_advance; 2139 pos[start].y_advance += total_y_advance; 2140 for (unsigned int i = start + 1; i < end; i++) { 2141 pos[i].x_offset -= total_x_advance; 2142 pos[i].y_offset -= total_y_advance; 2143 } 2144 hb_stable_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1); 2145 } 2146 } 2147 2148 /** 2149 * hb_buffer_normalize_glyphs: 2150 * @buffer: An #hb_buffer_t 2151 * 2152 * Reorders a glyph buffer to have canonical in-cluster glyph order / position. 2153 * The resulting clusters should behave identical to pre-reordering clusters. 2154 * 2155 * <note>This has nothing to do with Unicode normalization.</note> 2156 * 2157 * Since: 0.9.2 2158 **/ 2159 void 2160 hb_buffer_normalize_glyphs (hb_buffer_t *buffer) 2161 { 2162 assert (buffer->have_positions); 2163 2164 buffer->assert_glyphs (); 2165 2166 bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); 2167 2168 foreach_cluster (buffer, start, end) 2169 normalize_glyphs_cluster (buffer, start, end, backward); 2170 } 2171 2172 void 2173 hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *)) 2174 { 2175 assert (!have_positions); 2176 for (unsigned int i = start + 1; i < end; i++) 2177 { 2178 unsigned int j = i; 2179 while (j > start && compar (&info[j - 1], &info[i]) > 0) 2180 j--; 2181 if (i == j) 2182 continue; 2183 /* Move item i to occupy place for item j, shift what's in between. */ 2184 merge_clusters (j, i + 1); 2185 { 2186 hb_glyph_info_t t = info[i]; 2187 memmove (&info[j + 1], &info[j], (i - j) * sizeof (hb_glyph_info_t)); 2188 info[j] = t; 2189 } 2190 } 2191 } 2192 2193 2194 /* 2195 * Comparing buffers. 2196 */ 2197 2198 /** 2199 * hb_buffer_diff: 2200 * @buffer: a buffer. 2201 * @reference: other buffer to compare to. 2202 * @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepoint_t) -1. 2203 * @position_fuzz: allowed absolute difference in position values. 2204 * 2205 * If dottedcircle_glyph is (hb_codepoint_t) -1 then #HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT 2206 * and #HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most 2207 * callers if just comparing two buffers is needed. 2208 * 2209 * Since: 1.5.0 2210 **/ 2211 hb_buffer_diff_flags_t 2212 hb_buffer_diff (hb_buffer_t *buffer, 2213 hb_buffer_t *reference, 2214 hb_codepoint_t dottedcircle_glyph, 2215 unsigned int position_fuzz) 2216 { 2217 if (buffer->content_type != reference->content_type && buffer->len && reference->len) 2218 return HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH; 2219 2220 hb_buffer_diff_flags_t result = HB_BUFFER_DIFF_FLAG_EQUAL; 2221 bool contains = dottedcircle_glyph != (hb_codepoint_t) -1; 2222 2223 unsigned int count = reference->len; 2224 2225 if (buffer->len != count) 2226 { 2227 /* 2228 * we can't compare glyph-by-glyph, but we do want to know if there 2229 * are .notdef or dottedcircle glyphs present in the reference buffer 2230 */ 2231 const hb_glyph_info_t *info = reference->info; 2232 unsigned int i; 2233 for (i = 0; i < count; i++) 2234 { 2235 if (contains && info[i].codepoint == dottedcircle_glyph) 2236 result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT; 2237 if (contains && info[i].codepoint == 0) 2238 result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT; 2239 } 2240 result |= HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH; 2241 return hb_buffer_diff_flags_t (result); 2242 } 2243 2244 if (!count) 2245 return hb_buffer_diff_flags_t (result); 2246 2247 const hb_glyph_info_t *buf_info = buffer->info; 2248 const hb_glyph_info_t *ref_info = reference->info; 2249 for (unsigned int i = 0; i < count; i++) 2250 { 2251 if (buf_info->codepoint != ref_info->codepoint) 2252 result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH; 2253 if (buf_info->cluster != ref_info->cluster) 2254 result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH; 2255 if ((buf_info->mask ^ ref_info->mask) & HB_GLYPH_FLAG_DEFINED) 2256 result |= HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH; 2257 if (contains && ref_info->codepoint == dottedcircle_glyph) 2258 result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT; 2259 if (contains && ref_info->codepoint == 0) 2260 result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT; 2261 buf_info++; 2262 ref_info++; 2263 } 2264 2265 if (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS) 2266 { 2267 assert (buffer->have_positions); 2268 const hb_glyph_position_t *buf_pos = buffer->pos; 2269 const hb_glyph_position_t *ref_pos = reference->pos; 2270 for (unsigned int i = 0; i < count; i++) 2271 { 2272 if ((unsigned int) abs (buf_pos->x_advance - ref_pos->x_advance) > position_fuzz || 2273 (unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz || 2274 (unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz || 2275 (unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz) 2276 { 2277 result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH; 2278 break; 2279 } 2280 buf_pos++; 2281 ref_pos++; 2282 } 2283 } 2284 2285 return result; 2286 } 2287 2288 2289 /* 2290 * Debugging. 2291 */ 2292 2293 #ifndef HB_NO_BUFFER_MESSAGE 2294 /** 2295 * hb_buffer_set_message_func: 2296 * @buffer: An #hb_buffer_t 2297 * @func: (closure user_data) (destroy destroy) (scope notified): Callback function 2298 * @user_data: (nullable): Data to pass to @func 2299 * @destroy: (nullable): The function to call when @user_data is not needed anymore 2300 * 2301 * Sets the implementation function for #hb_buffer_message_func_t. 2302 * 2303 * Since: 1.1.3 2304 **/ 2305 void 2306 hb_buffer_set_message_func (hb_buffer_t *buffer, 2307 hb_buffer_message_func_t func, 2308 void *user_data, hb_destroy_func_t destroy) 2309 { 2310 if (unlikely (hb_object_is_immutable (buffer))) 2311 { 2312 if (destroy) 2313 destroy (user_data); 2314 return; 2315 } 2316 2317 if (buffer->message_destroy) 2318 buffer->message_destroy (buffer->message_data); 2319 2320 if (func) { 2321 buffer->message_func = func; 2322 buffer->message_data = user_data; 2323 buffer->message_destroy = destroy; 2324 } else { 2325 buffer->message_func = nullptr; 2326 buffer->message_data = nullptr; 2327 buffer->message_destroy = nullptr; 2328 } 2329 } 2330 bool 2331 hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap) 2332 { 2333 assert (!have_output || (out_info == info && out_len == idx)); 2334 2335 message_depth++; 2336 2337 char buf[100]; 2338 vsnprintf (buf, sizeof (buf), fmt, ap); 2339 bool ret = (bool) this->message_func (this, font, buf, this->message_data); 2340 2341 message_depth--; 2342 2343 return ret; 2344 } 2345 #endif