hb-buffer.cc revision 3f82f8ff07a9d16a7c047129658c1bbedfdb5436
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
39hb_bool_t
40hb_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
51unsigned int
52hb_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
83bool
84hb_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
107done:
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
124bool
125hb_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
142void *
143hb_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
159void
160hb_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
171void
172hb_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
199void
200hb_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
217void
218hb_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
230void
231hb_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
243void
244hb_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
258void
259hb_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
284void
285hb_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
306void
307hb_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
317void
318hb_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
327void
328hb_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
337void
338hb_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
351void
352hb_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
376void
377hb_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
404void
405hb_buffer_t::reverse (void)
406{
407  if (unlikely (!len))
408    return;
409
410  reverse_range (0, len);
411}
412
413void
414hb_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
436void
437hb_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}
464void
465hb_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
493void
494hb_buffer_t::guess_segment_properties (void)
495{
496  if (unlikely (!len)) return;
497  assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
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
525static inline void
526dump_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
537void 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
554void 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
571void 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
587void 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
595hb_buffer_t *
596hb_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
608hb_buffer_t *
609hb_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
629hb_buffer_t *
630hb_buffer_reference (hb_buffer_t *buffer)
631{
632  return hb_object_reference (buffer);
633}
634
635void
636hb_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
648hb_bool_t
649hb_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
658void *
659hb_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
666void
667hb_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
673hb_buffer_content_type_t
674hb_buffer_get_content_type (hb_buffer_t *buffer)
675{
676  return buffer->content_type;
677}
678
679
680void
681hb_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
696hb_unicode_funcs_t *
697hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
698{
699  return buffer->unicode;
700}
701
702void
703hb_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
713hb_direction_t
714hb_buffer_get_direction (hb_buffer_t    *buffer)
715{
716  return buffer->props.direction;
717}
718
719void
720hb_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
729hb_script_t
730hb_buffer_get_script (hb_buffer_t *buffer)
731{
732  return buffer->props.script;
733}
734
735void
736hb_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
745hb_language_t
746hb_buffer_get_language (hb_buffer_t *buffer)
747{
748  return buffer->props.language;
749}
750
751void
752hb_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
761void
762hb_buffer_get_segment_properties (hb_buffer_t *buffer,
763				  hb_segment_properties_t *props)
764{
765  *props = buffer->props;
766}
767
768
769void
770hb_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
779hb_buffer_flags_t
780hb_buffer_get_flags (hb_buffer_t *buffer)
781{
782  return buffer->flags;
783}
784
785
786void
787hb_buffer_reset (hb_buffer_t *buffer)
788{
789  buffer->reset ();
790}
791
792void
793hb_buffer_clear (hb_buffer_t *buffer)
794{
795  buffer->clear ();
796}
797
798hb_bool_t
799hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
800{
801  return buffer->ensure (size);
802}
803
804hb_bool_t
805hb_buffer_allocation_successful (hb_buffer_t  *buffer)
806{
807  return !buffer->in_error;
808}
809
810void
811hb_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
819hb_bool_t
820hb_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
845unsigned int
846hb_buffer_get_length (hb_buffer_t *buffer)
847{
848  return buffer->len;
849}
850
851/* Return value valid as long as buffer not modified */
852hb_glyph_info_t *
853hb_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 */
863hb_glyph_position_t *
864hb_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
876void
877hb_buffer_reverse (hb_buffer_t *buffer)
878{
879  buffer->reverse ();
880}
881
882void
883hb_buffer_reverse_clusters (hb_buffer_t *buffer)
884{
885  buffer->reverse_clusters ();
886}
887
888void
889hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
890{
891  buffer->guess_segment_properties ();
892}
893
894template <typename T>
895static inline void
896hb_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
960void
961hb_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
970void
971hb_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
980void
981hb_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
991static int
992compare_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
998static inline void
999normalize_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
1046void
1047hb_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
1073static const char *serialize_formats[] = {
1074  "TEXT",
1075  "JSON",
1076  NULL
1077};
1078
1079const char **
1080hb_buffer_serialize_list_formats (void)
1081{
1082  return serialize_formats;
1083}
1084
1085hb_buffer_serialize_format_t
1086hb_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
1092const char *
1093hb_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
1104static 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
1177static 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. */
1242unsigned int
1243hb_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
1285hb_bool_t
1286hb_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}
1295