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::get_scratch_buffer (unsigned int *size
)
146 have_positions
= false;
151 *size
= allocated
* sizeof (pos
[0]);
157 /* HarfBuzz-Internal API */
160 hb_buffer_t::reset (void)
162 if (unlikely (hb_object_is_inert (this)))
165 hb_unicode_funcs_destroy (unicode
);
166 unicode
= hb_unicode_funcs_get_default ();
172 hb_buffer_t::clear (void)
174 if (unlikely (hb_object_is_inert (this)))
177 hb_segment_properties_t default_props
= HB_SEGMENT_PROPERTIES_DEFAULT
;
178 props
= default_props
;
179 flags
= HB_BUFFER_FLAGS_DEFAULT
;
181 content_type
= HB_BUFFER_CONTENT_TYPE_INVALID
;
184 have_positions
= false;
192 memset (allocated_var_bytes
, 0, sizeof allocated_var_bytes
);
193 memset (allocated_var_owner
, 0, sizeof allocated_var_owner
);
195 memset (context
, 0, sizeof context
);
196 memset (context_len
, 0, sizeof context_len
);
200 hb_buffer_t::add (hb_codepoint_t codepoint
,
201 unsigned int cluster
)
203 hb_glyph_info_t
*glyph
;
205 if (unlikely (!ensure (len
+ 1))) return;
209 memset (glyph
, 0, sizeof (*glyph
));
210 glyph
->codepoint
= codepoint
;
212 glyph
->cluster
= cluster
;
218 hb_buffer_t::add_info (const hb_glyph_info_t
&glyph_info
)
220 if (unlikely (!ensure (len
+ 1))) return;
222 info
[len
] = glyph_info
;
229 hb_buffer_t::remove_output (void)
231 if (unlikely (hb_object_is_inert (this)))
235 have_positions
= false;
242 hb_buffer_t::clear_output (void)
244 if (unlikely (hb_object_is_inert (this)))
248 have_positions
= false;
255 hb_buffer_t::clear_positions (void)
257 if (unlikely (hb_object_is_inert (this)))
261 have_positions
= true;
266 memset (pos
, 0, sizeof (pos
[0]) * len
);
270 hb_buffer_t::swap_buffers (void)
272 if (unlikely (in_error
)) return;
274 assert (have_output
);
277 if (out_info
!= info
)
279 hb_glyph_info_t
*tmp_string
;
282 out_info
= tmp_string
;
283 pos
= (hb_glyph_position_t
*) out_info
;
296 hb_buffer_t::replace_glyphs (unsigned int num_in
,
297 unsigned int num_out
,
298 const uint32_t *glyph_data
)
300 if (unlikely (!make_room_for (num_in
, num_out
))) return;
302 merge_clusters (idx
, idx
+ num_in
);
304 hb_glyph_info_t orig_info
= info
[idx
];
305 hb_glyph_info_t
*pinfo
= &out_info
[out_len
];
306 for (unsigned int i
= 0; i
< num_out
; i
++)
309 pinfo
->codepoint
= glyph_data
[i
];
318 hb_buffer_t::output_glyph (hb_codepoint_t glyph_index
)
320 if (unlikely (!make_room_for (0, 1))) return;
322 out_info
[out_len
] = info
[idx
];
323 out_info
[out_len
].codepoint
= glyph_index
;
329 hb_buffer_t::output_info (const hb_glyph_info_t
&glyph_info
)
331 if (unlikely (!make_room_for (0, 1))) return;
333 out_info
[out_len
] = glyph_info
;
339 hb_buffer_t::copy_glyph (void)
341 if (unlikely (!make_room_for (0, 1))) return;
343 out_info
[out_len
] = info
[idx
];
349 hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index
)
351 if (unlikely (out_info
!= info
|| out_len
!= idx
)) {
352 if (unlikely (!make_room_for (1, 1))) return;
353 out_info
[out_len
] = info
[idx
];
355 out_info
[out_len
].codepoint
= glyph_index
;
363 hb_buffer_t::set_masks (hb_mask_t value
,
365 unsigned int cluster_start
,
366 unsigned int cluster_end
)
368 hb_mask_t not_mask
= ~mask
;
374 if (cluster_start
== 0 && cluster_end
== (unsigned int)-1) {
375 unsigned int count
= len
;
376 for (unsigned int i
= 0; i
< count
; i
++)
377 info
[i
].mask
= (info
[i
].mask
& not_mask
) | value
;
381 unsigned int count
= len
;
382 for (unsigned int i
= 0; i
< count
; i
++)
383 if (cluster_start
<= info
[i
].cluster
&& info
[i
].cluster
< cluster_end
)
384 info
[i
].mask
= (info
[i
].mask
& not_mask
) | value
;
388 hb_buffer_t::reverse_range (unsigned int start
,
393 if (start
== end
- 1)
396 for (i
= start
, j
= end
- 1; i
< j
; i
++, j
--) {
405 for (i
= start
, j
= end
- 1; i
< j
; i
++, j
--) {
406 hb_glyph_position_t t
;
416 hb_buffer_t::reverse (void)
421 reverse_range (0, len
);
425 hb_buffer_t::reverse_clusters (void)
427 unsigned int i
, start
, count
, last_cluster
;
436 last_cluster
= info
[0].cluster
;
437 for (i
= 1; i
< count
; i
++) {
438 if (last_cluster
!= info
[i
].cluster
) {
439 reverse_range (start
, i
);
441 last_cluster
= info
[i
].cluster
;
444 reverse_range (start
, i
);
448 hb_buffer_t::merge_clusters (unsigned int start
,
451 if (unlikely (end
- start
< 2))
454 unsigned int cluster
= info
[start
].cluster
;
456 for (unsigned int i
= start
+ 1; i
< end
; i
++)
457 cluster
= MIN (cluster
, info
[i
].cluster
);
460 while (end
< len
&& info
[end
- 1].cluster
== info
[end
].cluster
)
464 while (idx
< start
&& info
[start
- 1].cluster
== info
[start
].cluster
)
467 /* If we hit the start of buffer, continue in out-buffer. */
469 for (unsigned i
= out_len
; i
&& out_info
[i
- 1].cluster
== info
[start
].cluster
; i
--)
470 out_info
[i
- 1].cluster
= cluster
;
472 for (unsigned int i
= start
; i
< end
; i
++)
473 info
[i
].cluster
= cluster
;
476 hb_buffer_t::merge_out_clusters (unsigned int start
,
479 if (unlikely (end
- start
< 2))
482 unsigned int cluster
= out_info
[start
].cluster
;
484 for (unsigned int i
= start
+ 1; i
< end
; i
++)
485 cluster
= MIN (cluster
, out_info
[i
].cluster
);
488 while (start
&& out_info
[start
- 1].cluster
== out_info
[start
].cluster
)
492 while (end
< out_len
&& out_info
[end
- 1].cluster
== out_info
[end
].cluster
)
495 /* If we hit the end of out-buffer, continue in buffer. */
497 for (unsigned i
= idx
; i
< len
&& info
[i
].cluster
== out_info
[end
- 1].cluster
; i
++)
498 info
[i
].cluster
= cluster
;
500 for (unsigned int i
= start
; i
< end
; i
++)
501 out_info
[i
].cluster
= cluster
;
505 hb_buffer_t::guess_segment_properties (void)
507 assert (content_type
== HB_BUFFER_CONTENT_TYPE_UNICODE
||
508 (!len
&& content_type
== HB_BUFFER_CONTENT_TYPE_INVALID
));
510 /* If script is set to INVALID, guess from buffer contents */
511 if (props
.script
== HB_SCRIPT_INVALID
) {
512 for (unsigned int i
= 0; i
< len
; i
++) {
513 hb_script_t script
= unicode
->script (info
[i
].codepoint
);
514 if (likely (script
!= HB_SCRIPT_COMMON
&&
515 script
!= HB_SCRIPT_INHERITED
&&
516 script
!= HB_SCRIPT_UNKNOWN
)) {
517 props
.script
= script
;
523 /* If direction is set to INVALID, guess from script */
524 if (props
.direction
== HB_DIRECTION_INVALID
) {
525 props
.direction
= hb_script_get_horizontal_direction (props
.script
);
528 /* If language is not set, use default language from locale */
529 if (props
.language
== HB_LANGUAGE_INVALID
) {
530 /* TODO get_default_for_script? using $LANGUAGE */
531 props
.language
= hb_language_get_default ();
537 dump_var_allocation (const hb_buffer_t
*buffer
)
540 for (unsigned int i
= 0; i
< 8; i
++)
541 buf
[i
] = '0' + buffer
->allocated_var_bytes
[7 - i
];
543 DEBUG_MSG (BUFFER
, buffer
,
544 "Current var allocation: %s",
548 void hb_buffer_t::allocate_var (unsigned int byte_i
, unsigned int count
, const char *owner
)
550 assert (byte_i
< 8 && byte_i
+ count
<= 8);
552 if (DEBUG_ENABLED (BUFFER
))
553 dump_var_allocation (this);
554 DEBUG_MSG (BUFFER
, this,
555 "Allocating var bytes %d..%d for %s",
556 byte_i
, byte_i
+ count
- 1, owner
);
558 for (unsigned int i
= byte_i
; i
< byte_i
+ count
; i
++) {
559 assert (!allocated_var_bytes
[i
]);
560 allocated_var_bytes
[i
]++;
561 allocated_var_owner
[i
] = owner
;
565 void hb_buffer_t::deallocate_var (unsigned int byte_i
, unsigned int count
, const char *owner
)
567 if (DEBUG_ENABLED (BUFFER
))
568 dump_var_allocation (this);
570 DEBUG_MSG (BUFFER
, this,
571 "Deallocating var bytes %d..%d for %s",
572 byte_i
, byte_i
+ count
- 1, owner
);
574 assert (byte_i
< 8 && byte_i
+ count
<= 8);
575 for (unsigned int i
= byte_i
; i
< byte_i
+ count
; i
++) {
576 assert (allocated_var_bytes
[i
]);
577 assert (0 == strcmp (allocated_var_owner
[i
], owner
));
578 allocated_var_bytes
[i
]--;
582 void hb_buffer_t::assert_var (unsigned int byte_i
, unsigned int count
, const char *owner
)
584 if (DEBUG_ENABLED (BUFFER
))
585 dump_var_allocation (this);
587 DEBUG_MSG (BUFFER
, this,
588 "Asserting var bytes %d..%d for %s",
589 byte_i
, byte_i
+ count
- 1, owner
);
591 assert (byte_i
< 8 && byte_i
+ count
<= 8);
592 for (unsigned int i
= byte_i
; i
< byte_i
+ count
; i
++) {
593 assert (allocated_var_bytes
[i
]);
594 assert (0 == strcmp (allocated_var_owner
[i
], owner
));
598 void hb_buffer_t::deallocate_var_all (void)
600 memset (allocated_var_bytes
, 0, sizeof (allocated_var_bytes
));
601 memset (allocated_var_owner
, 0, sizeof (allocated_var_owner
));
607 hb_buffer_create (void)
611 if (!(buffer
= hb_object_create
<hb_buffer_t
> ()))
612 return hb_buffer_get_empty ();
620 hb_buffer_get_empty (void)
622 static const hb_buffer_t _hb_buffer_nil
= {
623 HB_OBJECT_HEADER_STATIC
,
625 const_cast<hb_unicode_funcs_t
*> (&_hb_unicode_funcs_nil
),
626 HB_SEGMENT_PROPERTIES_DEFAULT
,
627 HB_BUFFER_FLAGS_DEFAULT
,
629 HB_BUFFER_CONTENT_TYPE_INVALID
,
631 true, /* have_output */
632 true /* have_positions */
634 /* Zero is good enough for everything else. */
637 return const_cast<hb_buffer_t
*> (&_hb_buffer_nil
);
641 hb_buffer_reference (hb_buffer_t
*buffer
)
643 return hb_object_reference (buffer
);
647 hb_buffer_destroy (hb_buffer_t
*buffer
)
649 if (!hb_object_destroy (buffer
)) return;
651 hb_unicode_funcs_destroy (buffer
->unicode
);
660 hb_buffer_set_user_data (hb_buffer_t
*buffer
,
661 hb_user_data_key_t
*key
,
663 hb_destroy_func_t destroy
,
666 return hb_object_set_user_data (buffer
, key
, data
, destroy
, replace
);
670 hb_buffer_get_user_data (hb_buffer_t
*buffer
,
671 hb_user_data_key_t
*key
)
673 return hb_object_get_user_data (buffer
, key
);
678 hb_buffer_set_content_type (hb_buffer_t
*buffer
,
679 hb_buffer_content_type_t content_type
)
681 buffer
->content_type
= content_type
;
684 hb_buffer_content_type_t
685 hb_buffer_get_content_type (hb_buffer_t
*buffer
)
687 return buffer
->content_type
;
692 hb_buffer_set_unicode_funcs (hb_buffer_t
*buffer
,
693 hb_unicode_funcs_t
*unicode
)
695 if (unlikely (hb_object_is_inert (buffer
)))
699 unicode
= hb_unicode_funcs_get_default ();
702 hb_unicode_funcs_reference (unicode
);
703 hb_unicode_funcs_destroy (buffer
->unicode
);
704 buffer
->unicode
= unicode
;
708 hb_buffer_get_unicode_funcs (hb_buffer_t
*buffer
)
710 return buffer
->unicode
;
714 hb_buffer_set_direction (hb_buffer_t
*buffer
,
715 hb_direction_t direction
)
718 if (unlikely (hb_object_is_inert (buffer
)))
721 buffer
->props
.direction
= direction
;
725 hb_buffer_get_direction (hb_buffer_t
*buffer
)
727 return buffer
->props
.direction
;
731 hb_buffer_set_script (hb_buffer_t
*buffer
,
734 if (unlikely (hb_object_is_inert (buffer
)))
737 buffer
->props
.script
= script
;
741 hb_buffer_get_script (hb_buffer_t
*buffer
)
743 return buffer
->props
.script
;
747 hb_buffer_set_language (hb_buffer_t
*buffer
,
748 hb_language_t language
)
750 if (unlikely (hb_object_is_inert (buffer
)))
753 buffer
->props
.language
= language
;
757 hb_buffer_get_language (hb_buffer_t
*buffer
)
759 return buffer
->props
.language
;
763 hb_buffer_set_segment_properties (hb_buffer_t
*buffer
,
764 const hb_segment_properties_t
*props
)
766 if (unlikely (hb_object_is_inert (buffer
)))
769 buffer
->props
= *props
;
773 hb_buffer_get_segment_properties (hb_buffer_t
*buffer
,
774 hb_segment_properties_t
*props
)
776 *props
= buffer
->props
;
781 hb_buffer_set_flags (hb_buffer_t
*buffer
,
782 hb_buffer_flags_t flags
)
784 if (unlikely (hb_object_is_inert (buffer
)))
787 buffer
->flags
= flags
;
791 hb_buffer_get_flags (hb_buffer_t
*buffer
)
793 return buffer
->flags
;
798 hb_buffer_reset (hb_buffer_t
*buffer
)
804 hb_buffer_clear_contents (hb_buffer_t
*buffer
)
810 hb_buffer_pre_allocate (hb_buffer_t
*buffer
, unsigned int size
)
812 return buffer
->ensure (size
);
816 hb_buffer_allocation_successful (hb_buffer_t
*buffer
)
818 return !buffer
->in_error
;
822 hb_buffer_add (hb_buffer_t
*buffer
,
823 hb_codepoint_t codepoint
,
824 unsigned int cluster
)
826 buffer
->add (codepoint
, cluster
);
827 buffer
->clear_context (1);
831 hb_buffer_set_length (hb_buffer_t
*buffer
,
834 if (unlikely (hb_object_is_inert (buffer
)))
837 if (!buffer
->ensure (length
))
840 /* Wipe the new space */
841 if (length
> buffer
->len
) {
842 memset (buffer
->info
+ buffer
->len
, 0, sizeof (buffer
->info
[0]) * (length
- buffer
->len
));
843 if (buffer
->have_positions
)
844 memset (buffer
->pos
+ buffer
->len
, 0, sizeof (buffer
->pos
[0]) * (length
- buffer
->len
));
847 buffer
->len
= length
;
850 buffer
->clear_context (0);
851 buffer
->clear_context (1);
857 hb_buffer_get_length (hb_buffer_t
*buffer
)
862 /* Return value valid as long as buffer not modified */
864 hb_buffer_get_glyph_infos (hb_buffer_t
*buffer
,
865 unsigned int *length
)
868 *length
= buffer
->len
;
870 return (hb_glyph_info_t
*) buffer
->info
;
873 /* Return value valid as long as buffer not modified */
874 hb_glyph_position_t
*
875 hb_buffer_get_glyph_positions (hb_buffer_t
*buffer
,
876 unsigned int *length
)
878 if (!buffer
->have_positions
)
879 buffer
->clear_positions ();
882 *length
= buffer
->len
;
884 return (hb_glyph_position_t
*) buffer
->pos
;
888 hb_buffer_reverse (hb_buffer_t
*buffer
)
894 hb_buffer_reverse_clusters (hb_buffer_t
*buffer
)
896 buffer
->reverse_clusters ();
900 hb_buffer_guess_segment_properties (hb_buffer_t
*buffer
)
902 buffer
->guess_segment_properties ();
905 template <typename T
>
907 hb_buffer_add_utf (hb_buffer_t
*buffer
,
910 unsigned int item_offset
,
913 assert (buffer
->content_type
== HB_BUFFER_CONTENT_TYPE_UNICODE
||
914 (!buffer
->len
&& buffer
->content_type
== HB_BUFFER_CONTENT_TYPE_INVALID
));
916 if (unlikely (hb_object_is_inert (buffer
)))
919 if (text_length
== -1)
920 text_length
= hb_utf_strlen (text
);
922 if (item_length
== -1)
923 item_length
= text_length
- item_offset
;
925 buffer
->ensure (buffer
->len
+ item_length
* sizeof (T
) / 4);
927 /* If buffer is empty and pre-context provided, install it.
928 * This check is written this way, to make sure people can
929 * provide pre-context in one add_utf() call, then provide
930 * text in a follow-up call. See:
932 * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
934 if (!buffer
->len
&& item_offset
> 0)
936 /* Add pre-context */
937 buffer
->clear_context (0);
938 const T
*prev
= text
+ item_offset
;
939 const T
*start
= text
;
940 while (start
< prev
&& buffer
->context_len
[0] < buffer
->CONTEXT_LENGTH
)
943 prev
= hb_utf_prev (prev
, start
, &u
);
944 buffer
->context
[0][buffer
->context_len
[0]++] = u
;
948 const T
*next
= text
+ item_offset
;
949 const T
*end
= next
+ item_length
;
953 const T
*old_next
= next
;
954 next
= hb_utf_next (next
, end
, &u
);
955 buffer
->add (u
, old_next
- (const T
*) text
);
958 /* Add post-context */
959 buffer
->clear_context (1);
960 end
= text
+ text_length
;
961 while (next
< end
&& buffer
->context_len
[1] < buffer
->CONTEXT_LENGTH
)
964 next
= hb_utf_next (next
, end
, &u
);
965 buffer
->context
[1][buffer
->context_len
[1]++] = u
;
968 buffer
->content_type
= HB_BUFFER_CONTENT_TYPE_UNICODE
;
972 hb_buffer_add_utf8 (hb_buffer_t
*buffer
,
975 unsigned int item_offset
,
978 hb_buffer_add_utf (buffer
, (const uint8_t *) text
, text_length
, item_offset
, item_length
);
982 hb_buffer_add_utf16 (hb_buffer_t
*buffer
,
983 const uint16_t *text
,
985 unsigned int item_offset
,
988 hb_buffer_add_utf (buffer
, text
, text_length
, item_offset
, item_length
);
992 hb_buffer_add_utf32 (hb_buffer_t
*buffer
,
993 const uint32_t *text
,
995 unsigned int item_offset
,
998 hb_buffer_add_utf (buffer
, text
, text_length
, item_offset
, item_length
);
1003 compare_info_codepoint (const hb_glyph_info_t
*pa
,
1004 const hb_glyph_info_t
*pb
)
1006 return (int) pb
->codepoint
- (int) pa
->codepoint
;
1010 normalize_glyphs_cluster (hb_buffer_t
*buffer
,
1015 hb_glyph_position_t
*pos
= buffer
->pos
;
1017 /* Total cluster advance */
1018 hb_position_t total_x_advance
= 0, total_y_advance
= 0;
1019 for (unsigned int i
= start
; i
< end
; i
++)
1021 total_x_advance
+= pos
[i
].x_advance
;
1022 total_y_advance
+= pos
[i
].y_advance
;
1025 hb_position_t x_advance
= 0, y_advance
= 0;
1026 for (unsigned int i
= start
; i
< end
; i
++)
1028 pos
[i
].x_offset
+= x_advance
;
1029 pos
[i
].y_offset
+= y_advance
;
1031 x_advance
+= pos
[i
].x_advance
;
1032 y_advance
+= pos
[i
].y_advance
;
1034 pos
[i
].x_advance
= 0;
1035 pos
[i
].y_advance
= 0;
1040 /* Transfer all cluster advance to the last glyph. */
1041 pos
[end
- 1].x_advance
= total_x_advance
;
1042 pos
[end
- 1].y_advance
= total_y_advance
;
1044 hb_bubble_sort (buffer
->info
+ start
, end
- start
- 1, compare_info_codepoint
, buffer
->pos
+ start
);
1046 /* Transfer all cluster advance to the first glyph. */
1047 pos
[start
].x_advance
+= total_x_advance
;
1048 pos
[start
].y_advance
+= total_y_advance
;
1049 for (unsigned int i
= start
+ 1; i
< end
; i
++) {
1050 pos
[i
].x_offset
-= total_x_advance
;
1051 pos
[i
].y_offset
-= total_y_advance
;
1053 hb_bubble_sort (buffer
->info
+ start
+ 1, end
- start
- 1, compare_info_codepoint
, buffer
->pos
+ start
+ 1);
1058 hb_buffer_normalize_glyphs (hb_buffer_t
*buffer
)
1060 assert (buffer
->have_positions
);
1061 assert (buffer
->content_type
== HB_BUFFER_CONTENT_TYPE_GLYPHS
);
1063 bool backward
= HB_DIRECTION_IS_BACKWARD (buffer
->props
.direction
);
1065 unsigned int count
= buffer
->len
;
1066 if (unlikely (!count
)) return;
1067 hb_glyph_info_t
*info
= buffer
->info
;
1069 unsigned int start
= 0;
1071 for (end
= start
+ 1; end
< count
; end
++)
1072 if (info
[start
].cluster
!= info
[end
].cluster
) {
1073 normalize_glyphs_cluster (buffer
, start
, end
, backward
);
1076 normalize_glyphs_cluster (buffer
, start
, end
, backward
);