|
@@ -74,15 +74,16 @@ struct RearrangementSubtable
|
|
|
ret (false),
|
|
|
start (0), end (0) {}
|
|
|
|
|
|
- bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
|
|
- const Entry<EntryData> &entry)
|
|
|
+ bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
|
|
|
+ StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
|
|
+ const Entry<EntryData> &entry) const
|
|
|
{
|
|
|
return (entry.flags & Verb) && start < end;
|
|
|
}
|
|
|
- void transition (StateTableDriver<Types, EntryData> *driver,
|
|
|
+ void transition (hb_buffer_t *buffer,
|
|
|
+ StateTableDriver<Types, EntryData> *driver,
|
|
|
const Entry<EntryData> &entry)
|
|
|
{
|
|
|
- hb_buffer_t *buffer = driver->buffer;
|
|
|
unsigned int flags = entry.flags;
|
|
|
|
|
|
if (flags & MarkFirst)
|
|
@@ -168,7 +169,7 @@ struct RearrangementSubtable
|
|
|
|
|
|
driver_context_t dc (this);
|
|
|
|
|
|
- StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
|
|
|
+ StateTableDriver<Types, EntryData> driver (machine, c->face);
|
|
|
driver.drive (&dc, c);
|
|
|
|
|
|
return_trace (dc.ret);
|
|
@@ -180,10 +181,10 @@ struct RearrangementSubtable
|
|
|
return_trace (machine.sanitize (c));
|
|
|
}
|
|
|
|
|
|
- protected:
|
|
|
+ public:
|
|
|
StateTable<Types, EntryData> machine;
|
|
|
public:
|
|
|
- DEFINE_SIZE_STATIC (16);
|
|
|
+ DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size));
|
|
|
};
|
|
|
|
|
|
template <typename Types>
|
|
@@ -223,21 +224,19 @@ struct ContextualSubtable
|
|
|
table (table_),
|
|
|
subs (table+table->substitutionTables) {}
|
|
|
|
|
|
- bool is_actionable (StateTableDriver<Types, EntryData> *driver,
|
|
|
- const Entry<EntryData> &entry)
|
|
|
+ bool is_actionable (hb_buffer_t *buffer,
|
|
|
+ StateTableDriver<Types, EntryData> *driver,
|
|
|
+ const Entry<EntryData> &entry) const
|
|
|
{
|
|
|
- hb_buffer_t *buffer = driver->buffer;
|
|
|
-
|
|
|
if (buffer->idx == buffer->len && !mark_set)
|
|
|
return false;
|
|
|
|
|
|
return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
|
|
|
}
|
|
|
- void transition (StateTableDriver<Types, EntryData> *driver,
|
|
|
+ void transition (hb_buffer_t *buffer,
|
|
|
+ StateTableDriver<Types, EntryData> *driver,
|
|
|
const Entry<EntryData> &entry)
|
|
|
{
|
|
|
- hb_buffer_t *buffer = driver->buffer;
|
|
|
-
|
|
|
/* Looks like CoreText applies neither mark nor current substitution for
|
|
|
* end-of-text if mark was not explicitly set. */
|
|
|
if (buffer->idx == buffer->len && !mark_set)
|
|
@@ -328,7 +327,7 @@ struct ContextualSubtable
|
|
|
|
|
|
driver_context_t dc (this, c);
|
|
|
|
|
|
- StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
|
|
|
+ StateTableDriver<Types, EntryData> driver (machine, c->face);
|
|
|
driver.drive (&dc, c);
|
|
|
|
|
|
return_trace (dc.ret);
|
|
@@ -361,13 +360,14 @@ struct ContextualSubtable
|
|
|
return_trace (substitutionTables.sanitize (c, this, num_lookups));
|
|
|
}
|
|
|
|
|
|
- protected:
|
|
|
+ public:
|
|
|
StateTable<Types, EntryData>
|
|
|
machine;
|
|
|
+ protected:
|
|
|
NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false>, HBUINT>
|
|
|
substitutionTables;
|
|
|
public:
|
|
|
- DEFINE_SIZE_STATIC (20);
|
|
|
+ DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size));
|
|
|
};
|
|
|
|
|
|
|
|
@@ -464,16 +464,16 @@ struct LigatureSubtable
|
|
|
ligature (table+table->ligature),
|
|
|
match_length (0) {}
|
|
|
|
|
|
- bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
|
|
- const Entry<EntryData> &entry)
|
|
|
+ bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
|
|
|
+ StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
|
|
+ const Entry<EntryData> &entry) const
|
|
|
{
|
|
|
return LigatureEntryT::performAction (entry);
|
|
|
}
|
|
|
- void transition (StateTableDriver<Types, EntryData> *driver,
|
|
|
+ void transition (hb_buffer_t *buffer,
|
|
|
+ StateTableDriver<Types, EntryData> *driver,
|
|
|
const Entry<EntryData> &entry)
|
|
|
{
|
|
|
- hb_buffer_t *buffer = driver->buffer;
|
|
|
-
|
|
|
DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
|
|
|
if (entry.flags & LigatureEntryT::SetComponent)
|
|
|
{
|
|
@@ -585,7 +585,7 @@ struct LigatureSubtable
|
|
|
|
|
|
driver_context_t dc (this, c);
|
|
|
|
|
|
- StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
|
|
|
+ StateTableDriver<Types, EntryData> driver (machine, c->face);
|
|
|
driver.drive (&dc, c);
|
|
|
|
|
|
return_trace (dc.ret);
|
|
@@ -600,9 +600,10 @@ struct LigatureSubtable
|
|
|
ligAction && component && ligature);
|
|
|
}
|
|
|
|
|
|
- protected:
|
|
|
+ public:
|
|
|
StateTable<Types, EntryData>
|
|
|
machine;
|
|
|
+ protected:
|
|
|
NNOffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT>
|
|
|
ligAction; /* Offset to the ligature action table. */
|
|
|
NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT>
|
|
@@ -610,7 +611,7 @@ struct LigatureSubtable
|
|
|
NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
|
|
|
ligature; /* Offset to the actual ligature lists. */
|
|
|
public:
|
|
|
- DEFINE_SIZE_STATIC (28);
|
|
|
+ DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + 3 * HBUINT::static_size));
|
|
|
};
|
|
|
|
|
|
template <typename Types>
|
|
@@ -754,16 +755,17 @@ struct InsertionSubtable
|
|
|
mark (0),
|
|
|
insertionAction (table+table->insertionAction) {}
|
|
|
|
|
|
- bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
|
|
- const Entry<EntryData> &entry)
|
|
|
+ bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
|
|
|
+ StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
|
|
+ const Entry<EntryData> &entry) const
|
|
|
{
|
|
|
return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
|
|
|
(entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
|
|
|
}
|
|
|
- void transition (StateTableDriver<Types, EntryData> *driver,
|
|
|
+ void transition (hb_buffer_t *buffer,
|
|
|
+ StateTableDriver<Types, EntryData> *driver,
|
|
|
const Entry<EntryData> &entry)
|
|
|
{
|
|
|
- hb_buffer_t *buffer = driver->buffer;
|
|
|
unsigned int flags = entry.flags;
|
|
|
|
|
|
unsigned mark_loc = buffer->out_len;
|
|
@@ -850,7 +852,7 @@ struct InsertionSubtable
|
|
|
|
|
|
driver_context_t dc (this, c);
|
|
|
|
|
|
- StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
|
|
|
+ StateTableDriver<Types, EntryData> driver (machine, c->face);
|
|
|
driver.drive (&dc, c);
|
|
|
|
|
|
return_trace (dc.ret);
|
|
@@ -865,14 +867,15 @@ struct InsertionSubtable
|
|
|
insertionAction);
|
|
|
}
|
|
|
|
|
|
- protected:
|
|
|
+ public:
|
|
|
StateTable<Types, EntryData>
|
|
|
machine;
|
|
|
+ protected:
|
|
|
NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
|
|
|
insertionAction; /* Byte offset from stateHeader to the start of
|
|
|
* the insertion glyph table. */
|
|
|
public:
|
|
|
- DEFINE_SIZE_STATIC (20);
|
|
|
+ DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size));
|
|
|
};
|
|
|
|
|
|
|
|
@@ -896,6 +899,89 @@ struct Feature
|
|
|
DEFINE_SIZE_STATIC (12);
|
|
|
};
|
|
|
|
|
|
+
|
|
|
+struct hb_accelerate_subtables_context_t :
|
|
|
+ hb_dispatch_context_t<hb_accelerate_subtables_context_t>
|
|
|
+{
|
|
|
+ struct hb_applicable_t
|
|
|
+ {
|
|
|
+ friend struct hb_accelerate_subtables_context_t;
|
|
|
+ friend struct hb_aat_layout_lookup_accelerator_t;
|
|
|
+
|
|
|
+ public:
|
|
|
+ hb_set_digest_t digest;
|
|
|
+
|
|
|
+ template <typename T>
|
|
|
+ auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN
|
|
|
+ (
|
|
|
+ obj_.machine.collect_glyphs (this->digest, num_glyphs)
|
|
|
+ )
|
|
|
+
|
|
|
+ template <typename T>
|
|
|
+ void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>)
|
|
|
+ {
|
|
|
+ digest = digest.full ();
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename T>
|
|
|
+ void init (const T &obj_, unsigned num_glyphs)
|
|
|
+ {
|
|
|
+ init_ (obj_, num_glyphs, hb_prioritize);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ /* Dispatch interface. */
|
|
|
+ template <typename T>
|
|
|
+ return_t dispatch (const T &obj)
|
|
|
+ {
|
|
|
+ hb_applicable_t *entry = &array[i++];
|
|
|
+
|
|
|
+ entry->init (obj, num_glyphs);
|
|
|
+
|
|
|
+ return hb_empty_t ();
|
|
|
+ }
|
|
|
+ static return_t default_return_value () { return hb_empty_t (); }
|
|
|
+
|
|
|
+ bool stop_sublookup_iteration (return_t r) const { return false; }
|
|
|
+
|
|
|
+ hb_accelerate_subtables_context_t (hb_applicable_t *array_, unsigned num_glyphs_) :
|
|
|
+ hb_dispatch_context_t<hb_accelerate_subtables_context_t> (),
|
|
|
+ array (array_), num_glyphs (num_glyphs_) {}
|
|
|
+
|
|
|
+ hb_applicable_t *array;
|
|
|
+ unsigned num_glyphs;
|
|
|
+ unsigned i = 0;
|
|
|
+};
|
|
|
+
|
|
|
+struct hb_aat_layout_chain_accelerator_t
|
|
|
+{
|
|
|
+ template <typename TChain>
|
|
|
+ static hb_aat_layout_chain_accelerator_t *create (const TChain &chain, unsigned num_glyphs)
|
|
|
+ {
|
|
|
+ unsigned count = chain.get_subtable_count ();
|
|
|
+
|
|
|
+ unsigned size = sizeof (hb_aat_layout_chain_accelerator_t) -
|
|
|
+ HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t) +
|
|
|
+ count * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t);
|
|
|
+
|
|
|
+ /* The following is a calloc because when we are collecting subtables,
|
|
|
+ * some of them might be invalid and hence not collect; as a result,
|
|
|
+ * we might not fill in all the count entries of the subtables array.
|
|
|
+ * Zeroing it allows the set digest to gatekeep it without having to
|
|
|
+ * initialize it further. */
|
|
|
+ auto *thiz = (hb_aat_layout_chain_accelerator_t *) hb_calloc (1, size);
|
|
|
+ if (unlikely (!thiz))
|
|
|
+ return nullptr;
|
|
|
+
|
|
|
+ hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables, num_glyphs);
|
|
|
+ chain.dispatch (&c_accelerate_subtables);
|
|
|
+
|
|
|
+ return thiz;
|
|
|
+ }
|
|
|
+
|
|
|
+ hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY];
|
|
|
+};
|
|
|
+
|
|
|
template <typename Types>
|
|
|
struct ChainSubtable
|
|
|
{
|
|
@@ -987,6 +1073,8 @@ struct Chain
|
|
|
{
|
|
|
typedef typename Types::HBUINT HBUINT;
|
|
|
|
|
|
+ unsigned get_subtable_count () const { return subtableCount; }
|
|
|
+
|
|
|
hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const
|
|
|
{
|
|
|
hb_mask_t flags = defaultFlags;
|
|
@@ -1027,7 +1115,8 @@ struct Chain
|
|
|
return flags;
|
|
|
}
|
|
|
|
|
|
- void apply (hb_aat_apply_context_t *c) const
|
|
|
+ void apply (hb_aat_apply_context_t *c,
|
|
|
+ const hb_aat_layout_chain_accelerator_t *accel) const
|
|
|
{
|
|
|
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
|
|
|
unsigned int count = subtableCount;
|
|
@@ -1039,6 +1128,7 @@ struct Chain
|
|
|
hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
|
|
|
goto skip;
|
|
|
c->subtable_flags = subtable->subFeatureFlags;
|
|
|
+ c->machine_glyph_set = accel ? accel->subtables[i].digest : hb_set_digest_t::full ();
|
|
|
|
|
|
if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
|
|
|
HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
|
|
@@ -1100,7 +1190,22 @@ struct Chain
|
|
|
|
|
|
unsigned int get_size () const { return length; }
|
|
|
|
|
|
- bool sanitize (hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const
|
|
|
+ template <typename context_t, typename ...Ts>
|
|
|
+ typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
|
|
+ {
|
|
|
+ const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
|
|
|
+ unsigned int count = subtableCount;
|
|
|
+ for (unsigned int i = 0; i < count; i++)
|
|
|
+ {
|
|
|
+ typename context_t::return_t ret = subtable->dispatch (c, std::forward<Ts> (ds)...);
|
|
|
+ if (c->stop_sublookup_iteration (ret))
|
|
|
+ return ret;
|
|
|
+ subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
|
|
|
+ }
|
|
|
+ return c->default_return_value ();
|
|
|
+ }
|
|
|
+
|
|
|
+ bool sanitize (hb_sanitize_context_t *c, unsigned int version) const
|
|
|
{
|
|
|
TRACE_SANITIZE (this);
|
|
|
if (!(length.sanitize (c) &&
|
|
@@ -1122,6 +1227,13 @@ struct Chain
|
|
|
subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
|
|
|
}
|
|
|
|
|
|
+ if (version >= 3)
|
|
|
+ {
|
|
|
+ const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) subtable;
|
|
|
+ if (!coverage->sanitize (c, count))
|
|
|
+ return_trace (false);
|
|
|
+ }
|
|
|
+
|
|
|
return_trace (true);
|
|
|
}
|
|
|
|
|
@@ -1133,7 +1245,7 @@ struct Chain
|
|
|
|
|
|
UnsizedArrayOf<Feature> featureZ; /* Features. */
|
|
|
/*ChainSubtable firstSubtable;*//* Subtables. */
|
|
|
-/*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */
|
|
|
+/*SubtableGlyphCoverage coverages*//* Only if version >= 3. */
|
|
|
|
|
|
public:
|
|
|
DEFINE_SIZE_MIN (8 + 2 * sizeof (HBUINT));
|
|
@@ -1144,13 +1256,69 @@ struct Chain
|
|
|
* The 'mort'/'morx' Table
|
|
|
*/
|
|
|
|
|
|
-template <typename Types, hb_tag_t TAG>
|
|
|
+template <typename T, typename Types, hb_tag_t TAG>
|
|
|
struct mortmorx
|
|
|
{
|
|
|
static constexpr hb_tag_t tableTag = TAG;
|
|
|
|
|
|
bool has_data () const { return version != 0; }
|
|
|
|
|
|
+ struct accelerator_t
|
|
|
+ {
|
|
|
+ accelerator_t (hb_face_t *face)
|
|
|
+ {
|
|
|
+ hb_sanitize_context_t sc;
|
|
|
+ this->table = sc.reference_table<T> (face);
|
|
|
+
|
|
|
+ this->chain_count = table->get_chain_count ();
|
|
|
+
|
|
|
+ this->accels = (hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *) hb_calloc (this->chain_count, sizeof (*accels));
|
|
|
+ if (unlikely (!this->accels))
|
|
|
+ {
|
|
|
+ this->chain_count = 0;
|
|
|
+ this->table.destroy ();
|
|
|
+ this->table = hb_blob_get_empty ();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ~accelerator_t ()
|
|
|
+ {
|
|
|
+ for (unsigned int i = 0; i < this->chain_count; i++)
|
|
|
+ hb_free (this->accels[i]);
|
|
|
+ hb_free (this->accels);
|
|
|
+ this->table.destroy ();
|
|
|
+ }
|
|
|
+
|
|
|
+ hb_blob_t *get_blob () const { return table.get_blob (); }
|
|
|
+
|
|
|
+ template <typename Chain>
|
|
|
+ hb_aat_layout_chain_accelerator_t *get_accel (unsigned chain_index, const Chain &chain, unsigned num_glyphs) const
|
|
|
+ {
|
|
|
+ if (unlikely (chain_index >= chain_count)) return nullptr;
|
|
|
+
|
|
|
+ retry:
|
|
|
+ auto *accel = accels[chain_index].get_acquire ();
|
|
|
+ if (unlikely (!accel))
|
|
|
+ {
|
|
|
+ accel = hb_aat_layout_chain_accelerator_t::create (chain, num_glyphs);
|
|
|
+ if (unlikely (!accel))
|
|
|
+ return nullptr;
|
|
|
+
|
|
|
+ if (unlikely (!accels[chain_index].cmpexch (nullptr, accel)))
|
|
|
+ {
|
|
|
+ hb_free (accel);
|
|
|
+ goto retry;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return accel;
|
|
|
+ }
|
|
|
+
|
|
|
+ hb_blob_ptr_t<T> table;
|
|
|
+ unsigned int chain_count;
|
|
|
+ hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *accels;
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
void compile_flags (const hb_aat_map_builder_t *mapper,
|
|
|
hb_aat_map_t *map) const
|
|
|
{
|
|
@@ -1167,8 +1335,14 @@ struct mortmorx
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ unsigned get_chain_count () const
|
|
|
+ {
|
|
|
+ return chainCount;
|
|
|
+ }
|
|
|
+
|
|
|
void apply (hb_aat_apply_context_t *c,
|
|
|
- const hb_aat_map_t &map) const
|
|
|
+ const hb_aat_map_t &map,
|
|
|
+ const accelerator_t &accel) const
|
|
|
{
|
|
|
if (unlikely (!c->buffer->successful)) return;
|
|
|
|
|
@@ -1179,8 +1353,9 @@ struct mortmorx
|
|
|
unsigned int count = chainCount;
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
{
|
|
|
+ auto *chain_accel = accel.get_accel (i, *chain, c->face->get_num_glyphs ());
|
|
|
c->range_flags = &map.chain_flags[i];
|
|
|
- chain->apply (c);
|
|
|
+ chain->apply (c, chain_accel);
|
|
|
if (unlikely (!c->buffer->successful)) return;
|
|
|
chain = &StructAfter<Chain<Types>> (*chain);
|
|
|
}
|
|
@@ -1220,8 +1395,15 @@ struct mortmorx
|
|
|
DEFINE_SIZE_MIN (8);
|
|
|
};
|
|
|
|
|
|
-struct morx : mortmorx<ExtendedTypes, HB_AAT_TAG_morx> {};
|
|
|
-struct mort : mortmorx<ObsoleteTypes, HB_AAT_TAG_mort> {};
|
|
|
+struct morx : mortmorx<morx, ExtendedTypes, HB_AAT_TAG_morx> {};
|
|
|
+struct mort : mortmorx<mort, ObsoleteTypes, HB_AAT_TAG_mort> {};
|
|
|
+
|
|
|
+struct morx_accelerator_t : morx::accelerator_t {
|
|
|
+ morx_accelerator_t (hb_face_t *face) : morx::accelerator_t (face) {}
|
|
|
+};
|
|
|
+struct mort_accelerator_t : mort::accelerator_t {
|
|
|
+ mort_accelerator_t (hb_face_t *face) : mort::accelerator_t (face) {}
|
|
|
+};
|
|
|
|
|
|
|
|
|
} /* namespace AAT */
|