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