1 #ifndef OT_LAYOUT_GSUB_LIGATURESET_HH 2 #define OT_LAYOUT_GSUB_LIGATURESET_HH 3 4 #include "Common.hh" 5 #include "Ligature.hh" 6 7 namespace OT { 8 namespace Layout { 9 namespace GSUB_impl { 10 11 template <typename Types> 12 struct LigatureSet 13 { 14 protected: 15 Array16OfOffset16To<Ligature<Types>> 16 ligature; /* Array LigatureSet tables 17 * ordered by preference */ 18 public: 19 DEFINE_SIZE_ARRAY (2, ligature); 20 sanitizeOT::Layout::GSUB_impl::LigatureSet21 bool sanitize (hb_sanitize_context_t *c) const 22 { 23 TRACE_SANITIZE (this); 24 return_trace (ligature.sanitize (c, this)); 25 } 26 intersectsOT::Layout::GSUB_impl::LigatureSet27 bool intersects (const hb_set_t *glyphs) const 28 { 29 return 30 + hb_iter (ligature) 31 | hb_map (hb_add (this)) 32 | hb_map ([glyphs] (const Ligature<Types> &_) { return _.intersects (glyphs); }) 33 | hb_any 34 ; 35 } 36 intersects_lig_glyphOT::Layout::GSUB_impl::LigatureSet37 bool intersects_lig_glyph (const hb_set_t *glyphs) const 38 { 39 return 40 + hb_iter (ligature) 41 | hb_map (hb_add (this)) 42 | hb_map ([glyphs] (const Ligature<Types> &_) { 43 return _.intersects_lig_glyph (glyphs) && _.intersects (glyphs); 44 }) 45 | hb_any 46 ; 47 } 48 closureOT::Layout::GSUB_impl::LigatureSet49 void closure (hb_closure_context_t *c) const 50 { 51 + hb_iter (ligature) 52 | hb_map (hb_add (this)) 53 | hb_apply ([c] (const Ligature<Types> &_) { _.closure (c); }) 54 ; 55 } 56 collect_glyphsOT::Layout::GSUB_impl::LigatureSet57 void collect_glyphs (hb_collect_glyphs_context_t *c) const 58 { 59 + hb_iter (ligature) 60 | hb_map (hb_add (this)) 61 | hb_apply ([c] (const Ligature<Types> &_) { _.collect_glyphs (c); }) 62 ; 63 } 64 would_applyOT::Layout::GSUB_impl::LigatureSet65 bool would_apply (hb_would_apply_context_t *c) const 66 { 67 return 68 + hb_iter (ligature) 69 | hb_map (hb_add (this)) 70 | hb_map ([c] (const Ligature<Types> &_) { return _.would_apply (c); }) 71 | hb_any 72 ; 73 } 74 applyOT::Layout::GSUB_impl::LigatureSet75 bool apply (hb_ot_apply_context_t *c) const 76 { 77 TRACE_APPLY (this); 78 79 unsigned int num_ligs = ligature.len; 80 81 #ifndef HB_NO_OT_RULESETS_FAST_PATH 82 if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 4) 83 #endif 84 { 85 slow: 86 for (unsigned int i = 0; i < num_ligs; i++) 87 { 88 const auto &lig = this+ligature.arrayZ[i]; 89 if (lig.apply (c)) return_trace (true); 90 } 91 return_trace (false); 92 } 93 94 /* This version is optimized for speed by matching the first component 95 * of the ligature here, instead of calling into the ligation code. 96 * 97 * This is replicated in ChainRuleSet and RuleSet. */ 98 99 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; 100 skippy_iter.reset (c->buffer->idx); 101 skippy_iter.set_match_func (match_always, nullptr); 102 skippy_iter.set_glyph_data ((HBUINT16 *) nullptr); 103 unsigned unsafe_to; 104 hb_codepoint_t first = (unsigned) -1; 105 bool matched = skippy_iter.next (&unsafe_to); 106 if (likely (matched)) 107 { 108 first = c->buffer->info[skippy_iter.idx].codepoint; 109 unsafe_to = skippy_iter.idx + 1; 110 111 if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])) 112 { 113 /* Can't use the fast path if eg. the next char is a default-ignorable 114 * or other skippable. */ 115 goto slow; 116 } 117 } 118 else 119 goto slow; 120 121 bool unsafe_to_concat = false; 122 123 for (unsigned int i = 0; i < num_ligs; i++) 124 { 125 const auto &lig = this+ligature.arrayZ[i]; 126 if (unlikely (lig.component.lenP1 <= 1) || 127 lig.component.arrayZ[0] == first) 128 { 129 if (lig.apply (c)) 130 { 131 if (unsafe_to_concat) 132 c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to); 133 return_trace (true); 134 } 135 } 136 else if (likely (lig.component.lenP1 > 1)) 137 unsafe_to_concat = true; 138 } 139 if (likely (unsafe_to_concat)) 140 c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to); 141 142 return_trace (false); 143 } 144 serializeOT::Layout::GSUB_impl::LigatureSet145 bool serialize (hb_serialize_context_t *c, 146 hb_array_t<const HBGlyphID16> ligatures, 147 hb_array_t<const unsigned int> component_count_list, 148 hb_array_t<const HBGlyphID16> &component_list /* Starting from second for each ligature */) 149 { 150 TRACE_SERIALIZE (this); 151 if (unlikely (!c->extend_min (this))) return_trace (false); 152 if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false); 153 for (unsigned int i = 0; i < ligatures.length; i++) 154 { 155 unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0); 156 if (unlikely (!ligature[i].serialize_serialize (c, 157 ligatures[i], 158 component_list.sub_array (0, component_count)))) 159 return_trace (false); 160 component_list += component_count; 161 } 162 return_trace (true); 163 } 164 subsetOT::Layout::GSUB_impl::LigatureSet165 bool subset (hb_subset_context_t *c, unsigned coverage_idx) const 166 { 167 TRACE_SUBSET (this); 168 auto *out = c->serializer->start_embed (*this); 169 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 170 171 + hb_iter (ligature) 172 | hb_filter (subset_offset_array (c, out->ligature, this, coverage_idx)) 173 | hb_drain 174 ; 175 176 if (bool (out->ligature)) 177 // Ensure Coverage table is always packed after this. 178 c->serializer->add_virtual_link (coverage_idx); 179 180 return_trace (bool (out->ligature)); 181 } 182 }; 183 184 } 185 } 186 } 187 188 #endif /* OT_LAYOUT_GSUB_LIGATURESET_HH */ 189