1 #ifndef OT_LAYOUT_GSUB_SUBSTLOOKUP_HH 2 #define OT_LAYOUT_GSUB_SUBSTLOOKUP_HH 3 4 #include "Common.hh" 5 #include "SubstLookupSubTable.hh" 6 7 namespace OT { 8 namespace Layout { 9 namespace GSUB_impl { 10 11 struct SubstLookup : Lookup 12 { 13 using SubTable = SubstLookupSubTable; 14 sanitizeOT::Layout::GSUB_impl::SubstLookup15 bool sanitize (hb_sanitize_context_t *c) const 16 { return Lookup::sanitize<SubTable> (c); } 17 get_subtableOT::Layout::GSUB_impl::SubstLookup18 const SubTable& get_subtable (unsigned int i) const 19 { return Lookup::get_subtable<SubTable> (i); } 20 lookup_type_is_reverseOT::Layout::GSUB_impl::SubstLookup21 static inline bool lookup_type_is_reverse (unsigned int lookup_type) 22 { return lookup_type == SubTable::ReverseChainSingle; } 23 is_reverseOT::Layout::GSUB_impl::SubstLookup24 bool is_reverse () const 25 { 26 unsigned int type = get_type (); 27 if (unlikely (type == SubTable::Extension)) 28 return get_subtable (0).u.extension.is_reverse (); 29 return lookup_type_is_reverse (type); 30 } 31 may_have_non_1to1OT::Layout::GSUB_impl::SubstLookup32 bool may_have_non_1to1 () const 33 { 34 hb_have_non_1to1_context_t c; 35 return dispatch (&c); 36 } 37 applyOT::Layout::GSUB_impl::SubstLookup38 bool apply (hb_ot_apply_context_t *c) const 39 { 40 TRACE_APPLY (this); 41 return_trace (dispatch (c)); 42 } 43 intersectsOT::Layout::GSUB_impl::SubstLookup44 bool intersects (const hb_set_t *glyphs) const 45 { 46 hb_intersects_context_t c (glyphs); 47 return dispatch (&c); 48 } 49 closureOT::Layout::GSUB_impl::SubstLookup50 hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const 51 { 52 if (!c->should_visit_lookup (this_index)) 53 return hb_closure_context_t::default_return_value (); 54 55 c->set_recurse_func (dispatch_closure_recurse_func); 56 57 hb_closure_context_t::return_t ret = dispatch (c); 58 59 c->flush (); 60 61 return ret; 62 } 63 closure_lookupsOT::Layout::GSUB_impl::SubstLookup64 hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const 65 { 66 if (c->is_lookup_visited (this_index)) 67 return hb_closure_lookups_context_t::default_return_value (); 68 69 c->set_lookup_visited (this_index); 70 if (!intersects (c->glyphs)) 71 { 72 c->set_lookup_inactive (this_index); 73 return hb_closure_lookups_context_t::default_return_value (); 74 } 75 76 hb_closure_lookups_context_t::return_t ret = dispatch (c); 77 return ret; 78 } 79 collect_glyphsOT::Layout::GSUB_impl::SubstLookup80 hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const 81 { 82 c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>); 83 return dispatch (c); 84 } 85 86 template <typename set_t> collect_coverageOT::Layout::GSUB_impl::SubstLookup87 void collect_coverage (set_t *glyphs) const 88 { 89 hb_collect_coverage_context_t<set_t> c (glyphs); 90 dispatch (&c); 91 } 92 would_applyOT::Layout::GSUB_impl::SubstLookup93 bool would_apply (hb_would_apply_context_t *c, 94 const hb_ot_layout_lookup_accelerator_t *accel) const 95 { 96 if (unlikely (!c->len)) return false; 97 if (!accel->may_have (c->glyphs[0])) return false; 98 return dispatch (c); 99 } 100 101 template<typename Glyphs, typename Substitutes, 102 hb_requires (hb_is_sorted_source_of (Glyphs, 103 const hb_codepoint_t) && 104 hb_is_source_of (Substitutes, 105 const hb_codepoint_t))> serialize_singleOT::Layout::GSUB_impl::SubstLookup106 bool serialize_single (hb_serialize_context_t *c, 107 uint32_t lookup_props, 108 Glyphs glyphs, 109 Substitutes substitutes) 110 { 111 TRACE_SERIALIZE (this); 112 if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false); 113 if (c->push<SubTable> ()->u.single.serialize (c, hb_zip (glyphs, substitutes))) 114 { 115 c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ()); 116 return_trace (true); 117 } 118 c->pop_discard (); 119 return_trace (false); 120 } 121 122 template<typename Iterator, 123 hb_requires (hb_is_sorted_iterator (Iterator))> serializeOT::Layout::GSUB_impl::SubstLookup124 bool serialize (hb_serialize_context_t *c, 125 uint32_t lookup_props, 126 Iterator it) 127 { 128 TRACE_SERIALIZE (this); 129 if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false); 130 if (c->push<SubTable> ()->u.multiple. 131 serialize (c, it)) 132 { 133 c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ()); 134 return_trace (true); 135 } 136 c->pop_discard (); 137 return_trace (false); 138 } 139 serialize_alternateOT::Layout::GSUB_impl::SubstLookup140 bool serialize_alternate (hb_serialize_context_t *c, 141 uint32_t lookup_props, 142 hb_sorted_array_t<const HBGlyphID16> glyphs, 143 hb_array_t<const unsigned int> alternate_len_list, 144 hb_array_t<const HBGlyphID16> alternate_glyphs_list) 145 { 146 TRACE_SERIALIZE (this); 147 if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false); 148 149 if (c->push<SubTable> ()->u.alternate. 150 serialize (c, 151 glyphs, 152 alternate_len_list, 153 alternate_glyphs_list)) 154 { 155 c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ()); 156 return_trace (true); 157 } 158 c->pop_discard (); 159 return_trace (false); 160 } 161 serialize_ligatureOT::Layout::GSUB_impl::SubstLookup162 bool serialize_ligature (hb_serialize_context_t *c, 163 uint32_t lookup_props, 164 hb_sorted_array_t<const HBGlyphID16> first_glyphs, 165 hb_array_t<const unsigned int> ligature_per_first_glyph_count_list, 166 hb_array_t<const HBGlyphID16> ligatures_list, 167 hb_array_t<const unsigned int> component_count_list, 168 hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */) 169 { 170 TRACE_SERIALIZE (this); 171 if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false); 172 if (c->push<SubTable> ()->u.ligature. 173 serialize (c, 174 first_glyphs, 175 ligature_per_first_glyph_count_list, 176 ligatures_list, 177 component_count_list, 178 component_list)) 179 { 180 c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ()); 181 return_trace (true); 182 } 183 c->pop_discard (); 184 return_trace (false); 185 } 186 187 template <typename context_t> 188 static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); 189 190 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); 191 dispatch_closure_recurse_funcOT::Layout::GSUB_impl::SubstLookup192 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) 193 { 194 if (!c->should_visit_lookup (lookup_index)) 195 return hb_empty_t (); 196 197 hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_index); 198 199 /* While in theory we should flush here, it will cause timeouts because a recursive 200 * lookup can keep growing the glyph set. Skip, and outer loop will retry up to 201 * HB_CLOSURE_MAX_STAGES time, which should be enough for every realistic font. */ 202 //c->flush (); 203 204 return ret; 205 } 206 207 template <typename context_t, typename ...Ts> dispatchOT::Layout::GSUB_impl::SubstLookup208 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 209 { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); } 210 subsetOT::Layout::GSUB_impl::SubstLookup211 bool subset (hb_subset_context_t *c) const 212 { return Lookup::subset<SubTable> (c); } 213 }; 214 215 216 } 217 } 218 } 219 220 #endif /* OT_LAYOUT_GSUB_SUBSTLOOKUP_HH */ 221