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