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