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