LigatureSet.hh (5479B)
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 public: 15 Array16OfOffset16To<Ligature<Types>> 16 ligature; /* Array LigatureSet tables 17 * ordered by preference */ 18 19 DEFINE_SIZE_ARRAY (2, ligature); 20 21 bool sanitize (hb_sanitize_context_t *c) const 22 { 23 TRACE_SANITIZE (this); 24 return_trace (ligature.sanitize (c, this)); 25 } 26 27 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 37 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 49 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 57 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 65 template <typename set_t> 66 void collect_seconds (set_t &s) const 67 { 68 + hb_iter (ligature) 69 | hb_map (hb_add (this)) 70 | hb_apply ([&s] (const Ligature<Types> &_) { _.collect_second (s); }) 71 ; 72 } 73 74 bool would_apply (hb_would_apply_context_t *c) const 75 { 76 return 77 + hb_iter (ligature) 78 | hb_map (hb_add (this)) 79 | hb_map ([c] (const Ligature<Types> &_) { return _.would_apply (c); }) 80 | hb_any 81 ; 82 } 83 84 bool apply (hb_ot_apply_context_t *c, const hb_set_digest_t *seconds = nullptr) const 85 { 86 TRACE_APPLY (this); 87 88 unsigned int num_ligs = ligature.len; 89 90 #ifndef HB_NO_OT_RULESETS_FAST_PATH 91 if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 1) 92 #endif 93 { 94 slow: 95 for (unsigned int i = 0; i < num_ligs; i++) 96 { 97 const auto &lig = this+ligature.arrayZ[i]; 98 if (lig.apply (c)) return_trace (true); 99 } 100 return_trace (false); 101 } 102 103 /* This version is optimized for speed by matching the second component 104 * of the ligature here, instead of calling into the ligation code. 105 * 106 * This is replicated in ChainRuleSet and RuleSet. */ 107 108 auto &skippy_iter = c->iter_context; 109 skippy_iter.reset (c->buffer->idx); 110 skippy_iter.set_match_func (match_always, nullptr); 111 skippy_iter.set_glyph_data ((HBUINT16 *) nullptr); 112 unsigned unsafe_to; 113 hb_codepoint_t second = (unsigned) -1; 114 bool matched = skippy_iter.next (&unsafe_to); 115 if (likely (matched)) 116 { 117 second = c->buffer->info[skippy_iter.idx].codepoint; 118 unsafe_to = skippy_iter.idx + 1; 119 120 if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])) 121 { 122 /* Can't use the fast path if eg. the next char is a default-ignorable 123 * or other skippable. */ 124 goto slow; 125 } 126 } 127 else 128 goto slow; 129 130 if (seconds && !seconds->may_have (second)) 131 return_trace (false); 132 bool unsafe_to_concat = false; 133 for (unsigned int i = 0; i < num_ligs; i++) 134 { 135 const auto &lig = this+ligature.arrayZ[i]; 136 if (unlikely (lig.component.lenP1 <= 1) || 137 lig.component.arrayZ[0] == second) 138 { 139 if (lig.apply (c)) 140 { 141 if (unsafe_to_concat) 142 c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to); 143 return_trace (true); 144 } 145 } 146 else if (likely (lig.component.lenP1 > 1)) 147 unsafe_to_concat = true; 148 } 149 if (likely (unsafe_to_concat)) 150 c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to); 151 152 return_trace (false); 153 } 154 155 bool serialize (hb_serialize_context_t *c, 156 hb_array_t<const HBGlyphID16> ligatures, 157 hb_array_t<const unsigned int> component_count_list, 158 hb_array_t<const HBGlyphID16> &component_list /* Starting from second for each ligature */) 159 { 160 TRACE_SERIALIZE (this); 161 if (unlikely (!c->extend_min (this))) return_trace (false); 162 if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false); 163 for (unsigned int i = 0; i < ligatures.length; i++) 164 { 165 unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0); 166 if (unlikely (!ligature[i].serialize_serialize (c, 167 ligatures[i], 168 component_list.sub_array (0, component_count)))) 169 return_trace (false); 170 component_list += component_count; 171 } 172 return_trace (true); 173 } 174 175 bool subset (hb_subset_context_t *c, unsigned coverage_idx) const 176 { 177 TRACE_SUBSET (this); 178 auto *out = c->serializer->start_embed (*this); 179 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 180 181 + hb_iter (ligature) 182 | hb_filter (subset_offset_array (c, out->ligature, this, coverage_idx)) 183 | hb_drain 184 ; 185 186 if (bool (out->ligature)) 187 // Ensure Coverage table is always packed after this. 188 c->serializer->add_virtual_link (coverage_idx); 189 190 return_trace (bool (out->ligature)); 191 } 192 }; 193 194 } 195 } 196 } 197 198 #endif /* OT_LAYOUT_GSUB_LIGATURESET_HH */