hb-buffer.cc revision 82ecaff736e245e117d70b6ec1497508c6eb08d2
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/* Here is how the buffer works internally:
39 *
40 * There are two info pointers: info and out_info.  They always have
41 * the same allocated size, but different lengths.
42 *
43 * As an optimization, both info and out_info may point to the
44 * same piece of memory, which is owned by info.  This remains the
45 * case as long as out_len doesn't exceed i at any time.
46 * In that case, swap_buffers() is no-op and the glyph operations operate
47 * mostly in-place.
48 *
49 * As soon as out_info gets longer than info, out_info is moved over
50 * to an alternate buffer (which we reuse the pos buffer for!), and its
51 * current contents (out_len entries) are copied to the new place.
52 * This should all remain transparent to the user.  swap_buffers() then
53 * switches info and out_info.
54 */
55
56
57
58/* Internal API */
59
60bool
61hb_buffer_t::enlarge (unsigned int size)
62{
63  if (unlikely (in_error))
64    return false;
65
66  unsigned int new_allocated = allocated;
67  hb_glyph_position_t *new_pos = NULL;
68  hb_glyph_info_t *new_info = NULL;
69  bool separate_out = out_info != info;
70
71  if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
72    goto done;
73
74  while (size >= new_allocated)
75    new_allocated += (new_allocated >> 1) + 32;
76
77  ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
78  if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
79    goto done;
80
81  new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
82  new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
83
84done:
85  if (unlikely (!new_pos || !new_info))
86    in_error = true;
87
88  if (likely (new_pos))
89    pos = new_pos;
90
91  if (likely (new_info))
92    info = new_info;
93
94  out_info = separate_out ? (hb_glyph_info_t *) pos : info;
95  if (likely (!in_error))
96    allocated = new_allocated;
97
98  return likely (!in_error);
99}
100
101bool
102hb_buffer_t::make_room_for (unsigned int num_in,
103			    unsigned int num_out)
104{
105  if (unlikely (!ensure (out_len + num_out))) return false;
106
107  if (out_info == info &&
108      out_len + num_out > idx + num_in)
109  {
110    assert (have_output);
111
112    out_info = (hb_glyph_info_t *) pos;
113    memcpy (out_info, info, out_len * sizeof (out_info[0]));
114  }
115
116  return true;
117}
118
119void *
120hb_buffer_t::get_scratch_buffer (unsigned int *size)
121{
122  have_output = false;
123  have_positions = false;
124
125  out_len = 0;
126  out_info = info;
127
128  *size = allocated * sizeof (pos[0]);
129  return pos;
130}
131
132
133
134/* HarfBuzz-Internal API */
135
136void
137hb_buffer_t::reset (void)
138{
139  if (unlikely (hb_object_is_inert (this)))
140    return;
141
142  hb_unicode_funcs_destroy (unicode);
143  unicode = hb_unicode_funcs_get_default ();
144
145  clear ();
146}
147
148void
149hb_buffer_t::clear (void)
150{
151  if (unlikely (hb_object_is_inert (this)))
152    return;
153
154  hb_segment_properties_t default_props = _HB_BUFFER_PROPS_DEFAULT;
155  props = default_props;
156
157  content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
158  in_error = false;
159  have_output = false;
160  have_positions = false;
161
162  idx = 0;
163  len = 0;
164  out_len = 0;
165  out_info = info;
166
167  serial = 0;
168  memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
169  memset (allocated_var_owner, 0, sizeof allocated_var_owner);
170
171  memset (context, 0, sizeof context);
172  memset (context_len, 0, sizeof context_len);
173}
174
175void
176hb_buffer_t::add (hb_codepoint_t  codepoint,
177		  hb_mask_t       mask,
178		  unsigned int    cluster)
179{
180  hb_glyph_info_t *glyph;
181
182  if (unlikely (!ensure (len + 1))) return;
183
184  glyph = &info[len];
185
186  memset (glyph, 0, sizeof (*glyph));
187  glyph->codepoint = codepoint;
188  glyph->mask = mask;
189  glyph->cluster = cluster;
190
191  len++;
192}
193
194void
195hb_buffer_t::remove_output (void)
196{
197  if (unlikely (hb_object_is_inert (this)))
198    return;
199
200  have_output = false;
201  have_positions = false;
202
203  out_len = 0;
204  out_info = info;
205}
206
207void
208hb_buffer_t::clear_output (void)
209{
210  if (unlikely (hb_object_is_inert (this)))
211    return;
212
213  have_output = true;
214  have_positions = false;
215
216  out_len = 0;
217  out_info = info;
218}
219
220void
221hb_buffer_t::clear_positions (void)
222{
223  if (unlikely (hb_object_is_inert (this)))
224    return;
225
226  have_output = false;
227  have_positions = true;
228
229  out_len = 0;
230  out_info = info;
231
232  memset (pos, 0, sizeof (pos[0]) * len);
233}
234
235void
236hb_buffer_t::swap_buffers (void)
237{
238  if (unlikely (in_error)) return;
239
240  assert (have_output);
241  have_output = false;
242
243  if (out_info != info)
244  {
245    hb_glyph_info_t *tmp_string;
246    tmp_string = info;
247    info = out_info;
248    out_info = tmp_string;
249    pos = (hb_glyph_position_t *) out_info;
250  }
251
252  unsigned int tmp;
253  tmp = len;
254  len = out_len;
255  out_len = tmp;
256
257  idx = 0;
258}
259
260
261void
262hb_buffer_t::replace_glyphs (unsigned int num_in,
263			     unsigned int num_out,
264			     const uint32_t *glyph_data)
265{
266  if (unlikely (!make_room_for (num_in, num_out))) return;
267
268  merge_clusters (idx, idx + num_in);
269
270  hb_glyph_info_t orig_info = info[idx];
271  hb_glyph_info_t *pinfo = &out_info[out_len];
272  for (unsigned int i = 0; i < num_out; i++)
273  {
274    *pinfo = orig_info;
275    pinfo->codepoint = glyph_data[i];
276    pinfo++;
277  }
278
279  idx  += num_in;
280  out_len += num_out;
281}
282
283void
284hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
285{
286  if (unlikely (!make_room_for (0, 1))) return;
287
288  out_info[out_len] = info[idx];
289  out_info[out_len].codepoint = glyph_index;
290
291  out_len++;
292}
293
294void
295hb_buffer_t::output_info (hb_glyph_info_t &glyph_info)
296{
297  if (unlikely (!make_room_for (0, 1))) return;
298
299  out_info[out_len] = glyph_info;
300
301  out_len++;
302}
303
304void
305hb_buffer_t::copy_glyph (void)
306{
307  if (unlikely (!make_room_for (0, 1))) return;
308
309  out_info[out_len] = info[idx];
310
311  out_len++;
312}
313
314void
315hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
316{
317  if (unlikely (out_info != info || out_len != idx)) {
318    if (unlikely (!make_room_for (1, 1))) return;
319    out_info[out_len] = info[idx];
320  }
321  out_info[out_len].codepoint = glyph_index;
322
323  idx++;
324  out_len++;
325}
326
327
328void
329hb_buffer_t::set_masks (hb_mask_t    value,
330			hb_mask_t    mask,
331			unsigned int cluster_start,
332			unsigned int cluster_end)
333{
334  hb_mask_t not_mask = ~mask;
335  value &= mask;
336
337  if (!mask)
338    return;
339
340  if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
341    unsigned int count = len;
342    for (unsigned int i = 0; i < count; i++)
343      info[i].mask = (info[i].mask & not_mask) | value;
344    return;
345  }
346
347  unsigned int count = len;
348  for (unsigned int i = 0; i < count; i++)
349    if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
350      info[i].mask = (info[i].mask & not_mask) | value;
351}
352
353void
354hb_buffer_t::reverse_range (unsigned int start,
355			    unsigned int end)
356{
357  unsigned int i, j;
358
359  if (start == end - 1)
360    return;
361
362  for (i = start, j = end - 1; i < j; i++, j--) {
363    hb_glyph_info_t t;
364
365    t = info[i];
366    info[i] = info[j];
367    info[j] = t;
368  }
369
370  if (pos) {
371    for (i = start, j = end - 1; i < j; i++, j--) {
372      hb_glyph_position_t t;
373
374      t = pos[i];
375      pos[i] = pos[j];
376      pos[j] = t;
377    }
378  }
379}
380
381void
382hb_buffer_t::reverse (void)
383{
384  if (unlikely (!len))
385    return;
386
387  reverse_range (0, len);
388}
389
390void
391hb_buffer_t::reverse_clusters (void)
392{
393  unsigned int i, start, count, last_cluster;
394
395  if (unlikely (!len))
396    return;
397
398  reverse ();
399
400  count = len;
401  start = 0;
402  last_cluster = info[0].cluster;
403  for (i = 1; i < count; i++) {
404    if (last_cluster != info[i].cluster) {
405      reverse_range (start, i);
406      start = i;
407      last_cluster = info[i].cluster;
408    }
409  }
410  reverse_range (start, i);
411}
412
413void
414hb_buffer_t::merge_clusters (unsigned int start,
415			     unsigned int end)
416{
417  if (unlikely (end - start < 2))
418    return;
419
420  unsigned int cluster = info[start].cluster;
421
422  for (unsigned int i = start + 1; i < end; i++)
423    cluster = MIN (cluster, info[i].cluster);
424
425  /* Extend end */
426  while (end < len && info[end - 1].cluster == info[end].cluster)
427    end++;
428
429  /* Extend start */
430  while (idx < start && info[start - 1].cluster == info[start].cluster)
431    start--;
432
433  /* If we hit the start of buffer, continue in out-buffer. */
434  if (idx == start)
435    for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
436      out_info[i - 1].cluster = cluster;
437
438  for (unsigned int i = start; i < end; i++)
439    info[i].cluster = cluster;
440}
441void
442hb_buffer_t::merge_out_clusters (unsigned int start,
443				 unsigned int end)
444{
445  if (unlikely (end - start < 2))
446    return;
447
448  unsigned int cluster = out_info[start].cluster;
449
450  for (unsigned int i = start + 1; i < end; i++)
451    cluster = MIN (cluster, out_info[i].cluster);
452
453  /* Extend start */
454  while (start && out_info[start - 1].cluster == out_info[start].cluster)
455    start--;
456
457  /* Extend end */
458  while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)
459    end++;
460
461  /* If we hit the end of out-buffer, continue in buffer. */
462  if (end == out_len)
463    for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
464      info[i].cluster = cluster;
465
466  for (unsigned int i = start; i < end; i++)
467    out_info[i].cluster = cluster;
468}
469
470void
471hb_buffer_t::guess_properties (void)
472{
473  if (unlikely (!len)) return;
474  assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
475
476  /* If script is set to INVALID, guess from buffer contents */
477  if (props.script == HB_SCRIPT_INVALID) {
478    for (unsigned int i = 0; i < len; i++) {
479      hb_script_t script = unicode->script (info[i].codepoint);
480      if (likely (script != HB_SCRIPT_COMMON &&
481		  script != HB_SCRIPT_INHERITED &&
482		  script != HB_SCRIPT_UNKNOWN)) {
483        props.script = script;
484        break;
485      }
486    }
487  }
488
489  /* If direction is set to INVALID, guess from script */
490  if (props.direction == HB_DIRECTION_INVALID) {
491    props.direction = hb_script_get_horizontal_direction (props.script);
492  }
493
494  /* If language is not set, use default language from locale */
495  if (props.language == HB_LANGUAGE_INVALID) {
496    /* TODO get_default_for_script? using $LANGUAGE */
497    props.language = hb_language_get_default ();
498  }
499}
500
501
502static inline void
503dump_var_allocation (const hb_buffer_t *buffer)
504{
505  char buf[80];
506  for (unsigned int i = 0; i < 8; i++)
507    buf[i] = '0' + buffer->allocated_var_bytes[7 - i];
508  buf[8] = '\0';
509  DEBUG_MSG (BUFFER, buffer,
510	     "Current var allocation: %s",
511	     buf);
512}
513
514void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner)
515{
516  assert (byte_i < 8 && byte_i + count <= 8);
517
518  if (DEBUG (BUFFER))
519    dump_var_allocation (this);
520  DEBUG_MSG (BUFFER, this,
521	     "Allocating var bytes %d..%d for %s",
522	     byte_i, byte_i + count - 1, owner);
523
524  for (unsigned int i = byte_i; i < byte_i + count; i++) {
525    assert (!allocated_var_bytes[i]);
526    allocated_var_bytes[i]++;
527    allocated_var_owner[i] = owner;
528  }
529}
530
531void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
532{
533  if (DEBUG (BUFFER))
534    dump_var_allocation (this);
535
536  DEBUG_MSG (BUFFER, this,
537	     "Deallocating var bytes %d..%d for %s",
538	     byte_i, byte_i + count - 1, owner);
539
540  assert (byte_i < 8 && byte_i + count <= 8);
541  for (unsigned int i = byte_i; i < byte_i + count; i++) {
542    assert (allocated_var_bytes[i]);
543    assert (0 == strcmp (allocated_var_owner[i], owner));
544    allocated_var_bytes[i]--;
545  }
546}
547
548void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner)
549{
550  if (DEBUG (BUFFER))
551    dump_var_allocation (this);
552
553  DEBUG_MSG (BUFFER, this,
554	     "Asserting var bytes %d..%d for %s",
555	     byte_i, byte_i + count - 1, owner);
556
557  assert (byte_i < 8 && byte_i + count <= 8);
558  for (unsigned int i = byte_i; i < byte_i + count; i++) {
559    assert (allocated_var_bytes[i]);
560    assert (0 == strcmp (allocated_var_owner[i], owner));
561  }
562}
563
564void hb_buffer_t::deallocate_var_all (void)
565{
566  memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
567  memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
568}
569
570/* Public API */
571
572hb_buffer_t *
573hb_buffer_create ()
574{
575  hb_buffer_t *buffer;
576
577  if (!(buffer = hb_object_create<hb_buffer_t> ()))
578    return hb_buffer_get_empty ();
579
580  buffer->reset ();
581
582  return buffer;
583}
584
585hb_buffer_t *
586hb_buffer_get_empty (void)
587{
588  static const hb_buffer_t _hb_buffer_nil = {
589    HB_OBJECT_HEADER_STATIC,
590
591    const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
592    _HB_BUFFER_PROPS_DEFAULT,
593
594    HB_BUFFER_CONTENT_TYPE_INVALID,
595    true, /* in_error */
596    true, /* have_output */
597    true  /* have_positions */
598
599    /* Zero is good enough for everything else. */
600  };
601
602  return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
603}
604
605hb_buffer_t *
606hb_buffer_reference (hb_buffer_t *buffer)
607{
608  return hb_object_reference (buffer);
609}
610
611void
612hb_buffer_destroy (hb_buffer_t *buffer)
613{
614  if (!hb_object_destroy (buffer)) return;
615
616  hb_unicode_funcs_destroy (buffer->unicode);
617
618  free (buffer->info);
619  free (buffer->pos);
620
621  free (buffer);
622}
623
624hb_bool_t
625hb_buffer_set_user_data (hb_buffer_t        *buffer,
626			 hb_user_data_key_t *key,
627			 void *              data,
628			 hb_destroy_func_t   destroy,
629			 hb_bool_t           replace)
630{
631  return hb_object_set_user_data (buffer, key, data, destroy, replace);
632}
633
634void *
635hb_buffer_get_user_data (hb_buffer_t        *buffer,
636			 hb_user_data_key_t *key)
637{
638  return hb_object_get_user_data (buffer, key);
639}
640
641
642void
643hb_buffer_set_content_type (hb_buffer_t              *buffer,
644			    hb_buffer_content_type_t  content_type)
645{
646  buffer->content_type = content_type;
647}
648
649hb_buffer_content_type_t
650hb_buffer_get_content_type (hb_buffer_t *buffer)
651{
652  return buffer->content_type;
653}
654
655
656void
657hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
658			     hb_unicode_funcs_t *unicode)
659{
660  if (unlikely (hb_object_is_inert (buffer)))
661    return;
662
663  if (!unicode)
664    unicode = hb_unicode_funcs_get_default ();
665
666
667  hb_unicode_funcs_reference (unicode);
668  hb_unicode_funcs_destroy (buffer->unicode);
669  buffer->unicode = unicode;
670}
671
672hb_unicode_funcs_t *
673hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
674{
675  return buffer->unicode;
676}
677
678void
679hb_buffer_set_direction (hb_buffer_t    *buffer,
680			 hb_direction_t  direction)
681
682{
683  if (unlikely (hb_object_is_inert (buffer)))
684    return;
685
686  buffer->props.direction = direction;
687}
688
689hb_direction_t
690hb_buffer_get_direction (hb_buffer_t    *buffer)
691{
692  return buffer->props.direction;
693}
694
695void
696hb_buffer_set_script (hb_buffer_t *buffer,
697		      hb_script_t  script)
698{
699  if (unlikely (hb_object_is_inert (buffer)))
700    return;
701
702  buffer->props.script = script;
703}
704
705hb_script_t
706hb_buffer_get_script (hb_buffer_t *buffer)
707{
708  return buffer->props.script;
709}
710
711void
712hb_buffer_set_language (hb_buffer_t   *buffer,
713			hb_language_t  language)
714{
715  if (unlikely (hb_object_is_inert (buffer)))
716    return;
717
718  buffer->props.language = language;
719}
720
721hb_language_t
722hb_buffer_get_language (hb_buffer_t *buffer)
723{
724  return buffer->props.language;
725}
726
727
728void
729hb_buffer_reset (hb_buffer_t *buffer)
730{
731  buffer->reset ();
732}
733
734void
735hb_buffer_clear (hb_buffer_t *buffer)
736{
737  buffer->clear ();
738}
739
740hb_bool_t
741hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
742{
743  return buffer->ensure (size);
744}
745
746hb_bool_t
747hb_buffer_allocation_successful (hb_buffer_t  *buffer)
748{
749  return !buffer->in_error;
750}
751
752void
753hb_buffer_add (hb_buffer_t    *buffer,
754	       hb_codepoint_t  codepoint,
755	       hb_mask_t       mask,
756	       unsigned int    cluster)
757{
758  buffer->add (codepoint, mask, cluster);
759  buffer->clear_context (1);
760}
761
762hb_bool_t
763hb_buffer_set_length (hb_buffer_t  *buffer,
764		      unsigned int  length)
765{
766  if (unlikely (hb_object_is_inert (buffer)))
767    return length == 0;
768
769  if (!buffer->ensure (length))
770    return false;
771
772  /* Wipe the new space */
773  if (length > buffer->len) {
774    memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
775    if (buffer->have_positions)
776      memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
777  }
778
779  buffer->len = length;
780
781  if (!length)
782    buffer->clear_context (0);
783  buffer->clear_context (1);
784
785  return true;
786}
787
788unsigned int
789hb_buffer_get_length (hb_buffer_t *buffer)
790{
791  return buffer->len;
792}
793
794/* Return value valid as long as buffer not modified */
795hb_glyph_info_t *
796hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
797                           unsigned int *length)
798{
799  if (length)
800    *length = buffer->len;
801
802  return (hb_glyph_info_t *) buffer->info;
803}
804
805/* Return value valid as long as buffer not modified */
806hb_glyph_position_t *
807hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
808                               unsigned int *length)
809{
810  if (!buffer->have_positions)
811    buffer->clear_positions ();
812
813  if (length)
814    *length = buffer->len;
815
816  return (hb_glyph_position_t *) buffer->pos;
817}
818
819void
820hb_buffer_reverse (hb_buffer_t *buffer)
821{
822  buffer->reverse ();
823}
824
825void
826hb_buffer_reverse_clusters (hb_buffer_t *buffer)
827{
828  buffer->reverse_clusters ();
829}
830
831void
832hb_buffer_guess_properties (hb_buffer_t *buffer)
833{
834  buffer->guess_properties ();
835}
836
837template <typename T>
838static inline void
839hb_buffer_add_utf (hb_buffer_t  *buffer,
840		   const T      *text,
841		   int           text_length,
842		   unsigned int  item_offset,
843		   int           item_length)
844{
845  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
846	  (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
847
848  if (unlikely (hb_object_is_inert (buffer)))
849    return;
850
851  if (text_length == -1)
852    text_length = hb_utf_strlen (text);
853
854  if (item_length == -1)
855    item_length = text_length - item_offset;
856
857  buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
858
859  /* If buffer is empty and pre-context provided, install it.
860   * This check is written this way, to make sure people can
861   * provide pre-context in one add_utf() call, then provide
862   * text in a follow-up call.  See:
863   *
864   * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
865   */
866  if (!buffer->len && item_offset > 0)
867  {
868    /* Add pre-context */
869    buffer->clear_context (0);
870    const T *prev = text + item_offset;
871    const T *start = text;
872    while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
873    {
874      hb_codepoint_t u;
875      prev = hb_utf_prev (prev, start, &u);
876      buffer->context[0][buffer->context_len[0]++] = u;
877    }
878  }
879
880  const T *next = text + item_offset;
881  const T *end = next + item_length;
882  while (next < end)
883  {
884    hb_codepoint_t u;
885    const T *old_next = next;
886    next = hb_utf_next (next, end, &u);
887    buffer->add (u, 1,  old_next - (const T *) text);
888  }
889
890  /* Add post-context */
891  buffer->clear_context (1);
892  end = text + text_length;
893  while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
894  {
895    hb_codepoint_t u;
896    next = hb_utf_next (next, end, &u);
897    buffer->context[1][buffer->context_len[1]++] = u;
898  }
899
900  buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
901}
902
903void
904hb_buffer_add_utf8 (hb_buffer_t  *buffer,
905		    const char   *text,
906		    int           text_length,
907		    unsigned int  item_offset,
908		    int           item_length)
909{
910  hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
911}
912
913void
914hb_buffer_add_utf16 (hb_buffer_t    *buffer,
915		     const uint16_t *text,
916		     int             text_length,
917		     unsigned int    item_offset,
918		     int            item_length)
919{
920  hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
921}
922
923void
924hb_buffer_add_utf32 (hb_buffer_t    *buffer,
925		     const uint32_t *text,
926		     int             text_length,
927		     unsigned int    item_offset,
928		     int             item_length)
929{
930  hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
931}
932
933
934static int
935compare_info_codepoint (const hb_glyph_info_t *pa,
936			const hb_glyph_info_t *pb)
937{
938  return (int) pb->codepoint - (int) pa->codepoint;
939}
940
941static inline void
942normalize_glyphs_cluster (hb_buffer_t *buffer,
943			  unsigned int start,
944			  unsigned int end,
945			  bool backward)
946{
947  hb_glyph_position_t *pos = buffer->pos;
948
949  /* Total cluster advance */
950  hb_position_t total_x_advance = 0, total_y_advance = 0;
951  for (unsigned int i = start; i < end; i++)
952  {
953    total_x_advance += pos[i].x_advance;
954    total_y_advance += pos[i].y_advance;
955  }
956
957  hb_position_t x_advance = 0, y_advance = 0;
958  for (unsigned int i = start; i < end; i++)
959  {
960    pos[i].x_offset += x_advance;
961    pos[i].y_offset += y_advance;
962
963    x_advance += pos[i].x_advance;
964    y_advance += pos[i].y_advance;
965
966    pos[i].x_advance = 0;
967    pos[i].y_advance = 0;
968  }
969
970  if (backward)
971  {
972    /* Transfer all cluster advance to the last glyph. */
973    pos[end - 1].x_advance = total_x_advance;
974    pos[end - 1].y_advance = total_y_advance;
975
976    hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
977  } else {
978    /* Transfer all cluster advance to the first glyph. */
979    pos[start].x_advance += total_x_advance;
980    pos[start].y_advance += total_y_advance;
981    for (unsigned int i = start + 1; i < end; i++) {
982      pos[i].x_offset -= total_x_advance;
983      pos[i].y_offset -= total_y_advance;
984    }
985    hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
986  }
987}
988
989void
990hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
991{
992  assert (buffer->have_positions);
993  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
994
995  bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
996
997  unsigned int count = buffer->len;
998  if (unlikely (!count)) return;
999  hb_glyph_info_t *info = buffer->info;
1000
1001  unsigned int start = 0;
1002  unsigned int end;
1003  for (end = start + 1; end < count; end++)
1004    if (info[start].cluster != info[end].cluster) {
1005      normalize_glyphs_cluster (buffer, start, end, backward);
1006      start = end;
1007    }
1008  normalize_glyphs_cluster (buffer, start, end, backward);
1009}
1010