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