Add an inline version of hb_buffer_ensure()
[framework/uifw/harfbuzz.git] / src / hb-buffer.cc
1 /*
2  * Copyright (C) 1998-2004  David Turner and Werner Lemberg
3  * Copyright (C) 2004,2007,2009,2010  Red Hat, Inc.
4  *
5  * This is part of HarfBuzz, a text shaping library.
6  *
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.
12  *
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
17  * DAMAGE.
18  *
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.
24  *
25  * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
26  */
27
28 #include "hb-buffer-private.hh"
29
30 #include <string.h>
31
32
33 static hb_buffer_t _hb_buffer_nil = {
34   HB_REFERENCE_COUNT_INVALID, /* ref_count */
35
36   &_hb_unicode_funcs_nil  /* unicode */
37 };
38
39 /* Here is how the buffer works internally:
40  *
41  * There are two info pointers: info and out_info.  They always have
42  * the same allocated size, but different lengths.
43  *
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
48  * mostly in-place.
49  *
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.
55  */
56
57
58 static hb_bool_t
59 _hb_buffer_enlarge (hb_buffer_t *buffer, unsigned int size)
60 {
61   if (unlikely (buffer->in_error))
62     return FALSE;
63
64   unsigned int new_allocated = buffer->allocated;
65   hb_internal_glyph_position_t *new_pos;
66   hb_internal_glyph_info_t *new_info;
67   bool separate_out;
68
69   separate_out = buffer->out_info != buffer->info;
70
71   while (size > new_allocated)
72     new_allocated += (new_allocated >> 1) + 8;
73
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]));
76
77   if (unlikely (!new_pos || !new_info))
78     buffer->in_error = TRUE;
79
80   if (likely (new_pos))
81     buffer->pos = new_pos;
82
83   if (likely (new_info))
84     buffer->info = new_info;
85
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;
89
90   return likely (!buffer->in_error);
91 }
92
93 static inline hb_bool_t
94 _hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size)
95 {
96   return likely (size <= buffer->allocated) ? TRUE : _hb_buffer_enlarge (buffer, size);
97 }
98
99 static hb_bool_t
100 _hb_buffer_ensure_separate (hb_buffer_t *buffer, unsigned int size)
101 {
102   if (unlikely (!_hb_buffer_ensure (buffer, size))) return FALSE;
103
104   if (buffer->out_info == buffer->info)
105   {
106     assert (buffer->have_output);
107
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]));
110   }
111
112   return TRUE;
113 }
114
115
116 /* Public API */
117
118 hb_buffer_t *
119 hb_buffer_create (unsigned int pre_alloc_size)
120 {
121   hb_buffer_t *buffer;
122
123   if (!HB_OBJECT_DO_CREATE (hb_buffer_t, buffer))
124     return &_hb_buffer_nil;
125
126   if (pre_alloc_size)
127     _hb_buffer_ensure (buffer, pre_alloc_size);
128
129   buffer->unicode = &_hb_unicode_funcs_nil;
130
131   return buffer;
132 }
133
134 hb_buffer_t *
135 hb_buffer_reference (hb_buffer_t *buffer)
136 {
137   HB_OBJECT_DO_REFERENCE (buffer);
138 }
139
140 unsigned int
141 hb_buffer_get_reference_count (hb_buffer_t *buffer)
142 {
143   HB_OBJECT_DO_GET_REFERENCE_COUNT (buffer);
144 }
145
146 void
147 hb_buffer_destroy (hb_buffer_t *buffer)
148 {
149   HB_OBJECT_DO_DESTROY (buffer);
150
151   hb_unicode_funcs_destroy (buffer->unicode);
152
153   free (buffer->info);
154   free (buffer->pos);
155
156   free (buffer);
157 }
158
159
160 void
161 hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
162                              hb_unicode_funcs_t *unicode)
163 {
164   if (!unicode)
165     unicode = &_hb_unicode_funcs_nil;
166
167   hb_unicode_funcs_reference (unicode);
168   hb_unicode_funcs_destroy (buffer->unicode);
169   buffer->unicode = unicode;
170 }
171
172 hb_unicode_funcs_t *
173 hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
174 {
175   return buffer->unicode;
176 }
177
178 void
179 hb_buffer_set_direction (hb_buffer_t    *buffer,
180                          hb_direction_t  direction)
181
182 {
183   buffer->direction = direction;
184 }
185
186 hb_direction_t
187 hb_buffer_get_direction (hb_buffer_t    *buffer)
188 {
189   return buffer->direction;
190 }
191
192 void
193 hb_buffer_set_script (hb_buffer_t *buffer,
194                       hb_script_t  script)
195 {
196   buffer->script = script;
197 }
198
199 hb_script_t
200 hb_buffer_get_script (hb_buffer_t *buffer)
201 {
202   return buffer->script;
203 }
204
205 void
206 hb_buffer_set_language (hb_buffer_t   *buffer,
207                         hb_language_t  language)
208 {
209   buffer->language = language;
210 }
211
212 hb_language_t
213 hb_buffer_get_language (hb_buffer_t *buffer)
214 {
215   return buffer->language;
216 }
217
218
219 void
220 hb_buffer_clear (hb_buffer_t *buffer)
221 {
222   buffer->have_output = FALSE;
223   buffer->have_positions = FALSE;
224   buffer->in_error = FALSE;
225   buffer->len = 0;
226   buffer->out_len = 0;
227   buffer->i = 0;
228   buffer->out_info = buffer->info;
229   buffer->max_lig_id = 0;
230 }
231
232 hb_bool_t
233 hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size)
234 {
235   return _hb_buffer_ensure (buffer, size);
236 }
237
238 void
239 hb_buffer_add_glyph (hb_buffer_t    *buffer,
240                      hb_codepoint_t  codepoint,
241                      hb_mask_t       mask,
242                      unsigned int    cluster)
243 {
244   hb_internal_glyph_info_t *glyph;
245
246   if (unlikely (!_hb_buffer_ensure (buffer, buffer->len + 1))) return;
247
248   glyph = &buffer->info[buffer->len];
249   glyph->codepoint = codepoint;
250   glyph->mask = mask;
251   glyph->cluster = cluster;
252   glyph->component = 0;
253   glyph->lig_id = 0;
254   glyph->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
255
256   buffer->len++;
257 }
258
259 void
260 hb_buffer_clear_positions (hb_buffer_t *buffer)
261 {
262   _hb_buffer_clear_output (buffer);
263   buffer->have_output = FALSE;
264   buffer->have_positions = TRUE;
265
266   if (unlikely (!buffer->pos))
267   {
268     buffer->pos = (hb_internal_glyph_position_t *) calloc (buffer->allocated, sizeof (buffer->pos[0]));
269     return;
270   }
271
272   memset (buffer->pos, 0, sizeof (buffer->pos[0]) * buffer->len);
273 }
274
275 /* HarfBuzz-Internal API */
276
277 void
278 _hb_buffer_clear_output (hb_buffer_t *buffer)
279 {
280   buffer->have_output = TRUE;
281   buffer->have_positions = FALSE;
282   buffer->out_len = 0;
283   buffer->out_info = buffer->info;
284 }
285
286 void
287 _hb_buffer_swap (hb_buffer_t *buffer)
288 {
289   unsigned int tmp;
290
291   assert (buffer->have_output);
292
293   if (unlikely (buffer->in_error)) return;
294
295   if (buffer->out_info != buffer->info)
296   {
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;
302   }
303
304   tmp = buffer->len;
305   buffer->len = buffer->out_len;
306   buffer->out_len = tmp;
307
308   buffer->i = 0;
309 }
310
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.
316
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.
320
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.
324
325    The mask for all replacement glyphs are taken
326    from the glyph at position `buffer->i'.
327
328    The cluster value for the glyph at position buffer->i is used
329    for all replacement glyphs */
330
331 void
332 _hb_buffer_add_output_glyphs (hb_buffer_t *buffer,
333                               unsigned int num_in,
334                               unsigned int num_out,
335                               const hb_codepoint_t *glyph_data,
336                               unsigned short component,
337                               unsigned short lig_id)
338 {
339   unsigned int i;
340   unsigned int mask;
341   unsigned int cluster;
342
343   if (buffer->out_info != buffer->info ||
344       buffer->out_len + num_out > buffer->i + num_in)
345   {
346     if (unlikely (!_hb_buffer_ensure_separate (buffer, buffer->out_len + num_out)))
347       return;
348   }
349
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;
356
357   for (i = 0; i < num_out; i++)
358   {
359     hb_internal_glyph_info_t *info = &buffer->out_info[buffer->out_len + i];
360     info->codepoint = glyph_data[i];
361     info->mask = mask;
362     info->cluster = cluster;
363     info->component = component;
364     info->lig_id = lig_id;
365     info->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
366   }
367
368   buffer->i  += num_in;
369   buffer->out_len += num_out;
370 }
371
372 void
373 _hb_buffer_add_output_glyphs_be16 (hb_buffer_t *buffer,
374                                    unsigned int num_in,
375                                    unsigned int num_out,
376                                    const uint16_t *glyph_data_be,
377                                    unsigned short component,
378                                    unsigned short lig_id)
379 {
380   unsigned int i;
381   unsigned int mask;
382   unsigned int cluster;
383
384   if (buffer->out_info != buffer->info ||
385       buffer->out_len + num_out > buffer->i + num_in)
386   {
387     if (unlikely (!_hb_buffer_ensure_separate (buffer, buffer->out_len + num_out)))
388       return;
389   }
390
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;
397
398   for (i = 0; i < num_out; i++)
399   {
400     hb_internal_glyph_info_t *info = &buffer->out_info[buffer->out_len + i];
401     info->codepoint = hb_be_uint16 (glyph_data_be[i]);
402     info->mask = mask;
403     info->cluster = cluster;
404     info->component = component;
405     info->lig_id = lig_id;
406     info->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
407   }
408
409   buffer->i  += num_in;
410   buffer->out_len += num_out;
411 }
412
413 void
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)
418 {
419   hb_internal_glyph_info_t *info;
420
421   if (buffer->out_info != buffer->info)
422   {
423     if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return;
424     buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
425   }
426   else if (buffer->out_len != buffer->i)
427     buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
428
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;
436
437   buffer->i++;
438   buffer->out_len++;
439 }
440
441 void
442 _hb_buffer_next_glyph (hb_buffer_t *buffer)
443 {
444   if (buffer->have_output)
445   {
446     if (buffer->out_info != buffer->info)
447     {
448       if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return;
449       buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
450     }
451     else if (buffer->out_len != buffer->i)
452       buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
453
454     buffer->out_len++;
455   }
456
457   buffer->i++;
458 }
459
460
461 /* Public API again */
462
463 unsigned int
464 hb_buffer_get_length (hb_buffer_t *buffer)
465 {
466   return buffer->len;
467 }
468
469 /* Return value valid as long as buffer not modified */
470 hb_glyph_info_t *
471 hb_buffer_get_glyph_infos (hb_buffer_t *buffer)
472 {
473   return (hb_glyph_info_t *) buffer->info;
474 }
475
476 /* Return value valid as long as buffer not modified */
477 hb_glyph_position_t *
478 hb_buffer_get_glyph_positions (hb_buffer_t *buffer)
479 {
480   if (!buffer->have_positions)
481     hb_buffer_clear_positions (buffer);
482
483   return (hb_glyph_position_t *) buffer->pos;
484 }
485
486
487 static void
488 reverse_range (hb_buffer_t *buffer,
489                unsigned int start,
490                unsigned int end)
491 {
492   unsigned int i, j;
493
494   for (i = start, j = end - 1; i < j; i++, j--) {
495     hb_internal_glyph_info_t t;
496
497     t = buffer->info[i];
498     buffer->info[i] = buffer->info[j];
499     buffer->info[j] = t;
500   }
501
502   if (buffer->pos) {
503     for (i = 0, j = end - 1; i < j; i++, j--) {
504       hb_internal_glyph_position_t t;
505
506       t = buffer->pos[i];
507       buffer->pos[i] = buffer->pos[j];
508       buffer->pos[j] = t;
509     }
510   }
511 }
512
513 void
514 hb_buffer_reverse (hb_buffer_t *buffer)
515 {
516   if (unlikely (!buffer->len))
517     return;
518
519   reverse_range (buffer, 0, buffer->len);
520 }
521
522 void
523 hb_buffer_reverse_clusters (hb_buffer_t *buffer)
524 {
525   unsigned int i, start, count, last_cluster;
526
527   if (unlikely (!buffer->len))
528     return;
529
530   hb_buffer_reverse (buffer);
531
532   count = buffer->len;
533   start = 0;
534   last_cluster = buffer->info[0].cluster;
535   for (i = 1; i < count; i++) {
536     if (last_cluster != buffer->info[i].cluster) {
537       reverse_range (buffer, start, i);
538       start = i;
539       last_cluster = buffer->info[i].cluster;
540     }
541   }
542   reverse_range (buffer, start, i);
543 }
544
545
546 #define ADD_UTF(T) \
547         HB_STMT_START { \
548           const T *next = (const T *) text + item_offset; \
549           const T *end = next + item_length; \
550           while (next < end) { \
551             hb_codepoint_t u; \
552             const T *old_next = next; \
553             next = UTF_NEXT (next, end, u); \
554             hb_buffer_add_glyph (buffer, u, 0,  old_next - (const T *) text); \
555           } \
556         } HB_STMT_END
557
558
559 #define UTF8_COMPUTE(Char, Mask, Len) \
560   if (Char < 128) { Len = 1; Mask = 0x7f; } \
561   else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \
562   else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \
563   else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \
564   else Len = 0;
565
566 static inline const uint8_t *
567 hb_utf8_next (const uint8_t *text,
568               const uint8_t *end,
569               hb_codepoint_t *unicode)
570 {
571   uint8_t c = *text;
572   unsigned int mask, len;
573
574   UTF8_COMPUTE (c, mask, len);
575   if (unlikely (!len || (unsigned int) (end - text) < len)) {
576     *unicode = -1;
577     return text + 1;
578   } else {
579     hb_codepoint_t result;
580     unsigned int i;
581     result = c & mask;
582     for (i = 1; i < len; i++)
583       {
584         if (unlikely ((text[i] & 0xc0) != 0x80))
585           {
586             *unicode = -1;
587             return text + 1;
588           }
589         result <<= 6;
590         result |= (text[i] & 0x3f);
591       }
592     *unicode = result;
593     return text + len;
594   }
595 }
596
597 void
598 hb_buffer_add_utf8 (hb_buffer_t  *buffer,
599                     const char   *text,
600                     unsigned int  text_length HB_UNUSED,
601                     unsigned int  item_offset,
602                     unsigned int  item_length)
603 {
604 #define UTF_NEXT(S, E, U)       hb_utf8_next (S, E, &(U))
605   ADD_UTF (uint8_t);
606 #undef UTF_NEXT
607 }
608
609 static inline const uint16_t *
610 hb_utf16_next (const uint16_t *text,
611                const uint16_t *end,
612                hb_codepoint_t *unicode)
613 {
614   uint16_t c = *text++;
615
616   if (unlikely (c >= 0xd800 && c < 0xdc00)) {
617     /* high surrogate */
618     uint16_t l;
619     if (text < end && ((l = *text), unlikely (l >= 0xdc00 && l < 0xe000))) {
620       /* low surrogate */
621       *unicode = ((hb_codepoint_t) ((c) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000);
622        text++;
623     } else
624       *unicode = -1;
625   } else
626     *unicode = c;
627
628   return text;
629 }
630
631 void
632 hb_buffer_add_utf16 (hb_buffer_t    *buffer,
633                      const uint16_t *text,
634                      unsigned int    text_length HB_UNUSED,
635                      unsigned int    item_offset,
636                      unsigned int    item_length)
637 {
638 #define UTF_NEXT(S, E, U)       hb_utf16_next (S, E, &(U))
639   ADD_UTF (uint16_t);
640 #undef UTF_NEXT
641 }
642
643 void
644 hb_buffer_add_utf32 (hb_buffer_t    *buffer,
645                      const uint32_t *text,
646                      unsigned int    text_length HB_UNUSED,
647                      unsigned int    item_offset,
648                      unsigned int    item_length)
649 {
650 #define UTF_NEXT(S, E, U)       ((U) = *(S), (S)+1)
651   ADD_UTF (uint32_t);
652 #undef UTF_NEXT
653 }