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