1#ifndef OT_LAYOUT_GSUB_SEQUENCE_HH
2#define OT_LAYOUT_GSUB_SEQUENCE_HH
3
4#include "Common.hh"
5
6namespace OT {
7namespace Layout {
8namespace GSUB_impl {
9
10template <typename Types>
11struct Sequence
12{
13 protected:
14 Array16Of<typename Types::HBGlyphID>
15 substitute; /* String of GlyphIDs to substitute */
16 public:
17 DEFINE_SIZE_ARRAY (2, substitute);
18
19 bool sanitize (hb_sanitize_context_t *c) const
20 {
21 TRACE_SANITIZE (this);
22 return_trace (substitute.sanitize (c));
23 }
24
25 bool intersects (const hb_set_t *glyphs) const
26 { return hb_all (substitute, glyphs); }
27
28 void closure (hb_closure_context_t *c) const
29 { c->output->add_array (substitute.arrayZ, substitute.len); }
30
31 void collect_glyphs (hb_collect_glyphs_context_t *c) const
32 { c->output->add_array (substitute.arrayZ, substitute.len); }
33
34 bool apply (hb_ot_apply_context_t *c) const
35 {
36 TRACE_APPLY (this);
37 unsigned int count = substitute.len;
38
39 /* Special-case to make it in-place and not consider this
40 * as a "multiplied" substitution. */
41 if (unlikely (count == 1))
42 {
43 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
44 {
45 c->buffer->sync_so_far ();
46 c->buffer->message (c->font,
47 "replacing glyph at %u (multiple substitution)",
48 c->buffer->idx);
49 }
50
51 c->replace_glyph (substitute.arrayZ[0]);
52
53 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
54 {
55 c->buffer->message (c->font,
56 "replaced glyph at %u (multiple substitution)",
57 c->buffer->idx - 1u);
58 }
59
60 return_trace (true);
61 }
62 /* Spec disallows this, but Uniscribe allows it.
63 * https://github.com/harfbuzz/harfbuzz/issues/253 */
64 else if (unlikely (count == 0))
65 {
66 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
67 {
68 c->buffer->sync_so_far ();
69 c->buffer->message (c->font,
70 "deleting glyph at %u (multiple substitution)",
71 c->buffer->idx);
72 }
73
74 c->buffer->delete_glyph ();
75
76 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
77 {
78 c->buffer->sync_so_far ();
79 c->buffer->message (c->font,
80 "deleted glyph at %u (multiple substitution)",
81 c->buffer->idx);
82 }
83
84 return_trace (true);
85 }
86
87 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
88 {
89 c->buffer->sync_so_far ();
90 c->buffer->message (c->font,
91 "multiplying glyph at %u",
92 c->buffer->idx);
93 }
94
95 unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
96 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
97 unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
98
99 for (unsigned int i = 0; i < count; i++)
100 {
101 /* If is attached to a ligature, don't disturb that.
102 * https://github.com/harfbuzz/harfbuzz/issues/3069 */
103 if (!lig_id)
104 _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
105 c->output_glyph_for_component (substitute.arrayZ[i], klass);
106 }
107 c->buffer->skip_glyph ();
108
109 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
110 {
111 c->buffer->sync_so_far ();
112
113 char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
114 char *p = buf;
115
116 for (unsigned i = c->buffer->idx - count; i < c->buffer->idx; i++)
117 {
118 if (buf < p)
119 *p++ = ',';
120 snprintf (p, sizeof(buf) - (p - buf), "%u", i);
121 p += strlen(p);
122 }
123
124 c->buffer->message (c->font,
125 "multiplied glyphs at %s",
126 buf);
127 }
128
129 return_trace (true);
130 }
131
132 template <typename Iterator,
133 hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
134 bool serialize (hb_serialize_context_t *c,
135 Iterator subst)
136 {
137 TRACE_SERIALIZE (this);
138 return_trace (substitute.serialize (c, subst));
139 }
140
141 bool subset (hb_subset_context_t *c) const
142 {
143 TRACE_SUBSET (this);
144 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
145 const hb_map_t &glyph_map = *c->plan->glyph_map;
146
147 if (!intersects (&glyphset)) return_trace (false);
148
149 auto it =
150 + hb_iter (substitute)
151 | hb_map (glyph_map)
152 ;
153
154 auto *out = c->serializer->start_embed (*this);
155 return_trace (out->serialize (c->serializer, it));
156 }
157};
158
159
160}
161}
162}
163
164
165#endif /* OT_LAYOUT_GSUB_SEQUENCE_HH */
166