gfx/harfbuzz/src/hb-buffer.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/harfbuzz/src/hb-buffer.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1501 @@
     1.4 +/*
     1.5 + * Copyright © 1998-2004  David Turner and Werner Lemberg
     1.6 + * Copyright © 2004,2007,2009,2010  Red Hat, Inc.
     1.7 + * Copyright © 2011,2012  Google, Inc.
     1.8 + *
     1.9 + *  This is part of HarfBuzz, a text shaping library.
    1.10 + *
    1.11 + * Permission is hereby granted, without written agreement and without
    1.12 + * license or royalty fees, to use, copy, modify, and distribute this
    1.13 + * software and its documentation for any purpose, provided that the
    1.14 + * above copyright notice and the following two paragraphs appear in
    1.15 + * all copies of this software.
    1.16 + *
    1.17 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
    1.18 + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
    1.19 + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
    1.20 + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
    1.21 + * DAMAGE.
    1.22 + *
    1.23 + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
    1.24 + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    1.25 + * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
    1.26 + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
    1.27 + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    1.28 + *
    1.29 + * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
    1.30 + * Google Author(s): Behdad Esfahbod
    1.31 + */
    1.32 +
    1.33 +#include "hb-buffer-private.hh"
    1.34 +#include "hb-utf-private.hh"
    1.35 +
    1.36 +
    1.37 +#ifndef HB_DEBUG_BUFFER
    1.38 +#define HB_DEBUG_BUFFER (HB_DEBUG+0)
    1.39 +#endif
    1.40 +
    1.41 +
    1.42 +hb_bool_t
    1.43 +hb_segment_properties_equal (const hb_segment_properties_t *a,
    1.44 +			     const hb_segment_properties_t *b)
    1.45 +{
    1.46 +  return a->direction == b->direction &&
    1.47 +	 a->script    == b->script    &&
    1.48 +	 a->language  == b->language  &&
    1.49 +	 a->reserved1 == b->reserved1 &&
    1.50 +	 a->reserved2 == b->reserved2;
    1.51 +
    1.52 +}
    1.53 +
    1.54 +unsigned int
    1.55 +hb_segment_properties_hash (const hb_segment_properties_t *p)
    1.56 +{
    1.57 +  return (unsigned int) p->direction ^
    1.58 +	 (unsigned int) p->script ^
    1.59 +	 (intptr_t) (p->language);
    1.60 +}
    1.61 +
    1.62 +
    1.63 +
    1.64 +/* Here is how the buffer works internally:
    1.65 + *
    1.66 + * There are two info pointers: info and out_info.  They always have
    1.67 + * the same allocated size, but different lengths.
    1.68 + *
    1.69 + * As an optimization, both info and out_info may point to the
    1.70 + * same piece of memory, which is owned by info.  This remains the
    1.71 + * case as long as out_len doesn't exceed i at any time.
    1.72 + * In that case, swap_buffers() is no-op and the glyph operations operate
    1.73 + * mostly in-place.
    1.74 + *
    1.75 + * As soon as out_info gets longer than info, out_info is moved over
    1.76 + * to an alternate buffer (which we reuse the pos buffer for!), and its
    1.77 + * current contents (out_len entries) are copied to the new place.
    1.78 + * This should all remain transparent to the user.  swap_buffers() then
    1.79 + * switches info and out_info.
    1.80 + */
    1.81 +
    1.82 +
    1.83 +
    1.84 +/* Internal API */
    1.85 +
    1.86 +bool
    1.87 +hb_buffer_t::enlarge (unsigned int size)
    1.88 +{
    1.89 +  if (unlikely (in_error))
    1.90 +    return false;
    1.91 +
    1.92 +  unsigned int new_allocated = allocated;
    1.93 +  hb_glyph_position_t *new_pos = NULL;
    1.94 +  hb_glyph_info_t *new_info = NULL;
    1.95 +  bool separate_out = out_info != info;
    1.96 +
    1.97 +  if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
    1.98 +    goto done;
    1.99 +
   1.100 +  while (size >= new_allocated)
   1.101 +    new_allocated += (new_allocated >> 1) + 32;
   1.102 +
   1.103 +  ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
   1.104 +  if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
   1.105 +    goto done;
   1.106 +
   1.107 +  new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
   1.108 +  new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
   1.109 +
   1.110 +done:
   1.111 +  if (unlikely (!new_pos || !new_info))
   1.112 +    in_error = true;
   1.113 +
   1.114 +  if (likely (new_pos))
   1.115 +    pos = new_pos;
   1.116 +
   1.117 +  if (likely (new_info))
   1.118 +    info = new_info;
   1.119 +
   1.120 +  out_info = separate_out ? (hb_glyph_info_t *) pos : info;
   1.121 +  if (likely (!in_error))
   1.122 +    allocated = new_allocated;
   1.123 +
   1.124 +  return likely (!in_error);
   1.125 +}
   1.126 +
   1.127 +bool
   1.128 +hb_buffer_t::make_room_for (unsigned int num_in,
   1.129 +			    unsigned int num_out)
   1.130 +{
   1.131 +  if (unlikely (!ensure (out_len + num_out))) return false;
   1.132 +
   1.133 +  if (out_info == info &&
   1.134 +      out_len + num_out > idx + num_in)
   1.135 +  {
   1.136 +    assert (have_output);
   1.137 +
   1.138 +    out_info = (hb_glyph_info_t *) pos;
   1.139 +    memcpy (out_info, info, out_len * sizeof (out_info[0]));
   1.140 +  }
   1.141 +
   1.142 +  return true;
   1.143 +}
   1.144 +
   1.145 +bool
   1.146 +hb_buffer_t::shift_forward (unsigned int count)
   1.147 +{
   1.148 +  assert (have_output);
   1.149 +  if (unlikely (!ensure (len + count))) return false;
   1.150 +
   1.151 +  memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));
   1.152 +  len += count;
   1.153 +  idx += count;
   1.154 +
   1.155 +  return true;
   1.156 +}
   1.157 +
   1.158 +hb_buffer_t::scratch_buffer_t *
   1.159 +hb_buffer_t::get_scratch_buffer (unsigned int *size)
   1.160 +{
   1.161 +  have_output = false;
   1.162 +  have_positions = false;
   1.163 +
   1.164 +  out_len = 0;
   1.165 +  out_info = info;
   1.166 +
   1.167 +  assert ((uintptr_t) pos % sizeof (scratch_buffer_t) == 0);
   1.168 +  *size = allocated * sizeof (pos[0]) / sizeof (scratch_buffer_t);
   1.169 +  return (scratch_buffer_t *) (void *) pos;
   1.170 +}
   1.171 +
   1.172 +
   1.173 +
   1.174 +/* HarfBuzz-Internal API */
   1.175 +
   1.176 +void
   1.177 +hb_buffer_t::reset (void)
   1.178 +{
   1.179 +  if (unlikely (hb_object_is_inert (this)))
   1.180 +    return;
   1.181 +
   1.182 +  hb_unicode_funcs_destroy (unicode);
   1.183 +  unicode = hb_unicode_funcs_get_default ();
   1.184 +
   1.185 +  clear ();
   1.186 +}
   1.187 +
   1.188 +void
   1.189 +hb_buffer_t::clear (void)
   1.190 +{
   1.191 +  if (unlikely (hb_object_is_inert (this)))
   1.192 +    return;
   1.193 +
   1.194 +  hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
   1.195 +  props = default_props;
   1.196 +  flags = HB_BUFFER_FLAG_DEFAULT;
   1.197 +
   1.198 +  content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
   1.199 +  in_error = false;
   1.200 +  have_output = false;
   1.201 +  have_positions = false;
   1.202 +
   1.203 +  idx = 0;
   1.204 +  len = 0;
   1.205 +  out_len = 0;
   1.206 +  out_info = info;
   1.207 +
   1.208 +  serial = 0;
   1.209 +  memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
   1.210 +  memset (allocated_var_owner, 0, sizeof allocated_var_owner);
   1.211 +
   1.212 +  memset (context, 0, sizeof context);
   1.213 +  memset (context_len, 0, sizeof context_len);
   1.214 +}
   1.215 +
   1.216 +void
   1.217 +hb_buffer_t::add (hb_codepoint_t  codepoint,
   1.218 +		  unsigned int    cluster)
   1.219 +{
   1.220 +  hb_glyph_info_t *glyph;
   1.221 +
   1.222 +  if (unlikely (!ensure (len + 1))) return;
   1.223 +
   1.224 +  glyph = &info[len];
   1.225 +
   1.226 +  memset (glyph, 0, sizeof (*glyph));
   1.227 +  glyph->codepoint = codepoint;
   1.228 +  glyph->mask = 1;
   1.229 +  glyph->cluster = cluster;
   1.230 +
   1.231 +  len++;
   1.232 +}
   1.233 +
   1.234 +void
   1.235 +hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
   1.236 +{
   1.237 +  if (unlikely (!ensure (len + 1))) return;
   1.238 +
   1.239 +  info[len] = glyph_info;
   1.240 +
   1.241 +  len++;
   1.242 +}
   1.243 +
   1.244 +
   1.245 +void
   1.246 +hb_buffer_t::remove_output (void)
   1.247 +{
   1.248 +  if (unlikely (hb_object_is_inert (this)))
   1.249 +    return;
   1.250 +
   1.251 +  have_output = false;
   1.252 +  have_positions = false;
   1.253 +
   1.254 +  out_len = 0;
   1.255 +  out_info = info;
   1.256 +}
   1.257 +
   1.258 +void
   1.259 +hb_buffer_t::clear_output (void)
   1.260 +{
   1.261 +  if (unlikely (hb_object_is_inert (this)))
   1.262 +    return;
   1.263 +
   1.264 +  have_output = true;
   1.265 +  have_positions = false;
   1.266 +
   1.267 +  out_len = 0;
   1.268 +  out_info = info;
   1.269 +}
   1.270 +
   1.271 +void
   1.272 +hb_buffer_t::clear_positions (void)
   1.273 +{
   1.274 +  if (unlikely (hb_object_is_inert (this)))
   1.275 +    return;
   1.276 +
   1.277 +  have_output = false;
   1.278 +  have_positions = true;
   1.279 +
   1.280 +  out_len = 0;
   1.281 +  out_info = info;
   1.282 +
   1.283 +  memset (pos, 0, sizeof (pos[0]) * len);
   1.284 +}
   1.285 +
   1.286 +void
   1.287 +hb_buffer_t::swap_buffers (void)
   1.288 +{
   1.289 +  if (unlikely (in_error)) return;
   1.290 +
   1.291 +  assert (have_output);
   1.292 +  have_output = false;
   1.293 +
   1.294 +  if (out_info != info)
   1.295 +  {
   1.296 +    hb_glyph_info_t *tmp_string;
   1.297 +    tmp_string = info;
   1.298 +    info = out_info;
   1.299 +    out_info = tmp_string;
   1.300 +    pos = (hb_glyph_position_t *) out_info;
   1.301 +  }
   1.302 +
   1.303 +  unsigned int tmp;
   1.304 +  tmp = len;
   1.305 +  len = out_len;
   1.306 +  out_len = tmp;
   1.307 +
   1.308 +  idx = 0;
   1.309 +}
   1.310 +
   1.311 +
   1.312 +void
   1.313 +hb_buffer_t::replace_glyphs (unsigned int num_in,
   1.314 +			     unsigned int num_out,
   1.315 +			     const uint32_t *glyph_data)
   1.316 +{
   1.317 +  if (unlikely (!make_room_for (num_in, num_out))) return;
   1.318 +
   1.319 +  merge_clusters (idx, idx + num_in);
   1.320 +
   1.321 +  hb_glyph_info_t orig_info = info[idx];
   1.322 +  hb_glyph_info_t *pinfo = &out_info[out_len];
   1.323 +  for (unsigned int i = 0; i < num_out; i++)
   1.324 +  {
   1.325 +    *pinfo = orig_info;
   1.326 +    pinfo->codepoint = glyph_data[i];
   1.327 +    pinfo++;
   1.328 +  }
   1.329 +
   1.330 +  idx  += num_in;
   1.331 +  out_len += num_out;
   1.332 +}
   1.333 +
   1.334 +void
   1.335 +hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
   1.336 +{
   1.337 +  if (unlikely (!make_room_for (0, 1))) return;
   1.338 +
   1.339 +  out_info[out_len] = info[idx];
   1.340 +  out_info[out_len].codepoint = glyph_index;
   1.341 +
   1.342 +  out_len++;
   1.343 +}
   1.344 +
   1.345 +void
   1.346 +hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info)
   1.347 +{
   1.348 +  if (unlikely (!make_room_for (0, 1))) return;
   1.349 +
   1.350 +  out_info[out_len] = glyph_info;
   1.351 +
   1.352 +  out_len++;
   1.353 +}
   1.354 +
   1.355 +void
   1.356 +hb_buffer_t::copy_glyph (void)
   1.357 +{
   1.358 +  if (unlikely (!make_room_for (0, 1))) return;
   1.359 +
   1.360 +  out_info[out_len] = info[idx];
   1.361 +
   1.362 +  out_len++;
   1.363 +}
   1.364 +
   1.365 +bool
   1.366 +hb_buffer_t::move_to (unsigned int i)
   1.367 +{
   1.368 +  if (!have_output)
   1.369 +  {
   1.370 +    assert (i <= len);
   1.371 +    idx = i;
   1.372 +    return true;
   1.373 +  }
   1.374 +
   1.375 +  assert (i <= out_len + (len - idx));
   1.376 +
   1.377 +  if (out_len < i)
   1.378 +  {
   1.379 +    unsigned int count = i - out_len;
   1.380 +    if (unlikely (!make_room_for (count, count))) return false;
   1.381 +
   1.382 +    memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));
   1.383 +    idx += count;
   1.384 +    out_len += count;
   1.385 +  }
   1.386 +  else if (out_len > i)
   1.387 +  {
   1.388 +    /* Tricky part: rewinding... */
   1.389 +    unsigned int count = out_len - i;
   1.390 +
   1.391 +    if (unlikely (idx < count && !shift_forward (count + 32))) return false;
   1.392 +
   1.393 +    assert (idx >= count);
   1.394 +
   1.395 +    idx -= count;
   1.396 +    out_len -= count;
   1.397 +    memmove (info + idx, out_info + out_len, count * sizeof (out_info[0]));
   1.398 +  }
   1.399 +
   1.400 +  return true;
   1.401 +}
   1.402 +
   1.403 +void
   1.404 +hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
   1.405 +{
   1.406 +  if (unlikely (out_info != info || out_len != idx)) {
   1.407 +    if (unlikely (!make_room_for (1, 1))) return;
   1.408 +    out_info[out_len] = info[idx];
   1.409 +  }
   1.410 +  out_info[out_len].codepoint = glyph_index;
   1.411 +
   1.412 +  idx++;
   1.413 +  out_len++;
   1.414 +}
   1.415 +
   1.416 +
   1.417 +void
   1.418 +hb_buffer_t::set_masks (hb_mask_t    value,
   1.419 +			hb_mask_t    mask,
   1.420 +			unsigned int cluster_start,
   1.421 +			unsigned int cluster_end)
   1.422 +{
   1.423 +  hb_mask_t not_mask = ~mask;
   1.424 +  value &= mask;
   1.425 +
   1.426 +  if (!mask)
   1.427 +    return;
   1.428 +
   1.429 +  if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
   1.430 +    unsigned int count = len;
   1.431 +    for (unsigned int i = 0; i < count; i++)
   1.432 +      info[i].mask = (info[i].mask & not_mask) | value;
   1.433 +    return;
   1.434 +  }
   1.435 +
   1.436 +  unsigned int count = len;
   1.437 +  for (unsigned int i = 0; i < count; i++)
   1.438 +    if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
   1.439 +      info[i].mask = (info[i].mask & not_mask) | value;
   1.440 +}
   1.441 +
   1.442 +void
   1.443 +hb_buffer_t::reverse_range (unsigned int start,
   1.444 +			    unsigned int end)
   1.445 +{
   1.446 +  unsigned int i, j;
   1.447 +
   1.448 +  if (start == end - 1)
   1.449 +    return;
   1.450 +
   1.451 +  for (i = start, j = end - 1; i < j; i++, j--) {
   1.452 +    hb_glyph_info_t t;
   1.453 +
   1.454 +    t = info[i];
   1.455 +    info[i] = info[j];
   1.456 +    info[j] = t;
   1.457 +  }
   1.458 +
   1.459 +  if (pos) {
   1.460 +    for (i = start, j = end - 1; i < j; i++, j--) {
   1.461 +      hb_glyph_position_t t;
   1.462 +
   1.463 +      t = pos[i];
   1.464 +      pos[i] = pos[j];
   1.465 +      pos[j] = t;
   1.466 +    }
   1.467 +  }
   1.468 +}
   1.469 +
   1.470 +void
   1.471 +hb_buffer_t::reverse (void)
   1.472 +{
   1.473 +  if (unlikely (!len))
   1.474 +    return;
   1.475 +
   1.476 +  reverse_range (0, len);
   1.477 +}
   1.478 +
   1.479 +void
   1.480 +hb_buffer_t::reverse_clusters (void)
   1.481 +{
   1.482 +  unsigned int i, start, count, last_cluster;
   1.483 +
   1.484 +  if (unlikely (!len))
   1.485 +    return;
   1.486 +
   1.487 +  reverse ();
   1.488 +
   1.489 +  count = len;
   1.490 +  start = 0;
   1.491 +  last_cluster = info[0].cluster;
   1.492 +  for (i = 1; i < count; i++) {
   1.493 +    if (last_cluster != info[i].cluster) {
   1.494 +      reverse_range (start, i);
   1.495 +      start = i;
   1.496 +      last_cluster = info[i].cluster;
   1.497 +    }
   1.498 +  }
   1.499 +  reverse_range (start, i);
   1.500 +}
   1.501 +
   1.502 +void
   1.503 +hb_buffer_t::merge_clusters (unsigned int start,
   1.504 +			     unsigned int end)
   1.505 +{
   1.506 +  if (unlikely (end - start < 2))
   1.507 +    return;
   1.508 +
   1.509 +  unsigned int cluster = info[start].cluster;
   1.510 +
   1.511 +  for (unsigned int i = start + 1; i < end; i++)
   1.512 +    cluster = MIN (cluster, info[i].cluster);
   1.513 +
   1.514 +  /* Extend end */
   1.515 +  while (end < len && info[end - 1].cluster == info[end].cluster)
   1.516 +    end++;
   1.517 +
   1.518 +  /* Extend start */
   1.519 +  while (idx < start && info[start - 1].cluster == info[start].cluster)
   1.520 +    start--;
   1.521 +
   1.522 +  /* If we hit the start of buffer, continue in out-buffer. */
   1.523 +  if (idx == start)
   1.524 +    for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
   1.525 +      out_info[i - 1].cluster = cluster;
   1.526 +
   1.527 +  for (unsigned int i = start; i < end; i++)
   1.528 +    info[i].cluster = cluster;
   1.529 +}
   1.530 +void
   1.531 +hb_buffer_t::merge_out_clusters (unsigned int start,
   1.532 +				 unsigned int end)
   1.533 +{
   1.534 +  if (unlikely (end - start < 2))
   1.535 +    return;
   1.536 +
   1.537 +  unsigned int cluster = out_info[start].cluster;
   1.538 +
   1.539 +  for (unsigned int i = start + 1; i < end; i++)
   1.540 +    cluster = MIN (cluster, out_info[i].cluster);
   1.541 +
   1.542 +  /* Extend start */
   1.543 +  while (start && out_info[start - 1].cluster == out_info[start].cluster)
   1.544 +    start--;
   1.545 +
   1.546 +  /* Extend end */
   1.547 +  while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)
   1.548 +    end++;
   1.549 +
   1.550 +  /* If we hit the end of out-buffer, continue in buffer. */
   1.551 +  if (end == out_len)
   1.552 +    for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
   1.553 +      info[i].cluster = cluster;
   1.554 +
   1.555 +  for (unsigned int i = start; i < end; i++)
   1.556 +    out_info[i].cluster = cluster;
   1.557 +}
   1.558 +
   1.559 +void
   1.560 +hb_buffer_t::guess_segment_properties (void)
   1.561 +{
   1.562 +  assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
   1.563 +	  (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
   1.564 +
   1.565 +  /* If script is set to INVALID, guess from buffer contents */
   1.566 +  if (props.script == HB_SCRIPT_INVALID) {
   1.567 +    for (unsigned int i = 0; i < len; i++) {
   1.568 +      hb_script_t script = unicode->script (info[i].codepoint);
   1.569 +      if (likely (script != HB_SCRIPT_COMMON &&
   1.570 +		  script != HB_SCRIPT_INHERITED &&
   1.571 +		  script != HB_SCRIPT_UNKNOWN)) {
   1.572 +        props.script = script;
   1.573 +        break;
   1.574 +      }
   1.575 +    }
   1.576 +  }
   1.577 +
   1.578 +  /* If direction is set to INVALID, guess from script */
   1.579 +  if (props.direction == HB_DIRECTION_INVALID) {
   1.580 +    props.direction = hb_script_get_horizontal_direction (props.script);
   1.581 +  }
   1.582 +
   1.583 +  /* If language is not set, use default language from locale */
   1.584 +  if (props.language == HB_LANGUAGE_INVALID) {
   1.585 +    /* TODO get_default_for_script? using $LANGUAGE */
   1.586 +    props.language = hb_language_get_default ();
   1.587 +  }
   1.588 +}
   1.589 +
   1.590 +
   1.591 +static inline void
   1.592 +dump_var_allocation (const hb_buffer_t *buffer)
   1.593 +{
   1.594 +  char buf[80];
   1.595 +  for (unsigned int i = 0; i < 8; i++)
   1.596 +    buf[i] = '0' + buffer->allocated_var_bytes[7 - i];
   1.597 +  buf[8] = '\0';
   1.598 +  DEBUG_MSG (BUFFER, buffer,
   1.599 +	     "Current var allocation: %s",
   1.600 +	     buf);
   1.601 +}
   1.602 +
   1.603 +void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner)
   1.604 +{
   1.605 +  assert (byte_i < 8 && byte_i + count <= 8);
   1.606 +
   1.607 +  if (DEBUG_ENABLED (BUFFER))
   1.608 +    dump_var_allocation (this);
   1.609 +  DEBUG_MSG (BUFFER, this,
   1.610 +	     "Allocating var bytes %d..%d for %s",
   1.611 +	     byte_i, byte_i + count - 1, owner);
   1.612 +
   1.613 +  for (unsigned int i = byte_i; i < byte_i + count; i++) {
   1.614 +    assert (!allocated_var_bytes[i]);
   1.615 +    allocated_var_bytes[i]++;
   1.616 +    allocated_var_owner[i] = owner;
   1.617 +  }
   1.618 +}
   1.619 +
   1.620 +void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
   1.621 +{
   1.622 +  if (DEBUG_ENABLED (BUFFER))
   1.623 +    dump_var_allocation (this);
   1.624 +
   1.625 +  DEBUG_MSG (BUFFER, this,
   1.626 +	     "Deallocating var bytes %d..%d for %s",
   1.627 +	     byte_i, byte_i + count - 1, owner);
   1.628 +
   1.629 +  assert (byte_i < 8 && byte_i + count <= 8);
   1.630 +  for (unsigned int i = byte_i; i < byte_i + count; i++) {
   1.631 +    assert (allocated_var_bytes[i]);
   1.632 +    assert (0 == strcmp (allocated_var_owner[i], owner));
   1.633 +    allocated_var_bytes[i]--;
   1.634 +  }
   1.635 +}
   1.636 +
   1.637 +void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner)
   1.638 +{
   1.639 +  if (DEBUG_ENABLED (BUFFER))
   1.640 +    dump_var_allocation (this);
   1.641 +
   1.642 +  DEBUG_MSG (BUFFER, this,
   1.643 +	     "Asserting var bytes %d..%d for %s",
   1.644 +	     byte_i, byte_i + count - 1, owner);
   1.645 +
   1.646 +  assert (byte_i < 8 && byte_i + count <= 8);
   1.647 +  for (unsigned int i = byte_i; i < byte_i + count; i++) {
   1.648 +    assert (allocated_var_bytes[i]);
   1.649 +    assert (0 == strcmp (allocated_var_owner[i], owner));
   1.650 +  }
   1.651 +}
   1.652 +
   1.653 +void hb_buffer_t::deallocate_var_all (void)
   1.654 +{
   1.655 +  memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
   1.656 +  memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
   1.657 +}
   1.658 +
   1.659 +/* Public API */
   1.660 +
   1.661 +/**
   1.662 + * hb_buffer_create: (Xconstructor)
   1.663 + *
   1.664 + * 
   1.665 + *
   1.666 + * Return value: (transfer full)
   1.667 + *
   1.668 + * Since: 1.0
   1.669 + **/
   1.670 +hb_buffer_t *
   1.671 +hb_buffer_create (void)
   1.672 +{
   1.673 +  hb_buffer_t *buffer;
   1.674 +
   1.675 +  if (!(buffer = hb_object_create<hb_buffer_t> ()))
   1.676 +    return hb_buffer_get_empty ();
   1.677 +
   1.678 +  buffer->reset ();
   1.679 +
   1.680 +  return buffer;
   1.681 +}
   1.682 +
   1.683 +/**
   1.684 + * hb_buffer_get_empty:
   1.685 + *
   1.686 + * 
   1.687 + *
   1.688 + * Return value: (transfer full):
   1.689 + *
   1.690 + * Since: 1.0
   1.691 + **/
   1.692 +hb_buffer_t *
   1.693 +hb_buffer_get_empty (void)
   1.694 +{
   1.695 +  static const hb_buffer_t _hb_buffer_nil = {
   1.696 +    HB_OBJECT_HEADER_STATIC,
   1.697 +
   1.698 +    const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
   1.699 +    HB_SEGMENT_PROPERTIES_DEFAULT,
   1.700 +    HB_BUFFER_FLAG_DEFAULT,
   1.701 +
   1.702 +    HB_BUFFER_CONTENT_TYPE_INVALID,
   1.703 +    true, /* in_error */
   1.704 +    true, /* have_output */
   1.705 +    true  /* have_positions */
   1.706 +
   1.707 +    /* Zero is good enough for everything else. */
   1.708 +  };
   1.709 +
   1.710 +  return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
   1.711 +}
   1.712 +
   1.713 +/**
   1.714 + * hb_buffer_reference: (skip)
   1.715 + * @buffer: a buffer.
   1.716 + *
   1.717 + * 
   1.718 + *
   1.719 + * Return value: (transfer full):
   1.720 + *
   1.721 + * Since: 1.0
   1.722 + **/
   1.723 +hb_buffer_t *
   1.724 +hb_buffer_reference (hb_buffer_t *buffer)
   1.725 +{
   1.726 +  return hb_object_reference (buffer);
   1.727 +}
   1.728 +
   1.729 +/**
   1.730 + * hb_buffer_destroy: (skip)
   1.731 + * @buffer: a buffer.
   1.732 + *
   1.733 + * 
   1.734 + *
   1.735 + * Since: 1.0
   1.736 + **/
   1.737 +void
   1.738 +hb_buffer_destroy (hb_buffer_t *buffer)
   1.739 +{
   1.740 +  if (!hb_object_destroy (buffer)) return;
   1.741 +
   1.742 +  hb_unicode_funcs_destroy (buffer->unicode);
   1.743 +
   1.744 +  free (buffer->info);
   1.745 +  free (buffer->pos);
   1.746 +
   1.747 +  free (buffer);
   1.748 +}
   1.749 +
   1.750 +/**
   1.751 + * hb_buffer_set_user_data: (skip)
   1.752 + * @buffer: a buffer.
   1.753 + * @key: 
   1.754 + * @data: 
   1.755 + * @destroy: 
   1.756 + * @replace: 
   1.757 + *
   1.758 + * 
   1.759 + *
   1.760 + * Return value: 
   1.761 + *
   1.762 + * Since: 1.0
   1.763 + **/
   1.764 +hb_bool_t
   1.765 +hb_buffer_set_user_data (hb_buffer_t        *buffer,
   1.766 +			 hb_user_data_key_t *key,
   1.767 +			 void *              data,
   1.768 +			 hb_destroy_func_t   destroy,
   1.769 +			 hb_bool_t           replace)
   1.770 +{
   1.771 +  return hb_object_set_user_data (buffer, key, data, destroy, replace);
   1.772 +}
   1.773 +
   1.774 +/**
   1.775 + * hb_buffer_get_user_data: (skip)
   1.776 + * @buffer: a buffer.
   1.777 + * @key: 
   1.778 + *
   1.779 + * 
   1.780 + *
   1.781 + * Return value: 
   1.782 + *
   1.783 + * Since: 1.0
   1.784 + **/
   1.785 +void *
   1.786 +hb_buffer_get_user_data (hb_buffer_t        *buffer,
   1.787 +			 hb_user_data_key_t *key)
   1.788 +{
   1.789 +  return hb_object_get_user_data (buffer, key);
   1.790 +}
   1.791 +
   1.792 +
   1.793 +/**
   1.794 + * hb_buffer_set_content_type:
   1.795 + * @buffer: a buffer.
   1.796 + * @content_type: 
   1.797 + *
   1.798 + * 
   1.799 + *
   1.800 + * Since: 1.0
   1.801 + **/
   1.802 +void
   1.803 +hb_buffer_set_content_type (hb_buffer_t              *buffer,
   1.804 +			    hb_buffer_content_type_t  content_type)
   1.805 +{
   1.806 +  buffer->content_type = content_type;
   1.807 +}
   1.808 +
   1.809 +/**
   1.810 + * hb_buffer_get_content_type:
   1.811 + * @buffer: a buffer.
   1.812 + *
   1.813 + * 
   1.814 + *
   1.815 + * Return value: 
   1.816 + *
   1.817 + * Since: 1.0
   1.818 + **/
   1.819 +hb_buffer_content_type_t
   1.820 +hb_buffer_get_content_type (hb_buffer_t *buffer)
   1.821 +{
   1.822 +  return buffer->content_type;
   1.823 +}
   1.824 +
   1.825 +
   1.826 +/**
   1.827 + * hb_buffer_set_unicode_funcs:
   1.828 + * @buffer: a buffer.
   1.829 + * @unicode_funcs: 
   1.830 + *
   1.831 + * 
   1.832 + *
   1.833 + * Since: 1.0
   1.834 + **/
   1.835 +void
   1.836 +hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
   1.837 +			     hb_unicode_funcs_t *unicode_funcs)
   1.838 +{
   1.839 +  if (unlikely (hb_object_is_inert (buffer)))
   1.840 +    return;
   1.841 +
   1.842 +  if (!unicode_funcs)
   1.843 +    unicode_funcs = hb_unicode_funcs_get_default ();
   1.844 +
   1.845 +
   1.846 +  hb_unicode_funcs_reference (unicode_funcs);
   1.847 +  hb_unicode_funcs_destroy (buffer->unicode);
   1.848 +  buffer->unicode = unicode_funcs;
   1.849 +}
   1.850 +
   1.851 +/**
   1.852 + * hb_buffer_get_unicode_funcs:
   1.853 + * @buffer: a buffer.
   1.854 + *
   1.855 + * 
   1.856 + *
   1.857 + * Return value: 
   1.858 + *
   1.859 + * Since: 1.0
   1.860 + **/
   1.861 +hb_unicode_funcs_t *
   1.862 +hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
   1.863 +{
   1.864 +  return buffer->unicode;
   1.865 +}
   1.866 +
   1.867 +/**
   1.868 + * hb_buffer_set_direction:
   1.869 + * @buffer: a buffer.
   1.870 + * @direction: 
   1.871 + *
   1.872 + * 
   1.873 + *
   1.874 + * Since: 1.0
   1.875 + **/
   1.876 +void
   1.877 +hb_buffer_set_direction (hb_buffer_t    *buffer,
   1.878 +			 hb_direction_t  direction)
   1.879 +
   1.880 +{
   1.881 +  if (unlikely (hb_object_is_inert (buffer)))
   1.882 +    return;
   1.883 +
   1.884 +  buffer->props.direction = direction;
   1.885 +}
   1.886 +
   1.887 +/**
   1.888 + * hb_buffer_get_direction:
   1.889 + * @buffer: a buffer.
   1.890 + *
   1.891 + * 
   1.892 + *
   1.893 + * Return value: 
   1.894 + *
   1.895 + * Since: 1.0
   1.896 + **/
   1.897 +hb_direction_t
   1.898 +hb_buffer_get_direction (hb_buffer_t    *buffer)
   1.899 +{
   1.900 +  return buffer->props.direction;
   1.901 +}
   1.902 +
   1.903 +/**
   1.904 + * hb_buffer_set_script:
   1.905 + * @buffer: a buffer.
   1.906 + * @script: 
   1.907 + *
   1.908 + * 
   1.909 + *
   1.910 + * Since: 1.0
   1.911 + **/
   1.912 +void
   1.913 +hb_buffer_set_script (hb_buffer_t *buffer,
   1.914 +		      hb_script_t  script)
   1.915 +{
   1.916 +  if (unlikely (hb_object_is_inert (buffer)))
   1.917 +    return;
   1.918 +
   1.919 +  buffer->props.script = script;
   1.920 +}
   1.921 +
   1.922 +/**
   1.923 + * hb_buffer_get_script:
   1.924 + * @buffer: a buffer.
   1.925 + *
   1.926 + * 
   1.927 + *
   1.928 + * Return value: 
   1.929 + *
   1.930 + * Since: 1.0
   1.931 + **/
   1.932 +hb_script_t
   1.933 +hb_buffer_get_script (hb_buffer_t *buffer)
   1.934 +{
   1.935 +  return buffer->props.script;
   1.936 +}
   1.937 +
   1.938 +/**
   1.939 + * hb_buffer_set_language:
   1.940 + * @buffer: a buffer.
   1.941 + * @language: 
   1.942 + *
   1.943 + * 
   1.944 + *
   1.945 + * Since: 1.0
   1.946 + **/
   1.947 +void
   1.948 +hb_buffer_set_language (hb_buffer_t   *buffer,
   1.949 +			hb_language_t  language)
   1.950 +{
   1.951 +  if (unlikely (hb_object_is_inert (buffer)))
   1.952 +    return;
   1.953 +
   1.954 +  buffer->props.language = language;
   1.955 +}
   1.956 +
   1.957 +/**
   1.958 + * hb_buffer_get_language:
   1.959 + * @buffer: a buffer.
   1.960 + *
   1.961 + * 
   1.962 + *
   1.963 + * Return value: 
   1.964 + *
   1.965 + * Since: 1.0
   1.966 + **/
   1.967 +hb_language_t
   1.968 +hb_buffer_get_language (hb_buffer_t *buffer)
   1.969 +{
   1.970 +  return buffer->props.language;
   1.971 +}
   1.972 +
   1.973 +/**
   1.974 + * hb_buffer_set_segment_properties:
   1.975 + * @buffer: a buffer.
   1.976 + * @props: 
   1.977 + *
   1.978 + * 
   1.979 + *
   1.980 + * Since: 1.0
   1.981 + **/
   1.982 +void
   1.983 +hb_buffer_set_segment_properties (hb_buffer_t *buffer,
   1.984 +				  const hb_segment_properties_t *props)
   1.985 +{
   1.986 +  if (unlikely (hb_object_is_inert (buffer)))
   1.987 +    return;
   1.988 +
   1.989 +  buffer->props = *props;
   1.990 +}
   1.991 +
   1.992 +/**
   1.993 + * hb_buffer_get_segment_properties:
   1.994 + * @buffer: a buffer.
   1.995 + * @props: 
   1.996 + *
   1.997 + * 
   1.998 + *
   1.999 + * Since: 1.0
  1.1000 + **/
  1.1001 +void
  1.1002 +hb_buffer_get_segment_properties (hb_buffer_t *buffer,
  1.1003 +				  hb_segment_properties_t *props)
  1.1004 +{
  1.1005 +  *props = buffer->props;
  1.1006 +}
  1.1007 +
  1.1008 +
  1.1009 +/**
  1.1010 + * hb_buffer_set_flags:
  1.1011 + * @buffer: a buffer.
  1.1012 + * @flags: 
  1.1013 + *
  1.1014 + * 
  1.1015 + *
  1.1016 + * Since: 1.0
  1.1017 + **/
  1.1018 +void
  1.1019 +hb_buffer_set_flags (hb_buffer_t       *buffer,
  1.1020 +		     hb_buffer_flags_t  flags)
  1.1021 +{
  1.1022 +  if (unlikely (hb_object_is_inert (buffer)))
  1.1023 +    return;
  1.1024 +
  1.1025 +  buffer->flags = flags;
  1.1026 +}
  1.1027 +
  1.1028 +/**
  1.1029 + * hb_buffer_get_flags:
  1.1030 + * @buffer: a buffer.
  1.1031 + *
  1.1032 + * 
  1.1033 + *
  1.1034 + * Return value: 
  1.1035 + *
  1.1036 + * Since: 1.0
  1.1037 + **/
  1.1038 +hb_buffer_flags_t
  1.1039 +hb_buffer_get_flags (hb_buffer_t *buffer)
  1.1040 +{
  1.1041 +  return buffer->flags;
  1.1042 +}
  1.1043 +
  1.1044 +
  1.1045 +/**
  1.1046 + * hb_buffer_reset:
  1.1047 + * @buffer: a buffer.
  1.1048 + *
  1.1049 + * 
  1.1050 + *
  1.1051 + * Since: 1.0
  1.1052 + **/
  1.1053 +void
  1.1054 +hb_buffer_reset (hb_buffer_t *buffer)
  1.1055 +{
  1.1056 +  buffer->reset ();
  1.1057 +}
  1.1058 +
  1.1059 +/**
  1.1060 + * hb_buffer_clear_contents:
  1.1061 + * @buffer: a buffer.
  1.1062 + *
  1.1063 + * 
  1.1064 + *
  1.1065 + * Since: 1.0
  1.1066 + **/
  1.1067 +void
  1.1068 +hb_buffer_clear_contents (hb_buffer_t *buffer)
  1.1069 +{
  1.1070 +  buffer->clear ();
  1.1071 +}
  1.1072 +
  1.1073 +/**
  1.1074 + * hb_buffer_pre_allocate:
  1.1075 + * @buffer: a buffer.
  1.1076 + * @size: 
  1.1077 + *
  1.1078 + * 
  1.1079 + *
  1.1080 + * Return value: 
  1.1081 + *
  1.1082 + * Since: 1.0
  1.1083 + **/
  1.1084 +hb_bool_t
  1.1085 +hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
  1.1086 +{
  1.1087 +  return buffer->ensure (size);
  1.1088 +}
  1.1089 +
  1.1090 +/**
  1.1091 + * hb_buffer_allocation_successful:
  1.1092 + * @buffer: a buffer.
  1.1093 + *
  1.1094 + * 
  1.1095 + *
  1.1096 + * Return value: 
  1.1097 + *
  1.1098 + * Since: 1.0
  1.1099 + **/
  1.1100 +hb_bool_t
  1.1101 +hb_buffer_allocation_successful (hb_buffer_t  *buffer)
  1.1102 +{
  1.1103 +  return !buffer->in_error;
  1.1104 +}
  1.1105 +
  1.1106 +/**
  1.1107 + * hb_buffer_add:
  1.1108 + * @buffer: a buffer.
  1.1109 + * @codepoint: 
  1.1110 + * @cluster: 
  1.1111 + *
  1.1112 + * 
  1.1113 + *
  1.1114 + * Since: 1.0
  1.1115 + **/
  1.1116 +void
  1.1117 +hb_buffer_add (hb_buffer_t    *buffer,
  1.1118 +	       hb_codepoint_t  codepoint,
  1.1119 +	       unsigned int    cluster)
  1.1120 +{
  1.1121 +  buffer->add (codepoint, cluster);
  1.1122 +  buffer->clear_context (1);
  1.1123 +}
  1.1124 +
  1.1125 +/**
  1.1126 + * hb_buffer_set_length:
  1.1127 + * @buffer: a buffer.
  1.1128 + * @length: 
  1.1129 + *
  1.1130 + * 
  1.1131 + *
  1.1132 + * Return value: 
  1.1133 + *
  1.1134 + * Since: 1.0
  1.1135 + **/
  1.1136 +hb_bool_t
  1.1137 +hb_buffer_set_length (hb_buffer_t  *buffer,
  1.1138 +		      unsigned int  length)
  1.1139 +{
  1.1140 +  if (unlikely (hb_object_is_inert (buffer)))
  1.1141 +    return length == 0;
  1.1142 +
  1.1143 +  if (!buffer->ensure (length))
  1.1144 +    return false;
  1.1145 +
  1.1146 +  /* Wipe the new space */
  1.1147 +  if (length > buffer->len) {
  1.1148 +    memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
  1.1149 +    if (buffer->have_positions)
  1.1150 +      memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
  1.1151 +  }
  1.1152 +
  1.1153 +  buffer->len = length;
  1.1154 +
  1.1155 +  if (!length)
  1.1156 +  {
  1.1157 +    buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
  1.1158 +    buffer->clear_context (0);
  1.1159 +  }
  1.1160 +  buffer->clear_context (1);
  1.1161 +
  1.1162 +  return true;
  1.1163 +}
  1.1164 +
  1.1165 +/**
  1.1166 + * hb_buffer_get_length:
  1.1167 + * @buffer: a buffer.
  1.1168 + *
  1.1169 + * Returns the number of items in the buffer.
  1.1170 + *
  1.1171 + * Return value: buffer length.
  1.1172 + *
  1.1173 + * Since: 1.0
  1.1174 + **/
  1.1175 +unsigned int
  1.1176 +hb_buffer_get_length (hb_buffer_t *buffer)
  1.1177 +{
  1.1178 +  return buffer->len;
  1.1179 +}
  1.1180 +
  1.1181 +/**
  1.1182 + * hb_buffer_get_glyph_infos:
  1.1183 + * @buffer: a buffer.
  1.1184 + * @length: (out): output array length.
  1.1185 + *
  1.1186 + * Returns buffer glyph information array.  Returned pointer
  1.1187 + * is valid as long as buffer contents are not modified.
  1.1188 + *
  1.1189 + * Return value: (transfer none) (array length=length): buffer glyph information array.
  1.1190 + *
  1.1191 + * Since: 1.0
  1.1192 + **/
  1.1193 +hb_glyph_info_t *
  1.1194 +hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
  1.1195 +                           unsigned int *length)
  1.1196 +{
  1.1197 +  if (length)
  1.1198 +    *length = buffer->len;
  1.1199 +
  1.1200 +  return (hb_glyph_info_t *) buffer->info;
  1.1201 +}
  1.1202 +
  1.1203 +/**
  1.1204 + * hb_buffer_get_glyph_positions:
  1.1205 + * @buffer: a buffer.
  1.1206 + * @length: (out): output length.
  1.1207 + *
  1.1208 + * Returns buffer glyph position array.  Returned pointer
  1.1209 + * is valid as long as buffer contents are not modified.
  1.1210 + *
  1.1211 + * Return value: (transfer none) (array length=length): buffer glyph position array.
  1.1212 + *
  1.1213 + * Since: 1.0
  1.1214 + **/
  1.1215 +hb_glyph_position_t *
  1.1216 +hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
  1.1217 +                               unsigned int *length)
  1.1218 +{
  1.1219 +  if (!buffer->have_positions)
  1.1220 +    buffer->clear_positions ();
  1.1221 +
  1.1222 +  if (length)
  1.1223 +    *length = buffer->len;
  1.1224 +
  1.1225 +  return (hb_glyph_position_t *) buffer->pos;
  1.1226 +}
  1.1227 +
  1.1228 +/**
  1.1229 + * hb_buffer_reverse:
  1.1230 + * @buffer: a buffer.
  1.1231 + *
  1.1232 + * Reverses buffer contents.
  1.1233 + *
  1.1234 + * Since: 1.0
  1.1235 + **/
  1.1236 +void
  1.1237 +hb_buffer_reverse (hb_buffer_t *buffer)
  1.1238 +{
  1.1239 +  buffer->reverse ();
  1.1240 +}
  1.1241 +
  1.1242 +/**
  1.1243 + * hb_buffer_reverse_clusters:
  1.1244 + * @buffer: a buffer.
  1.1245 + *
  1.1246 + * Reverses buffer clusters.  That is, the buffer contents are
  1.1247 + * reversed, then each cluster (consecutive items having the
  1.1248 + * same cluster number) are reversed again.
  1.1249 + *
  1.1250 + * Since: 1.0
  1.1251 + **/
  1.1252 +void
  1.1253 +hb_buffer_reverse_clusters (hb_buffer_t *buffer)
  1.1254 +{
  1.1255 +  buffer->reverse_clusters ();
  1.1256 +}
  1.1257 +
  1.1258 +/**
  1.1259 + * hb_buffer_guess_segment_properties:
  1.1260 + * @buffer: a buffer.
  1.1261 + *
  1.1262 + * Sets unset buffer segment properties based on buffer Unicode
  1.1263 + * contents.  If buffer is not empty, it must have content type
  1.1264 + * %HB_BUFFER_CONTENT_TYPE_UNICODE.
  1.1265 + *
  1.1266 + * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
  1.1267 + * will be set to the Unicode script of the first character in
  1.1268 + * the buffer that has a script other than %HB_SCRIPT_COMMON,
  1.1269 + * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
  1.1270 + *
  1.1271 + * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
  1.1272 + * it will be set to the natural horizontal direction of the
  1.1273 + * buffer script as returned by hb_script_get_horizontal_direction().
  1.1274 + *
  1.1275 + * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
  1.1276 + * it will be set to the process's default language as returned by
  1.1277 + * hb_language_get_default().  This may change in the future by
  1.1278 + * taking buffer script into consideration when choosing a language.
  1.1279 + *
  1.1280 + * Since: 1.0
  1.1281 + **/
  1.1282 +void
  1.1283 +hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
  1.1284 +{
  1.1285 +  buffer->guess_segment_properties ();
  1.1286 +}
  1.1287 +
  1.1288 +template <typename T>
  1.1289 +static inline void
  1.1290 +hb_buffer_add_utf (hb_buffer_t  *buffer,
  1.1291 +		   const T      *text,
  1.1292 +		   int           text_length,
  1.1293 +		   unsigned int  item_offset,
  1.1294 +		   int           item_length)
  1.1295 +{
  1.1296 +  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
  1.1297 +	  (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
  1.1298 +
  1.1299 +  if (unlikely (hb_object_is_inert (buffer)))
  1.1300 +    return;
  1.1301 +
  1.1302 +  if (text_length == -1)
  1.1303 +    text_length = hb_utf_strlen (text);
  1.1304 +
  1.1305 +  if (item_length == -1)
  1.1306 +    item_length = text_length - item_offset;
  1.1307 +
  1.1308 +  buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
  1.1309 +
  1.1310 +  /* If buffer is empty and pre-context provided, install it.
  1.1311 +   * This check is written this way, to make sure people can
  1.1312 +   * provide pre-context in one add_utf() call, then provide
  1.1313 +   * text in a follow-up call.  See:
  1.1314 +   *
  1.1315 +   * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
  1.1316 +   */
  1.1317 +  if (!buffer->len && item_offset > 0)
  1.1318 +  {
  1.1319 +    /* Add pre-context */
  1.1320 +    buffer->clear_context (0);
  1.1321 +    const T *prev = text + item_offset;
  1.1322 +    const T *start = text;
  1.1323 +    while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
  1.1324 +    {
  1.1325 +      hb_codepoint_t u;
  1.1326 +      prev = hb_utf_prev (prev, start, &u);
  1.1327 +      buffer->context[0][buffer->context_len[0]++] = u;
  1.1328 +    }
  1.1329 +  }
  1.1330 +
  1.1331 +  const T *next = text + item_offset;
  1.1332 +  const T *end = next + item_length;
  1.1333 +  while (next < end)
  1.1334 +  {
  1.1335 +    hb_codepoint_t u;
  1.1336 +    const T *old_next = next;
  1.1337 +    next = hb_utf_next (next, end, &u);
  1.1338 +    buffer->add (u, old_next - (const T *) text);
  1.1339 +  }
  1.1340 +
  1.1341 +  /* Add post-context */
  1.1342 +  buffer->clear_context (1);
  1.1343 +  end = text + text_length;
  1.1344 +  while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
  1.1345 +  {
  1.1346 +    hb_codepoint_t u;
  1.1347 +    next = hb_utf_next (next, end, &u);
  1.1348 +    buffer->context[1][buffer->context_len[1]++] = u;
  1.1349 +  }
  1.1350 +
  1.1351 +  buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
  1.1352 +}
  1.1353 +
  1.1354 +/**
  1.1355 + * hb_buffer_add_utf8:
  1.1356 + * @buffer: a buffer.
  1.1357 + * @text: (array length=text_length):
  1.1358 + * @text_length: 
  1.1359 + * @item_offset: 
  1.1360 + * @item_length: 
  1.1361 + *
  1.1362 + * 
  1.1363 + *
  1.1364 + * Since: 1.0
  1.1365 + **/
  1.1366 +void
  1.1367 +hb_buffer_add_utf8 (hb_buffer_t  *buffer,
  1.1368 +		    const char   *text,
  1.1369 +		    int           text_length,
  1.1370 +		    unsigned int  item_offset,
  1.1371 +		    int           item_length)
  1.1372 +{
  1.1373 +  hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
  1.1374 +}
  1.1375 +
  1.1376 +/**
  1.1377 + * hb_buffer_add_utf16:
  1.1378 + * @buffer: a buffer.
  1.1379 + * @text: (array length=text_length):
  1.1380 + * @text_length: 
  1.1381 + * @item_offset: 
  1.1382 + * @item_length: 
  1.1383 + *
  1.1384 + * 
  1.1385 + *
  1.1386 + * Since: 1.0
  1.1387 + **/
  1.1388 +void
  1.1389 +hb_buffer_add_utf16 (hb_buffer_t    *buffer,
  1.1390 +		     const uint16_t *text,
  1.1391 +		     int             text_length,
  1.1392 +		     unsigned int    item_offset,
  1.1393 +		     int             item_length)
  1.1394 +{
  1.1395 +  hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
  1.1396 +}
  1.1397 +
  1.1398 +/**
  1.1399 + * hb_buffer_add_utf32:
  1.1400 + * @buffer: a buffer.
  1.1401 + * @text: (array length=text_length):
  1.1402 + * @text_length: 
  1.1403 + * @item_offset: 
  1.1404 + * @item_length: 
  1.1405 + *
  1.1406 + * 
  1.1407 + *
  1.1408 + * Since: 1.0
  1.1409 + **/
  1.1410 +void
  1.1411 +hb_buffer_add_utf32 (hb_buffer_t    *buffer,
  1.1412 +		     const uint32_t *text,
  1.1413 +		     int             text_length,
  1.1414 +		     unsigned int    item_offset,
  1.1415 +		     int             item_length)
  1.1416 +{
  1.1417 +  hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
  1.1418 +}
  1.1419 +
  1.1420 +
  1.1421 +static int
  1.1422 +compare_info_codepoint (const hb_glyph_info_t *pa,
  1.1423 +			const hb_glyph_info_t *pb)
  1.1424 +{
  1.1425 +  return (int) pb->codepoint - (int) pa->codepoint;
  1.1426 +}
  1.1427 +
  1.1428 +static inline void
  1.1429 +normalize_glyphs_cluster (hb_buffer_t *buffer,
  1.1430 +			  unsigned int start,
  1.1431 +			  unsigned int end,
  1.1432 +			  bool backward)
  1.1433 +{
  1.1434 +  hb_glyph_position_t *pos = buffer->pos;
  1.1435 +
  1.1436 +  /* Total cluster advance */
  1.1437 +  hb_position_t total_x_advance = 0, total_y_advance = 0;
  1.1438 +  for (unsigned int i = start; i < end; i++)
  1.1439 +  {
  1.1440 +    total_x_advance += pos[i].x_advance;
  1.1441 +    total_y_advance += pos[i].y_advance;
  1.1442 +  }
  1.1443 +
  1.1444 +  hb_position_t x_advance = 0, y_advance = 0;
  1.1445 +  for (unsigned int i = start; i < end; i++)
  1.1446 +  {
  1.1447 +    pos[i].x_offset += x_advance;
  1.1448 +    pos[i].y_offset += y_advance;
  1.1449 +
  1.1450 +    x_advance += pos[i].x_advance;
  1.1451 +    y_advance += pos[i].y_advance;
  1.1452 +
  1.1453 +    pos[i].x_advance = 0;
  1.1454 +    pos[i].y_advance = 0;
  1.1455 +  }
  1.1456 +
  1.1457 +  if (backward)
  1.1458 +  {
  1.1459 +    /* Transfer all cluster advance to the last glyph. */
  1.1460 +    pos[end - 1].x_advance = total_x_advance;
  1.1461 +    pos[end - 1].y_advance = total_y_advance;
  1.1462 +
  1.1463 +    hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
  1.1464 +  } else {
  1.1465 +    /* Transfer all cluster advance to the first glyph. */
  1.1466 +    pos[start].x_advance += total_x_advance;
  1.1467 +    pos[start].y_advance += total_y_advance;
  1.1468 +    for (unsigned int i = start + 1; i < end; i++) {
  1.1469 +      pos[i].x_offset -= total_x_advance;
  1.1470 +      pos[i].y_offset -= total_y_advance;
  1.1471 +    }
  1.1472 +    hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
  1.1473 +  }
  1.1474 +}
  1.1475 +
  1.1476 +/**
  1.1477 + * hb_buffer_normalize_glyphs:
  1.1478 + * @buffer: a buffer.
  1.1479 + *
  1.1480 + * 
  1.1481 + *
  1.1482 + * Since: 1.0
  1.1483 + **/
  1.1484 +void
  1.1485 +hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
  1.1486 +{
  1.1487 +  assert (buffer->have_positions);
  1.1488 +  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
  1.1489 +
  1.1490 +  bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
  1.1491 +
  1.1492 +  unsigned int count = buffer->len;
  1.1493 +  if (unlikely (!count)) return;
  1.1494 +  hb_glyph_info_t *info = buffer->info;
  1.1495 +
  1.1496 +  unsigned int start = 0;
  1.1497 +  unsigned int end;
  1.1498 +  for (end = start + 1; end < count; end++)
  1.1499 +    if (info[start].cluster != info[end].cluster) {
  1.1500 +      normalize_glyphs_cluster (buffer, start, end, backward);
  1.1501 +      start = end;
  1.1502 +    }
  1.1503 +  normalize_glyphs_cluster (buffer, start, end, backward);
  1.1504 +}

mercurial