xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-buffer.cc (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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