1 | #ifndef OT_LAYOUT_GSUB_LIGATURE_HH |
2 | #define OT_LAYOUT_GSUB_LIGATURE_HH |
3 | |
4 | #include "Common.hh" |
5 | |
6 | namespace OT { |
7 | namespace Layout { |
8 | namespace GSUB_impl { |
9 | |
10 | template <typename Types> |
11 | struct Ligature |
12 | { |
13 | public: |
14 | typename Types::HBGlyphID |
15 | ligGlyph; /* GlyphID of ligature to substitute */ |
16 | HeadlessArray16Of<typename Types::HBGlyphID> |
17 | component; /* Array of component GlyphIDs--start |
18 | * with the second component--ordered |
19 | * in writing direction */ |
20 | public: |
21 | DEFINE_SIZE_ARRAY (Types::size + 2, component); |
22 | |
23 | bool sanitize (hb_sanitize_context_t *c) const |
24 | { |
25 | TRACE_SANITIZE (this); |
26 | return_trace (ligGlyph.sanitize (c) && component.sanitize (c)); |
27 | } |
28 | |
29 | bool intersects (const hb_set_t *glyphs) const |
30 | { return hb_all (component, glyphs); } |
31 | |
32 | bool intersects_lig_glyph (const hb_set_t *glyphs) const |
33 | { return glyphs->has(ligGlyph); } |
34 | |
35 | void closure (hb_closure_context_t *c) const |
36 | { |
37 | if (!intersects (c->glyphs)) return; |
38 | c->output->add (ligGlyph); |
39 | } |
40 | |
41 | void collect_glyphs (hb_collect_glyphs_context_t *c) const |
42 | { |
43 | c->input->add_array (component.arrayZ, component.get_length ()); |
44 | c->output->add (ligGlyph); |
45 | } |
46 | |
47 | bool would_apply (hb_would_apply_context_t *c) const |
48 | { |
49 | if (c->len != component.lenP1) |
50 | return false; |
51 | |
52 | for (unsigned int i = 1; i < c->len; i++) |
53 | if (likely (c->glyphs[i] != component[i])) |
54 | return false; |
55 | |
56 | return true; |
57 | } |
58 | |
59 | bool apply (hb_ot_apply_context_t *c) const |
60 | { |
61 | TRACE_APPLY (this); |
62 | unsigned int count = component.lenP1; |
63 | |
64 | if (unlikely (!count)) return_trace (false); |
65 | |
66 | /* Special-case to make it in-place and not consider this |
67 | * as a "ligated" substitution. */ |
68 | if (unlikely (count == 1)) |
69 | { |
70 | |
71 | if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) |
72 | { |
73 | c->buffer->sync_so_far (); |
74 | c->buffer->message (c->font, |
75 | "replacing glyph at %u (ligature substitution)" , |
76 | c->buffer->idx); |
77 | } |
78 | |
79 | c->replace_glyph (ligGlyph); |
80 | |
81 | if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) |
82 | { |
83 | c->buffer->message (c->font, |
84 | "replaced glyph at %u (ligature substitution)" , |
85 | c->buffer->idx - 1u); |
86 | } |
87 | |
88 | return_trace (true); |
89 | } |
90 | |
91 | unsigned int total_component_count = 0; |
92 | |
93 | unsigned int match_end = 0; |
94 | unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; |
95 | |
96 | if (likely (!match_input (c, count, |
97 | &component[1], |
98 | match_glyph, |
99 | nullptr, |
100 | &match_end, |
101 | match_positions, |
102 | &total_component_count))) |
103 | { |
104 | c->buffer->unsafe_to_concat (c->buffer->idx, match_end); |
105 | return_trace (false); |
106 | } |
107 | |
108 | unsigned pos = 0; |
109 | if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) |
110 | { |
111 | unsigned delta = c->buffer->sync_so_far (); |
112 | |
113 | pos = c->buffer->idx; |
114 | |
115 | char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0}; |
116 | char *p = buf; |
117 | |
118 | match_end += delta; |
119 | for (unsigned i = 0; i < count; i++) |
120 | { |
121 | match_positions[i] += delta; |
122 | if (i) |
123 | *p++ = ','; |
124 | snprintf (p, sizeof(buf) - (p - buf), "%u" , match_positions[i]); |
125 | p += strlen(p); |
126 | } |
127 | |
128 | c->buffer->message (c->font, |
129 | "ligating glyphs at %s" , |
130 | buf); |
131 | } |
132 | |
133 | ligate_input (c, |
134 | count, |
135 | match_positions, |
136 | match_end, |
137 | ligGlyph, |
138 | total_component_count); |
139 | |
140 | if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) |
141 | { |
142 | c->buffer->sync_so_far (); |
143 | c->buffer->message (c->font, |
144 | "ligated glyph at %u" , |
145 | pos); |
146 | } |
147 | |
148 | return_trace (true); |
149 | } |
150 | |
151 | template <typename Iterator, |
152 | hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))> |
153 | bool serialize (hb_serialize_context_t *c, |
154 | hb_codepoint_t ligature, |
155 | Iterator components /* Starting from second */) |
156 | { |
157 | TRACE_SERIALIZE (this); |
158 | if (unlikely (!c->extend_min (this))) return_trace (false); |
159 | ligGlyph = ligature; |
160 | if (unlikely (!component.serialize (c, components))) return_trace (false); |
161 | return_trace (true); |
162 | } |
163 | |
164 | bool subset (hb_subset_context_t *c, unsigned coverage_idx) const |
165 | { |
166 | TRACE_SUBSET (this); |
167 | const hb_set_t &glyphset = *c->plan->glyphset_gsub (); |
168 | const hb_map_t &glyph_map = *c->plan->glyph_map; |
169 | |
170 | if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false); |
171 | // Ensure Coverage table is always packed after this. |
172 | c->serializer->add_virtual_link (coverage_idx); |
173 | |
174 | auto it = |
175 | + hb_iter (component) |
176 | | hb_map (glyph_map) |
177 | ; |
178 | |
179 | auto *out = c->serializer->start_embed (*this); |
180 | return_trace (out->serialize (c->serializer, |
181 | glyph_map[ligGlyph], |
182 | it)); } |
183 | }; |
184 | |
185 | |
186 | } |
187 | } |
188 | } |
189 | |
190 | #endif /* OT_LAYOUT_GSUB_LIGATURE_HH */ |
191 | |