#ifndef OT_LAYOUT_GSUB_SUBSTLOOKUP_HH #define OT_LAYOUT_GSUB_SUBSTLOOKUP_HH #include "Common.hh" #include "SubstLookupSubTable.hh" namespace OT { namespace Layout { namespace GSUB_impl { struct SubstLookup : Lookup { using SubTable = SubstLookupSubTable; bool sanitize (hb_sanitize_context_t *c) const { return Lookup::sanitize (c); } const SubTable& get_subtable (unsigned int i) const { return Lookup::get_subtable (i); } static inline bool lookup_type_is_reverse (unsigned int lookup_type) { return lookup_type == SubTable::ReverseChainSingle; } bool is_reverse () const { unsigned int type = get_type (); if (unlikely (type == SubTable::Extension)) return get_subtable (0).u.extension.is_reverse (); return lookup_type_is_reverse (type); } bool may_have_non_1to1 () const { hb_have_non_1to1_context_t c; return dispatch (&c); } bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); return_trace (dispatch (c)); } bool intersects (const hb_set_t *glyphs) const { hb_intersects_context_t c (glyphs); return dispatch (&c); } hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const { if (!c->should_visit_lookup (this_index)) return hb_closure_context_t::default_return_value (); c->set_recurse_func (dispatch_closure_recurse_func); hb_closure_context_t::return_t ret = dispatch (c); c->flush (); return ret; } hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const { if (c->is_lookup_visited (this_index)) return hb_closure_lookups_context_t::default_return_value (); c->set_lookup_visited (this_index); if (!intersects (c->glyphs)) { c->set_lookup_inactive (this_index); return hb_closure_lookups_context_t::default_return_value (); } hb_closure_lookups_context_t::return_t ret = dispatch (c); return ret; } hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const { c->set_recurse_func (dispatch_recurse_func); return dispatch (c); } template void collect_coverage (set_t *glyphs) const { hb_collect_coverage_context_t c (glyphs); dispatch (&c); } bool would_apply (hb_would_apply_context_t *c, const hb_ot_layout_lookup_accelerator_t *accel) const { if (unlikely (!c->len)) return false; if (!accel->may_have (c->glyphs[0])) return false; return dispatch (c); } template bool serialize_single (hb_serialize_context_t *c, uint32_t lookup_props, Glyphs glyphs, Substitutes substitutes) { TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false); if (c->push ()->u.single.serialize (c, hb_zip (glyphs, substitutes))) { c->add_link (get_subtables ()[0], c->pop_pack ()); return_trace (true); } c->pop_discard (); return_trace (false); } bool serialize_multiple (hb_serialize_context_t *c, uint32_t lookup_props, hb_sorted_array_t glyphs, hb_array_t substitute_len_list, hb_array_t substitute_glyphs_list) { TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false); if (c->push ()->u.multiple. serialize (c, glyphs, substitute_len_list, substitute_glyphs_list)) { c->add_link (get_subtables ()[0], c->pop_pack ()); return_trace (true); } c->pop_discard (); return_trace (false); } bool serialize_alternate (hb_serialize_context_t *c, uint32_t lookup_props, hb_sorted_array_t glyphs, hb_array_t alternate_len_list, hb_array_t alternate_glyphs_list) { TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false); if (c->push ()->u.alternate. serialize (c, glyphs, alternate_len_list, alternate_glyphs_list)) { c->add_link (get_subtables ()[0], c->pop_pack ()); return_trace (true); } c->pop_discard (); return_trace (false); } bool serialize_ligature (hb_serialize_context_t *c, uint32_t lookup_props, hb_sorted_array_t first_glyphs, hb_array_t ligature_per_first_glyph_count_list, hb_array_t ligatures_list, hb_array_t component_count_list, hb_array_t component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false); if (c->push ()->u.ligature. serialize (c, first_glyphs, ligature_per_first_glyph_count_list, ligatures_list, component_count_list, component_list)) { c->add_link (get_subtables ()[0], c->pop_pack ()); return_trace (true); } c->pop_discard (); return_trace (false); } template static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index); static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index) { if (!c->should_visit_lookup (lookup_index)) return hb_empty_t (); hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_index); /* While in theory we should flush here, it will cause timeouts because a recursive * lookup can keep growing the glyph set. Skip, and outer loop will retry up to * HB_CLOSURE_MAX_STAGES time, which should be enough for every realistic font. */ //c->flush (); return ret; } template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { return Lookup::dispatch (c, std::forward (ds)...); } bool subset (hb_subset_context_t *c) const { return Lookup::subset (c); } }; } } } #endif /* OT_LAYOUT_GSUB_SUBSTLOOKUP_HH */