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)
40 hb_segment_properties_equal (const hb_segment_properties_t
*a
,
41 const hb_segment_properties_t
*b
)
43 return a
->direction
== b
->direction
&&
44 a
->script
== b
->script
&&
45 a
->language
== b
->language
&&
46 a
->reserved1
== b
->reserved1
&&
47 a
->reserved2
== b
->reserved2
;
52 hb_segment_properties_hash (const hb_segment_properties_t
*p
)
54 return (unsigned int) p
->direction
^
55 (unsigned int) p
->script
^
56 (intptr_t) (p
->language
);
61 /* Here is how the buffer works internally:
63 * There are two info pointers: info and out_info. They always have
64 * the same allocated size, but different lengths.
66 * As an optimization, both info and out_info may point to the
67 * same piece of memory, which is owned by info. This remains the
68 * case as long as out_len doesn't exceed i at any time.
69 * In that case, swap_buffers() is no-op and the glyph operations operate
72 * As soon as out_info gets longer than info, out_info is moved over
73 * to an alternate buffer (which we reuse the pos buffer for!), and its
74 * current contents (out_len entries) are copied to the new place.
75 * This should all remain transparent to the user. swap_buffers() then
76 * switches info and out_info.
84 hb_buffer_t::enlarge (unsigned int size
)
86 if (unlikely (in_error
))
89 unsigned int new_allocated
= allocated
;
90 hb_glyph_position_t
*new_pos
= NULL
;
91 hb_glyph_info_t
*new_info
= NULL
;
92 bool separate_out
= out_info
!= info
;
94 if (unlikely (_hb_unsigned_int_mul_overflows (size
, sizeof (info
[0]))))
97 while (size
>= new_allocated
)
98 new_allocated
+= (new_allocated
>> 1) + 32;
100 ASSERT_STATIC (sizeof (info
[0]) == sizeof (pos
[0]));
101 if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated
, sizeof (info
[0]))))
104 new_pos
= (hb_glyph_position_t
*) realloc (pos
, new_allocated
* sizeof (pos
[0]));
105 new_info
= (hb_glyph_info_t
*) realloc (info
, new_allocated
* sizeof (info
[0]));
108 if (unlikely (!new_pos
|| !new_info
))
111 if (likely (new_pos
))
114 if (likely (new_info
))
117 out_info
= separate_out
? (hb_glyph_info_t
*) pos
: info
;
118 if (likely (!in_error
))
119 allocated
= new_allocated
;
121 return likely (!in_error
);
125 hb_buffer_t::make_room_for (unsigned int num_in
,
126 unsigned int num_out
)
128 if (unlikely (!ensure (out_len
+ num_out
))) return false;
130 if (out_info
== info
&&
131 out_len
+ num_out
> idx
+ num_in
)
133 assert (have_output
);
135 out_info
= (hb_glyph_info_t
*) pos
;
136 memcpy (out_info
, info
, out_len
* sizeof (out_info
[0]));
143 hb_buffer_t::shift_forward (unsigned int count
)
145 assert (have_output
);
146 if (unlikely (!ensure (len
+ count
))) return false;
148 memmove (info
+ idx
+ count
, info
+ idx
, (len
- idx
) * sizeof (info
[0]));
155 hb_buffer_t::scratch_buffer_t
*
156 hb_buffer_t::get_scratch_buffer (unsigned int *size
)
159 have_positions
= false;
164 assert ((uintptr_t) pos
% sizeof (scratch_buffer_t
) == 0);
165 *size
= allocated
* sizeof (pos
[0]) / sizeof (scratch_buffer_t
);
166 return (scratch_buffer_t
*) (void *) pos
;
171 /* HarfBuzz-Internal API */
174 hb_buffer_t::reset (void)
176 if (unlikely (hb_object_is_inert (this)))
179 hb_unicode_funcs_destroy (unicode
);
180 unicode
= hb_unicode_funcs_get_default ();
186 hb_buffer_t::clear (void)
188 if (unlikely (hb_object_is_inert (this)))
191 hb_segment_properties_t default_props
= HB_SEGMENT_PROPERTIES_DEFAULT
;
192 props
= default_props
;
193 flags
= HB_BUFFER_FLAG_DEFAULT
;
195 content_type
= HB_BUFFER_CONTENT_TYPE_INVALID
;
198 have_positions
= false;
206 memset (allocated_var_bytes
, 0, sizeof allocated_var_bytes
);
207 memset (allocated_var_owner
, 0, sizeof allocated_var_owner
);
209 memset (context
, 0, sizeof context
);
210 memset (context_len
, 0, sizeof context_len
);
214 hb_buffer_t::add (hb_codepoint_t codepoint
,
215 unsigned int cluster
)
217 hb_glyph_info_t
*glyph
;
219 if (unlikely (!ensure (len
+ 1))) return;
223 memset (glyph
, 0, sizeof (*glyph
));
224 glyph
->codepoint
= codepoint
;
226 glyph
->cluster
= cluster
;
232 hb_buffer_t::add_info (const hb_glyph_info_t
&glyph_info
)
234 if (unlikely (!ensure (len
+ 1))) return;
236 info
[len
] = glyph_info
;
243 hb_buffer_t::remove_output (void)
245 if (unlikely (hb_object_is_inert (this)))
249 have_positions
= false;
256 hb_buffer_t::clear_output (void)
258 if (unlikely (hb_object_is_inert (this)))
262 have_positions
= false;
269 hb_buffer_t::clear_positions (void)
271 if (unlikely (hb_object_is_inert (this)))
275 have_positions
= true;
280 memset (pos
, 0, sizeof (pos
[0]) * len
);
284 hb_buffer_t::swap_buffers (void)
286 if (unlikely (in_error
)) return;
288 assert (have_output
);
291 if (out_info
!= info
)
293 hb_glyph_info_t
*tmp_string
;
296 out_info
= tmp_string
;
297 pos
= (hb_glyph_position_t
*) out_info
;
310 hb_buffer_t::replace_glyphs (unsigned int num_in
,
311 unsigned int num_out
,
312 const uint32_t *glyph_data
)
314 if (unlikely (!make_room_for (num_in
, num_out
))) return;
316 merge_clusters (idx
, idx
+ num_in
);
318 hb_glyph_info_t orig_info
= info
[idx
];
319 hb_glyph_info_t
*pinfo
= &out_info
[out_len
];
320 for (unsigned int i
= 0; i
< num_out
; i
++)
323 pinfo
->codepoint
= glyph_data
[i
];
332 hb_buffer_t::output_glyph (hb_codepoint_t glyph_index
)
334 if (unlikely (!make_room_for (0, 1))) return;
336 out_info
[out_len
] = info
[idx
];
337 out_info
[out_len
].codepoint
= glyph_index
;
343 hb_buffer_t::output_info (const hb_glyph_info_t
&glyph_info
)
345 if (unlikely (!make_room_for (0, 1))) return;
347 out_info
[out_len
] = glyph_info
;
353 hb_buffer_t::copy_glyph (void)
355 if (unlikely (!make_room_for (0, 1))) return;
357 out_info
[out_len
] = info
[idx
];
363 hb_buffer_t::move_to (unsigned int i
)
372 assert (i
<= out_len
+ (len
- idx
));
376 unsigned int count
= i
- out_len
;
377 if (unlikely (!make_room_for (count
, count
))) return false;
379 memmove (out_info
+ out_len
, info
+ idx
, count
* sizeof (out_info
[0]));
383 else if (out_len
> i
)
385 /* Tricky part: rewinding... */
386 unsigned int count
= out_len
- i
;
388 if (unlikely (idx
< count
&& !shift_forward (count
+ 32))) return false;
390 assert (idx
>= count
);
394 memmove (info
+ idx
, out_info
+ out_len
, count
* sizeof (out_info
[0]));
401 hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index
)
403 if (unlikely (out_info
!= info
|| out_len
!= idx
)) {
404 if (unlikely (!make_room_for (1, 1))) return;
405 out_info
[out_len
] = info
[idx
];
407 out_info
[out_len
].codepoint
= glyph_index
;
415 hb_buffer_t::set_masks (hb_mask_t value
,
417 unsigned int cluster_start
,
418 unsigned int cluster_end
)
420 hb_mask_t not_mask
= ~mask
;
426 if (cluster_start
== 0 && cluster_end
== (unsigned int)-1) {
427 unsigned int count
= len
;
428 for (unsigned int i
= 0; i
< count
; i
++)
429 info
[i
].mask
= (info
[i
].mask
& not_mask
) | value
;
433 unsigned int count
= len
;
434 for (unsigned int i
= 0; i
< count
; i
++)
435 if (cluster_start
<= info
[i
].cluster
&& info
[i
].cluster
< cluster_end
)
436 info
[i
].mask
= (info
[i
].mask
& not_mask
) | value
;
440 hb_buffer_t::reverse_range (unsigned int start
,
445 if (start
== end
- 1)
448 for (i
= start
, j
= end
- 1; i
< j
; i
++, j
--) {
457 for (i
= start
, j
= end
- 1; i
< j
; i
++, j
--) {
458 hb_glyph_position_t t
;
468 hb_buffer_t::reverse (void)
473 reverse_range (0, len
);
477 hb_buffer_t::reverse_clusters (void)
479 unsigned int i
, start
, count
, last_cluster
;
488 last_cluster
= info
[0].cluster
;
489 for (i
= 1; i
< count
; i
++) {
490 if (last_cluster
!= info
[i
].cluster
) {
491 reverse_range (start
, i
);
493 last_cluster
= info
[i
].cluster
;
496 reverse_range (start
, i
);
500 hb_buffer_t::merge_clusters (unsigned int start
,
503 if (unlikely (end
- start
< 2))
506 unsigned int cluster
= info
[start
].cluster
;
508 for (unsigned int i
= start
+ 1; i
< end
; i
++)
509 cluster
= MIN (cluster
, info
[i
].cluster
);
512 while (end
< len
&& info
[end
- 1].cluster
== info
[end
].cluster
)
516 while (idx
< start
&& info
[start
- 1].cluster
== info
[start
].cluster
)
519 /* If we hit the start of buffer, continue in out-buffer. */
521 for (unsigned i
= out_len
; i
&& out_info
[i
- 1].cluster
== info
[start
].cluster
; i
--)
522 out_info
[i
- 1].cluster
= cluster
;
524 for (unsigned int i
= start
; i
< end
; i
++)
525 info
[i
].cluster
= cluster
;
528 hb_buffer_t::merge_out_clusters (unsigned int start
,
531 if (unlikely (end
- start
< 2))
534 unsigned int cluster
= out_info
[start
].cluster
;
536 for (unsigned int i
= start
+ 1; i
< end
; i
++)
537 cluster
= MIN (cluster
, out_info
[i
].cluster
);
540 while (start
&& out_info
[start
- 1].cluster
== out_info
[start
].cluster
)
544 while (end
< out_len
&& out_info
[end
- 1].cluster
== out_info
[end
].cluster
)
547 /* If we hit the end of out-buffer, continue in buffer. */
549 for (unsigned i
= idx
; i
< len
&& info
[i
].cluster
== out_info
[end
- 1].cluster
; i
++)
550 info
[i
].cluster
= cluster
;
552 for (unsigned int i
= start
; i
< end
; i
++)
553 out_info
[i
].cluster
= cluster
;
557 hb_buffer_t::guess_segment_properties (void)
559 assert (content_type
== HB_BUFFER_CONTENT_TYPE_UNICODE
||
560 (!len
&& content_type
== HB_BUFFER_CONTENT_TYPE_INVALID
));
562 /* If script is set to INVALID, guess from buffer contents */
563 if (props
.script
== HB_SCRIPT_INVALID
) {
564 for (unsigned int i
= 0; i
< len
; i
++) {
565 hb_script_t script
= unicode
->script (info
[i
].codepoint
);
566 if (likely (script
!= HB_SCRIPT_COMMON
&&
567 script
!= HB_SCRIPT_INHERITED
&&
568 script
!= HB_SCRIPT_UNKNOWN
)) {
569 props
.script
= script
;
575 /* If direction is set to INVALID, guess from script */
576 if (props
.direction
== HB_DIRECTION_INVALID
) {
577 props
.direction
= hb_script_get_horizontal_direction (props
.script
);
580 /* If language is not set, use default language from locale */
581 if (props
.language
== HB_LANGUAGE_INVALID
) {
582 /* TODO get_default_for_script? using $LANGUAGE */
583 props
.language
= hb_language_get_default ();
589 dump_var_allocation (const hb_buffer_t
*buffer
)
592 for (unsigned int i
= 0; i
< 8; i
++)
593 buf
[i
] = '0' + buffer
->allocated_var_bytes
[7 - i
];
595 DEBUG_MSG (BUFFER
, buffer
,
596 "Current var allocation: %s",
600 void hb_buffer_t::allocate_var (unsigned int byte_i
, unsigned int count
, const char *owner
)
602 assert (byte_i
< 8 && byte_i
+ count
<= 8);
604 if (DEBUG_ENABLED (BUFFER
))
605 dump_var_allocation (this);
606 DEBUG_MSG (BUFFER
, this,
607 "Allocating var bytes %d..%d for %s",
608 byte_i
, byte_i
+ count
- 1, owner
);
610 for (unsigned int i
= byte_i
; i
< byte_i
+ count
; i
++) {
611 assert (!allocated_var_bytes
[i
]);
612 allocated_var_bytes
[i
]++;
613 allocated_var_owner
[i
] = owner
;
617 void hb_buffer_t::deallocate_var (unsigned int byte_i
, unsigned int count
, const char *owner
)
619 if (DEBUG_ENABLED (BUFFER
))
620 dump_var_allocation (this);
622 DEBUG_MSG (BUFFER
, this,
623 "Deallocating var bytes %d..%d for %s",
624 byte_i
, byte_i
+ count
- 1, owner
);
626 assert (byte_i
< 8 && byte_i
+ count
<= 8);
627 for (unsigned int i
= byte_i
; i
< byte_i
+ count
; i
++) {
628 assert (allocated_var_bytes
[i
]);
629 assert (0 == strcmp (allocated_var_owner
[i
], owner
));
630 allocated_var_bytes
[i
]--;
634 void hb_buffer_t::assert_var (unsigned int byte_i
, unsigned int count
, const char *owner
)
636 if (DEBUG_ENABLED (BUFFER
))
637 dump_var_allocation (this);
639 DEBUG_MSG (BUFFER
, this,
640 "Asserting var bytes %d..%d for %s",
641 byte_i
, byte_i
+ count
- 1, owner
);
643 assert (byte_i
< 8 && byte_i
+ count
<= 8);
644 for (unsigned int i
= byte_i
; i
< byte_i
+ count
; i
++) {
645 assert (allocated_var_bytes
[i
]);
646 assert (0 == strcmp (allocated_var_owner
[i
], owner
));
650 void hb_buffer_t::deallocate_var_all (void)
652 memset (allocated_var_bytes
, 0, sizeof (allocated_var_bytes
));
653 memset (allocated_var_owner
, 0, sizeof (allocated_var_owner
));
659 * hb_buffer_create: (Xconstructor)
663 * Return value: (transfer full)
668 hb_buffer_create (void)
672 if (!(buffer
= hb_object_create
<hb_buffer_t
> ()))
673 return hb_buffer_get_empty ();
681 * hb_buffer_get_empty:
685 * Return value: (transfer full):
690 hb_buffer_get_empty (void)
692 static const hb_buffer_t _hb_buffer_nil
= {
693 HB_OBJECT_HEADER_STATIC
,
695 const_cast<hb_unicode_funcs_t
*> (&_hb_unicode_funcs_nil
),
696 HB_SEGMENT_PROPERTIES_DEFAULT
,
697 HB_BUFFER_FLAG_DEFAULT
,
699 HB_BUFFER_CONTENT_TYPE_INVALID
,
701 true, /* have_output */
702 true /* have_positions */
704 /* Zero is good enough for everything else. */
707 return const_cast<hb_buffer_t
*> (&_hb_buffer_nil
);
711 * hb_buffer_reference: (skip)
716 * Return value: (transfer full):
721 hb_buffer_reference (hb_buffer_t
*buffer
)
723 return hb_object_reference (buffer
);
727 * hb_buffer_destroy: (skip)
735 hb_buffer_destroy (hb_buffer_t
*buffer
)
737 if (!hb_object_destroy (buffer
)) return;
739 hb_unicode_funcs_destroy (buffer
->unicode
);
748 * hb_buffer_set_user_data: (skip)
762 hb_buffer_set_user_data (hb_buffer_t
*buffer
,
763 hb_user_data_key_t
*key
,
765 hb_destroy_func_t destroy
,
768 return hb_object_set_user_data (buffer
, key
, data
, destroy
, replace
);
772 * hb_buffer_get_user_data: (skip)
783 hb_buffer_get_user_data (hb_buffer_t
*buffer
,
784 hb_user_data_key_t
*key
)
786 return hb_object_get_user_data (buffer
, key
);
791 * hb_buffer_set_content_type:
800 hb_buffer_set_content_type (hb_buffer_t
*buffer
,
801 hb_buffer_content_type_t content_type
)
803 buffer
->content_type
= content_type
;
807 * hb_buffer_get_content_type:
816 hb_buffer_content_type_t
817 hb_buffer_get_content_type (hb_buffer_t
*buffer
)
819 return buffer
->content_type
;
824 * hb_buffer_set_unicode_funcs:
833 hb_buffer_set_unicode_funcs (hb_buffer_t
*buffer
,
834 hb_unicode_funcs_t
*unicode_funcs
)
836 if (unlikely (hb_object_is_inert (buffer
)))
840 unicode_funcs
= hb_unicode_funcs_get_default ();
843 hb_unicode_funcs_reference (unicode_funcs
);
844 hb_unicode_funcs_destroy (buffer
->unicode
);
845 buffer
->unicode
= unicode_funcs
;
849 * hb_buffer_get_unicode_funcs:
859 hb_buffer_get_unicode_funcs (hb_buffer_t
*buffer
)
861 return buffer
->unicode
;
865 * hb_buffer_set_direction:
874 hb_buffer_set_direction (hb_buffer_t
*buffer
,
875 hb_direction_t direction
)
878 if (unlikely (hb_object_is_inert (buffer
)))
881 buffer
->props
.direction
= direction
;
885 * hb_buffer_get_direction:
895 hb_buffer_get_direction (hb_buffer_t
*buffer
)
897 return buffer
->props
.direction
;
901 * hb_buffer_set_script:
910 hb_buffer_set_script (hb_buffer_t
*buffer
,
913 if (unlikely (hb_object_is_inert (buffer
)))
916 buffer
->props
.script
= script
;
920 * hb_buffer_get_script:
930 hb_buffer_get_script (hb_buffer_t
*buffer
)
932 return buffer
->props
.script
;
936 * hb_buffer_set_language:
945 hb_buffer_set_language (hb_buffer_t
*buffer
,
946 hb_language_t language
)
948 if (unlikely (hb_object_is_inert (buffer
)))
951 buffer
->props
.language
= language
;
955 * hb_buffer_get_language:
965 hb_buffer_get_language (hb_buffer_t
*buffer
)
967 return buffer
->props
.language
;
971 * hb_buffer_set_segment_properties:
980 hb_buffer_set_segment_properties (hb_buffer_t
*buffer
,
981 const hb_segment_properties_t
*props
)
983 if (unlikely (hb_object_is_inert (buffer
)))
986 buffer
->props
= *props
;
990 * hb_buffer_get_segment_properties:
999 hb_buffer_get_segment_properties (hb_buffer_t
*buffer
,
1000 hb_segment_properties_t
*props
)
1002 *props
= buffer
->props
;
1007 * hb_buffer_set_flags:
1008 * @buffer: a buffer.
1016 hb_buffer_set_flags (hb_buffer_t
*buffer
,
1017 hb_buffer_flags_t flags
)
1019 if (unlikely (hb_object_is_inert (buffer
)))
1022 buffer
->flags
= flags
;
1026 * hb_buffer_get_flags:
1027 * @buffer: a buffer.
1036 hb_buffer_get_flags (hb_buffer_t
*buffer
)
1038 return buffer
->flags
;
1044 * @buffer: a buffer.
1051 hb_buffer_reset (hb_buffer_t
*buffer
)
1057 * hb_buffer_clear_contents:
1058 * @buffer: a buffer.
1065 hb_buffer_clear_contents (hb_buffer_t
*buffer
)
1071 * hb_buffer_pre_allocate:
1072 * @buffer: a buffer.
1082 hb_buffer_pre_allocate (hb_buffer_t
*buffer
, unsigned int size
)
1084 return buffer
->ensure (size
);
1088 * hb_buffer_allocation_successful:
1089 * @buffer: a buffer.
1098 hb_buffer_allocation_successful (hb_buffer_t
*buffer
)
1100 return !buffer
->in_error
;
1105 * @buffer: a buffer.
1114 hb_buffer_add (hb_buffer_t
*buffer
,
1115 hb_codepoint_t codepoint
,
1116 unsigned int cluster
)
1118 buffer
->add (codepoint
, cluster
);
1119 buffer
->clear_context (1);
1123 * hb_buffer_set_length:
1124 * @buffer: a buffer.
1134 hb_buffer_set_length (hb_buffer_t
*buffer
,
1135 unsigned int length
)
1137 if (unlikely (hb_object_is_inert (buffer
)))
1140 if (!buffer
->ensure (length
))
1143 /* Wipe the new space */
1144 if (length
> buffer
->len
) {
1145 memset (buffer
->info
+ buffer
->len
, 0, sizeof (buffer
->info
[0]) * (length
- buffer
->len
));
1146 if (buffer
->have_positions
)
1147 memset (buffer
->pos
+ buffer
->len
, 0, sizeof (buffer
->pos
[0]) * (length
- buffer
->len
));
1150 buffer
->len
= length
;
1153 buffer
->clear_context (0);
1154 buffer
->clear_context (1);
1160 * hb_buffer_get_length:
1161 * @buffer: a buffer.
1163 * Returns the number of items in the buffer.
1165 * Return value: buffer length.
1170 hb_buffer_get_length (hb_buffer_t
*buffer
)
1176 * hb_buffer_get_glyph_infos:
1177 * @buffer: a buffer.
1178 * @length: (out): output array length.
1180 * Returns buffer glyph information array. Returned pointer
1181 * is valid as long as buffer contents are not modified.
1183 * Return value: (transfer none) (array length=length): buffer glyph information array.
1188 hb_buffer_get_glyph_infos (hb_buffer_t
*buffer
,
1189 unsigned int *length
)
1192 *length
= buffer
->len
;
1194 return (hb_glyph_info_t
*) buffer
->info
;
1198 * hb_buffer_get_glyph_positions:
1199 * @buffer: a buffer.
1200 * @length: (out): output length.
1202 * Returns buffer glyph position array. Returned pointer
1203 * is valid as long as buffer contents are not modified.
1205 * Return value: (transfer none) (array length=length): buffer glyph position array.
1209 hb_glyph_position_t
*
1210 hb_buffer_get_glyph_positions (hb_buffer_t
*buffer
,
1211 unsigned int *length
)
1213 if (!buffer
->have_positions
)
1214 buffer
->clear_positions ();
1217 *length
= buffer
->len
;
1219 return (hb_glyph_position_t
*) buffer
->pos
;
1223 * hb_buffer_reverse:
1224 * @buffer: a buffer.
1226 * Reverses buffer contents.
1231 hb_buffer_reverse (hb_buffer_t
*buffer
)
1237 * hb_buffer_reverse_clusters:
1238 * @buffer: a buffer.
1240 * Reverses buffer clusters. That is, the buffer contents are
1241 * reversed, then each cluster (consecutive items having the
1242 * same cluster number) are reversed again.
1247 hb_buffer_reverse_clusters (hb_buffer_t
*buffer
)
1249 buffer
->reverse_clusters ();
1253 * hb_buffer_guess_segment_properties:
1254 * @buffer: a buffer.
1256 * Sets unset buffer segment properties based on buffer Unicode
1257 * contents. If buffer is not empty, it must have content type
1258 * %HB_BUFFER_CONTENT_TYPE_UNICODE.
1260 * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
1261 * will be set to the Unicode script of the first character in
1262 * the buffer that has a script other than %HB_SCRIPT_COMMON,
1263 * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
1265 * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
1266 * it will be set to the natural horizontal direction of the
1267 * buffer script as returned by hb_script_get_horizontal_direction().
1269 * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
1270 * it will be set to the process's default language as returned by
1271 * hb_language_get_default(). This may change in the future by
1272 * taking buffer script into consideration when choosing a language.
1277 hb_buffer_guess_segment_properties (hb_buffer_t
*buffer
)
1279 buffer
->guess_segment_properties ();
1282 template <typename T
>
1284 hb_buffer_add_utf (hb_buffer_t
*buffer
,
1287 unsigned int item_offset
,
1290 assert (buffer
->content_type
== HB_BUFFER_CONTENT_TYPE_UNICODE
||
1291 (!buffer
->len
&& buffer
->content_type
== HB_BUFFER_CONTENT_TYPE_INVALID
));
1293 if (unlikely (hb_object_is_inert (buffer
)))
1296 if (text_length
== -1)
1297 text_length
= hb_utf_strlen (text
);
1299 if (item_length
== -1)
1300 item_length
= text_length
- item_offset
;
1302 buffer
->ensure (buffer
->len
+ item_length
* sizeof (T
) / 4);
1304 /* If buffer is empty and pre-context provided, install it.
1305 * This check is written this way, to make sure people can
1306 * provide pre-context in one add_utf() call, then provide
1307 * text in a follow-up call. See:
1309 * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
1311 if (!buffer
->len
&& item_offset
> 0)
1313 /* Add pre-context */
1314 buffer
->clear_context (0);
1315 const T
*prev
= text
+ item_offset
;
1316 const T
*start
= text
;
1317 while (start
< prev
&& buffer
->context_len
[0] < buffer
->CONTEXT_LENGTH
)
1320 prev
= hb_utf_prev (prev
, start
, &u
);
1321 buffer
->context
[0][buffer
->context_len
[0]++] = u
;
1325 const T
*next
= text
+ item_offset
;
1326 const T
*end
= next
+ item_length
;
1330 const T
*old_next
= next
;
1331 next
= hb_utf_next (next
, end
, &u
);
1332 buffer
->add (u
, old_next
- (const T
*) text
);
1335 /* Add post-context */
1336 buffer
->clear_context (1);
1337 end
= text
+ text_length
;
1338 while (next
< end
&& buffer
->context_len
[1] < buffer
->CONTEXT_LENGTH
)
1341 next
= hb_utf_next (next
, end
, &u
);
1342 buffer
->context
[1][buffer
->context_len
[1]++] = u
;
1345 buffer
->content_type
= HB_BUFFER_CONTENT_TYPE_UNICODE
;
1349 * hb_buffer_add_utf8:
1350 * @buffer: a buffer.
1351 * @text: (array length=text_length):
1361 hb_buffer_add_utf8 (hb_buffer_t
*buffer
,
1364 unsigned int item_offset
,
1367 hb_buffer_add_utf (buffer
, (const uint8_t *) text
, text_length
, item_offset
, item_length
);
1371 * hb_buffer_add_utf16:
1372 * @buffer: a buffer.
1373 * @text: (array length=text_length):
1383 hb_buffer_add_utf16 (hb_buffer_t
*buffer
,
1384 const uint16_t *text
,
1386 unsigned int item_offset
,
1389 hb_buffer_add_utf (buffer
, text
, text_length
, item_offset
, item_length
);
1393 * hb_buffer_add_utf32:
1394 * @buffer: a buffer.
1395 * @text: (array length=text_length):
1405 hb_buffer_add_utf32 (hb_buffer_t
*buffer
,
1406 const uint32_t *text
,
1408 unsigned int item_offset
,
1411 hb_buffer_add_utf (buffer
, text
, text_length
, item_offset
, item_length
);
1416 compare_info_codepoint (const hb_glyph_info_t
*pa
,
1417 const hb_glyph_info_t
*pb
)
1419 return (int) pb
->codepoint
- (int) pa
->codepoint
;
1423 normalize_glyphs_cluster (hb_buffer_t
*buffer
,
1428 hb_glyph_position_t
*pos
= buffer
->pos
;
1430 /* Total cluster advance */
1431 hb_position_t total_x_advance
= 0, total_y_advance
= 0;
1432 for (unsigned int i
= start
; i
< end
; i
++)
1434 total_x_advance
+= pos
[i
].x_advance
;
1435 total_y_advance
+= pos
[i
].y_advance
;
1438 hb_position_t x_advance
= 0, y_advance
= 0;
1439 for (unsigned int i
= start
; i
< end
; i
++)
1441 pos
[i
].x_offset
+= x_advance
;
1442 pos
[i
].y_offset
+= y_advance
;
1444 x_advance
+= pos
[i
].x_advance
;
1445 y_advance
+= pos
[i
].y_advance
;
1447 pos
[i
].x_advance
= 0;
1448 pos
[i
].y_advance
= 0;
1453 /* Transfer all cluster advance to the last glyph. */
1454 pos
[end
- 1].x_advance
= total_x_advance
;
1455 pos
[end
- 1].y_advance
= total_y_advance
;
1457 hb_bubble_sort (buffer
->info
+ start
, end
- start
- 1, compare_info_codepoint
, buffer
->pos
+ start
);
1459 /* Transfer all cluster advance to the first glyph. */
1460 pos
[start
].x_advance
+= total_x_advance
;
1461 pos
[start
].y_advance
+= total_y_advance
;
1462 for (unsigned int i
= start
+ 1; i
< end
; i
++) {
1463 pos
[i
].x_offset
-= total_x_advance
;
1464 pos
[i
].y_offset
-= total_y_advance
;
1466 hb_bubble_sort (buffer
->info
+ start
+ 1, end
- start
- 1, compare_info_codepoint
, buffer
->pos
+ start
+ 1);
1471 * hb_buffer_normalize_glyphs:
1472 * @buffer: a buffer.
1479 hb_buffer_normalize_glyphs (hb_buffer_t
*buffer
)
1481 assert (buffer
->have_positions
);
1482 assert (buffer
->content_type
== HB_BUFFER_CONTENT_TYPE_GLYPHS
);
1484 bool backward
= HB_DIRECTION_IS_BACKWARD (buffer
->props
.direction
);
1486 unsigned int count
= buffer
->len
;
1487 if (unlikely (!count
)) return;
1488 hb_glyph_info_t
*info
= buffer
->info
;
1490 unsigned int start
= 0;
1492 for (end
= start
+ 1; end
< count
; end
++)
1493 if (info
[start
].cluster
!= info
[end
].cluster
) {
1494 normalize_glyphs_cluster (buffer
, start
, end
, backward
);
1497 normalize_glyphs_cluster (buffer
, start
, end
, backward
);