OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (C) 1998-2004 David Turner and Werner Lemberg |
| 3 * Copyright (C) 2004,2007,2009,2010 Red Hat, Inc. |
| 4 * |
| 5 * This is part of HarfBuzz, a text shaping library. |
| 6 * |
| 7 * Permission is hereby granted, without written agreement and without |
| 8 * license or royalty fees, to use, copy, modify, and distribute this |
| 9 * software and its documentation for any purpose, provided that the |
| 10 * above copyright notice and the following two paragraphs appear in |
| 11 * all copies of this software. |
| 12 * |
| 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
| 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
| 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
| 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
| 17 * DAMAGE. |
| 18 * |
| 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
| 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
| 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
| 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
| 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
| 24 * |
| 25 * Red Hat Author(s): Owen Taylor, Behdad Esfahbod |
| 26 */ |
| 27 |
| 28 #include "hb-buffer-private.hh" |
| 29 |
| 30 #include <string.h> |
| 31 |
| 32 HB_BEGIN_DECLS |
| 33 |
| 34 |
| 35 static hb_buffer_t _hb_buffer_nil = { |
| 36 HB_REFERENCE_COUNT_INVALID, /* ref_count */ |
| 37 |
| 38 &_hb_unicode_funcs_nil /* unicode */ |
| 39 }; |
| 40 |
| 41 /* Here is how the buffer works internally: |
| 42 * |
| 43 * There are two info pointers: info and out_info. They always have |
| 44 * the same allocated size, but different lengths. |
| 45 * |
| 46 * As an optimization, both info and out_info may point to the |
| 47 * same piece of memory, which is owned by info. This remains the |
| 48 * case as long as out_len doesn't exceed len at any time. |
| 49 * In that case, swap() is no-op and the glyph operations operate |
| 50 * mostly in-place. |
| 51 * |
| 52 * As soon as out_info gets longer than info, out_info is moved over |
| 53 * to an alternate buffer (which we reuse the pos buffer for!), and its |
| 54 * current contents (out_len entries) are copied to the new place. |
| 55 * This should all remain transparent to the user. swap() then |
| 56 * switches info and out_info. |
| 57 */ |
| 58 |
| 59 |
| 60 static hb_bool_t |
| 61 _hb_buffer_enlarge (hb_buffer_t *buffer, unsigned int size) |
| 62 { |
| 63 if (unlikely (buffer->in_error)) |
| 64 return FALSE; |
| 65 |
| 66 unsigned int new_allocated = buffer->allocated; |
| 67 hb_glyph_position_t *new_pos; |
| 68 hb_glyph_info_t *new_info; |
| 69 bool separate_out; |
| 70 |
| 71 separate_out = buffer->out_info != buffer->info; |
| 72 |
| 73 while (size > new_allocated) |
| 74 new_allocated += (new_allocated >> 1) + 8; |
| 75 |
| 76 new_pos = (hb_glyph_position_t *) realloc (buffer->pos, new_allocated * sizeof
(buffer->pos[0])); |
| 77 new_info = (hb_glyph_info_t *) realloc (buffer->info, new_allocated * sizeof (
buffer->info[0])); |
| 78 |
| 79 if (unlikely (!new_pos || !new_info)) |
| 80 buffer->in_error = TRUE; |
| 81 |
| 82 if (likely (new_pos)) |
| 83 buffer->pos = new_pos; |
| 84 |
| 85 if (likely (new_info)) |
| 86 buffer->info = new_info; |
| 87 |
| 88 buffer->out_info = separate_out ? (hb_glyph_info_t *) buffer->pos : buffer->in
fo; |
| 89 if (likely (!buffer->in_error)) |
| 90 buffer->allocated = new_allocated; |
| 91 |
| 92 return likely (!buffer->in_error); |
| 93 } |
| 94 |
| 95 static inline hb_bool_t |
| 96 _hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size) |
| 97 { |
| 98 return likely (size <= buffer->allocated) ? TRUE : _hb_buffer_enlarge (buffer,
size); |
| 99 } |
| 100 |
| 101 static inline hb_bool_t |
| 102 _hb_buffer_ensure_separate (hb_buffer_t *buffer, unsigned int size) |
| 103 { |
| 104 if (unlikely (!_hb_buffer_ensure (buffer, size))) return FALSE; |
| 105 |
| 106 if (buffer->out_info == buffer->info) |
| 107 { |
| 108 assert (buffer->have_output); |
| 109 |
| 110 buffer->out_info = (hb_glyph_info_t *) buffer->pos; |
| 111 memcpy (buffer->out_info, buffer->info, buffer->out_len * sizeof (buffer->ou
t_info[0])); |
| 112 } |
| 113 |
| 114 return TRUE; |
| 115 } |
| 116 |
| 117 |
| 118 /* Public API */ |
| 119 |
| 120 hb_buffer_t * |
| 121 hb_buffer_create (unsigned int pre_alloc_size) |
| 122 { |
| 123 hb_buffer_t *buffer; |
| 124 |
| 125 if (!HB_OBJECT_DO_CREATE (hb_buffer_t, buffer)) |
| 126 return &_hb_buffer_nil; |
| 127 |
| 128 if (pre_alloc_size) |
| 129 _hb_buffer_ensure (buffer, pre_alloc_size); |
| 130 |
| 131 buffer->unicode = &_hb_unicode_funcs_nil; |
| 132 |
| 133 return buffer; |
| 134 } |
| 135 |
| 136 hb_buffer_t * |
| 137 hb_buffer_reference (hb_buffer_t *buffer) |
| 138 { |
| 139 HB_OBJECT_DO_REFERENCE (buffer); |
| 140 } |
| 141 |
| 142 unsigned int |
| 143 hb_buffer_get_reference_count (hb_buffer_t *buffer) |
| 144 { |
| 145 HB_OBJECT_DO_GET_REFERENCE_COUNT (buffer); |
| 146 } |
| 147 |
| 148 void |
| 149 hb_buffer_destroy (hb_buffer_t *buffer) |
| 150 { |
| 151 HB_OBJECT_DO_DESTROY (buffer); |
| 152 |
| 153 hb_unicode_funcs_destroy (buffer->unicode); |
| 154 |
| 155 free (buffer->info); |
| 156 free (buffer->pos); |
| 157 |
| 158 free (buffer); |
| 159 } |
| 160 |
| 161 |
| 162 void |
| 163 hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, |
| 164 hb_unicode_funcs_t *unicode) |
| 165 { |
| 166 if (!unicode) |
| 167 unicode = &_hb_unicode_funcs_nil; |
| 168 |
| 169 hb_unicode_funcs_reference (unicode); |
| 170 hb_unicode_funcs_destroy (buffer->unicode); |
| 171 buffer->unicode = unicode; |
| 172 } |
| 173 |
| 174 hb_unicode_funcs_t * |
| 175 hb_buffer_get_unicode_funcs (hb_buffer_t *buffer) |
| 176 { |
| 177 return buffer->unicode; |
| 178 } |
| 179 |
| 180 void |
| 181 hb_buffer_set_direction (hb_buffer_t *buffer, |
| 182 hb_direction_t direction) |
| 183 |
| 184 { |
| 185 buffer->props.direction = direction; |
| 186 } |
| 187 |
| 188 hb_direction_t |
| 189 hb_buffer_get_direction (hb_buffer_t *buffer) |
| 190 { |
| 191 return buffer->props.direction; |
| 192 } |
| 193 |
| 194 void |
| 195 hb_buffer_set_script (hb_buffer_t *buffer, |
| 196 hb_script_t script) |
| 197 { |
| 198 buffer->props.script = script; |
| 199 } |
| 200 |
| 201 hb_script_t |
| 202 hb_buffer_get_script (hb_buffer_t *buffer) |
| 203 { |
| 204 return buffer->props.script; |
| 205 } |
| 206 |
| 207 void |
| 208 hb_buffer_set_language (hb_buffer_t *buffer, |
| 209 hb_language_t language) |
| 210 { |
| 211 buffer->props.language = language; |
| 212 } |
| 213 |
| 214 hb_language_t |
| 215 hb_buffer_get_language (hb_buffer_t *buffer) |
| 216 { |
| 217 return buffer->props.language; |
| 218 } |
| 219 |
| 220 |
| 221 void |
| 222 hb_buffer_clear (hb_buffer_t *buffer) |
| 223 { |
| 224 buffer->have_output = FALSE; |
| 225 buffer->have_positions = FALSE; |
| 226 buffer->in_error = FALSE; |
| 227 buffer->len = 0; |
| 228 buffer->out_len = 0; |
| 229 buffer->i = 0; |
| 230 buffer->out_info = buffer->info; |
| 231 buffer->serial = 0; |
| 232 } |
| 233 |
| 234 hb_bool_t |
| 235 hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size) |
| 236 { |
| 237 return _hb_buffer_ensure (buffer, size); |
| 238 } |
| 239 |
| 240 void |
| 241 hb_buffer_add_glyph (hb_buffer_t *buffer, |
| 242 hb_codepoint_t codepoint, |
| 243 hb_mask_t mask, |
| 244 unsigned int cluster) |
| 245 { |
| 246 hb_glyph_info_t *glyph; |
| 247 |
| 248 if (unlikely (!_hb_buffer_ensure (buffer, buffer->len + 1))) return; |
| 249 |
| 250 glyph = &buffer->info[buffer->len]; |
| 251 |
| 252 memset (glyph, 0, sizeof (*glyph)); |
| 253 glyph->codepoint = codepoint; |
| 254 glyph->mask = mask; |
| 255 glyph->cluster = cluster; |
| 256 |
| 257 buffer->len++; |
| 258 } |
| 259 |
| 260 void |
| 261 hb_buffer_clear_positions (hb_buffer_t *buffer) |
| 262 { |
| 263 _hb_buffer_clear_output (buffer); |
| 264 buffer->have_output = FALSE; |
| 265 buffer->have_positions = TRUE; |
| 266 |
| 267 if (unlikely (!buffer->pos)) |
| 268 { |
| 269 buffer->pos = (hb_glyph_position_t *) calloc (buffer->allocated, sizeof (buf
fer->pos[0])); |
| 270 return; |
| 271 } |
| 272 |
| 273 memset (buffer->pos, 0, sizeof (buffer->pos[0]) * buffer->len); |
| 274 } |
| 275 |
| 276 /* HarfBuzz-Internal API */ |
| 277 |
| 278 void |
| 279 _hb_buffer_clear_output (hb_buffer_t *buffer) |
| 280 { |
| 281 buffer->have_output = TRUE; |
| 282 buffer->have_positions = FALSE; |
| 283 buffer->out_len = 0; |
| 284 buffer->out_info = buffer->info; |
| 285 } |
| 286 |
| 287 void |
| 288 _hb_buffer_swap (hb_buffer_t *buffer) |
| 289 { |
| 290 unsigned int tmp; |
| 291 |
| 292 assert (buffer->have_output); |
| 293 |
| 294 if (unlikely (buffer->in_error)) return; |
| 295 |
| 296 if (buffer->out_info != buffer->info) |
| 297 { |
| 298 hb_glyph_info_t *tmp_string; |
| 299 tmp_string = buffer->info; |
| 300 buffer->info = buffer->out_info; |
| 301 buffer->out_info = tmp_string; |
| 302 buffer->pos = (hb_glyph_position_t *) buffer->out_info; |
| 303 } |
| 304 |
| 305 tmp = buffer->len; |
| 306 buffer->len = buffer->out_len; |
| 307 buffer->out_len = tmp; |
| 308 |
| 309 buffer->i = 0; |
| 310 } |
| 311 |
| 312 void |
| 313 _hb_buffer_replace_glyphs_be16 (hb_buffer_t *buffer, |
| 314 unsigned int num_in, |
| 315 unsigned int num_out, |
| 316 const uint16_t *glyph_data_be) |
| 317 { |
| 318 if (buffer->out_info != buffer->info || |
| 319 buffer->out_len + num_out > buffer->i + num_in) |
| 320 { |
| 321 if (unlikely (!_hb_buffer_ensure_separate (buffer, buffer->out_len + num_out
))) |
| 322 return; |
| 323 } |
| 324 |
| 325 hb_glyph_info_t orig_info = buffer->info[buffer->i]; |
| 326 |
| 327 for (unsigned int i = 0; i < num_out; i++) |
| 328 { |
| 329 hb_glyph_info_t *info = &buffer->out_info[buffer->out_len + i]; |
| 330 *info = orig_info; |
| 331 info->codepoint = hb_be_uint16 (glyph_data_be[i]); |
| 332 } |
| 333 |
| 334 buffer->i += num_in; |
| 335 buffer->out_len += num_out; |
| 336 } |
| 337 |
| 338 void |
| 339 _hb_buffer_replace_glyph (hb_buffer_t *buffer, |
| 340 hb_codepoint_t glyph_index) |
| 341 { |
| 342 hb_glyph_info_t *info; |
| 343 |
| 344 if (buffer->out_info != buffer->info) |
| 345 { |
| 346 if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return; |
| 347 buffer->out_info[buffer->out_len] = buffer->info[buffer->i]; |
| 348 } |
| 349 else if (buffer->out_len != buffer->i) |
| 350 buffer->out_info[buffer->out_len] = buffer->info[buffer->i]; |
| 351 |
| 352 info = &buffer->out_info[buffer->out_len]; |
| 353 info->codepoint = glyph_index; |
| 354 |
| 355 buffer->i++; |
| 356 buffer->out_len++; |
| 357 } |
| 358 |
| 359 void |
| 360 _hb_buffer_next_glyph (hb_buffer_t *buffer) |
| 361 { |
| 362 if (buffer->have_output) |
| 363 { |
| 364 if (buffer->out_info != buffer->info) |
| 365 { |
| 366 if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return; |
| 367 buffer->out_info[buffer->out_len] = buffer->info[buffer->i]; |
| 368 } |
| 369 else if (buffer->out_len != buffer->i) |
| 370 buffer->out_info[buffer->out_len] = buffer->info[buffer->i]; |
| 371 |
| 372 buffer->out_len++; |
| 373 } |
| 374 |
| 375 buffer->i++; |
| 376 } |
| 377 |
| 378 void |
| 379 _hb_buffer_reset_masks (hb_buffer_t *buffer, |
| 380 hb_mask_t mask) |
| 381 { |
| 382 unsigned int count = buffer->len; |
| 383 for (unsigned int i = 0; i < count; i++) |
| 384 buffer->info[i].mask = mask; |
| 385 } |
| 386 |
| 387 void |
| 388 _hb_buffer_add_masks (hb_buffer_t *buffer, |
| 389 hb_mask_t mask) |
| 390 { |
| 391 unsigned int count = buffer->len; |
| 392 for (unsigned int i = 0; i < count; i++) |
| 393 buffer->info[i].mask |= mask; |
| 394 } |
| 395 |
| 396 void |
| 397 _hb_buffer_set_masks (hb_buffer_t *buffer, |
| 398 hb_mask_t value, |
| 399 hb_mask_t mask, |
| 400 unsigned int cluster_start, |
| 401 unsigned int cluster_end) |
| 402 { |
| 403 hb_mask_t not_mask = ~mask; |
| 404 value &= mask; |
| 405 |
| 406 if (!mask) |
| 407 return; |
| 408 |
| 409 if (cluster_start == 0 && cluster_end == (unsigned int)-1) { |
| 410 unsigned int count = buffer->len; |
| 411 for (unsigned int i = 0; i < count; i++) |
| 412 buffer->info[i].mask = (buffer->info[i].mask & not_mask) | value; |
| 413 return; |
| 414 } |
| 415 |
| 416 /* XXX can't bsearch since .cluster may not be sorted. */ |
| 417 /* Binary search to find the start position and go from there. */ |
| 418 unsigned int min = 0, max = buffer->len; |
| 419 while (min < max) |
| 420 { |
| 421 unsigned int mid = min + ((max - min) / 2); |
| 422 if (buffer->info[mid].cluster < cluster_start) |
| 423 min = mid + 1; |
| 424 else |
| 425 max = mid; |
| 426 } |
| 427 unsigned int count = buffer->len; |
| 428 for (unsigned int i = min; i < count && buffer->info[i].cluster < cluster_end;
i++) |
| 429 buffer->info[i].mask = (buffer->info[i].mask & not_mask) | value; |
| 430 } |
| 431 |
| 432 |
| 433 /* Public API again */ |
| 434 |
| 435 unsigned int |
| 436 hb_buffer_get_length (hb_buffer_t *buffer) |
| 437 { |
| 438 return buffer->len; |
| 439 } |
| 440 |
| 441 /* Return value valid as long as buffer not modified */ |
| 442 hb_glyph_info_t * |
| 443 hb_buffer_get_glyph_infos (hb_buffer_t *buffer) |
| 444 { |
| 445 return (hb_glyph_info_t *) buffer->info; |
| 446 } |
| 447 |
| 448 /* Return value valid as long as buffer not modified */ |
| 449 hb_glyph_position_t * |
| 450 hb_buffer_get_glyph_positions (hb_buffer_t *buffer) |
| 451 { |
| 452 if (!buffer->have_positions) |
| 453 hb_buffer_clear_positions (buffer); |
| 454 |
| 455 return (hb_glyph_position_t *) buffer->pos; |
| 456 } |
| 457 |
| 458 |
| 459 static void |
| 460 reverse_range (hb_buffer_t *buffer, |
| 461 unsigned int start, |
| 462 unsigned int end) |
| 463 { |
| 464 unsigned int i, j; |
| 465 |
| 466 for (i = start, j = end - 1; i < j; i++, j--) { |
| 467 hb_glyph_info_t t; |
| 468 |
| 469 t = buffer->info[i]; |
| 470 buffer->info[i] = buffer->info[j]; |
| 471 buffer->info[j] = t; |
| 472 } |
| 473 |
| 474 if (buffer->pos) { |
| 475 for (i = 0, j = end - 1; i < j; i++, j--) { |
| 476 hb_glyph_position_t t; |
| 477 |
| 478 t = buffer->pos[i]; |
| 479 buffer->pos[i] = buffer->pos[j]; |
| 480 buffer->pos[j] = t; |
| 481 } |
| 482 } |
| 483 } |
| 484 |
| 485 void |
| 486 hb_buffer_reverse (hb_buffer_t *buffer) |
| 487 { |
| 488 if (unlikely (!buffer->len)) |
| 489 return; |
| 490 |
| 491 reverse_range (buffer, 0, buffer->len); |
| 492 } |
| 493 |
| 494 void |
| 495 hb_buffer_reverse_clusters (hb_buffer_t *buffer) |
| 496 { |
| 497 unsigned int i, start, count, last_cluster; |
| 498 |
| 499 if (unlikely (!buffer->len)) |
| 500 return; |
| 501 |
| 502 hb_buffer_reverse (buffer); |
| 503 |
| 504 count = buffer->len; |
| 505 start = 0; |
| 506 last_cluster = buffer->info[0].cluster; |
| 507 for (i = 1; i < count; i++) { |
| 508 if (last_cluster != buffer->info[i].cluster) { |
| 509 reverse_range (buffer, start, i); |
| 510 start = i; |
| 511 last_cluster = buffer->info[i].cluster; |
| 512 } |
| 513 } |
| 514 reverse_range (buffer, start, i); |
| 515 } |
| 516 |
| 517 |
| 518 #define ADD_UTF(T) \ |
| 519 HB_STMT_START { \ |
| 520 const T *next = (const T *) text + item_offset; \ |
| 521 const T *end = next + item_length; \ |
| 522 while (next < end) { \ |
| 523 hb_codepoint_t u; \ |
| 524 const T *old_next = next; \ |
| 525 next = UTF_NEXT (next, end, u); \ |
| 526 hb_buffer_add_glyph (buffer, u, 1, old_next - (const T *) text); \ |
| 527 } \ |
| 528 } HB_STMT_END |
| 529 |
| 530 |
| 531 #define UTF8_COMPUTE(Char, Mask, Len) \ |
| 532 if (Char < 128) { Len = 1; Mask = 0x7f; } \ |
| 533 else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \ |
| 534 else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \ |
| 535 else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \ |
| 536 else Len = 0; |
| 537 |
| 538 static inline const uint8_t * |
| 539 hb_utf8_next (const uint8_t *text, |
| 540 const uint8_t *end, |
| 541 hb_codepoint_t *unicode) |
| 542 { |
| 543 uint8_t c = *text; |
| 544 unsigned int mask, len; |
| 545 |
| 546 /* TODO check for overlong sequences? also: optimize? */ |
| 547 |
| 548 UTF8_COMPUTE (c, mask, len); |
| 549 if (unlikely (!len || (unsigned int) (end - text) < len)) { |
| 550 *unicode = -1; |
| 551 return text + 1; |
| 552 } else { |
| 553 hb_codepoint_t result; |
| 554 unsigned int i; |
| 555 result = c & mask; |
| 556 for (i = 1; i < len; i++) |
| 557 { |
| 558 if (unlikely ((text[i] & 0xc0) != 0x80)) |
| 559 { |
| 560 *unicode = -1; |
| 561 return text + 1; |
| 562 } |
| 563 result <<= 6; |
| 564 result |= (text[i] & 0x3f); |
| 565 } |
| 566 *unicode = result; |
| 567 return text + len; |
| 568 } |
| 569 } |
| 570 |
| 571 void |
| 572 hb_buffer_add_utf8 (hb_buffer_t *buffer, |
| 573 const char *text, |
| 574 unsigned int text_length HB_UNUSED, |
| 575 unsigned int item_offset, |
| 576 unsigned int item_length) |
| 577 { |
| 578 #define UTF_NEXT(S, E, U) hb_utf8_next (S, E, &(U)) |
| 579 ADD_UTF (uint8_t); |
| 580 #undef UTF_NEXT |
| 581 } |
| 582 |
| 583 static inline const uint16_t * |
| 584 hb_utf16_next (const uint16_t *text, |
| 585 const uint16_t *end, |
| 586 hb_codepoint_t *unicode) |
| 587 { |
| 588 uint16_t c = *text++; |
| 589 |
| 590 if (unlikely (c >= 0xd800 && c < 0xdc00)) { |
| 591 /* high surrogate */ |
| 592 uint16_t l; |
| 593 if (text < end && ((l = *text), unlikely (l >= 0xdc00 && l < 0xe000))) { |
| 594 /* low surrogate */ |
| 595 *unicode = ((hb_codepoint_t) ((c) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x100
00); |
| 596 text++; |
| 597 } else |
| 598 *unicode = -1; |
| 599 } else |
| 600 *unicode = c; |
| 601 |
| 602 return text; |
| 603 } |
| 604 |
| 605 void |
| 606 hb_buffer_add_utf16 (hb_buffer_t *buffer, |
| 607 const uint16_t *text, |
| 608 unsigned int text_length HB_UNUSED, |
| 609 unsigned int item_offset, |
| 610 unsigned int item_length) |
| 611 { |
| 612 #define UTF_NEXT(S, E, U) hb_utf16_next (S, E, &(U)) |
| 613 ADD_UTF (uint16_t); |
| 614 #undef UTF_NEXT |
| 615 } |
| 616 |
| 617 void |
| 618 hb_buffer_add_utf32 (hb_buffer_t *buffer, |
| 619 const uint32_t *text, |
| 620 unsigned int text_length HB_UNUSED, |
| 621 unsigned int item_offset, |
| 622 unsigned int item_length) |
| 623 { |
| 624 #define UTF_NEXT(S, E, U) ((U) = *(S), (S)+1) |
| 625 ADD_UTF (uint32_t); |
| 626 #undef UTF_NEXT |
| 627 } |
| 628 |
| 629 |
| 630 HB_END_DECLS |
OLD | NEW |