Allow disabling default features
[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 void
461 _hb_buffer_clear_masks (hb_buffer_t *buffer)
462 {
463   unsigned int count = buffer->len;
464   for (unsigned int i = 0; i < count; i++)
465     buffer->info[i].mask = 1;
466 }
467
468 void
469 _hb_buffer_set_masks (hb_buffer_t *buffer,
470                       hb_mask_t    value,
471                       hb_mask_t    mask,
472                       unsigned int cluster_start,
473                       unsigned int cluster_end)
474 {
475   hb_mask_t not_mask = ~mask;
476
477   if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
478     unsigned int count = buffer->len;
479     for (unsigned int i = 0; i < count; i++)
480       buffer->info[i].mask = (buffer->info[i].mask & not_mask) | value;
481     return;
482   }
483
484   /* Binary search to find the start position and go from there. */
485   unsigned int min = 0, max = buffer->len;
486   while (min < max)
487   {
488     unsigned int mid = min + ((max - min) / 2);
489     if (buffer->info[mid].cluster < cluster_start)
490       min = mid + 1;
491     else
492       max = mid;
493   }
494   unsigned int count = buffer->len;
495   for (unsigned int i = min; i < count && buffer->info[i].cluster < cluster_end; i++)
496     buffer->info[i].mask = (buffer->info[i].mask & not_mask) | value;
497 }
498
499
500 /* Public API again */
501
502 unsigned int
503 hb_buffer_get_length (hb_buffer_t *buffer)
504 {
505   return buffer->len;
506 }
507
508 /* Return value valid as long as buffer not modified */
509 hb_glyph_info_t *
510 hb_buffer_get_glyph_infos (hb_buffer_t *buffer)
511 {
512   return (hb_glyph_info_t *) buffer->info;
513 }
514
515 /* Return value valid as long as buffer not modified */
516 hb_glyph_position_t *
517 hb_buffer_get_glyph_positions (hb_buffer_t *buffer)
518 {
519   if (!buffer->have_positions)
520     hb_buffer_clear_positions (buffer);
521
522   return (hb_glyph_position_t *) buffer->pos;
523 }
524
525
526 static void
527 reverse_range (hb_buffer_t *buffer,
528                unsigned int start,
529                unsigned int end)
530 {
531   unsigned int i, j;
532
533   for (i = start, j = end - 1; i < j; i++, j--) {
534     hb_internal_glyph_info_t t;
535
536     t = buffer->info[i];
537     buffer->info[i] = buffer->info[j];
538     buffer->info[j] = t;
539   }
540
541   if (buffer->pos) {
542     for (i = 0, j = end - 1; i < j; i++, j--) {
543       hb_internal_glyph_position_t t;
544
545       t = buffer->pos[i];
546       buffer->pos[i] = buffer->pos[j];
547       buffer->pos[j] = t;
548     }
549   }
550 }
551
552 void
553 hb_buffer_reverse (hb_buffer_t *buffer)
554 {
555   if (unlikely (!buffer->len))
556     return;
557
558   reverse_range (buffer, 0, buffer->len);
559 }
560
561 void
562 hb_buffer_reverse_clusters (hb_buffer_t *buffer)
563 {
564   unsigned int i, start, count, last_cluster;
565
566   if (unlikely (!buffer->len))
567     return;
568
569   hb_buffer_reverse (buffer);
570
571   count = buffer->len;
572   start = 0;
573   last_cluster = buffer->info[0].cluster;
574   for (i = 1; i < count; i++) {
575     if (last_cluster != buffer->info[i].cluster) {
576       reverse_range (buffer, start, i);
577       start = i;
578       last_cluster = buffer->info[i].cluster;
579     }
580   }
581   reverse_range (buffer, start, i);
582 }
583
584
585 #define ADD_UTF(T) \
586         HB_STMT_START { \
587           const T *next = (const T *) text + item_offset; \
588           const T *end = next + item_length; \
589           while (next < end) { \
590             hb_codepoint_t u; \
591             const T *old_next = next; \
592             next = UTF_NEXT (next, end, u); \
593             hb_buffer_add_glyph (buffer, u, 1,  old_next - (const T *) text); \
594           } \
595         } HB_STMT_END
596
597
598 #define UTF8_COMPUTE(Char, Mask, Len) \
599   if (Char < 128) { Len = 1; Mask = 0x7f; } \
600   else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \
601   else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \
602   else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \
603   else Len = 0;
604
605 static inline const uint8_t *
606 hb_utf8_next (const uint8_t *text,
607               const uint8_t *end,
608               hb_codepoint_t *unicode)
609 {
610   uint8_t c = *text;
611   unsigned int mask, len;
612
613   /* TODO check for overlong sequences?  also: optimize? */
614
615   UTF8_COMPUTE (c, mask, len);
616   if (unlikely (!len || (unsigned int) (end - text) < len)) {
617     *unicode = -1;
618     return text + 1;
619   } else {
620     hb_codepoint_t result;
621     unsigned int i;
622     result = c & mask;
623     for (i = 1; i < len; i++)
624       {
625         if (unlikely ((text[i] & 0xc0) != 0x80))
626           {
627             *unicode = -1;
628             return text + 1;
629           }
630         result <<= 6;
631         result |= (text[i] & 0x3f);
632       }
633     *unicode = result;
634     return text + len;
635   }
636 }
637
638 void
639 hb_buffer_add_utf8 (hb_buffer_t  *buffer,
640                     const char   *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_utf8_next (S, E, &(U))
646   ADD_UTF (uint8_t);
647 #undef UTF_NEXT
648 }
649
650 static inline const uint16_t *
651 hb_utf16_next (const uint16_t *text,
652                const uint16_t *end,
653                hb_codepoint_t *unicode)
654 {
655   uint16_t c = *text++;
656
657   if (unlikely (c >= 0xd800 && c < 0xdc00)) {
658     /* high surrogate */
659     uint16_t l;
660     if (text < end && ((l = *text), unlikely (l >= 0xdc00 && l < 0xe000))) {
661       /* low surrogate */
662       *unicode = ((hb_codepoint_t) ((c) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000);
663        text++;
664     } else
665       *unicode = -1;
666   } else
667     *unicode = c;
668
669   return text;
670 }
671
672 void
673 hb_buffer_add_utf16 (hb_buffer_t    *buffer,
674                      const uint16_t *text,
675                      unsigned int    text_length HB_UNUSED,
676                      unsigned int    item_offset,
677                      unsigned int    item_length)
678 {
679 #define UTF_NEXT(S, E, U)       hb_utf16_next (S, E, &(U))
680   ADD_UTF (uint16_t);
681 #undef UTF_NEXT
682 }
683
684 void
685 hb_buffer_add_utf32 (hb_buffer_t    *buffer,
686                      const uint32_t *text,
687                      unsigned int    text_length HB_UNUSED,
688                      unsigned int    item_offset,
689                      unsigned int    item_length)
690 {
691 #define UTF_NEXT(S, E, U)       ((U) = *(S), (S)+1)
692   ADD_UTF (uint32_t);
693 #undef UTF_NEXT
694 }