tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

hb-buffer.cc (60701B)


      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.hh"
     31 #include "hb-utf.hh"
     32 
     33 
     34 /**
     35 * SECTION: hb-buffer
     36 * @title: hb-buffer
     37 * @short_description: Input and output buffers
     38 * @include: hb.h
     39 *
     40 * Buffers serve a dual role in HarfBuzz; before shaping, they hold
     41 * the input characters that are passed to hb_shape(), and after
     42 * shaping they hold the output glyphs.
     43 *
     44 * The input buffer is a sequence of Unicode codepoints, with
     45 * associated attributes such as direction and script.  The output
     46 * buffer is a sequence of glyphs, with associated attributes such
     47 * as position and cluster.
     48 **/
     49 
     50 
     51 /**
     52 * hb_segment_properties_equal:
     53 * @a: first #hb_segment_properties_t to compare.
     54 * @b: second #hb_segment_properties_t to compare.
     55 *
     56 * Checks the equality of two #hb_segment_properties_t's.
     57 *
     58 * Return value:
     59 * `true` if all properties of @a equal those of @b, `false` otherwise.
     60 *
     61 * Since: 0.9.7
     62 **/
     63 hb_bool_t
     64 hb_segment_properties_equal (const hb_segment_properties_t *a,
     65 		     const hb_segment_properties_t *b)
     66 {
     67  return a->direction == b->direction &&
     68  a->script    == b->script    &&
     69  a->language  == b->language  &&
     70  a->reserved1 == b->reserved1 &&
     71  a->reserved2 == b->reserved2;
     72 
     73 }
     74 
     75 /**
     76 * hb_segment_properties_hash:
     77 * @p: #hb_segment_properties_t to hash.
     78 *
     79 * Creates a hash representing @p.
     80 *
     81 * Return value:
     82 * A hash of @p.
     83 *
     84 * Since: 0.9.7
     85 **/
     86 unsigned int
     87 hb_segment_properties_hash (const hb_segment_properties_t *p)
     88 {
     89  return ((unsigned int) p->direction * 31 +
     90   (unsigned int) p->script) * 31 +
     91  (intptr_t) (p->language);
     92 }
     93 
     94 /**
     95 * hb_segment_properties_overlay:
     96 * @p: #hb_segment_properties_t to fill in.
     97 * @src: #hb_segment_properties_t to fill in from.
     98 *
     99 * Fills in missing fields of @p from @src in a considered manner.
    100 *
    101 * First, if @p does not have direction set, direction is copied from @src.
    102 *
    103 * Next, if @p and @src have the same direction (which can be unset), if @p
    104 * does not have script set, script is copied from @src.
    105 *
    106 * Finally, if @p and @src have the same direction and script (which either
    107 * can be unset), if @p does not have language set, language is copied from
    108 * @src.
    109 *
    110 * Since: 3.3.0
    111 **/
    112 void
    113 hb_segment_properties_overlay (hb_segment_properties_t *p,
    114 		       const hb_segment_properties_t *src)
    115 {
    116  if (unlikely (!p || !src))
    117    return;
    118 
    119  if (!p->direction)
    120    p->direction = src->direction;
    121 
    122  if (p->direction != src->direction)
    123    return;
    124 
    125  if (!p->script)
    126    p->script = src->script;
    127 
    128  if (p->script != src->script)
    129    return;
    130 
    131  if (!p->language)
    132    p->language = src->language;
    133 }
    134 
    135 /* Here is how the buffer works internally:
    136 *
    137 * There are two info pointers: info and out_info.  They always have
    138 * the same allocated size, but different lengths.
    139 *
    140 * As an optimization, both info and out_info may point to the
    141 * same piece of memory, which is owned by info.  This remains the
    142 * case as long as out_len doesn't exceed i at any time.
    143 * In that case, sync() is mostly no-op and the glyph operations
    144 * operate mostly in-place.
    145 *
    146 * As soon as out_info gets longer than info, out_info is moved over
    147 * to an alternate buffer (which we reuse the pos buffer for), and its
    148 * current contents (out_len entries) are copied to the new place.
    149 *
    150 * This should all remain transparent to the user.  sync() then
    151 * switches info over to out_info and does housekeeping.
    152 */
    153 
    154 
    155 
    156 /* Internal API */
    157 
    158 bool
    159 hb_buffer_t::enlarge (unsigned int size)
    160 {
    161  if (unlikely (size > max_len))
    162  {
    163    successful = false;
    164    return false;
    165  }
    166 
    167  if (unlikely (!successful))
    168    return false;
    169 
    170  unsigned int new_allocated = allocated;
    171  hb_glyph_position_t *new_pos = nullptr;
    172  hb_glyph_info_t *new_info = nullptr;
    173  bool separate_out = out_info != info;
    174 
    175  if (unlikely (hb_unsigned_mul_overflows (size, sizeof (info[0]))))
    176    goto done;
    177 
    178  while (size >= new_allocated)
    179    new_allocated += (new_allocated >> 1) + 32;
    180 
    181  unsigned new_bytes;
    182  if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]), &new_bytes)))
    183    goto done;
    184 
    185  static_assert (sizeof (info[0]) == sizeof (pos[0]), "");
    186  new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_bytes);
    187  new_info = (hb_glyph_info_t *) hb_realloc (info, new_bytes);
    188 
    189 done:
    190  if (unlikely (!new_pos || !new_info))
    191    successful = false;
    192 
    193  if (likely (new_pos))
    194    pos = new_pos;
    195 
    196  if (likely (new_info))
    197    info = new_info;
    198 
    199  out_info = separate_out ? (hb_glyph_info_t *) pos : info;
    200  if (likely (successful))
    201    allocated = new_allocated;
    202 
    203  return likely (successful);
    204 }
    205 
    206 bool
    207 hb_buffer_t::make_room_for (unsigned int num_in,
    208 		    unsigned int num_out)
    209 {
    210  if (unlikely (!ensure (out_len + num_out))) return false;
    211 
    212  if (out_info == info &&
    213      out_len + num_out > idx + num_in)
    214  {
    215    assert (have_output);
    216 
    217    out_info = (hb_glyph_info_t *) pos;
    218    hb_memcpy (out_info, info, out_len * sizeof (out_info[0]));
    219  }
    220 
    221  return true;
    222 }
    223 
    224 bool
    225 hb_buffer_t::shift_forward (unsigned int count)
    226 {
    227  assert (have_output);
    228  if (unlikely (!ensure (len + count))) return false;
    229 
    230  max_ops -= len - idx;
    231  if (unlikely (max_ops < 0))
    232  {
    233    successful = false;
    234    return false;
    235  }
    236 
    237  memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));
    238  if (idx + count > len)
    239  {
    240    /* Under memory failure we might expose this area.  At least
    241     * clean it up.  Oh well...
    242     *
    243     * Ideally, we should at least set Default_Ignorable bits on
    244     * these, as well as consistent cluster values.  But the former
    245     * is layering violation... */
    246    hb_memset (info + len, 0, (idx + count - len) * sizeof (info[0]));
    247  }
    248  len += count;
    249  idx += count;
    250 
    251  return true;
    252 }
    253 
    254 hb_buffer_t::scratch_buffer_t *
    255 hb_buffer_t::get_scratch_buffer (unsigned int *size)
    256 {
    257  have_output = false;
    258  have_positions = false;
    259 
    260  out_len = 0;
    261  out_info = info;
    262 
    263  assert ((uintptr_t) pos % sizeof (scratch_buffer_t) == 0);
    264  *size = allocated * sizeof (pos[0]) / sizeof (scratch_buffer_t);
    265  return (scratch_buffer_t *) (void *) pos;
    266 }
    267 
    268 
    269 
    270 /* HarfBuzz-Internal API */
    271 
    272 void
    273 hb_buffer_t::similar (const hb_buffer_t &src)
    274 {
    275  hb_unicode_funcs_destroy (unicode);
    276  unicode = hb_unicode_funcs_reference (src.unicode);
    277  flags = src.flags;
    278  cluster_level = src.cluster_level;
    279  replacement = src.replacement;
    280  invisible = src.invisible;
    281  not_found = src.not_found;
    282  not_found_variation_selector = src.not_found_variation_selector;
    283 }
    284 
    285 void
    286 hb_buffer_t::reset ()
    287 {
    288  hb_unicode_funcs_destroy (unicode);
    289  unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ());
    290  flags = HB_BUFFER_FLAG_DEFAULT;
    291  cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;
    292  replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
    293  invisible = 0;
    294  not_found = 0;
    295  not_found_variation_selector = HB_CODEPOINT_INVALID;
    296 
    297  clear ();
    298 }
    299 
    300 void
    301 hb_buffer_t::clear ()
    302 {
    303  content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
    304  hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
    305  props = default_props;
    306 
    307  successful = true;
    308  have_output = false;
    309  have_positions = false;
    310 
    311  idx = 0;
    312  len = 0;
    313  out_len = 0;
    314  out_info = info;
    315 
    316  hb_memset (context, 0, sizeof context);
    317  hb_memset (context_len, 0, sizeof context_len);
    318 
    319  deallocate_var_all ();
    320  serial = 0;
    321  random_state = 1;
    322  scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
    323 }
    324 
    325 void
    326 hb_buffer_t::enter ()
    327 {
    328  deallocate_var_all ();
    329  serial = 0;
    330  scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
    331  unsigned mul;
    332  if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR, &mul)))
    333  {
    334    max_len = hb_max (mul, (unsigned) HB_BUFFER_MAX_LEN_MIN);
    335  }
    336  if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR, &mul)))
    337  {
    338    max_ops = hb_max (mul, (unsigned) HB_BUFFER_MAX_OPS_MIN);
    339  }
    340 }
    341 void
    342 hb_buffer_t::leave ()
    343 {
    344  max_len = HB_BUFFER_MAX_LEN_DEFAULT;
    345  max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
    346  deallocate_var_all ();
    347  serial = 0;
    348 }
    349 
    350 
    351 void
    352 hb_buffer_t::add (hb_codepoint_t  codepoint,
    353 	  unsigned int    cluster)
    354 {
    355  hb_glyph_info_t *glyph;
    356 
    357  if (unlikely (!ensure (len + 1))) return;
    358 
    359  glyph = &info[len];
    360 
    361  hb_memset (glyph, 0, sizeof (*glyph));
    362  glyph->codepoint = codepoint;
    363  glyph->mask = 0;
    364  glyph->cluster = cluster;
    365 
    366  len++;
    367 }
    368 
    369 void
    370 hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
    371 {
    372  if (unlikely (!ensure (len + 1))) return;
    373 
    374  info[len] = glyph_info;
    375 
    376  len++;
    377 }
    378 void
    379 hb_buffer_t::add_info_and_pos (const hb_glyph_info_t &glyph_info,
    380 		       const hb_glyph_position_t &glyph_pos)
    381 {
    382  if (unlikely (!ensure (len + 1))) return;
    383 
    384  info[len] = glyph_info;
    385  assert (have_positions);
    386  pos[len] = glyph_pos;
    387 
    388  len++;
    389 }
    390 
    391 
    392 void
    393 hb_buffer_t::clear_output ()
    394 {
    395  have_output = true;
    396  have_positions = false;
    397 
    398  idx = 0;
    399  out_len = 0;
    400  out_info = info;
    401 }
    402 
    403 void
    404 hb_buffer_t::clear_positions ()
    405 {
    406  have_output = false;
    407  have_positions = true;
    408 
    409  out_len = 0;
    410  out_info = info;
    411 
    412  hb_memset (pos, 0, sizeof (pos[0]) * len);
    413 }
    414 
    415 bool
    416 hb_buffer_t::sync ()
    417 {
    418  bool ret = false;
    419 
    420  assert (have_output);
    421 
    422  assert (idx <= len);
    423 
    424  if (unlikely (!successful || !next_glyphs (len - idx)))
    425    goto reset;
    426 
    427  if (out_info != info)
    428  {
    429    pos = (hb_glyph_position_t *) info;
    430    info = out_info;
    431  }
    432  len = out_len;
    433  ret = true;
    434 
    435 reset:
    436  have_output = false;
    437  out_len = 0;
    438  out_info = info;
    439  idx = 0;
    440 
    441  return ret;
    442 }
    443 
    444 int
    445 hb_buffer_t::sync_so_far ()
    446 {
    447  bool had_output = have_output;
    448  unsigned out_i = out_len;
    449  unsigned i = idx;
    450  unsigned old_idx = idx;
    451 
    452  if (sync ())
    453    idx = out_i;
    454  else
    455    idx = i;
    456 
    457  if (had_output)
    458  {
    459    have_output = true;
    460    out_len = idx;
    461  }
    462 
    463  assert (idx <= len);
    464 
    465  return idx - old_idx;
    466 }
    467 
    468 bool
    469 hb_buffer_t::move_to (unsigned int i)
    470 {
    471  if (!have_output)
    472  {
    473    assert (i <= len);
    474    idx = i;
    475    return true;
    476  }
    477  if (unlikely (!successful))
    478    return false;
    479 
    480  assert (i <= out_len + (len - idx));
    481 
    482  if (out_len < i)
    483  {
    484    unsigned int count = i - out_len;
    485    if (unlikely (!make_room_for (count, count))) return false;
    486 
    487    memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));
    488    idx += count;
    489    out_len += count;
    490  }
    491  else if (out_len > i)
    492  {
    493    /* Tricky part: rewinding... */
    494    unsigned int count = out_len - i;
    495 
    496    /* This will blow in our face if memory allocation fails later
    497     * in this same lookup...
    498     *
    499     * We used to shift with extra 32 items.
    500     * But that would leave empty slots in the buffer in case of allocation
    501     * failures.  See comments in shift_forward().  This can cause O(N^2)
    502     * behavior more severely than adding 32 empty slots can... */
    503    if (unlikely (idx < count && !shift_forward (count - idx))) return false;
    504 
    505    assert (idx >= count);
    506 
    507    idx -= count;
    508    out_len -= count;
    509    memmove (info + idx, out_info + out_len, count * sizeof (out_info[0]));
    510  }
    511 
    512  return true;
    513 }
    514 
    515 
    516 void
    517 hb_buffer_t::set_masks (hb_mask_t    value,
    518 		hb_mask_t    mask,
    519 		unsigned int cluster_start,
    520 		unsigned int cluster_end)
    521 {
    522  if (!mask)
    523    return;
    524 
    525  hb_mask_t not_mask = ~mask;
    526  value &= mask;
    527 
    528  max_ops -= len;
    529  if (unlikely (max_ops < 0))
    530    successful = false;
    531 
    532  unsigned int count = len;
    533 
    534  if (cluster_start == 0 && cluster_end == (unsigned int) -1)
    535  {
    536    for (unsigned int i = 0; i < count; i++)
    537      info[i].mask = (info[i].mask & not_mask) | value;
    538    return;
    539  }
    540 
    541  for (unsigned int i = 0; i < count; i++)
    542    if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
    543      info[i].mask = (info[i].mask & not_mask) | value;
    544 }
    545 
    546 void
    547 hb_buffer_t::merge_clusters_impl (unsigned int start,
    548 			  unsigned int end)
    549 {
    550  if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))
    551  {
    552    unsafe_to_break (start, end);
    553    return;
    554  }
    555 
    556  max_ops -= end - start;
    557  if (unlikely (max_ops < 0))
    558    successful = false;
    559 
    560  unsigned int cluster = info[start].cluster;
    561 
    562  for (unsigned int i = start + 1; i < end; i++)
    563    cluster = hb_min (cluster, info[i].cluster);
    564 
    565  /* Extend end */
    566  if (cluster != info[end - 1].cluster)
    567    while (end < len && info[end - 1].cluster == info[end].cluster)
    568      end++;
    569 
    570  /* Extend start */
    571  if (cluster != info[start].cluster)
    572    while (idx < start && info[start - 1].cluster == info[start].cluster)
    573      start--;
    574 
    575  /* If we hit the start of buffer, continue in out-buffer. */
    576  if (idx == start && info[start].cluster != cluster)
    577    for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
    578      set_cluster (out_info[i - 1], cluster);
    579 
    580  for (unsigned int i = start; i < end; i++)
    581    set_cluster (info[i], cluster);
    582 }
    583 void
    584 hb_buffer_t::merge_out_clusters (unsigned int start,
    585 			 unsigned int end)
    586 {
    587  if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))
    588    return;
    589 
    590  if (unlikely (end - start < 2))
    591    return;
    592 
    593  max_ops -= end - start;
    594  if (unlikely (max_ops < 0))
    595    successful = false;
    596 
    597  unsigned int cluster = out_info[start].cluster;
    598 
    599  for (unsigned int i = start + 1; i < end; i++)
    600    cluster = hb_min (cluster, out_info[i].cluster);
    601 
    602  /* Extend start */
    603  while (start && out_info[start - 1].cluster == out_info[start].cluster)
    604    start--;
    605 
    606  /* Extend end */
    607  while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)
    608    end++;
    609 
    610  /* If we hit the end of out-buffer, continue in buffer. */
    611  if (end == out_len)
    612    for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
    613      set_cluster (info[i], cluster);
    614 
    615  for (unsigned int i = start; i < end; i++)
    616    set_cluster (out_info[i], cluster);
    617 }
    618 void
    619 hb_buffer_t::delete_glyph ()
    620 {
    621  /* The logic here is duplicated in hb_ot_hide_default_ignorables(). */
    622 
    623  unsigned int cluster = info[idx].cluster;
    624  if ((idx + 1 < len && cluster == info[idx + 1].cluster) ||
    625      (out_len && cluster == out_info[out_len - 1].cluster))
    626  {
    627    /* Cluster survives; do nothing. */
    628    goto done;
    629  }
    630 
    631  if (out_len)
    632  {
    633    /* Merge cluster backward. */
    634    if (cluster < out_info[out_len - 1].cluster)
    635    {
    636      unsigned int mask = info[idx].mask;
    637      unsigned int old_cluster = out_info[out_len - 1].cluster;
    638      for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--)
    639 set_cluster (out_info[i - 1], cluster, mask);
    640    }
    641    goto done;
    642  }
    643 
    644  if (idx + 1 < len)
    645  {
    646    /* Merge cluster forward. */
    647    merge_clusters (idx, idx + 2);
    648    goto done;
    649  }
    650 
    651 done:
    652  skip_glyph ();
    653 }
    654 
    655 void
    656 hb_buffer_t::delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info))
    657 {
    658  /* Merge clusters and delete filtered glyphs.
    659   * NOTE! We can't use out-buffer as we have positioning data. */
    660  unsigned int j = 0;
    661  unsigned int count = len;
    662  for (unsigned int i = 0; i < count; i++)
    663  {
    664    if (filter (&info[i]))
    665    {
    666      /* Merge clusters.
    667       * Same logic as delete_glyph(), but for in-place removal. */
    668 
    669      unsigned int cluster = info[i].cluster;
    670      if (i + 1 < count && cluster == info[i + 1].cluster)
    671 continue; /* Cluster survives; do nothing. */
    672 
    673      if (j)
    674      {
    675 /* Merge cluster backward. */
    676 if (cluster < info[j - 1].cluster)
    677 {
    678   unsigned int mask = info[i].mask;
    679   unsigned int old_cluster = info[j - 1].cluster;
    680   for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
    681     set_cluster (info[k - 1], cluster, mask);
    682 }
    683 continue;
    684      }
    685 
    686      if (i + 1 < count)
    687 merge_clusters (i, i + 2); /* Merge cluster forward. */
    688 
    689      continue;
    690    }
    691 
    692    if (j != i)
    693    {
    694      info[j] = info[i];
    695      pos[j] = pos[i];
    696    }
    697    j++;
    698  }
    699  len = j;
    700 }
    701 
    702 void
    703 hb_buffer_t::guess_segment_properties ()
    704 {
    705  assert_unicode ();
    706 
    707  /* If script is set to INVALID, guess from buffer contents */
    708  if (props.script == HB_SCRIPT_INVALID) {
    709    for (unsigned int i = 0; i < len; i++) {
    710      hb_script_t script = unicode->script (info[i].codepoint);
    711      if (likely (script != HB_SCRIPT_COMMON &&
    712 	  script != HB_SCRIPT_INHERITED &&
    713 	  script != HB_SCRIPT_UNKNOWN)) {
    714 props.script = script;
    715 break;
    716      }
    717    }
    718  }
    719 
    720  /* If direction is set to INVALID, guess from script */
    721  if (props.direction == HB_DIRECTION_INVALID) {
    722    props.direction = hb_script_get_horizontal_direction (props.script);
    723    if (props.direction == HB_DIRECTION_INVALID)
    724      props.direction = HB_DIRECTION_LTR;
    725  }
    726 
    727  /* If language is not set, use default language from locale */
    728  if (props.language == HB_LANGUAGE_INVALID) {
    729    /* TODO get_default_for_script? using $LANGUAGE */
    730    props.language = hb_language_get_default ();
    731  }
    732 }
    733 
    734 
    735 /* Public API */
    736 
    737 DEFINE_NULL_INSTANCE (hb_buffer_t) =
    738 {
    739  HB_OBJECT_HEADER_STATIC,
    740 
    741  const_cast<hb_unicode_funcs_t *> (&_hb_Null_hb_unicode_funcs_t),
    742  HB_BUFFER_FLAG_DEFAULT,
    743  HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
    744  HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
    745  0, /* invisible */
    746  0, /* not_found */
    747  HB_CODEPOINT_INVALID, /* not_found_variation_selector */
    748 
    749 
    750  HB_BUFFER_CONTENT_TYPE_INVALID,
    751  HB_SEGMENT_PROPERTIES_DEFAULT,
    752 
    753  false, /* successful */
    754  false, /* have_output */
    755  true  /* have_positions */
    756 
    757  /* Zero is good enough for everything else. */
    758 };
    759 
    760 
    761 /**
    762 * hb_buffer_create:
    763 *
    764 * Creates a new #hb_buffer_t with all properties to defaults.
    765 *
    766 * Return value: (transfer full):
    767 * A newly allocated #hb_buffer_t with a reference count of 1. The initial
    768 * reference count should be released with hb_buffer_destroy() when you are done
    769 * using the #hb_buffer_t. This function never returns `NULL`. If memory cannot
    770 * be allocated, a special #hb_buffer_t object will be returned on which
    771 * hb_buffer_allocation_successful() returns `false`.
    772 *
    773 * Since: 0.9.2
    774 **/
    775 hb_buffer_t *
    776 hb_buffer_create ()
    777 {
    778  hb_buffer_t *buffer;
    779 
    780  if (!(buffer = hb_object_create<hb_buffer_t> ()))
    781    return hb_buffer_get_empty ();
    782 
    783  buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
    784  buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
    785 
    786  buffer->reset ();
    787 
    788  return buffer;
    789 }
    790 
    791 /**
    792 * hb_buffer_create_similar:
    793 * @src: An #hb_buffer_t
    794 *
    795 * Creates a new #hb_buffer_t, similar to hb_buffer_create(). The only
    796 * difference is that the buffer is configured similarly to @src.
    797 *
    798 * Return value: (transfer full):
    799 * A newly allocated #hb_buffer_t, similar to hb_buffer_create().
    800 *
    801 * Since: 3.3.0
    802 **/
    803 hb_buffer_t *
    804 hb_buffer_create_similar (const hb_buffer_t *src)
    805 {
    806  hb_buffer_t *buffer = hb_buffer_create ();
    807 
    808  buffer->similar (*src);
    809 
    810  return buffer;
    811 }
    812 
    813 /**
    814 * hb_buffer_reset:
    815 * @buffer: An #hb_buffer_t
    816 *
    817 * Resets the buffer to its initial status, as if it was just newly created
    818 * with hb_buffer_create().
    819 *
    820 * Since: 0.9.2
    821 **/
    822 void
    823 hb_buffer_reset (hb_buffer_t *buffer)
    824 {
    825  if (unlikely (hb_object_is_immutable (buffer)))
    826    return;
    827 
    828  buffer->reset ();
    829 }
    830 
    831 /**
    832 * hb_buffer_get_empty:
    833 *
    834 * Fetches an empty #hb_buffer_t.
    835 *
    836 * Return value: (transfer full): The empty buffer
    837 *
    838 * Since: 0.9.2
    839 **/
    840 hb_buffer_t *
    841 hb_buffer_get_empty ()
    842 {
    843  return const_cast<hb_buffer_t *> (&Null (hb_buffer_t));
    844 }
    845 
    846 /**
    847 * hb_buffer_reference: (skip)
    848 * @buffer: An #hb_buffer_t
    849 *
    850 * Increases the reference count on @buffer by one. This prevents @buffer from
    851 * being destroyed until a matching call to hb_buffer_destroy() is made.
    852 *
    853 * Return value: (transfer full):
    854 * The referenced #hb_buffer_t.
    855 *
    856 * Since: 0.9.2
    857 **/
    858 hb_buffer_t *
    859 hb_buffer_reference (hb_buffer_t *buffer)
    860 {
    861  return hb_object_reference (buffer);
    862 }
    863 
    864 /**
    865 * hb_buffer_destroy: (skip)
    866 * @buffer: An #hb_buffer_t
    867 *
    868 * Deallocate the @buffer.
    869 * Decreases the reference count on @buffer by one. If the result is zero, then
    870 * @buffer and all associated resources are freed. See hb_buffer_reference().
    871 *
    872 * Since: 0.9.2
    873 **/
    874 void
    875 hb_buffer_destroy (hb_buffer_t *buffer)
    876 {
    877  if (!hb_object_destroy (buffer)) return;
    878 
    879  hb_unicode_funcs_destroy (buffer->unicode);
    880 
    881  hb_free (buffer->info);
    882  hb_free (buffer->pos);
    883 #ifndef HB_NO_BUFFER_MESSAGE
    884  if (buffer->message_destroy)
    885    buffer->message_destroy (buffer->message_data);
    886 #endif
    887 
    888  hb_free (buffer);
    889 }
    890 
    891 /**
    892 * hb_buffer_set_user_data: (skip)
    893 * @buffer: An #hb_buffer_t
    894 * @key: The user-data key
    895 * @data: A pointer to the user data
    896 * @destroy: (nullable): A callback to call when @data is not needed anymore
    897 * @replace: Whether to replace an existing data with the same key
    898 *
    899 * Attaches a user-data key/data pair to the specified buffer.
    900 *
    901 * Return value: `true` if success, `false` otherwise
    902 *
    903 * Since: 0.9.2
    904 **/
    905 hb_bool_t
    906 hb_buffer_set_user_data (hb_buffer_t        *buffer,
    907 		 hb_user_data_key_t *key,
    908 		 void *              data,
    909 		 hb_destroy_func_t   destroy,
    910 		 hb_bool_t           replace)
    911 {
    912  return hb_object_set_user_data (buffer, key, data, destroy, replace);
    913 }
    914 
    915 /**
    916 * hb_buffer_get_user_data: (skip)
    917 * @buffer: An #hb_buffer_t
    918 * @key: The user-data key to query
    919 *
    920 * Fetches the user data associated with the specified key,
    921 * attached to the specified buffer.
    922 *
    923 * Return value: (transfer none): A pointer to the user data
    924 *
    925 * Since: 0.9.2
    926 **/
    927 void *
    928 hb_buffer_get_user_data (const hb_buffer_t  *buffer,
    929 		 hb_user_data_key_t *key)
    930 {
    931  return hb_object_get_user_data (buffer, key);
    932 }
    933 
    934 
    935 /**
    936 * hb_buffer_set_content_type:
    937 * @buffer: An #hb_buffer_t
    938 * @content_type: The type of buffer contents to set
    939 *
    940 * Sets the type of @buffer contents. Buffers are either empty, contain
    941 * characters (before shaping), or contain glyphs (the result of shaping).
    942 *
    943 * You rarely need to call this function, since a number of other
    944 * functions transition the content type for you. Namely:
    945 *
    946 * - A newly created buffer starts with content type
    947 *   %HB_BUFFER_CONTENT_TYPE_INVALID. Calling hb_buffer_reset(),
    948 *   hb_buffer_clear_contents(), as well as calling hb_buffer_set_length()
    949 *   with an argument of zero all set the buffer content type to invalid
    950 *   as well.
    951 *
    952 * - Calling hb_buffer_add_utf8(), hb_buffer_add_utf16(),
    953 *   hb_buffer_add_utf32(), hb_buffer_add_codepoints() and
    954 *   hb_buffer_add_latin1() expect that buffer is either empty and
    955 *   have a content type of invalid, or that buffer content type is
    956 *   %HB_BUFFER_CONTENT_TYPE_UNICODE, and they also set the content
    957 *   type to Unicode if they added anything to an empty buffer.
    958 *
    959 * - Finally hb_shape() and hb_shape_full() expect that the buffer
    960 *   is either empty and have content type of invalid, or that buffer
    961 *   content type is %HB_BUFFER_CONTENT_TYPE_UNICODE, and upon
    962 *   success they set the buffer content type to
    963 *   %HB_BUFFER_CONTENT_TYPE_GLYPHS.
    964 *
    965 * The above transitions are designed such that one can use a buffer
    966 * in a loop of "reset : add-text : shape" without needing to ever
    967 * modify the content type manually.
    968 *
    969 * Since: 0.9.5
    970 **/
    971 void
    972 hb_buffer_set_content_type (hb_buffer_t              *buffer,
    973 		    hb_buffer_content_type_t  content_type)
    974 {
    975  buffer->content_type = content_type;
    976 }
    977 
    978 /**
    979 * hb_buffer_get_content_type:
    980 * @buffer: An #hb_buffer_t
    981 *
    982 * Fetches the type of @buffer contents. Buffers are either empty, contain
    983 * characters (before shaping), or contain glyphs (the result of shaping).
    984 *
    985 * Return value:
    986 * The type of @buffer contents
    987 *
    988 * Since: 0.9.5
    989 **/
    990 hb_buffer_content_type_t
    991 hb_buffer_get_content_type (const hb_buffer_t *buffer)
    992 {
    993  return buffer->content_type;
    994 }
    995 
    996 
    997 /**
    998 * hb_buffer_set_unicode_funcs:
    999 * @buffer: An #hb_buffer_t
   1000 * @unicode_funcs: The Unicode-functions structure
   1001 *
   1002 * Sets the Unicode-functions structure of a buffer to
   1003 * @unicode_funcs.
   1004 *
   1005 * Since: 0.9.2
   1006 **/
   1007 void
   1008 hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
   1009 		     hb_unicode_funcs_t *unicode_funcs)
   1010 {
   1011  if (unlikely (hb_object_is_immutable (buffer)))
   1012    return;
   1013 
   1014  if (!unicode_funcs)
   1015    unicode_funcs = hb_unicode_funcs_get_default ();
   1016 
   1017  hb_unicode_funcs_reference (unicode_funcs);
   1018  hb_unicode_funcs_destroy (buffer->unicode);
   1019  buffer->unicode = unicode_funcs;
   1020 }
   1021 
   1022 /**
   1023 * hb_buffer_get_unicode_funcs:
   1024 * @buffer: An #hb_buffer_t
   1025 *
   1026 * Fetches the Unicode-functions structure of a buffer.
   1027 *
   1028 * Return value: The Unicode-functions structure
   1029 *
   1030 * Since: 0.9.2
   1031 **/
   1032 hb_unicode_funcs_t *
   1033 hb_buffer_get_unicode_funcs (const hb_buffer_t *buffer)
   1034 {
   1035  return buffer->unicode;
   1036 }
   1037 
   1038 /**
   1039 * hb_buffer_set_direction:
   1040 * @buffer: An #hb_buffer_t
   1041 * @direction: the #hb_direction_t of the @buffer
   1042 *
   1043 * Set the text flow direction of the buffer. No shaping can happen without
   1044 * setting @buffer direction, and it controls the visual direction for the
   1045 * output glyphs; for RTL direction the glyphs will be reversed. Many layout
   1046 * features depend on the proper setting of the direction, for example,
   1047 * reversing RTL text before shaping, then shaping with LTR direction is not
   1048 * the same as keeping the text in logical order and shaping with RTL
   1049 * direction.
   1050 *
   1051 * Since: 0.9.2
   1052 **/
   1053 void
   1054 hb_buffer_set_direction (hb_buffer_t    *buffer,
   1055 		 hb_direction_t  direction)
   1056 {
   1057  if (unlikely (hb_object_is_immutable (buffer)))
   1058    return;
   1059 
   1060  buffer->props.direction = direction;
   1061 }
   1062 
   1063 /**
   1064 * hb_buffer_get_direction:
   1065 * @buffer: An #hb_buffer_t
   1066 *
   1067 * See hb_buffer_set_direction()
   1068 *
   1069 * Return value:
   1070 * The direction of the @buffer.
   1071 *
   1072 * Since: 0.9.2
   1073 **/
   1074 hb_direction_t
   1075 hb_buffer_get_direction (const hb_buffer_t *buffer)
   1076 {
   1077  return buffer->props.direction;
   1078 }
   1079 
   1080 /**
   1081 * hb_buffer_set_script:
   1082 * @buffer: An #hb_buffer_t
   1083 * @script: An #hb_script_t to set.
   1084 *
   1085 * Sets the script of @buffer to @script.
   1086 *
   1087 * Script is crucial for choosing the proper shaping behaviour for scripts that
   1088 * require it (e.g. Arabic) and the which OpenType features defined in the font
   1089 * to be applied.
   1090 *
   1091 * You can pass one of the predefined #hb_script_t values, or use
   1092 * hb_script_from_string() or hb_script_from_iso15924_tag() to get the
   1093 * corresponding script from an ISO 15924 script tag.
   1094 *
   1095 * Since: 0.9.2
   1096 **/
   1097 void
   1098 hb_buffer_set_script (hb_buffer_t *buffer,
   1099 	      hb_script_t  script)
   1100 {
   1101  if (unlikely (hb_object_is_immutable (buffer)))
   1102    return;
   1103 
   1104  buffer->props.script = script;
   1105 }
   1106 
   1107 /**
   1108 * hb_buffer_get_script:
   1109 * @buffer: An #hb_buffer_t
   1110 *
   1111 * Fetches the script of @buffer.
   1112 *
   1113 * Return value:
   1114 * The #hb_script_t of the @buffer
   1115 *
   1116 * Since: 0.9.2
   1117 **/
   1118 hb_script_t
   1119 hb_buffer_get_script (const hb_buffer_t *buffer)
   1120 {
   1121  return buffer->props.script;
   1122 }
   1123 
   1124 /**
   1125 * hb_buffer_set_language:
   1126 * @buffer: An #hb_buffer_t
   1127 * @language: An hb_language_t to set
   1128 *
   1129 * Sets the language of @buffer to @language.
   1130 *
   1131 * Languages are crucial for selecting which OpenType feature to apply to the
   1132 * buffer which can result in applying language-specific behaviour. Languages
   1133 * are orthogonal to the scripts, and though they are related, they are
   1134 * different concepts and should not be confused with each other.
   1135 *
   1136 * Use hb_language_from_string() to convert from BCP 47 language tags to
   1137 * #hb_language_t.
   1138 *
   1139 * Since: 0.9.2
   1140 **/
   1141 void
   1142 hb_buffer_set_language (hb_buffer_t   *buffer,
   1143 		hb_language_t  language)
   1144 {
   1145  if (unlikely (hb_object_is_immutable (buffer)))
   1146    return;
   1147 
   1148  buffer->props.language = language;
   1149 }
   1150 
   1151 /**
   1152 * hb_buffer_get_language:
   1153 * @buffer: An #hb_buffer_t
   1154 *
   1155 * See hb_buffer_set_language().
   1156 *
   1157 * Return value: (transfer none):
   1158 * The #hb_language_t of the buffer. Must not be freed by the caller.
   1159 *
   1160 * Since: 0.9.2
   1161 **/
   1162 hb_language_t
   1163 hb_buffer_get_language (const hb_buffer_t *buffer)
   1164 {
   1165  return buffer->props.language;
   1166 }
   1167 
   1168 /**
   1169 * hb_buffer_set_segment_properties:
   1170 * @buffer: An #hb_buffer_t
   1171 * @props: An #hb_segment_properties_t to use
   1172 *
   1173 * Sets the segment properties of the buffer, a shortcut for calling
   1174 * hb_buffer_set_direction(), hb_buffer_set_script() and
   1175 * hb_buffer_set_language() individually.
   1176 *
   1177 * Since: 0.9.7
   1178 **/
   1179 void
   1180 hb_buffer_set_segment_properties (hb_buffer_t *buffer,
   1181 			  const hb_segment_properties_t *props)
   1182 {
   1183  if (unlikely (hb_object_is_immutable (buffer)))
   1184    return;
   1185 
   1186  buffer->props = *props;
   1187 }
   1188 
   1189 /**
   1190 * hb_buffer_get_segment_properties:
   1191 * @buffer: An #hb_buffer_t
   1192 * @props: (out): The output #hb_segment_properties_t
   1193 *
   1194 * Sets @props to the #hb_segment_properties_t of @buffer.
   1195 *
   1196 * Since: 0.9.7
   1197 **/
   1198 void
   1199 hb_buffer_get_segment_properties (const hb_buffer_t *buffer,
   1200 			  hb_segment_properties_t *props)
   1201 {
   1202  *props = buffer->props;
   1203 }
   1204 
   1205 
   1206 /**
   1207 * hb_buffer_set_flags:
   1208 * @buffer: An #hb_buffer_t
   1209 * @flags: The buffer flags to set
   1210 *
   1211 * Sets @buffer flags to @flags. See #hb_buffer_flags_t.
   1212 *
   1213 * Since: 0.9.7
   1214 **/
   1215 void
   1216 hb_buffer_set_flags (hb_buffer_t       *buffer,
   1217 	     hb_buffer_flags_t  flags)
   1218 {
   1219  if (unlikely (hb_object_is_immutable (buffer)))
   1220    return;
   1221 
   1222  buffer->flags = flags;
   1223 }
   1224 
   1225 /**
   1226 * hb_buffer_get_flags:
   1227 * @buffer: An #hb_buffer_t
   1228 *
   1229 * Fetches the #hb_buffer_flags_t of @buffer.
   1230 *
   1231 * Return value:
   1232 * The @buffer flags
   1233 *
   1234 * Since: 0.9.7
   1235 **/
   1236 hb_buffer_flags_t
   1237 hb_buffer_get_flags (const hb_buffer_t *buffer)
   1238 {
   1239  return buffer->flags;
   1240 }
   1241 
   1242 /**
   1243 * hb_buffer_set_cluster_level:
   1244 * @buffer: An #hb_buffer_t
   1245 * @cluster_level: The cluster level to set on the buffer
   1246 *
   1247 * Sets the cluster level of a buffer. The #hb_buffer_cluster_level_t
   1248 * dictates one aspect of how HarfBuzz will treat non-base characters
   1249 * during shaping.
   1250 *
   1251 * Since: 0.9.42
   1252 **/
   1253 void
   1254 hb_buffer_set_cluster_level (hb_buffer_t               *buffer,
   1255 		     hb_buffer_cluster_level_t  cluster_level)
   1256 {
   1257  if (unlikely (hb_object_is_immutable (buffer)))
   1258    return;
   1259 
   1260  buffer->cluster_level = cluster_level;
   1261 }
   1262 
   1263 /**
   1264 * hb_buffer_get_cluster_level:
   1265 * @buffer: An #hb_buffer_t
   1266 *
   1267 * Fetches the cluster level of a buffer. The #hb_buffer_cluster_level_t
   1268 * dictates one aspect of how HarfBuzz will treat non-base characters
   1269 * during shaping.
   1270 *
   1271 * Return value: The cluster level of @buffer
   1272 *
   1273 * Since: 0.9.42
   1274 **/
   1275 hb_buffer_cluster_level_t
   1276 hb_buffer_get_cluster_level (const hb_buffer_t *buffer)
   1277 {
   1278  return buffer->cluster_level;
   1279 }
   1280 
   1281 
   1282 /**
   1283 * hb_buffer_set_replacement_codepoint:
   1284 * @buffer: An #hb_buffer_t
   1285 * @replacement: the replacement #hb_codepoint_t
   1286 *
   1287 * Sets the #hb_codepoint_t that replaces invalid entries for a given encoding
   1288 * when adding text to @buffer.
   1289 *
   1290 * Default is #HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT.
   1291 *
   1292 * Since: 0.9.31
   1293 **/
   1294 void
   1295 hb_buffer_set_replacement_codepoint (hb_buffer_t    *buffer,
   1296 			     hb_codepoint_t  replacement)
   1297 {
   1298  if (unlikely (hb_object_is_immutable (buffer)))
   1299    return;
   1300 
   1301  buffer->replacement = replacement;
   1302 }
   1303 
   1304 /**
   1305 * hb_buffer_get_replacement_codepoint:
   1306 * @buffer: An #hb_buffer_t
   1307 *
   1308 * Fetches the #hb_codepoint_t that replaces invalid entries for a given encoding
   1309 * when adding text to @buffer.
   1310 *
   1311 * Return value:
   1312 * The @buffer replacement #hb_codepoint_t
   1313 *
   1314 * Since: 0.9.31
   1315 **/
   1316 hb_codepoint_t
   1317 hb_buffer_get_replacement_codepoint (const hb_buffer_t *buffer)
   1318 {
   1319  return buffer->replacement;
   1320 }
   1321 
   1322 
   1323 /**
   1324 * hb_buffer_set_invisible_glyph:
   1325 * @buffer: An #hb_buffer_t
   1326 * @invisible: the invisible #hb_codepoint_t
   1327 *
   1328 * Sets the #hb_codepoint_t that replaces invisible characters in
   1329 * the shaping result.  If set to zero (default), the glyph for the
   1330 * U+0020 SPACE character is used.  Otherwise, this value is used
   1331 * verbatim.
   1332 *
   1333 * Since: 2.0.0
   1334 **/
   1335 void
   1336 hb_buffer_set_invisible_glyph (hb_buffer_t    *buffer,
   1337 		       hb_codepoint_t  invisible)
   1338 {
   1339  if (unlikely (hb_object_is_immutable (buffer)))
   1340    return;
   1341 
   1342  buffer->invisible = invisible;
   1343 }
   1344 
   1345 /**
   1346 * hb_buffer_get_invisible_glyph:
   1347 * @buffer: An #hb_buffer_t
   1348 *
   1349 * See hb_buffer_set_invisible_glyph().
   1350 *
   1351 * Return value:
   1352 * The @buffer invisible #hb_codepoint_t
   1353 *
   1354 * Since: 2.0.0
   1355 **/
   1356 hb_codepoint_t
   1357 hb_buffer_get_invisible_glyph (const hb_buffer_t *buffer)
   1358 {
   1359  return buffer->invisible;
   1360 }
   1361 
   1362 /**
   1363 * hb_buffer_set_not_found_glyph:
   1364 * @buffer: An #hb_buffer_t
   1365 * @not_found: the not-found #hb_codepoint_t
   1366 *
   1367 * Sets the #hb_codepoint_t that replaces characters not found in
   1368 * the font during shaping.
   1369 *
   1370 * The not-found glyph defaults to zero, sometimes known as the
   1371 * ".notdef" glyph.  This API allows for differentiating the two.
   1372 *
   1373 * Since: 3.1.0
   1374 **/
   1375 void
   1376 hb_buffer_set_not_found_glyph (hb_buffer_t    *buffer,
   1377 		       hb_codepoint_t  not_found)
   1378 {
   1379  if (unlikely (hb_object_is_immutable (buffer)))
   1380    return;
   1381 
   1382  buffer->not_found = not_found;
   1383 }
   1384 
   1385 /**
   1386 * hb_buffer_get_not_found_glyph:
   1387 * @buffer: An #hb_buffer_t
   1388 *
   1389 * See hb_buffer_set_not_found_glyph().
   1390 *
   1391 * Return value:
   1392 * The @buffer not-found #hb_codepoint_t
   1393 *
   1394 * Since: 3.1.0
   1395 **/
   1396 hb_codepoint_t
   1397 hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer)
   1398 {
   1399  return buffer->not_found;
   1400 }
   1401 
   1402 /**
   1403 * hb_buffer_set_not_found_variation_selector_glyph:
   1404 * @buffer: An #hb_buffer_t
   1405 * @not_found_variation_selector: the not-found-variation-selector #hb_codepoint_t
   1406 *
   1407 * Sets the #hb_codepoint_t that replaces variation-selector characters not resolved
   1408 * in the font during shaping.
   1409 *
   1410 * The not-found-variation-selector glyph defaults to #HB_CODEPOINT_INVALID,
   1411 * in which case an unresolved variation-selector will be removed from the glyph
   1412 * string during shaping. This API allows for changing that and retaining a glyph,
   1413 * such that the situation can be detected by the client and handled accordingly
   1414 * (e.g. by using a different font).
   1415 *
   1416 * Since: 10.0.0
   1417 **/
   1418 void
   1419 hb_buffer_set_not_found_variation_selector_glyph (hb_buffer_t    *buffer,
   1420 					  hb_codepoint_t  not_found_variation_selector)
   1421 {
   1422  buffer->not_found_variation_selector = not_found_variation_selector;
   1423 }
   1424 
   1425 /**
   1426 * hb_buffer_get_not_found_variation_selector_glyph:
   1427 * @buffer: An #hb_buffer_t
   1428 *
   1429 * See hb_buffer_set_not_found_variation_selector_glyph().
   1430 *
   1431 * Return value:
   1432 * The @buffer not-found-variation-selector #hb_codepoint_t
   1433 *
   1434 * Since: 10.0.0
   1435 **/
   1436 hb_codepoint_t
   1437 hb_buffer_get_not_found_variation_selector_glyph (const hb_buffer_t *buffer)
   1438 {
   1439  return buffer->not_found_variation_selector;
   1440 }
   1441 
   1442 /**
   1443 * hb_buffer_set_random_state:
   1444 * @buffer: An #hb_buffer_t
   1445 * @state: the new random state
   1446 *
   1447 * Sets the random state of the buffer. The state changes
   1448 * every time a glyph uses randomness (eg. the `rand`
   1449 * OpenType feature). This function together with
   1450 * hb_buffer_get_random_state() allow for transferring
   1451 * the current random state to a subsequent buffer, to
   1452 * get better randomness distribution.
   1453 *
   1454 * Defaults to 1 and when buffer contents are cleared.
   1455 * A value of 0 disables randomness during shaping.
   1456 *
   1457 * Since: 8.4.0
   1458 **/
   1459 void
   1460 hb_buffer_set_random_state (hb_buffer_t    *buffer,
   1461 		    unsigned        state)
   1462 {
   1463  if (unlikely (hb_object_is_immutable (buffer)))
   1464    return;
   1465 
   1466  buffer->random_state = state;
   1467 }
   1468 
   1469 /**
   1470 * hb_buffer_get_random_state:
   1471 * @buffer: An #hb_buffer_t
   1472 *
   1473 * See hb_buffer_set_random_state().
   1474 *
   1475 * Return value:
   1476 * The @buffer random state
   1477 *
   1478 * Since: 8.4.0
   1479 **/
   1480 unsigned
   1481 hb_buffer_get_random_state (const hb_buffer_t *buffer)
   1482 {
   1483  return buffer->random_state;
   1484 }
   1485 
   1486 /**
   1487 * hb_buffer_clear_contents:
   1488 * @buffer: An #hb_buffer_t
   1489 *
   1490 * Similar to hb_buffer_reset(), but does not clear the Unicode functions and
   1491 * the replacement code point.
   1492 *
   1493 * Since: 0.9.11
   1494 **/
   1495 void
   1496 hb_buffer_clear_contents (hb_buffer_t *buffer)
   1497 {
   1498  if (unlikely (hb_object_is_immutable (buffer)))
   1499    return;
   1500 
   1501  buffer->clear ();
   1502 }
   1503 
   1504 /**
   1505 * hb_buffer_pre_allocate:
   1506 * @buffer: An #hb_buffer_t
   1507 * @size: Number of items to pre allocate.
   1508 *
   1509 * Pre allocates memory for @buffer to fit at least @size number of items.
   1510 *
   1511 * Return value:
   1512 * `true` if @buffer memory allocation succeeded, `false` otherwise
   1513 *
   1514 * Since: 0.9.2
   1515 **/
   1516 hb_bool_t
   1517 hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
   1518 {
   1519  return buffer->ensure (size);
   1520 }
   1521 
   1522 /**
   1523 * hb_buffer_allocation_successful:
   1524 * @buffer: An #hb_buffer_t
   1525 *
   1526 * Check if allocating memory for the buffer succeeded.
   1527 *
   1528 * Return value:
   1529 * `true` if @buffer memory allocation succeeded, `false` otherwise.
   1530 *
   1531 * Since: 0.9.2
   1532 **/
   1533 hb_bool_t
   1534 hb_buffer_allocation_successful (hb_buffer_t  *buffer)
   1535 {
   1536  return buffer->successful;
   1537 }
   1538 
   1539 /**
   1540 * hb_buffer_add:
   1541 * @buffer: An #hb_buffer_t
   1542 * @codepoint: A Unicode code point.
   1543 * @cluster: The cluster value of @codepoint.
   1544 *
   1545 * Appends a character with the Unicode value of @codepoint to @buffer, and
   1546 * gives it the initial cluster value of @cluster. Clusters can be any thing
   1547 * the client wants, they are usually used to refer to the index of the
   1548 * character in the input text stream and are output in
   1549 * #hb_glyph_info_t.cluster field.
   1550 *
   1551 * This function does not check the validity of @codepoint, it is up to the
   1552 * caller to ensure it is a valid Unicode code point.
   1553 *
   1554 * Since: 0.9.7
   1555 **/
   1556 void
   1557 hb_buffer_add (hb_buffer_t    *buffer,
   1558        hb_codepoint_t  codepoint,
   1559        unsigned int    cluster)
   1560 {
   1561  buffer->add (codepoint, cluster);
   1562  buffer->clear_context (1);
   1563 }
   1564 
   1565 /**
   1566 * hb_buffer_set_length:
   1567 * @buffer: An #hb_buffer_t
   1568 * @length: The new length of @buffer
   1569 *
   1570 * Similar to hb_buffer_pre_allocate(), but clears any new items added at the
   1571 * end.
   1572 *
   1573 * Return value:
   1574 * `true` if @buffer memory allocation succeeded, `false` otherwise.
   1575 *
   1576 * Since: 0.9.2
   1577 **/
   1578 hb_bool_t
   1579 hb_buffer_set_length (hb_buffer_t  *buffer,
   1580 	      unsigned int  length)
   1581 {
   1582  if (unlikely (hb_object_is_immutable (buffer)))
   1583    return length == 0;
   1584 
   1585  if (unlikely (!buffer->ensure (length)))
   1586    return false;
   1587 
   1588  /* Wipe the new space */
   1589  if (length > buffer->len) {
   1590    hb_memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
   1591    if (buffer->have_positions)
   1592      hb_memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
   1593  }
   1594 
   1595  buffer->len = length;
   1596 
   1597  if (!length)
   1598  {
   1599    buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
   1600    buffer->clear_context (0);
   1601  }
   1602  buffer->clear_context (1);
   1603 
   1604  return true;
   1605 }
   1606 
   1607 /**
   1608 * hb_buffer_get_length:
   1609 * @buffer: An #hb_buffer_t
   1610 *
   1611 * Returns the number of items in the buffer.
   1612 *
   1613 * Return value:
   1614 * The @buffer length.
   1615 * The value valid as long as buffer has not been modified.
   1616 *
   1617 * Since: 0.9.2
   1618 **/
   1619 unsigned int
   1620 hb_buffer_get_length (const hb_buffer_t *buffer)
   1621 {
   1622  return buffer->len;
   1623 }
   1624 
   1625 /**
   1626 * hb_buffer_get_glyph_infos:
   1627 * @buffer: An #hb_buffer_t
   1628 * @length: (out): The output-array length.
   1629 *
   1630 * Returns @buffer glyph information array.  Returned pointer
   1631 * is valid as long as @buffer contents are not modified.
   1632 *
   1633 * Return value: (transfer none) (array length=length):
   1634 * The @buffer glyph information array.
   1635 * The value valid as long as buffer has not been modified.
   1636 *
   1637 * Since: 0.9.2
   1638 **/
   1639 hb_glyph_info_t *
   1640 hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
   1641 		   unsigned int *length)
   1642 {
   1643  if (length)
   1644    *length = buffer->len;
   1645 
   1646  return (hb_glyph_info_t *) buffer->info;
   1647 }
   1648 
   1649 /**
   1650 * hb_buffer_get_glyph_positions:
   1651 * @buffer: An #hb_buffer_t
   1652 * @length: (out): The output length
   1653 *
   1654 * Returns @buffer glyph position array.  Returned pointer
   1655 * is valid as long as @buffer contents are not modified.
   1656 *
   1657 * If buffer did not have positions before, the positions will be
   1658 * initialized to zeros, unless this function is called from
   1659 * within a buffer message callback (see hb_buffer_set_message_func()),
   1660 * in which case `NULL` is returned.
   1661 *
   1662 * Return value: (transfer none) (array length=length):
   1663 * The @buffer glyph position array.
   1664 * The value valid as long as buffer has not been modified.
   1665 *
   1666 * Since: 0.9.2
   1667 **/
   1668 hb_glyph_position_t *
   1669 hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
   1670 		       unsigned int *length)
   1671 {
   1672  if (length)
   1673    *length = buffer->len;
   1674 
   1675  if (!buffer->have_positions)
   1676  {
   1677    if (unlikely (buffer->message_depth))
   1678      return nullptr;
   1679 
   1680    buffer->clear_positions ();
   1681  }
   1682 
   1683  return (hb_glyph_position_t *) buffer->pos;
   1684 }
   1685 
   1686 /**
   1687 * hb_buffer_has_positions:
   1688 * @buffer: an #hb_buffer_t.
   1689 *
   1690 * Returns whether @buffer has glyph position data.
   1691 * A buffer gains position data when hb_buffer_get_glyph_positions() is called on it,
   1692 * and cleared of position data when hb_buffer_clear_contents() is called.
   1693 *
   1694 * Return value:
   1695 * `true` if the @buffer has position array, `false` otherwise.
   1696 *
   1697 * Since: 2.7.3
   1698 **/
   1699 HB_EXTERN hb_bool_t
   1700 hb_buffer_has_positions (hb_buffer_t  *buffer)
   1701 {
   1702  return buffer->have_positions;
   1703 }
   1704 
   1705 /**
   1706 * hb_glyph_info_get_glyph_flags:
   1707 * @info: a #hb_glyph_info_t
   1708 *
   1709 * Returns glyph flags encoded within a #hb_glyph_info_t.
   1710 *
   1711 * Return value:
   1712 * The #hb_glyph_flags_t encoded within @info
   1713 *
   1714 * Since: 1.5.0
   1715 **/
   1716 hb_glyph_flags_t
   1717 (hb_glyph_info_get_glyph_flags) (const hb_glyph_info_t *info)
   1718 {
   1719  return hb_glyph_info_get_glyph_flags (info);
   1720 }
   1721 
   1722 /**
   1723 * hb_buffer_reverse:
   1724 * @buffer: An #hb_buffer_t
   1725 *
   1726 * Reverses buffer contents.
   1727 *
   1728 * Since: 0.9.2
   1729 **/
   1730 void
   1731 hb_buffer_reverse (hb_buffer_t *buffer)
   1732 {
   1733  buffer->reverse ();
   1734 }
   1735 
   1736 /**
   1737 * hb_buffer_reverse_range:
   1738 * @buffer: An #hb_buffer_t
   1739 * @start: start index
   1740 * @end: end index
   1741 *
   1742 * Reverses buffer contents between @start and @end.
   1743 *
   1744 * Since: 0.9.41
   1745 **/
   1746 void
   1747 hb_buffer_reverse_range (hb_buffer_t *buffer,
   1748 		 unsigned int start, unsigned int end)
   1749 {
   1750  buffer->reverse_range (start, end);
   1751 }
   1752 
   1753 /**
   1754 * hb_buffer_reverse_clusters:
   1755 * @buffer: An #hb_buffer_t
   1756 *
   1757 * Reverses buffer clusters.  That is, the buffer contents are
   1758 * reversed, then each cluster (consecutive items having the
   1759 * same cluster number) are reversed again.
   1760 *
   1761 * Since: 0.9.2
   1762 **/
   1763 void
   1764 hb_buffer_reverse_clusters (hb_buffer_t *buffer)
   1765 {
   1766  buffer->reverse_clusters ();
   1767 }
   1768 
   1769 /**
   1770 * hb_buffer_guess_segment_properties:
   1771 * @buffer: An #hb_buffer_t
   1772 *
   1773 * Sets unset buffer segment properties based on buffer Unicode
   1774 * contents.  If buffer is not empty, it must have content type
   1775 * #HB_BUFFER_CONTENT_TYPE_UNICODE.
   1776 *
   1777 * If buffer script is not set (ie. is #HB_SCRIPT_INVALID), it
   1778 * will be set to the Unicode script of the first character in
   1779 * the buffer that has a script other than #HB_SCRIPT_COMMON,
   1780 * #HB_SCRIPT_INHERITED, and #HB_SCRIPT_UNKNOWN.
   1781 *
   1782 * Next, if buffer direction is not set (ie. is #HB_DIRECTION_INVALID),
   1783 * it will be set to the natural horizontal direction of the
   1784 * buffer script as returned by hb_script_get_horizontal_direction().
   1785 * If hb_script_get_horizontal_direction() returns #HB_DIRECTION_INVALID,
   1786 * then #HB_DIRECTION_LTR is used.
   1787 *
   1788 * Finally, if buffer language is not set (ie. is #HB_LANGUAGE_INVALID),
   1789 * it will be set to the process's default language as returned by
   1790 * hb_language_get_default().  This may change in the future by
   1791 * taking buffer script into consideration when choosing a language.
   1792 * Note that hb_language_get_default() is NOT threadsafe the first time
   1793 * it is called.  See documentation for that function for details.
   1794 *
   1795 * Since: 0.9.7
   1796 **/
   1797 void
   1798 hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
   1799 {
   1800  buffer->guess_segment_properties ();
   1801 }
   1802 
   1803 template <typename utf_t>
   1804 static inline void
   1805 hb_buffer_add_utf (hb_buffer_t  *buffer,
   1806 	   const typename utf_t::codepoint_t *text,
   1807 	   int           text_length,
   1808 	   unsigned int  item_offset,
   1809 	   int           item_length)
   1810 {
   1811  typedef typename utf_t::codepoint_t T;
   1812  const hb_codepoint_t replacement = buffer->replacement;
   1813 
   1814  buffer->assert_unicode ();
   1815 
   1816  if (unlikely (hb_object_is_immutable (buffer)))
   1817    return;
   1818 
   1819  if (text_length == -1)
   1820    text_length = utf_t::strlen (text);
   1821 
   1822  if (item_length == -1)
   1823    item_length = text_length - item_offset;
   1824 
   1825  if (unlikely (item_length < 0 ||
   1826 	item_length > INT_MAX / 8 ||
   1827 	!buffer->ensure (buffer->len + item_length * sizeof (T) / 4)))
   1828    return;
   1829 
   1830  /* If buffer is empty and pre-context provided, install it.
   1831   * This check is written this way, to make sure people can
   1832   * provide pre-context in one add_utf() call, then provide
   1833   * text in a follow-up call.  See:
   1834   *
   1835   * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
   1836   */
   1837  if (!buffer->len && item_offset > 0)
   1838  {
   1839    /* Add pre-context */
   1840    buffer->clear_context (0);
   1841    const T *prev = text + item_offset;
   1842    const T *start = text;
   1843    while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
   1844    {
   1845      hb_codepoint_t u;
   1846      prev = utf_t::prev (prev, start, &u, replacement);
   1847      buffer->context[0][buffer->context_len[0]++] = u;
   1848    }
   1849  }
   1850 
   1851  const T *next = text + item_offset;
   1852  const T *end = next + item_length;
   1853  while (next < end)
   1854  {
   1855    hb_codepoint_t u;
   1856    const T *old_next = next;
   1857    next = utf_t::next (next, end, &u, replacement);
   1858    buffer->add (u, old_next - (const T *) text);
   1859  }
   1860 
   1861  /* Add post-context */
   1862  buffer->clear_context (1);
   1863  end = text + text_length;
   1864  while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
   1865  {
   1866    hb_codepoint_t u;
   1867    next = utf_t::next (next, end, &u, replacement);
   1868    buffer->context[1][buffer->context_len[1]++] = u;
   1869  }
   1870 
   1871  buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
   1872 }
   1873 
   1874 /**
   1875 * hb_buffer_add_utf8:
   1876 * @buffer: An #hb_buffer_t
   1877 * @text: (array length=text_length) (element-type uint8_t): An array of UTF-8
   1878 *               characters to append.
   1879 * @text_length: The length of the @text, or -1 if it is `NULL` terminated.
   1880 * @item_offset: The offset of the first character to add to the @buffer.
   1881 * @item_length: The number of characters to add to the @buffer, or -1 for the
   1882 *               end of @text (assuming it is `NULL` terminated).
   1883 *
   1884 * See hb_buffer_add_codepoints().
   1885 *
   1886 * Replaces invalid UTF-8 characters with the @buffer replacement code point,
   1887 * see hb_buffer_set_replacement_codepoint().
   1888 *
   1889 * Since: 0.9.2
   1890 **/
   1891 void
   1892 hb_buffer_add_utf8 (hb_buffer_t  *buffer,
   1893 	    const char   *text,
   1894 	    int           text_length,
   1895 	    unsigned int  item_offset,
   1896 	    int           item_length)
   1897 {
   1898  hb_buffer_add_utf<hb_utf8_t> (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
   1899 }
   1900 
   1901 /**
   1902 * hb_buffer_add_utf16:
   1903 * @buffer: An #hb_buffer_t
   1904 * @text: (array length=text_length): An array of UTF-16 characters to append
   1905 * @text_length: The length of the @text, or -1 if it is `NULL` terminated
   1906 * @item_offset: The offset of the first character to add to the @buffer
   1907 * @item_length: The number of characters to add to the @buffer, or -1 for the
   1908 *               end of @text (assuming it is `NULL` terminated)
   1909 *
   1910 * See hb_buffer_add_codepoints().
   1911 *
   1912 * Replaces invalid UTF-16 characters with the @buffer replacement code point,
   1913 * see hb_buffer_set_replacement_codepoint().
   1914 *
   1915 * Since: 0.9.2
   1916 **/
   1917 void
   1918 hb_buffer_add_utf16 (hb_buffer_t    *buffer,
   1919 	     const uint16_t *text,
   1920 	     int             text_length,
   1921 	     unsigned int    item_offset,
   1922 	     int             item_length)
   1923 {
   1924  hb_buffer_add_utf<hb_utf16_t> (buffer, text, text_length, item_offset, item_length);
   1925 }
   1926 
   1927 /**
   1928 * hb_buffer_add_utf32:
   1929 * @buffer: An #hb_buffer_t
   1930 * @text: (array length=text_length): An array of UTF-32 characters to append
   1931 * @text_length: The length of the @text, or -1 if it is `NULL` terminated
   1932 * @item_offset: The offset of the first character to add to the @buffer
   1933 * @item_length: The number of characters to add to the @buffer, or -1 for the
   1934 *               end of @text (assuming it is `NULL` terminated)
   1935 *
   1936 * See hb_buffer_add_codepoints().
   1937 *
   1938 * Replaces invalid UTF-32 characters with the @buffer replacement code point,
   1939 * see hb_buffer_set_replacement_codepoint().
   1940 *
   1941 * Since: 0.9.2
   1942 **/
   1943 void
   1944 hb_buffer_add_utf32 (hb_buffer_t    *buffer,
   1945 	     const uint32_t *text,
   1946 	     int             text_length,
   1947 	     unsigned int    item_offset,
   1948 	     int             item_length)
   1949 {
   1950  hb_buffer_add_utf<hb_utf32_t> (buffer, text, text_length, item_offset, item_length);
   1951 }
   1952 
   1953 /**
   1954 * hb_buffer_add_latin1:
   1955 * @buffer: An #hb_buffer_t
   1956 * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8
   1957 *               characters to append
   1958 * @text_length: the length of the @text, or -1 if it is `NULL` terminated
   1959 * @item_offset: the offset of the first character to add to the @buffer
   1960 * @item_length: the number of characters to add to the @buffer, or -1 for the
   1961 *               end of @text (assuming it is `NULL` terminated)
   1962 *
   1963 * Similar to hb_buffer_add_codepoints(), but allows only access to first 256
   1964 * Unicode code points that can fit in 8-bit strings.
   1965 *
   1966 * <note>Has nothing to do with non-Unicode Latin-1 encoding.</note>
   1967 *
   1968 * Since: 0.9.39
   1969 **/
   1970 void
   1971 hb_buffer_add_latin1 (hb_buffer_t   *buffer,
   1972 	      const uint8_t *text,
   1973 	      int            text_length,
   1974 	      unsigned int   item_offset,
   1975 	      int            item_length)
   1976 {
   1977  hb_buffer_add_utf<hb_latin1_t> (buffer, text, text_length, item_offset, item_length);
   1978 }
   1979 
   1980 /**
   1981 * hb_buffer_add_codepoints:
   1982 * @buffer: a #hb_buffer_t to append characters to.
   1983 * @text: (array length=text_length): an array of Unicode code points to append.
   1984 * @text_length: the length of the @text, or -1 if it is `NULL` terminated.
   1985 * @item_offset: the offset of the first code point to add to the @buffer.
   1986 * @item_length: the number of code points to add to the @buffer, or -1 for the
   1987 *               end of @text (assuming it is `NULL` terminated).
   1988 *
   1989 * Appends characters from @text array to @buffer. The @item_offset is the
   1990 * position of the first character from @text that will be appended, and
   1991 * @item_length is the number of character. When shaping part of a larger text
   1992 * (e.g. a run of text from a paragraph), instead of passing just the substring
   1993 * corresponding to the run, it is preferable to pass the whole
   1994 * paragraph and specify the run start and length as @item_offset and
   1995 * @item_length, respectively, to give HarfBuzz the full context to be able,
   1996 * for example, to do cross-run Arabic shaping or properly handle combining
   1997 * marks at stat of run.
   1998 *
   1999 * This function does not check the validity of @text, it is up to the caller
   2000 * to ensure it contains a valid Unicode scalar values.  In contrast,
   2001 * hb_buffer_add_utf32() can be used that takes similar input but performs
   2002 * sanity-check on the input.
   2003 *
   2004 * Since: 0.9.31
   2005 **/
   2006 void
   2007 hb_buffer_add_codepoints (hb_buffer_t          *buffer,
   2008 		  const hb_codepoint_t *text,
   2009 		  int                   text_length,
   2010 		  unsigned int          item_offset,
   2011 		  int                   item_length)
   2012 {
   2013  hb_buffer_add_utf<hb_utf32_novalidate_t> (buffer, text, text_length, item_offset, item_length);
   2014 }
   2015 
   2016 
   2017 /**
   2018 * hb_buffer_append:
   2019 * @buffer: An #hb_buffer_t
   2020 * @source: source #hb_buffer_t
   2021 * @start: start index into source buffer to copy.  Use 0 to copy from start of buffer.
   2022 * @end: end index into source buffer to copy.  Use @UINT_MAX (or ((unsigned int) -1)) to copy to end of buffer.
   2023 *
   2024 * Append (part of) contents of another buffer to this buffer.
   2025 *
   2026 * Since: 1.5.0
   2027 **/
   2028 HB_EXTERN void
   2029 hb_buffer_append (hb_buffer_t *buffer,
   2030 	  const hb_buffer_t *source,
   2031 	  unsigned int start,
   2032 	  unsigned int end)
   2033 {
   2034  assert (!buffer->have_output && !source->have_output);
   2035  assert (buffer->have_positions == source->have_positions ||
   2036   !buffer->len || !source->len);
   2037  assert (buffer->content_type == source->content_type ||
   2038   !buffer->len || !source->len);
   2039 
   2040  if (end > source->len)
   2041    end = source->len;
   2042  if (start > end)
   2043    start = end;
   2044  if (start == end)
   2045    return;
   2046 
   2047  if (buffer->len + (end - start) < buffer->len) /* Overflows. */
   2048  {
   2049    buffer->successful = false;
   2050    return;
   2051  }
   2052 
   2053  unsigned int orig_len = buffer->len;
   2054  hb_buffer_set_length (buffer, buffer->len + (end - start));
   2055  if (unlikely (!buffer->successful))
   2056    return;
   2057 
   2058  if (!orig_len)
   2059    buffer->content_type = source->content_type;
   2060  if (!buffer->have_positions && source->have_positions)
   2061    buffer->clear_positions ();
   2062 
   2063  hb_segment_properties_overlay (&buffer->props, &source->props);
   2064 
   2065  hb_memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
   2066  if (buffer->have_positions)
   2067    hb_memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
   2068 
   2069  if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE)
   2070  {
   2071    /* See similar logic in add_utf. */
   2072 
   2073    /* pre-context */
   2074    if (!orig_len && start + source->context_len[0] > 0)
   2075    {
   2076      buffer->clear_context (0);
   2077      while (start > 0 && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
   2078 buffer->context[0][buffer->context_len[0]++] = source->info[--start].codepoint;
   2079      for (auto i = 0u; i < source->context_len[0] && buffer->context_len[0] < buffer->CONTEXT_LENGTH; i++)
   2080 buffer->context[0][buffer->context_len[0]++] = source->context[0][i];
   2081    }
   2082 
   2083    /* post-context */
   2084    buffer->clear_context (1);
   2085    while (end < source->len && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
   2086      buffer->context[1][buffer->context_len[1]++] = source->info[end++].codepoint;
   2087    for (auto i = 0u; i < source->context_len[1] && buffer->context_len[1] < buffer->CONTEXT_LENGTH; i++)
   2088      buffer->context[1][buffer->context_len[1]++] = source->context[1][i];
   2089  }
   2090 }
   2091 
   2092 
   2093 static int
   2094 compare_info_codepoint (const hb_glyph_info_t *pa,
   2095 		const hb_glyph_info_t *pb)
   2096 {
   2097  return (int) pb->codepoint - (int) pa->codepoint;
   2098 }
   2099 
   2100 static inline void
   2101 normalize_glyphs_cluster (hb_buffer_t *buffer,
   2102 		  unsigned int start,
   2103 		  unsigned int end,
   2104 		  bool backward)
   2105 {
   2106  hb_glyph_position_t *pos = buffer->pos;
   2107 
   2108  /* Total cluster advance */
   2109  hb_position_t total_x_advance = 0, total_y_advance = 0;
   2110  for (unsigned int i = start; i < end; i++)
   2111  {
   2112    total_x_advance += pos[i].x_advance;
   2113    total_y_advance += pos[i].y_advance;
   2114  }
   2115 
   2116  hb_position_t x_advance = 0, y_advance = 0;
   2117  for (unsigned int i = start; i < end; i++)
   2118  {
   2119    pos[i].x_offset += x_advance;
   2120    pos[i].y_offset += y_advance;
   2121 
   2122    x_advance += pos[i].x_advance;
   2123    y_advance += pos[i].y_advance;
   2124 
   2125    pos[i].x_advance = 0;
   2126    pos[i].y_advance = 0;
   2127  }
   2128 
   2129  if (backward)
   2130  {
   2131    /* Transfer all cluster advance to the last glyph. */
   2132    pos[end - 1].x_advance = total_x_advance;
   2133    pos[end - 1].y_advance = total_y_advance;
   2134 
   2135    hb_stable_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
   2136  } else {
   2137    /* Transfer all cluster advance to the first glyph. */
   2138    pos[start].x_advance += total_x_advance;
   2139    pos[start].y_advance += total_y_advance;
   2140    for (unsigned int i = start + 1; i < end; i++) {
   2141      pos[i].x_offset -= total_x_advance;
   2142      pos[i].y_offset -= total_y_advance;
   2143    }
   2144    hb_stable_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
   2145  }
   2146 }
   2147 
   2148 /**
   2149 * hb_buffer_normalize_glyphs:
   2150 * @buffer: An #hb_buffer_t
   2151 *
   2152 * Reorders a glyph buffer to have canonical in-cluster glyph order / position.
   2153 * The resulting clusters should behave identical to pre-reordering clusters.
   2154 *
   2155 * <note>This has nothing to do with Unicode normalization.</note>
   2156 *
   2157 * Since: 0.9.2
   2158 **/
   2159 void
   2160 hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
   2161 {
   2162  assert (buffer->have_positions);
   2163 
   2164  buffer->assert_glyphs ();
   2165 
   2166  bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
   2167 
   2168  foreach_cluster (buffer, start, end)
   2169    normalize_glyphs_cluster (buffer, start, end, backward);
   2170 }
   2171 
   2172 void
   2173 hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *))
   2174 {
   2175  assert (!have_positions);
   2176  for (unsigned int i = start + 1; i < end; i++)
   2177  {
   2178    unsigned int j = i;
   2179    while (j > start && compar (&info[j - 1], &info[i]) > 0)
   2180      j--;
   2181    if (i == j)
   2182      continue;
   2183    /* Move item i to occupy place for item j, shift what's in between. */
   2184    merge_clusters (j, i + 1);
   2185    {
   2186      hb_glyph_info_t t = info[i];
   2187      memmove (&info[j + 1], &info[j], (i - j) * sizeof (hb_glyph_info_t));
   2188      info[j] = t;
   2189    }
   2190  }
   2191 }
   2192 
   2193 
   2194 /*
   2195 * Comparing buffers.
   2196 */
   2197 
   2198 /**
   2199 * hb_buffer_diff:
   2200 * @buffer: a buffer.
   2201 * @reference: other buffer to compare to.
   2202 * @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepoint_t) -1.
   2203 * @position_fuzz: allowed absolute difference in position values.
   2204 *
   2205 * If dottedcircle_glyph is (hb_codepoint_t) -1 then #HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
   2206 * and #HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned.  This should be used by most
   2207 * callers if just comparing two buffers is needed.
   2208 *
   2209 * Since: 1.5.0
   2210 **/
   2211 hb_buffer_diff_flags_t
   2212 hb_buffer_diff (hb_buffer_t *buffer,
   2213 	hb_buffer_t *reference,
   2214 	hb_codepoint_t dottedcircle_glyph,
   2215 	unsigned int position_fuzz)
   2216 {
   2217  if (buffer->content_type != reference->content_type && buffer->len && reference->len)
   2218    return HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH;
   2219 
   2220  hb_buffer_diff_flags_t result = HB_BUFFER_DIFF_FLAG_EQUAL;
   2221  bool contains = dottedcircle_glyph != (hb_codepoint_t) -1;
   2222 
   2223  unsigned int count = reference->len;
   2224 
   2225  if (buffer->len != count)
   2226  {
   2227    /*
   2228     * we can't compare glyph-by-glyph, but we do want to know if there
   2229     * are .notdef or dottedcircle glyphs present in the reference buffer
   2230     */
   2231    const hb_glyph_info_t *info = reference->info;
   2232    unsigned int i;
   2233    for (i = 0; i < count; i++)
   2234    {
   2235      if (contains && info[i].codepoint == dottedcircle_glyph)
   2236 result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
   2237      if (contains && info[i].codepoint == 0)
   2238 result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
   2239    }
   2240    result |= HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH;
   2241    return hb_buffer_diff_flags_t (result);
   2242  }
   2243 
   2244  if (!count)
   2245    return hb_buffer_diff_flags_t (result);
   2246 
   2247  const hb_glyph_info_t *buf_info = buffer->info;
   2248  const hb_glyph_info_t *ref_info = reference->info;
   2249  for (unsigned int i = 0; i < count; i++)
   2250  {
   2251    if (buf_info->codepoint != ref_info->codepoint)
   2252      result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH;
   2253    if (buf_info->cluster != ref_info->cluster)
   2254      result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH;
   2255    if ((buf_info->mask ^ ref_info->mask) & HB_GLYPH_FLAG_DEFINED)
   2256      result |= HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH;
   2257    if (contains && ref_info->codepoint == dottedcircle_glyph)
   2258      result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
   2259    if (contains && ref_info->codepoint == 0)
   2260      result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
   2261    buf_info++;
   2262    ref_info++;
   2263  }
   2264 
   2265  if (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS)
   2266  {
   2267    assert (buffer->have_positions);
   2268    const hb_glyph_position_t *buf_pos = buffer->pos;
   2269    const hb_glyph_position_t *ref_pos = reference->pos;
   2270    for (unsigned int i = 0; i < count; i++)
   2271    {
   2272      if ((unsigned int) abs (buf_pos->x_advance - ref_pos->x_advance) > position_fuzz ||
   2273   (unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz ||
   2274   (unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz ||
   2275   (unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz)
   2276      {
   2277 result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH;
   2278 break;
   2279      }
   2280      buf_pos++;
   2281      ref_pos++;
   2282    }
   2283  }
   2284 
   2285  return result;
   2286 }
   2287 
   2288 
   2289 /*
   2290 * Debugging.
   2291 */
   2292 
   2293 #ifndef HB_NO_BUFFER_MESSAGE
   2294 /**
   2295 * hb_buffer_set_message_func:
   2296 * @buffer: An #hb_buffer_t
   2297 * @func: (closure user_data) (destroy destroy) (scope notified): Callback function
   2298 * @user_data: (nullable): Data to pass to @func
   2299 * @destroy: (nullable): The function to call when @user_data is not needed anymore
   2300 *
   2301 * Sets the implementation function for #hb_buffer_message_func_t.
   2302 *
   2303 * Since: 1.1.3
   2304 **/
   2305 void
   2306 hb_buffer_set_message_func (hb_buffer_t *buffer,
   2307 		    hb_buffer_message_func_t func,
   2308 		    void *user_data, hb_destroy_func_t destroy)
   2309 {
   2310  if (unlikely (hb_object_is_immutable (buffer)))
   2311  {
   2312    if (destroy)
   2313      destroy (user_data);
   2314    return;
   2315  }
   2316 
   2317  if (buffer->message_destroy)
   2318    buffer->message_destroy (buffer->message_data);
   2319 
   2320  if (func) {
   2321    buffer->message_func = func;
   2322    buffer->message_data = user_data;
   2323    buffer->message_destroy = destroy;
   2324  } else {
   2325    buffer->message_func = nullptr;
   2326    buffer->message_data = nullptr;
   2327    buffer->message_destroy = nullptr;
   2328  }
   2329 }
   2330 bool
   2331 hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
   2332 {
   2333  assert (!have_output || (out_info == info && out_len == idx));
   2334 
   2335  message_depth++;
   2336 
   2337  char buf[100];
   2338  vsnprintf (buf, sizeof (buf), fmt, ap);
   2339  bool ret = (bool) this->message_func (this, font, buf, this->message_data);
   2340 
   2341  message_depth--;
   2342 
   2343  return ret;
   2344 }
   2345 #endif