Home | History | Annotate | Download | only in src
      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 
     39 hb_bool_t
     40 hb_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 
     51 unsigned int
     52 hb_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 
     83 bool
     84 hb_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 
    107 done:
    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 
    124 bool
    125 hb_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 
    142 bool
    143 hb_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 
    155 hb_buffer_t::scratch_buffer_t *
    156 hb_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 
    173 void
    174 hb_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 
    185 void
    186 hb_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 
    213 void
    214 hb_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 
    231 void
    232 hb_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 
    242 void
    243 hb_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 
    255 void
    256 hb_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 
    268 void
    269 hb_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 
    283 void
    284 hb_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 
    309 void
    310 hb_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 
    331 void
    332 hb_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 
    342 void
    343 hb_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 
    352 void
    353 hb_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 
    362 bool
    363 hb_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 
    400 void
    401 hb_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 
    414 void
    415 hb_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 
    439 void
    440 hb_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 
    467 void
    468 hb_buffer_t::reverse (void)
    469 {
    470   if (unlikely (!len))
    471     return;
    472 
    473   reverse_range (0, len);
    474 }
    475 
    476 void
    477 hb_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 
    499 void
    500 hb_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 }
    527 void
    528 hb_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 
    556 void
    557 hb_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 
    588 static inline void
    589 dump_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 
    600 void 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 
    617 void 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 
    634 void 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 
    650 void 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  **/
    667 hb_buffer_t *
    668 hb_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  **/
    689 hb_buffer_t *
    690 hb_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  **/
    720 hb_buffer_t *
    721 hb_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  **/
    734 void
    735 hb_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  **/
    761 hb_bool_t
    762 hb_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  **/
    782 void *
    783 hb_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  **/
    799 void
    800 hb_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  **/
    816 hb_buffer_content_type_t
    817 hb_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  **/
    832 void
    833 hb_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  **/
    858 hb_unicode_funcs_t *
    859 hb_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  **/
    873 void
    874 hb_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  **/
    894 hb_direction_t
    895 hb_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  **/
    909 void
    910 hb_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  **/
    929 hb_script_t
    930 hb_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  **/
    944 void
    945 hb_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  **/
    964 hb_language_t
    965 hb_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  **/
    979 void
    980 hb_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  **/
    998 void
    999 hb_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  **/
   1015 void
   1016 hb_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  **/
   1035 hb_buffer_flags_t
   1036 hb_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  **/
   1050 void
   1051 hb_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  **/
   1064 void
   1065 hb_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  **/
   1081 hb_bool_t
   1082 hb_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  **/
   1097 hb_bool_t
   1098 hb_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  **/
   1113 void
   1114 hb_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  **/
   1133 hb_bool_t
   1134 hb_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   {
   1154     buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
   1155     buffer->clear_context (0);
   1156   }
   1157   buffer->clear_context (1);
   1158 
   1159   return true;
   1160 }
   1161 
   1162 /**
   1163  * hb_buffer_get_length:
   1164  * @buffer: a buffer.
   1165  *
   1166  * Returns the number of items in the buffer.
   1167  *
   1168  * Return value: buffer length.
   1169  *
   1170  * Since: 1.0
   1171  **/
   1172 unsigned int
   1173 hb_buffer_get_length (hb_buffer_t *buffer)
   1174 {
   1175   return buffer->len;
   1176 }
   1177 
   1178 /**
   1179  * hb_buffer_get_glyph_infos:
   1180  * @buffer: a buffer.
   1181  * @length: (out): output array length.
   1182  *
   1183  * Returns buffer glyph information array.  Returned pointer
   1184  * is valid as long as buffer contents are not modified.
   1185  *
   1186  * Return value: (transfer none) (array length=length): buffer glyph information array.
   1187  *
   1188  * Since: 1.0
   1189  **/
   1190 hb_glyph_info_t *
   1191 hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
   1192                            unsigned int *length)
   1193 {
   1194   if (length)
   1195     *length = buffer->len;
   1196 
   1197   return (hb_glyph_info_t *) buffer->info;
   1198 }
   1199 
   1200 /**
   1201  * hb_buffer_get_glyph_positions:
   1202  * @buffer: a buffer.
   1203  * @length: (out): output length.
   1204  *
   1205  * Returns buffer glyph position array.  Returned pointer
   1206  * is valid as long as buffer contents are not modified.
   1207  *
   1208  * Return value: (transfer none) (array length=length): buffer glyph position array.
   1209  *
   1210  * Since: 1.0
   1211  **/
   1212 hb_glyph_position_t *
   1213 hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
   1214                                unsigned int *length)
   1215 {
   1216   if (!buffer->have_positions)
   1217     buffer->clear_positions ();
   1218 
   1219   if (length)
   1220     *length = buffer->len;
   1221 
   1222   return (hb_glyph_position_t *) buffer->pos;
   1223 }
   1224 
   1225 /**
   1226  * hb_buffer_reverse:
   1227  * @buffer: a buffer.
   1228  *
   1229  * Reverses buffer contents.
   1230  *
   1231  * Since: 1.0
   1232  **/
   1233 void
   1234 hb_buffer_reverse (hb_buffer_t *buffer)
   1235 {
   1236   buffer->reverse ();
   1237 }
   1238 
   1239 /**
   1240  * hb_buffer_reverse_clusters:
   1241  * @buffer: a buffer.
   1242  *
   1243  * Reverses buffer clusters.  That is, the buffer contents are
   1244  * reversed, then each cluster (consecutive items having the
   1245  * same cluster number) are reversed again.
   1246  *
   1247  * Since: 1.0
   1248  **/
   1249 void
   1250 hb_buffer_reverse_clusters (hb_buffer_t *buffer)
   1251 {
   1252   buffer->reverse_clusters ();
   1253 }
   1254 
   1255 /**
   1256  * hb_buffer_guess_segment_properties:
   1257  * @buffer: a buffer.
   1258  *
   1259  * Sets unset buffer segment properties based on buffer Unicode
   1260  * contents.  If buffer is not empty, it must have content type
   1261  * %HB_BUFFER_CONTENT_TYPE_UNICODE.
   1262  *
   1263  * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
   1264  * will be set to the Unicode script of the first character in
   1265  * the buffer that has a script other than %HB_SCRIPT_COMMON,
   1266  * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
   1267  *
   1268  * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
   1269  * it will be set to the natural horizontal direction of the
   1270  * buffer script as returned by hb_script_get_horizontal_direction().
   1271  *
   1272  * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
   1273  * it will be set to the process's default language as returned by
   1274  * hb_language_get_default().  This may change in the future by
   1275  * taking buffer script into consideration when choosing a language.
   1276  *
   1277  * Since: 1.0
   1278  **/
   1279 void
   1280 hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
   1281 {
   1282   buffer->guess_segment_properties ();
   1283 }
   1284 
   1285 template <typename T>
   1286 static inline void
   1287 hb_buffer_add_utf (hb_buffer_t  *buffer,
   1288 		   const T      *text,
   1289 		   int           text_length,
   1290 		   unsigned int  item_offset,
   1291 		   int           item_length)
   1292 {
   1293   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
   1294 	  (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
   1295 
   1296   if (unlikely (hb_object_is_inert (buffer)))
   1297     return;
   1298 
   1299   if (text_length == -1)
   1300     text_length = hb_utf_strlen (text);
   1301 
   1302   if (item_length == -1)
   1303     item_length = text_length - item_offset;
   1304 
   1305   buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
   1306 
   1307   /* If buffer is empty and pre-context provided, install it.
   1308    * This check is written this way, to make sure people can
   1309    * provide pre-context in one add_utf() call, then provide
   1310    * text in a follow-up call.  See:
   1311    *
   1312    * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
   1313    */
   1314   if (!buffer->len && item_offset > 0)
   1315   {
   1316     /* Add pre-context */
   1317     buffer->clear_context (0);
   1318     const T *prev = text + item_offset;
   1319     const T *start = text;
   1320     while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
   1321     {
   1322       hb_codepoint_t u;
   1323       prev = hb_utf_prev (prev, start, &u);
   1324       buffer->context[0][buffer->context_len[0]++] = u;
   1325     }
   1326   }
   1327 
   1328   const T *next = text + item_offset;
   1329   const T *end = next + item_length;
   1330   while (next < end)
   1331   {
   1332     hb_codepoint_t u;
   1333     const T *old_next = next;
   1334     next = hb_utf_next (next, end, &u);
   1335     buffer->add (u, old_next - (const T *) text);
   1336   }
   1337 
   1338   /* Add post-context */
   1339   buffer->clear_context (1);
   1340   end = text + text_length;
   1341   while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
   1342   {
   1343     hb_codepoint_t u;
   1344     next = hb_utf_next (next, end, &u);
   1345     buffer->context[1][buffer->context_len[1]++] = u;
   1346   }
   1347 
   1348   buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
   1349 }
   1350 
   1351 /**
   1352  * hb_buffer_add_utf8:
   1353  * @buffer: a buffer.
   1354  * @text: (array length=text_length):
   1355  * @text_length:
   1356  * @item_offset:
   1357  * @item_length:
   1358  *
   1359  *
   1360  *
   1361  * Since: 1.0
   1362  **/
   1363 void
   1364 hb_buffer_add_utf8 (hb_buffer_t  *buffer,
   1365 		    const char   *text,
   1366 		    int           text_length,
   1367 		    unsigned int  item_offset,
   1368 		    int           item_length)
   1369 {
   1370   hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
   1371 }
   1372 
   1373 /**
   1374  * hb_buffer_add_utf16:
   1375  * @buffer: a buffer.
   1376  * @text: (array length=text_length):
   1377  * @text_length:
   1378  * @item_offset:
   1379  * @item_length:
   1380  *
   1381  *
   1382  *
   1383  * Since: 1.0
   1384  **/
   1385 void
   1386 hb_buffer_add_utf16 (hb_buffer_t    *buffer,
   1387 		     const uint16_t *text,
   1388 		     int             text_length,
   1389 		     unsigned int    item_offset,
   1390 		     int             item_length)
   1391 {
   1392   hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
   1393 }
   1394 
   1395 /**
   1396  * hb_buffer_add_utf32:
   1397  * @buffer: a buffer.
   1398  * @text: (array length=text_length):
   1399  * @text_length:
   1400  * @item_offset:
   1401  * @item_length:
   1402  *
   1403  *
   1404  *
   1405  * Since: 1.0
   1406  **/
   1407 void
   1408 hb_buffer_add_utf32 (hb_buffer_t    *buffer,
   1409 		     const uint32_t *text,
   1410 		     int             text_length,
   1411 		     unsigned int    item_offset,
   1412 		     int             item_length)
   1413 {
   1414   hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
   1415 }
   1416 
   1417 
   1418 static int
   1419 compare_info_codepoint (const hb_glyph_info_t *pa,
   1420 			const hb_glyph_info_t *pb)
   1421 {
   1422   return (int) pb->codepoint - (int) pa->codepoint;
   1423 }
   1424 
   1425 static inline void
   1426 normalize_glyphs_cluster (hb_buffer_t *buffer,
   1427 			  unsigned int start,
   1428 			  unsigned int end,
   1429 			  bool backward)
   1430 {
   1431   hb_glyph_position_t *pos = buffer->pos;
   1432 
   1433   /* Total cluster advance */
   1434   hb_position_t total_x_advance = 0, total_y_advance = 0;
   1435   for (unsigned int i = start; i < end; i++)
   1436   {
   1437     total_x_advance += pos[i].x_advance;
   1438     total_y_advance += pos[i].y_advance;
   1439   }
   1440 
   1441   hb_position_t x_advance = 0, y_advance = 0;
   1442   for (unsigned int i = start; i < end; i++)
   1443   {
   1444     pos[i].x_offset += x_advance;
   1445     pos[i].y_offset += y_advance;
   1446 
   1447     x_advance += pos[i].x_advance;
   1448     y_advance += pos[i].y_advance;
   1449 
   1450     pos[i].x_advance = 0;
   1451     pos[i].y_advance = 0;
   1452   }
   1453 
   1454   if (backward)
   1455   {
   1456     /* Transfer all cluster advance to the last glyph. */
   1457     pos[end - 1].x_advance = total_x_advance;
   1458     pos[end - 1].y_advance = total_y_advance;
   1459 
   1460     hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
   1461   } else {
   1462     /* Transfer all cluster advance to the first glyph. */
   1463     pos[start].x_advance += total_x_advance;
   1464     pos[start].y_advance += total_y_advance;
   1465     for (unsigned int i = start + 1; i < end; i++) {
   1466       pos[i].x_offset -= total_x_advance;
   1467       pos[i].y_offset -= total_y_advance;
   1468     }
   1469     hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
   1470   }
   1471 }
   1472 
   1473 /**
   1474  * hb_buffer_normalize_glyphs:
   1475  * @buffer: a buffer.
   1476  *
   1477  *
   1478  *
   1479  * Since: 1.0
   1480  **/
   1481 void
   1482 hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
   1483 {
   1484   assert (buffer->have_positions);
   1485   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
   1486 
   1487   bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
   1488 
   1489   unsigned int count = buffer->len;
   1490   if (unlikely (!count)) return;
   1491   hb_glyph_info_t *info = buffer->info;
   1492 
   1493   unsigned int start = 0;
   1494   unsigned int end;
   1495   for (end = start + 1; end < count; end++)
   1496     if (info[start].cluster != info[end].cluster) {
   1497       normalize_glyphs_cluster (buffer, start, end, backward);
   1498       start = end;
   1499     }
   1500   normalize_glyphs_cluster (buffer, start, end, backward);
   1501 }
   1502