Imported Upstream version 0.9.12
[platform/upstream/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,2012  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 #include "hb-utf-private.hh"
32
33
34 #ifndef HB_DEBUG_BUFFER
35 #define HB_DEBUG_BUFFER (HB_DEBUG+0)
36 #endif
37
38
39 hb_bool_t
40 hb_segment_properties_equal (const hb_segment_properties_t *a,
41                              const hb_segment_properties_t *b)
42 {
43   return a->direction == b->direction &&
44          a->script    == b->script    &&
45          a->language  == b->language  &&
46          a->reserved1 == b->reserved1 &&
47          a->reserved2 == b->reserved2;
48
49 }
50
51 unsigned int
52 hb_segment_properties_hash (const hb_segment_properties_t *p)
53 {
54   return (unsigned int) p->direction ^
55          (unsigned int) p->script ^
56          (intptr_t) (p->language);
57 }
58
59
60
61 /* Here is how the buffer works internally:
62  *
63  * There are two info pointers: info and out_info.  They always have
64  * the same allocated size, but different lengths.
65  *
66  * As an optimization, both info and out_info may point to the
67  * same piece of memory, which is owned by info.  This remains the
68  * case as long as out_len doesn't exceed i at any time.
69  * In that case, swap_buffers() is no-op and the glyph operations operate
70  * mostly in-place.
71  *
72  * As soon as out_info gets longer than info, out_info is moved over
73  * to an alternate buffer (which we reuse the pos buffer for!), and its
74  * current contents (out_len entries) are copied to the new place.
75  * This should all remain transparent to the user.  swap_buffers() then
76  * switches info and out_info.
77  */
78
79
80
81 /* Internal API */
82
83 bool
84 hb_buffer_t::enlarge (unsigned int size)
85 {
86   if (unlikely (in_error))
87     return false;
88
89   unsigned int new_allocated = allocated;
90   hb_glyph_position_t *new_pos = NULL;
91   hb_glyph_info_t *new_info = NULL;
92   bool separate_out = out_info != info;
93
94   if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
95     goto done;
96
97   while (size >= new_allocated)
98     new_allocated += (new_allocated >> 1) + 32;
99
100   ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
101   if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
102     goto done;
103
104   new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
105   new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
106
107 done:
108   if (unlikely (!new_pos || !new_info))
109     in_error = true;
110
111   if (likely (new_pos))
112     pos = new_pos;
113
114   if (likely (new_info))
115     info = new_info;
116
117   out_info = separate_out ? (hb_glyph_info_t *) pos : info;
118   if (likely (!in_error))
119     allocated = new_allocated;
120
121   return likely (!in_error);
122 }
123
124 bool
125 hb_buffer_t::make_room_for (unsigned int num_in,
126                             unsigned int num_out)
127 {
128   if (unlikely (!ensure (out_len + num_out))) return false;
129
130   if (out_info == info &&
131       out_len + num_out > idx + num_in)
132   {
133     assert (have_output);
134
135     out_info = (hb_glyph_info_t *) pos;
136     memcpy (out_info, info, out_len * sizeof (out_info[0]));
137   }
138
139   return true;
140 }
141
142 void *
143 hb_buffer_t::get_scratch_buffer (unsigned int *size)
144 {
145   have_output = false;
146   have_positions = false;
147
148   out_len = 0;
149   out_info = info;
150
151   *size = allocated * sizeof (pos[0]);
152   return pos;
153 }
154
155
156
157 /* HarfBuzz-Internal API */
158
159 void
160 hb_buffer_t::reset (void)
161 {
162   if (unlikely (hb_object_is_inert (this)))
163     return;
164
165   hb_unicode_funcs_destroy (unicode);
166   unicode = hb_unicode_funcs_get_default ();
167
168   clear ();
169 }
170
171 void
172 hb_buffer_t::clear (void)
173 {
174   if (unlikely (hb_object_is_inert (this)))
175     return;
176
177   hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
178   props = default_props;
179   flags = HB_BUFFER_FLAGS_DEFAULT;
180
181   content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
182   in_error = false;
183   have_output = false;
184   have_positions = false;
185
186   idx = 0;
187   len = 0;
188   out_len = 0;
189   out_info = info;
190
191   serial = 0;
192   memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
193   memset (allocated_var_owner, 0, sizeof allocated_var_owner);
194
195   memset (context, 0, sizeof context);
196   memset (context_len, 0, sizeof context_len);
197 }
198
199 void
200 hb_buffer_t::add (hb_codepoint_t  codepoint,
201                   unsigned int    cluster)
202 {
203   hb_glyph_info_t *glyph;
204
205   if (unlikely (!ensure (len + 1))) return;
206
207   glyph = &info[len];
208
209   memset (glyph, 0, sizeof (*glyph));
210   glyph->codepoint = codepoint;
211   glyph->mask = 1;
212   glyph->cluster = cluster;
213
214   len++;
215 }
216
217 void
218 hb_buffer_t::remove_output (void)
219 {
220   if (unlikely (hb_object_is_inert (this)))
221     return;
222
223   have_output = false;
224   have_positions = false;
225
226   out_len = 0;
227   out_info = info;
228 }
229
230 void
231 hb_buffer_t::clear_output (void)
232 {
233   if (unlikely (hb_object_is_inert (this)))
234     return;
235
236   have_output = true;
237   have_positions = false;
238
239   out_len = 0;
240   out_info = info;
241 }
242
243 void
244 hb_buffer_t::clear_positions (void)
245 {
246   if (unlikely (hb_object_is_inert (this)))
247     return;
248
249   have_output = false;
250   have_positions = true;
251
252   out_len = 0;
253   out_info = info;
254
255   memset (pos, 0, sizeof (pos[0]) * len);
256 }
257
258 void
259 hb_buffer_t::swap_buffers (void)
260 {
261   if (unlikely (in_error)) return;
262
263   assert (have_output);
264   have_output = false;
265
266   if (out_info != info)
267   {
268     hb_glyph_info_t *tmp_string;
269     tmp_string = info;
270     info = out_info;
271     out_info = tmp_string;
272     pos = (hb_glyph_position_t *) out_info;
273   }
274
275   unsigned int tmp;
276   tmp = len;
277   len = out_len;
278   out_len = tmp;
279
280   idx = 0;
281 }
282
283
284 void
285 hb_buffer_t::replace_glyphs (unsigned int num_in,
286                              unsigned int num_out,
287                              const uint32_t *glyph_data)
288 {
289   if (unlikely (!make_room_for (num_in, num_out))) return;
290
291   merge_clusters (idx, idx + num_in);
292
293   hb_glyph_info_t orig_info = info[idx];
294   hb_glyph_info_t *pinfo = &out_info[out_len];
295   for (unsigned int i = 0; i < num_out; i++)
296   {
297     *pinfo = orig_info;
298     pinfo->codepoint = glyph_data[i];
299     pinfo++;
300   }
301
302   idx  += num_in;
303   out_len += num_out;
304 }
305
306 void
307 hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
308 {
309   if (unlikely (!make_room_for (0, 1))) return;
310
311   out_info[out_len] = info[idx];
312   out_info[out_len].codepoint = glyph_index;
313
314   out_len++;
315 }
316
317 void
318 hb_buffer_t::output_info (hb_glyph_info_t &glyph_info)
319 {
320   if (unlikely (!make_room_for (0, 1))) return;
321
322   out_info[out_len] = glyph_info;
323
324   out_len++;
325 }
326
327 void
328 hb_buffer_t::copy_glyph (void)
329 {
330   if (unlikely (!make_room_for (0, 1))) return;
331
332   out_info[out_len] = info[idx];
333
334   out_len++;
335 }
336
337 void
338 hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
339 {
340   if (unlikely (out_info != info || out_len != idx)) {
341     if (unlikely (!make_room_for (1, 1))) return;
342     out_info[out_len] = info[idx];
343   }
344   out_info[out_len].codepoint = glyph_index;
345
346   idx++;
347   out_len++;
348 }
349
350
351 void
352 hb_buffer_t::set_masks (hb_mask_t    value,
353                         hb_mask_t    mask,
354                         unsigned int cluster_start,
355                         unsigned int cluster_end)
356 {
357   hb_mask_t not_mask = ~mask;
358   value &= mask;
359
360   if (!mask)
361     return;
362
363   if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
364     unsigned int count = len;
365     for (unsigned int i = 0; i < count; i++)
366       info[i].mask = (info[i].mask & not_mask) | value;
367     return;
368   }
369
370   unsigned int count = len;
371   for (unsigned int i = 0; i < count; i++)
372     if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
373       info[i].mask = (info[i].mask & not_mask) | value;
374 }
375
376 void
377 hb_buffer_t::reverse_range (unsigned int start,
378                             unsigned int end)
379 {
380   unsigned int i, j;
381
382   if (start == end - 1)
383     return;
384
385   for (i = start, j = end - 1; i < j; i++, j--) {
386     hb_glyph_info_t t;
387
388     t = info[i];
389     info[i] = info[j];
390     info[j] = t;
391   }
392
393   if (pos) {
394     for (i = start, j = end - 1; i < j; i++, j--) {
395       hb_glyph_position_t t;
396
397       t = pos[i];
398       pos[i] = pos[j];
399       pos[j] = t;
400     }
401   }
402 }
403
404 void
405 hb_buffer_t::reverse (void)
406 {
407   if (unlikely (!len))
408     return;
409
410   reverse_range (0, len);
411 }
412
413 void
414 hb_buffer_t::reverse_clusters (void)
415 {
416   unsigned int i, start, count, last_cluster;
417
418   if (unlikely (!len))
419     return;
420
421   reverse ();
422
423   count = len;
424   start = 0;
425   last_cluster = info[0].cluster;
426   for (i = 1; i < count; i++) {
427     if (last_cluster != info[i].cluster) {
428       reverse_range (start, i);
429       start = i;
430       last_cluster = info[i].cluster;
431     }
432   }
433   reverse_range (start, i);
434 }
435
436 void
437 hb_buffer_t::merge_clusters (unsigned int start,
438                              unsigned int end)
439 {
440   if (unlikely (end - start < 2))
441     return;
442
443   unsigned int cluster = info[start].cluster;
444
445   for (unsigned int i = start + 1; i < end; i++)
446     cluster = MIN (cluster, info[i].cluster);
447
448   /* Extend end */
449   while (end < len && info[end - 1].cluster == info[end].cluster)
450     end++;
451
452   /* Extend start */
453   while (idx < start && info[start - 1].cluster == info[start].cluster)
454     start--;
455
456   /* If we hit the start of buffer, continue in out-buffer. */
457   if (idx == start)
458     for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
459       out_info[i - 1].cluster = cluster;
460
461   for (unsigned int i = start; i < end; i++)
462     info[i].cluster = cluster;
463 }
464 void
465 hb_buffer_t::merge_out_clusters (unsigned int start,
466                                  unsigned int end)
467 {
468   if (unlikely (end - start < 2))
469     return;
470
471   unsigned int cluster = out_info[start].cluster;
472
473   for (unsigned int i = start + 1; i < end; i++)
474     cluster = MIN (cluster, out_info[i].cluster);
475
476   /* Extend start */
477   while (start && out_info[start - 1].cluster == out_info[start].cluster)
478     start--;
479
480   /* Extend end */
481   while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)
482     end++;
483
484   /* If we hit the end of out-buffer, continue in buffer. */
485   if (end == out_len)
486     for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
487       info[i].cluster = cluster;
488
489   for (unsigned int i = start; i < end; i++)
490     out_info[i].cluster = cluster;
491 }
492
493 void
494 hb_buffer_t::guess_segment_properties (void)
495 {
496   assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
497           (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
498
499   /* If script is set to INVALID, guess from buffer contents */
500   if (props.script == HB_SCRIPT_INVALID) {
501     for (unsigned int i = 0; i < len; i++) {
502       hb_script_t script = unicode->script (info[i].codepoint);
503       if (likely (script != HB_SCRIPT_COMMON &&
504                   script != HB_SCRIPT_INHERITED &&
505                   script != HB_SCRIPT_UNKNOWN)) {
506         props.script = script;
507         break;
508       }
509     }
510   }
511
512   /* If direction is set to INVALID, guess from script */
513   if (props.direction == HB_DIRECTION_INVALID) {
514     props.direction = hb_script_get_horizontal_direction (props.script);
515   }
516
517   /* If language is not set, use default language from locale */
518   if (props.language == HB_LANGUAGE_INVALID) {
519     /* TODO get_default_for_script? using $LANGUAGE */
520     props.language = hb_language_get_default ();
521   }
522 }
523
524
525 static inline void
526 dump_var_allocation (const hb_buffer_t *buffer)
527 {
528   char buf[80];
529   for (unsigned int i = 0; i < 8; i++)
530     buf[i] = '0' + buffer->allocated_var_bytes[7 - i];
531   buf[8] = '\0';
532   DEBUG_MSG (BUFFER, buffer,
533              "Current var allocation: %s",
534              buf);
535 }
536
537 void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner)
538 {
539   assert (byte_i < 8 && byte_i + count <= 8);
540
541   if (DEBUG (BUFFER))
542     dump_var_allocation (this);
543   DEBUG_MSG (BUFFER, this,
544              "Allocating var bytes %d..%d for %s",
545              byte_i, byte_i + count - 1, owner);
546
547   for (unsigned int i = byte_i; i < byte_i + count; i++) {
548     assert (!allocated_var_bytes[i]);
549     allocated_var_bytes[i]++;
550     allocated_var_owner[i] = owner;
551   }
552 }
553
554 void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
555 {
556   if (DEBUG (BUFFER))
557     dump_var_allocation (this);
558
559   DEBUG_MSG (BUFFER, this,
560              "Deallocating var bytes %d..%d for %s",
561              byte_i, byte_i + count - 1, owner);
562
563   assert (byte_i < 8 && byte_i + count <= 8);
564   for (unsigned int i = byte_i; i < byte_i + count; i++) {
565     assert (allocated_var_bytes[i]);
566     assert (0 == strcmp (allocated_var_owner[i], owner));
567     allocated_var_bytes[i]--;
568   }
569 }
570
571 void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner)
572 {
573   if (DEBUG (BUFFER))
574     dump_var_allocation (this);
575
576   DEBUG_MSG (BUFFER, this,
577              "Asserting var bytes %d..%d for %s",
578              byte_i, byte_i + count - 1, owner);
579
580   assert (byte_i < 8 && byte_i + count <= 8);
581   for (unsigned int i = byte_i; i < byte_i + count; i++) {
582     assert (allocated_var_bytes[i]);
583     assert (0 == strcmp (allocated_var_owner[i], owner));
584   }
585 }
586
587 void hb_buffer_t::deallocate_var_all (void)
588 {
589   memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
590   memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
591 }
592
593 /* Public API */
594
595 hb_buffer_t *
596 hb_buffer_create (void)
597 {
598   hb_buffer_t *buffer;
599
600   if (!(buffer = hb_object_create<hb_buffer_t> ()))
601     return hb_buffer_get_empty ();
602
603   buffer->reset ();
604
605   return buffer;
606 }
607
608 hb_buffer_t *
609 hb_buffer_get_empty (void)
610 {
611   static const hb_buffer_t _hb_buffer_nil = {
612     HB_OBJECT_HEADER_STATIC,
613
614     const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
615     HB_SEGMENT_PROPERTIES_DEFAULT,
616     HB_BUFFER_FLAGS_DEFAULT,
617
618     HB_BUFFER_CONTENT_TYPE_INVALID,
619     true, /* in_error */
620     true, /* have_output */
621     true  /* have_positions */
622
623     /* Zero is good enough for everything else. */
624   };
625
626   return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
627 }
628
629 hb_buffer_t *
630 hb_buffer_reference (hb_buffer_t *buffer)
631 {
632   return hb_object_reference (buffer);
633 }
634
635 void
636 hb_buffer_destroy (hb_buffer_t *buffer)
637 {
638   if (!hb_object_destroy (buffer)) return;
639
640   hb_unicode_funcs_destroy (buffer->unicode);
641
642   free (buffer->info);
643   free (buffer->pos);
644
645   free (buffer);
646 }
647
648 hb_bool_t
649 hb_buffer_set_user_data (hb_buffer_t        *buffer,
650                          hb_user_data_key_t *key,
651                          void *              data,
652                          hb_destroy_func_t   destroy,
653                          hb_bool_t           replace)
654 {
655   return hb_object_set_user_data (buffer, key, data, destroy, replace);
656 }
657
658 void *
659 hb_buffer_get_user_data (hb_buffer_t        *buffer,
660                          hb_user_data_key_t *key)
661 {
662   return hb_object_get_user_data (buffer, key);
663 }
664
665
666 void
667 hb_buffer_set_content_type (hb_buffer_t              *buffer,
668                             hb_buffer_content_type_t  content_type)
669 {
670   buffer->content_type = content_type;
671 }
672
673 hb_buffer_content_type_t
674 hb_buffer_get_content_type (hb_buffer_t *buffer)
675 {
676   return buffer->content_type;
677 }
678
679
680 void
681 hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
682                              hb_unicode_funcs_t *unicode)
683 {
684   if (unlikely (hb_object_is_inert (buffer)))
685     return;
686
687   if (!unicode)
688     unicode = hb_unicode_funcs_get_default ();
689
690
691   hb_unicode_funcs_reference (unicode);
692   hb_unicode_funcs_destroy (buffer->unicode);
693   buffer->unicode = unicode;
694 }
695
696 hb_unicode_funcs_t *
697 hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
698 {
699   return buffer->unicode;
700 }
701
702 void
703 hb_buffer_set_direction (hb_buffer_t    *buffer,
704                          hb_direction_t  direction)
705
706 {
707   if (unlikely (hb_object_is_inert (buffer)))
708     return;
709
710   buffer->props.direction = direction;
711 }
712
713 hb_direction_t
714 hb_buffer_get_direction (hb_buffer_t    *buffer)
715 {
716   return buffer->props.direction;
717 }
718
719 void
720 hb_buffer_set_script (hb_buffer_t *buffer,
721                       hb_script_t  script)
722 {
723   if (unlikely (hb_object_is_inert (buffer)))
724     return;
725
726   buffer->props.script = script;
727 }
728
729 hb_script_t
730 hb_buffer_get_script (hb_buffer_t *buffer)
731 {
732   return buffer->props.script;
733 }
734
735 void
736 hb_buffer_set_language (hb_buffer_t   *buffer,
737                         hb_language_t  language)
738 {
739   if (unlikely (hb_object_is_inert (buffer)))
740     return;
741
742   buffer->props.language = language;
743 }
744
745 hb_language_t
746 hb_buffer_get_language (hb_buffer_t *buffer)
747 {
748   return buffer->props.language;
749 }
750
751 void
752 hb_buffer_set_segment_properties (hb_buffer_t *buffer,
753                                   const hb_segment_properties_t *props)
754 {
755   if (unlikely (hb_object_is_inert (buffer)))
756     return;
757
758   buffer->props = *props;
759 }
760
761 void
762 hb_buffer_get_segment_properties (hb_buffer_t *buffer,
763                                   hb_segment_properties_t *props)
764 {
765   *props = buffer->props;
766 }
767
768
769 void
770 hb_buffer_set_flags (hb_buffer_t       *buffer,
771                      hb_buffer_flags_t  flags)
772 {
773   if (unlikely (hb_object_is_inert (buffer)))
774     return;
775
776   buffer->flags = flags;
777 }
778
779 hb_buffer_flags_t
780 hb_buffer_get_flags (hb_buffer_t *buffer)
781 {
782   return buffer->flags;
783 }
784
785
786 void
787 hb_buffer_reset (hb_buffer_t *buffer)
788 {
789   buffer->reset ();
790 }
791
792 void
793 hb_buffer_clear_contents (hb_buffer_t *buffer)
794 {
795   buffer->clear ();
796 }
797
798 hb_bool_t
799 hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
800 {
801   return buffer->ensure (size);
802 }
803
804 hb_bool_t
805 hb_buffer_allocation_successful (hb_buffer_t  *buffer)
806 {
807   return !buffer->in_error;
808 }
809
810 void
811 hb_buffer_add (hb_buffer_t    *buffer,
812                hb_codepoint_t  codepoint,
813                unsigned int    cluster)
814 {
815   buffer->add (codepoint, cluster);
816   buffer->clear_context (1);
817 }
818
819 hb_bool_t
820 hb_buffer_set_length (hb_buffer_t  *buffer,
821                       unsigned int  length)
822 {
823   if (unlikely (hb_object_is_inert (buffer)))
824     return length == 0;
825
826   if (!buffer->ensure (length))
827     return false;
828
829   /* Wipe the new space */
830   if (length > buffer->len) {
831     memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
832     if (buffer->have_positions)
833       memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
834   }
835
836   buffer->len = length;
837
838   if (!length)
839     buffer->clear_context (0);
840   buffer->clear_context (1);
841
842   return true;
843 }
844
845 unsigned int
846 hb_buffer_get_length (hb_buffer_t *buffer)
847 {
848   return buffer->len;
849 }
850
851 /* Return value valid as long as buffer not modified */
852 hb_glyph_info_t *
853 hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
854                            unsigned int *length)
855 {
856   if (length)
857     *length = buffer->len;
858
859   return (hb_glyph_info_t *) buffer->info;
860 }
861
862 /* Return value valid as long as buffer not modified */
863 hb_glyph_position_t *
864 hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
865                                unsigned int *length)
866 {
867   if (!buffer->have_positions)
868     buffer->clear_positions ();
869
870   if (length)
871     *length = buffer->len;
872
873   return (hb_glyph_position_t *) buffer->pos;
874 }
875
876 void
877 hb_buffer_reverse (hb_buffer_t *buffer)
878 {
879   buffer->reverse ();
880 }
881
882 void
883 hb_buffer_reverse_clusters (hb_buffer_t *buffer)
884 {
885   buffer->reverse_clusters ();
886 }
887
888 void
889 hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
890 {
891   buffer->guess_segment_properties ();
892 }
893
894 template <typename T>
895 static inline void
896 hb_buffer_add_utf (hb_buffer_t  *buffer,
897                    const T      *text,
898                    int           text_length,
899                    unsigned int  item_offset,
900                    int           item_length)
901 {
902   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
903           (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
904
905   if (unlikely (hb_object_is_inert (buffer)))
906     return;
907
908   if (text_length == -1)
909     text_length = hb_utf_strlen (text);
910
911   if (item_length == -1)
912     item_length = text_length - item_offset;
913
914   buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
915
916   /* If buffer is empty and pre-context provided, install it.
917    * This check is written this way, to make sure people can
918    * provide pre-context in one add_utf() call, then provide
919    * text in a follow-up call.  See:
920    *
921    * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
922    */
923   if (!buffer->len && item_offset > 0)
924   {
925     /* Add pre-context */
926     buffer->clear_context (0);
927     const T *prev = text + item_offset;
928     const T *start = text;
929     while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
930     {
931       hb_codepoint_t u;
932       prev = hb_utf_prev (prev, start, &u);
933       buffer->context[0][buffer->context_len[0]++] = u;
934     }
935   }
936
937   const T *next = text + item_offset;
938   const T *end = next + item_length;
939   while (next < end)
940   {
941     hb_codepoint_t u;
942     const T *old_next = next;
943     next = hb_utf_next (next, end, &u);
944     buffer->add (u, old_next - (const T *) text);
945   }
946
947   /* Add post-context */
948   buffer->clear_context (1);
949   end = text + text_length;
950   while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
951   {
952     hb_codepoint_t u;
953     next = hb_utf_next (next, end, &u);
954     buffer->context[1][buffer->context_len[1]++] = u;
955   }
956
957   buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
958 }
959
960 void
961 hb_buffer_add_utf8 (hb_buffer_t  *buffer,
962                     const char   *text,
963                     int           text_length,
964                     unsigned int  item_offset,
965                     int           item_length)
966 {
967   hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
968 }
969
970 void
971 hb_buffer_add_utf16 (hb_buffer_t    *buffer,
972                      const uint16_t *text,
973                      int             text_length,
974                      unsigned int    item_offset,
975                      int            item_length)
976 {
977   hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
978 }
979
980 void
981 hb_buffer_add_utf32 (hb_buffer_t    *buffer,
982                      const uint32_t *text,
983                      int             text_length,
984                      unsigned int    item_offset,
985                      int             item_length)
986 {
987   hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
988 }
989
990
991 static int
992 compare_info_codepoint (const hb_glyph_info_t *pa,
993                         const hb_glyph_info_t *pb)
994 {
995   return (int) pb->codepoint - (int) pa->codepoint;
996 }
997
998 static inline void
999 normalize_glyphs_cluster (hb_buffer_t *buffer,
1000                           unsigned int start,
1001                           unsigned int end,
1002                           bool backward)
1003 {
1004   hb_glyph_position_t *pos = buffer->pos;
1005
1006   /* Total cluster advance */
1007   hb_position_t total_x_advance = 0, total_y_advance = 0;
1008   for (unsigned int i = start; i < end; i++)
1009   {
1010     total_x_advance += pos[i].x_advance;
1011     total_y_advance += pos[i].y_advance;
1012   }
1013
1014   hb_position_t x_advance = 0, y_advance = 0;
1015   for (unsigned int i = start; i < end; i++)
1016   {
1017     pos[i].x_offset += x_advance;
1018     pos[i].y_offset += y_advance;
1019
1020     x_advance += pos[i].x_advance;
1021     y_advance += pos[i].y_advance;
1022
1023     pos[i].x_advance = 0;
1024     pos[i].y_advance = 0;
1025   }
1026
1027   if (backward)
1028   {
1029     /* Transfer all cluster advance to the last glyph. */
1030     pos[end - 1].x_advance = total_x_advance;
1031     pos[end - 1].y_advance = total_y_advance;
1032
1033     hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
1034   } else {
1035     /* Transfer all cluster advance to the first glyph. */
1036     pos[start].x_advance += total_x_advance;
1037     pos[start].y_advance += total_y_advance;
1038     for (unsigned int i = start + 1; i < end; i++) {
1039       pos[i].x_offset -= total_x_advance;
1040       pos[i].y_offset -= total_y_advance;
1041     }
1042     hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
1043   }
1044 }
1045
1046 void
1047 hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
1048 {
1049   assert (buffer->have_positions);
1050   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
1051
1052   bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
1053
1054   unsigned int count = buffer->len;
1055   if (unlikely (!count)) return;
1056   hb_glyph_info_t *info = buffer->info;
1057
1058   unsigned int start = 0;
1059   unsigned int end;
1060   for (end = start + 1; end < count; end++)
1061     if (info[start].cluster != info[end].cluster) {
1062       normalize_glyphs_cluster (buffer, start, end, backward);
1063       start = end;
1064     }
1065   normalize_glyphs_cluster (buffer, start, end, backward);
1066 }
1067
1068
1069 /*
1070  * Serialize
1071  */
1072
1073 static const char *serialize_formats[] = {
1074   "text",
1075   "json",
1076   NULL
1077 };
1078
1079 const char **
1080 hb_buffer_serialize_list_formats (void)
1081 {
1082   return serialize_formats;
1083 }
1084
1085 hb_buffer_serialize_format_t
1086 hb_buffer_serialize_format_from_string (const char *str, int len)
1087 {
1088   /* Upper-case it. */
1089   return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020);
1090 }
1091
1092 const char *
1093 hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
1094 {
1095   switch (format)
1096   {
1097     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:       return serialize_formats[0];
1098     case HB_BUFFER_SERIALIZE_FORMAT_JSON:       return serialize_formats[1];
1099     default:
1100     case HB_BUFFER_SERIALIZE_FORMAT_INVALID:    return NULL;
1101   }
1102 }
1103
1104 static unsigned int
1105 _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
1106                                   unsigned int start,
1107                                   unsigned int end,
1108                                   char *buf,
1109                                   unsigned int buf_size,
1110                                   unsigned int *buf_consumed,
1111                                   hb_font_t *font,
1112                                   hb_buffer_serialize_flags_t flags)
1113 {
1114   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
1115   hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
1116
1117   *buf_consumed = 0;
1118   for (unsigned int i = start; i < end; i++)
1119   {
1120     char b[1024];
1121     char *p = b;
1122
1123     /* In the following code, we know b is large enough that no overflow can happen. */
1124
1125 #define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END
1126
1127     if (i)
1128       *p++ = ',';
1129
1130     *p++ = '{';
1131
1132     APPEND ("\"g\":");
1133     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
1134     {
1135       char g[128];
1136       hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g));
1137       *p++ = '"';
1138       for (char *q = g; *q; q++) {
1139         if (*q == '"')
1140           *p++ = '\\';
1141         *p++ = *q;
1142       }
1143       *p++ = '"';
1144     }
1145     else
1146       p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint);
1147
1148     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
1149       p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster);
1150     }
1151
1152     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
1153     {
1154       p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
1155                      pos[i].x_offset, pos[i].y_offset);
1156       p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
1157                      pos[i].x_advance, pos[i].y_advance);
1158     }
1159
1160     *p++ = '}';
1161
1162     if (buf_size > (p - b))
1163     {
1164       unsigned int l = p - b;
1165       memcpy (buf, b, l);
1166       buf += l;
1167       buf_size -= l;
1168       *buf_consumed += l;
1169       *buf = '\0';
1170     } else
1171       return i - start;
1172   }
1173
1174   return end - start;
1175 }
1176
1177 static unsigned int
1178 _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
1179                                   unsigned int start,
1180                                   unsigned int end,
1181                                   char *buf,
1182                                   unsigned int buf_size,
1183                                   unsigned int *buf_consumed,
1184                                   hb_font_t *font,
1185                                   hb_buffer_serialize_flags_t flags)
1186 {
1187   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
1188   hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
1189   hb_direction_t direction = hb_buffer_get_direction (buffer);
1190
1191   *buf_consumed = 0;
1192   for (unsigned int i = start; i < end; i++)
1193   {
1194     char b[1024];
1195     char *p = b;
1196
1197     /* In the following code, we know b is large enough that no overflow can happen. */
1198
1199     if (i)
1200       *p++ = '|';
1201
1202     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
1203     {
1204       hb_font_glyph_to_string (font, info[i].codepoint, p, 128);
1205       p += strlen (p);
1206     }
1207     else
1208       p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint);
1209
1210     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
1211       p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster);
1212     }
1213
1214     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
1215     {
1216       if (pos[i].x_offset || pos[i].y_offset)
1217         p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset);
1218
1219       *p++ = '+';
1220       if (HB_DIRECTION_IS_HORIZONTAL (direction) || pos[i].x_advance)
1221         p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance);
1222       if (HB_DIRECTION_IS_VERTICAL (direction) || pos->y_advance)
1223         p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance);
1224     }
1225
1226     if (buf_size > (p - b))
1227     {
1228       unsigned int l = p - b;
1229       memcpy (buf, b, l);
1230       buf += l;
1231       buf_size -= l;
1232       *buf_consumed += l;
1233       *buf = '\0';
1234     } else
1235       return i - start;
1236   }
1237
1238   return end - start;
1239 }
1240
1241 /* Returns number of items, starting at start, that were serialized. */
1242 unsigned int
1243 hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
1244                             unsigned int start,
1245                             unsigned int end,
1246                             char *buf,
1247                             unsigned int buf_size,
1248                             unsigned int *buf_consumed,
1249                             hb_font_t *font, /* May be NULL */
1250                             hb_buffer_serialize_format_t format,
1251                             hb_buffer_serialize_flags_t flags)
1252 {
1253   assert (start <= end && end <= buffer->len);
1254
1255   *buf_consumed = 0;
1256
1257   assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
1258           buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
1259
1260   if (unlikely (start == end))
1261     return 0;
1262
1263   if (!font)
1264     font = hb_font_get_empty ();
1265
1266   switch (format)
1267   {
1268     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
1269       return _hb_buffer_serialize_glyphs_text (buffer, start, end,
1270                                                buf, buf_size, buf_consumed,
1271                                                font, flags);
1272
1273     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
1274       return _hb_buffer_serialize_glyphs_json (buffer, start, end,
1275                                                buf, buf_size, buf_consumed,
1276                                                font, flags);
1277
1278     default:
1279     case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
1280       return 0;
1281
1282   }
1283 }
1284
1285 hb_bool_t
1286 hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
1287                               const char *buf,
1288                               unsigned int buf_len,
1289                               unsigned int *buf_consumed,
1290                               hb_font_t *font, /* May be NULL */
1291                               hb_buffer_serialize_format_t format)
1292 {
1293   return false;
1294 }