[mort] Bring back mort generalizations

Started by reverting https://github.com/harfbuzz/harfbuzz/commit/1f1c85a5

Just a starting point, if we agree even mort can come back.
This commit is contained in:
Ebrahim Byagowi 2018-10-30 18:41:34 +03:30 committed by Behdad Esfahbod
parent 5cd544a621
commit b053cabacd
5 changed files with 171 additions and 72 deletions

View File

@ -410,9 +410,13 @@ struct Entry<void>
DEFINE_SIZE_STATIC (4);
};
template <typename Extra>
template <typename Types, typename Extra>
struct StateTable
{
typedef typename Types::HBUINT HBUINT;
typedef typename Types::HBUSHORT HBUSHORT;
typedef typename Types::ClassType ClassType;
enum State
{
STATE_START_OF_TEXT = 0,
@ -504,23 +508,73 @@ struct StateTable
}
protected:
HBUINT32 nClasses; /* Number of classes, which is the number of indices
HBUINT nClasses; /* Number of classes, which is the number of indices
* in a single line in the state array. */
LOffsetTo<Lookup<HBUINT16>, false>
OffsetTo<ClassType, HBUINT, false>
classTable; /* Offset to the class table. */
LOffsetTo<UnsizedArrayOf<HBUINT16>, false>
OffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT, false>
stateArrayTable;/* Offset to the state array. */
LOffsetTo<UnsizedArrayOf<Entry<Extra> >, false>
OffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT, false>
entryTable; /* Offset to the entry array. */
public:
DEFINE_SIZE_STATIC (16);
};
template <typename EntryData>
struct ClassTable
{
inline unsigned int get_class (hb_codepoint_t glyph_id) const
{
return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? classArrayZ[glyph_id - firstGlyph] : 1;
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && classArrayZ.sanitize (c, glyphCount));
}
protected:
GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
* glyph minus the value of firstGlyph plus 1). */
UnsizedArrayOf<HBUINT8>
classArrayZ; /* The class codes (indexed by glyph index minus
* firstGlyph). */
public:
DEFINE_SIZE_ARRAY (4, classArrayZ);
};
struct MortTypes
{
static const bool extended = false;
typedef HBUINT16 HBUINT;
typedef HBUINT8 HBUSHORT;
struct ClassType : ClassTable
{
inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs HB_UNUSED) const
{
return ClassTable::get_class (glyph_id);
}
};
};
struct MorxTypes
{
static const bool extended = true;
typedef HBUINT32 HBUINT;
typedef HBUINT16 HBUSHORT;
struct ClassType : Lookup<HBUINT16>
{
inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
const HBUINT16 *v = get_value (glyph_id, num_glyphs);
return v ? *v : 1;
}
};
};
template <typename Types, typename EntryData>
struct StateTableDriver
{
inline StateTableDriver (const StateTable<EntryData> &machine_,
inline StateTableDriver (const StateTable<Types, EntryData> &machine_,
hb_buffer_t *buffer_,
hb_face_t *face_) :
machine (machine_),
@ -533,13 +587,13 @@ struct StateTableDriver
if (!c->in_place)
buffer->clear_output ();
unsigned int state = StateTable<EntryData>::STATE_START_OF_TEXT;
unsigned int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
bool last_was_dont_advance = false;
for (buffer->idx = 0; buffer->successful;)
{
unsigned int klass = buffer->idx < buffer->len ?
machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
(unsigned) StateTable<EntryData>::CLASS_END_OF_TEXT;
(unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
if (unlikely (!entry))
break;
@ -553,7 +607,7 @@ struct StateTableDriver
/* If there's no action and we're just epsilon-transitioning to state 0,
* safe to break. */
if (c->is_actionable (this, entry) ||
!(entry->newState == StateTable<EntryData>::STATE_START_OF_TEXT &&
!(entry->newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
entry->flags == context_t::DontAdvance))
buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
}
@ -590,7 +644,7 @@ struct StateTableDriver
}
public:
const StateTable<EntryData> &machine;
const StateTable<Types, EntryData> &machine;
hb_buffer_t *buffer;
unsigned int num_glyphs;
};

View File

@ -163,12 +163,12 @@ struct KerxSubTableFormat1
kernAction (&table->machine + table->kernAction),
depth (0) {}
inline bool is_actionable (StateTableDriver<EntryData> *driver HB_UNUSED,
inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED,
const Entry<EntryData> *entry)
{
return entry->data.kernActionIndex != 0xFFFF;
}
inline bool transition (StateTableDriver<EntryData> *driver,
inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
const Entry<EntryData> *entry)
{
hb_buffer_t *buffer = driver->buffer;
@ -239,7 +239,7 @@ struct KerxSubTableFormat1
driver_context_t dc (this, c);
StateTableDriver<EntryData> driver (machine, c->buffer, c->font->face);
StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->font->face);
driver.drive (&dc);
return_trace (true);
@ -255,7 +255,7 @@ struct KerxSubTableFormat1
protected:
KerxSubTableHeader header;
StateTable<EntryData> machine;
StateTable<MorxTypes, EntryData> machine;
LOffsetTo<UnsizedArrayOf<FWORD>, false> kernAction;
public:
DEFINE_SIZE_STATIC (32);
@ -365,12 +365,12 @@ struct KerxSubTableFormat4
mark_set (false),
mark (0) {}
inline bool is_actionable (StateTableDriver<EntryData> *driver HB_UNUSED,
inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED,
const Entry<EntryData> *entry)
{
return entry->data.ankrActionIndex != 0xFFFF;
}
inline bool transition (StateTableDriver<EntryData> *driver,
inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
const Entry<EntryData> *entry)
{
hb_buffer_t *buffer = driver->buffer;
@ -473,7 +473,7 @@ struct KerxSubTableFormat4
driver_context_t dc (this, c);
StateTableDriver<EntryData> driver (machine, c->buffer, c->font->face);
StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->font->face);
driver.drive (&dc);
return_trace (true);
@ -489,7 +489,8 @@ struct KerxSubTableFormat4
protected:
KerxSubTableHeader header;
StateTable<EntryData> machine;
StateTable<MorxTypes, EntryData>
machine;
HBUINT32 flags;
public:
DEFINE_SIZE_STATIC (32);

View File

@ -35,17 +35,21 @@
/*
* morx -- Extended Glyph Metamorphosis
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html
*/
#define HB_AAT_TAG_morx HB_TAG('m','o','r','x')
#define HB_AAT_TAG_mort HB_TAG('m','o','r','t')
namespace AAT {
using namespace OT;
template <typename Types>
struct RearrangementSubtable
{
typedef typename Types::HBUINT HBUINT;
typedef void EntryData;
struct driver_context_t
@ -69,12 +73,12 @@ struct RearrangementSubtable
ret (false),
start (0), end (0) {}
inline bool is_actionable (StateTableDriver<EntryData> *driver HB_UNUSED,
inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED,
const Entry<EntryData> *entry)
{
return (entry->flags & Verb) && start < end;
}
inline bool transition (StateTableDriver<EntryData> *driver,
inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
const Entry<EntryData> *entry)
{
hb_buffer_t *buffer = driver->buffer;
@ -165,7 +169,7 @@ struct RearrangementSubtable
driver_context_t dc (this);
StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->face);
driver.drive (&dc);
return_trace (dc.ret);
@ -178,13 +182,16 @@ struct RearrangementSubtable
}
protected:
StateTable<EntryData> machine;
StateTable<Types, EntryData> machine;
public:
DEFINE_SIZE_STATIC (16);
};
template <typename Types>
struct ContextualSubtable
{
typedef typename Types::HBUINT HBUINT;
struct EntryData
{
HBUINT16 markIndex; /* Index of the substitution table for the
@ -212,7 +219,7 @@ struct ContextualSubtable
mark (0),
subs (table+table->substitutionTables) {}
inline bool is_actionable (StateTableDriver<EntryData> *driver,
inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver,
const Entry<EntryData> *entry)
{
hb_buffer_t *buffer = driver->buffer;
@ -222,7 +229,7 @@ struct ContextualSubtable
return entry->data.markIndex != 0xFFFF || entry->data.currentIndex != 0xFFFF;
}
inline bool transition (StateTableDriver<EntryData> *driver,
inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
const Entry<EntryData> *entry)
{
hb_buffer_t *buffer = driver->buffer;
@ -280,7 +287,7 @@ struct ContextualSubtable
driver_context_t dc (this);
StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->face);
driver.drive (&dc);
return_trace (dc.ret);
@ -310,16 +317,19 @@ struct ContextualSubtable
}
protected:
StateTable<EntryData>
StateTable<Types, EntryData>
machine;
LOffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32, false>, false>
OffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false>, HBUINT, false>
substitutionTables;
public:
DEFINE_SIZE_STATIC (20);
};
template <typename Types>
struct LigatureSubtable
{
typedef typename Types::HBUINT HBUINT;
struct EntryData
{
HBUINT16 ligActionIndex; /* Index to the first ligActionTable entry
@ -363,12 +373,12 @@ struct LigatureSubtable
ligature (table+table->ligature),
match_length (0) {}
inline bool is_actionable (StateTableDriver<EntryData> *driver HB_UNUSED,
inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED,
const Entry<EntryData> *entry)
{
return entry->flags & PerformAction;
}
inline bool transition (StateTableDriver<EntryData> *driver,
inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
const Entry<EntryData> *entry)
{
hb_buffer_t *buffer = driver->buffer;
@ -482,7 +492,7 @@ struct LigatureSubtable
driver_context_t dc (this, c);
StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->face);
driver.drive (&dc);
return_trace (dc.ret);
@ -497,18 +507,19 @@ struct LigatureSubtable
}
protected:
StateTable<EntryData>
StateTable<Types, EntryData>
machine;
LOffsetTo<UnsizedArrayOf<HBUINT32>, false>
OffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT, false>
ligAction; /* Offset to the ligature action table. */
LOffsetTo<UnsizedArrayOf<HBUINT16>, false>
OffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT, false>
component; /* Offset to the component table. */
LOffsetTo<UnsizedArrayOf<GlyphID>, false>
OffsetTo<UnsizedArrayOf<GlyphID>, HBUINT, false>
ligature; /* Offset to the actual ligature lists. */
public:
DEFINE_SIZE_STATIC (28);
};
template <typename Types>
struct NoncontextualSubtable
{
inline bool apply (hb_aat_apply_context_t *c) const
@ -545,8 +556,11 @@ struct NoncontextualSubtable
DEFINE_SIZE_MIN (2);
};
template <typename Types>
struct InsertionSubtable
{
typedef typename Types::HBUINT HBUINT;
struct EntryData
{
HBUINT16 currentInsertIndex; /* Zero-based index into the insertion glyph table.
@ -622,13 +636,13 @@ struct InsertionSubtable
mark (0),
insertionAction (table+table->insertionAction) {}
inline bool is_actionable (StateTableDriver<EntryData> *driver HB_UNUSED,
inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED,
const Entry<EntryData> *entry)
{
return (entry->flags & (CurrentInsertCount | MarkedInsertCount)) &&
(entry->data.currentInsertIndex != 0xFFFF ||entry->data.markedInsertIndex != 0xFFFF);
}
inline bool transition (StateTableDriver<EntryData> *driver,
inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver,
const Entry<EntryData> *entry)
{
hb_buffer_t *buffer = driver->buffer;
@ -720,7 +734,7 @@ struct InsertionSubtable
driver_context_t dc (this, c);
StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->face);
driver.drive (&dc);
return_trace (dc.ret);
@ -735,9 +749,9 @@ struct InsertionSubtable
}
protected:
StateTable<EntryData>
StateTable<Types, EntryData>
machine;
LOffsetTo<UnsizedArrayOf<GlyphID>, false>
OffsetTo<UnsizedArrayOf<GlyphID>, HBUINT, false>
insertionAction; /* Byte offset from stateHeader to the start of
* the insertion glyph table. */
public:
@ -765,9 +779,10 @@ struct Feature
DEFINE_SIZE_STATIC (12);
};
template <typename Types>
struct ChainSubtable
{
template <typename T>
friend struct Chain;
inline unsigned int get_size (void) const { return length; }
@ -830,18 +845,21 @@ struct ChainSubtable
HBUINT32 coverage; /* Coverage flags and subtable type. */
HBUINT32 subFeatureFlags;/* The 32-bit mask identifying which subtable this is. */
union {
RearrangementSubtable rearrangement;
ContextualSubtable contextual;
LigatureSubtable ligature;
NoncontextualSubtable noncontextual;
InsertionSubtable insertion;
RearrangementSubtable<Types> rearrangement;
ContextualSubtable<Types> contextual;
LigatureSubtable<Types> ligature;
NoncontextualSubtable<Types> noncontextual;
InsertionSubtable<Types> insertion;
} u;
public:
DEFINE_SIZE_MIN (12);
DEFINE_SIZE_MIN (2 * sizeof (HBUINT32) + 4);
};
template <typename Types>
struct Chain
{
typedef typename Types::HBUINT HBUINT;
inline hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const
{
hb_mask_t flags = defaultFlags;
@ -868,7 +886,7 @@ struct Chain
inline void apply (hb_aat_apply_context_t *c,
hb_mask_t flags) const
{
const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (&featureZ, featureZ[0].static_size * featureCount);
const ChainSubtable<Types> *subtable = &StructAtOffset<ChainSubtable<Types> > (&featureZ, featureZ[0].static_size * featureCount);
unsigned int count = subtableCount;
for (unsigned int i = 0; i < count; i++)
{
@ -877,9 +895,9 @@ struct Chain
if (!(subtable->subFeatureFlags & flags))
goto skip;
if (!(subtable->coverage & ChainSubtable::AllDirections) &&
if (!(subtable->coverage & ChainSubtable<Types>::AllDirections) &&
HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
bool (subtable->coverage & ChainSubtable::Vertical))
bool (subtable->coverage & ChainSubtable<Types>::Vertical))
goto skip;
/* Buffer contents is always in logical direction. Determine if
@ -909,9 +927,9 @@ struct Chain
(the order opposite that of the characters, which
may be right-to-left or left-to-right).
*/
reverse = subtable->coverage & ChainSubtable::Logical ?
bool (subtable->coverage & ChainSubtable::Backwards) :
bool (subtable->coverage & ChainSubtable::Backwards) !=
reverse = subtable->coverage & ChainSubtable<Types>::Logical ?
bool (subtable->coverage & ChainSubtable<Types>::Backwards) :
bool (subtable->coverage & ChainSubtable<Types>::Backwards) !=
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index))
@ -932,7 +950,7 @@ struct Chain
if (unlikely (!c->buffer->successful)) return;
skip:
subtable = &StructAfter<ChainSubtable> (*subtable);
subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
c->set_lookup_index (c->lookup_index + 1);
}
}
@ -950,38 +968,39 @@ struct Chain
if (!c->check_array (featureZ.arrayZ, featureCount))
return_trace (false);
const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (&featureZ, featureZ[0].static_size * featureCount);
const ChainSubtable<Types> *subtable = &StructAtOffset<ChainSubtable<Types> > (&featureZ, featureZ[0].static_size * featureCount);
unsigned int count = subtableCount;
for (unsigned int i = 0; i < count; i++)
{
if (!subtable->sanitize (c))
return_trace (false);
subtable = &StructAfter<ChainSubtable> (*subtable);
subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
}
return_trace (true);
}
protected:
HBUINT32 defaultFlags; /* The default specification for subtables. */
HBUINT32 length; /* Total byte count, including this header. */
HBUINT32 featureCount; /* Number of feature subtable entries. */
HBUINT32 subtableCount; /* The number of subtables in the chain. */
HBUINT defaultFlags; /* The default specification for subtables. */
HBUINT length; /* Total byte count, including this header. */
HBUINT featureCount; /* Number of feature subtable entries. */
HBUINT subtableCount; /* The number of subtables in the chain. */
UnsizedArrayOf<Feature> featureZ; /* Features. */
/*ChainSubtable firstSubtable;*//* Subtables. */
/*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */
public:
DEFINE_SIZE_MIN (16);
DEFINE_SIZE_MIN (2 * sizeof (HBUINT) + 4);
};
/*
* The 'morx' Table
* The 'mort'/'morx' Table
*/
struct morx
template <typename Types>
struct mortmorx
{
static const hb_tag_t tableTag = HB_AAT_TAG_morx;
@ -990,12 +1009,12 @@ struct morx
inline void compile_flags (const hb_aat_map_builder_t *mapper,
hb_aat_map_t *map) const
{
const Chain *chain = &firstChain;
const Chain<Types> *chain = &firstChain;
unsigned int count = chainCount;
for (unsigned int i = 0; i < count; i++)
{
map->chain_flags.push (chain->compile_flags (mapper));
chain = &StructAfter<Chain> (*chain);
chain = &StructAfter<Chain<Types> > (*chain);
}
}
@ -1019,13 +1038,13 @@ struct morx
{
if (unlikely (!c->buffer->successful)) return;
c->set_lookup_index (0);
const Chain *chain = &firstChain;
const Chain<Types> *chain = &firstChain;
unsigned int count = chainCount;
for (unsigned int i = 0; i < count; i++)
{
chain->apply (c, c->plan->aat_map.chain_flags[i]);
if (unlikely (!c->buffer->successful)) return;
chain = &StructAfter<Chain> (*chain);
chain = &StructAfter<Chain<Types> > (*chain);
}
remove_deleted_glyphs (c->buffer);
}
@ -1037,13 +1056,13 @@ struct morx
!chainCount.sanitize (c))
return_trace (false);
const Chain *chain = &firstChain;
const Chain<Types> *chain = &firstChain;
unsigned int count = chainCount;
for (unsigned int i = 0; i < count; i++)
{
if (!chain->sanitize (c, version))
return_trace (false);
chain = &StructAfter<Chain> (*chain);
chain = &StructAfter<Chain<Types> > (*chain);
}
return_trace (true);
@ -1055,12 +1074,22 @@ struct morx
HBUINT16 unused; /* Set to 0. */
HBUINT32 chainCount; /* Number of metamorphosis chains contained in this
* table. */
Chain firstChain; /* Chains. */
Chain<Types> firstChain; /* Chains. */
public:
DEFINE_SIZE_MIN (8);
};
struct morx : mortmorx<MorxTypes>
{
static const hb_tag_t tableTag = HB_AAT_TAG_morx;
};
struct mort : mortmorx<MortTypes>
{
static const hb_tag_t tableTag = HB_AAT_TAG_mort;
};
} /* namespace AAT */

View File

@ -130,9 +130,23 @@ hb_aat_layout_find_feature_mapping (hb_tag_t tag)
/*
* morx/kerx/trak
* mort/morx/kerx/trak
*/
// static inline const AAT::mort&
// _get_mort (hb_face_t *face, hb_blob_t **blob = nullptr)
// {
// if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
// {
// if (blob)
// *blob = hb_blob_get_empty ();
// return Null(AAT::mort);
// }
// const AAT::morx& mort = *(hb_ot_face_data (face)->mort.get ());
// if (blob)
// *blob = hb_ot_face_data (face)->mort.get_blob ();
// return mort;
// }
static inline const AAT::morx&
_get_morx (hb_face_t *face, hb_blob_t **blob = nullptr)
{

View File

@ -52,6 +52,7 @@
HB_OT_TABLE(OT, BASE) \
/* AAT shaping. */ \
HB_OT_TABLE(AAT, morx) \
HB_OT_TABLE(AAT, mort) \
HB_OT_TABLE(AAT, kerx) \
HB_OT_TABLE(AAT, ankr) \
HB_OT_TABLE(AAT, trak) \