1 #ifndef OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH 2 #define OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH 3 4 #include "Common.hh" 5 6 namespace OT { 7 namespace Layout { 8 namespace GSUB_impl { 9 10 struct ReverseChainSingleSubstFormat1 11 { 12 protected: 13 HBUINT16 format; /* Format identifier--format = 1 */ 14 Offset16To<Coverage> 15 coverage; /* Offset to Coverage table--from 16 * beginning of table */ 17 Array16OfOffset16To<Coverage> 18 backtrack; /* Array of coverage tables 19 * in backtracking sequence, in glyph 20 * sequence order */ 21 Array16OfOffset16To<Coverage> 22 lookaheadX; /* Array of coverage tables 23 * in lookahead sequence, in glyph 24 * sequence order */ 25 Array16Of<HBGlyphID16> 26 substituteX; /* Array of substitute 27 * GlyphIDs--ordered by Coverage Index */ 28 public: 29 DEFINE_SIZE_MIN (10); 30 sanitizeOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat131 bool sanitize (hb_sanitize_context_t *c) const 32 { 33 TRACE_SANITIZE (this); 34 if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this))) 35 return_trace (false); 36 hb_barrier (); 37 const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack); 38 if (!lookahead.sanitize (c, this)) 39 return_trace (false); 40 hb_barrier (); 41 const auto &substitute = StructAfter<decltype (substituteX)> (lookahead); 42 return_trace (substitute.sanitize (c)); 43 } 44 intersectsOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat145 bool intersects (const hb_set_t *glyphs) const 46 { 47 if (!(this+coverage).intersects (glyphs)) 48 return false; 49 50 const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack); 51 52 unsigned int count; 53 54 count = backtrack.len; 55 for (unsigned int i = 0; i < count; i++) 56 if (!(this+backtrack[i]).intersects (glyphs)) 57 return false; 58 59 count = lookahead.len; 60 for (unsigned int i = 0; i < count; i++) 61 if (!(this+lookahead[i]).intersects (glyphs)) 62 return false; 63 64 return true; 65 } 66 may_have_non_1to1OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat167 bool may_have_non_1to1 () const 68 { return false; } 69 closureOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat170 void closure (hb_closure_context_t *c) const 71 { 72 if (!intersects (c->glyphs)) return; 73 74 const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack); 75 const auto &substitute = StructAfter<decltype (substituteX)> (lookahead); 76 77 + hb_zip (this+coverage, substitute) 78 | hb_filter (c->parent_active_glyphs (), hb_first) 79 | hb_map (hb_second) 80 | hb_sink (c->output) 81 ; 82 } 83 closure_lookupsOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat184 void closure_lookups (hb_closure_lookups_context_t *c) const {} 85 collect_glyphsOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat186 void collect_glyphs (hb_collect_glyphs_context_t *c) const 87 { 88 if (unlikely (!(this+coverage).collect_coverage (c->input))) return; 89 90 unsigned int count; 91 92 count = backtrack.len; 93 for (unsigned int i = 0; i < count; i++) 94 if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return; 95 96 const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack); 97 count = lookahead.len; 98 for (unsigned int i = 0; i < count; i++) 99 if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return; 100 101 const auto &substitute = StructAfter<decltype (substituteX)> (lookahead); 102 count = substitute.len; 103 c->output->add_array (substitute.arrayZ, substitute.len); 104 } 105 get_coverageOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1106 const Coverage &get_coverage () const { return this+coverage; } 107 would_applyOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1108 bool would_apply (hb_would_apply_context_t *c) const 109 { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } 110 applyOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1111 bool apply (hb_ot_apply_context_t *c) const 112 { 113 TRACE_APPLY (this); 114 unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); 115 if (likely (index == NOT_COVERED)) return_trace (false); 116 117 if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL)) 118 return_trace (false); /* No chaining to this type */ 119 120 const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack); 121 const auto &substitute = StructAfter<decltype (substituteX)> (lookahead); 122 123 if (unlikely (index >= substitute.len)) return_trace (false); 124 125 unsigned int start_index = 0, end_index = 0; 126 if (match_backtrack (c, 127 backtrack.len, (HBUINT16 *) backtrack.arrayZ, 128 match_coverage, this, 129 &start_index) && 130 match_lookahead (c, 131 lookahead.len, (HBUINT16 *) lookahead.arrayZ, 132 match_coverage, this, 133 c->buffer->idx + 1, &end_index)) 134 { 135 c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index); 136 137 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 138 { 139 c->buffer->message (c->font, 140 "replacing glyph at %u (reverse chaining substitution)", 141 c->buffer->idx); 142 } 143 144 c->replace_glyph_inplace (substitute[index]); 145 146 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 147 { 148 c->buffer->message (c->font, 149 "replaced glyph at %u (reverse chaining substitution)", 150 c->buffer->idx); 151 } 152 153 /* Note: We DON'T decrease buffer->idx. The main loop does it 154 * for us. This is useful for preventing surprises if someone 155 * calls us through a Context lookup. */ 156 return_trace (true); 157 } 158 else 159 { 160 c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index); 161 return_trace (false); 162 } 163 } 164 165 template<typename Iterator, 166 hb_requires (hb_is_iterator (Iterator))> serialize_coverage_offset_arrayOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1167 bool serialize_coverage_offset_array (hb_subset_context_t *c, Iterator it) const 168 { 169 TRACE_SERIALIZE (this); 170 auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> (); 171 172 if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size))) 173 return_trace (false); 174 175 for (auto& offset : it) { 176 auto *o = out->serialize_append (c->serializer); 177 if (unlikely (!o) || !o->serialize_subset (c, offset, this)) 178 return_trace (false); 179 } 180 181 return_trace (true); 182 } 183 184 template<typename Iterator, typename BacktrackIterator, typename LookaheadIterator, 185 hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_pair_t)), 186 hb_requires (hb_is_iterator (BacktrackIterator)), 187 hb_requires (hb_is_iterator (LookaheadIterator))> serializeOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1188 bool serialize (hb_subset_context_t *c, 189 Iterator coverage_subst_iter, 190 BacktrackIterator backtrack_iter, 191 LookaheadIterator lookahead_iter) const 192 { 193 TRACE_SERIALIZE (this); 194 195 auto *out = c->serializer->start_embed (this); 196 if (unlikely (!c->serializer->embed (this->format))) return_trace (false); 197 if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false); 198 199 if (!serialize_coverage_offset_array (c, backtrack_iter)) return_trace (false); 200 if (!serialize_coverage_offset_array (c, lookahead_iter)) return_trace (false); 201 202 auto *substitute_out = c->serializer->start_embed<Array16Of<HBGlyphID16>> (); 203 auto substitutes = 204 + coverage_subst_iter 205 | hb_map (hb_second) 206 ; 207 208 auto glyphs = 209 + coverage_subst_iter 210 | hb_map_retains_sorting (hb_first) 211 ; 212 if (unlikely (! c->serializer->check_success (substitute_out->serialize (c->serializer, substitutes)))) 213 return_trace (false); 214 215 if (unlikely (!out->coverage.serialize_serialize (c->serializer, glyphs))) 216 return_trace (false); 217 return_trace (true); 218 } 219 subsetOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1220 bool subset (hb_subset_context_t *c) const 221 { 222 TRACE_SUBSET (this); 223 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 224 const hb_map_t &glyph_map = *c->plan->glyph_map; 225 226 const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack); 227 const auto &substitute = StructAfter<decltype (substituteX)> (lookahead); 228 229 auto it = 230 + hb_zip (this+coverage, substitute) 231 | hb_filter (glyphset, hb_first) 232 | hb_filter (glyphset, hb_second) 233 | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t 234 { return hb_pair (glyph_map[p.first], glyph_map[p.second]); }) 235 ; 236 237 return_trace (bool (it) && serialize (c, it, backtrack.iter (), lookahead.iter ())); 238 } 239 }; 240 241 } 242 } 243 } 244 245 #endif /* HB_OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH */ 246