[kerx] Adjust CrossStream kern to match 'kern' table

This commit is contained in:
Behdad Esfahbod 2018-11-06 21:45:40 -05:00
parent 80a33b9ac3
commit 0123976a0c
1 changed files with 48 additions and 14 deletions

View File

@ -179,7 +179,8 @@ struct KerxSubTableFormat1
* other subtables in kerx. Discovered via testing. */ * other subtables in kerx. Discovered via testing. */
kernAction (&table->machine + table->kernAction), kernAction (&table->machine + table->kernAction),
depth (0), depth (0),
crossStream (table->header.coverage & table->header.CrossStream) {} crossStream (table->header.coverage & table->header.CrossStream),
crossOffset (0) {}
inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED, inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED,
const Entry<EntryData> *entry) const Entry<EntryData> *entry)
@ -215,40 +216,72 @@ struct KerxSubTableFormat1
} }
hb_mask_t kern_mask = c->plan->kern_mask; 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)
{ {
/* Apparently, when spec says "Each pops one glyph from the kerning stack i++;
* and applies the kerning value to it.", it doesn't mean it in that order. break;
* The deepest item in the stack corresponds to the first item in the action }
* list. Discovered by testing. */ for (; i; i--)
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 (idx < buffer->len && buffer->info[idx].mask & kern_mask)
{ {
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
{ {
if (crossStream) 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 else
{
if (!buffer->pos[idx].x_offset)
{ {
buffer->pos[idx].x_advance += c->font->em_scale_x (v); buffer->pos[idx].x_advance += c->font->em_scale_x (v);
if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
buffer->pos[idx].x_offset += c->font->em_scale_x (v); buffer->pos[idx].x_offset += c->font->em_scale_x (v);
} }
} }
}
else else
{ {
if (crossStream) 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 else
{
if (!buffer->pos[idx].y_offset)
{ {
buffer->pos[idx].y_advance += c->font->em_scale_y (v); buffer->pos[idx].y_advance += c->font->em_scale_y (v);
if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
buffer->pos[idx].y_offset += c->font->em_scale_y (v); buffer->pos[idx].y_offset += c->font->em_scale_y (v);
} }
} }
} }
} }
}
depth = 0; depth = 0;
} }
@ -261,6 +294,7 @@ struct KerxSubTableFormat1
unsigned int stack[8]; unsigned int stack[8];
unsigned int depth; unsigned int depth;
bool crossStream; bool crossStream;
int crossOffset;
}; };
inline bool apply (hb_aat_apply_context_t *c) const inline bool apply (hb_aat_apply_context_t *c) const