diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh index 550abf31b..93d3ffb7f 100644 --- a/src/hb-aat-layout-kerx-table.hh +++ b/src/hb-aat-layout-kerx-table.hh @@ -179,7 +179,8 @@ struct KerxSubTableFormat1 * other subtables in kerx. Discovered via testing. */ kernAction (&table->machine + table->kernAction), depth (0), - crossStream (table->header.coverage & table->header.CrossStream) {} + crossStream (table->header.coverage & table->header.CrossStream), + crossOffset (0) {} inline bool is_actionable (StateTableDriver *driver HB_UNUSED, const Entry *entry) @@ -215,36 +216,68 @@ struct KerxSubTableFormat1 } hb_mask_t kern_mask = c->plan->kern_mask; - for (unsigned int i = 0; i < depth; i++) + + /* From Apple 'kern' spec: + * "Each pops one glyph from the kerning stack and applies the kerning value to it. + * The end of the list is marked by an odd value... */ + unsigned int i; + for (i = 0; i < depth; i++) + if (actions[i] & 1) + { + i++; + break; + } + for (; i; i--) { - /* Apparently, when spec says "Each pops one glyph from the kerning stack - * and applies the kerning value to it.", it doesn't mean it in that order. - * The deepest item in the stack corresponds to the first item in the action - * list. Discovered by testing. */ - unsigned int idx = stack[i]; - int v = *actions++; + unsigned int idx = stack[depth - i]; + int v = actions[i - 1]; + + /* "The end of the list is marked by an odd value..." + * Ignore it. */ + v &= ~1; + + /* The following flag is undocumented in the spec, but described + * in the 'kern' table example. */ + if (v == 0x8000) + { + crossOffset = 0; + v = 0; + } if (idx < buffer->len && buffer->info[idx].mask & kern_mask) { if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) { if (crossStream) - buffer->pos[idx].y_offset += c->font->em_scale_y (v); + { + crossOffset += v; + if (!buffer->pos[idx].y_offset) + buffer->pos[idx].y_offset += c->font->em_scale_y (crossOffset); + } else { - buffer->pos[idx].x_advance += c->font->em_scale_x (v); - if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) + if (!buffer->pos[idx].x_offset) + { + buffer->pos[idx].x_advance += c->font->em_scale_x (v); buffer->pos[idx].x_offset += c->font->em_scale_x (v); + } } } else { if (crossStream) - buffer->pos[idx].x_offset += c->font->em_scale_x (v); + { + /* CoreText doesn't do crossStream kerning in vertical. */ + //crossOffset += v; + //if (!buffer->pos[idx].x_offset) + // buffer->pos[idx].x_offset = c->font->em_scale_x (crossOffset); + } else { - buffer->pos[idx].y_advance += c->font->em_scale_y (v); - if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) + if (!buffer->pos[idx].y_offset) + { + buffer->pos[idx].y_advance += c->font->em_scale_y (v); buffer->pos[idx].y_offset += c->font->em_scale_y (v); + } } } } @@ -261,6 +294,7 @@ struct KerxSubTableFormat1 unsigned int stack[8]; unsigned int depth; bool crossStream; + int crossOffset; }; inline bool apply (hb_aat_apply_context_t *c) const