Add ICU message format support
[chromium-blink-merge.git] / third_party / harfbuzz-ng / src / hb-buffer.cc
blob03fe8e1348b8cdc8909dd9f419fab31ceb4ae8a2
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.
6 * This is part of HarfBuzz, a text shaping library.
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.
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.
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.
26 * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
27 * Google Author(s): Behdad Esfahbod
30 #include "hb-buffer-private.hh"
31 #include "hb-utf-private.hh"
34 #ifndef HB_DEBUG_BUFFER
35 #define HB_DEBUG_BUFFER (HB_DEBUG+0)
36 #endif
39 /**
40 * Since: 0.9.7
41 **/
42 hb_bool_t
43 hb_segment_properties_equal (const hb_segment_properties_t *a,
44 const hb_segment_properties_t *b)
46 return a->direction == b->direction &&
47 a->script == b->script &&
48 a->language == b->language &&
49 a->reserved1 == b->reserved1 &&
50 a->reserved2 == b->reserved2;
54 /**
55 * Since: 0.9.7
56 **/
57 unsigned int
58 hb_segment_properties_hash (const hb_segment_properties_t *p)
60 return (unsigned int) p->direction ^
61 (unsigned int) p->script ^
62 (intptr_t) (p->language);
67 /* Here is how the buffer works internally:
69 * There are two info pointers: info and out_info. They always have
70 * the same allocated size, but different lengths.
72 * As an optimization, both info and out_info may point to the
73 * same piece of memory, which is owned by info. This remains the
74 * case as long as out_len doesn't exceed i at any time.
75 * In that case, swap_buffers() is no-op and the glyph operations operate
76 * mostly in-place.
78 * As soon as out_info gets longer than info, out_info is moved over
79 * to an alternate buffer (which we reuse the pos buffer for!), and its
80 * current contents (out_len entries) are copied to the new place.
81 * This should all remain transparent to the user. swap_buffers() then
82 * switches info and out_info.
87 /* Internal API */
89 bool
90 hb_buffer_t::enlarge (unsigned int size)
92 if (unlikely (in_error))
93 return false;
95 unsigned int new_allocated = allocated;
96 hb_glyph_position_t *new_pos = NULL;
97 hb_glyph_info_t *new_info = NULL;
98 bool separate_out = out_info != info;
100 if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
101 goto done;
103 while (size >= new_allocated)
104 new_allocated += (new_allocated >> 1) + 32;
106 ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
107 if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
108 goto done;
110 new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
111 new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
113 done:
114 if (unlikely (!new_pos || !new_info))
115 in_error = true;
117 if (likely (new_pos))
118 pos = new_pos;
120 if (likely (new_info))
121 info = new_info;
123 out_info = separate_out ? (hb_glyph_info_t *) pos : info;
124 if (likely (!in_error))
125 allocated = new_allocated;
127 return likely (!in_error);
130 bool
131 hb_buffer_t::make_room_for (unsigned int num_in,
132 unsigned int num_out)
134 if (unlikely (!ensure (out_len + num_out))) return false;
136 if (out_info == info &&
137 out_len + num_out > idx + num_in)
139 assert (have_output);
141 out_info = (hb_glyph_info_t *) pos;
142 memcpy (out_info, info, out_len * sizeof (out_info[0]));
145 return true;
148 bool
149 hb_buffer_t::shift_forward (unsigned int count)
151 assert (have_output);
152 if (unlikely (!ensure (len + count))) return false;
154 memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));
155 len += count;
156 idx += count;
158 return true;
161 hb_buffer_t::scratch_buffer_t *
162 hb_buffer_t::get_scratch_buffer (unsigned int *size)
164 have_output = false;
165 have_positions = false;
167 out_len = 0;
168 out_info = info;
170 assert ((uintptr_t) pos % sizeof (scratch_buffer_t) == 0);
171 *size = allocated * sizeof (pos[0]) / sizeof (scratch_buffer_t);
172 return (scratch_buffer_t *) (void *) pos;
177 /* HarfBuzz-Internal API */
179 void
180 hb_buffer_t::reset (void)
182 if (unlikely (hb_object_is_inert (this)))
183 return;
185 hb_unicode_funcs_destroy (unicode);
186 unicode = hb_unicode_funcs_get_default ();
187 flags = HB_BUFFER_FLAG_DEFAULT;
188 replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
190 clear ();
193 void
194 hb_buffer_t::clear (void)
196 if (unlikely (hb_object_is_inert (this)))
197 return;
199 hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
200 props = default_props;
202 content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
203 in_error = false;
204 have_output = false;
205 have_positions = false;
207 idx = 0;
208 len = 0;
209 out_len = 0;
210 out_info = info;
212 serial = 0;
213 memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
214 memset (allocated_var_owner, 0, sizeof allocated_var_owner);
216 memset (context, 0, sizeof context);
217 memset (context_len, 0, sizeof context_len);
220 void
221 hb_buffer_t::add (hb_codepoint_t codepoint,
222 unsigned int cluster)
224 hb_glyph_info_t *glyph;
226 if (unlikely (!ensure (len + 1))) return;
228 glyph = &info[len];
230 memset (glyph, 0, sizeof (*glyph));
231 glyph->codepoint = codepoint;
232 glyph->mask = 1;
233 glyph->cluster = cluster;
235 len++;
238 void
239 hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
241 if (unlikely (!ensure (len + 1))) return;
243 info[len] = glyph_info;
245 len++;
249 void
250 hb_buffer_t::remove_output (void)
252 if (unlikely (hb_object_is_inert (this)))
253 return;
255 have_output = false;
256 have_positions = false;
258 out_len = 0;
259 out_info = info;
262 void
263 hb_buffer_t::clear_output (void)
265 if (unlikely (hb_object_is_inert (this)))
266 return;
268 have_output = true;
269 have_positions = false;
271 out_len = 0;
272 out_info = info;
275 void
276 hb_buffer_t::clear_positions (void)
278 if (unlikely (hb_object_is_inert (this)))
279 return;
281 have_output = false;
282 have_positions = true;
284 out_len = 0;
285 out_info = info;
287 memset (pos, 0, sizeof (pos[0]) * len);
290 void
291 hb_buffer_t::swap_buffers (void)
293 if (unlikely (in_error)) return;
295 assert (have_output);
296 have_output = false;
298 if (out_info != info)
300 hb_glyph_info_t *tmp_string;
301 tmp_string = info;
302 info = out_info;
303 out_info = tmp_string;
304 pos = (hb_glyph_position_t *) out_info;
307 unsigned int tmp;
308 tmp = len;
309 len = out_len;
310 out_len = tmp;
312 idx = 0;
316 void
317 hb_buffer_t::replace_glyphs (unsigned int num_in,
318 unsigned int num_out,
319 const uint32_t *glyph_data)
321 if (unlikely (!make_room_for (num_in, num_out))) return;
323 merge_clusters (idx, idx + num_in);
325 hb_glyph_info_t orig_info = info[idx];
326 hb_glyph_info_t *pinfo = &out_info[out_len];
327 for (unsigned int i = 0; i < num_out; i++)
329 *pinfo = orig_info;
330 pinfo->codepoint = glyph_data[i];
331 pinfo++;
334 idx += num_in;
335 out_len += num_out;
338 void
339 hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
341 if (unlikely (!make_room_for (0, 1))) return;
343 out_info[out_len] = info[idx];
344 out_info[out_len].codepoint = glyph_index;
346 out_len++;
349 void
350 hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info)
352 if (unlikely (!make_room_for (0, 1))) return;
354 out_info[out_len] = glyph_info;
356 out_len++;
359 void
360 hb_buffer_t::copy_glyph (void)
362 if (unlikely (!make_room_for (0, 1))) return;
364 out_info[out_len] = info[idx];
366 out_len++;
369 bool
370 hb_buffer_t::move_to (unsigned int i)
372 if (!have_output)
374 assert (i <= len);
375 idx = i;
376 return true;
379 assert (i <= out_len + (len - idx));
381 if (out_len < i)
383 unsigned int count = i - out_len;
384 if (unlikely (!make_room_for (count, count))) return false;
386 memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));
387 idx += count;
388 out_len += count;
390 else if (out_len > i)
392 /* Tricky part: rewinding... */
393 unsigned int count = out_len - i;
395 if (unlikely (idx < count && !shift_forward (count + 32))) return false;
397 assert (idx >= count);
399 idx -= count;
400 out_len -= count;
401 memmove (info + idx, out_info + out_len, count * sizeof (out_info[0]));
404 return true;
407 void
408 hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
410 if (unlikely (out_info != info || out_len != idx)) {
411 if (unlikely (!make_room_for (1, 1))) return;
412 out_info[out_len] = info[idx];
414 out_info[out_len].codepoint = glyph_index;
416 idx++;
417 out_len++;
421 void
422 hb_buffer_t::set_masks (hb_mask_t value,
423 hb_mask_t mask,
424 unsigned int cluster_start,
425 unsigned int cluster_end)
427 hb_mask_t not_mask = ~mask;
428 value &= mask;
430 if (!mask)
431 return;
433 if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
434 unsigned int count = len;
435 for (unsigned int i = 0; i < count; i++)
436 info[i].mask = (info[i].mask & not_mask) | value;
437 return;
440 unsigned int count = len;
441 for (unsigned int i = 0; i < count; i++)
442 if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
443 info[i].mask = (info[i].mask & not_mask) | value;
446 void
447 hb_buffer_t::reverse_range (unsigned int start,
448 unsigned int end)
450 unsigned int i, j;
452 if (end - start < 2)
453 return;
455 for (i = start, j = end - 1; i < j; i++, j--) {
456 hb_glyph_info_t t;
458 t = info[i];
459 info[i] = info[j];
460 info[j] = t;
463 if (have_positions) {
464 for (i = start, j = end - 1; i < j; i++, j--) {
465 hb_glyph_position_t t;
467 t = pos[i];
468 pos[i] = pos[j];
469 pos[j] = t;
474 void
475 hb_buffer_t::reverse (void)
477 if (unlikely (!len))
478 return;
480 reverse_range (0, len);
483 void
484 hb_buffer_t::reverse_clusters (void)
486 unsigned int i, start, count, last_cluster;
488 if (unlikely (!len))
489 return;
491 reverse ();
493 count = len;
494 start = 0;
495 last_cluster = info[0].cluster;
496 for (i = 1; i < count; i++) {
497 if (last_cluster != info[i].cluster) {
498 reverse_range (start, i);
499 start = i;
500 last_cluster = info[i].cluster;
503 reverse_range (start, i);
506 void
507 hb_buffer_t::merge_clusters_impl (unsigned int start,
508 unsigned int end)
510 if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
511 return;
513 unsigned int cluster = info[start].cluster;
515 for (unsigned int i = start + 1; i < end; i++)
516 cluster = MIN (cluster, info[i].cluster);
518 /* Extend end */
519 while (end < len && info[end - 1].cluster == info[end].cluster)
520 end++;
522 /* Extend start */
523 while (idx < start && info[start - 1].cluster == info[start].cluster)
524 start--;
526 /* If we hit the start of buffer, continue in out-buffer. */
527 if (idx == start)
528 for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
529 out_info[i - 1].cluster = cluster;
531 for (unsigned int i = start; i < end; i++)
532 info[i].cluster = cluster;
534 void
535 hb_buffer_t::merge_out_clusters (unsigned int start,
536 unsigned int end)
538 if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
539 return;
541 if (unlikely (end - start < 2))
542 return;
544 unsigned int cluster = out_info[start].cluster;
546 for (unsigned int i = start + 1; i < end; i++)
547 cluster = MIN (cluster, out_info[i].cluster);
549 /* Extend start */
550 while (start && out_info[start - 1].cluster == out_info[start].cluster)
551 start--;
553 /* Extend end */
554 while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)
555 end++;
557 /* If we hit the end of out-buffer, continue in buffer. */
558 if (end == out_len)
559 for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
560 info[i].cluster = cluster;
562 for (unsigned int i = start; i < end; i++)
563 out_info[i].cluster = cluster;
565 void
566 hb_buffer_t::delete_glyph ()
568 unsigned int cluster = info[idx].cluster;
569 if (idx + 1 < len && cluster == info[idx + 1].cluster)
571 /* Cluster survives; do nothing. */
572 goto done;
575 if (out_len)
577 /* Merge cluster backward. */
578 if (cluster < out_info[out_len - 1].cluster)
580 unsigned int old_cluster = out_info[out_len - 1].cluster;
581 for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--)
582 out_info[i - 1].cluster = cluster;
584 goto done;
587 if (idx + 1 < len)
589 /* Merge cluster forward. */
590 merge_clusters (idx, idx + 2);
591 goto done;
594 done:
595 skip_glyph ();
598 void
599 hb_buffer_t::guess_segment_properties (void)
601 assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
602 (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
604 /* If script is set to INVALID, guess from buffer contents */
605 if (props.script == HB_SCRIPT_INVALID) {
606 for (unsigned int i = 0; i < len; i++) {
607 hb_script_t script = unicode->script (info[i].codepoint);
608 if (likely (script != HB_SCRIPT_COMMON &&
609 script != HB_SCRIPT_INHERITED &&
610 script != HB_SCRIPT_UNKNOWN)) {
611 props.script = script;
612 break;
617 /* If direction is set to INVALID, guess from script */
618 if (props.direction == HB_DIRECTION_INVALID) {
619 props.direction = hb_script_get_horizontal_direction (props.script);
622 /* If language is not set, use default language from locale */
623 if (props.language == HB_LANGUAGE_INVALID) {
624 /* TODO get_default_for_script? using $LANGUAGE */
625 props.language = hb_language_get_default ();
630 static inline void
631 dump_var_allocation (const hb_buffer_t *buffer)
633 char buf[80];
634 for (unsigned int i = 0; i < 8; i++)
635 buf[i] = '0' + buffer->allocated_var_bytes[7 - i];
636 buf[8] = '\0';
637 DEBUG_MSG (BUFFER, buffer,
638 "Current var allocation: %s",
639 buf);
642 void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner)
644 assert (byte_i < 8 && byte_i + count <= 8);
646 if (DEBUG_ENABLED (BUFFER))
647 dump_var_allocation (this);
648 DEBUG_MSG (BUFFER, this,
649 "Allocating var bytes %d..%d for %s",
650 byte_i, byte_i + count - 1, owner);
652 for (unsigned int i = byte_i; i < byte_i + count; i++) {
653 assert (!allocated_var_bytes[i]);
654 allocated_var_bytes[i]++;
655 allocated_var_owner[i] = owner;
659 void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
661 if (DEBUG_ENABLED (BUFFER))
662 dump_var_allocation (this);
664 DEBUG_MSG (BUFFER, this,
665 "Deallocating var bytes %d..%d for %s",
666 byte_i, byte_i + count - 1, owner);
668 assert (byte_i < 8 && byte_i + count <= 8);
669 for (unsigned int i = byte_i; i < byte_i + count; i++) {
670 assert (allocated_var_bytes[i]);
671 assert (0 == strcmp (allocated_var_owner[i], owner));
672 allocated_var_bytes[i]--;
676 void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner)
678 if (DEBUG_ENABLED (BUFFER))
679 dump_var_allocation (this);
681 DEBUG_MSG (BUFFER, this,
682 "Asserting var bytes %d..%d for %s",
683 byte_i, byte_i + count - 1, owner);
685 assert (byte_i < 8 && byte_i + count <= 8);
686 for (unsigned int i = byte_i; i < byte_i + count; i++) {
687 assert (allocated_var_bytes[i]);
688 assert (0 == strcmp (allocated_var_owner[i], owner));
692 void hb_buffer_t::deallocate_var_all (void)
694 memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
695 memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
698 /* Public API */
701 * hb_buffer_create: (Xconstructor)
705 * Return value: (transfer full)
707 * Since: 1.0
709 hb_buffer_t *
710 hb_buffer_create (void)
712 hb_buffer_t *buffer;
714 if (!(buffer = hb_object_create<hb_buffer_t> ()))
715 return hb_buffer_get_empty ();
717 buffer->reset ();
719 return buffer;
723 * hb_buffer_get_empty:
727 * Return value: (transfer full):
729 * Since: 1.0
731 hb_buffer_t *
732 hb_buffer_get_empty (void)
734 static const hb_buffer_t _hb_buffer_nil = {
735 HB_OBJECT_HEADER_STATIC,
737 const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
738 HB_BUFFER_FLAG_DEFAULT,
739 HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
740 HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
742 HB_BUFFER_CONTENT_TYPE_INVALID,
743 HB_SEGMENT_PROPERTIES_DEFAULT,
744 true, /* in_error */
745 true, /* have_output */
746 true /* have_positions */
748 /* Zero is good enough for everything else. */
751 return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
755 * hb_buffer_reference: (skip)
756 * @buffer: a buffer.
760 * Return value: (transfer full):
762 * Since: 1.0
764 hb_buffer_t *
765 hb_buffer_reference (hb_buffer_t *buffer)
767 return hb_object_reference (buffer);
771 * hb_buffer_destroy: (skip)
772 * @buffer: a buffer.
776 * Since: 1.0
778 void
779 hb_buffer_destroy (hb_buffer_t *buffer)
781 if (!hb_object_destroy (buffer)) return;
783 hb_unicode_funcs_destroy (buffer->unicode);
785 free (buffer->info);
786 free (buffer->pos);
788 free (buffer);
792 * hb_buffer_set_user_data: (skip)
793 * @buffer: a buffer.
794 * @key:
795 * @data:
796 * @destroy:
797 * @replace:
801 * Return value:
803 * Since: 1.0
805 hb_bool_t
806 hb_buffer_set_user_data (hb_buffer_t *buffer,
807 hb_user_data_key_t *key,
808 void * data,
809 hb_destroy_func_t destroy,
810 hb_bool_t replace)
812 return hb_object_set_user_data (buffer, key, data, destroy, replace);
816 * hb_buffer_get_user_data: (skip)
817 * @buffer: a buffer.
818 * @key:
822 * Return value:
824 * Since: 1.0
826 void *
827 hb_buffer_get_user_data (hb_buffer_t *buffer,
828 hb_user_data_key_t *key)
830 return hb_object_get_user_data (buffer, key);
835 * hb_buffer_set_content_type:
836 * @buffer: a buffer.
837 * @content_type:
841 * Since: 0.9.5
843 void
844 hb_buffer_set_content_type (hb_buffer_t *buffer,
845 hb_buffer_content_type_t content_type)
847 buffer->content_type = content_type;
851 * hb_buffer_get_content_type:
852 * @buffer: a buffer.
856 * Return value:
858 * Since: 0.9.5
860 hb_buffer_content_type_t
861 hb_buffer_get_content_type (hb_buffer_t *buffer)
863 return buffer->content_type;
868 * hb_buffer_set_unicode_funcs:
869 * @buffer: a buffer.
870 * @unicode_funcs:
874 * Since: 1.0
876 void
877 hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
878 hb_unicode_funcs_t *unicode_funcs)
880 if (unlikely (hb_object_is_inert (buffer)))
881 return;
883 if (!unicode_funcs)
884 unicode_funcs = hb_unicode_funcs_get_default ();
887 hb_unicode_funcs_reference (unicode_funcs);
888 hb_unicode_funcs_destroy (buffer->unicode);
889 buffer->unicode = unicode_funcs;
893 * hb_buffer_get_unicode_funcs:
894 * @buffer: a buffer.
898 * Return value:
900 * Since: 1.0
902 hb_unicode_funcs_t *
903 hb_buffer_get_unicode_funcs (hb_buffer_t *buffer)
905 return buffer->unicode;
909 * hb_buffer_set_direction:
910 * @buffer: a buffer.
911 * @direction:
915 * Since: 1.0
917 void
918 hb_buffer_set_direction (hb_buffer_t *buffer,
919 hb_direction_t direction)
922 if (unlikely (hb_object_is_inert (buffer)))
923 return;
925 buffer->props.direction = direction;
929 * hb_buffer_get_direction:
930 * @buffer: a buffer.
934 * Return value:
936 * Since: 1.0
938 hb_direction_t
939 hb_buffer_get_direction (hb_buffer_t *buffer)
941 return buffer->props.direction;
945 * hb_buffer_set_script:
946 * @buffer: a buffer.
947 * @script:
951 * Since: 1.0
953 void
954 hb_buffer_set_script (hb_buffer_t *buffer,
955 hb_script_t script)
957 if (unlikely (hb_object_is_inert (buffer)))
958 return;
960 buffer->props.script = script;
964 * hb_buffer_get_script:
965 * @buffer: a buffer.
969 * Return value:
971 * Since: 1.0
973 hb_script_t
974 hb_buffer_get_script (hb_buffer_t *buffer)
976 return buffer->props.script;
980 * hb_buffer_set_language:
981 * @buffer: a buffer.
982 * @language:
986 * Since: 1.0
988 void
989 hb_buffer_set_language (hb_buffer_t *buffer,
990 hb_language_t language)
992 if (unlikely (hb_object_is_inert (buffer)))
993 return;
995 buffer->props.language = language;
999 * hb_buffer_get_language:
1000 * @buffer: a buffer.
1004 * Return value: (transfer none):
1006 * Since: 1.0
1008 hb_language_t
1009 hb_buffer_get_language (hb_buffer_t *buffer)
1011 return buffer->props.language;
1015 * hb_buffer_set_segment_properties:
1016 * @buffer: a buffer.
1017 * @props:
1021 * Since: 0.9.7
1023 void
1024 hb_buffer_set_segment_properties (hb_buffer_t *buffer,
1025 const hb_segment_properties_t *props)
1027 if (unlikely (hb_object_is_inert (buffer)))
1028 return;
1030 buffer->props = *props;
1034 * hb_buffer_get_segment_properties:
1035 * @buffer: a buffer.
1036 * @props: (out):
1040 * Since: 0.9.7
1042 void
1043 hb_buffer_get_segment_properties (hb_buffer_t *buffer,
1044 hb_segment_properties_t *props)
1046 *props = buffer->props;
1051 * hb_buffer_set_flags:
1052 * @buffer: a buffer.
1053 * @flags:
1057 * Since: 0.9.7
1059 void
1060 hb_buffer_set_flags (hb_buffer_t *buffer,
1061 hb_buffer_flags_t flags)
1063 if (unlikely (hb_object_is_inert (buffer)))
1064 return;
1066 buffer->flags = flags;
1070 * hb_buffer_get_flags:
1071 * @buffer: a buffer.
1075 * Return value:
1077 * Since: 0.9.7
1079 hb_buffer_flags_t
1080 hb_buffer_get_flags (hb_buffer_t *buffer)
1082 return buffer->flags;
1086 * hb_buffer_set_cluster_level:
1087 * @buffer: a buffer.
1088 * @cluster_level:
1092 * Since: 0.9.42
1094 void
1095 hb_buffer_set_cluster_level (hb_buffer_t *buffer,
1096 hb_buffer_cluster_level_t cluster_level)
1098 if (unlikely (hb_object_is_inert (buffer)))
1099 return;
1101 buffer->cluster_level = cluster_level;
1105 * hb_buffer_get_cluster_level:
1106 * @buffer: a buffer.
1110 * Return value:
1112 * Since: 0.9.42
1114 hb_buffer_cluster_level_t
1115 hb_buffer_get_cluster_level (hb_buffer_t *buffer)
1117 return buffer->cluster_level;
1122 * hb_buffer_set_replacement_codepoint:
1123 * @buffer: a buffer.
1124 * @replacement:
1128 * Since: 0.9.31
1130 void
1131 hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
1132 hb_codepoint_t replacement)
1134 if (unlikely (hb_object_is_inert (buffer)))
1135 return;
1137 buffer->replacement = replacement;
1141 * hb_buffer_get_replacement_codepoint:
1142 * @buffer: a buffer.
1146 * Return value:
1148 * Since: 0.9.31
1150 hb_codepoint_t
1151 hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer)
1153 return buffer->replacement;
1158 * hb_buffer_reset:
1159 * @buffer: a buffer.
1163 * Since: 1.0
1165 void
1166 hb_buffer_reset (hb_buffer_t *buffer)
1168 buffer->reset ();
1172 * hb_buffer_clear_contents:
1173 * @buffer: a buffer.
1177 * Since: 0.9.11
1179 void
1180 hb_buffer_clear_contents (hb_buffer_t *buffer)
1182 buffer->clear ();
1186 * hb_buffer_pre_allocate:
1187 * @buffer: a buffer.
1188 * @size:
1192 * Return value:
1194 * Since: 1.0
1196 hb_bool_t
1197 hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
1199 return buffer->ensure (size);
1203 * hb_buffer_allocation_successful:
1204 * @buffer: a buffer.
1208 * Return value:
1210 * Since: 1.0
1212 hb_bool_t
1213 hb_buffer_allocation_successful (hb_buffer_t *buffer)
1215 return !buffer->in_error;
1219 * hb_buffer_add:
1220 * @buffer: a buffer.
1221 * @codepoint:
1222 * @cluster:
1226 * Since: 1.0
1228 void
1229 hb_buffer_add (hb_buffer_t *buffer,
1230 hb_codepoint_t codepoint,
1231 unsigned int cluster)
1233 buffer->add (codepoint, cluster);
1234 buffer->clear_context (1);
1238 * hb_buffer_set_length:
1239 * @buffer: a buffer.
1240 * @length:
1244 * Return value:
1246 * Since: 1.0
1248 hb_bool_t
1249 hb_buffer_set_length (hb_buffer_t *buffer,
1250 unsigned int length)
1252 if (unlikely (hb_object_is_inert (buffer)))
1253 return length == 0;
1255 if (!buffer->ensure (length))
1256 return false;
1258 /* Wipe the new space */
1259 if (length > buffer->len) {
1260 memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
1261 if (buffer->have_positions)
1262 memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
1265 buffer->len = length;
1267 if (!length)
1269 buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
1270 buffer->clear_context (0);
1272 buffer->clear_context (1);
1274 return true;
1278 * hb_buffer_get_length:
1279 * @buffer: a buffer.
1281 * Returns the number of items in the buffer.
1283 * Return value: buffer length.
1285 * Since: 1.0
1287 unsigned int
1288 hb_buffer_get_length (hb_buffer_t *buffer)
1290 return buffer->len;
1294 * hb_buffer_get_glyph_infos:
1295 * @buffer: a buffer.
1296 * @length: (out): output array length.
1298 * Returns buffer glyph information array. Returned pointer
1299 * is valid as long as buffer contents are not modified.
1301 * Return value: (transfer none) (array length=length): buffer glyph information array.
1303 * Since: 1.0
1305 hb_glyph_info_t *
1306 hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
1307 unsigned int *length)
1309 if (length)
1310 *length = buffer->len;
1312 return (hb_glyph_info_t *) buffer->info;
1316 * hb_buffer_get_glyph_positions:
1317 * @buffer: a buffer.
1318 * @length: (out): output length.
1320 * Returns buffer glyph position array. Returned pointer
1321 * is valid as long as buffer contents are not modified.
1323 * Return value: (transfer none) (array length=length): buffer glyph position array.
1325 * Since: 1.0
1327 hb_glyph_position_t *
1328 hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
1329 unsigned int *length)
1331 if (!buffer->have_positions)
1332 buffer->clear_positions ();
1334 if (length)
1335 *length = buffer->len;
1337 return (hb_glyph_position_t *) buffer->pos;
1341 * hb_buffer_reverse:
1342 * @buffer: a buffer.
1344 * Reverses buffer contents.
1346 * Since: 1.0
1348 void
1349 hb_buffer_reverse (hb_buffer_t *buffer)
1351 buffer->reverse ();
1355 * hb_buffer_reverse_range:
1356 * @buffer: a buffer.
1357 * @start: start index.
1358 * @end: end index.
1360 * Reverses buffer contents between start to end.
1362 * Since: 1.0
1364 void
1365 hb_buffer_reverse_range (hb_buffer_t *buffer,
1366 unsigned int start, unsigned int end)
1368 buffer->reverse_range (start, end);
1372 * hb_buffer_reverse_clusters:
1373 * @buffer: a buffer.
1375 * Reverses buffer clusters. That is, the buffer contents are
1376 * reversed, then each cluster (consecutive items having the
1377 * same cluster number) are reversed again.
1379 * Since: 1.0
1381 void
1382 hb_buffer_reverse_clusters (hb_buffer_t *buffer)
1384 buffer->reverse_clusters ();
1388 * hb_buffer_guess_segment_properties:
1389 * @buffer: a buffer.
1391 * Sets unset buffer segment properties based on buffer Unicode
1392 * contents. If buffer is not empty, it must have content type
1393 * %HB_BUFFER_CONTENT_TYPE_UNICODE.
1395 * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
1396 * will be set to the Unicode script of the first character in
1397 * the buffer that has a script other than %HB_SCRIPT_COMMON,
1398 * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
1400 * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
1401 * it will be set to the natural horizontal direction of the
1402 * buffer script as returned by hb_script_get_horizontal_direction().
1404 * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
1405 * it will be set to the process's default language as returned by
1406 * hb_language_get_default(). This may change in the future by
1407 * taking buffer script into consideration when choosing a language.
1409 * Since: 0.9.7
1411 void
1412 hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
1414 buffer->guess_segment_properties ();
1417 template <typename utf_t>
1418 static inline void
1419 hb_buffer_add_utf (hb_buffer_t *buffer,
1420 const typename utf_t::codepoint_t *text,
1421 int text_length,
1422 unsigned int item_offset,
1423 int item_length)
1425 typedef typename utf_t::codepoint_t T;
1426 const hb_codepoint_t replacement = buffer->replacement;
1428 assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
1429 (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
1431 if (unlikely (hb_object_is_inert (buffer)))
1432 return;
1434 if (text_length == -1)
1435 text_length = utf_t::strlen (text);
1437 if (item_length == -1)
1438 item_length = text_length - item_offset;
1440 buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
1442 /* If buffer is empty and pre-context provided, install it.
1443 * This check is written this way, to make sure people can
1444 * provide pre-context in one add_utf() call, then provide
1445 * text in a follow-up call. See:
1447 * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
1449 if (!buffer->len && item_offset > 0)
1451 /* Add pre-context */
1452 buffer->clear_context (0);
1453 const T *prev = text + item_offset;
1454 const T *start = text;
1455 while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
1457 hb_codepoint_t u;
1458 prev = utf_t::prev (prev, start, &u, replacement);
1459 buffer->context[0][buffer->context_len[0]++] = u;
1463 const T *next = text + item_offset;
1464 const T *end = next + item_length;
1465 while (next < end)
1467 hb_codepoint_t u;
1468 const T *old_next = next;
1469 next = utf_t::next (next, end, &u, replacement);
1470 buffer->add (u, old_next - (const T *) text);
1473 /* Add post-context */
1474 buffer->clear_context (1);
1475 end = text + text_length;
1476 while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
1478 hb_codepoint_t u;
1479 next = utf_t::next (next, end, &u, replacement);
1480 buffer->context[1][buffer->context_len[1]++] = u;
1483 buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
1487 * hb_buffer_add_utf8:
1488 * @buffer: a buffer.
1489 * @text: (array length=text_length) (element-type uint8_t):
1490 * @text_length:
1491 * @item_offset:
1492 * @item_length:
1496 * Since: 1.0
1498 void
1499 hb_buffer_add_utf8 (hb_buffer_t *buffer,
1500 const char *text,
1501 int text_length,
1502 unsigned int item_offset,
1503 int item_length)
1505 hb_buffer_add_utf<hb_utf8_t> (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
1509 * hb_buffer_add_utf16:
1510 * @buffer: a buffer.
1511 * @text: (array length=text_length):
1512 * @text_length:
1513 * @item_offset:
1514 * @item_length:
1518 * Since: 1.0
1520 void
1521 hb_buffer_add_utf16 (hb_buffer_t *buffer,
1522 const uint16_t *text,
1523 int text_length,
1524 unsigned int item_offset,
1525 int item_length)
1527 hb_buffer_add_utf<hb_utf16_t> (buffer, text, text_length, item_offset, item_length);
1531 * hb_buffer_add_utf32:
1532 * @buffer: a buffer.
1533 * @text: (array length=text_length):
1534 * @text_length:
1535 * @item_offset:
1536 * @item_length:
1540 * Since: 1.0
1542 void
1543 hb_buffer_add_utf32 (hb_buffer_t *buffer,
1544 const uint32_t *text,
1545 int text_length,
1546 unsigned int item_offset,
1547 int item_length)
1549 hb_buffer_add_utf<hb_utf32_t<> > (buffer, text, text_length, item_offset, item_length);
1553 * hb_buffer_add_latin1:
1554 * @buffer: a buffer.
1555 * @text: (array length=text_length) (element-type uint8_t):
1556 * @text_length:
1557 * @item_offset:
1558 * @item_length:
1562 * Since: 0.9.39
1564 void
1565 hb_buffer_add_latin1 (hb_buffer_t *buffer,
1566 const uint8_t *text,
1567 int text_length,
1568 unsigned int item_offset,
1569 int item_length)
1571 hb_buffer_add_utf<hb_latin1_t> (buffer, text, text_length, item_offset, item_length);
1575 * hb_buffer_add_codepoints:
1576 * @buffer: a buffer.
1577 * @text: (array length=text_length):
1578 * @text_length:
1579 * @item_offset:
1580 * @item_length:
1584 * Since: 0.9.31
1586 void
1587 hb_buffer_add_codepoints (hb_buffer_t *buffer,
1588 const hb_codepoint_t *text,
1589 int text_length,
1590 unsigned int item_offset,
1591 int item_length)
1593 hb_buffer_add_utf<hb_utf32_t<false> > (buffer, text, text_length, item_offset, item_length);
1597 static int
1598 compare_info_codepoint (const hb_glyph_info_t *pa,
1599 const hb_glyph_info_t *pb)
1601 return (int) pb->codepoint - (int) pa->codepoint;
1604 static inline void
1605 normalize_glyphs_cluster (hb_buffer_t *buffer,
1606 unsigned int start,
1607 unsigned int end,
1608 bool backward)
1610 hb_glyph_position_t *pos = buffer->pos;
1612 /* Total cluster advance */
1613 hb_position_t total_x_advance = 0, total_y_advance = 0;
1614 for (unsigned int i = start; i < end; i++)
1616 total_x_advance += pos[i].x_advance;
1617 total_y_advance += pos[i].y_advance;
1620 hb_position_t x_advance = 0, y_advance = 0;
1621 for (unsigned int i = start; i < end; i++)
1623 pos[i].x_offset += x_advance;
1624 pos[i].y_offset += y_advance;
1626 x_advance += pos[i].x_advance;
1627 y_advance += pos[i].y_advance;
1629 pos[i].x_advance = 0;
1630 pos[i].y_advance = 0;
1633 if (backward)
1635 /* Transfer all cluster advance to the last glyph. */
1636 pos[end - 1].x_advance = total_x_advance;
1637 pos[end - 1].y_advance = total_y_advance;
1639 hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
1640 } else {
1641 /* Transfer all cluster advance to the first glyph. */
1642 pos[start].x_advance += total_x_advance;
1643 pos[start].y_advance += total_y_advance;
1644 for (unsigned int i = start + 1; i < end; i++) {
1645 pos[i].x_offset -= total_x_advance;
1646 pos[i].y_offset -= total_y_advance;
1648 hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
1653 * hb_buffer_normalize_glyphs:
1654 * @buffer: a buffer.
1658 * Since: 0.9.2
1660 void
1661 hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
1663 assert (buffer->have_positions);
1664 assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
1666 bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
1668 unsigned int count = buffer->len;
1669 if (unlikely (!count)) return;
1670 hb_glyph_info_t *info = buffer->info;
1672 unsigned int start = 0;
1673 unsigned int end;
1674 for (end = start + 1; end < count; end++)
1675 if (info[start].cluster != info[end].cluster) {
1676 normalize_glyphs_cluster (buffer, start, end, backward);
1677 start = end;
1679 normalize_glyphs_cluster (buffer, start, end, backward);