2 * Copyright (C) 1998-2004 David Turner and Werner Lemberg
3 * Copyright (C) 2004,2007,2009,2010 Red Hat, Inc.
5 * This is part of HarfBuzz, a text shaping library.
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25 * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
28 #include "hb-buffer-private.hh"
33 static hb_buffer_t _hb_buffer_nil = {
34 HB_REFERENCE_COUNT_INVALID, /* ref_count */
36 &_hb_unicode_funcs_nil /* unicode */
39 /* Here is how the buffer works internally:
41 * There are two info pointers: info and out_info. They always have
42 * the same allocated size, but different lengths.
44 * As an optimization, both info and out_info may point to the
45 * same piece of memory, which is owned by info. This remains the
46 * case as long as out_len doesn't exceed len at any time.
47 * In that case, swap() is no-op and the glyph operations operate
50 * As soon as out_info gets longer than info, out_info is moved over
51 * to an alternate buffer (which we reuse the pos buffer for!), and its
52 * current contents (out_len entries) are copied to the new place.
53 * This should all remain transparent to the user. swap() then
54 * switches info and out_info.
59 _hb_buffer_enlarge (hb_buffer_t *buffer, unsigned int size)
61 if (unlikely (buffer->in_error))
64 unsigned int new_allocated = buffer->allocated;
65 hb_internal_glyph_position_t *new_pos;
66 hb_internal_glyph_info_t *new_info;
69 separate_out = buffer->out_info != buffer->info;
71 while (size > new_allocated)
72 new_allocated += (new_allocated >> 1) + 8;
74 new_pos = (hb_internal_glyph_position_t *) realloc (buffer->pos, new_allocated * sizeof (buffer->pos[0]));
75 new_info = (hb_internal_glyph_info_t *) realloc (buffer->info, new_allocated * sizeof (buffer->info[0]));
77 if (unlikely (!new_pos || !new_info))
78 buffer->in_error = TRUE;
81 buffer->pos = new_pos;
83 if (likely (new_info))
84 buffer->info = new_info;
86 buffer->out_info = separate_out ? (hb_internal_glyph_info_t *) buffer->pos : buffer->info;
87 if (likely (!buffer->in_error))
88 buffer->allocated = new_allocated;
90 return likely (!buffer->in_error);
93 static inline hb_bool_t
94 _hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size)
96 return likely (size <= buffer->allocated) ? TRUE : _hb_buffer_enlarge (buffer, size);
100 _hb_buffer_ensure_separate (hb_buffer_t *buffer, unsigned int size)
102 if (unlikely (!_hb_buffer_ensure (buffer, size))) return FALSE;
104 if (buffer->out_info == buffer->info)
106 assert (buffer->have_output);
108 buffer->out_info = (hb_internal_glyph_info_t *) buffer->pos;
109 memcpy (buffer->out_info, buffer->info, buffer->out_len * sizeof (buffer->out_info[0]));
119 hb_buffer_create (unsigned int pre_alloc_size)
123 if (!HB_OBJECT_DO_CREATE (hb_buffer_t, buffer))
124 return &_hb_buffer_nil;
127 _hb_buffer_ensure (buffer, pre_alloc_size);
129 buffer->unicode = &_hb_unicode_funcs_nil;
135 hb_buffer_reference (hb_buffer_t *buffer)
137 HB_OBJECT_DO_REFERENCE (buffer);
141 hb_buffer_get_reference_count (hb_buffer_t *buffer)
143 HB_OBJECT_DO_GET_REFERENCE_COUNT (buffer);
147 hb_buffer_destroy (hb_buffer_t *buffer)
149 HB_OBJECT_DO_DESTROY (buffer);
151 hb_unicode_funcs_destroy (buffer->unicode);
161 hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
162 hb_unicode_funcs_t *unicode)
165 unicode = &_hb_unicode_funcs_nil;
167 hb_unicode_funcs_reference (unicode);
168 hb_unicode_funcs_destroy (buffer->unicode);
169 buffer->unicode = unicode;
173 hb_buffer_get_unicode_funcs (hb_buffer_t *buffer)
175 return buffer->unicode;
179 hb_buffer_set_direction (hb_buffer_t *buffer,
180 hb_direction_t direction)
183 buffer->direction = direction;
187 hb_buffer_get_direction (hb_buffer_t *buffer)
189 return buffer->direction;
193 hb_buffer_set_script (hb_buffer_t *buffer,
196 buffer->script = script;
200 hb_buffer_get_script (hb_buffer_t *buffer)
202 return buffer->script;
206 hb_buffer_set_language (hb_buffer_t *buffer,
207 hb_language_t language)
209 buffer->language = language;
213 hb_buffer_get_language (hb_buffer_t *buffer)
215 return buffer->language;
220 hb_buffer_clear (hb_buffer_t *buffer)
222 buffer->have_output = FALSE;
223 buffer->have_positions = FALSE;
224 buffer->in_error = FALSE;
228 buffer->out_info = buffer->info;
229 buffer->max_lig_id = 0;
233 hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size)
235 return _hb_buffer_ensure (buffer, size);
239 hb_buffer_add_glyph (hb_buffer_t *buffer,
240 hb_codepoint_t codepoint,
242 unsigned int cluster)
244 hb_internal_glyph_info_t *glyph;
246 if (unlikely (!_hb_buffer_ensure (buffer, buffer->len + 1))) return;
248 glyph = &buffer->info[buffer->len];
249 glyph->codepoint = codepoint;
251 glyph->cluster = cluster;
252 glyph->component = 0;
254 glyph->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
260 hb_buffer_clear_positions (hb_buffer_t *buffer)
262 _hb_buffer_clear_output (buffer);
263 buffer->have_output = FALSE;
264 buffer->have_positions = TRUE;
266 if (unlikely (!buffer->pos))
268 buffer->pos = (hb_internal_glyph_position_t *) calloc (buffer->allocated, sizeof (buffer->pos[0]));
272 memset (buffer->pos, 0, sizeof (buffer->pos[0]) * buffer->len);
275 /* HarfBuzz-Internal API */
278 _hb_buffer_clear_output (hb_buffer_t *buffer)
280 buffer->have_output = TRUE;
281 buffer->have_positions = FALSE;
283 buffer->out_info = buffer->info;
287 _hb_buffer_swap (hb_buffer_t *buffer)
291 assert (buffer->have_output);
293 if (unlikely (buffer->in_error)) return;
295 if (buffer->out_info != buffer->info)
297 hb_internal_glyph_info_t *tmp_string;
298 tmp_string = buffer->info;
299 buffer->info = buffer->out_info;
300 buffer->out_info = tmp_string;
301 buffer->pos = (hb_internal_glyph_position_t *) buffer->out_info;
305 buffer->len = buffer->out_len;
306 buffer->out_len = tmp;
311 /* The following function copies `num_out' elements from `glyph_data'
312 to `buffer->out_info', advancing the in array pointer in the structure
313 by `num_in' elements, and the out array pointer by `num_out' elements.
314 Finally, it sets the `length' field of `out' equal to
315 `pos' of the `out' structure.
317 If `component' is 0xFFFF, the component value from buffer->i
318 will copied `num_out' times, otherwise `component' itself will
319 be used to fill the `component' fields.
321 If `lig_id' is 0xFFFF, the lig_id value from buffer->i
322 will copied `num_out' times, otherwise `lig_id' itself will
323 be used to fill the `lig_id' fields.
325 The mask for all replacement glyphs are taken
326 from the glyph at position `buffer->i'.
328 The cluster value for the glyph at position buffer->i is used
329 for all replacement glyphs */
332 _hb_buffer_add_output_glyphs (hb_buffer_t *buffer,
334 unsigned int num_out,
335 const hb_codepoint_t *glyph_data,
336 unsigned short component,
337 unsigned short lig_id)
341 unsigned int cluster;
343 if (buffer->out_info != buffer->info ||
344 buffer->out_len + num_out > buffer->i + num_in)
346 if (unlikely (!_hb_buffer_ensure_separate (buffer, buffer->out_len + num_out)))
350 mask = buffer->info[buffer->i].mask;
351 cluster = buffer->info[buffer->i].cluster;
352 if (component == 0xFFFF)
353 component = buffer->info[buffer->i].component;
354 if (lig_id == 0xFFFF)
355 lig_id = buffer->info[buffer->i].lig_id;
357 for (i = 0; i < num_out; i++)
359 hb_internal_glyph_info_t *info = &buffer->out_info[buffer->out_len + i];
360 info->codepoint = glyph_data[i];
362 info->cluster = cluster;
363 info->component = component;
364 info->lig_id = lig_id;
365 info->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
369 buffer->out_len += num_out;
373 _hb_buffer_add_output_glyphs_be16 (hb_buffer_t *buffer,
375 unsigned int num_out,
376 const uint16_t *glyph_data_be,
377 unsigned short component,
378 unsigned short lig_id)
382 unsigned int cluster;
384 if (buffer->out_info != buffer->info ||
385 buffer->out_len + num_out > buffer->i + num_in)
387 if (unlikely (!_hb_buffer_ensure_separate (buffer, buffer->out_len + num_out)))
391 mask = buffer->info[buffer->i].mask;
392 cluster = buffer->info[buffer->i].cluster;
393 if (component == 0xFFFF)
394 component = buffer->info[buffer->i].component;
395 if (lig_id == 0xFFFF)
396 lig_id = buffer->info[buffer->i].lig_id;
398 for (i = 0; i < num_out; i++)
400 hb_internal_glyph_info_t *info = &buffer->out_info[buffer->out_len + i];
401 info->codepoint = hb_be_uint16 (glyph_data_be[i]);
403 info->cluster = cluster;
404 info->component = component;
405 info->lig_id = lig_id;
406 info->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
410 buffer->out_len += num_out;
414 _hb_buffer_add_output_glyph (hb_buffer_t *buffer,
415 hb_codepoint_t glyph_index,
416 unsigned short component,
417 unsigned short lig_id)
419 hb_internal_glyph_info_t *info;
421 if (buffer->out_info != buffer->info)
423 if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return;
424 buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
426 else if (buffer->out_len != buffer->i)
427 buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
429 info = &buffer->out_info[buffer->out_len];
430 info->codepoint = glyph_index;
431 if (component != 0xFFFF)
432 info->component = component;
433 if (lig_id != 0xFFFF)
434 info->lig_id = lig_id;
435 info->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
442 _hb_buffer_next_glyph (hb_buffer_t *buffer)
444 if (buffer->have_output)
446 if (buffer->out_info != buffer->info)
448 if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return;
449 buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
451 else if (buffer->out_len != buffer->i)
452 buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
461 _hb_buffer_clear_masks (hb_buffer_t *buffer)
463 unsigned int count = buffer->len;
464 for (unsigned int i = 0; i < count; i++)
465 buffer->info[i].mask = 1;
469 _hb_buffer_or_masks (hb_buffer_t *buffer,
471 unsigned int cluster_start,
472 unsigned int cluster_end)
474 if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
475 unsigned int count = buffer->len;
476 for (unsigned int i = 0; i < count; i++)
477 buffer->info[i].mask |= mask;
481 /* Binary search to find the start position and go from there. */
482 unsigned int min = 0, max = buffer->len;
485 unsigned int mid = min + ((max - min) / 2);
486 if (buffer->info[mid].cluster < cluster_start)
491 unsigned int count = buffer->len;
492 for (unsigned int i = min; i < count && buffer->info[i].cluster < cluster_end; i++)
493 buffer->info[i].mask |= mask;
497 /* Public API again */
500 hb_buffer_get_length (hb_buffer_t *buffer)
505 /* Return value valid as long as buffer not modified */
507 hb_buffer_get_glyph_infos (hb_buffer_t *buffer)
509 return (hb_glyph_info_t *) buffer->info;
512 /* Return value valid as long as buffer not modified */
513 hb_glyph_position_t *
514 hb_buffer_get_glyph_positions (hb_buffer_t *buffer)
516 if (!buffer->have_positions)
517 hb_buffer_clear_positions (buffer);
519 return (hb_glyph_position_t *) buffer->pos;
524 reverse_range (hb_buffer_t *buffer,
530 for (i = start, j = end - 1; i < j; i++, j--) {
531 hb_internal_glyph_info_t t;
534 buffer->info[i] = buffer->info[j];
539 for (i = 0, j = end - 1; i < j; i++, j--) {
540 hb_internal_glyph_position_t t;
543 buffer->pos[i] = buffer->pos[j];
550 hb_buffer_reverse (hb_buffer_t *buffer)
552 if (unlikely (!buffer->len))
555 reverse_range (buffer, 0, buffer->len);
559 hb_buffer_reverse_clusters (hb_buffer_t *buffer)
561 unsigned int i, start, count, last_cluster;
563 if (unlikely (!buffer->len))
566 hb_buffer_reverse (buffer);
570 last_cluster = buffer->info[0].cluster;
571 for (i = 1; i < count; i++) {
572 if (last_cluster != buffer->info[i].cluster) {
573 reverse_range (buffer, start, i);
575 last_cluster = buffer->info[i].cluster;
578 reverse_range (buffer, start, i);
584 const T *next = (const T *) text + item_offset; \
585 const T *end = next + item_length; \
586 while (next < end) { \
588 const T *old_next = next; \
589 next = UTF_NEXT (next, end, u); \
590 hb_buffer_add_glyph (buffer, u, 1, old_next - (const T *) text); \
595 #define UTF8_COMPUTE(Char, Mask, Len) \
596 if (Char < 128) { Len = 1; Mask = 0x7f; } \
597 else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \
598 else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \
599 else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \
602 static inline const uint8_t *
603 hb_utf8_next (const uint8_t *text,
605 hb_codepoint_t *unicode)
608 unsigned int mask, len;
610 UTF8_COMPUTE (c, mask, len);
611 if (unlikely (!len || (unsigned int) (end - text) < len)) {
615 hb_codepoint_t result;
618 for (i = 1; i < len; i++)
620 if (unlikely ((text[i] & 0xc0) != 0x80))
626 result |= (text[i] & 0x3f);
634 hb_buffer_add_utf8 (hb_buffer_t *buffer,
636 unsigned int text_length HB_UNUSED,
637 unsigned int item_offset,
638 unsigned int item_length)
640 #define UTF_NEXT(S, E, U) hb_utf8_next (S, E, &(U))
645 static inline const uint16_t *
646 hb_utf16_next (const uint16_t *text,
648 hb_codepoint_t *unicode)
650 uint16_t c = *text++;
652 if (unlikely (c >= 0xd800 && c < 0xdc00)) {
655 if (text < end && ((l = *text), unlikely (l >= 0xdc00 && l < 0xe000))) {
657 *unicode = ((hb_codepoint_t) ((c) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000);
668 hb_buffer_add_utf16 (hb_buffer_t *buffer,
669 const uint16_t *text,
670 unsigned int text_length HB_UNUSED,
671 unsigned int item_offset,
672 unsigned int item_length)
674 #define UTF_NEXT(S, E, U) hb_utf16_next (S, E, &(U))
680 hb_buffer_add_utf32 (hb_buffer_t *buffer,
681 const uint32_t *text,
682 unsigned int text_length HB_UNUSED,
683 unsigned int item_offset,
684 unsigned int item_length)
686 #define UTF_NEXT(S, E, U) ((U) = *(S), (S)+1)