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
142bool
143hb_buffer_t::shift_forward (unsigned int count)
144{
145  assert (have_output);
146  if (unlikely (!ensure (len + count))) return false;
147
148  memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));
149  len += count;
150  idx += count;
151
152  return true;
153}
154
155hb_buffer_t::scratch_buffer_t *
156hb_buffer_t::get_scratch_buffer (unsigned int *size)
157{
158  have_output = false;
159  have_positions = false;
160
161  out_len = 0;
162  out_info = info;
163
164  assert ((uintptr_t) pos % sizeof (scratch_buffer_t) == 0);
165  *size = allocated * sizeof (pos[0]) / sizeof (scratch_buffer_t);
166  return (scratch_buffer_t *) (void *) pos;
167}
168
169
170
171/* HarfBuzz-Internal API */
172
173void
174hb_buffer_t::reset (void)
175{
176  if (unlikely (hb_object_is_inert (this)))
177    return;
178
179  hb_unicode_funcs_destroy (unicode);
180  unicode = hb_unicode_funcs_get_default ();
181  flags = HB_BUFFER_FLAG_DEFAULT;
182  replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
183
184  clear ();
185}
186
187void
188hb_buffer_t::clear (void)
189{
190  if (unlikely (hb_object_is_inert (this)))
191    return;
192
193  hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
194  props = default_props;
195
196  content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
197  in_error = false;
198  have_output = false;
199  have_positions = false;
200
201  idx = 0;
202  len = 0;
203  out_len = 0;
204  out_info = info;
205
206  serial = 0;
207  memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
208  memset (allocated_var_owner, 0, sizeof allocated_var_owner);
209
210  memset (context, 0, sizeof context);
211  memset (context_len, 0, sizeof context_len);
212}
213
214void
215hb_buffer_t::add (hb_codepoint_t  codepoint,
216		  unsigned int    cluster)
217{
218  hb_glyph_info_t *glyph;
219
220  if (unlikely (!ensure (len + 1))) return;
221
222  glyph = &info[len];
223
224  memset (glyph, 0, sizeof (*glyph));
225  glyph->codepoint = codepoint;
226  glyph->mask = 1;
227  glyph->cluster = cluster;
228
229  len++;
230}
231
232void
233hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
234{
235  if (unlikely (!ensure (len + 1))) return;
236
237  info[len] = glyph_info;
238
239  len++;
240}
241
242
243void
244hb_buffer_t::remove_output (void)
245{
246  if (unlikely (hb_object_is_inert (this)))
247    return;
248
249  have_output = false;
250  have_positions = false;
251
252  out_len = 0;
253  out_info = info;
254}
255
256void
257hb_buffer_t::clear_output (void)
258{
259  if (unlikely (hb_object_is_inert (this)))
260    return;
261
262  have_output = true;
263  have_positions = false;
264
265  out_len = 0;
266  out_info = info;
267}
268
269void
270hb_buffer_t::clear_positions (void)
271{
272  if (unlikely (hb_object_is_inert (this)))
273    return;
274
275  have_output = false;
276  have_positions = true;
277
278  out_len = 0;
279  out_info = info;
280
281  memset (pos, 0, sizeof (pos[0]) * len);
282}
283
284void
285hb_buffer_t::swap_buffers (void)
286{
287  if (unlikely (in_error)) return;
288
289  assert (have_output);
290  have_output = false;
291
292  if (out_info != info)
293  {
294    hb_glyph_info_t *tmp_string;
295    tmp_string = info;
296    info = out_info;
297    out_info = tmp_string;
298    pos = (hb_glyph_position_t *) out_info;
299  }
300
301  unsigned int tmp;
302  tmp = len;
303  len = out_len;
304  out_len = tmp;
305
306  idx = 0;
307}
308
309
310void
311hb_buffer_t::replace_glyphs (unsigned int num_in,
312			     unsigned int num_out,
313			     const uint32_t *glyph_data)
314{
315  if (unlikely (!make_room_for (num_in, num_out))) return;
316
317  merge_clusters (idx, idx + num_in);
318
319  hb_glyph_info_t orig_info = info[idx];
320  hb_glyph_info_t *pinfo = &out_info[out_len];
321  for (unsigned int i = 0; i < num_out; i++)
322  {
323    *pinfo = orig_info;
324    pinfo->codepoint = glyph_data[i];
325    pinfo++;
326  }
327
328  idx  += num_in;
329  out_len += num_out;
330}
331
332void
333hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
334{
335  if (unlikely (!make_room_for (0, 1))) return;
336
337  out_info[out_len] = info[idx];
338  out_info[out_len].codepoint = glyph_index;
339
340  out_len++;
341}
342
343void
344hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info)
345{
346  if (unlikely (!make_room_for (0, 1))) return;
347
348  out_info[out_len] = glyph_info;
349
350  out_len++;
351}
352
353void
354hb_buffer_t::copy_glyph (void)
355{
356  if (unlikely (!make_room_for (0, 1))) return;
357
358  out_info[out_len] = info[idx];
359
360  out_len++;
361}
362
363bool
364hb_buffer_t::move_to (unsigned int i)
365{
366  if (!have_output)
367  {
368    assert (i <= len);
369    idx = i;
370    return true;
371  }
372
373  assert (i <= out_len + (len - idx));
374
375  if (out_len < i)
376  {
377    unsigned int count = i - out_len;
378    if (unlikely (!make_room_for (count, count))) return false;
379
380    memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));
381    idx += count;
382    out_len += count;
383  }
384  else if (out_len > i)
385  {
386    /* Tricky part: rewinding... */
387    unsigned int count = out_len - i;
388
389    if (unlikely (idx < count && !shift_forward (count + 32))) return false;
390
391    assert (idx >= count);
392
393    idx -= count;
394    out_len -= count;
395    memmove (info + idx, out_info + out_len, count * sizeof (out_info[0]));
396  }
397
398  return true;
399}
400
401void
402hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
403{
404  if (unlikely (out_info != info || out_len != idx)) {
405    if (unlikely (!make_room_for (1, 1))) return;
406    out_info[out_len] = info[idx];
407  }
408  out_info[out_len].codepoint = glyph_index;
409
410  idx++;
411  out_len++;
412}
413
414
415void
416hb_buffer_t::set_masks (hb_mask_t    value,
417			hb_mask_t    mask,
418			unsigned int cluster_start,
419			unsigned int cluster_end)
420{
421  hb_mask_t not_mask = ~mask;
422  value &= mask;
423
424  if (!mask)
425    return;
426
427  if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
428    unsigned int count = len;
429    for (unsigned int i = 0; i < count; i++)
430      info[i].mask = (info[i].mask & not_mask) | value;
431    return;
432  }
433
434  unsigned int count = len;
435  for (unsigned int i = 0; i < count; i++)
436    if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
437      info[i].mask = (info[i].mask & not_mask) | value;
438}
439
440void
441hb_buffer_t::reverse_range (unsigned int start,
442			    unsigned int end)
443{
444  unsigned int i, j;
445
446  if (start == end - 1)
447    return;
448
449  for (i = start, j = end - 1; i < j; i++, j--) {
450    hb_glyph_info_t t;
451
452    t = info[i];
453    info[i] = info[j];
454    info[j] = t;
455  }
456
457  if (pos) {
458    for (i = start, j = end - 1; i < j; i++, j--) {
459      hb_glyph_position_t t;
460
461      t = pos[i];
462      pos[i] = pos[j];
463      pos[j] = t;
464    }
465  }
466}
467
468void
469hb_buffer_t::reverse (void)
470{
471  if (unlikely (!len))
472    return;
473
474  reverse_range (0, len);
475}
476
477void
478hb_buffer_t::reverse_clusters (void)
479{
480  unsigned int i, start, count, last_cluster;
481
482  if (unlikely (!len))
483    return;
484
485  reverse ();
486
487  count = len;
488  start = 0;
489  last_cluster = info[0].cluster;
490  for (i = 1; i < count; i++) {
491    if (last_cluster != info[i].cluster) {
492      reverse_range (start, i);
493      start = i;
494      last_cluster = info[i].cluster;
495    }
496  }
497  reverse_range (start, i);
498}
499
500void
501hb_buffer_t::merge_clusters (unsigned int start,
502			     unsigned int end)
503{
504#ifdef HB_NO_MERGE_CLUSTERS
505  return;
506#endif
507
508  if (unlikely (end - start < 2))
509    return;
510
511  unsigned int cluster = info[start].cluster;
512
513  for (unsigned int i = start + 1; i < end; i++)
514    cluster = MIN (cluster, info[i].cluster);
515
516  /* Extend end */
517  while (end < len && info[end - 1].cluster == info[end].cluster)
518    end++;
519
520  /* Extend start */
521  while (idx < start && info[start - 1].cluster == info[start].cluster)
522    start--;
523
524  /* If we hit the start of buffer, continue in out-buffer. */
525  if (idx == start)
526    for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
527      out_info[i - 1].cluster = cluster;
528
529  for (unsigned int i = start; i < end; i++)
530    info[i].cluster = cluster;
531}
532void
533hb_buffer_t::merge_out_clusters (unsigned int start,
534				 unsigned int end)
535{
536#ifdef HB_NO_MERGE_CLUSTERS
537  return;
538#endif
539
540  if (unlikely (end - start < 2))
541    return;
542
543  unsigned int cluster = out_info[start].cluster;
544
545  for (unsigned int i = start + 1; i < end; i++)
546    cluster = MIN (cluster, out_info[i].cluster);
547
548  /* Extend start */
549  while (start && out_info[start - 1].cluster == out_info[start].cluster)
550    start--;
551
552  /* Extend end */
553  while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)
554    end++;
555
556  /* If we hit the end of out-buffer, continue in buffer. */
557  if (end == out_len)
558    for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
559      info[i].cluster = cluster;
560
561  for (unsigned int i = start; i < end; i++)
562    out_info[i].cluster = cluster;
563}
564
565void
566hb_buffer_t::guess_segment_properties (void)
567{
568  assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
569	  (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
570
571  /* If script is set to INVALID, guess from buffer contents */
572  if (props.script == HB_SCRIPT_INVALID) {
573    for (unsigned int i = 0; i < len; i++) {
574      hb_script_t script = unicode->script (info[i].codepoint);
575      if (likely (script != HB_SCRIPT_COMMON &&
576		  script != HB_SCRIPT_INHERITED &&
577		  script != HB_SCRIPT_UNKNOWN)) {
578        props.script = script;
579        break;
580      }
581    }
582  }
583
584  /* If direction is set to INVALID, guess from script */
585  if (props.direction == HB_DIRECTION_INVALID) {
586    props.direction = hb_script_get_horizontal_direction (props.script);
587  }
588
589  /* If language is not set, use default language from locale */
590  if (props.language == HB_LANGUAGE_INVALID) {
591    /* TODO get_default_for_script? using $LANGUAGE */
592    props.language = hb_language_get_default ();
593  }
594}
595
596
597static inline void
598dump_var_allocation (const hb_buffer_t *buffer)
599{
600  char buf[80];
601  for (unsigned int i = 0; i < 8; i++)
602    buf[i] = '0' + buffer->allocated_var_bytes[7 - i];
603  buf[8] = '\0';
604  DEBUG_MSG (BUFFER, buffer,
605	     "Current var allocation: %s",
606	     buf);
607}
608
609void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner)
610{
611  assert (byte_i < 8 && byte_i + count <= 8);
612
613  if (DEBUG_ENABLED (BUFFER))
614    dump_var_allocation (this);
615  DEBUG_MSG (BUFFER, this,
616	     "Allocating var bytes %d..%d for %s",
617	     byte_i, byte_i + count - 1, owner);
618
619  for (unsigned int i = byte_i; i < byte_i + count; i++) {
620    assert (!allocated_var_bytes[i]);
621    allocated_var_bytes[i]++;
622    allocated_var_owner[i] = owner;
623  }
624}
625
626void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
627{
628  if (DEBUG_ENABLED (BUFFER))
629    dump_var_allocation (this);
630
631  DEBUG_MSG (BUFFER, this,
632	     "Deallocating var bytes %d..%d for %s",
633	     byte_i, byte_i + count - 1, owner);
634
635  assert (byte_i < 8 && byte_i + count <= 8);
636  for (unsigned int i = byte_i; i < byte_i + count; i++) {
637    assert (allocated_var_bytes[i]);
638    assert (0 == strcmp (allocated_var_owner[i], owner));
639    allocated_var_bytes[i]--;
640  }
641}
642
643void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner)
644{
645  if (DEBUG_ENABLED (BUFFER))
646    dump_var_allocation (this);
647
648  DEBUG_MSG (BUFFER, this,
649	     "Asserting var bytes %d..%d for %s",
650	     byte_i, byte_i + count - 1, owner);
651
652  assert (byte_i < 8 && byte_i + count <= 8);
653  for (unsigned int i = byte_i; i < byte_i + count; i++) {
654    assert (allocated_var_bytes[i]);
655    assert (0 == strcmp (allocated_var_owner[i], owner));
656  }
657}
658
659void hb_buffer_t::deallocate_var_all (void)
660{
661  memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
662  memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
663}
664
665/* Public API */
666
667/**
668 * hb_buffer_create: (Xconstructor)
669 *
670 *
671 *
672 * Return value: (transfer full)
673 *
674 * Since: 1.0
675 **/
676hb_buffer_t *
677hb_buffer_create (void)
678{
679  hb_buffer_t *buffer;
680
681  if (!(buffer = hb_object_create<hb_buffer_t> ()))
682    return hb_buffer_get_empty ();
683
684  buffer->reset ();
685
686  return buffer;
687}
688
689/**
690 * hb_buffer_get_empty:
691 *
692 *
693 *
694 * Return value: (transfer full):
695 *
696 * Since: 1.0
697 **/
698hb_buffer_t *
699hb_buffer_get_empty (void)
700{
701  static const hb_buffer_t _hb_buffer_nil = {
702    HB_OBJECT_HEADER_STATIC,
703
704    const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
705    HB_BUFFER_FLAG_DEFAULT,
706    HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
707
708    HB_BUFFER_CONTENT_TYPE_INVALID,
709    HB_SEGMENT_PROPERTIES_DEFAULT,
710    true, /* in_error */
711    true, /* have_output */
712    true  /* have_positions */
713
714    /* Zero is good enough for everything else. */
715  };
716
717  return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
718}
719
720/**
721 * hb_buffer_reference: (skip)
722 * @buffer: a buffer.
723 *
724 *
725 *
726 * Return value: (transfer full):
727 *
728 * Since: 1.0
729 **/
730hb_buffer_t *
731hb_buffer_reference (hb_buffer_t *buffer)
732{
733  return hb_object_reference (buffer);
734}
735
736/**
737 * hb_buffer_destroy: (skip)
738 * @buffer: a buffer.
739 *
740 *
741 *
742 * Since: 1.0
743 **/
744void
745hb_buffer_destroy (hb_buffer_t *buffer)
746{
747  if (!hb_object_destroy (buffer)) return;
748
749  hb_unicode_funcs_destroy (buffer->unicode);
750
751  free (buffer->info);
752  free (buffer->pos);
753
754  free (buffer);
755}
756
757/**
758 * hb_buffer_set_user_data: (skip)
759 * @buffer: a buffer.
760 * @key:
761 * @data:
762 * @destroy:
763 * @replace:
764 *
765 *
766 *
767 * Return value:
768 *
769 * Since: 1.0
770 **/
771hb_bool_t
772hb_buffer_set_user_data (hb_buffer_t        *buffer,
773			 hb_user_data_key_t *key,
774			 void *              data,
775			 hb_destroy_func_t   destroy,
776			 hb_bool_t           replace)
777{
778  return hb_object_set_user_data (buffer, key, data, destroy, replace);
779}
780
781/**
782 * hb_buffer_get_user_data: (skip)
783 * @buffer: a buffer.
784 * @key:
785 *
786 *
787 *
788 * Return value:
789 *
790 * Since: 1.0
791 **/
792void *
793hb_buffer_get_user_data (hb_buffer_t        *buffer,
794			 hb_user_data_key_t *key)
795{
796  return hb_object_get_user_data (buffer, key);
797}
798
799
800/**
801 * hb_buffer_set_content_type:
802 * @buffer: a buffer.
803 * @content_type:
804 *
805 *
806 *
807 * Since: 1.0
808 **/
809void
810hb_buffer_set_content_type (hb_buffer_t              *buffer,
811			    hb_buffer_content_type_t  content_type)
812{
813  buffer->content_type = content_type;
814}
815
816/**
817 * hb_buffer_get_content_type:
818 * @buffer: a buffer.
819 *
820 *
821 *
822 * Return value:
823 *
824 * Since: 1.0
825 **/
826hb_buffer_content_type_t
827hb_buffer_get_content_type (hb_buffer_t *buffer)
828{
829  return buffer->content_type;
830}
831
832
833/**
834 * hb_buffer_set_unicode_funcs:
835 * @buffer: a buffer.
836 * @unicode_funcs:
837 *
838 *
839 *
840 * Since: 1.0
841 **/
842void
843hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
844			     hb_unicode_funcs_t *unicode_funcs)
845{
846  if (unlikely (hb_object_is_inert (buffer)))
847    return;
848
849  if (!unicode_funcs)
850    unicode_funcs = hb_unicode_funcs_get_default ();
851
852
853  hb_unicode_funcs_reference (unicode_funcs);
854  hb_unicode_funcs_destroy (buffer->unicode);
855  buffer->unicode = unicode_funcs;
856}
857
858/**
859 * hb_buffer_get_unicode_funcs:
860 * @buffer: a buffer.
861 *
862 *
863 *
864 * Return value:
865 *
866 * Since: 1.0
867 **/
868hb_unicode_funcs_t *
869hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
870{
871  return buffer->unicode;
872}
873
874/**
875 * hb_buffer_set_direction:
876 * @buffer: a buffer.
877 * @direction:
878 *
879 *
880 *
881 * Since: 1.0
882 **/
883void
884hb_buffer_set_direction (hb_buffer_t    *buffer,
885			 hb_direction_t  direction)
886
887{
888  if (unlikely (hb_object_is_inert (buffer)))
889    return;
890
891  buffer->props.direction = direction;
892}
893
894/**
895 * hb_buffer_get_direction:
896 * @buffer: a buffer.
897 *
898 *
899 *
900 * Return value:
901 *
902 * Since: 1.0
903 **/
904hb_direction_t
905hb_buffer_get_direction (hb_buffer_t    *buffer)
906{
907  return buffer->props.direction;
908}
909
910/**
911 * hb_buffer_set_script:
912 * @buffer: a buffer.
913 * @script:
914 *
915 *
916 *
917 * Since: 1.0
918 **/
919void
920hb_buffer_set_script (hb_buffer_t *buffer,
921		      hb_script_t  script)
922{
923  if (unlikely (hb_object_is_inert (buffer)))
924    return;
925
926  buffer->props.script = script;
927}
928
929/**
930 * hb_buffer_get_script:
931 * @buffer: a buffer.
932 *
933 *
934 *
935 * Return value:
936 *
937 * Since: 1.0
938 **/
939hb_script_t
940hb_buffer_get_script (hb_buffer_t *buffer)
941{
942  return buffer->props.script;
943}
944
945/**
946 * hb_buffer_set_language:
947 * @buffer: a buffer.
948 * @language:
949 *
950 *
951 *
952 * Since: 1.0
953 **/
954void
955hb_buffer_set_language (hb_buffer_t   *buffer,
956			hb_language_t  language)
957{
958  if (unlikely (hb_object_is_inert (buffer)))
959    return;
960
961  buffer->props.language = language;
962}
963
964/**
965 * hb_buffer_get_language:
966 * @buffer: a buffer.
967 *
968 *
969 *
970 * Return value:
971 *
972 * Since: 1.0
973 **/
974hb_language_t
975hb_buffer_get_language (hb_buffer_t *buffer)
976{
977  return buffer->props.language;
978}
979
980/**
981 * hb_buffer_set_segment_properties:
982 * @buffer: a buffer.
983 * @props:
984 *
985 *
986 *
987 * Since: 1.0
988 **/
989void
990hb_buffer_set_segment_properties (hb_buffer_t *buffer,
991				  const hb_segment_properties_t *props)
992{
993  if (unlikely (hb_object_is_inert (buffer)))
994    return;
995
996  buffer->props = *props;
997}
998
999/**
1000 * hb_buffer_get_segment_properties:
1001 * @buffer: a buffer.
1002 * @props:
1003 *
1004 *
1005 *
1006 * Since: 1.0
1007 **/
1008void
1009hb_buffer_get_segment_properties (hb_buffer_t *buffer,
1010				  hb_segment_properties_t *props)
1011{
1012  *props = buffer->props;
1013}
1014
1015
1016/**
1017 * hb_buffer_set_flags:
1018 * @buffer: a buffer.
1019 * @flags:
1020 *
1021 *
1022 *
1023 * Since: 1.0
1024 **/
1025void
1026hb_buffer_set_flags (hb_buffer_t       *buffer,
1027		     hb_buffer_flags_t  flags)
1028{
1029  if (unlikely (hb_object_is_inert (buffer)))
1030    return;
1031
1032  buffer->flags = flags;
1033}
1034
1035/**
1036 * hb_buffer_get_flags:
1037 * @buffer: a buffer.
1038 *
1039 *
1040 *
1041 * Return value:
1042 *
1043 * Since: 1.0
1044 **/
1045hb_buffer_flags_t
1046hb_buffer_get_flags (hb_buffer_t *buffer)
1047{
1048  return buffer->flags;
1049}
1050
1051
1052/**
1053 * hb_buffer_set_replacement_codepoint:
1054 * @buffer: a buffer.
1055 * @replacement:
1056 *
1057 *
1058 *
1059 * Since: 1.0
1060 **/
1061void
1062hb_buffer_set_replacement_codepoint (hb_buffer_t    *buffer,
1063				     hb_codepoint_t  replacement)
1064{
1065  if (unlikely (hb_object_is_inert (buffer)))
1066    return;
1067
1068  buffer->replacement = replacement;
1069}
1070
1071/**
1072 * hb_buffer_get_replacement_codepoint:
1073 * @buffer: a buffer.
1074 *
1075 *
1076 *
1077 * Return value:
1078 *
1079 * Since: 1.0
1080 **/
1081hb_codepoint_t
1082hb_buffer_get_replacement_codepoint (hb_buffer_t    *buffer)
1083{
1084  return buffer->replacement;
1085}
1086
1087
1088/**
1089 * hb_buffer_reset:
1090 * @buffer: a buffer.
1091 *
1092 *
1093 *
1094 * Since: 1.0
1095 **/
1096void
1097hb_buffer_reset (hb_buffer_t *buffer)
1098{
1099  buffer->reset ();
1100}
1101
1102/**
1103 * hb_buffer_clear_contents:
1104 * @buffer: a buffer.
1105 *
1106 *
1107 *
1108 * Since: 1.0
1109 **/
1110void
1111hb_buffer_clear_contents (hb_buffer_t *buffer)
1112{
1113  buffer->clear ();
1114}
1115
1116/**
1117 * hb_buffer_pre_allocate:
1118 * @buffer: a buffer.
1119 * @size:
1120 *
1121 *
1122 *
1123 * Return value:
1124 *
1125 * Since: 1.0
1126 **/
1127hb_bool_t
1128hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
1129{
1130  return buffer->ensure (size);
1131}
1132
1133/**
1134 * hb_buffer_allocation_successful:
1135 * @buffer: a buffer.
1136 *
1137 *
1138 *
1139 * Return value:
1140 *
1141 * Since: 1.0
1142 **/
1143hb_bool_t
1144hb_buffer_allocation_successful (hb_buffer_t  *buffer)
1145{
1146  return !buffer->in_error;
1147}
1148
1149/**
1150 * hb_buffer_add:
1151 * @buffer: a buffer.
1152 * @codepoint:
1153 * @cluster:
1154 *
1155 *
1156 *
1157 * Since: 1.0
1158 **/
1159void
1160hb_buffer_add (hb_buffer_t    *buffer,
1161	       hb_codepoint_t  codepoint,
1162	       unsigned int    cluster)
1163{
1164  buffer->add (codepoint, cluster);
1165  buffer->clear_context (1);
1166}
1167
1168/**
1169 * hb_buffer_set_length:
1170 * @buffer: a buffer.
1171 * @length:
1172 *
1173 *
1174 *
1175 * Return value:
1176 *
1177 * Since: 1.0
1178 **/
1179hb_bool_t
1180hb_buffer_set_length (hb_buffer_t  *buffer,
1181		      unsigned int  length)
1182{
1183  if (unlikely (hb_object_is_inert (buffer)))
1184    return length == 0;
1185
1186  if (!buffer->ensure (length))
1187    return false;
1188
1189  /* Wipe the new space */
1190  if (length > buffer->len) {
1191    memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
1192    if (buffer->have_positions)
1193      memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
1194  }
1195
1196  buffer->len = length;
1197
1198  if (!length)
1199  {
1200    buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
1201    buffer->clear_context (0);
1202  }
1203  buffer->clear_context (1);
1204
1205  return true;
1206}
1207
1208/**
1209 * hb_buffer_get_length:
1210 * @buffer: a buffer.
1211 *
1212 * Returns the number of items in the buffer.
1213 *
1214 * Return value: buffer length.
1215 *
1216 * Since: 1.0
1217 **/
1218unsigned int
1219hb_buffer_get_length (hb_buffer_t *buffer)
1220{
1221  return buffer->len;
1222}
1223
1224/**
1225 * hb_buffer_get_glyph_infos:
1226 * @buffer: a buffer.
1227 * @length: (out): output array length.
1228 *
1229 * Returns buffer glyph information array.  Returned pointer
1230 * is valid as long as buffer contents are not modified.
1231 *
1232 * Return value: (transfer none) (array length=length): buffer glyph information array.
1233 *
1234 * Since: 1.0
1235 **/
1236hb_glyph_info_t *
1237hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
1238                           unsigned int *length)
1239{
1240  if (length)
1241    *length = buffer->len;
1242
1243  return (hb_glyph_info_t *) buffer->info;
1244}
1245
1246/**
1247 * hb_buffer_get_glyph_positions:
1248 * @buffer: a buffer.
1249 * @length: (out): output length.
1250 *
1251 * Returns buffer glyph position array.  Returned pointer
1252 * is valid as long as buffer contents are not modified.
1253 *
1254 * Return value: (transfer none) (array length=length): buffer glyph position array.
1255 *
1256 * Since: 1.0
1257 **/
1258hb_glyph_position_t *
1259hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
1260                               unsigned int *length)
1261{
1262  if (!buffer->have_positions)
1263    buffer->clear_positions ();
1264
1265  if (length)
1266    *length = buffer->len;
1267
1268  return (hb_glyph_position_t *) buffer->pos;
1269}
1270
1271/**
1272 * hb_buffer_reverse:
1273 * @buffer: a buffer.
1274 *
1275 * Reverses buffer contents.
1276 *
1277 * Since: 1.0
1278 **/
1279void
1280hb_buffer_reverse (hb_buffer_t *buffer)
1281{
1282  buffer->reverse ();
1283}
1284
1285/**
1286 * hb_buffer_reverse_clusters:
1287 * @buffer: a buffer.
1288 *
1289 * Reverses buffer clusters.  That is, the buffer contents are
1290 * reversed, then each cluster (consecutive items having the
1291 * same cluster number) are reversed again.
1292 *
1293 * Since: 1.0
1294 **/
1295void
1296hb_buffer_reverse_clusters (hb_buffer_t *buffer)
1297{
1298  buffer->reverse_clusters ();
1299}
1300
1301/**
1302 * hb_buffer_guess_segment_properties:
1303 * @buffer: a buffer.
1304 *
1305 * Sets unset buffer segment properties based on buffer Unicode
1306 * contents.  If buffer is not empty, it must have content type
1307 * %HB_BUFFER_CONTENT_TYPE_UNICODE.
1308 *
1309 * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
1310 * will be set to the Unicode script of the first character in
1311 * the buffer that has a script other than %HB_SCRIPT_COMMON,
1312 * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
1313 *
1314 * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
1315 * it will be set to the natural horizontal direction of the
1316 * buffer script as returned by hb_script_get_horizontal_direction().
1317 *
1318 * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
1319 * it will be set to the process's default language as returned by
1320 * hb_language_get_default().  This may change in the future by
1321 * taking buffer script into consideration when choosing a language.
1322 *
1323 * Since: 1.0
1324 **/
1325void
1326hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
1327{
1328  buffer->guess_segment_properties ();
1329}
1330
1331template <bool validate, typename T>
1332static inline void
1333hb_buffer_add_utf (hb_buffer_t  *buffer,
1334		   const T      *text,
1335		   int           text_length,
1336		   unsigned int  item_offset,
1337		   int           item_length)
1338{
1339  typedef hb_utf_t<T, true> utf_t;
1340  const hb_codepoint_t replacement = buffer->replacement;
1341
1342  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
1343	  (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
1344
1345  if (unlikely (hb_object_is_inert (buffer)))
1346    return;
1347
1348  if (text_length == -1)
1349    text_length = utf_t::strlen (text);
1350
1351  if (item_length == -1)
1352    item_length = text_length - item_offset;
1353
1354  buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
1355
1356  /* If buffer is empty and pre-context provided, install it.
1357   * This check is written this way, to make sure people can
1358   * provide pre-context in one add_utf() call, then provide
1359   * text in a follow-up call.  See:
1360   *
1361   * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
1362   */
1363  if (!buffer->len && item_offset > 0)
1364  {
1365    /* Add pre-context */
1366    buffer->clear_context (0);
1367    const T *prev = text + item_offset;
1368    const T *start = text;
1369    while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
1370    {
1371      hb_codepoint_t u;
1372      prev = utf_t::prev (prev, start, &u, replacement);
1373      buffer->context[0][buffer->context_len[0]++] = u;
1374    }
1375  }
1376
1377  const T *next = text + item_offset;
1378  const T *end = next + item_length;
1379  while (next < end)
1380  {
1381    hb_codepoint_t u;
1382    const T *old_next = next;
1383    next = utf_t::next (next, end, &u, replacement);
1384    buffer->add (u, old_next - (const T *) text);
1385  }
1386
1387  /* Add post-context */
1388  buffer->clear_context (1);
1389  end = text + text_length;
1390  while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
1391  {
1392    hb_codepoint_t u;
1393    next = utf_t::next (next, end, &u, replacement);
1394    buffer->context[1][buffer->context_len[1]++] = u;
1395  }
1396
1397  buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
1398}
1399
1400/**
1401 * hb_buffer_add_utf8:
1402 * @buffer: a buffer.
1403 * @text: (array length=text_length) (element-type uint8_t):
1404 * @text_length:
1405 * @item_offset:
1406 * @item_length:
1407 *
1408 *
1409 *
1410 * Since: 1.0
1411 **/
1412void
1413hb_buffer_add_utf8 (hb_buffer_t  *buffer,
1414		    const char   *text,
1415		    int           text_length,
1416		    unsigned int  item_offset,
1417		    int           item_length)
1418{
1419  hb_buffer_add_utf<true> (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
1420}
1421
1422/**
1423 * hb_buffer_add_utf16:
1424 * @buffer: a buffer.
1425 * @text: (array length=text_length):
1426 * @text_length:
1427 * @item_offset:
1428 * @item_length:
1429 *
1430 *
1431 *
1432 * Since: 1.0
1433 **/
1434void
1435hb_buffer_add_utf16 (hb_buffer_t    *buffer,
1436		     const uint16_t *text,
1437		     int             text_length,
1438		     unsigned int    item_offset,
1439		     int             item_length)
1440{
1441  hb_buffer_add_utf<true> (buffer, text, text_length, item_offset, item_length);
1442}
1443
1444/**
1445 * hb_buffer_add_utf32:
1446 * @buffer: a buffer.
1447 * @text: (array length=text_length):
1448 * @text_length:
1449 * @item_offset:
1450 * @item_length:
1451 *
1452 *
1453 *
1454 * Since: 1.0
1455 **/
1456void
1457hb_buffer_add_utf32 (hb_buffer_t    *buffer,
1458		     const uint32_t *text,
1459		     int             text_length,
1460		     unsigned int    item_offset,
1461		     int             item_length)
1462{
1463  hb_buffer_add_utf<true> (buffer, text, text_length, item_offset, item_length);
1464}
1465
1466/**
1467 * hb_buffer_add_codepoints:
1468 * @buffer: a buffer.
1469 * @text: (array length=text_length):
1470 * @text_length:
1471 * @item_offset:
1472 * @item_length:
1473 *
1474 *
1475 *
1476 * Since: 1.0
1477 **/
1478void
1479hb_buffer_add_codepoints (hb_buffer_t          *buffer,
1480			  const hb_codepoint_t *text,
1481			  int                   text_length,
1482			  unsigned int          item_offset,
1483			  int                   item_length)
1484{
1485  hb_buffer_add_utf<false> (buffer, text, text_length, item_offset, item_length);
1486}
1487
1488
1489static int
1490compare_info_codepoint (const hb_glyph_info_t *pa,
1491			const hb_glyph_info_t *pb)
1492{
1493  return (int) pb->codepoint - (int) pa->codepoint;
1494}
1495
1496static inline void
1497normalize_glyphs_cluster (hb_buffer_t *buffer,
1498			  unsigned int start,
1499			  unsigned int end,
1500			  bool backward)
1501{
1502  hb_glyph_position_t *pos = buffer->pos;
1503
1504  /* Total cluster advance */
1505  hb_position_t total_x_advance = 0, total_y_advance = 0;
1506  for (unsigned int i = start; i < end; i++)
1507  {
1508    total_x_advance += pos[i].x_advance;
1509    total_y_advance += pos[i].y_advance;
1510  }
1511
1512  hb_position_t x_advance = 0, y_advance = 0;
1513  for (unsigned int i = start; i < end; i++)
1514  {
1515    pos[i].x_offset += x_advance;
1516    pos[i].y_offset += y_advance;
1517
1518    x_advance += pos[i].x_advance;
1519    y_advance += pos[i].y_advance;
1520
1521    pos[i].x_advance = 0;
1522    pos[i].y_advance = 0;
1523  }
1524
1525  if (backward)
1526  {
1527    /* Transfer all cluster advance to the last glyph. */
1528    pos[end - 1].x_advance = total_x_advance;
1529    pos[end - 1].y_advance = total_y_advance;
1530
1531    hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
1532  } else {
1533    /* Transfer all cluster advance to the first glyph. */
1534    pos[start].x_advance += total_x_advance;
1535    pos[start].y_advance += total_y_advance;
1536    for (unsigned int i = start + 1; i < end; i++) {
1537      pos[i].x_offset -= total_x_advance;
1538      pos[i].y_offset -= total_y_advance;
1539    }
1540    hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
1541  }
1542}
1543
1544/**
1545 * hb_buffer_normalize_glyphs:
1546 * @buffer: a buffer.
1547 *
1548 *
1549 *
1550 * Since: 1.0
1551 **/
1552void
1553hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
1554{
1555  assert (buffer->have_positions);
1556  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
1557
1558  bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
1559
1560  unsigned int count = buffer->len;
1561  if (unlikely (!count)) return;
1562  hb_glyph_info_t *info = buffer->info;
1563
1564  unsigned int start = 0;
1565  unsigned int end;
1566  for (end = start + 1; end < count; end++)
1567    if (info[start].cluster != info[end].cluster) {
1568      normalize_glyphs_cluster (buffer, start, end, backward);
1569      start = end;
1570    }
1571  normalize_glyphs_cluster (buffer, start, end, backward);
1572}
1573