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::add_info (const hb_glyph_info_t &glyph_info)
219{
220  if (unlikely (!ensure (len + 1))) return;
221
222  info[len] = glyph_info;
223
224  len++;
225}
226
227
228void
229hb_buffer_t::remove_output (void)
230{
231  if (unlikely (hb_object_is_inert (this)))
232    return;
233
234  have_output = false;
235  have_positions = false;
236
237  out_len = 0;
238  out_info = info;
239}
240
241void
242hb_buffer_t::clear_output (void)
243{
244  if (unlikely (hb_object_is_inert (this)))
245    return;
246
247  have_output = true;
248  have_positions = false;
249
250  out_len = 0;
251  out_info = info;
252}
253
254void
255hb_buffer_t::clear_positions (void)
256{
257  if (unlikely (hb_object_is_inert (this)))
258    return;
259
260  have_output = false;
261  have_positions = true;
262
263  out_len = 0;
264  out_info = info;
265
266  memset (pos, 0, sizeof (pos[0]) * len);
267}
268
269void
270hb_buffer_t::swap_buffers (void)
271{
272  if (unlikely (in_error)) return;
273
274  assert (have_output);
275  have_output = false;
276
277  if (out_info != info)
278  {
279    hb_glyph_info_t *tmp_string;
280    tmp_string = info;
281    info = out_info;
282    out_info = tmp_string;
283    pos = (hb_glyph_position_t *) out_info;
284  }
285
286  unsigned int tmp;
287  tmp = len;
288  len = out_len;
289  out_len = tmp;
290
291  idx = 0;
292}
293
294
295void
296hb_buffer_t::replace_glyphs (unsigned int num_in,
297			     unsigned int num_out,
298			     const uint32_t *glyph_data)
299{
300  if (unlikely (!make_room_for (num_in, num_out))) return;
301
302  merge_clusters (idx, idx + num_in);
303
304  hb_glyph_info_t orig_info = info[idx];
305  hb_glyph_info_t *pinfo = &out_info[out_len];
306  for (unsigned int i = 0; i < num_out; i++)
307  {
308    *pinfo = orig_info;
309    pinfo->codepoint = glyph_data[i];
310    pinfo++;
311  }
312
313  idx  += num_in;
314  out_len += num_out;
315}
316
317void
318hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
319{
320  if (unlikely (!make_room_for (0, 1))) return;
321
322  out_info[out_len] = info[idx];
323  out_info[out_len].codepoint = glyph_index;
324
325  out_len++;
326}
327
328void
329hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info)
330{
331  if (unlikely (!make_room_for (0, 1))) return;
332
333  out_info[out_len] = glyph_info;
334
335  out_len++;
336}
337
338void
339hb_buffer_t::copy_glyph (void)
340{
341  if (unlikely (!make_room_for (0, 1))) return;
342
343  out_info[out_len] = info[idx];
344
345  out_len++;
346}
347
348void
349hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
350{
351  if (unlikely (out_info != info || out_len != idx)) {
352    if (unlikely (!make_room_for (1, 1))) return;
353    out_info[out_len] = info[idx];
354  }
355  out_info[out_len].codepoint = glyph_index;
356
357  idx++;
358  out_len++;
359}
360
361
362void
363hb_buffer_t::set_masks (hb_mask_t    value,
364			hb_mask_t    mask,
365			unsigned int cluster_start,
366			unsigned int cluster_end)
367{
368  hb_mask_t not_mask = ~mask;
369  value &= mask;
370
371  if (!mask)
372    return;
373
374  if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
375    unsigned int count = len;
376    for (unsigned int i = 0; i < count; i++)
377      info[i].mask = (info[i].mask & not_mask) | value;
378    return;
379  }
380
381  unsigned int count = len;
382  for (unsigned int i = 0; i < count; i++)
383    if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
384      info[i].mask = (info[i].mask & not_mask) | value;
385}
386
387void
388hb_buffer_t::reverse_range (unsigned int start,
389			    unsigned int end)
390{
391  unsigned int i, j;
392
393  if (start == end - 1)
394    return;
395
396  for (i = start, j = end - 1; i < j; i++, j--) {
397    hb_glyph_info_t t;
398
399    t = info[i];
400    info[i] = info[j];
401    info[j] = t;
402  }
403
404  if (pos) {
405    for (i = start, j = end - 1; i < j; i++, j--) {
406      hb_glyph_position_t t;
407
408      t = pos[i];
409      pos[i] = pos[j];
410      pos[j] = t;
411    }
412  }
413}
414
415void
416hb_buffer_t::reverse (void)
417{
418  if (unlikely (!len))
419    return;
420
421  reverse_range (0, len);
422}
423
424void
425hb_buffer_t::reverse_clusters (void)
426{
427  unsigned int i, start, count, last_cluster;
428
429  if (unlikely (!len))
430    return;
431
432  reverse ();
433
434  count = len;
435  start = 0;
436  last_cluster = info[0].cluster;
437  for (i = 1; i < count; i++) {
438    if (last_cluster != info[i].cluster) {
439      reverse_range (start, i);
440      start = i;
441      last_cluster = info[i].cluster;
442    }
443  }
444  reverse_range (start, i);
445}
446
447void
448hb_buffer_t::merge_clusters (unsigned int start,
449			     unsigned int end)
450{
451  if (unlikely (end - start < 2))
452    return;
453
454  unsigned int cluster = info[start].cluster;
455
456  for (unsigned int i = start + 1; i < end; i++)
457    cluster = MIN (cluster, info[i].cluster);
458
459  /* Extend end */
460  while (end < len && info[end - 1].cluster == info[end].cluster)
461    end++;
462
463  /* Extend start */
464  while (idx < start && info[start - 1].cluster == info[start].cluster)
465    start--;
466
467  /* If we hit the start of buffer, continue in out-buffer. */
468  if (idx == start)
469    for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
470      out_info[i - 1].cluster = cluster;
471
472  for (unsigned int i = start; i < end; i++)
473    info[i].cluster = cluster;
474}
475void
476hb_buffer_t::merge_out_clusters (unsigned int start,
477				 unsigned int end)
478{
479  if (unlikely (end - start < 2))
480    return;
481
482  unsigned int cluster = out_info[start].cluster;
483
484  for (unsigned int i = start + 1; i < end; i++)
485    cluster = MIN (cluster, out_info[i].cluster);
486
487  /* Extend start */
488  while (start && out_info[start - 1].cluster == out_info[start].cluster)
489    start--;
490
491  /* Extend end */
492  while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)
493    end++;
494
495  /* If we hit the end of out-buffer, continue in buffer. */
496  if (end == out_len)
497    for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
498      info[i].cluster = cluster;
499
500  for (unsigned int i = start; i < end; i++)
501    out_info[i].cluster = cluster;
502}
503
504void
505hb_buffer_t::guess_segment_properties (void)
506{
507  assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
508	  (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
509
510  /* If script is set to INVALID, guess from buffer contents */
511  if (props.script == HB_SCRIPT_INVALID) {
512    for (unsigned int i = 0; i < len; i++) {
513      hb_script_t script = unicode->script (info[i].codepoint);
514      if (likely (script != HB_SCRIPT_COMMON &&
515		  script != HB_SCRIPT_INHERITED &&
516		  script != HB_SCRIPT_UNKNOWN)) {
517        props.script = script;
518        break;
519      }
520    }
521  }
522
523  /* If direction is set to INVALID, guess from script */
524  if (props.direction == HB_DIRECTION_INVALID) {
525    props.direction = hb_script_get_horizontal_direction (props.script);
526  }
527
528  /* If language is not set, use default language from locale */
529  if (props.language == HB_LANGUAGE_INVALID) {
530    /* TODO get_default_for_script? using $LANGUAGE */
531    props.language = hb_language_get_default ();
532  }
533}
534
535
536static inline void
537dump_var_allocation (const hb_buffer_t *buffer)
538{
539  char buf[80];
540  for (unsigned int i = 0; i < 8; i++)
541    buf[i] = '0' + buffer->allocated_var_bytes[7 - i];
542  buf[8] = '\0';
543  DEBUG_MSG (BUFFER, buffer,
544	     "Current var allocation: %s",
545	     buf);
546}
547
548void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner)
549{
550  assert (byte_i < 8 && byte_i + count <= 8);
551
552  if (DEBUG_ENABLED (BUFFER))
553    dump_var_allocation (this);
554  DEBUG_MSG (BUFFER, this,
555	     "Allocating var bytes %d..%d for %s",
556	     byte_i, byte_i + count - 1, owner);
557
558  for (unsigned int i = byte_i; i < byte_i + count; i++) {
559    assert (!allocated_var_bytes[i]);
560    allocated_var_bytes[i]++;
561    allocated_var_owner[i] = owner;
562  }
563}
564
565void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
566{
567  if (DEBUG_ENABLED (BUFFER))
568    dump_var_allocation (this);
569
570  DEBUG_MSG (BUFFER, this,
571	     "Deallocating var bytes %d..%d for %s",
572	     byte_i, byte_i + count - 1, owner);
573
574  assert (byte_i < 8 && byte_i + count <= 8);
575  for (unsigned int i = byte_i; i < byte_i + count; i++) {
576    assert (allocated_var_bytes[i]);
577    assert (0 == strcmp (allocated_var_owner[i], owner));
578    allocated_var_bytes[i]--;
579  }
580}
581
582void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner)
583{
584  if (DEBUG_ENABLED (BUFFER))
585    dump_var_allocation (this);
586
587  DEBUG_MSG (BUFFER, this,
588	     "Asserting var bytes %d..%d for %s",
589	     byte_i, byte_i + count - 1, owner);
590
591  assert (byte_i < 8 && byte_i + count <= 8);
592  for (unsigned int i = byte_i; i < byte_i + count; i++) {
593    assert (allocated_var_bytes[i]);
594    assert (0 == strcmp (allocated_var_owner[i], owner));
595  }
596}
597
598void hb_buffer_t::deallocate_var_all (void)
599{
600  memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
601  memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
602}
603
604/* Public API */
605
606hb_buffer_t *
607hb_buffer_create (void)
608{
609  hb_buffer_t *buffer;
610
611  if (!(buffer = hb_object_create<hb_buffer_t> ()))
612    return hb_buffer_get_empty ();
613
614  buffer->reset ();
615
616  return buffer;
617}
618
619hb_buffer_t *
620hb_buffer_get_empty (void)
621{
622  static const hb_buffer_t _hb_buffer_nil = {
623    HB_OBJECT_HEADER_STATIC,
624
625    const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
626    HB_SEGMENT_PROPERTIES_DEFAULT,
627    HB_BUFFER_FLAGS_DEFAULT,
628
629    HB_BUFFER_CONTENT_TYPE_INVALID,
630    true, /* in_error */
631    true, /* have_output */
632    true  /* have_positions */
633
634    /* Zero is good enough for everything else. */
635  };
636
637  return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
638}
639
640hb_buffer_t *
641hb_buffer_reference (hb_buffer_t *buffer)
642{
643  return hb_object_reference (buffer);
644}
645
646void
647hb_buffer_destroy (hb_buffer_t *buffer)
648{
649  if (!hb_object_destroy (buffer)) return;
650
651  hb_unicode_funcs_destroy (buffer->unicode);
652
653  free (buffer->info);
654  free (buffer->pos);
655
656  free (buffer);
657}
658
659hb_bool_t
660hb_buffer_set_user_data (hb_buffer_t        *buffer,
661			 hb_user_data_key_t *key,
662			 void *              data,
663			 hb_destroy_func_t   destroy,
664			 hb_bool_t           replace)
665{
666  return hb_object_set_user_data (buffer, key, data, destroy, replace);
667}
668
669void *
670hb_buffer_get_user_data (hb_buffer_t        *buffer,
671			 hb_user_data_key_t *key)
672{
673  return hb_object_get_user_data (buffer, key);
674}
675
676
677void
678hb_buffer_set_content_type (hb_buffer_t              *buffer,
679			    hb_buffer_content_type_t  content_type)
680{
681  buffer->content_type = content_type;
682}
683
684hb_buffer_content_type_t
685hb_buffer_get_content_type (hb_buffer_t *buffer)
686{
687  return buffer->content_type;
688}
689
690
691void
692hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
693			     hb_unicode_funcs_t *unicode)
694{
695  if (unlikely (hb_object_is_inert (buffer)))
696    return;
697
698  if (!unicode)
699    unicode = hb_unicode_funcs_get_default ();
700
701
702  hb_unicode_funcs_reference (unicode);
703  hb_unicode_funcs_destroy (buffer->unicode);
704  buffer->unicode = unicode;
705}
706
707hb_unicode_funcs_t *
708hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
709{
710  return buffer->unicode;
711}
712
713void
714hb_buffer_set_direction (hb_buffer_t    *buffer,
715			 hb_direction_t  direction)
716
717{
718  if (unlikely (hb_object_is_inert (buffer)))
719    return;
720
721  buffer->props.direction = direction;
722}
723
724hb_direction_t
725hb_buffer_get_direction (hb_buffer_t    *buffer)
726{
727  return buffer->props.direction;
728}
729
730void
731hb_buffer_set_script (hb_buffer_t *buffer,
732		      hb_script_t  script)
733{
734  if (unlikely (hb_object_is_inert (buffer)))
735    return;
736
737  buffer->props.script = script;
738}
739
740hb_script_t
741hb_buffer_get_script (hb_buffer_t *buffer)
742{
743  return buffer->props.script;
744}
745
746void
747hb_buffer_set_language (hb_buffer_t   *buffer,
748			hb_language_t  language)
749{
750  if (unlikely (hb_object_is_inert (buffer)))
751    return;
752
753  buffer->props.language = language;
754}
755
756hb_language_t
757hb_buffer_get_language (hb_buffer_t *buffer)
758{
759  return buffer->props.language;
760}
761
762void
763hb_buffer_set_segment_properties (hb_buffer_t *buffer,
764				  const hb_segment_properties_t *props)
765{
766  if (unlikely (hb_object_is_inert (buffer)))
767    return;
768
769  buffer->props = *props;
770}
771
772void
773hb_buffer_get_segment_properties (hb_buffer_t *buffer,
774				  hb_segment_properties_t *props)
775{
776  *props = buffer->props;
777}
778
779
780void
781hb_buffer_set_flags (hb_buffer_t       *buffer,
782		     hb_buffer_flags_t  flags)
783{
784  if (unlikely (hb_object_is_inert (buffer)))
785    return;
786
787  buffer->flags = flags;
788}
789
790hb_buffer_flags_t
791hb_buffer_get_flags (hb_buffer_t *buffer)
792{
793  return buffer->flags;
794}
795
796
797void
798hb_buffer_reset (hb_buffer_t *buffer)
799{
800  buffer->reset ();
801}
802
803void
804hb_buffer_clear_contents (hb_buffer_t *buffer)
805{
806  buffer->clear ();
807}
808
809hb_bool_t
810hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
811{
812  return buffer->ensure (size);
813}
814
815hb_bool_t
816hb_buffer_allocation_successful (hb_buffer_t  *buffer)
817{
818  return !buffer->in_error;
819}
820
821void
822hb_buffer_add (hb_buffer_t    *buffer,
823	       hb_codepoint_t  codepoint,
824	       unsigned int    cluster)
825{
826  buffer->add (codepoint, cluster);
827  buffer->clear_context (1);
828}
829
830hb_bool_t
831hb_buffer_set_length (hb_buffer_t  *buffer,
832		      unsigned int  length)
833{
834  if (unlikely (hb_object_is_inert (buffer)))
835    return length == 0;
836
837  if (!buffer->ensure (length))
838    return false;
839
840  /* Wipe the new space */
841  if (length > buffer->len) {
842    memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
843    if (buffer->have_positions)
844      memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
845  }
846
847  buffer->len = length;
848
849  if (!length)
850    buffer->clear_context (0);
851  buffer->clear_context (1);
852
853  return true;
854}
855
856unsigned int
857hb_buffer_get_length (hb_buffer_t *buffer)
858{
859  return buffer->len;
860}
861
862/* Return value valid as long as buffer not modified */
863hb_glyph_info_t *
864hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
865                           unsigned int *length)
866{
867  if (length)
868    *length = buffer->len;
869
870  return (hb_glyph_info_t *) buffer->info;
871}
872
873/* Return value valid as long as buffer not modified */
874hb_glyph_position_t *
875hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
876                               unsigned int *length)
877{
878  if (!buffer->have_positions)
879    buffer->clear_positions ();
880
881  if (length)
882    *length = buffer->len;
883
884  return (hb_glyph_position_t *) buffer->pos;
885}
886
887void
888hb_buffer_reverse (hb_buffer_t *buffer)
889{
890  buffer->reverse ();
891}
892
893void
894hb_buffer_reverse_clusters (hb_buffer_t *buffer)
895{
896  buffer->reverse_clusters ();
897}
898
899void
900hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
901{
902  buffer->guess_segment_properties ();
903}
904
905template <typename T>
906static inline void
907hb_buffer_add_utf (hb_buffer_t  *buffer,
908		   const T      *text,
909		   int           text_length,
910		   unsigned int  item_offset,
911		   int           item_length)
912{
913  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
914	  (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
915
916  if (unlikely (hb_object_is_inert (buffer)))
917    return;
918
919  if (text_length == -1)
920    text_length = hb_utf_strlen (text);
921
922  if (item_length == -1)
923    item_length = text_length - item_offset;
924
925  buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
926
927  /* If buffer is empty and pre-context provided, install it.
928   * This check is written this way, to make sure people can
929   * provide pre-context in one add_utf() call, then provide
930   * text in a follow-up call.  See:
931   *
932   * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
933   */
934  if (!buffer->len && item_offset > 0)
935  {
936    /* Add pre-context */
937    buffer->clear_context (0);
938    const T *prev = text + item_offset;
939    const T *start = text;
940    while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
941    {
942      hb_codepoint_t u;
943      prev = hb_utf_prev (prev, start, &u);
944      buffer->context[0][buffer->context_len[0]++] = u;
945    }
946  }
947
948  const T *next = text + item_offset;
949  const T *end = next + item_length;
950  while (next < end)
951  {
952    hb_codepoint_t u;
953    const T *old_next = next;
954    next = hb_utf_next (next, end, &u);
955    buffer->add (u, old_next - (const T *) text);
956  }
957
958  /* Add post-context */
959  buffer->clear_context (1);
960  end = text + text_length;
961  while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
962  {
963    hb_codepoint_t u;
964    next = hb_utf_next (next, end, &u);
965    buffer->context[1][buffer->context_len[1]++] = u;
966  }
967
968  buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
969}
970
971void
972hb_buffer_add_utf8 (hb_buffer_t  *buffer,
973		    const char   *text,
974		    int           text_length,
975		    unsigned int  item_offset,
976		    int           item_length)
977{
978  hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
979}
980
981void
982hb_buffer_add_utf16 (hb_buffer_t    *buffer,
983		     const uint16_t *text,
984		     int             text_length,
985		     unsigned int    item_offset,
986		     int            item_length)
987{
988  hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
989}
990
991void
992hb_buffer_add_utf32 (hb_buffer_t    *buffer,
993		     const uint32_t *text,
994		     int             text_length,
995		     unsigned int    item_offset,
996		     int             item_length)
997{
998  hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
999}
1000
1001
1002static int
1003compare_info_codepoint (const hb_glyph_info_t *pa,
1004			const hb_glyph_info_t *pb)
1005{
1006  return (int) pb->codepoint - (int) pa->codepoint;
1007}
1008
1009static inline void
1010normalize_glyphs_cluster (hb_buffer_t *buffer,
1011			  unsigned int start,
1012			  unsigned int end,
1013			  bool backward)
1014{
1015  hb_glyph_position_t *pos = buffer->pos;
1016
1017  /* Total cluster advance */
1018  hb_position_t total_x_advance = 0, total_y_advance = 0;
1019  for (unsigned int i = start; i < end; i++)
1020  {
1021    total_x_advance += pos[i].x_advance;
1022    total_y_advance += pos[i].y_advance;
1023  }
1024
1025  hb_position_t x_advance = 0, y_advance = 0;
1026  for (unsigned int i = start; i < end; i++)
1027  {
1028    pos[i].x_offset += x_advance;
1029    pos[i].y_offset += y_advance;
1030
1031    x_advance += pos[i].x_advance;
1032    y_advance += pos[i].y_advance;
1033
1034    pos[i].x_advance = 0;
1035    pos[i].y_advance = 0;
1036  }
1037
1038  if (backward)
1039  {
1040    /* Transfer all cluster advance to the last glyph. */
1041    pos[end - 1].x_advance = total_x_advance;
1042    pos[end - 1].y_advance = total_y_advance;
1043
1044    hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
1045  } else {
1046    /* Transfer all cluster advance to the first glyph. */
1047    pos[start].x_advance += total_x_advance;
1048    pos[start].y_advance += total_y_advance;
1049    for (unsigned int i = start + 1; i < end; i++) {
1050      pos[i].x_offset -= total_x_advance;
1051      pos[i].y_offset -= total_y_advance;
1052    }
1053    hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
1054  }
1055}
1056
1057void
1058hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
1059{
1060  assert (buffer->have_positions);
1061  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
1062
1063  bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
1064
1065  unsigned int count = buffer->len;
1066  if (unlikely (!count)) return;
1067  hb_glyph_info_t *info = buffer->info;
1068
1069  unsigned int start = 0;
1070  unsigned int end;
1071  for (end = start + 1; end < count; end++)
1072    if (info[start].cluster != info[end].cluster) {
1073      normalize_glyphs_cluster (buffer, start, end, backward);
1074      start = end;
1075    }
1076  normalize_glyphs_cluster (buffer, start, end, backward);
1077}
1078