gfx/harfbuzz/src/hb-buffer.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial