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 +}