• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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