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