comparison mupdf-source/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
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
25 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
31 hb_codepoint_t get_mask () const
32 { return (1 << (8 * Types::size)) - 1; }
33
34 bool intersects (const hb_set_t *glyphs) const
35 { return (this+coverage).intersects (glyphs); }
36
37 bool may_have_non_1to1 () const
38 { return false; }
39
40 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
71 void closure_lookups (hb_closure_lookups_context_t *c) const {}
72
73 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
85 const Coverage &get_coverage () const { return this+coverage; }
86
87 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
90 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))>
124 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
135 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 */