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 ();
181 flags
= HB_BUFFER_FLAG_DEFAULT
;
182 replacement
= HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT
;
188 hb_buffer_t::clear (void)
190 if (unlikely (hb_object_is_inert (this)))
193 hb_segment_properties_t default_props
= HB_SEGMENT_PROPERTIES_DEFAULT
;
194 props
= default_props
;
196 content_type
= HB_BUFFER_CONTENT_TYPE_INVALID
;
199 have_positions
= false;
207 memset (allocated_var_bytes
, 0, sizeof allocated_var_bytes
);
208 memset (allocated_var_owner
, 0, sizeof allocated_var_owner
);
210 memset (context
, 0, sizeof context
);
211 memset (context_len
, 0, sizeof context_len
);
215 hb_buffer_t::add (hb_codepoint_t codepoint
,
216 unsigned int cluster
)
218 hb_glyph_info_t
*glyph
;
220 if (unlikely (!ensure (len
+ 1))) return;
224 memset (glyph
, 0, sizeof (*glyph
));
225 glyph
->codepoint
= codepoint
;
227 glyph
->cluster
= cluster
;
233 hb_buffer_t::add_info (const hb_glyph_info_t
&glyph_info
)
235 if (unlikely (!ensure (len
+ 1))) return;
237 info
[len
] = glyph_info
;
244 hb_buffer_t::remove_output (void)
246 if (unlikely (hb_object_is_inert (this)))
250 have_positions
= false;
257 hb_buffer_t::clear_output (void)
259 if (unlikely (hb_object_is_inert (this)))
263 have_positions
= false;
270 hb_buffer_t::clear_positions (void)
272 if (unlikely (hb_object_is_inert (this)))
276 have_positions
= true;
281 memset (pos
, 0, sizeof (pos
[0]) * len
);
285 hb_buffer_t::swap_buffers (void)
287 if (unlikely (in_error
)) return;
289 assert (have_output
);
292 if (out_info
!= info
)
294 hb_glyph_info_t
*tmp_string
;
297 out_info
= tmp_string
;
298 pos
= (hb_glyph_position_t
*) out_info
;
311 hb_buffer_t::replace_glyphs (unsigned int num_in
,
312 unsigned int num_out
,
313 const uint32_t *glyph_data
)
315 if (unlikely (!make_room_for (num_in
, num_out
))) return;
317 merge_clusters (idx
, idx
+ num_in
);
319 hb_glyph_info_t orig_info
= info
[idx
];
320 hb_glyph_info_t
*pinfo
= &out_info
[out_len
];
321 for (unsigned int i
= 0; i
< num_out
; i
++)
324 pinfo
->codepoint
= glyph_data
[i
];
333 hb_buffer_t::output_glyph (hb_codepoint_t glyph_index
)
335 if (unlikely (!make_room_for (0, 1))) return;
337 out_info
[out_len
] = info
[idx
];
338 out_info
[out_len
].codepoint
= glyph_index
;
344 hb_buffer_t::output_info (const hb_glyph_info_t
&glyph_info
)
346 if (unlikely (!make_room_for (0, 1))) return;
348 out_info
[out_len
] = glyph_info
;
354 hb_buffer_t::copy_glyph (void)
356 if (unlikely (!make_room_for (0, 1))) return;
358 out_info
[out_len
] = info
[idx
];
364 hb_buffer_t::move_to (unsigned int i
)
373 assert (i
<= out_len
+ (len
- idx
));
377 unsigned int count
= i
- out_len
;
378 if (unlikely (!make_room_for (count
, count
))) return false;
380 memmove (out_info
+ out_len
, info
+ idx
, count
* sizeof (out_info
[0]));
384 else if (out_len
> i
)
386 /* Tricky part: rewinding... */
387 unsigned int count
= out_len
- i
;
389 if (unlikely (idx
< count
&& !shift_forward (count
+ 32))) return false;
391 assert (idx
>= count
);
395 memmove (info
+ idx
, out_info
+ out_len
, count
* sizeof (out_info
[0]));
402 hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index
)
404 if (unlikely (out_info
!= info
|| out_len
!= idx
)) {
405 if (unlikely (!make_room_for (1, 1))) return;
406 out_info
[out_len
] = info
[idx
];
408 out_info
[out_len
].codepoint
= glyph_index
;
416 hb_buffer_t::set_masks (hb_mask_t value
,
418 unsigned int cluster_start
,
419 unsigned int cluster_end
)
421 hb_mask_t not_mask
= ~mask
;
427 if (cluster_start
== 0 && cluster_end
== (unsigned int)-1) {
428 unsigned int count
= len
;
429 for (unsigned int i
= 0; i
< count
; i
++)
430 info
[i
].mask
= (info
[i
].mask
& not_mask
) | value
;
434 unsigned int count
= len
;
435 for (unsigned int i
= 0; i
< count
; i
++)
436 if (cluster_start
<= info
[i
].cluster
&& info
[i
].cluster
< cluster_end
)
437 info
[i
].mask
= (info
[i
].mask
& not_mask
) | value
;
441 hb_buffer_t::reverse_range (unsigned int start
,
449 for (i
= start
, j
= end
- 1; i
< j
; i
++, j
--) {
457 if (have_positions
) {
458 for (i
= start
, j
= end
- 1; i
< j
; i
++, j
--) {
459 hb_glyph_position_t t
;
469 hb_buffer_t::reverse (void)
474 reverse_range (0, len
);
478 hb_buffer_t::reverse_clusters (void)
480 unsigned int i
, start
, count
, last_cluster
;
489 last_cluster
= info
[0].cluster
;
490 for (i
= 1; i
< count
; i
++) {
491 if (last_cluster
!= info
[i
].cluster
) {
492 reverse_range (start
, i
);
494 last_cluster
= info
[i
].cluster
;
497 reverse_range (start
, i
);
501 hb_buffer_t::merge_clusters (unsigned int start
,
504 #ifdef HB_NO_MERGE_CLUSTERS
508 if (unlikely (end
- start
< 2))
511 unsigned int cluster
= info
[start
].cluster
;
513 for (unsigned int i
= start
+ 1; i
< end
; i
++)
514 cluster
= MIN (cluster
, info
[i
].cluster
);
517 while (end
< len
&& info
[end
- 1].cluster
== info
[end
].cluster
)
521 while (idx
< start
&& info
[start
- 1].cluster
== info
[start
].cluster
)
524 /* If we hit the start of buffer, continue in out-buffer. */
526 for (unsigned i
= out_len
; i
&& out_info
[i
- 1].cluster
== info
[start
].cluster
; i
--)
527 out_info
[i
- 1].cluster
= cluster
;
529 for (unsigned int i
= start
; i
< end
; i
++)
530 info
[i
].cluster
= cluster
;
533 hb_buffer_t::merge_out_clusters (unsigned int start
,
536 #ifdef HB_NO_MERGE_CLUSTERS
540 if (unlikely (end
- start
< 2))
543 unsigned int cluster
= out_info
[start
].cluster
;
545 for (unsigned int i
= start
+ 1; i
< end
; i
++)
546 cluster
= MIN (cluster
, out_info
[i
].cluster
);
549 while (start
&& out_info
[start
- 1].cluster
== out_info
[start
].cluster
)
553 while (end
< out_len
&& out_info
[end
- 1].cluster
== out_info
[end
].cluster
)
556 /* If we hit the end of out-buffer, continue in buffer. */
558 for (unsigned i
= idx
; i
< len
&& info
[i
].cluster
== out_info
[end
- 1].cluster
; i
++)
559 info
[i
].cluster
= cluster
;
561 for (unsigned int i
= start
; i
< end
; i
++)
562 out_info
[i
].cluster
= cluster
;
566 hb_buffer_t::guess_segment_properties (void)
568 assert (content_type
== HB_BUFFER_CONTENT_TYPE_UNICODE
||
569 (!len
&& content_type
== HB_BUFFER_CONTENT_TYPE_INVALID
));
571 /* If script is set to INVALID, guess from buffer contents */
572 if (props
.script
== HB_SCRIPT_INVALID
) {
573 for (unsigned int i
= 0; i
< len
; i
++) {
574 hb_script_t script
= unicode
->script (info
[i
].codepoint
);
575 if (likely (script
!= HB_SCRIPT_COMMON
&&
576 script
!= HB_SCRIPT_INHERITED
&&
577 script
!= HB_SCRIPT_UNKNOWN
)) {
578 props
.script
= script
;
584 /* If direction is set to INVALID, guess from script */
585 if (props
.direction
== HB_DIRECTION_INVALID
) {
586 props
.direction
= hb_script_get_horizontal_direction (props
.script
);
589 /* If language is not set, use default language from locale */
590 if (props
.language
== HB_LANGUAGE_INVALID
) {
591 /* TODO get_default_for_script? using $LANGUAGE */
592 props
.language
= hb_language_get_default ();
598 dump_var_allocation (const hb_buffer_t
*buffer
)
601 for (unsigned int i
= 0; i
< 8; i
++)
602 buf
[i
] = '0' + buffer
->allocated_var_bytes
[7 - i
];
604 DEBUG_MSG (BUFFER
, buffer
,
605 "Current var allocation: %s",
609 void hb_buffer_t::allocate_var (unsigned int byte_i
, unsigned int count
, const char *owner
)
611 assert (byte_i
< 8 && byte_i
+ count
<= 8);
613 if (DEBUG_ENABLED (BUFFER
))
614 dump_var_allocation (this);
615 DEBUG_MSG (BUFFER
, this,
616 "Allocating var bytes %d..%d for %s",
617 byte_i
, byte_i
+ count
- 1, owner
);
619 for (unsigned int i
= byte_i
; i
< byte_i
+ count
; i
++) {
620 assert (!allocated_var_bytes
[i
]);
621 allocated_var_bytes
[i
]++;
622 allocated_var_owner
[i
] = owner
;
626 void hb_buffer_t::deallocate_var (unsigned int byte_i
, unsigned int count
, const char *owner
)
628 if (DEBUG_ENABLED (BUFFER
))
629 dump_var_allocation (this);
631 DEBUG_MSG (BUFFER
, this,
632 "Deallocating var bytes %d..%d for %s",
633 byte_i
, byte_i
+ count
- 1, owner
);
635 assert (byte_i
< 8 && byte_i
+ count
<= 8);
636 for (unsigned int i
= byte_i
; i
< byte_i
+ count
; i
++) {
637 assert (allocated_var_bytes
[i
]);
638 assert (0 == strcmp (allocated_var_owner
[i
], owner
));
639 allocated_var_bytes
[i
]--;
643 void hb_buffer_t::assert_var (unsigned int byte_i
, unsigned int count
, const char *owner
)
645 if (DEBUG_ENABLED (BUFFER
))
646 dump_var_allocation (this);
648 DEBUG_MSG (BUFFER
, this,
649 "Asserting var bytes %d..%d for %s",
650 byte_i
, byte_i
+ count
- 1, owner
);
652 assert (byte_i
< 8 && byte_i
+ count
<= 8);
653 for (unsigned int i
= byte_i
; i
< byte_i
+ count
; i
++) {
654 assert (allocated_var_bytes
[i
]);
655 assert (0 == strcmp (allocated_var_owner
[i
], owner
));
659 void hb_buffer_t::deallocate_var_all (void)
661 memset (allocated_var_bytes
, 0, sizeof (allocated_var_bytes
));
662 memset (allocated_var_owner
, 0, sizeof (allocated_var_owner
));
668 * hb_buffer_create: (Xconstructor)
672 * Return value: (transfer full)
677 hb_buffer_create (void)
681 if (!(buffer
= hb_object_create
<hb_buffer_t
> ()))
682 return hb_buffer_get_empty ();
690 * hb_buffer_get_empty:
694 * Return value: (transfer full):
699 hb_buffer_get_empty (void)
701 static const hb_buffer_t _hb_buffer_nil
= {
702 HB_OBJECT_HEADER_STATIC
,
704 const_cast<hb_unicode_funcs_t
*> (&_hb_unicode_funcs_nil
),
705 HB_BUFFER_FLAG_DEFAULT
,
706 HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT
,
708 HB_BUFFER_CONTENT_TYPE_INVALID
,
709 HB_SEGMENT_PROPERTIES_DEFAULT
,
711 true, /* have_output */
712 true /* have_positions */
714 /* Zero is good enough for everything else. */
717 return const_cast<hb_buffer_t
*> (&_hb_buffer_nil
);
721 * hb_buffer_reference: (skip)
726 * Return value: (transfer full):
731 hb_buffer_reference (hb_buffer_t
*buffer
)
733 return hb_object_reference (buffer
);
737 * hb_buffer_destroy: (skip)
745 hb_buffer_destroy (hb_buffer_t
*buffer
)
747 if (!hb_object_destroy (buffer
)) return;
749 hb_unicode_funcs_destroy (buffer
->unicode
);
758 * hb_buffer_set_user_data: (skip)
772 hb_buffer_set_user_data (hb_buffer_t
*buffer
,
773 hb_user_data_key_t
*key
,
775 hb_destroy_func_t destroy
,
778 return hb_object_set_user_data (buffer
, key
, data
, destroy
, replace
);
782 * hb_buffer_get_user_data: (skip)
793 hb_buffer_get_user_data (hb_buffer_t
*buffer
,
794 hb_user_data_key_t
*key
)
796 return hb_object_get_user_data (buffer
, key
);
801 * hb_buffer_set_content_type:
810 hb_buffer_set_content_type (hb_buffer_t
*buffer
,
811 hb_buffer_content_type_t content_type
)
813 buffer
->content_type
= content_type
;
817 * hb_buffer_get_content_type:
826 hb_buffer_content_type_t
827 hb_buffer_get_content_type (hb_buffer_t
*buffer
)
829 return buffer
->content_type
;
834 * hb_buffer_set_unicode_funcs:
843 hb_buffer_set_unicode_funcs (hb_buffer_t
*buffer
,
844 hb_unicode_funcs_t
*unicode_funcs
)
846 if (unlikely (hb_object_is_inert (buffer
)))
850 unicode_funcs
= hb_unicode_funcs_get_default ();
853 hb_unicode_funcs_reference (unicode_funcs
);
854 hb_unicode_funcs_destroy (buffer
->unicode
);
855 buffer
->unicode
= unicode_funcs
;
859 * hb_buffer_get_unicode_funcs:
869 hb_buffer_get_unicode_funcs (hb_buffer_t
*buffer
)
871 return buffer
->unicode
;
875 * hb_buffer_set_direction:
884 hb_buffer_set_direction (hb_buffer_t
*buffer
,
885 hb_direction_t direction
)
888 if (unlikely (hb_object_is_inert (buffer
)))
891 buffer
->props
.direction
= direction
;
895 * hb_buffer_get_direction:
905 hb_buffer_get_direction (hb_buffer_t
*buffer
)
907 return buffer
->props
.direction
;
911 * hb_buffer_set_script:
920 hb_buffer_set_script (hb_buffer_t
*buffer
,
923 if (unlikely (hb_object_is_inert (buffer
)))
926 buffer
->props
.script
= script
;
930 * hb_buffer_get_script:
940 hb_buffer_get_script (hb_buffer_t
*buffer
)
942 return buffer
->props
.script
;
946 * hb_buffer_set_language:
955 hb_buffer_set_language (hb_buffer_t
*buffer
,
956 hb_language_t language
)
958 if (unlikely (hb_object_is_inert (buffer
)))
961 buffer
->props
.language
= language
;
965 * hb_buffer_get_language:
975 hb_buffer_get_language (hb_buffer_t
*buffer
)
977 return buffer
->props
.language
;
981 * hb_buffer_set_segment_properties:
990 hb_buffer_set_segment_properties (hb_buffer_t
*buffer
,
991 const hb_segment_properties_t
*props
)
993 if (unlikely (hb_object_is_inert (buffer
)))
996 buffer
->props
= *props
;
1000 * hb_buffer_get_segment_properties:
1001 * @buffer: a buffer.
1009 hb_buffer_get_segment_properties (hb_buffer_t
*buffer
,
1010 hb_segment_properties_t
*props
)
1012 *props
= buffer
->props
;
1017 * hb_buffer_set_flags:
1018 * @buffer: a buffer.
1026 hb_buffer_set_flags (hb_buffer_t
*buffer
,
1027 hb_buffer_flags_t flags
)
1029 if (unlikely (hb_object_is_inert (buffer
)))
1032 buffer
->flags
= flags
;
1036 * hb_buffer_get_flags:
1037 * @buffer: a buffer.
1046 hb_buffer_get_flags (hb_buffer_t
*buffer
)
1048 return buffer
->flags
;
1053 * hb_buffer_set_replacement_codepoint:
1054 * @buffer: a buffer.
1062 hb_buffer_set_replacement_codepoint (hb_buffer_t
*buffer
,
1063 hb_codepoint_t replacement
)
1065 if (unlikely (hb_object_is_inert (buffer
)))
1068 buffer
->replacement
= replacement
;
1072 * hb_buffer_get_replacement_codepoint:
1073 * @buffer: a buffer.
1082 hb_buffer_get_replacement_codepoint (hb_buffer_t
*buffer
)
1084 return buffer
->replacement
;
1090 * @buffer: a buffer.
1097 hb_buffer_reset (hb_buffer_t
*buffer
)
1103 * hb_buffer_clear_contents:
1104 * @buffer: a buffer.
1111 hb_buffer_clear_contents (hb_buffer_t
*buffer
)
1117 * hb_buffer_pre_allocate:
1118 * @buffer: a buffer.
1128 hb_buffer_pre_allocate (hb_buffer_t
*buffer
, unsigned int size
)
1130 return buffer
->ensure (size
);
1134 * hb_buffer_allocation_successful:
1135 * @buffer: a buffer.
1144 hb_buffer_allocation_successful (hb_buffer_t
*buffer
)
1146 return !buffer
->in_error
;
1151 * @buffer: a buffer.
1160 hb_buffer_add (hb_buffer_t
*buffer
,
1161 hb_codepoint_t codepoint
,
1162 unsigned int cluster
)
1164 buffer
->add (codepoint
, cluster
);
1165 buffer
->clear_context (1);
1169 * hb_buffer_set_length:
1170 * @buffer: a buffer.
1180 hb_buffer_set_length (hb_buffer_t
*buffer
,
1181 unsigned int length
)
1183 if (unlikely (hb_object_is_inert (buffer
)))
1186 if (!buffer
->ensure (length
))
1189 /* Wipe the new space */
1190 if (length
> buffer
->len
) {
1191 memset (buffer
->info
+ buffer
->len
, 0, sizeof (buffer
->info
[0]) * (length
- buffer
->len
));
1192 if (buffer
->have_positions
)
1193 memset (buffer
->pos
+ buffer
->len
, 0, sizeof (buffer
->pos
[0]) * (length
- buffer
->len
));
1196 buffer
->len
= length
;
1200 buffer
->content_type
= HB_BUFFER_CONTENT_TYPE_INVALID
;
1201 buffer
->clear_context (0);
1203 buffer
->clear_context (1);
1209 * hb_buffer_get_length:
1210 * @buffer: a buffer.
1212 * Returns the number of items in the buffer.
1214 * Return value: buffer length.
1219 hb_buffer_get_length (hb_buffer_t
*buffer
)
1225 * hb_buffer_get_glyph_infos:
1226 * @buffer: a buffer.
1227 * @length: (out): output array length.
1229 * Returns buffer glyph information array. Returned pointer
1230 * is valid as long as buffer contents are not modified.
1232 * Return value: (transfer none) (array length=length): buffer glyph information array.
1237 hb_buffer_get_glyph_infos (hb_buffer_t
*buffer
,
1238 unsigned int *length
)
1241 *length
= buffer
->len
;
1243 return (hb_glyph_info_t
*) buffer
->info
;
1247 * hb_buffer_get_glyph_positions:
1248 * @buffer: a buffer.
1249 * @length: (out): output length.
1251 * Returns buffer glyph position array. Returned pointer
1252 * is valid as long as buffer contents are not modified.
1254 * Return value: (transfer none) (array length=length): buffer glyph position array.
1258 hb_glyph_position_t
*
1259 hb_buffer_get_glyph_positions (hb_buffer_t
*buffer
,
1260 unsigned int *length
)
1262 if (!buffer
->have_positions
)
1263 buffer
->clear_positions ();
1266 *length
= buffer
->len
;
1268 return (hb_glyph_position_t
*) buffer
->pos
;
1272 * hb_buffer_reverse:
1273 * @buffer: a buffer.
1275 * Reverses buffer contents.
1280 hb_buffer_reverse (hb_buffer_t
*buffer
)
1286 * hb_buffer_reverse_clusters:
1287 * @buffer: a buffer.
1289 * Reverses buffer clusters. That is, the buffer contents are
1290 * reversed, then each cluster (consecutive items having the
1291 * same cluster number) are reversed again.
1296 hb_buffer_reverse_clusters (hb_buffer_t
*buffer
)
1298 buffer
->reverse_clusters ();
1302 * hb_buffer_guess_segment_properties:
1303 * @buffer: a buffer.
1305 * Sets unset buffer segment properties based on buffer Unicode
1306 * contents. If buffer is not empty, it must have content type
1307 * %HB_BUFFER_CONTENT_TYPE_UNICODE.
1309 * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
1310 * will be set to the Unicode script of the first character in
1311 * the buffer that has a script other than %HB_SCRIPT_COMMON,
1312 * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
1314 * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
1315 * it will be set to the natural horizontal direction of the
1316 * buffer script as returned by hb_script_get_horizontal_direction().
1318 * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
1319 * it will be set to the process's default language as returned by
1320 * hb_language_get_default(). This may change in the future by
1321 * taking buffer script into consideration when choosing a language.
1326 hb_buffer_guess_segment_properties (hb_buffer_t
*buffer
)
1328 buffer
->guess_segment_properties ();
1331 template <typename utf_t
>
1333 hb_buffer_add_utf (hb_buffer_t
*buffer
,
1334 const typename
utf_t::codepoint_t
*text
,
1336 unsigned int item_offset
,
1339 typedef typename
utf_t::codepoint_t T
;
1340 const hb_codepoint_t replacement
= buffer
->replacement
;
1342 assert (buffer
->content_type
== HB_BUFFER_CONTENT_TYPE_UNICODE
||
1343 (!buffer
->len
&& buffer
->content_type
== HB_BUFFER_CONTENT_TYPE_INVALID
));
1345 if (unlikely (hb_object_is_inert (buffer
)))
1348 if (text_length
== -1)
1349 text_length
= utf_t::strlen (text
);
1351 if (item_length
== -1)
1352 item_length
= text_length
- item_offset
;
1354 buffer
->ensure (buffer
->len
+ item_length
* sizeof (T
) / 4);
1356 /* If buffer is empty and pre-context provided, install it.
1357 * This check is written this way, to make sure people can
1358 * provide pre-context in one add_utf() call, then provide
1359 * text in a follow-up call. See:
1361 * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
1363 if (!buffer
->len
&& item_offset
> 0)
1365 /* Add pre-context */
1366 buffer
->clear_context (0);
1367 const T
*prev
= text
+ item_offset
;
1368 const T
*start
= text
;
1369 while (start
< prev
&& buffer
->context_len
[0] < buffer
->CONTEXT_LENGTH
)
1372 prev
= utf_t::prev (prev
, start
, &u
, replacement
);
1373 buffer
->context
[0][buffer
->context_len
[0]++] = u
;
1377 const T
*next
= text
+ item_offset
;
1378 const T
*end
= next
+ item_length
;
1382 const T
*old_next
= next
;
1383 next
= utf_t::next (next
, end
, &u
, replacement
);
1384 buffer
->add (u
, old_next
- (const T
*) text
);
1387 /* Add post-context */
1388 buffer
->clear_context (1);
1389 end
= text
+ text_length
;
1390 while (next
< end
&& buffer
->context_len
[1] < buffer
->CONTEXT_LENGTH
)
1393 next
= utf_t::next (next
, end
, &u
, replacement
);
1394 buffer
->context
[1][buffer
->context_len
[1]++] = u
;
1397 buffer
->content_type
= HB_BUFFER_CONTENT_TYPE_UNICODE
;
1401 * hb_buffer_add_utf8:
1402 * @buffer: a buffer.
1403 * @text: (array length=text_length) (element-type uint8_t):
1413 hb_buffer_add_utf8 (hb_buffer_t
*buffer
,
1416 unsigned int item_offset
,
1419 hb_buffer_add_utf
<hb_utf8_t
> (buffer
, (const uint8_t *) text
, text_length
, item_offset
, item_length
);
1423 * hb_buffer_add_utf16:
1424 * @buffer: a buffer.
1425 * @text: (array length=text_length):
1435 hb_buffer_add_utf16 (hb_buffer_t
*buffer
,
1436 const uint16_t *text
,
1438 unsigned int item_offset
,
1441 hb_buffer_add_utf
<hb_utf16_t
> (buffer
, text
, text_length
, item_offset
, item_length
);
1445 * hb_buffer_add_utf32:
1446 * @buffer: a buffer.
1447 * @text: (array length=text_length):
1457 hb_buffer_add_utf32 (hb_buffer_t
*buffer
,
1458 const uint32_t *text
,
1460 unsigned int item_offset
,
1463 hb_buffer_add_utf
<hb_utf32_t
<> > (buffer
, text
, text_length
, item_offset
, item_length
);
1467 * hb_buffer_add_latin1:
1468 * @buffer: a buffer.
1469 * @text: (array length=text_length) (element-type uint8_t):
1479 hb_buffer_add_latin1 (hb_buffer_t
*buffer
,
1480 const uint8_t *text
,
1482 unsigned int item_offset
,
1485 hb_buffer_add_utf
<hb_latin1_t
> (buffer
, text
, text_length
, item_offset
, item_length
);
1489 * hb_buffer_add_codepoints:
1490 * @buffer: a buffer.
1491 * @text: (array length=text_length):
1501 hb_buffer_add_codepoints (hb_buffer_t
*buffer
,
1502 const hb_codepoint_t
*text
,
1504 unsigned int item_offset
,
1507 hb_buffer_add_utf
<hb_utf32_t
<false> > (buffer
, text
, text_length
, item_offset
, item_length
);
1512 compare_info_codepoint (const hb_glyph_info_t
*pa
,
1513 const hb_glyph_info_t
*pb
)
1515 return (int) pb
->codepoint
- (int) pa
->codepoint
;
1519 normalize_glyphs_cluster (hb_buffer_t
*buffer
,
1524 hb_glyph_position_t
*pos
= buffer
->pos
;
1526 /* Total cluster advance */
1527 hb_position_t total_x_advance
= 0, total_y_advance
= 0;
1528 for (unsigned int i
= start
; i
< end
; i
++)
1530 total_x_advance
+= pos
[i
].x_advance
;
1531 total_y_advance
+= pos
[i
].y_advance
;
1534 hb_position_t x_advance
= 0, y_advance
= 0;
1535 for (unsigned int i
= start
; i
< end
; i
++)
1537 pos
[i
].x_offset
+= x_advance
;
1538 pos
[i
].y_offset
+= y_advance
;
1540 x_advance
+= pos
[i
].x_advance
;
1541 y_advance
+= pos
[i
].y_advance
;
1543 pos
[i
].x_advance
= 0;
1544 pos
[i
].y_advance
= 0;
1549 /* Transfer all cluster advance to the last glyph. */
1550 pos
[end
- 1].x_advance
= total_x_advance
;
1551 pos
[end
- 1].y_advance
= total_y_advance
;
1553 hb_bubble_sort (buffer
->info
+ start
, end
- start
- 1, compare_info_codepoint
, buffer
->pos
+ start
);
1555 /* Transfer all cluster advance to the first glyph. */
1556 pos
[start
].x_advance
+= total_x_advance
;
1557 pos
[start
].y_advance
+= total_y_advance
;
1558 for (unsigned int i
= start
+ 1; i
< end
; i
++) {
1559 pos
[i
].x_offset
-= total_x_advance
;
1560 pos
[i
].y_offset
-= total_y_advance
;
1562 hb_bubble_sort (buffer
->info
+ start
+ 1, end
- start
- 1, compare_info_codepoint
, buffer
->pos
+ start
+ 1);
1567 * hb_buffer_normalize_glyphs:
1568 * @buffer: a buffer.
1575 hb_buffer_normalize_glyphs (hb_buffer_t
*buffer
)
1577 assert (buffer
->have_positions
);
1578 assert (buffer
->content_type
== HB_BUFFER_CONTENT_TYPE_GLYPHS
);
1580 bool backward
= HB_DIRECTION_IS_BACKWARD (buffer
->props
.direction
);
1582 unsigned int count
= buffer
->len
;
1583 if (unlikely (!count
)) return;
1584 hb_glyph_info_t
*info
= buffer
->info
;
1586 unsigned int start
= 0;
1588 for (end
= start
+ 1; end
< count
; end
++)
1589 if (info
[start
].cluster
!= info
[end
].cluster
) {
1590 normalize_glyphs_cluster (buffer
, start
, end
, backward
);
1593 normalize_glyphs_cluster (buffer
, start
, end
, backward
);