1 #ifndef OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH 2 #define OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH 3 4 #include "Common.hh" 5 6 namespace OT { 7 namespace Layout { 8 namespace GSUB_impl { 9 10 template <typename Types> 11 struct SingleSubstFormat1_3 12 { 13 protected: 14 HBUINT16 format; /* Format identifier--format = 1 */ 15 typename Types::template OffsetTo<Coverage> 16 coverage; /* Offset to Coverage table--from 17 * beginning of Substitution table */ 18 typename Types::HBUINT 19 deltaGlyphID; /* Add to original GlyphID to get 20 * substitute GlyphID, modulo 0x10000 */ 21 22 public: 23 DEFINE_SIZE_STATIC (2 + 2 * Types::size); 24 sanitizeOT::Layout::GSUB_impl::SingleSubstFormat1_325 bool sanitize (hb_sanitize_context_t *c) const 26 { 27 TRACE_SANITIZE (this); 28 return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); 29 } 30 get_maskOT::Layout::GSUB_impl::SingleSubstFormat1_331 hb_codepoint_t get_mask () const 32 { return (1 << (8 * Types::size)) - 1; } 33 intersectsOT::Layout::GSUB_impl::SingleSubstFormat1_334 bool intersects (const hb_set_t *glyphs) const 35 { return (this+coverage).intersects (glyphs); } 36 may_have_non_1to1OT::Layout::GSUB_impl::SingleSubstFormat1_337 bool may_have_non_1to1 () const 38 { return false; } 39 closureOT::Layout::GSUB_impl::SingleSubstFormat1_340 void closure (hb_closure_context_t *c) const 41 { 42 hb_codepoint_t d = deltaGlyphID; 43 hb_codepoint_t mask = get_mask (); 44 45 /* Help fuzzer avoid this function as much. */ 46 unsigned pop = (this+coverage).get_population (); 47 if (pop >= mask) 48 return; 49 50 hb_set_t intersection; 51 (this+coverage).intersect_set (c->parent_active_glyphs (), intersection); 52 53 /* In degenerate fuzzer-found fonts, but not real fonts, 54 * this table can keep adding new glyphs in each round of closure. 55 * Refuse to close-over, if it maps glyph range to overlapping range. */ 56 hb_codepoint_t min_before = intersection.get_min (); 57 hb_codepoint_t max_before = intersection.get_max (); 58 hb_codepoint_t min_after = (min_before + d) & mask; 59 hb_codepoint_t max_after = (max_before + d) & mask; 60 if (intersection.get_population () == max_before - min_before + 1 && 61 ((min_before <= min_after && min_after <= max_before) || 62 (min_before <= max_after && max_after <= max_before))) 63 return; 64 65 + hb_iter (intersection) 66 | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; }) 67 | hb_sink (c->output) 68 ; 69 } 70 closure_lookupsOT::Layout::GSUB_impl::SingleSubstFormat1_371 void closure_lookups (hb_closure_lookups_context_t *c) const {} 72 collect_glyphsOT::Layout::GSUB_impl::SingleSubstFormat1_373 void collect_glyphs (hb_collect_glyphs_context_t *c) const 74 { 75 if (unlikely (!(this+coverage).collect_coverage (c->input))) return; 76 hb_codepoint_t d = deltaGlyphID; 77 hb_codepoint_t mask = get_mask (); 78 79 + hb_iter (this+coverage) 80 | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; }) 81 | hb_sink (c->output) 82 ; 83 } 84 get_coverageOT::Layout::GSUB_impl::SingleSubstFormat1_385 const Coverage &get_coverage () const { return this+coverage; } 86 would_applyOT::Layout::GSUB_impl::SingleSubstFormat1_387 bool would_apply (hb_would_apply_context_t *c) const 88 { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } 89 applyOT::Layout::GSUB_impl::SingleSubstFormat1_390 bool apply (hb_ot_apply_context_t *c) const 91 { 92 TRACE_APPLY (this); 93 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 94 unsigned int index = (this+coverage).get_coverage (glyph_id); 95 if (likely (index == NOT_COVERED)) return_trace (false); 96 97 hb_codepoint_t d = deltaGlyphID; 98 hb_codepoint_t mask = get_mask (); 99 100 glyph_id = (glyph_id + d) & mask; 101 102 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 103 { 104 c->buffer->sync_so_far (); 105 c->buffer->message (c->font, 106 "replacing glyph at %d (single substitution)", 107 c->buffer->idx); 108 } 109 110 c->replace_glyph (glyph_id); 111 112 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 113 { 114 c->buffer->message (c->font, 115 "replaced glyph at %d (single substitution)", 116 c->buffer->idx - 1); 117 } 118 119 return_trace (true); 120 } 121 122 template<typename Iterator, 123 hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))> serializeOT::Layout::GSUB_impl::SingleSubstFormat1_3124 bool serialize (hb_serialize_context_t *c, 125 Iterator glyphs, 126 unsigned delta) 127 { 128 TRACE_SERIALIZE (this); 129 if (unlikely (!c->extend_min (this))) return_trace (false); 130 if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false); 131 c->check_assign (deltaGlyphID, delta, HB_SERIALIZE_ERROR_INT_OVERFLOW); 132 return_trace (true); 133 } 134 subsetOT::Layout::GSUB_impl::SingleSubstFormat1_3135 bool subset (hb_subset_context_t *c) const 136 { 137 TRACE_SUBSET (this); 138 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 139 const hb_map_t &glyph_map = *c->plan->glyph_map; 140 141 hb_codepoint_t d = deltaGlyphID; 142 hb_codepoint_t mask = get_mask (); 143 144 hb_set_t intersection; 145 (this+coverage).intersect_set (glyphset, intersection); 146 147 auto it = 148 + hb_iter (intersection) 149 | hb_map_retains_sorting ([d, mask] (hb_codepoint_t g) { 150 return hb_codepoint_pair_t (g, 151 (g + d) & mask); }) 152 | hb_filter (glyphset, hb_second) 153 | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t 154 { return hb_pair (glyph_map[p.first], glyph_map[p.second]); }) 155 ; 156 157 bool ret = bool (it); 158 SingleSubst_serialize (c->serializer, it); 159 return_trace (ret); 160 } 161 }; 162 163 } 164 } 165 } 166 167 168 #endif /* OT_LAYOUT_GSUB_SINGLESUBSTFORMAT1_HH */ 169