[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); DEFINE_SIZE_STATIC (4);
}; };
template <typename Extra> template <typename Types, typename Extra>
struct StateTable struct StateTable
{ {
typedef typename Types::HBUINT HBUINT;
typedef typename Types::HBUSHORT HBUSHORT;
typedef typename Types::ClassType ClassType;
enum State enum State
{ {
STATE_START_OF_TEXT = 0, STATE_START_OF_TEXT = 0,
@ -504,23 +508,73 @@ struct StateTable
} }
protected: 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. */ * in a single line in the state array. */
LOffsetTo<Lookup<HBUINT16>, false> OffsetTo<ClassType, HBUINT, false>
classTable; /* Offset to the class table. */ classTable; /* Offset to the class table. */
LOffsetTo<UnsizedArrayOf<HBUINT16>, false> OffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT, false>
stateArrayTable;/* Offset to the state array. */ stateArrayTable;/* Offset to the state array. */
LOffsetTo<UnsizedArrayOf<Entry<Extra> >, false> OffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT, false>
entryTable; /* Offset to the entry array. */ entryTable; /* Offset to the entry array. */
public: public:
DEFINE_SIZE_STATIC (16); 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 struct StateTableDriver
{ {
inline StateTableDriver (const StateTable<EntryData> &machine_, inline StateTableDriver (const StateTable<Types, EntryData> &machine_,
hb_buffer_t *buffer_, hb_buffer_t *buffer_,
hb_face_t *face_) : hb_face_t *face_) :
machine (machine_), machine (machine_),
@ -533,13 +587,13 @@ struct StateTableDriver
if (!c->in_place) if (!c->in_place)
buffer->clear_output (); 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; bool last_was_dont_advance = false;
for (buffer->idx = 0; buffer->successful;) for (buffer->idx = 0; buffer->successful;)
{ {
unsigned int klass = buffer->idx < buffer->len ? unsigned int klass = buffer->idx < buffer->len ?
machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) : 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); const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
if (unlikely (!entry)) if (unlikely (!entry))
break; break;
@ -553,7 +607,7 @@ struct StateTableDriver
/* If there's no action and we're just epsilon-transitioning to state 0, /* If there's no action and we're just epsilon-transitioning to state 0,
* safe to break. */ * safe to break. */
if (c->is_actionable (this, entry) || 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)) entry->flags == context_t::DontAdvance))
buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1); buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
} }
@ -590,7 +644,7 @@ struct StateTableDriver
} }
public: public:
const StateTable<EntryData> &machine; const StateTable<Types, EntryData> &machine;
hb_buffer_t *buffer; hb_buffer_t *buffer;
unsigned int num_glyphs; unsigned int num_glyphs;
}; };

View File

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

View File

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

View File

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