Move more code around
[framework/uifw/harfbuzz.git] / src / hb-buffer.cc
1 /*
2  * Copyright © 1998-2004  David Turner and Werner Lemberg
3  * Copyright © 2004,2007,2009,2010  Red Hat, Inc.
4  * Copyright © 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 #ifndef HB_DEBUG_BUFFER
38 #define HB_DEBUG_BUFFER (HB_DEBUG+0)
39 #endif
40
41
42 static hb_buffer_t _hb_buffer_nil = {
43   HB_OBJECT_HEADER_STATIC,
44
45   &_hb_unicode_funcs_default,
46   {
47     HB_DIRECTION_INVALID,
48     HB_SCRIPT_INVALID,
49     NULL,
50   },
51
52   TRUE, /* in_error */
53   TRUE, /* have_output */
54   TRUE  /* have_positions */
55 };
56
57 /* Here is how the buffer works internally:
58  *
59  * There are two info pointers: info and out_info.  They always have
60  * the same allocated size, but different lengths.
61  *
62  * As an optimization, both info and out_info may point to the
63  * same piece of memory, which is owned by info.  This remains the
64  * case as long as out_len doesn't exceed i at any time.
65  * In that case, swap_buffers() is no-op and the glyph operations operate
66  * mostly in-place.
67  *
68  * As soon as out_info gets longer than info, out_info is moved over
69  * to an alternate buffer (which we reuse the pos buffer for!), and its
70  * current contents (out_len entries) are copied to the new place.
71  * This should all remain transparent to the user.  swap_buffers() then
72  * switches info and out_info.
73  */
74
75
76
77 /* Internal API */
78
79 bool
80 hb_buffer_t::enlarge (unsigned int size)
81 {
82   if (unlikely (in_error))
83     return FALSE;
84
85   unsigned int new_allocated = allocated;
86   hb_glyph_position_t *new_pos = NULL;
87   hb_glyph_info_t *new_info = NULL;
88   bool separate_out = out_info != info;
89
90   if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
91     goto done;
92
93   while (size > new_allocated)
94     new_allocated += (new_allocated >> 1) + 32;
95
96   ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
97   if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
98     goto done;
99
100   new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
101   new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
102
103 done:
104   if (unlikely (!new_pos || !new_info))
105     in_error = TRUE;
106
107   if (likely (new_pos))
108     pos = new_pos;
109
110   if (likely (new_info))
111     info = new_info;
112
113   out_info = separate_out ? (hb_glyph_info_t *) pos : info;
114   if (likely (!in_error))
115     allocated = new_allocated;
116
117   return likely (!in_error);
118 }
119
120 bool
121 hb_buffer_t::make_room_for (unsigned int num_in,
122                             unsigned int num_out)
123 {
124   if (unlikely (!ensure (out_len + num_out))) return FALSE;
125
126   if (out_info == info &&
127       out_len + num_out > idx + num_in)
128   {
129     assert (have_output);
130
131     out_info = (hb_glyph_info_t *) pos;
132     memcpy (out_info, info, out_len * sizeof (out_info[0]));
133   }
134
135   return TRUE;
136 }
137
138
139 /* HarfBuzz-Internal API */
140
141 void
142 hb_buffer_t::reset (void)
143 {
144   if (unlikely (hb_object_is_inert (this)))
145     return;
146
147   hb_unicode_funcs_destroy (unicode);
148   unicode = _hb_buffer_nil.unicode;
149
150   props = _hb_buffer_nil.props;
151
152   in_error = FALSE;
153   have_output = FALSE;
154   have_positions = FALSE;
155
156   idx = 0;
157   len = 0;
158   out_len = 0;
159
160   serial = 0;
161   memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
162   memset (allocated_var_owner, 0, sizeof allocated_var_owner);
163
164   out_info = info;
165 }
166
167 void
168 hb_buffer_t::add (hb_codepoint_t  codepoint,
169                   hb_mask_t       mask,
170                   unsigned int    cluster)
171 {
172   hb_glyph_info_t *glyph;
173
174   if (unlikely (!ensure (len + 1))) return;
175
176   glyph = &info[len];
177
178   memset (glyph, 0, sizeof (*glyph));
179   glyph->codepoint = codepoint;
180   glyph->mask = mask;
181   glyph->cluster = cluster;
182
183   len++;
184 }
185
186 void
187 hb_buffer_t::clear_output (void)
188 {
189   if (unlikely (hb_object_is_inert (this)))
190     return;
191
192   have_output = TRUE;
193   have_positions = FALSE;
194
195   out_len = 0;
196   out_info = info;
197 }
198
199 void
200 hb_buffer_t::clear_positions (void)
201 {
202   if (unlikely (hb_object_is_inert (this)))
203     return;
204
205   have_output = FALSE;
206   have_positions = TRUE;
207
208   memset (pos, 0, sizeof (pos[0]) * len);
209 }
210
211 void
212 hb_buffer_t::swap_buffers (void)
213 {
214   if (unlikely (in_error)) return;
215
216   assert (have_output);
217
218   if (out_info != info)
219   {
220     hb_glyph_info_t *tmp_string;
221     tmp_string = info;
222     info = out_info;
223     out_info = tmp_string;
224     pos = (hb_glyph_position_t *) out_info;
225   }
226
227   unsigned int tmp;
228   tmp = len;
229   len = out_len;
230   out_len = tmp;
231
232   idx = 0;
233 }
234
235 void
236 hb_buffer_t::replace_glyphs_be16 (unsigned int num_in,
237                                   unsigned int num_out,
238                                   const uint16_t *glyph_data_be)
239 {
240   if (!make_room_for (num_in, num_out)) return;
241
242   hb_glyph_info_t orig_info = info[idx];
243   for (unsigned int i = 1; i < num_in; i++)
244   {
245     hb_glyph_info_t *inf = &info[idx + i];
246     orig_info.cluster = MIN (orig_info.cluster, inf->cluster);
247   }
248
249   hb_glyph_info_t *pinfo = &out_info[out_len];
250   for (unsigned int i = 0; i < num_out; i++)
251   {
252     *pinfo = orig_info;
253     pinfo->codepoint = hb_be_uint16 (glyph_data_be[i]);
254     pinfo++;
255   }
256
257   idx  += num_in;
258   out_len += num_out;
259 }
260
261 void
262 hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
263 {
264   if (!make_room_for (0, 1)) return;
265
266   out_info[out_len] = info[idx];
267   out_info[out_len].codepoint = glyph_index;
268
269   out_len++;
270 }
271
272 void
273 hb_buffer_t::copy_glyph (void)
274 {
275   if (!make_room_for (0, 1)) return;
276
277   out_info[out_len] = info[idx];
278
279   out_len++;
280 }
281
282 void
283 hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
284 {
285   out_info[out_len] = info[idx];
286   out_info[out_len].codepoint = glyph_index;
287
288   idx++;
289   out_len++;
290 }
291
292 void
293 hb_buffer_t::next_glyph (void)
294 {
295   if (have_output)
296   {
297     if (out_info != info)
298     {
299       if (unlikely (!ensure (out_len + 1))) return;
300       out_info[out_len] = info[idx];
301     }
302     else if (out_len != idx)
303       out_info[out_len] = info[idx];
304
305     out_len++;
306   }
307
308   idx++;
309 }
310
311 void
312 hb_buffer_t::set_masks (hb_mask_t    value,
313                         hb_mask_t    mask,
314                         unsigned int cluster_start,
315                         unsigned int cluster_end)
316 {
317   hb_mask_t not_mask = ~mask;
318   value &= mask;
319
320   if (!mask)
321     return;
322
323   if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
324     unsigned int count = len;
325     for (unsigned int i = 0; i < count; i++)
326       info[i].mask = (info[i].mask & not_mask) | value;
327     return;
328   }
329
330   unsigned int count = len;
331   for (unsigned int i = 0; i < count; i++)
332     if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
333       info[i].mask = (info[i].mask & not_mask) | value;
334 }
335
336 void
337 hb_buffer_t::reverse_range (unsigned int start,
338                             unsigned int end)
339 {
340   unsigned int i, j;
341
342   if (start == end - 1)
343     return;
344
345   for (i = start, j = end - 1; i < j; i++, j--) {
346     hb_glyph_info_t t;
347
348     t = info[i];
349     info[i] = info[j];
350     info[j] = t;
351   }
352
353   if (pos) {
354     for (i = start, j = end - 1; i < j; i++, j--) {
355       hb_glyph_position_t t;
356
357       t = pos[i];
358       pos[i] = pos[j];
359       pos[j] = t;
360     }
361   }
362 }
363
364 void
365 hb_buffer_t::reverse (void)
366 {
367   if (unlikely (!len))
368     return;
369
370   reverse_range (0, len);
371 }
372
373 void
374 hb_buffer_t::reverse_clusters (void)
375 {
376   unsigned int i, start, count, last_cluster;
377
378   if (unlikely (!len))
379     return;
380
381   reverse ();
382
383   count = len;
384   start = 0;
385   last_cluster = info[0].cluster;
386   for (i = 1; i < count; i++) {
387     if (last_cluster != info[i].cluster) {
388       reverse_range (start, i);
389       start = i;
390       last_cluster = info[i].cluster;
391     }
392   }
393   reverse_range (start, i);
394 }
395
396 static inline void
397 dump_var_allocation (const hb_buffer_t *buffer)
398 {
399   char buf[80];
400   for (unsigned int i = 0; i < 8; i++)
401     buf[i] = '0' + buffer->allocated_var_bytes[i];
402   buf[8] = '\0';
403   DEBUG_MSG (BUFFER, buffer,
404              "Current var allocation: %s",
405              buf);
406 }
407
408 void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner)
409 {
410   assert (byte_i < 8 && byte_i + count < 8);
411
412   if (DEBUG (BUFFER))
413     dump_var_allocation (this);
414   DEBUG_MSG (BUFFER, this,
415              "Allocating var bytes %d..%d for %s",
416              byte_i, byte_i + count - 1, owner);
417
418   for (unsigned int i = byte_i; i < byte_i + count; i++) {
419     assert (!allocated_var_bytes[i]);
420     allocated_var_bytes[i]++;
421     allocated_var_owner[i] = owner;
422   }
423 }
424
425 void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
426 {
427   DEBUG_MSG (BUFFER, this,
428              "Deallocating var bytes %d..%d for %s",
429              byte_i, byte_i + count - 1, owner);
430
431   assert (byte_i < 8 && byte_i + count < 8);
432   for (unsigned int i = byte_i; i < byte_i + count; i++) {
433     assert (allocated_var_bytes[i] && allocated_var_owner[i] == owner);
434     allocated_var_bytes[i]--;
435   }
436
437   if (DEBUG (BUFFER))
438     dump_var_allocation (this);
439 }
440
441 void hb_buffer_t::deallocate_var_all (void)
442 {
443   memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
444   memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
445 }
446
447 /* Public API */
448
449 hb_buffer_t *
450 hb_buffer_create (unsigned int pre_alloc_size)
451 {
452   hb_buffer_t *buffer;
453
454   if (!(buffer = hb_object_create<hb_buffer_t> ()))
455     return &_hb_buffer_nil;
456
457   buffer->reset ();
458
459   if (pre_alloc_size && !buffer->ensure (pre_alloc_size)) {
460     hb_buffer_destroy (buffer);
461     return &_hb_buffer_nil;
462   }
463
464   return buffer;
465 }
466
467 hb_buffer_t *
468 hb_buffer_get_empty (void)
469 {
470   return &_hb_buffer_nil;
471 }
472
473 hb_buffer_t *
474 hb_buffer_reference (hb_buffer_t *buffer)
475 {
476   return hb_object_reference (buffer);
477 }
478
479 void
480 hb_buffer_destroy (hb_buffer_t *buffer)
481 {
482   if (!hb_object_destroy (buffer)) return;
483
484   hb_unicode_funcs_destroy (buffer->unicode);
485
486   free (buffer->info);
487   free (buffer->pos);
488
489   free (buffer);
490 }
491
492 hb_bool_t
493 hb_buffer_set_user_data (hb_buffer_t        *buffer,
494                          hb_user_data_key_t *key,
495                          void *              data,
496                          hb_destroy_func_t   destroy)
497 {
498   return hb_object_set_user_data (buffer, key, data, destroy);
499 }
500
501 void *
502 hb_buffer_get_user_data (hb_buffer_t        *buffer,
503                          hb_user_data_key_t *key)
504 {
505   return hb_object_get_user_data (buffer, key);
506 }
507
508
509 void
510 hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
511                              hb_unicode_funcs_t *unicode)
512 {
513   if (unlikely (hb_object_is_inert (buffer)))
514     return;
515
516   if (!unicode)
517     unicode = _hb_buffer_nil.unicode;
518
519   hb_unicode_funcs_reference (unicode);
520   hb_unicode_funcs_destroy (buffer->unicode);
521   buffer->unicode = unicode;
522 }
523
524 hb_unicode_funcs_t *
525 hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
526 {
527   return buffer->unicode;
528 }
529
530 void
531 hb_buffer_set_direction (hb_buffer_t    *buffer,
532                          hb_direction_t  direction)
533
534 {
535   if (unlikely (hb_object_is_inert (buffer)))
536     return;
537
538   buffer->props.direction = direction;
539 }
540
541 hb_direction_t
542 hb_buffer_get_direction (hb_buffer_t    *buffer)
543 {
544   return buffer->props.direction;
545 }
546
547 void
548 hb_buffer_set_script (hb_buffer_t *buffer,
549                       hb_script_t  script)
550 {
551   if (unlikely (hb_object_is_inert (buffer)))
552     return;
553
554   buffer->props.script = script;
555 }
556
557 hb_script_t
558 hb_buffer_get_script (hb_buffer_t *buffer)
559 {
560   return buffer->props.script;
561 }
562
563 void
564 hb_buffer_set_language (hb_buffer_t   *buffer,
565                         hb_language_t  language)
566 {
567   if (unlikely (hb_object_is_inert (buffer)))
568     return;
569
570   buffer->props.language = language;
571 }
572
573 hb_language_t
574 hb_buffer_get_language (hb_buffer_t *buffer)
575 {
576   return buffer->props.language;
577 }
578
579
580 void
581 hb_buffer_reset (hb_buffer_t *buffer)
582 {
583   buffer->reset ();
584 }
585
586 hb_bool_t
587 hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
588 {
589   return buffer->ensure (size);
590 }
591
592 hb_bool_t
593 hb_buffer_allocation_successful (hb_buffer_t  *buffer)
594 {
595   return !buffer->in_error;
596 }
597
598 void
599 hb_buffer_add (hb_buffer_t    *buffer,
600                hb_codepoint_t  codepoint,
601                hb_mask_t       mask,
602                unsigned int    cluster)
603 {
604   buffer->add (codepoint, mask, cluster);
605 }
606
607 hb_bool_t
608 hb_buffer_set_length (hb_buffer_t  *buffer,
609                       unsigned int  length)
610 {
611   if (!buffer->ensure (length))
612     return FALSE;
613
614   /* Wipe the new space */
615   if (length > buffer->len) {
616     memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
617     if (buffer->have_positions)
618       memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
619   }
620
621   buffer->len = length;
622   return TRUE;
623 }
624
625 unsigned int
626 hb_buffer_get_length (hb_buffer_t *buffer)
627 {
628   return buffer->len;
629 }
630
631 /* Return value valid as long as buffer not modified */
632 hb_glyph_info_t *
633 hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
634                            unsigned int *length)
635 {
636   if (length)
637     *length = buffer->len;
638
639   return (hb_glyph_info_t *) buffer->info;
640 }
641
642 /* Return value valid as long as buffer not modified */
643 hb_glyph_position_t *
644 hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
645                                unsigned int *length)
646 {
647   if (!buffer->have_positions)
648     buffer->clear_positions ();
649
650   if (length)
651     *length = buffer->len;
652
653   return (hb_glyph_position_t *) buffer->pos;
654 }
655
656 void
657 hb_buffer_reverse (hb_buffer_t *buffer)
658 {
659   buffer->reverse ();
660 }
661
662 void
663 hb_buffer_reverse_clusters (hb_buffer_t *buffer)
664 {
665   buffer->reverse_clusters ();
666 }
667
668 #define ADD_UTF(T) \
669         HB_STMT_START { \
670           const T *next = (const T *) text + item_offset; \
671           const T *end = next + item_length; \
672           while (next < end) { \
673             hb_codepoint_t u; \
674             const T *old_next = next; \
675             next = UTF_NEXT (next, end, u); \
676             hb_buffer_add (buffer, u, 1,  old_next - (const T *) text); \
677           } \
678         } HB_STMT_END
679
680
681 #define UTF8_COMPUTE(Char, Mask, Len) \
682   if (Char < 128) { Len = 1; Mask = 0x7f; } \
683   else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \
684   else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \
685   else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \
686   else Len = 0;
687
688 static inline const uint8_t *
689 hb_utf8_next (const uint8_t *text,
690               const uint8_t *end,
691               hb_codepoint_t *unicode)
692 {
693   uint8_t c = *text;
694   unsigned int mask, len;
695
696   /* TODO check for overlong sequences? */
697
698   UTF8_COMPUTE (c, mask, len);
699   if (unlikely (!len || (unsigned int) (end - text) < len)) {
700     *unicode = -1;
701     return text + 1;
702   } else {
703     hb_codepoint_t result;
704     unsigned int i;
705     result = c & mask;
706     for (i = 1; i < len; i++)
707       {
708         if (unlikely ((text[i] & 0xc0) != 0x80))
709           {
710             *unicode = -1;
711             return text + 1;
712           }
713         result <<= 6;
714         result |= (text[i] & 0x3f);
715       }
716     *unicode = result;
717     return text + len;
718   }
719 }
720
721 void
722 hb_buffer_add_utf8 (hb_buffer_t  *buffer,
723                     const char   *text,
724                     unsigned int  text_length HB_UNUSED,
725                     unsigned int  item_offset,
726                     unsigned int  item_length)
727 {
728 #define UTF_NEXT(S, E, U)       hb_utf8_next (S, E, &(U))
729   ADD_UTF (uint8_t);
730 #undef UTF_NEXT
731 }
732
733 static inline const uint16_t *
734 hb_utf16_next (const uint16_t *text,
735                const uint16_t *end,
736                hb_codepoint_t *unicode)
737 {
738   uint16_t c = *text++;
739
740   if (unlikely (c >= 0xd800 && c < 0xdc00)) {
741     /* high surrogate */
742     uint16_t l;
743     if (text < end && ((l = *text), likely (l >= 0xdc00 && l < 0xe000))) {
744       /* low surrogate */
745       *unicode = ((hb_codepoint_t) ((c) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000);
746        text++;
747     } else
748       *unicode = -1;
749   } else
750     *unicode = c;
751
752   return text;
753 }
754
755 void
756 hb_buffer_add_utf16 (hb_buffer_t    *buffer,
757                      const uint16_t *text,
758                      unsigned int    text_length HB_UNUSED,
759                      unsigned int    item_offset,
760                      unsigned int    item_length)
761 {
762 #define UTF_NEXT(S, E, U)       hb_utf16_next (S, E, &(U))
763   ADD_UTF (uint16_t);
764 #undef UTF_NEXT
765 }
766
767 void
768 hb_buffer_add_utf32 (hb_buffer_t    *buffer,
769                      const uint32_t *text,
770                      unsigned int    text_length HB_UNUSED,
771                      unsigned int    item_offset,
772                      unsigned int    item_length)
773 {
774 #define UTF_NEXT(S, E, U)       ((U) = *(S), (S)+1)
775   ADD_UTF (uint32_t);
776 #undef UTF_NEXT
777 }
778
779
780 HB_END_DECLS