diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh index ee80d51f6..f085642e8 100644 --- a/src/hb-aat-layout-common.hh +++ b/src/hb-aat-layout-common.hh @@ -59,6 +59,7 @@ struct hb_aat_apply_context_t : const ankr *ankr_table; const OT::GDEF *gdef_table; const hb_sorted_vector_t *range_flags = nullptr; + hb_set_digest_t machine_glyph_set = hb_set_digest_t::full (); hb_mask_t subtable_flags = 0; /* Unused. For debug tracing only. */ @@ -81,6 +82,8 @@ struct hb_aat_apply_context_t : * Lookup Table */ +enum { DELETED_GLYPH = 0xFFFF }; + template struct Lookup; template @@ -98,8 +101,7 @@ struct LookupFormat0 template void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const { - for (unsigned int i = 0; i < num_glyphs; i++) - glyphs.add (i); + glyphs.add_range (0, num_glyphs - 1); } bool sanitize (hb_sanitize_context_t *c) const @@ -133,6 +135,8 @@ struct LookupSegmentSingle template void collect_glyphs (set_t &glyphs) const { + if (first == DELETED_GLYPH) + return; glyphs.add_range (first, last); } @@ -208,6 +212,8 @@ struct LookupSegmentArray template void collect_glyphs (set_t &glyphs) const { + if (first == DELETED_GLYPH) + return; glyphs.add_range (first, last); } @@ -292,6 +298,8 @@ struct LookupSingle template void collect_glyphs (set_t &glyphs) const { + if (glyph == DELETED_GLYPH) + return; glyphs.add (glyph); } @@ -368,6 +376,8 @@ struct LookupFormat8 { if (unlikely (!glyphCount)) return; + if (firstGlyph == DELETED_GLYPH) + return; glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1); } @@ -530,8 +540,6 @@ struct Lookup }; DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2); -enum { DELETED_GLYPH = 0xFFFF }; - /* * (Extended) State Table */ @@ -582,6 +590,14 @@ struct Entry DEFINE_SIZE_STATIC (4); }; +enum Class +{ + CLASS_END_OF_TEXT = 0, + CLASS_OUT_OF_BOUNDS = 1, + CLASS_DELETED_GLYPH = 2, + CLASS_END_OF_LINE = 3, +}; + template struct StateTable { @@ -594,16 +610,6 @@ struct StateTable STATE_START_OF_TEXT = 0, STATE_START_OF_LINE = 1, }; - enum Class - { - CLASS_END_OF_TEXT = 0, - CLASS_OUT_OF_BOUNDS = 1, - CLASS_DELETED_GLYPH = 2, - CLASS_END_OF_LINE = 3, - }; - - int new_state (unsigned int newState) const - { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; } template void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const @@ -611,6 +617,9 @@ struct StateTable (this+classTable).collect_glyphs (glyphs, num_glyphs); } + int new_state (unsigned int newState) const + { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; } + template unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs, @@ -618,7 +627,7 @@ struct StateTable { if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH; if (!glyphs[glyph_id]) return CLASS_OUT_OF_BOUNDS; - return (this+classTable).get_class (glyph_id, num_glyphs, 1); + return (this+classTable).get_class (glyph_id, num_glyphs, CLASS_OUT_OF_BOUNDS); } const Entry *get_entries () const @@ -627,7 +636,7 @@ struct StateTable const Entry &get_entry (int state, unsigned int klass) const { if (unlikely (klass >= nClasses)) - klass = StateTable::CLASS_OUT_OF_BOUNDS; + klass = CLASS_OUT_OF_BOUNDS; const HBUSHORT *states = (this+stateArrayTable).arrayZ; const Entry *entries = (this+entryTable).arrayZ; @@ -772,10 +781,11 @@ struct ClassTable } template - void collect_glyphs (set_t &glyphs, HB_UNUSED unsigned num_glyphs) const + void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const { - for (unsigned int i = 0; i < classArray.len; i++) - glyphs.add (i + firstGlyph); + for (unsigned i = 0; i < classArray.len; i++) + if (classArray.arrayZ[i] != CLASS_OUT_OF_BOUNDS) + glyphs.add (firstGlyph + i); } bool sanitize (hb_sanitize_context_t *c) const @@ -901,10 +911,7 @@ struct StateTableDriver StateTableDriver (const StateTableT &machine_, hb_face_t *face_) : machine (machine_), - num_glyphs (face_->get_num_glyphs ()) - { - machine.collect_glyphs (glyph_set, num_glyphs); - } + num_glyphs (face_->get_num_glyphs ()) {} template void drive (context_t *c, hb_aat_apply_context_t *ac) @@ -945,9 +952,9 @@ struct StateTableDriver } } - unsigned int klass = buffer->idx < buffer->len ? - machine.get_class (buffer->cur().codepoint, num_glyphs, glyph_set) : - (unsigned) StateTableT::CLASS_END_OF_TEXT; + unsigned int klass = likely (buffer->idx < buffer->len) ? + machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_glyph_set) : + (unsigned) CLASS_END_OF_TEXT; DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx); const EntryT &entry = machine.get_entry (state, klass); const int next_state = machine.new_state (entry.newState); @@ -1011,7 +1018,7 @@ struct StateTableDriver return false; /* 3. */ - return !c->is_actionable (buffer, this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT)); + return !c->is_actionable (buffer, this, machine.get_entry (state, CLASS_END_OF_TEXT)); }; if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len) @@ -1036,7 +1043,6 @@ struct StateTableDriver public: const StateTableT &machine; unsigned int num_glyphs; - hb_set_digest_t glyph_set; }; diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh index 9dd4e7bfb..23cea0871 100644 --- a/src/hb-aat-layout-morx-table.hh +++ b/src/hb-aat-layout-morx-table.hh @@ -181,7 +181,7 @@ struct RearrangementSubtable return_trace (machine.sanitize (c)); } - protected: + public: StateTable machine; public: DEFINE_SIZE_STATIC (16); @@ -360,9 +360,10 @@ struct ContextualSubtable return_trace (substitutionTables.sanitize (c, this, num_lookups)); } - protected: + public: StateTable machine; + protected: NNOffsetTo, HBUINT, void, false>, HBUINT> substitutionTables; public: @@ -599,9 +600,10 @@ struct LigatureSubtable ligAction && component && ligature); } - protected: + public: StateTable machine; + protected: NNOffsetTo, HBUINT> ligAction; /* Offset to the ligature action table. */ NNOffsetTo, HBUINT> @@ -865,9 +867,10 @@ struct InsertionSubtable insertionAction); } - protected: + public: StateTable machine; + protected: NNOffsetTo, HBUINT> insertionAction; /* Byte offset from stateHeader to the start of * the insertion glyph table. */ @@ -896,6 +899,89 @@ struct Feature DEFINE_SIZE_STATIC (12); }; + +struct hb_accelerate_subtables_context_t : + hb_dispatch_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 + auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN + ( + obj_.machine.collect_glyphs (this->digest, num_glyphs) + ) + + template + void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>) + { + digest = digest.full (); + } + + template + void init (const T &obj_, unsigned num_glyphs) + { + init_ (obj_, num_glyphs, hb_prioritize); + } + }; + + /* Dispatch interface. */ + template + 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 (), + array (array_), num_glyphs (num_glyphs_) {} + + hb_applicable_t *array; + unsigned num_glyphs; + unsigned i = 0; +}; + +struct hb_aat_layout_chain_accelerator_t +{ + template + 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 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 *subtable = &StructAfter> (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::AllDirections) && HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != @@ -1100,6 +1190,21 @@ struct Chain unsigned int get_size () const { return length; } + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + const ChainSubtable *subtable = &StructAfter> (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 (ds)...); + if (c->stop_sublookup_iteration (ret)) + return ret; + subtable = &StructAfter> (*subtable); + } + return c->default_return_value (); + } + bool sanitize (hb_sanitize_context_t *c, unsigned int version) const { TRACE_SANITIZE (this); @@ -1151,13 +1256,69 @@ struct Chain * The 'mort'/'morx' Table */ -template +template 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 (face); + + this->chain_count = table->get_chain_count (); + + this->accels = (hb_atomic_ptr_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 + 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 table; + unsigned int chain_count; + hb_atomic_ptr_t *accels; + }; + + void compile_flags (const hb_aat_map_builder_t *mapper, hb_aat_map_t *map) const { @@ -1174,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; @@ -1186,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); } @@ -1227,8 +1395,15 @@ struct mortmorx DEFINE_SIZE_MIN (8); }; -struct morx : mortmorx {}; -struct mort : mortmorx {}; +struct morx : mortmorx {}; +struct mort : mortmorx {}; + +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 */ diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc index 5e4cea222..ff2fdab43 100644 --- a/src/hb-aat-layout.cc +++ b/src/hb-aat-layout.cc @@ -211,14 +211,14 @@ void hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper, hb_aat_map_t *map) { - const AAT::morx& morx = *mapper->face->table.morx; + const AAT::morx& morx = *mapper->face->table.morx->table; if (morx.has_data ()) { morx.compile_flags (mapper, map); return; } - const AAT::mort& mort = *mapper->face->table.mort; + const AAT::mort& mort = *mapper->face->table.mort->table; if (mort.has_data ()) { mort.compile_flags (mapper, map); @@ -243,8 +243,8 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper, hb_bool_t hb_aat_layout_has_substitution (hb_face_t *face) { - return face->table.morx->has_data () || - face->table.mort->has_data (); + return face->table.morx->table->has_data () || + face->table.mort->table->has_data (); } void @@ -260,26 +260,30 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan, hb_aat_map_t map; builder.compile (map); - hb_blob_t *morx_blob = font->face->table.morx.get_blob (); - const AAT::morx& morx = *morx_blob->as (); - if (morx.has_data ()) { - AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob); - if (!buffer->message (font, "start table morx")) return; - morx.apply (&c, map); - (void) buffer->message (font, "end table morx"); - return; + auto &accel = *font->face->table.morx; + const AAT::morx& morx = *accel.table; + if (morx.has_data ()) + { + AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ()); + if (!buffer->message (font, "start table morx")) return; + morx.apply (&c, map, accel); + (void) buffer->message (font, "end table morx"); + return; + } } - hb_blob_t *mort_blob = font->face->table.mort.get_blob (); - const AAT::mort& mort = *mort_blob->as (); - if (mort.has_data ()) { - AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob); - if (!buffer->message (font, "start table mort")) return; - mort.apply (&c, map); - (void) buffer->message (font, "end table mort"); - return; + auto &accel = *font->face->table.mort; + const AAT::mort& mort = *accel.table; + if (mort.has_data ()) + { + AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ()); + if (!buffer->message (font, "start table mort")) return; + mort.apply (&c, map, accel); + (void) buffer->message (font, "end table mort"); + return; + } } } diff --git a/src/hb-ot-face-table-list.hh b/src/hb-ot-face-table-list.hh index b552dfdd9..5a6fa2772 100644 --- a/src/hb-ot-face-table-list.hh +++ b/src/hb-ot-face-table-list.hh @@ -118,8 +118,8 @@ HB_OT_CORE_TABLE (OT, BASE) /* AAT shaping. */ #ifndef HB_NO_AAT -HB_OT_TABLE (AAT, morx) -HB_OT_TABLE (AAT, mort) +HB_OT_ACCELERATOR (AAT, morx) +HB_OT_ACCELERATOR (AAT, mort) HB_OT_TABLE (AAT, kerx) HB_OT_TABLE (AAT, ankr) HB_OT_TABLE (AAT, trak) diff --git a/src/hb-ot-face.cc b/src/hb-ot-face.cc index 2243ee028..44797945c 100644 --- a/src/hb-ot-face.cc +++ b/src/hb-ot-face.cc @@ -41,6 +41,7 @@ #include "hb-ot-layout-gdef-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" +#include "hb-aat-layout-morx-table.hh" void hb_ot_face_t::init0 (hb_face_t *face) diff --git a/src/hb-set-digest.hh b/src/hb-set-digest.hh index b2994c9d5..6e618b9ce 100644 --- a/src/hb-set-digest.hh +++ b/src/hb-set-digest.hh @@ -82,6 +82,8 @@ struct hb_set_digest_bits_pattern_t void init () { mask = 0; } + static hb_set_digest_bits_pattern_t full () { hb_set_digest_bits_pattern_t d; d.mask = (mask_t) -1; return d; } + void add (const hb_set_digest_bits_pattern_t &o) { mask |= o.mask; } void add (hb_codepoint_t g) { mask |= mask_for (g); } @@ -148,6 +150,8 @@ struct hb_set_digest_combiner_t tail.init (); } + static hb_set_digest_combiner_t full () { hb_set_digest_combiner_t d; d.head = head_t::full(); d.tail = tail_t::full (); return d; } + void add (const hb_set_digest_combiner_t &o) { head.add (o.head);