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 const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack); 37 if (!lookahead.sanitize (c, this)) 38 return_trace (false); 39 const auto &substitute = StructAfter<decltype (substituteX)> (lookahead); 40 return_trace (substitute.sanitize (c)); 41 } 42 intersectsOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat143 bool intersects (const hb_set_t *glyphs) const 44 { 45 if (!(this+coverage).intersects (glyphs)) 46 return false; 47 48 const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack); 49 50 unsigned int count; 51 52 count = backtrack.len; 53 for (unsigned int i = 0; i < count; i++) 54 if (!(this+backtrack[i]).intersects (glyphs)) 55 return false; 56 57 count = lookahead.len; 58 for (unsigned int i = 0; i < count; i++) 59 if (!(this+lookahead[i]).intersects (glyphs)) 60 return false; 61 62 return true; 63 } 64 may_have_non_1to1OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat165 bool may_have_non_1to1 () const 66 { return false; } 67 closureOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat168 void closure (hb_closure_context_t *c) const 69 { 70 if (!intersects (c->glyphs)) return; 71 72 const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack); 73 const auto &substitute = StructAfter<decltype (substituteX)> (lookahead); 74 75 + hb_zip (this+coverage, substitute) 76 | hb_filter (c->parent_active_glyphs (), hb_first) 77 | hb_map (hb_second) 78 | hb_sink (c->output) 79 ; 80 } 81 closure_lookupsOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat182 void closure_lookups (hb_closure_lookups_context_t *c) const {} 83 collect_glyphsOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat184 void collect_glyphs (hb_collect_glyphs_context_t *c) const 85 { 86 if (unlikely (!(this+coverage).collect_coverage (c->input))) return; 87 88 unsigned int count; 89 90 count = backtrack.len; 91 for (unsigned int i = 0; i < count; i++) 92 if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return; 93 94 const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack); 95 count = lookahead.len; 96 for (unsigned int i = 0; i < count; i++) 97 if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return; 98 99 const auto &substitute = StructAfter<decltype (substituteX)> (lookahead); 100 count = substitute.len; 101 c->output->add_array (substitute.arrayZ, substitute.len); 102 } 103 get_coverageOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1104 const Coverage &get_coverage () const { return this+coverage; } 105 would_applyOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1106 bool would_apply (hb_would_apply_context_t *c) const 107 { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } 108 applyOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1109 bool apply (hb_ot_apply_context_t *c) const 110 { 111 TRACE_APPLY (this); 112 if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL)) 113 return_trace (false); /* No chaining to this type */ 114 115 unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); 116 if (likely (index == NOT_COVERED)) return_trace (false); 117 118 const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack); 119 const auto &substitute = StructAfter<decltype (substituteX)> (lookahead); 120 121 if (unlikely (index >= substitute.len)) return_trace (false); 122 123 unsigned int start_index = 0, end_index = 0; 124 if (match_backtrack (c, 125 backtrack.len, (HBUINT16 *) backtrack.arrayZ, 126 match_coverage, this, 127 &start_index) && 128 match_lookahead (c, 129 lookahead.len, (HBUINT16 *) lookahead.arrayZ, 130 match_coverage, this, 131 c->buffer->idx + 1, &end_index)) 132 { 133 c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index); 134 135 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 136 { 137 c->buffer->message (c->font, 138 "replacing glyph at %d (reverse chaining substitution)", 139 c->buffer->idx); 140 } 141 142 c->replace_glyph_inplace (substitute[index]); 143 144 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 145 { 146 c->buffer->message (c->font, 147 "replaced glyph at %d (reverse chaining substitution)", 148 c->buffer->idx); 149 } 150 151 /* Note: We DON'T decrease buffer->idx. The main loop does it 152 * for us. This is useful for preventing surprises if someone 153 * calls us through a Context lookup. */ 154 return_trace (true); 155 } 156 else 157 { 158 c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index); 159 return_trace (false); 160 } 161 } 162 163 template<typename Iterator, 164 hb_requires (hb_is_iterator (Iterator))> serialize_coverage_offset_arrayOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1165 bool serialize_coverage_offset_array (hb_subset_context_t *c, Iterator it) const 166 { 167 TRACE_SERIALIZE (this); 168 auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> (); 169 170 if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size))) 171 return_trace (false); 172 173 for (auto& offset : it) { 174 auto *o = out->serialize_append (c->serializer); 175 if (unlikely (!o) || !o->serialize_subset (c, offset, this)) 176 return_trace (false); 177 } 178 179 return_trace (true); 180 } 181 182 template<typename Iterator, typename BacktrackIterator, typename LookaheadIterator, 183 hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_pair_t)), 184 hb_requires (hb_is_iterator (BacktrackIterator)), 185 hb_requires (hb_is_iterator (LookaheadIterator))> serializeOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1186 bool serialize (hb_subset_context_t *c, 187 Iterator coverage_subst_iter, 188 BacktrackIterator backtrack_iter, 189 LookaheadIterator lookahead_iter) const 190 { 191 TRACE_SERIALIZE (this); 192 193 auto *out = c->serializer->start_embed (this); 194 if (unlikely (!c->serializer->check_success (out))) return_trace (false); 195 if (unlikely (!c->serializer->embed (this->format))) return_trace (false); 196 if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false); 197 198 if (!serialize_coverage_offset_array (c, backtrack_iter)) return_trace (false); 199 if (!serialize_coverage_offset_array (c, lookahead_iter)) return_trace (false); 200 201 auto *substitute_out = c->serializer->start_embed<Array16Of<HBGlyphID16>> (); 202 auto substitutes = 203 + coverage_subst_iter 204 | hb_map (hb_second) 205 ; 206 207 auto glyphs = 208 + coverage_subst_iter 209 | hb_map_retains_sorting (hb_first) 210 ; 211 if (unlikely (! c->serializer->check_success (substitute_out->serialize (c->serializer, substitutes)))) 212 return_trace (false); 213 214 if (unlikely (!out->coverage.serialize_serialize (c->serializer, glyphs))) 215 return_trace (false); 216 return_trace (true); 217 } 218 subsetOT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1219 bool subset (hb_subset_context_t *c) const 220 { 221 TRACE_SUBSET (this); 222 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 223 const hb_map_t &glyph_map = *c->plan->glyph_map; 224 225 const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack); 226 const auto &substitute = StructAfter<decltype (substituteX)> (lookahead); 227 228 auto it = 229 + hb_zip (this+coverage, substitute) 230 | hb_filter (glyphset, hb_first) 231 | hb_filter (glyphset, hb_second) 232 | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t 233 { return hb_pair (glyph_map[p.first], glyph_map[p.second]); }) 234 ; 235 236 return_trace (bool (it) && serialize (c, it, backtrack.iter (), lookahead.iter ())); 237 } 238 }; 239 240 } 241 } 242 } 243 244 #endif /* HB_OT_LAYOUT_GSUB_REVERSECHAINSINGLESUBSTFORMAT1_HH */ 245