| #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<SubTable> (c); } | |
| const SubTable& get_subtable (unsigned int i) const | |
| { return Lookup::get_subtable<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<hb_collect_glyphs_context_t>); | |
| return dispatch (c); | |
| } | |
| template <typename set_t> | |
| void collect_coverage (set_t *glyphs) const | |
| { | |
| hb_collect_coverage_context_t<set_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<typename Glyphs, typename Substitutes, | |
| hb_requires (hb_is_sorted_source_of (Glyphs, | |
| const hb_codepoint_t) && | |
| hb_is_source_of (Substitutes, | |
| const hb_codepoint_t))> | |
| 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<SubTable> ()->u.single.serialize (c, hb_zip (glyphs, substitutes))) | |
| { | |
| c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ()); | |
| return_trace (true); | |
| } | |
| c->pop_discard (); | |
| return_trace (false); | |
| } | |
| template<typename Iterator, | |
| hb_requires (hb_is_sorted_iterator (Iterator))> | |
| bool serialize (hb_serialize_context_t *c, | |
| uint32_t lookup_props, | |
| Iterator it) | |
| { | |
| TRACE_SERIALIZE (this); | |
| if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false); | |
| if (c->push<SubTable> ()->u.multiple. | |
| serialize (c, it)) | |
| { | |
| c->add_link (get_subtables<SubTable> ()[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<const HBGlyphID16> glyphs, | |
| hb_array_t<const unsigned int> alternate_len_list, | |
| hb_array_t<const HBGlyphID16> alternate_glyphs_list) | |
| { | |
| TRACE_SERIALIZE (this); | |
| if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false); | |
| if (c->push<SubTable> ()->u.alternate. | |
| serialize (c, | |
| glyphs, | |
| alternate_len_list, | |
| alternate_glyphs_list)) | |
| { | |
| c->add_link (get_subtables<SubTable> ()[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<const HBGlyphID16> first_glyphs, | |
| hb_array_t<const unsigned int> ligature_per_first_glyph_count_list, | |
| hb_array_t<const HBGlyphID16> ligatures_list, | |
| hb_array_t<const unsigned int> component_count_list, | |
| hb_array_t<const HBGlyphID16> 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<SubTable> ()->u.ligature. | |
| serialize (c, | |
| first_glyphs, | |
| ligature_per_first_glyph_count_list, | |
| ligatures_list, | |
| component_count_list, | |
| component_list)) | |
| { | |
| c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ()); | |
| return_trace (true); | |
| } | |
| c->pop_discard (); | |
| return_trace (false); | |
| } | |
| template <typename context_t> | |
| 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, typename ...Ts> | |
| typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const | |
| { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); } | |
| bool subset (hb_subset_context_t *c) const | |
| { return Lookup::subset<SubTable> (c); } | |
| }; | |
| } | |
| } | |
| } | |
| #endif /* OT_LAYOUT_GSUB_SUBSTLOOKUP_HH */ |