1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/harfbuzz/src/hb-ot-shape-fallback.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,479 @@ 1.4 +/* 1.5 + * Copyright © 2011,2012 Google, Inc. 1.6 + * 1.7 + * This is part of HarfBuzz, a text shaping library. 1.8 + * 1.9 + * Permission is hereby granted, without written agreement and without 1.10 + * license or royalty fees, to use, copy, modify, and distribute this 1.11 + * software and its documentation for any purpose, provided that the 1.12 + * above copyright notice and the following two paragraphs appear in 1.13 + * all copies of this software. 1.14 + * 1.15 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 1.16 + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 1.17 + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 1.18 + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 1.19 + * DAMAGE. 1.20 + * 1.21 + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 1.22 + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 1.23 + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 1.24 + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 1.25 + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 1.26 + * 1.27 + * Google Author(s): Behdad Esfahbod 1.28 + */ 1.29 + 1.30 +#include "hb-ot-shape-fallback-private.hh" 1.31 +#include "hb-ot-layout-gsubgpos-private.hh" 1.32 + 1.33 +static unsigned int 1.34 +recategorize_combining_class (hb_codepoint_t u, 1.35 + unsigned int klass) 1.36 +{ 1.37 + if (klass >= 200) 1.38 + return klass; 1.39 + 1.40 + /* Thai / Lao need some per-character work. */ 1.41 + if ((u & ~0xFF) == 0x0E00) 1.42 + { 1.43 + if (unlikely (klass == 0)) 1.44 + { 1.45 + switch (u) 1.46 + { 1.47 + case 0x0E31: 1.48 + case 0x0E34: 1.49 + case 0x0E35: 1.50 + case 0x0E36: 1.51 + case 0x0E37: 1.52 + case 0x0E47: 1.53 + case 0x0E4C: 1.54 + case 0x0E4D: 1.55 + case 0x0E4E: 1.56 + klass = HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT; 1.57 + break; 1.58 + 1.59 + case 0x0EB1: 1.60 + case 0x0EB4: 1.61 + case 0x0EB5: 1.62 + case 0x0EB6: 1.63 + case 0x0EB7: 1.64 + case 0x0EBB: 1.65 + case 0x0ECC: 1.66 + case 0x0ECD: 1.67 + klass = HB_UNICODE_COMBINING_CLASS_ABOVE; 1.68 + break; 1.69 + 1.70 + case 0x0EBC: 1.71 + klass = HB_UNICODE_COMBINING_CLASS_BELOW; 1.72 + break; 1.73 + } 1.74 + } else { 1.75 + /* Thai virama is below-right */ 1.76 + if (u == 0x0E3A) 1.77 + klass = HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT; 1.78 + } 1.79 + } 1.80 + 1.81 + switch (klass) 1.82 + { 1.83 + 1.84 + /* Hebrew */ 1.85 + 1.86 + case HB_MODIFIED_COMBINING_CLASS_CCC10: /* sheva */ 1.87 + case HB_MODIFIED_COMBINING_CLASS_CCC11: /* hataf segol */ 1.88 + case HB_MODIFIED_COMBINING_CLASS_CCC12: /* hataf patah */ 1.89 + case HB_MODIFIED_COMBINING_CLASS_CCC13: /* hataf qamats */ 1.90 + case HB_MODIFIED_COMBINING_CLASS_CCC14: /* hiriq */ 1.91 + case HB_MODIFIED_COMBINING_CLASS_CCC15: /* tsere */ 1.92 + case HB_MODIFIED_COMBINING_CLASS_CCC16: /* segol */ 1.93 + case HB_MODIFIED_COMBINING_CLASS_CCC17: /* patah */ 1.94 + case HB_MODIFIED_COMBINING_CLASS_CCC18: /* qamats */ 1.95 + case HB_MODIFIED_COMBINING_CLASS_CCC20: /* qubuts */ 1.96 + case HB_MODIFIED_COMBINING_CLASS_CCC22: /* meteg */ 1.97 + return HB_UNICODE_COMBINING_CLASS_BELOW; 1.98 + 1.99 + case HB_MODIFIED_COMBINING_CLASS_CCC23: /* rafe */ 1.100 + return HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE; 1.101 + 1.102 + case HB_MODIFIED_COMBINING_CLASS_CCC24: /* shin dot */ 1.103 + return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT; 1.104 + 1.105 + case HB_MODIFIED_COMBINING_CLASS_CCC25: /* sin dot */ 1.106 + case HB_MODIFIED_COMBINING_CLASS_CCC19: /* holam */ 1.107 + return HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT; 1.108 + 1.109 + case HB_MODIFIED_COMBINING_CLASS_CCC26: /* point varika */ 1.110 + return HB_UNICODE_COMBINING_CLASS_ABOVE; 1.111 + 1.112 + case HB_MODIFIED_COMBINING_CLASS_CCC21: /* dagesh */ 1.113 + break; 1.114 + 1.115 + 1.116 + /* Arabic and Syriac */ 1.117 + 1.118 + case HB_MODIFIED_COMBINING_CLASS_CCC27: /* fathatan */ 1.119 + case HB_MODIFIED_COMBINING_CLASS_CCC28: /* dammatan */ 1.120 + case HB_MODIFIED_COMBINING_CLASS_CCC30: /* fatha */ 1.121 + case HB_MODIFIED_COMBINING_CLASS_CCC31: /* damma */ 1.122 + case HB_MODIFIED_COMBINING_CLASS_CCC33: /* shadda */ 1.123 + case HB_MODIFIED_COMBINING_CLASS_CCC34: /* sukun */ 1.124 + case HB_MODIFIED_COMBINING_CLASS_CCC35: /* superscript alef */ 1.125 + case HB_MODIFIED_COMBINING_CLASS_CCC36: /* superscript alaph */ 1.126 + return HB_UNICODE_COMBINING_CLASS_ABOVE; 1.127 + 1.128 + case HB_MODIFIED_COMBINING_CLASS_CCC29: /* kasratan */ 1.129 + case HB_MODIFIED_COMBINING_CLASS_CCC32: /* kasra */ 1.130 + return HB_UNICODE_COMBINING_CLASS_BELOW; 1.131 + 1.132 + 1.133 + /* Thai */ 1.134 + 1.135 + case HB_MODIFIED_COMBINING_CLASS_CCC103: /* sara u / sara uu */ 1.136 + return HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT; 1.137 + 1.138 + case HB_MODIFIED_COMBINING_CLASS_CCC107: /* mai */ 1.139 + return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT; 1.140 + 1.141 + 1.142 + /* Lao */ 1.143 + 1.144 + case HB_MODIFIED_COMBINING_CLASS_CCC118: /* sign u / sign uu */ 1.145 + return HB_UNICODE_COMBINING_CLASS_BELOW; 1.146 + 1.147 + case HB_MODIFIED_COMBINING_CLASS_CCC122: /* mai */ 1.148 + return HB_UNICODE_COMBINING_CLASS_ABOVE; 1.149 + 1.150 + 1.151 + /* Tibetan */ 1.152 + 1.153 + case HB_MODIFIED_COMBINING_CLASS_CCC129: /* sign aa */ 1.154 + return HB_UNICODE_COMBINING_CLASS_BELOW; 1.155 + 1.156 + case HB_MODIFIED_COMBINING_CLASS_CCC130: /* sign i*/ 1.157 + return HB_UNICODE_COMBINING_CLASS_ABOVE; 1.158 + 1.159 + case HB_MODIFIED_COMBINING_CLASS_CCC132: /* sign u */ 1.160 + return HB_UNICODE_COMBINING_CLASS_BELOW; 1.161 + 1.162 + } 1.163 + 1.164 + return klass; 1.165 +} 1.166 + 1.167 +void 1.168 +_hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan HB_UNUSED, 1.169 + hb_font_t *font HB_UNUSED, 1.170 + hb_buffer_t *buffer) 1.171 +{ 1.172 + unsigned int count = buffer->len; 1.173 + for (unsigned int i = 0; i < count; i++) 1.174 + if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) { 1.175 + unsigned int combining_class = _hb_glyph_info_get_modified_combining_class (&buffer->info[i]); 1.176 + combining_class = recategorize_combining_class (buffer->info[i].codepoint, combining_class); 1.177 + _hb_glyph_info_set_modified_combining_class (&buffer->info[i], combining_class); 1.178 + } 1.179 +} 1.180 + 1.181 + 1.182 +static void 1.183 +zero_mark_advances (hb_buffer_t *buffer, 1.184 + unsigned int start, 1.185 + unsigned int end) 1.186 +{ 1.187 + for (unsigned int i = start; i < end; i++) 1.188 + if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 1.189 + { 1.190 + buffer->pos[i].x_advance = 0; 1.191 + buffer->pos[i].y_advance = 0; 1.192 + } 1.193 +} 1.194 + 1.195 +static inline void 1.196 +position_mark (const hb_ot_shape_plan_t *plan, 1.197 + hb_font_t *font, 1.198 + hb_buffer_t *buffer, 1.199 + hb_glyph_extents_t &base_extents, 1.200 + unsigned int i, 1.201 + unsigned int combining_class) 1.202 +{ 1.203 + hb_glyph_extents_t mark_extents; 1.204 + if (!font->get_glyph_extents (buffer->info[i].codepoint, 1.205 + &mark_extents)) 1.206 + return; 1.207 + 1.208 + hb_position_t y_gap = font->y_scale / 16; 1.209 + 1.210 + hb_glyph_position_t &pos = buffer->pos[i]; 1.211 + pos.x_offset = pos.y_offset = 0; 1.212 + 1.213 + 1.214 + /* We dont position LEFT and RIGHT marks. */ 1.215 + 1.216 + /* X positioning */ 1.217 + switch (combining_class) 1.218 + { 1.219 + case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW: 1.220 + case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE: 1.221 + if (buffer->props.direction == HB_DIRECTION_LTR) { 1.222 + pos.x_offset += base_extents.x_bearing - mark_extents.width / 2 - mark_extents.x_bearing; 1.223 + break; 1.224 + } else if (buffer->props.direction == HB_DIRECTION_RTL) { 1.225 + pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing; 1.226 + break; 1.227 + } 1.228 + /* Fall through */ 1.229 + 1.230 + default: 1.231 + case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW: 1.232 + case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE: 1.233 + case HB_UNICODE_COMBINING_CLASS_BELOW: 1.234 + case HB_UNICODE_COMBINING_CLASS_ABOVE: 1.235 + /* Center align. */ 1.236 + pos.x_offset += base_extents.x_bearing + (base_extents.width - mark_extents.width) / 2 - mark_extents.x_bearing; 1.237 + break; 1.238 + 1.239 + case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT: 1.240 + case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT: 1.241 + case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT: 1.242 + /* Left align. */ 1.243 + pos.x_offset += base_extents.x_bearing - mark_extents.x_bearing; 1.244 + break; 1.245 + 1.246 + case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT: 1.247 + case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT: 1.248 + case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT: 1.249 + /* Right align. */ 1.250 + pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width - mark_extents.x_bearing; 1.251 + break; 1.252 + } 1.253 + 1.254 + /* Y positioning */ 1.255 + switch (combining_class) 1.256 + { 1.257 + case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW: 1.258 + case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT: 1.259 + case HB_UNICODE_COMBINING_CLASS_BELOW: 1.260 + case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT: 1.261 + /* Add gap, fall-through. */ 1.262 + base_extents.height -= y_gap; 1.263 + 1.264 + case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT: 1.265 + case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW: 1.266 + pos.y_offset = base_extents.y_bearing + base_extents.height - mark_extents.y_bearing; 1.267 + /* Never shift up "below" marks. */ 1.268 + if ((y_gap > 0) == (pos.y_offset > 0)) 1.269 + { 1.270 + base_extents.height -= pos.y_offset; 1.271 + pos.y_offset = 0; 1.272 + } 1.273 + base_extents.height += mark_extents.height; 1.274 + break; 1.275 + 1.276 + case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE: 1.277 + case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT: 1.278 + case HB_UNICODE_COMBINING_CLASS_ABOVE: 1.279 + case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT: 1.280 + /* Add gap, fall-through. */ 1.281 + base_extents.y_bearing += y_gap; 1.282 + base_extents.height -= y_gap; 1.283 + 1.284 + case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE: 1.285 + case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT: 1.286 + pos.y_offset = base_extents.y_bearing - (mark_extents.y_bearing + mark_extents.height); 1.287 + /* Don't shift down "above" marks too much. */ 1.288 + if ((y_gap > 0) != (pos.y_offset > 0)) 1.289 + { 1.290 + unsigned int correction = -pos.y_offset / 2; 1.291 + base_extents.y_bearing += correction; 1.292 + base_extents.height -= correction; 1.293 + pos.y_offset += correction; 1.294 + } 1.295 + base_extents.y_bearing -= mark_extents.height; 1.296 + base_extents.height += mark_extents.height; 1.297 + break; 1.298 + } 1.299 +} 1.300 + 1.301 +static inline void 1.302 +position_around_base (const hb_ot_shape_plan_t *plan, 1.303 + hb_font_t *font, 1.304 + hb_buffer_t *buffer, 1.305 + unsigned int base, 1.306 + unsigned int end) 1.307 +{ 1.308 + hb_direction_t horiz_dir = HB_DIRECTION_INVALID; 1.309 + hb_glyph_extents_t base_extents; 1.310 + if (!font->get_glyph_extents (buffer->info[base].codepoint, 1.311 + &base_extents)) 1.312 + { 1.313 + /* If extents don't work, zero marks and go home. */ 1.314 + zero_mark_advances (buffer, base + 1, end); 1.315 + return; 1.316 + } 1.317 + base_extents.x_bearing += buffer->pos[base].x_offset; 1.318 + base_extents.y_bearing += buffer->pos[base].y_offset; 1.319 + 1.320 + unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[base]); 1.321 + unsigned int num_lig_components = _hb_glyph_info_get_lig_num_comps (&buffer->info[base]); 1.322 + 1.323 + hb_position_t x_offset = 0, y_offset = 0; 1.324 + if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) { 1.325 + x_offset -= buffer->pos[base].x_advance; 1.326 + y_offset -= buffer->pos[base].y_advance; 1.327 + } 1.328 + 1.329 + hb_glyph_extents_t component_extents = base_extents; 1.330 + unsigned int last_lig_component = (unsigned int) -1; 1.331 + unsigned int last_combining_class = 255; 1.332 + hb_glyph_extents_t cluster_extents = base_extents; /* Initialization is just to shut gcc up. */ 1.333 + for (unsigned int i = base + 1; i < end; i++) 1.334 + if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i])) 1.335 + { 1.336 + if (num_lig_components > 1) { 1.337 + unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[i]); 1.338 + unsigned int this_lig_component = _hb_glyph_info_get_lig_comp (&buffer->info[i]) - 1; 1.339 + /* Conditions for attaching to the last component. */ 1.340 + if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components) 1.341 + this_lig_component = num_lig_components - 1; 1.342 + if (last_lig_component != this_lig_component) 1.343 + { 1.344 + last_lig_component = this_lig_component; 1.345 + last_combining_class = 255; 1.346 + component_extents = base_extents; 1.347 + if (unlikely (horiz_dir == HB_DIRECTION_INVALID)) { 1.348 + if (HB_DIRECTION_IS_HORIZONTAL (plan->props.direction)) 1.349 + horiz_dir = plan->props.direction; 1.350 + else 1.351 + horiz_dir = hb_script_get_horizontal_direction (plan->props.script); 1.352 + } 1.353 + if (horiz_dir == HB_DIRECTION_LTR) 1.354 + component_extents.x_bearing += (this_lig_component * component_extents.width) / num_lig_components; 1.355 + else 1.356 + component_extents.x_bearing += ((num_lig_components - 1 - this_lig_component) * component_extents.width) / num_lig_components; 1.357 + component_extents.width /= num_lig_components; 1.358 + } 1.359 + } 1.360 + 1.361 + unsigned int this_combining_class = _hb_glyph_info_get_modified_combining_class (&buffer->info[i]); 1.362 + if (last_combining_class != this_combining_class) 1.363 + { 1.364 + last_combining_class = this_combining_class; 1.365 + cluster_extents = component_extents; 1.366 + } 1.367 + 1.368 + position_mark (plan, font, buffer, cluster_extents, i, this_combining_class); 1.369 + 1.370 + buffer->pos[i].x_advance = 0; 1.371 + buffer->pos[i].y_advance = 0; 1.372 + buffer->pos[i].x_offset += x_offset; 1.373 + buffer->pos[i].y_offset += y_offset; 1.374 + 1.375 + } else { 1.376 + if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) { 1.377 + x_offset -= buffer->pos[i].x_advance; 1.378 + y_offset -= buffer->pos[i].y_advance; 1.379 + } else { 1.380 + x_offset += buffer->pos[i].x_advance; 1.381 + y_offset += buffer->pos[i].y_advance; 1.382 + } 1.383 + } 1.384 +} 1.385 + 1.386 +static inline void 1.387 +position_cluster (const hb_ot_shape_plan_t *plan, 1.388 + hb_font_t *font, 1.389 + hb_buffer_t *buffer, 1.390 + unsigned int start, 1.391 + unsigned int end) 1.392 +{ 1.393 + if (end - start < 2) 1.394 + return; 1.395 + 1.396 + /* Find the base glyph */ 1.397 + for (unsigned int i = start; i < end; i++) 1.398 + if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[i]))) 1.399 + { 1.400 + /* Find mark glyphs */ 1.401 + unsigned int j; 1.402 + for (j = i + 1; j < end; j++) 1.403 + if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[j]))) 1.404 + break; 1.405 + 1.406 + position_around_base (plan, font, buffer, i, j); 1.407 + 1.408 + i = j - 1; 1.409 + } 1.410 +} 1.411 + 1.412 +void 1.413 +_hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan, 1.414 + hb_font_t *font, 1.415 + hb_buffer_t *buffer) 1.416 +{ 1.417 + unsigned int start = 0; 1.418 + unsigned int last_cluster = buffer->info[0].cluster; 1.419 + unsigned int count = buffer->len; 1.420 + for (unsigned int i = 1; i < count; i++) 1.421 + if (buffer->info[i].cluster != last_cluster) { 1.422 + position_cluster (plan, font, buffer, start, i); 1.423 + start = i; 1.424 + last_cluster = buffer->info[i].cluster; 1.425 + } 1.426 + position_cluster (plan, font, buffer, start, count); 1.427 +} 1.428 + 1.429 + 1.430 +/* Performs old-style TrueType kerning. */ 1.431 +void 1.432 +_hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, 1.433 + hb_font_t *font, 1.434 + hb_buffer_t *buffer) 1.435 +{ 1.436 + if (!plan->has_kern) return; 1.437 + 1.438 + unsigned int count = buffer->len; 1.439 + 1.440 + OT::hb_apply_context_t c (1, font, buffer); 1.441 + c.set_lookup_mask (plan->kern_mask); 1.442 + c.set_lookup_props (OT::LookupFlag::IgnoreMarks); 1.443 + 1.444 + hb_glyph_info_t *info = buffer->info; 1.445 + hb_glyph_position_t *pos = buffer->pos; 1.446 + 1.447 + for (unsigned int idx = 0; idx < count;) 1.448 + { 1.449 + OT::hb_apply_context_t::skipping_forward_iterator_t skippy_iter (&c, idx, 1); 1.450 + if (!skippy_iter.next ()) 1.451 + { 1.452 + idx++; 1.453 + continue; 1.454 + } 1.455 + 1.456 + hb_position_t x_kern, y_kern; 1.457 + font->get_glyph_kerning_for_direction (info[idx].codepoint, 1.458 + info[skippy_iter.idx].codepoint, 1.459 + buffer->props.direction, 1.460 + &x_kern, &y_kern); 1.461 + 1.462 + if (x_kern) 1.463 + { 1.464 + hb_position_t kern1 = x_kern >> 1; 1.465 + hb_position_t kern2 = x_kern - kern1; 1.466 + pos[idx].x_advance += kern1; 1.467 + pos[skippy_iter.idx].x_advance += kern2; 1.468 + pos[skippy_iter.idx].x_offset += kern2; 1.469 + } 1.470 + 1.471 + if (y_kern) 1.472 + { 1.473 + hb_position_t kern1 = y_kern >> 1; 1.474 + hb_position_t kern2 = y_kern - kern1; 1.475 + pos[idx].y_advance += kern1; 1.476 + pos[skippy_iter.idx].y_advance += kern2; 1.477 + pos[skippy_iter.idx].y_offset += kern2; 1.478 + } 1.479 + 1.480 + idx = skippy_iter.idx; 1.481 + } 1.482 +}