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
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)
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
;
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
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.
90 hb_buffer_t::enlarge (unsigned int size
)
92 if (unlikely (in_error
))
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]))))
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]))))
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]));
114 if (unlikely (!new_pos
|| !new_info
))
117 if (likely (new_pos
))
120 if (likely (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
);
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]));
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]));
161 hb_buffer_t::scratch_buffer_t
*
162 hb_buffer_t::get_scratch_buffer (unsigned int *size
)
165 have_positions
= false;
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 */
180 hb_buffer_t::reset (void)
182 if (unlikely (hb_object_is_inert (this)))
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
;
194 hb_buffer_t::clear (void)
196 if (unlikely (hb_object_is_inert (this)))
199 hb_segment_properties_t default_props
= HB_SEGMENT_PROPERTIES_DEFAULT
;
200 props
= default_props
;
202 content_type
= HB_BUFFER_CONTENT_TYPE_INVALID
;
205 have_positions
= false;
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
);
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;
230 memset (glyph
, 0, sizeof (*glyph
));
231 glyph
->codepoint
= codepoint
;
233 glyph
->cluster
= cluster
;
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
;
250 hb_buffer_t::remove_output (void)
252 if (unlikely (hb_object_is_inert (this)))
256 have_positions
= false;
263 hb_buffer_t::clear_output (void)
265 if (unlikely (hb_object_is_inert (this)))
269 have_positions
= false;
276 hb_buffer_t::clear_positions (void)
278 if (unlikely (hb_object_is_inert (this)))
282 have_positions
= true;
287 memset (pos
, 0, sizeof (pos
[0]) * len
);
291 hb_buffer_t::swap_buffers (void)
293 if (unlikely (in_error
)) return;
295 assert (have_output
);
298 if (out_info
!= info
)
300 hb_glyph_info_t
*tmp_string
;
303 out_info
= tmp_string
;
304 pos
= (hb_glyph_position_t
*) out_info
;
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
++)
330 pinfo
->codepoint
= glyph_data
[i
];
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
;
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
;
360 hb_buffer_t::copy_glyph (void)
362 if (unlikely (!make_room_for (0, 1))) return;
364 out_info
[out_len
] = info
[idx
];
370 hb_buffer_t::move_to (unsigned int i
)
379 assert (i
<= out_len
+ (len
- idx
));
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]));
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
);
401 memmove (info
+ idx
, out_info
+ out_len
, count
* sizeof (out_info
[0]));
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
;
422 hb_buffer_t::set_masks (hb_mask_t value
,
424 unsigned int cluster_start
,
425 unsigned int cluster_end
)
427 hb_mask_t not_mask
= ~mask
;
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
;
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
;
447 hb_buffer_t::reverse_range (unsigned int start
,
455 for (i
= start
, j
= end
- 1; i
< j
; i
++, j
--) {
463 if (have_positions
) {
464 for (i
= start
, j
= end
- 1; i
< j
; i
++, j
--) {
465 hb_glyph_position_t t
;
475 hb_buffer_t::reverse (void)
480 reverse_range (0, len
);
484 hb_buffer_t::reverse_clusters (void)
486 unsigned int i
, start
, count
, last_cluster
;
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
);
500 last_cluster
= info
[i
].cluster
;
503 reverse_range (start
, i
);
507 hb_buffer_t::merge_clusters_impl (unsigned int start
,
510 if (cluster_level
== HB_BUFFER_CLUSTER_LEVEL_CHARACTERS
)
513 unsigned int cluster
= info
[start
].cluster
;
515 for (unsigned int i
= start
+ 1; i
< end
; i
++)
516 cluster
= MIN (cluster
, info
[i
].cluster
);
519 while (end
< len
&& info
[end
- 1].cluster
== info
[end
].cluster
)
523 while (idx
< start
&& info
[start
- 1].cluster
== info
[start
].cluster
)
526 /* If we hit the start of buffer, continue in out-buffer. */
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
;
535 hb_buffer_t::merge_out_clusters (unsigned int start
,
538 if (cluster_level
== HB_BUFFER_CLUSTER_LEVEL_CHARACTERS
)
541 if (unlikely (end
- start
< 2))
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
);
550 while (start
&& out_info
[start
- 1].cluster
== out_info
[start
].cluster
)
554 while (end
< out_len
&& out_info
[end
- 1].cluster
== out_info
[end
].cluster
)
557 /* If we hit the end of out-buffer, continue in buffer. */
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
;
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. */
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
;
589 /* Merge cluster forward. */
590 merge_clusters (idx
, idx
+ 2);
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
;
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 ();
631 dump_var_allocation (const hb_buffer_t
*buffer
)
634 for (unsigned int i
= 0; i
< 8; i
++)
635 buf
[i
] = '0' + buffer
->allocated_var_bytes
[7 - i
];
637 DEBUG_MSG (BUFFER
, buffer
,
638 "Current var allocation: %s",
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
));
701 * hb_buffer_create: (Xconstructor)
705 * Return value: (transfer full)
710 hb_buffer_create (void)
714 if (!(buffer
= hb_object_create
<hb_buffer_t
> ()))
715 return hb_buffer_get_empty ();
723 * hb_buffer_get_empty:
727 * Return value: (transfer full):
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
,
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)
760 * Return value: (transfer full):
765 hb_buffer_reference (hb_buffer_t
*buffer
)
767 return hb_object_reference (buffer
);
771 * hb_buffer_destroy: (skip)
779 hb_buffer_destroy (hb_buffer_t
*buffer
)
781 if (!hb_object_destroy (buffer
)) return;
783 hb_unicode_funcs_destroy (buffer
->unicode
);
792 * hb_buffer_set_user_data: (skip)
806 hb_buffer_set_user_data (hb_buffer_t
*buffer
,
807 hb_user_data_key_t
*key
,
809 hb_destroy_func_t destroy
,
812 return hb_object_set_user_data (buffer
, key
, data
, destroy
, replace
);
816 * hb_buffer_get_user_data: (skip)
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:
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:
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:
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
)))
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:
903 hb_buffer_get_unicode_funcs (hb_buffer_t
*buffer
)
905 return buffer
->unicode
;
909 * hb_buffer_set_direction:
918 hb_buffer_set_direction (hb_buffer_t
*buffer
,
919 hb_direction_t direction
)
922 if (unlikely (hb_object_is_inert (buffer
)))
925 buffer
->props
.direction
= direction
;
929 * hb_buffer_get_direction:
939 hb_buffer_get_direction (hb_buffer_t
*buffer
)
941 return buffer
->props
.direction
;
945 * hb_buffer_set_script:
954 hb_buffer_set_script (hb_buffer_t
*buffer
,
957 if (unlikely (hb_object_is_inert (buffer
)))
960 buffer
->props
.script
= script
;
964 * hb_buffer_get_script:
974 hb_buffer_get_script (hb_buffer_t
*buffer
)
976 return buffer
->props
.script
;
980 * hb_buffer_set_language:
989 hb_buffer_set_language (hb_buffer_t
*buffer
,
990 hb_language_t language
)
992 if (unlikely (hb_object_is_inert (buffer
)))
995 buffer
->props
.language
= language
;
999 * hb_buffer_get_language:
1000 * @buffer: a buffer.
1004 * Return value: (transfer none):
1009 hb_buffer_get_language (hb_buffer_t
*buffer
)
1011 return buffer
->props
.language
;
1015 * hb_buffer_set_segment_properties:
1016 * @buffer: a buffer.
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
)))
1030 buffer
->props
= *props
;
1034 * hb_buffer_get_segment_properties:
1035 * @buffer: a buffer.
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.
1060 hb_buffer_set_flags (hb_buffer_t
*buffer
,
1061 hb_buffer_flags_t flags
)
1063 if (unlikely (hb_object_is_inert (buffer
)))
1066 buffer
->flags
= flags
;
1070 * hb_buffer_get_flags:
1071 * @buffer: a buffer.
1080 hb_buffer_get_flags (hb_buffer_t
*buffer
)
1082 return buffer
->flags
;
1086 * hb_buffer_set_cluster_level:
1087 * @buffer: a buffer.
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
)))
1101 buffer
->cluster_level
= cluster_level
;
1105 * hb_buffer_get_cluster_level:
1106 * @buffer: a buffer.
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.
1131 hb_buffer_set_replacement_codepoint (hb_buffer_t
*buffer
,
1132 hb_codepoint_t replacement
)
1134 if (unlikely (hb_object_is_inert (buffer
)))
1137 buffer
->replacement
= replacement
;
1141 * hb_buffer_get_replacement_codepoint:
1142 * @buffer: a buffer.
1151 hb_buffer_get_replacement_codepoint (hb_buffer_t
*buffer
)
1153 return buffer
->replacement
;
1159 * @buffer: a buffer.
1166 hb_buffer_reset (hb_buffer_t
*buffer
)
1172 * hb_buffer_clear_contents:
1173 * @buffer: a buffer.
1180 hb_buffer_clear_contents (hb_buffer_t
*buffer
)
1186 * hb_buffer_pre_allocate:
1187 * @buffer: a buffer.
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.
1213 hb_buffer_allocation_successful (hb_buffer_t
*buffer
)
1215 return !buffer
->in_error
;
1220 * @buffer: a buffer.
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.
1249 hb_buffer_set_length (hb_buffer_t
*buffer
,
1250 unsigned int length
)
1252 if (unlikely (hb_object_is_inert (buffer
)))
1255 if (!buffer
->ensure (length
))
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
;
1269 buffer
->content_type
= HB_BUFFER_CONTENT_TYPE_INVALID
;
1270 buffer
->clear_context (0);
1272 buffer
->clear_context (1);
1278 * hb_buffer_get_length:
1279 * @buffer: a buffer.
1281 * Returns the number of items in the buffer.
1283 * Return value: buffer length.
1288 hb_buffer_get_length (hb_buffer_t
*buffer
)
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.
1306 hb_buffer_get_glyph_infos (hb_buffer_t
*buffer
,
1307 unsigned int *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.
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 ();
1335 *length
= buffer
->len
;
1337 return (hb_glyph_position_t
*) buffer
->pos
;
1341 * hb_buffer_reverse:
1342 * @buffer: a buffer.
1344 * Reverses buffer contents.
1349 hb_buffer_reverse (hb_buffer_t
*buffer
)
1355 * hb_buffer_reverse_range:
1356 * @buffer: a buffer.
1357 * @start: start index.
1360 * Reverses buffer contents between start to end.
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.
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.
1412 hb_buffer_guess_segment_properties (hb_buffer_t
*buffer
)
1414 buffer
->guess_segment_properties ();
1417 template <typename utf_t
>
1419 hb_buffer_add_utf (hb_buffer_t
*buffer
,
1420 const typename
utf_t::codepoint_t
*text
,
1422 unsigned int item_offset
,
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
)))
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
)
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
;
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
)
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):
1499 hb_buffer_add_utf8 (hb_buffer_t
*buffer
,
1502 unsigned int item_offset
,
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):
1521 hb_buffer_add_utf16 (hb_buffer_t
*buffer
,
1522 const uint16_t *text
,
1524 unsigned int item_offset
,
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):
1543 hb_buffer_add_utf32 (hb_buffer_t
*buffer
,
1544 const uint32_t *text
,
1546 unsigned int item_offset
,
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):
1565 hb_buffer_add_latin1 (hb_buffer_t
*buffer
,
1566 const uint8_t *text
,
1568 unsigned int item_offset
,
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):
1587 hb_buffer_add_codepoints (hb_buffer_t
*buffer
,
1588 const hb_codepoint_t
*text
,
1590 unsigned int item_offset
,
1593 hb_buffer_add_utf
<hb_utf32_t
<false> > (buffer
, text
, text_length
, item_offset
, item_length
);
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
;
1605 normalize_glyphs_cluster (hb_buffer_t
*buffer
,
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;
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
);
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.
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;
1674 for (end
= start
+ 1; end
< count
; end
++)
1675 if (info
[start
].cluster
!= info
[end
].cluster
) {
1676 normalize_glyphs_cluster (buffer
, start
, end
, backward
);
1679 normalize_glyphs_cluster (buffer
, start
, end
, backward
);