[API] Remove hb_buffer_clear()
[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   buffer->have_output = FALSE;
235   buffer->have_positions = FALSE;
236   buffer->in_error = FALSE;
237   buffer->len = 0;
238   buffer->out_len = 0;
239   buffer->i = 0;
240   buffer->out_info = buffer->info;
241   buffer->serial = 0;
242
243   buffer->props = _hb_buffer_nil.props;
244
245   hb_unicode_funcs_destroy (buffer->unicode);
246   buffer->unicode = _hb_buffer_nil.unicode;
247 }
248
249 hb_bool_t
250 hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size)
251 {
252   return _hb_buffer_ensure (buffer, size);
253 }
254
255 void
256 hb_buffer_add_glyph (hb_buffer_t    *buffer,
257                      hb_codepoint_t  codepoint,
258                      hb_mask_t       mask,
259                      unsigned int    cluster)
260 {
261   hb_glyph_info_t *glyph;
262
263   if (unlikely (!_hb_buffer_ensure (buffer, buffer->len + 1))) return;
264
265   glyph = &buffer->info[buffer->len];
266
267   memset (glyph, 0, sizeof (*glyph));
268   glyph->codepoint = codepoint;
269   glyph->mask = mask;
270   glyph->cluster = cluster;
271
272   buffer->len++;
273 }
274
275 void
276 hb_buffer_clear_positions (hb_buffer_t *buffer)
277 {
278   _hb_buffer_clear_output (buffer);
279   buffer->have_output = FALSE;
280   buffer->have_positions = TRUE;
281
282   memset (buffer->pos, 0, sizeof (buffer->pos[0]) * buffer->len);
283 }
284
285 /* HarfBuzz-Internal API */
286
287 void
288 _hb_buffer_clear_output (hb_buffer_t *buffer)
289 {
290   buffer->have_output = TRUE;
291   buffer->have_positions = FALSE;
292   buffer->out_len = 0;
293   buffer->out_info = buffer->info;
294 }
295
296 void
297 _hb_buffer_swap (hb_buffer_t *buffer)
298 {
299   unsigned int tmp;
300
301   assert (buffer->have_output);
302
303   if (unlikely (buffer->in_error)) return;
304
305   if (buffer->out_info != buffer->info)
306   {
307     hb_glyph_info_t *tmp_string;
308     tmp_string = buffer->info;
309     buffer->info = buffer->out_info;
310     buffer->out_info = tmp_string;
311     buffer->pos = (hb_glyph_position_t *) buffer->out_info;
312   }
313
314   tmp = buffer->len;
315   buffer->len = buffer->out_len;
316   buffer->out_len = tmp;
317
318   buffer->i = 0;
319 }
320
321 void
322 _hb_buffer_replace_glyphs_be16 (hb_buffer_t *buffer,
323                                 unsigned int num_in,
324                                 unsigned int num_out,
325                                 const uint16_t *glyph_data_be)
326 {
327   if (buffer->out_info != buffer->info ||
328       buffer->out_len + num_out > buffer->i + num_in)
329   {
330     if (unlikely (!_hb_buffer_ensure_separate (buffer, buffer->out_len + num_out)))
331       return;
332   }
333
334   hb_glyph_info_t orig_info = buffer->info[buffer->i];
335
336   for (unsigned int i = 0; i < num_out; i++)
337   {
338     hb_glyph_info_t *info = &buffer->out_info[buffer->out_len + i];
339     *info = orig_info;
340     info->codepoint = hb_be_uint16 (glyph_data_be[i]);
341   }
342
343   buffer->i  += num_in;
344   buffer->out_len += num_out;
345 }
346
347 void
348 _hb_buffer_replace_glyph (hb_buffer_t *buffer,
349                           hb_codepoint_t glyph_index)
350 {
351   hb_glyph_info_t *info;
352
353   if (buffer->out_info != buffer->info)
354   {
355     if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return;
356     buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
357   }
358   else if (buffer->out_len != buffer->i)
359     buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
360
361   info = &buffer->out_info[buffer->out_len];
362   info->codepoint = glyph_index;
363
364   buffer->i++;
365   buffer->out_len++;
366 }
367
368 void
369 _hb_buffer_next_glyph (hb_buffer_t *buffer)
370 {
371   if (buffer->have_output)
372   {
373     if (buffer->out_info != buffer->info)
374     {
375       if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return;
376       buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
377     }
378     else if (buffer->out_len != buffer->i)
379       buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
380
381     buffer->out_len++;
382   }
383
384   buffer->i++;
385 }
386
387 void
388 _hb_buffer_reset_masks (hb_buffer_t *buffer,
389                         hb_mask_t    mask)
390 {
391   unsigned int count = buffer->len;
392   for (unsigned int i = 0; i < count; i++)
393     buffer->info[i].mask = mask;
394 }
395
396 void
397 _hb_buffer_add_masks (hb_buffer_t *buffer,
398                       hb_mask_t    mask)
399 {
400   unsigned int count = buffer->len;
401   for (unsigned int i = 0; i < count; i++)
402     buffer->info[i].mask |= mask;
403 }
404
405 void
406 _hb_buffer_set_masks (hb_buffer_t *buffer,
407                       hb_mask_t    value,
408                       hb_mask_t    mask,
409                       unsigned int cluster_start,
410                       unsigned int cluster_end)
411 {
412   hb_mask_t not_mask = ~mask;
413   value &= mask;
414
415   if (!mask)
416     return;
417
418   if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
419     unsigned int count = buffer->len;
420     for (unsigned int i = 0; i < count; i++)
421       buffer->info[i].mask = (buffer->info[i].mask & not_mask) | value;
422     return;
423   }
424
425   /* XXX can't bsearch since .cluster may not be sorted. */
426   /* Binary search to find the start position and go from there. */
427   unsigned int min = 0, max = buffer->len;
428   while (min < max)
429   {
430     unsigned int mid = min + ((max - min) / 2);
431     if (buffer->info[mid].cluster < cluster_start)
432       min = mid + 1;
433     else
434       max = mid;
435   }
436   unsigned int count = buffer->len;
437   for (unsigned int i = min; i < count && buffer->info[i].cluster < cluster_end; i++)
438     buffer->info[i].mask = (buffer->info[i].mask & not_mask) | value;
439 }
440
441
442 /* Public API again */
443
444 hb_bool_t
445 hb_buffer_set_length (hb_buffer_t  *buffer,
446                       unsigned int  length)
447 {
448   if (!hb_buffer_ensure (buffer, length))
449     return FALSE;
450
451   /* Wipe the new space */
452   if (length > buffer->len) {
453     memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
454     if (buffer->have_positions)
455       memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
456   }
457
458   buffer->len = length;
459   return TRUE;
460 }
461
462 unsigned int
463 hb_buffer_get_length (hb_buffer_t *buffer)
464 {
465   return buffer->len;
466 }
467
468 /* Return value valid as long as buffer not modified */
469 hb_glyph_info_t *
470 hb_buffer_get_glyph_infos (hb_buffer_t *buffer)
471 {
472   return (hb_glyph_info_t *) buffer->info;
473 }
474
475 /* Return value valid as long as buffer not modified */
476 hb_glyph_position_t *
477 hb_buffer_get_glyph_positions (hb_buffer_t *buffer)
478 {
479   if (!buffer->have_positions)
480     hb_buffer_clear_positions (buffer);
481
482   return (hb_glyph_position_t *) buffer->pos;
483 }
484
485
486 static void
487 reverse_range (hb_buffer_t *buffer,
488                unsigned int start,
489                unsigned int end)
490 {
491   unsigned int i, j;
492
493   for (i = start, j = end - 1; i < j; i++, j--) {
494     hb_glyph_info_t t;
495
496     t = buffer->info[i];
497     buffer->info[i] = buffer->info[j];
498     buffer->info[j] = t;
499   }
500
501   if (buffer->pos) {
502     for (i = 0, j = end - 1; i < j; i++, j--) {
503       hb_glyph_position_t t;
504
505       t = buffer->pos[i];
506       buffer->pos[i] = buffer->pos[j];
507       buffer->pos[j] = t;
508     }
509   }
510 }
511
512 void
513 hb_buffer_reverse (hb_buffer_t *buffer)
514 {
515   if (unlikely (!buffer->len))
516     return;
517
518   reverse_range (buffer, 0, buffer->len);
519 }
520
521 void
522 hb_buffer_reverse_clusters (hb_buffer_t *buffer)
523 {
524   unsigned int i, start, count, last_cluster;
525
526   if (unlikely (!buffer->len))
527     return;
528
529   hb_buffer_reverse (buffer);
530
531   count = buffer->len;
532   start = 0;
533   last_cluster = buffer->info[0].cluster;
534   for (i = 1; i < count; i++) {
535     if (last_cluster != buffer->info[i].cluster) {
536       reverse_range (buffer, start, i);
537       start = i;
538       last_cluster = buffer->info[i].cluster;
539     }
540   }
541   reverse_range (buffer, start, i);
542 }
543
544
545 #define ADD_UTF(T) \
546         HB_STMT_START { \
547           const T *next = (const T *) text + item_offset; \
548           const T *end = next + item_length; \
549           while (next < end) { \
550             hb_codepoint_t u; \
551             const T *old_next = next; \
552             next = UTF_NEXT (next, end, u); \
553             hb_buffer_add_glyph (buffer, u, 1,  old_next - (const T *) text); \
554           } \
555         } HB_STMT_END
556
557
558 #define UTF8_COMPUTE(Char, Mask, Len) \
559   if (Char < 128) { Len = 1; Mask = 0x7f; } \
560   else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \
561   else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \
562   else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \
563   else Len = 0;
564
565 static inline const uint8_t *
566 hb_utf8_next (const uint8_t *text,
567               const uint8_t *end,
568               hb_codepoint_t *unicode)
569 {
570   uint8_t c = *text;
571   unsigned int mask, len;
572
573   /* TODO check for overlong sequences?  also: optimize? */
574
575   UTF8_COMPUTE (c, mask, len);
576   if (unlikely (!len || (unsigned int) (end - text) < len)) {
577     *unicode = -1;
578     return text + 1;
579   } else {
580     hb_codepoint_t result;
581     unsigned int i;
582     result = c & mask;
583     for (i = 1; i < len; i++)
584       {
585         if (unlikely ((text[i] & 0xc0) != 0x80))
586           {
587             *unicode = -1;
588             return text + 1;
589           }
590         result <<= 6;
591         result |= (text[i] & 0x3f);
592       }
593     *unicode = result;
594     return text + len;
595   }
596 }
597
598 void
599 hb_buffer_add_utf8 (hb_buffer_t  *buffer,
600                     const char   *text,
601                     unsigned int  text_length HB_UNUSED,
602                     unsigned int  item_offset,
603                     unsigned int  item_length)
604 {
605 #define UTF_NEXT(S, E, U)       hb_utf8_next (S, E, &(U))
606   ADD_UTF (uint8_t);
607 #undef UTF_NEXT
608 }
609
610 static inline const uint16_t *
611 hb_utf16_next (const uint16_t *text,
612                const uint16_t *end,
613                hb_codepoint_t *unicode)
614 {
615   uint16_t c = *text++;
616
617   if (unlikely (c >= 0xd800 && c < 0xdc00)) {
618     /* high surrogate */
619     uint16_t l;
620     if (text < end && ((l = *text), likely (l >= 0xdc00 && l < 0xe000))) {
621       /* low surrogate */
622       *unicode = ((hb_codepoint_t) ((c) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000);
623        text++;
624     } else
625       *unicode = -1;
626   } else
627     *unicode = c;
628
629   return text;
630 }
631
632 void
633 hb_buffer_add_utf16 (hb_buffer_t    *buffer,
634                      const uint16_t *text,
635                      unsigned int    text_length HB_UNUSED,
636                      unsigned int    item_offset,
637                      unsigned int    item_length)
638 {
639 #define UTF_NEXT(S, E, U)       hb_utf16_next (S, E, &(U))
640   ADD_UTF (uint16_t);
641 #undef UTF_NEXT
642 }
643
644 void
645 hb_buffer_add_utf32 (hb_buffer_t    *buffer,
646                      const uint32_t *text,
647                      unsigned int    text_length HB_UNUSED,
648                      unsigned int    item_offset,
649                      unsigned int    item_length)
650 {
651 #define UTF_NEXT(S, E, U)       ((U) = *(S), (S)+1)
652   ADD_UTF (uint32_t);
653 #undef UTF_NEXT
654 }
655
656
657 HB_END_DECLS