[kern] Implement CrossStream kerning
This commit is contained in:
parent
b11830c09e
commit
01bf43ac01
|
@ -62,6 +62,20 @@ kerxTupleKern (int value,
|
||||||
|
|
||||||
struct KerxSubTableHeader
|
struct KerxSubTableHeader
|
||||||
{
|
{
|
||||||
|
enum Coverage
|
||||||
|
{
|
||||||
|
Vertical = 0x80000000, /* Set if table has vertical kerning values. */
|
||||||
|
CrossStream = 0x40000000, /* Set if table has cross-stream kerning values. */
|
||||||
|
Variation = 0x20000000, /* Set if table has variation kerning values. */
|
||||||
|
Backwards = 0x10000000, /* If clear, process the glyphs forwards, that
|
||||||
|
* is, from first to last in the glyph stream.
|
||||||
|
* If we, process them from last to first.
|
||||||
|
* This flag only applies to state-table based
|
||||||
|
* 'kerx' subtables (types 1 and 4). */
|
||||||
|
Reserved = 0x0FFFFF00, /* Reserved, set to zero. */
|
||||||
|
SubtableType = 0x000000FF, /* Subtable type. */
|
||||||
|
};
|
||||||
|
|
||||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
|
@ -95,6 +109,9 @@ struct KerxSubTableFormat0
|
||||||
if (!c->plan->requested_kerning)
|
if (!c->plan->requested_kerning)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (header.coverage & header.CrossStream)
|
||||||
|
return false;
|
||||||
|
|
||||||
accelerator_t accel (*this, c);
|
accelerator_t accel (*this, c);
|
||||||
hb_kern_machine_t<accelerator_t> machine (accel);
|
hb_kern_machine_t<accelerator_t> machine (accel);
|
||||||
machine.kern (c->font, c->buffer, c->plan->kern_mask);
|
machine.kern (c->font, c->buffer, c->plan->kern_mask);
|
||||||
|
@ -161,7 +178,8 @@ struct KerxSubTableFormat1
|
||||||
* similar to offsets in morx table, NOT from beginning of this table, like
|
* similar to offsets in morx table, NOT from beginning of this table, like
|
||||||
* 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) {}
|
||||||
|
|
||||||
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)
|
||||||
|
@ -209,15 +227,25 @@ struct KerxSubTableFormat1
|
||||||
{
|
{
|
||||||
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
|
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
|
||||||
{
|
{
|
||||||
buffer->pos[idx].x_advance += c->font->em_scale_x (v);
|
if (crossStream)
|
||||||
if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
|
buffer->pos[idx].y_offset += c->font->em_scale_y (v);
|
||||||
buffer->pos[idx].x_offset += c->font->em_scale_x (v);
|
else
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer->pos[idx].y_advance += c->font->em_scale_y (v);
|
if (crossStream)
|
||||||
if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
|
buffer->pos[idx].x_offset += c->font->em_scale_x (v);
|
||||||
buffer->pos[idx].y_offset += c->font->em_scale_y (v);
|
else
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,6 +260,7 @@ struct KerxSubTableFormat1
|
||||||
const UnsizedArrayOf<FWORD> &kernAction;
|
const UnsizedArrayOf<FWORD> &kernAction;
|
||||||
unsigned int stack[8];
|
unsigned int stack[8];
|
||||||
unsigned int depth;
|
unsigned int depth;
|
||||||
|
bool crossStream;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool apply (hb_aat_apply_context_t *c) const
|
inline bool apply (hb_aat_apply_context_t *c) const
|
||||||
|
@ -241,6 +270,9 @@ struct KerxSubTableFormat1
|
||||||
if (!c->plan->requested_kerning)
|
if (!c->plan->requested_kerning)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (header.coverage & header.CrossStream)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (header.tupleCount)
|
if (header.tupleCount)
|
||||||
return_trace (false); /* TODO kerxTupleKern */
|
return_trace (false); /* TODO kerxTupleKern */
|
||||||
|
|
||||||
|
@ -289,6 +321,9 @@ struct KerxSubTableFormat2
|
||||||
if (!c->plan->requested_kerning)
|
if (!c->plan->requested_kerning)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (header.coverage & header.CrossStream)
|
||||||
|
return false;
|
||||||
|
|
||||||
accelerator_t accel (*this, c);
|
accelerator_t accel (*this, c);
|
||||||
hb_kern_machine_t<accelerator_t> machine (accel);
|
hb_kern_machine_t<accelerator_t> machine (accel);
|
||||||
machine.kern (c->font, c->buffer, c->plan->kern_mask);
|
machine.kern (c->font, c->buffer, c->plan->kern_mask);
|
||||||
|
@ -547,6 +582,9 @@ struct KerxSubTableFormat6
|
||||||
if (!c->plan->requested_kerning)
|
if (!c->plan->requested_kerning)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (header.coverage & header.CrossStream)
|
||||||
|
return false;
|
||||||
|
|
||||||
accelerator_t accel (*this, c);
|
accelerator_t accel (*this, c);
|
||||||
hb_kern_machine_t<accelerator_t> machine (accel);
|
hb_kern_machine_t<accelerator_t> machine (accel);
|
||||||
machine.kern (c->font, c->buffer, c->plan->kern_mask);
|
machine.kern (c->font, c->buffer, c->plan->kern_mask);
|
||||||
|
@ -615,21 +653,7 @@ struct KerxTable
|
||||||
friend struct kerx;
|
friend struct kerx;
|
||||||
|
|
||||||
inline unsigned int get_size (void) const { return u.header.length; }
|
inline unsigned int get_size (void) const { return u.header.length; }
|
||||||
inline unsigned int get_type (void) const { return u.header.coverage & SubtableType; }
|
inline unsigned int get_type (void) const { return u.header.coverage & u.header.SubtableType; }
|
||||||
|
|
||||||
enum Coverage
|
|
||||||
{
|
|
||||||
Vertical = 0x80000000, /* Set if table has vertical kerning values. */
|
|
||||||
CrossStream = 0x40000000, /* Set if table has cross-stream kerning values. */
|
|
||||||
Variation = 0x20000000, /* Set if table has variation kerning values. */
|
|
||||||
Backwards = 0x10000000, /* If clear, process the glyphs forwards, that
|
|
||||||
* is, from first to last in the glyph stream.
|
|
||||||
* If we, process them from last to first.
|
|
||||||
* This flag only applies to state-table based
|
|
||||||
* 'kerx' subtables (types 1 and 4). */
|
|
||||||
Reserved = 0x0FFFFF00, /* Reserved, set to zero. */
|
|
||||||
SubtableType = 0x000000FF, /* Subtable type. */
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename context_t>
|
template <typename context_t>
|
||||||
inline typename context_t::return_t dispatch (context_t *c) const
|
inline typename context_t::return_t dispatch (context_t *c) const
|
||||||
|
@ -689,14 +713,11 @@ struct kerx
|
||||||
{
|
{
|
||||||
bool reverse;
|
bool reverse;
|
||||||
|
|
||||||
if (table->u.header.coverage & (KerxTable::CrossStream))
|
|
||||||
goto skip; /* We do NOT handle cross-stream. */
|
|
||||||
|
|
||||||
if (HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
|
if (HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
|
||||||
bool (table->u.header.coverage & KerxTable::Vertical))
|
bool (table->u.header.coverage & table->u.header.Vertical))
|
||||||
goto skip;
|
goto skip;
|
||||||
|
|
||||||
reverse = bool (table->u.header.coverage & KerxTable::Backwards) !=
|
reverse = bool (table->u.header.coverage & table->u.header.Backwards) !=
|
||||||
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
|
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
|
||||||
|
|
||||||
if (!c->buffer->message (c->font, "start kerx subtable %d", c->lookup_index))
|
if (!c->buffer->message (c->font, "start kerx subtable %d", c->lookup_index))
|
||||||
|
|
|
@ -174,6 +174,9 @@ struct KernSubTableFormat0
|
||||||
if (!c->plan->requested_kerning)
|
if (!c->plan->requested_kerning)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (header.coverage & header.CrossStream)
|
||||||
|
return false;
|
||||||
|
|
||||||
hb_kern_machine_t<KernSubTableFormat0> machine (*this);
|
hb_kern_machine_t<KernSubTableFormat0> machine (*this);
|
||||||
machine.kern (c->font, c->buffer, c->plan->kern_mask);
|
machine.kern (c->font, c->buffer, c->plan->kern_mask);
|
||||||
|
|
||||||
|
@ -218,7 +221,9 @@ struct KernSubTableFormat1
|
||||||
* similar to offsets in morx table, NOT from beginning of this table, like
|
* similar to offsets in morx table, NOT from beginning of this table, like
|
||||||
* 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),
|
||||||
|
crossOffset (0) {}
|
||||||
|
|
||||||
inline bool is_actionable (AAT::StateTableDriver<AAT::MortTypes, EntryData> *driver HB_UNUSED,
|
inline bool is_actionable (AAT::StateTableDriver<AAT::MortTypes, EntryData> *driver HB_UNUSED,
|
||||||
const AAT::Entry<EntryData> *entry)
|
const AAT::Entry<EntryData> *entry)
|
||||||
|
@ -241,7 +246,9 @@ struct KernSubTableFormat1
|
||||||
|
|
||||||
if (entry->flags & Offset)
|
if (entry->flags & Offset)
|
||||||
{
|
{
|
||||||
unsigned int kernIndex = AAT::MortTypes::offsetToIndex (entry->flags & Offset, &table->machine, kernAction.arrayZ);
|
unsigned int kernIndex = AAT::MortTypes::offsetToIndex (entry->flags & Offset,
|
||||||
|
&table->machine,
|
||||||
|
kernAction.arrayZ);
|
||||||
const FWORD *actions = &kernAction[kernIndex];
|
const FWORD *actions = &kernAction[kernIndex];
|
||||||
if (!c->sanitizer.check_array (actions, depth))
|
if (!c->sanitizer.check_array (actions, depth))
|
||||||
{
|
{
|
||||||
|
@ -258,21 +265,50 @@ struct KernSubTableFormat1
|
||||||
* list. Discovered by testing. */
|
* list. Discovered by testing. */
|
||||||
unsigned int idx = stack[i];
|
unsigned int idx = stack[i];
|
||||||
int v = *actions++;
|
int v = *actions++;
|
||||||
|
|
||||||
|
/* The following two flags are undocumented in the spec, but described
|
||||||
|
* in the example. */
|
||||||
|
bool last = v & 1;
|
||||||
|
v = v & ~1;
|
||||||
|
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))
|
||||||
{
|
{
|
||||||
buffer->pos[idx].x_advance += c->font->em_scale_x (v);
|
if (crossStream)
|
||||||
if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
|
{
|
||||||
buffer->pos[idx].x_offset += c->font->em_scale_x (v);
|
crossOffset += v;
|
||||||
|
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))
|
||||||
|
buffer->pos[idx].x_offset += c->font->em_scale_x (v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer->pos[idx].y_advance += c->font->em_scale_y (v);
|
if (crossStream)
|
||||||
if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
|
{
|
||||||
buffer->pos[idx].y_offset += c->font->em_scale_y (v);
|
crossOffset += v;
|
||||||
|
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))
|
||||||
|
buffer->pos[idx].y_offset += c->font->em_scale_y (v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (last)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
depth = 0;
|
depth = 0;
|
||||||
}
|
}
|
||||||
|
@ -286,6 +322,8 @@ struct KernSubTableFormat1
|
||||||
const UnsizedArrayOf<FWORD> &kernAction;
|
const UnsizedArrayOf<FWORD> &kernAction;
|
||||||
unsigned int stack[8];
|
unsigned int stack[8];
|
||||||
unsigned int depth;
|
unsigned int depth;
|
||||||
|
bool crossStream;
|
||||||
|
int crossOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool apply (AAT::hb_aat_apply_context_t *c) const
|
inline bool apply (AAT::hb_aat_apply_context_t *c) const
|
||||||
|
@ -344,6 +382,9 @@ struct KernSubTableFormat2
|
||||||
if (!c->plan->requested_kerning)
|
if (!c->plan->requested_kerning)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (header.coverage & header.CrossStream)
|
||||||
|
return false;
|
||||||
|
|
||||||
accelerator_t accel (*this, c);
|
accelerator_t accel (*this, c);
|
||||||
hb_kern_machine_t<accelerator_t> machine (accel);
|
hb_kern_machine_t<accelerator_t> machine (accel);
|
||||||
machine.kern (c->font, c->buffer, c->plan->kern_mask);
|
machine.kern (c->font, c->buffer, c->plan->kern_mask);
|
||||||
|
@ -412,6 +453,9 @@ struct KernSubTableFormat3
|
||||||
if (!c->plan->requested_kerning)
|
if (!c->plan->requested_kerning)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (header.coverage & header.CrossStream)
|
||||||
|
return false;
|
||||||
|
|
||||||
hb_kern_machine_t<KernSubTableFormat3> machine (*this);
|
hb_kern_machine_t<KernSubTableFormat3> machine (*this);
|
||||||
machine.kern (c->font, c->buffer, c->plan->kern_mask);
|
machine.kern (c->font, c->buffer, c->plan->kern_mask);
|
||||||
|
|
||||||
|
@ -547,8 +591,7 @@ struct KernTable
|
||||||
st = CastP<SubTable> (&thiz()->dataZ);
|
st = CastP<SubTable> (&thiz()->dataZ);
|
||||||
for (unsigned int i = 0; i < count; i++)
|
for (unsigned int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
if (st->u.header.coverage &
|
if (st->u.header.coverage & st->u.header.Variation)
|
||||||
(st->u.header.Variation | st->u.header.CrossStream))
|
|
||||||
goto skip;
|
goto skip;
|
||||||
|
|
||||||
if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) !=
|
if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) !=
|
||||||
|
|
Loading…
Reference in New Issue