/src/harfbuzz/src/hb-subset-cff-common.hh
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright © 2018 Adobe Inc. |
3 | | * |
4 | | * This is part of HarfBuzz, a text shaping library. |
5 | | * |
6 | | * Permission is hereby granted, without written agreement and without |
7 | | * license or royalty fees, to use, copy, modify, and distribute this |
8 | | * software and its documentation for any purpose, provided that the |
9 | | * above copyright notice and the following two paragraphs appear in |
10 | | * all copies of this software. |
11 | | * |
12 | | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
13 | | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
14 | | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
15 | | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
16 | | * DAMAGE. |
17 | | * |
18 | | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
19 | | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
20 | | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
21 | | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
22 | | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
23 | | * |
24 | | * Adobe Author(s): Michiharu Ariza |
25 | | */ |
26 | | |
27 | | #ifndef HB_SUBSET_CFF_COMMON_HH |
28 | | #define HB_SUBSET_CFF_COMMON_HH |
29 | | |
30 | | #include "hb.hh" |
31 | | |
32 | | #include "hb-subset-plan.hh" |
33 | | #include "hb-cff-interp-cs-common.hh" |
34 | | |
35 | | namespace CFF { |
36 | | |
37 | | /* Used for writing a temporary charstring */ |
38 | | struct str_encoder_t |
39 | | { |
40 | | str_encoder_t (str_buff_t &buff_) |
41 | 70.7k | : buff (buff_) {} |
42 | | |
43 | 5.09k | void reset () { buff.reset (); } |
44 | | |
45 | | void encode_byte (unsigned char b) |
46 | 112k | { |
47 | 112k | if (likely ((signed) buff.length < buff.allocated)) |
48 | 105k | buff.arrayZ[buff.length++] = b; |
49 | 6.32k | else |
50 | 6.32k | buff.push (b); |
51 | 112k | } |
52 | | |
53 | | void encode_int (int v) |
54 | 67.0k | { |
55 | 67.0k | if ((-1131 <= v) && (v <= 1131)) |
56 | 66.6k | { |
57 | 66.6k | if ((-107 <= v) && (v <= 107)) |
58 | 61.7k | encode_byte (v + 139); |
59 | 4.86k | else if (v > 0) |
60 | 2.48k | { |
61 | 2.48k | v -= 108; |
62 | 2.48k | encode_byte ((v >> 8) + OpCode_TwoBytePosInt0); |
63 | 2.48k | encode_byte (v & 0xFF); |
64 | 2.48k | } |
65 | 2.37k | else |
66 | 2.37k | { |
67 | 2.37k | v = -v - 108; |
68 | 2.37k | encode_byte ((v >> 8) + OpCode_TwoByteNegInt0); |
69 | 2.37k | encode_byte (v & 0xFF); |
70 | 2.37k | } |
71 | 66.6k | } |
72 | 452 | else |
73 | 452 | { |
74 | 452 | if (unlikely (v < -32768)) |
75 | 0 | v = -32768; |
76 | 452 | else if (unlikely (v > 32767)) |
77 | 0 | v = 32767; |
78 | 452 | encode_byte (OpCode_shortint); |
79 | 452 | encode_byte ((v >> 8) & 0xFF); |
80 | 452 | encode_byte (v & 0xFF); |
81 | 452 | } |
82 | 67.0k | } |
83 | | |
84 | | // Encode number for CharString |
85 | | void encode_num_cs (const number_t& n) |
86 | 65.0k | { |
87 | 65.0k | if (n.in_int_range ()) |
88 | 62.2k | { |
89 | 62.2k | encode_int (n.to_int ()); |
90 | 62.2k | } |
91 | 2.77k | else |
92 | 2.77k | { |
93 | 2.77k | int32_t v = n.to_fixed (); |
94 | 2.77k | encode_byte (OpCode_fixedcs); |
95 | 2.77k | encode_byte ((v >> 24) & 0xFF); |
96 | 2.77k | encode_byte ((v >> 16) & 0xFF); |
97 | 2.77k | encode_byte ((v >> 8) & 0xFF); |
98 | 2.77k | encode_byte (v & 0xFF); |
99 | 2.77k | } |
100 | 65.0k | } |
101 | | |
102 | | // Encode number for TopDict / Private |
103 | | void encode_num_tp (const number_t& n) |
104 | 0 | { |
105 | 0 | if (n.in_int_range ()) |
106 | 0 | { |
107 | | // TODO longint |
108 | 0 | encode_int (n.to_int ()); |
109 | 0 | } |
110 | 0 | else |
111 | 0 | { |
112 | | // Sigh. BCD |
113 | | // https://learn.microsoft.com/en-us/typography/opentype/spec/cff2#table-5-nibble-definitions |
114 | 0 | double v = n.to_real (); |
115 | 0 | encode_byte (OpCode_BCD); |
116 | | |
117 | | // Based on: |
118 | | // https://github.com/fonttools/fonttools/blob/97ed3a61cde03e17b8be36f866192fbd56f1d1a7/Lib/fontTools/misc/psCharStrings.py#L265-L294 |
119 | |
|
120 | 0 | char buf[16]; |
121 | | /* FontTools has the following comment: |
122 | | * |
123 | | * # Note: 14 decimal digits seems to be the limitation for CFF real numbers |
124 | | * # in macOS. However, we use 8 here to match the implementation of AFDKO. |
125 | | * |
126 | | * We use 8 here to match FontTools X-). |
127 | | */ |
128 | |
|
129 | 0 | hb_locale_t clocale HB_UNUSED; |
130 | 0 | hb_locale_t oldlocale HB_UNUSED; |
131 | 0 | oldlocale = hb_uselocale (clocale = newlocale (LC_ALL_MASK, "C", NULL)); |
132 | 0 | snprintf (buf, sizeof (buf), "%.8G", v); |
133 | 0 | (void) hb_uselocale (((void) freelocale (clocale), oldlocale)); |
134 | |
|
135 | 0 | char *s = buf; |
136 | 0 | if (s[0] == '0' && s[1] == '.') |
137 | 0 | s++; |
138 | 0 | else if (s[0] == '-' && s[1] == '0' && s[2] == '.') |
139 | 0 | { |
140 | 0 | s[1] = '-'; |
141 | 0 | s++; |
142 | 0 | } |
143 | 0 | hb_vector_t<char> nibbles; |
144 | 0 | while (*s) |
145 | 0 | { |
146 | 0 | char c = s[0]; |
147 | 0 | s++; |
148 | |
|
149 | 0 | switch (c) |
150 | 0 | { |
151 | 0 | case 'E': |
152 | 0 | { |
153 | 0 | char c2 = *s; |
154 | 0 | if (c2 == '-') |
155 | 0 | { |
156 | 0 | s++; |
157 | 0 | nibbles.push (0x0C); // E- |
158 | 0 | continue; |
159 | 0 | } |
160 | 0 | if (c2 == '+') |
161 | 0 | s++; |
162 | 0 | nibbles.push (0x0B); // E |
163 | 0 | continue; |
164 | 0 | } |
165 | | |
166 | 0 | case '.': case ',': // Comma for some European locales in case no uselocale available. |
167 | 0 | nibbles.push (0x0A); // . |
168 | 0 | continue; |
169 | | |
170 | 0 | case '-': |
171 | 0 | nibbles.push (0x0E); // . |
172 | 0 | continue; |
173 | 0 | } |
174 | | |
175 | 0 | nibbles.push (c - '0'); |
176 | 0 | } |
177 | 0 | nibbles.push (0x0F); |
178 | 0 | if (nibbles.length % 2) |
179 | 0 | nibbles.push (0x0F); |
180 | |
|
181 | 0 | unsigned count = nibbles.length; |
182 | 0 | for (unsigned i = 0; i < count; i += 2) |
183 | 0 | encode_byte ((nibbles[i] << 4) | nibbles[i+1]); |
184 | 0 | } |
185 | 0 | } Unexecuted instantiation: CFF::str_encoder_t::encode_num_tp(CFF::number_t const&) Unexecuted instantiation: CFF::str_encoder_t::encode_num_tp(CFF::number_t const&) |
186 | | |
187 | | void encode_op (op_code_t op) |
188 | 22.7k | { |
189 | 22.7k | if (Is_OpCode_ESC (op)) |
190 | 1.24k | { |
191 | 1.24k | encode_byte (OpCode_escape); |
192 | 1.24k | encode_byte (Unmake_OpCode_ESC (op)); |
193 | 1.24k | } |
194 | 21.5k | else |
195 | 21.5k | encode_byte (op); |
196 | 22.7k | } |
197 | | |
198 | | void copy_str (const unsigned char *str, unsigned length) |
199 | 41.4k | { |
200 | 41.4k | assert ((signed) (buff.length + length) <= buff.allocated); |
201 | 0 | hb_memcpy (buff.arrayZ + buff.length, str, length); |
202 | 41.4k | buff.length += length; |
203 | 41.4k | } |
204 | | |
205 | 5.08k | bool in_error () const { return buff.in_error (); } |
206 | | |
207 | | protected: |
208 | | |
209 | | str_buff_t &buff; |
210 | | }; |
211 | | |
212 | | struct cff_sub_table_info_t { |
213 | | cff_sub_table_info_t () |
214 | | : fd_array_link (0), |
215 | | char_strings_link (0) |
216 | 2.35k | { |
217 | 2.35k | fd_select.init (); |
218 | 2.35k | } |
219 | | |
220 | | table_info_t fd_select; |
221 | | objidx_t fd_array_link; |
222 | | objidx_t char_strings_link; |
223 | | }; |
224 | | |
225 | | template <typename OPSTR=op_str_t> |
226 | | struct cff_top_dict_op_serializer_t : op_serializer_t |
227 | | { |
228 | | bool serialize (hb_serialize_context_t *c, |
229 | | const OPSTR &opstr, |
230 | | const cff_sub_table_info_t &info) const |
231 | 3.27k | { |
232 | 3.27k | TRACE_SERIALIZE (this); |
233 | | |
234 | 3.27k | switch (opstr.op) |
235 | 3.27k | { |
236 | 1.16k | case OpCode_CharStrings: |
237 | 1.16k | return_trace (FontDict::serialize_link4_op(c, opstr.op, info.char_strings_link, whence_t::Absolute)); |
238 | | |
239 | 646 | case OpCode_FDArray: |
240 | 646 | return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_array_link, whence_t::Absolute)); |
241 | | |
242 | 142 | case OpCode_FDSelect: |
243 | 142 | return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_select.link, whence_t::Absolute)); |
244 | | |
245 | 1.32k | default: |
246 | 1.32k | return_trace (copy_opstr (c, opstr)); |
247 | 3.27k | } |
248 | 3.27k | return_trace (true); |
249 | 3.27k | } CFF::cff_top_dict_op_serializer_t<CFF::cff1_top_dict_val_t>::serialize(hb_serialize_context_t*, CFF::cff1_top_dict_val_t const&, CFF::cff_sub_table_info_t const&) const Line | Count | Source | 231 | 1.78k | { | 232 | 1.78k | TRACE_SERIALIZE (this); | 233 | | | 234 | 1.78k | switch (opstr.op) | 235 | 1.78k | { | 236 | 606 | case OpCode_CharStrings: | 237 | 606 | return_trace (FontDict::serialize_link4_op(c, opstr.op, info.char_strings_link, whence_t::Absolute)); | 238 | | | 239 | 87 | case OpCode_FDArray: | 240 | 87 | return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_array_link, whence_t::Absolute)); | 241 | | | 242 | 94 | case OpCode_FDSelect: | 243 | 94 | return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_select.link, whence_t::Absolute)); | 244 | | | 245 | 994 | default: | 246 | 994 | return_trace (copy_opstr (c, opstr)); | 247 | 1.78k | } | 248 | 0 | return_trace (true); | 249 | 1.78k | } |
CFF::cff_top_dict_op_serializer_t<CFF::op_str_t>::serialize(hb_serialize_context_t*, CFF::op_str_t const&, CFF::cff_sub_table_info_t const&) const Line | Count | Source | 231 | 1.49k | { | 232 | 1.49k | TRACE_SERIALIZE (this); | 233 | | | 234 | 1.49k | switch (opstr.op) | 235 | 1.49k | { | 236 | 559 | case OpCode_CharStrings: | 237 | 559 | return_trace (FontDict::serialize_link4_op(c, opstr.op, info.char_strings_link, whence_t::Absolute)); | 238 | | | 239 | 559 | case OpCode_FDArray: | 240 | 559 | return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_array_link, whence_t::Absolute)); | 241 | | | 242 | 48 | case OpCode_FDSelect: | 243 | 48 | return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_select.link, whence_t::Absolute)); | 244 | | | 245 | 330 | default: | 246 | 330 | return_trace (copy_opstr (c, opstr)); | 247 | 1.49k | } | 248 | 0 | return_trace (true); | 249 | 1.49k | } |
|
250 | | }; |
251 | | |
252 | | struct cff_font_dict_op_serializer_t : op_serializer_t |
253 | | { |
254 | | bool serialize (hb_serialize_context_t *c, |
255 | | const op_str_t &opstr, |
256 | | const table_info_t &privateDictInfo) const |
257 | 713 | { |
258 | 713 | TRACE_SERIALIZE (this); |
259 | | |
260 | 713 | if (opstr.op == OpCode_Private) |
261 | 703 | { |
262 | | /* serialize the private dict size & offset as 2-byte & 4-byte integers */ |
263 | 703 | return_trace (UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) && |
264 | 703 | Dict::serialize_link4_op (c, opstr.op, privateDictInfo.link, whence_t::Absolute)); |
265 | 703 | } |
266 | 10 | else |
267 | 10 | { |
268 | 10 | unsigned char *d = c->allocate_size<unsigned char> (opstr.length); |
269 | 10 | if (unlikely (!d)) return_trace (false); |
270 | | /* Faster than hb_memcpy for small strings. */ |
271 | 82 | for (unsigned i = 0; i < opstr.length; i++) |
272 | 73 | d[i] = opstr.ptr[i]; |
273 | | //hb_memcpy (d, opstr.ptr, opstr.length); |
274 | 9 | } |
275 | 713 | return_trace (true); |
276 | 713 | } |
277 | | }; |
278 | | |
279 | | struct flatten_param_t |
280 | | { |
281 | | str_buff_t &flatStr; |
282 | | bool drop_hints; |
283 | | const hb_subset_plan_t *plan; |
284 | | }; |
285 | | |
286 | | template <typename ACC, typename ENV, typename OPSET, op_code_t endchar_op=OpCode_Invalid> |
287 | | struct subr_flattener_t |
288 | | { |
289 | | subr_flattener_t (const ACC &acc_, |
290 | | const hb_subset_plan_t *plan_) |
291 | 534 | : acc (acc_), plan (plan_) {} CFF::subr_flattener_t<OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_flatten_t, 14u>::subr_flattener_t(OT::cff1::accelerator_subset_t const&, hb_subset_plan_t const*) Line | Count | Source | 291 | 260 | : acc (acc_), plan (plan_) {} |
CFF::subr_flattener_t<OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_flatten_t, 65535u>::subr_flattener_t(OT::cff2::accelerator_subset_t const&, hb_subset_plan_t const*) Line | Count | Source | 291 | 274 | : acc (acc_), plan (plan_) {} |
|
292 | | |
293 | | bool flatten (str_buff_vec_t &flat_charstrings) |
294 | 534 | { |
295 | 534 | unsigned count = plan->num_output_glyphs (); |
296 | 534 | if (!flat_charstrings.resize_exact (count)) |
297 | 3 | return false; |
298 | 1.68k | for (unsigned int i = 0; i < count; i++) |
299 | 1.46k | { |
300 | 1.46k | hb_codepoint_t glyph; |
301 | 1.46k | if (!plan->old_gid_for_new_gid (i, &glyph)) |
302 | 765 | { |
303 | | /* add an endchar only charstring for a missing glyph if CFF1 */ |
304 | 765 | if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op); |
305 | 765 | continue; |
306 | 765 | } |
307 | 701 | const hb_ubytes_t str = (*acc.charStrings)[glyph]; |
308 | 701 | unsigned int fd = acc.fdSelect->get_fd (glyph); |
309 | 701 | if (unlikely (fd >= acc.fdCount)) |
310 | 7 | return false; |
311 | | |
312 | | |
313 | 694 | ENV env (str, acc, fd, |
314 | 694 | plan->normalized_coords.arrayZ, plan->normalized_coords.length); |
315 | 694 | cs_interpreter_t<ENV, OPSET, flatten_param_t> interp (env); |
316 | 694 | flatten_param_t param = { |
317 | 694 | flat_charstrings.arrayZ[i], |
318 | 694 | (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING), |
319 | 694 | plan |
320 | 694 | }; |
321 | 694 | if (unlikely (!interp.interpret (param))) |
322 | 307 | return false; |
323 | 694 | } |
324 | 217 | return true; |
325 | 531 | } CFF::subr_flattener_t<OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_flatten_t, 14u>::flatten(hb_vector_t<hb_vector_t<unsigned char, false>, false>&) Line | Count | Source | 294 | 260 | { | 295 | 260 | unsigned count = plan->num_output_glyphs (); | 296 | 260 | if (!flat_charstrings.resize_exact (count)) | 297 | 3 | return false; | 298 | 1.07k | for (unsigned int i = 0; i < count; i++) | 299 | 970 | { | 300 | 970 | hb_codepoint_t glyph; | 301 | 970 | if (!plan->old_gid_for_new_gid (i, &glyph)) | 302 | 602 | { | 303 | | /* add an endchar only charstring for a missing glyph if CFF1 */ | 304 | 602 | if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op); | 305 | 602 | continue; | 306 | 602 | } | 307 | 368 | const hb_ubytes_t str = (*acc.charStrings)[glyph]; | 308 | 368 | unsigned int fd = acc.fdSelect->get_fd (glyph); | 309 | 368 | if (unlikely (fd >= acc.fdCount)) | 310 | 3 | return false; | 311 | | | 312 | | | 313 | 365 | ENV env (str, acc, fd, | 314 | 365 | plan->normalized_coords.arrayZ, plan->normalized_coords.length); | 315 | 365 | cs_interpreter_t<ENV, OPSET, flatten_param_t> interp (env); | 316 | 365 | flatten_param_t param = { | 317 | 365 | flat_charstrings.arrayZ[i], | 318 | 365 | (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING), | 319 | 365 | plan | 320 | 365 | }; | 321 | 365 | if (unlikely (!interp.interpret (param))) | 322 | 151 | return false; | 323 | 365 | } | 324 | 103 | return true; | 325 | 257 | } |
CFF::subr_flattener_t<OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_flatten_t, 65535u>::flatten(hb_vector_t<hb_vector_t<unsigned char, false>, false>&) Line | Count | Source | 294 | 274 | { | 295 | 274 | unsigned count = plan->num_output_glyphs (); | 296 | 274 | if (!flat_charstrings.resize_exact (count)) | 297 | 0 | return false; | 298 | 610 | for (unsigned int i = 0; i < count; i++) | 299 | 496 | { | 300 | 496 | hb_codepoint_t glyph; | 301 | 496 | if (!plan->old_gid_for_new_gid (i, &glyph)) | 302 | 163 | { | 303 | | /* add an endchar only charstring for a missing glyph if CFF1 */ | 304 | 163 | if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op); | 305 | 163 | continue; | 306 | 163 | } | 307 | 333 | const hb_ubytes_t str = (*acc.charStrings)[glyph]; | 308 | 333 | unsigned int fd = acc.fdSelect->get_fd (glyph); | 309 | 333 | if (unlikely (fd >= acc.fdCount)) | 310 | 4 | return false; | 311 | | | 312 | | | 313 | 329 | ENV env (str, acc, fd, | 314 | 329 | plan->normalized_coords.arrayZ, plan->normalized_coords.length); | 315 | 329 | cs_interpreter_t<ENV, OPSET, flatten_param_t> interp (env); | 316 | 329 | flatten_param_t param = { | 317 | 329 | flat_charstrings.arrayZ[i], | 318 | 329 | (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING), | 319 | 329 | plan | 320 | 329 | }; | 321 | 329 | if (unlikely (!interp.interpret (param))) | 322 | 156 | return false; | 323 | 329 | } | 324 | 114 | return true; | 325 | 274 | } |
|
326 | | |
327 | | const ACC &acc; |
328 | | const hb_subset_plan_t *plan; |
329 | | }; |
330 | | |
331 | | struct subr_closures_t |
332 | | { |
333 | | subr_closures_t (unsigned int fd_count) : global_closure (), local_closures () |
334 | 1.80k | { |
335 | 1.80k | local_closures.resize_exact (fd_count); |
336 | 1.80k | } |
337 | | |
338 | | void reset () |
339 | 201 | { |
340 | 201 | global_closure.clear(); |
341 | 442 | for (unsigned int i = 0; i < local_closures.length; i++) |
342 | 241 | local_closures[i].clear(); |
343 | 201 | } |
344 | | |
345 | 1.79k | bool in_error () const { return local_closures.in_error (); } |
346 | | hb_set_t global_closure; |
347 | | hb_vector_t<hb_set_t> local_closures; |
348 | | }; |
349 | | |
350 | | struct parsed_cs_op_t : op_str_t |
351 | | { |
352 | | parsed_cs_op_t (unsigned int subr_num_ = 0) : |
353 | 195k | subr_num (subr_num_) {} |
354 | | |
355 | 201k | bool is_hinting () const { return hinting_flag; } |
356 | 5.82k | void set_hinting () { hinting_flag = true; } |
357 | | |
358 | | /* The layout of this struct is designed to fit within the |
359 | | * padding of op_str_t! */ |
360 | | |
361 | | protected: |
362 | | bool hinting_flag = false; |
363 | | |
364 | | public: |
365 | | uint16_t subr_num; |
366 | | }; |
367 | | |
368 | | struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t> |
369 | | { |
370 | | parsed_cs_str_t () : |
371 | | parsed (false), |
372 | | hint_dropped (false), |
373 | | has_prefix_ (false), |
374 | | has_calls_ (false) |
375 | 242k | { |
376 | 242k | SUPER::init (); |
377 | 242k | } |
378 | | |
379 | | void add_op (op_code_t op, const byte_str_ref_t& str_ref) |
380 | 263k | { |
381 | 263k | if (!is_parsed ()) |
382 | 189k | SUPER::add_op (op, str_ref); |
383 | 263k | } |
384 | | |
385 | | void add_call_op (op_code_t op, const byte_str_ref_t& str_ref, unsigned int subr_num) |
386 | 6.90k | { |
387 | 6.90k | if (!is_parsed ()) |
388 | 6.16k | { |
389 | 6.16k | has_calls_ = true; |
390 | | |
391 | | /* Pop the subroutine number. */ |
392 | 6.16k | values.pop (); |
393 | | |
394 | 6.16k | SUPER::add_op (op, str_ref, {subr_num}); |
395 | 6.16k | } |
396 | 6.90k | } |
397 | | |
398 | | void set_prefix (const number_t &num, op_code_t op = OpCode_Invalid) |
399 | 866 | { |
400 | 866 | has_prefix_ = true; |
401 | 866 | prefix_op_ = op; |
402 | 866 | prefix_num_ = num; |
403 | 866 | } |
404 | | |
405 | | bool at_end (unsigned int pos) const |
406 | 916 | { |
407 | 916 | return ((pos + 1 >= values.length) /* CFF2 */ |
408 | 916 | || (values[pos + 1].op == OpCode_return)); |
409 | 916 | } |
410 | | |
411 | 289k | bool is_parsed () const { return parsed; } |
412 | 10.6k | void set_parsed () { parsed = true; } |
413 | | |
414 | 117 | bool is_hint_dropped () const { return hint_dropped; } |
415 | 137 | void set_hint_dropped () { hint_dropped = true; } |
416 | | |
417 | 0 | bool is_vsindex_dropped () const { return vsindex_dropped; } |
418 | 1 | void set_vsindex_dropped () { vsindex_dropped = true; } |
419 | | |
420 | 5.09k | bool has_prefix () const { return has_prefix_; } |
421 | 46 | op_code_t prefix_op () const { return prefix_op_; } |
422 | 42 | const number_t &prefix_num () const { return prefix_num_; } |
423 | | |
424 | 618 | bool has_calls () const { return has_calls_; } |
425 | | |
426 | | void compact () |
427 | 2.90k | { |
428 | 2.90k | unsigned count = values.length; |
429 | 2.90k | if (!count) return; |
430 | 2.15k | auto &opstr = values.arrayZ; |
431 | 2.15k | unsigned j = 0; |
432 | 98.1k | for (unsigned i = 1; i < count; i++) |
433 | 95.9k | { |
434 | | /* See if we can combine op j and op i. */ |
435 | 95.9k | bool combine = |
436 | 95.9k | (opstr[j].op != OpCode_callsubr && opstr[j].op != OpCode_callgsubr) && |
437 | 95.9k | (opstr[i].op != OpCode_callsubr && opstr[i].op != OpCode_callgsubr) && |
438 | 95.9k | (opstr[j].is_hinting () == opstr[i].is_hinting ()) && |
439 | 95.9k | (opstr[j].ptr + opstr[j].length == opstr[i].ptr) && |
440 | 95.9k | (opstr[j].length + opstr[i].length <= 255); |
441 | | |
442 | 95.9k | if (combine) |
443 | 91.2k | { |
444 | 91.2k | opstr[j].length += opstr[i].length; |
445 | 91.2k | opstr[j].op = OpCode_Invalid; |
446 | 91.2k | } |
447 | 4.72k | else |
448 | 4.72k | { |
449 | 4.72k | opstr[++j] = opstr[i]; |
450 | 4.72k | } |
451 | 95.9k | } |
452 | 2.15k | values.shrink (j + 1); |
453 | 2.15k | } |
454 | | |
455 | | protected: |
456 | | bool parsed : 1; |
457 | | bool hint_dropped : 1; |
458 | | bool vsindex_dropped : 1; |
459 | | bool has_prefix_ : 1; |
460 | | bool has_calls_ : 1; |
461 | | op_code_t prefix_op_; |
462 | | number_t prefix_num_; |
463 | | |
464 | | private: |
465 | | typedef parsed_values_t<parsed_cs_op_t> SUPER; |
466 | | }; |
467 | | |
468 | | struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_t> |
469 | | { |
470 | | private: |
471 | | typedef hb_vector_t<parsed_cs_str_t> SUPER; |
472 | | }; |
473 | | |
474 | | struct cff_subset_accelerator_t |
475 | | { |
476 | | static cff_subset_accelerator_t* create ( |
477 | | hb_blob_t* original_blob, |
478 | | const parsed_cs_str_vec_t& parsed_charstrings, |
479 | | const parsed_cs_str_vec_t& parsed_global_subrs, |
480 | 0 | const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs) { |
481 | 0 | cff_subset_accelerator_t* accel = |
482 | 0 | (cff_subset_accelerator_t*) hb_malloc (sizeof(cff_subset_accelerator_t)); |
483 | 0 | if (unlikely (!accel)) return nullptr; |
484 | 0 | new (accel) cff_subset_accelerator_t (original_blob, |
485 | 0 | parsed_charstrings, |
486 | 0 | parsed_global_subrs, |
487 | 0 | parsed_local_subrs); |
488 | 0 | return accel; |
489 | 0 | } Unexecuted instantiation: CFF::cff_subset_accelerator_t::create(hb_blob_t*, CFF::parsed_cs_str_vec_t const&, CFF::parsed_cs_str_vec_t const&, hb_vector_t<CFF::parsed_cs_str_vec_t, false> const&) Unexecuted instantiation: CFF::cff_subset_accelerator_t::create(hb_blob_t*, CFF::parsed_cs_str_vec_t const&, CFF::parsed_cs_str_vec_t const&, hb_vector_t<CFF::parsed_cs_str_vec_t, false> const&) |
490 | | |
491 | 0 | static void destroy (void* value) { |
492 | 0 | if (!value) return; |
493 | | |
494 | 0 | cff_subset_accelerator_t* accel = (cff_subset_accelerator_t*) value; |
495 | 0 | accel->~cff_subset_accelerator_t (); |
496 | 0 | hb_free (accel); |
497 | 0 | } Unexecuted instantiation: CFF::cff_subset_accelerator_t::destroy(void*) Unexecuted instantiation: CFF::cff_subset_accelerator_t::destroy(void*) |
498 | | |
499 | | cff_subset_accelerator_t( |
500 | | hb_blob_t* original_blob_, |
501 | | const parsed_cs_str_vec_t& parsed_charstrings_, |
502 | | const parsed_cs_str_vec_t& parsed_global_subrs_, |
503 | | const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs_) |
504 | 0 | { |
505 | 0 | parsed_charstrings = parsed_charstrings_; |
506 | 0 | parsed_global_subrs = parsed_global_subrs_; |
507 | 0 | parsed_local_subrs = parsed_local_subrs_; |
508 | 0 |
|
509 | 0 | // the parsed charstrings point to memory in the original CFF table so we must hold a reference |
510 | 0 | // to it to keep the memory valid. |
511 | 0 | original_blob = hb_blob_reference (original_blob_); |
512 | 0 | } |
513 | | |
514 | | ~cff_subset_accelerator_t() |
515 | 0 | { |
516 | 0 | hb_blob_destroy (original_blob); |
517 | 0 | auto *mapping = glyph_to_sid_map.get_relaxed (); |
518 | 0 | if (mapping) |
519 | 0 | { |
520 | 0 | mapping->~glyph_to_sid_map_t (); |
521 | 0 | hb_free (mapping); |
522 | 0 | } |
523 | 0 | } Unexecuted instantiation: CFF::cff_subset_accelerator_t::~cff_subset_accelerator_t() Unexecuted instantiation: CFF::cff_subset_accelerator_t::~cff_subset_accelerator_t() |
524 | | |
525 | | parsed_cs_str_vec_t parsed_charstrings; |
526 | | parsed_cs_str_vec_t parsed_global_subrs; |
527 | | hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs; |
528 | | mutable hb_atomic_ptr_t<glyph_to_sid_map_t> glyph_to_sid_map; |
529 | | |
530 | | private: |
531 | | hb_blob_t* original_blob; |
532 | | }; |
533 | | |
534 | | struct subr_subset_param_t |
535 | | { |
536 | | subr_subset_param_t (parsed_cs_str_t *parsed_charstring_, |
537 | | parsed_cs_str_vec_t *parsed_global_subrs_, |
538 | | parsed_cs_str_vec_t *parsed_local_subrs_, |
539 | | hb_set_t *global_closure_, |
540 | | hb_set_t *local_closure_, |
541 | | bool drop_hints_) : |
542 | | current_parsed_str (parsed_charstring_), |
543 | | parsed_charstring (parsed_charstring_), |
544 | | parsed_global_subrs (parsed_global_subrs_), |
545 | | parsed_local_subrs (parsed_local_subrs_), |
546 | | global_closure (global_closure_), |
547 | | local_closure (local_closure_), |
548 | 4.36k | drop_hints (drop_hints_) {} |
549 | | |
550 | | parsed_cs_str_t *get_parsed_str_for_context (call_context_t &context) |
551 | 13.1k | { |
552 | 13.1k | switch (context.type) |
553 | 13.1k | { |
554 | 3.25k | case CSType_CharString: |
555 | 3.25k | return parsed_charstring; |
556 | | |
557 | 7.19k | case CSType_LocalSubr: |
558 | 7.19k | if (likely (context.subr_num < parsed_local_subrs->length)) |
559 | 7.19k | return &(*parsed_local_subrs)[context.subr_num]; |
560 | 0 | break; |
561 | | |
562 | 2.66k | case CSType_GlobalSubr: |
563 | 2.66k | if (likely (context.subr_num < parsed_global_subrs->length)) |
564 | 2.66k | return &(*parsed_global_subrs)[context.subr_num]; |
565 | 0 | break; |
566 | 13.1k | } |
567 | 0 | return nullptr; |
568 | 13.1k | } |
569 | | |
570 | | template <typename ENV> |
571 | | void set_current_str (ENV &env, bool calling) |
572 | 12.6k | { |
573 | 12.6k | parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context); |
574 | 12.6k | if (unlikely (!parsed_str)) |
575 | 0 | { |
576 | 0 | env.set_error (); |
577 | 0 | return; |
578 | 0 | } |
579 | | /* If the called subroutine is parsed partially but not completely yet, |
580 | | * it must be because we are calling it recursively. |
581 | | * Handle it as an error. */ |
582 | 12.6k | if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0))) |
583 | 193 | env.set_error (); |
584 | 12.4k | else |
585 | 12.4k | { |
586 | 12.4k | if (!parsed_str->is_parsed ()) |
587 | 9.17k | parsed_str->alloc (env.str_ref.total_size ()); |
588 | 12.4k | current_parsed_str = parsed_str; |
589 | 12.4k | } |
590 | 12.6k | } void CFF::subr_subset_param_t::set_current_str<CFF::cff1_cs_interp_env_t>(CFF::cff1_cs_interp_env_t&, bool) Line | Count | Source | 572 | 4.78k | { | 573 | 4.78k | parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context); | 574 | 4.78k | if (unlikely (!parsed_str)) | 575 | 0 | { | 576 | 0 | env.set_error (); | 577 | 0 | return; | 578 | 0 | } | 579 | | /* If the called subroutine is parsed partially but not completely yet, | 580 | | * it must be because we are calling it recursively. | 581 | | * Handle it as an error. */ | 582 | 4.78k | if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0))) | 583 | 97 | env.set_error (); | 584 | 4.68k | else | 585 | 4.68k | { | 586 | 4.68k | if (!parsed_str->is_parsed ()) | 587 | 3.18k | parsed_str->alloc (env.str_ref.total_size ()); | 588 | 4.68k | current_parsed_str = parsed_str; | 589 | 4.68k | } | 590 | 4.78k | } |
void CFF::subr_subset_param_t::set_current_str<CFF::cff2_cs_interp_env_t<CFF::blend_arg_t> >(CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>&, bool) Line | Count | Source | 572 | 7.85k | { | 573 | 7.85k | parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context); | 574 | 7.85k | if (unlikely (!parsed_str)) | 575 | 0 | { | 576 | 0 | env.set_error (); | 577 | 0 | return; | 578 | 0 | } | 579 | | /* If the called subroutine is parsed partially but not completely yet, | 580 | | * it must be because we are calling it recursively. | 581 | | * Handle it as an error. */ | 582 | 7.85k | if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0))) | 583 | 96 | env.set_error (); | 584 | 7.76k | else | 585 | 7.76k | { | 586 | 7.76k | if (!parsed_str->is_parsed ()) | 587 | 5.99k | parsed_str->alloc (env.str_ref.total_size ()); | 588 | 7.76k | current_parsed_str = parsed_str; | 589 | 7.76k | } | 590 | 7.85k | } |
|
591 | | |
592 | | parsed_cs_str_t *current_parsed_str; |
593 | | |
594 | | parsed_cs_str_t *parsed_charstring; |
595 | | parsed_cs_str_vec_t *parsed_global_subrs; |
596 | | parsed_cs_str_vec_t *parsed_local_subrs; |
597 | | hb_set_t *global_closure; |
598 | | hb_set_t *local_closure; |
599 | | bool drop_hints; |
600 | | }; |
601 | | |
602 | | struct subr_remap_t : hb_inc_bimap_t |
603 | | { |
604 | | void create (const hb_set_t *closure) |
605 | 4.79k | { |
606 | | /* create a remapping of subroutine numbers from old to new. |
607 | | * no optimization based on usage counts. fonttools doesn't appear doing that either. |
608 | | */ |
609 | | |
610 | 4.79k | alloc (closure->get_population ()); |
611 | 4.79k | for (auto old_num : *closure) |
612 | 2.66k | add (old_num); |
613 | | |
614 | 4.79k | if (get_population () < 1240) |
615 | 4.79k | bias = 107; |
616 | 0 | else if (get_population () < 33900) |
617 | 0 | bias = 1131; |
618 | 0 | else |
619 | 0 | bias = 32768; |
620 | 4.79k | } |
621 | | |
622 | | int biased_num (unsigned int old_num) const |
623 | 3.86k | { |
624 | 3.86k | hb_codepoint_t new_num = get (old_num); |
625 | 3.86k | return (int)new_num - bias; |
626 | 3.86k | } |
627 | | |
628 | | protected: |
629 | | int bias; |
630 | | }; |
631 | | |
632 | | struct subr_remaps_t |
633 | | { |
634 | | subr_remaps_t (unsigned int fdCount) |
635 | 1.80k | { |
636 | 1.80k | local_remaps.resize (fdCount); |
637 | 1.80k | } |
638 | | |
639 | | bool in_error() |
640 | 1.79k | { |
641 | 1.79k | return local_remaps.in_error (); |
642 | 1.79k | } |
643 | | |
644 | | void create (subr_closures_t& closures) |
645 | 1.00k | { |
646 | 1.00k | global_remap.create (&closures.global_closure); |
647 | 4.79k | for (unsigned int i = 0; i < local_remaps.length; i++) |
648 | 3.79k | local_remaps.arrayZ[i].create (&closures.local_closures[i]); |
649 | 1.00k | } |
650 | | |
651 | | subr_remap_t global_remap; |
652 | | hb_vector_t<subr_remap_t> local_remaps; |
653 | | }; |
654 | | |
655 | | template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typename OPSET, op_code_t endchar_op=OpCode_Invalid> |
656 | | struct subr_subsetter_t |
657 | | { |
658 | | subr_subsetter_t (ACC &acc_, const hb_subset_plan_t *plan_) |
659 | | : acc (acc_), plan (plan_), closures(acc_.fdCount), |
660 | | remaps(acc_.fdCount) |
661 | 1.80k | {} CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::subr_subsetter_t(OT::cff1::accelerator_subset_t const&, hb_subset_plan_t const*) Line | Count | Source | 661 | 1.02k | {} |
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::subr_subsetter_t(OT::cff2::accelerator_subset_t const&, hb_subset_plan_t const*) Line | Count | Source | 661 | 778 | {} |
|
662 | | |
663 | | /* Subroutine subsetting with --no-desubroutinize runs in phases: |
664 | | * |
665 | | * 1. execute charstrings/subroutines to determine subroutine closures |
666 | | * 2. parse out all operators and numbers |
667 | | * 3. mark hint operators and operands for removal if --no-hinting |
668 | | * 4. re-encode all charstrings and subroutines with new subroutine numbers |
669 | | * |
670 | | * Phases #1 and #2 are done at the same time in collect_subrs (). |
671 | | * Phase #3 walks charstrings/subroutines forward then backward (hence parsing required), |
672 | | * because we can't tell if a number belongs to a hint op until we see the first moveto. |
673 | | * |
674 | | * Assumption: a callsubr/callgsubr operator must immediately follow a (biased) subroutine number |
675 | | * within the same charstring/subroutine, e.g., not split across a charstring and a subroutine. |
676 | | */ |
677 | | bool subset (void) |
678 | 1.80k | { |
679 | 1.80k | unsigned fd_count = acc.fdCount; |
680 | 1.80k | const cff_subset_accelerator_t* cff_accelerator = nullptr; |
681 | 1.80k | if (acc.cff_accelerator) { |
682 | 0 | cff_accelerator = acc.cff_accelerator; |
683 | 0 | fd_count = cff_accelerator->parsed_local_subrs.length; |
684 | 0 | } |
685 | | |
686 | 1.80k | if (cff_accelerator) { |
687 | | // If we are not dropping hinting then charstrings are not modified so we can |
688 | | // just use a reference to the cached copies. |
689 | 0 | cached_charstrings.resize_exact (plan->num_output_glyphs ()); |
690 | 0 | parsed_global_subrs = &cff_accelerator->parsed_global_subrs; |
691 | 0 | parsed_local_subrs = &cff_accelerator->parsed_local_subrs; |
692 | 1.80k | } else { |
693 | 1.80k | parsed_charstrings.resize_exact (plan->num_output_glyphs ()); |
694 | 1.80k | parsed_global_subrs_storage.resize_exact (acc.globalSubrs->count); |
695 | | |
696 | 1.80k | if (unlikely (!parsed_local_subrs_storage.resize (fd_count))) return false; |
697 | | |
698 | 6.53k | for (unsigned int i = 0; i < acc.fdCount; i++) |
699 | 4.73k | { |
700 | 4.73k | unsigned count = acc.privateDicts[i].localSubrs->count; |
701 | 4.73k | parsed_local_subrs_storage[i].resize (count); |
702 | 4.73k | if (unlikely (parsed_local_subrs_storage[i].in_error ())) return false; |
703 | 4.73k | } |
704 | | |
705 | 1.79k | parsed_global_subrs = &parsed_global_subrs_storage; |
706 | 1.79k | parsed_local_subrs = &parsed_local_subrs_storage; |
707 | 1.79k | } |
708 | | |
709 | 1.79k | if (unlikely (remaps.in_error() |
710 | 1.79k | || cached_charstrings.in_error () |
711 | 1.79k | || parsed_charstrings.in_error () |
712 | 1.79k | || parsed_global_subrs->in_error () |
713 | 1.79k | || closures.in_error ())) { |
714 | 9 | return false; |
715 | 9 | } |
716 | | |
717 | | /* phase 1 & 2 */ |
718 | 1.78k | for (auto _ : plan->new_to_old_gid_list) |
719 | 3.69k | { |
720 | 3.69k | hb_codepoint_t new_glyph = _.first; |
721 | 3.69k | hb_codepoint_t old_glyph = _.second; |
722 | | |
723 | 3.69k | const hb_ubytes_t str = (*acc.charStrings)[old_glyph]; |
724 | 3.69k | unsigned int fd = acc.fdSelect->get_fd (old_glyph); |
725 | 3.69k | if (unlikely (fd >= acc.fdCount)) |
726 | 35 | return false; |
727 | | |
728 | 3.66k | if (cff_accelerator) |
729 | 0 | { |
730 | | // parsed string already exists in accelerator, copy it and move |
731 | | // on. |
732 | 0 | if (cached_charstrings) |
733 | 0 | cached_charstrings[new_glyph] = &cff_accelerator->parsed_charstrings[old_glyph]; |
734 | 0 | else |
735 | 0 | parsed_charstrings[new_glyph] = cff_accelerator->parsed_charstrings[old_glyph]; |
736 | |
|
737 | 0 | continue; |
738 | 0 | } |
739 | | |
740 | 3.66k | ENV env (str, acc, fd); |
741 | 3.66k | cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp (env); |
742 | | |
743 | 3.66k | parsed_charstrings[new_glyph].alloc (str.length); |
744 | 3.66k | subr_subset_param_t param (&parsed_charstrings[new_glyph], |
745 | 3.66k | &parsed_global_subrs_storage, |
746 | 3.66k | &parsed_local_subrs_storage[fd], |
747 | 3.66k | &closures.global_closure, |
748 | 3.66k | &closures.local_closures[fd], |
749 | 3.66k | plan->flags & HB_SUBSET_FLAGS_NO_HINTING); |
750 | | |
751 | 3.66k | if (unlikely (!interp.interpret (param))) |
752 | 752 | return false; |
753 | | |
754 | | /* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */ |
755 | 2.90k | SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[new_glyph]); |
756 | | |
757 | | /* mark hint ops and arguments for drop */ |
758 | 2.90k | if ((plan->flags & HB_SUBSET_FLAGS_NO_HINTING) || plan->inprogress_accelerator) |
759 | 359 | { |
760 | 359 | subr_subset_param_t param (&parsed_charstrings[new_glyph], |
761 | 359 | &parsed_global_subrs_storage, |
762 | 359 | &parsed_local_subrs_storage[fd], |
763 | 359 | &closures.global_closure, |
764 | 359 | &closures.local_closures[fd], |
765 | 359 | plan->flags & HB_SUBSET_FLAGS_NO_HINTING); |
766 | | |
767 | 359 | drop_hints_param_t drop; |
768 | 359 | if (drop_hints_in_str (parsed_charstrings[new_glyph], param, drop)) |
769 | 137 | { |
770 | 137 | parsed_charstrings[new_glyph].set_hint_dropped (); |
771 | 137 | if (drop.vsindex_dropped) |
772 | 1 | parsed_charstrings[new_glyph].set_vsindex_dropped (); |
773 | 137 | } |
774 | 359 | } |
775 | | |
776 | | /* Doing this here one by one instead of compacting all at the end |
777 | | * has massive peak-memory saving. |
778 | | * |
779 | | * The compacting both saves memory and makes further operations |
780 | | * faster. |
781 | | */ |
782 | 2.90k | parsed_charstrings[new_glyph].compact (); |
783 | 2.90k | } |
784 | | |
785 | | /* Since parsed strings were loaded from accelerator, we still need |
786 | | * to compute the subroutine closures which would have normally happened during |
787 | | * parsing. |
788 | | * |
789 | | * Or if we are dropping hinting, redo closure to get actually used subrs. |
790 | | */ |
791 | 1.00k | if ((cff_accelerator || |
792 | 1.00k | (!cff_accelerator && plan->flags & HB_SUBSET_FLAGS_NO_HINTING)) && |
793 | 1.00k | !closure_subroutines(*parsed_global_subrs, |
794 | 201 | *parsed_local_subrs)) |
795 | 0 | return false; |
796 | | |
797 | 1.00k | remaps.create (closures); |
798 | | |
799 | 1.00k | populate_subset_accelerator (); |
800 | 1.00k | return true; |
801 | 1.00k | } CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::subset() Line | Count | Source | 678 | 1.02k | { | 679 | 1.02k | unsigned fd_count = acc.fdCount; | 680 | 1.02k | const cff_subset_accelerator_t* cff_accelerator = nullptr; | 681 | 1.02k | if (acc.cff_accelerator) { | 682 | 0 | cff_accelerator = acc.cff_accelerator; | 683 | 0 | fd_count = cff_accelerator->parsed_local_subrs.length; | 684 | 0 | } | 685 | | | 686 | 1.02k | if (cff_accelerator) { | 687 | | // If we are not dropping hinting then charstrings are not modified so we can | 688 | | // just use a reference to the cached copies. | 689 | 0 | cached_charstrings.resize_exact (plan->num_output_glyphs ()); | 690 | 0 | parsed_global_subrs = &cff_accelerator->parsed_global_subrs; | 691 | 0 | parsed_local_subrs = &cff_accelerator->parsed_local_subrs; | 692 | 1.02k | } else { | 693 | 1.02k | parsed_charstrings.resize_exact (plan->num_output_glyphs ()); | 694 | 1.02k | parsed_global_subrs_storage.resize_exact (acc.globalSubrs->count); | 695 | | | 696 | 1.02k | if (unlikely (!parsed_local_subrs_storage.resize (fd_count))) return false; | 697 | | | 698 | 4.93k | for (unsigned int i = 0; i < acc.fdCount; i++) | 699 | 3.91k | { | 700 | 3.91k | unsigned count = acc.privateDicts[i].localSubrs->count; | 701 | 3.91k | parsed_local_subrs_storage[i].resize (count); | 702 | 3.91k | if (unlikely (parsed_local_subrs_storage[i].in_error ())) return false; | 703 | 3.91k | } | 704 | | | 705 | 1.02k | parsed_global_subrs = &parsed_global_subrs_storage; | 706 | 1.02k | parsed_local_subrs = &parsed_local_subrs_storage; | 707 | 1.02k | } | 708 | | | 709 | 1.02k | if (unlikely (remaps.in_error() | 710 | 1.02k | || cached_charstrings.in_error () | 711 | 1.02k | || parsed_charstrings.in_error () | 712 | 1.02k | || parsed_global_subrs->in_error () | 713 | 1.02k | || closures.in_error ())) { | 714 | 6 | return false; | 715 | 6 | } | 716 | | | 717 | | /* phase 1 & 2 */ | 718 | 1.01k | for (auto _ : plan->new_to_old_gid_list) | 719 | 2.01k | { | 720 | 2.01k | hb_codepoint_t new_glyph = _.first; | 721 | 2.01k | hb_codepoint_t old_glyph = _.second; | 722 | | | 723 | 2.01k | const hb_ubytes_t str = (*acc.charStrings)[old_glyph]; | 724 | 2.01k | unsigned int fd = acc.fdSelect->get_fd (old_glyph); | 725 | 2.01k | if (unlikely (fd >= acc.fdCount)) | 726 | 18 | return false; | 727 | | | 728 | 1.99k | if (cff_accelerator) | 729 | 0 | { | 730 | | // parsed string already exists in accelerator, copy it and move | 731 | | // on. | 732 | 0 | if (cached_charstrings) | 733 | 0 | cached_charstrings[new_glyph] = &cff_accelerator->parsed_charstrings[old_glyph]; | 734 | 0 | else | 735 | 0 | parsed_charstrings[new_glyph] = cff_accelerator->parsed_charstrings[old_glyph]; | 736 | |
| 737 | 0 | continue; | 738 | 0 | } | 739 | | | 740 | 1.99k | ENV env (str, acc, fd); | 741 | 1.99k | cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp (env); | 742 | | | 743 | 1.99k | parsed_charstrings[new_glyph].alloc (str.length); | 744 | 1.99k | subr_subset_param_t param (&parsed_charstrings[new_glyph], | 745 | 1.99k | &parsed_global_subrs_storage, | 746 | 1.99k | &parsed_local_subrs_storage[fd], | 747 | 1.99k | &closures.global_closure, | 748 | 1.99k | &closures.local_closures[fd], | 749 | 1.99k | plan->flags & HB_SUBSET_FLAGS_NO_HINTING); | 750 | | | 751 | 1.99k | if (unlikely (!interp.interpret (param))) | 752 | 455 | return false; | 753 | | | 754 | | /* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */ | 755 | 1.53k | SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[new_glyph]); | 756 | | | 757 | | /* mark hint ops and arguments for drop */ | 758 | 1.53k | if ((plan->flags & HB_SUBSET_FLAGS_NO_HINTING) || plan->inprogress_accelerator) | 759 | 250 | { | 760 | 250 | subr_subset_param_t param (&parsed_charstrings[new_glyph], | 761 | 250 | &parsed_global_subrs_storage, | 762 | 250 | &parsed_local_subrs_storage[fd], | 763 | 250 | &closures.global_closure, | 764 | 250 | &closures.local_closures[fd], | 765 | 250 | plan->flags & HB_SUBSET_FLAGS_NO_HINTING); | 766 | | | 767 | 250 | drop_hints_param_t drop; | 768 | 250 | if (drop_hints_in_str (parsed_charstrings[new_glyph], param, drop)) | 769 | 90 | { | 770 | 90 | parsed_charstrings[new_glyph].set_hint_dropped (); | 771 | 90 | if (drop.vsindex_dropped) | 772 | 0 | parsed_charstrings[new_glyph].set_vsindex_dropped (); | 773 | 90 | } | 774 | 250 | } | 775 | | | 776 | | /* Doing this here one by one instead of compacting all at the end | 777 | | * has massive peak-memory saving. | 778 | | * | 779 | | * The compacting both saves memory and makes further operations | 780 | | * faster. | 781 | | */ | 782 | 1.53k | parsed_charstrings[new_glyph].compact (); | 783 | 1.53k | } | 784 | | | 785 | | /* Since parsed strings were loaded from accelerator, we still need | 786 | | * to compute the subroutine closures which would have normally happened during | 787 | | * parsing. | 788 | | * | 789 | | * Or if we are dropping hinting, redo closure to get actually used subrs. | 790 | | */ | 791 | 542 | if ((cff_accelerator || | 792 | 542 | (!cff_accelerator && plan->flags & HB_SUBSET_FLAGS_NO_HINTING)) && | 793 | 542 | !closure_subroutines(*parsed_global_subrs, | 794 | 117 | *parsed_local_subrs)) | 795 | 0 | return false; | 796 | | | 797 | 542 | remaps.create (closures); | 798 | | | 799 | 542 | populate_subset_accelerator (); | 800 | 542 | return true; | 801 | 542 | } |
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::subset() Line | Count | Source | 678 | 778 | { | 679 | 778 | unsigned fd_count = acc.fdCount; | 680 | 778 | const cff_subset_accelerator_t* cff_accelerator = nullptr; | 681 | 778 | if (acc.cff_accelerator) { | 682 | 0 | cff_accelerator = acc.cff_accelerator; | 683 | 0 | fd_count = cff_accelerator->parsed_local_subrs.length; | 684 | 0 | } | 685 | | | 686 | 778 | if (cff_accelerator) { | 687 | | // If we are not dropping hinting then charstrings are not modified so we can | 688 | | // just use a reference to the cached copies. | 689 | 0 | cached_charstrings.resize_exact (plan->num_output_glyphs ()); | 690 | 0 | parsed_global_subrs = &cff_accelerator->parsed_global_subrs; | 691 | 0 | parsed_local_subrs = &cff_accelerator->parsed_local_subrs; | 692 | 778 | } else { | 693 | 778 | parsed_charstrings.resize_exact (plan->num_output_glyphs ()); | 694 | 778 | parsed_global_subrs_storage.resize_exact (acc.globalSubrs->count); | 695 | | | 696 | 778 | if (unlikely (!parsed_local_subrs_storage.resize (fd_count))) return false; | 697 | | | 698 | 1.60k | for (unsigned int i = 0; i < acc.fdCount; i++) | 699 | 825 | { | 700 | 825 | unsigned count = acc.privateDicts[i].localSubrs->count; | 701 | 825 | parsed_local_subrs_storage[i].resize (count); | 702 | 825 | if (unlikely (parsed_local_subrs_storage[i].in_error ())) return false; | 703 | 825 | } | 704 | | | 705 | 776 | parsed_global_subrs = &parsed_global_subrs_storage; | 706 | 776 | parsed_local_subrs = &parsed_local_subrs_storage; | 707 | 776 | } | 708 | | | 709 | 776 | if (unlikely (remaps.in_error() | 710 | 776 | || cached_charstrings.in_error () | 711 | 776 | || parsed_charstrings.in_error () | 712 | 776 | || parsed_global_subrs->in_error () | 713 | 776 | || closures.in_error ())) { | 714 | 3 | return false; | 715 | 3 | } | 716 | | | 717 | | /* phase 1 & 2 */ | 718 | 773 | for (auto _ : plan->new_to_old_gid_list) | 719 | 1.68k | { | 720 | 1.68k | hb_codepoint_t new_glyph = _.first; | 721 | 1.68k | hb_codepoint_t old_glyph = _.second; | 722 | | | 723 | 1.68k | const hb_ubytes_t str = (*acc.charStrings)[old_glyph]; | 724 | 1.68k | unsigned int fd = acc.fdSelect->get_fd (old_glyph); | 725 | 1.68k | if (unlikely (fd >= acc.fdCount)) | 726 | 17 | return false; | 727 | | | 728 | 1.66k | if (cff_accelerator) | 729 | 0 | { | 730 | | // parsed string already exists in accelerator, copy it and move | 731 | | // on. | 732 | 0 | if (cached_charstrings) | 733 | 0 | cached_charstrings[new_glyph] = &cff_accelerator->parsed_charstrings[old_glyph]; | 734 | 0 | else | 735 | 0 | parsed_charstrings[new_glyph] = cff_accelerator->parsed_charstrings[old_glyph]; | 736 | |
| 737 | 0 | continue; | 738 | 0 | } | 739 | | | 740 | 1.66k | ENV env (str, acc, fd); | 741 | 1.66k | cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp (env); | 742 | | | 743 | 1.66k | parsed_charstrings[new_glyph].alloc (str.length); | 744 | 1.66k | subr_subset_param_t param (&parsed_charstrings[new_glyph], | 745 | 1.66k | &parsed_global_subrs_storage, | 746 | 1.66k | &parsed_local_subrs_storage[fd], | 747 | 1.66k | &closures.global_closure, | 748 | 1.66k | &closures.local_closures[fd], | 749 | 1.66k | plan->flags & HB_SUBSET_FLAGS_NO_HINTING); | 750 | | | 751 | 1.66k | if (unlikely (!interp.interpret (param))) | 752 | 297 | return false; | 753 | | | 754 | | /* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */ | 755 | 1.37k | SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[new_glyph]); | 756 | | | 757 | | /* mark hint ops and arguments for drop */ | 758 | 1.37k | if ((plan->flags & HB_SUBSET_FLAGS_NO_HINTING) || plan->inprogress_accelerator) | 759 | 109 | { | 760 | 109 | subr_subset_param_t param (&parsed_charstrings[new_glyph], | 761 | 109 | &parsed_global_subrs_storage, | 762 | 109 | &parsed_local_subrs_storage[fd], | 763 | 109 | &closures.global_closure, | 764 | 109 | &closures.local_closures[fd], | 765 | 109 | plan->flags & HB_SUBSET_FLAGS_NO_HINTING); | 766 | | | 767 | 109 | drop_hints_param_t drop; | 768 | 109 | if (drop_hints_in_str (parsed_charstrings[new_glyph], param, drop)) | 769 | 47 | { | 770 | 47 | parsed_charstrings[new_glyph].set_hint_dropped (); | 771 | 47 | if (drop.vsindex_dropped) | 772 | 1 | parsed_charstrings[new_glyph].set_vsindex_dropped (); | 773 | 47 | } | 774 | 109 | } | 775 | | | 776 | | /* Doing this here one by one instead of compacting all at the end | 777 | | * has massive peak-memory saving. | 778 | | * | 779 | | * The compacting both saves memory and makes further operations | 780 | | * faster. | 781 | | */ | 782 | 1.37k | parsed_charstrings[new_glyph].compact (); | 783 | 1.37k | } | 784 | | | 785 | | /* Since parsed strings were loaded from accelerator, we still need | 786 | | * to compute the subroutine closures which would have normally happened during | 787 | | * parsing. | 788 | | * | 789 | | * Or if we are dropping hinting, redo closure to get actually used subrs. | 790 | | */ | 791 | 459 | if ((cff_accelerator || | 792 | 459 | (!cff_accelerator && plan->flags & HB_SUBSET_FLAGS_NO_HINTING)) && | 793 | 459 | !closure_subroutines(*parsed_global_subrs, | 794 | 84 | *parsed_local_subrs)) | 795 | 0 | return false; | 796 | | | 797 | 459 | remaps.create (closures); | 798 | | | 799 | 459 | populate_subset_accelerator (); | 800 | 459 | return true; | 801 | 459 | } |
|
802 | | |
803 | | bool encode_charstrings (str_buff_vec_t &buffArray, bool encode_prefix = true) const |
804 | 1.00k | { |
805 | 1.00k | unsigned num_glyphs = plan->num_output_glyphs (); |
806 | 1.00k | if (unlikely (!buffArray.resize_exact (num_glyphs))) |
807 | 3 | return false; |
808 | 998 | hb_codepoint_t last = 0; |
809 | 998 | for (auto _ : plan->new_to_old_gid_list) |
810 | 2.45k | { |
811 | 2.45k | hb_codepoint_t gid = _.first; |
812 | 2.45k | hb_codepoint_t old_glyph = _.second; |
813 | | |
814 | 2.45k | if (endchar_op != OpCode_Invalid) |
815 | 1.54k | for (; last < gid; last++) |
816 | 256 | { |
817 | | // Hack to point vector to static string. |
818 | 256 | auto &b = buffArray.arrayZ[last]; |
819 | 256 | b.length = 1; |
820 | 256 | b.arrayZ = const_cast<unsigned char *>(endchar_str); |
821 | 256 | } |
822 | | |
823 | 2.45k | last++; // Skip over gid |
824 | 2.45k | unsigned int fd = acc.fdSelect->get_fd (old_glyph); |
825 | 2.45k | if (unlikely (fd >= acc.fdCount)) |
826 | 0 | return false; |
827 | 2.45k | if (unlikely (!encode_str (get_parsed_charstring (gid), fd, buffArray.arrayZ[gid], encode_prefix))) |
828 | 3 | return false; |
829 | 2.45k | } |
830 | 995 | if (endchar_op != OpCode_Invalid) |
831 | 538 | for (; last < num_glyphs; last++) |
832 | 0 | { |
833 | | // Hack to point vector to static string. |
834 | 0 | auto &b = buffArray.arrayZ[last]; |
835 | 0 | b.length = 1; |
836 | 0 | b.arrayZ = const_cast<unsigned char *>(endchar_str); |
837 | 0 | } |
838 | | |
839 | 995 | return true; |
840 | 998 | } CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::encode_charstrings(hb_vector_t<hb_vector_t<unsigned char, false>, false>&, bool) const Line | Count | Source | 804 | 542 | { | 805 | 542 | unsigned num_glyphs = plan->num_output_glyphs (); | 806 | 542 | if (unlikely (!buffArray.resize_exact (num_glyphs))) | 807 | 2 | return false; | 808 | 540 | hb_codepoint_t last = 0; | 809 | 540 | for (auto _ : plan->new_to_old_gid_list) | 810 | 1.28k | { | 811 | 1.28k | hb_codepoint_t gid = _.first; | 812 | 1.28k | hb_codepoint_t old_glyph = _.second; | 813 | | | 814 | 1.28k | if (endchar_op != OpCode_Invalid) | 815 | 1.54k | for (; last < gid; last++) | 816 | 256 | { | 817 | | // Hack to point vector to static string. | 818 | 256 | auto &b = buffArray.arrayZ[last]; | 819 | 256 | b.length = 1; | 820 | 256 | b.arrayZ = const_cast<unsigned char *>(endchar_str); | 821 | 256 | } | 822 | | | 823 | 1.28k | last++; // Skip over gid | 824 | 1.28k | unsigned int fd = acc.fdSelect->get_fd (old_glyph); | 825 | 1.28k | if (unlikely (fd >= acc.fdCount)) | 826 | 0 | return false; | 827 | 1.28k | if (unlikely (!encode_str (get_parsed_charstring (gid), fd, buffArray.arrayZ[gid], encode_prefix))) | 828 | 2 | return false; | 829 | 1.28k | } | 830 | 538 | if (endchar_op != OpCode_Invalid) | 831 | 538 | for (; last < num_glyphs; last++) | 832 | 0 | { | 833 | | // Hack to point vector to static string. | 834 | 0 | auto &b = buffArray.arrayZ[last]; | 835 | 0 | b.length = 1; | 836 | 0 | b.arrayZ = const_cast<unsigned char *>(endchar_str); | 837 | 0 | } | 838 | | | 839 | 538 | return true; | 840 | 540 | } |
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::encode_charstrings(hb_vector_t<hb_vector_t<unsigned char, false>, false>&, bool) const Line | Count | Source | 804 | 459 | { | 805 | 459 | unsigned num_glyphs = plan->num_output_glyphs (); | 806 | 459 | if (unlikely (!buffArray.resize_exact (num_glyphs))) | 807 | 1 | return false; | 808 | 458 | hb_codepoint_t last = 0; | 809 | 458 | for (auto _ : plan->new_to_old_gid_list) | 810 | 1.16k | { | 811 | 1.16k | hb_codepoint_t gid = _.first; | 812 | 1.16k | hb_codepoint_t old_glyph = _.second; | 813 | | | 814 | 1.16k | if (endchar_op != OpCode_Invalid) | 815 | 0 | for (; last < gid; last++) | 816 | 0 | { | 817 | | // Hack to point vector to static string. | 818 | 0 | auto &b = buffArray.arrayZ[last]; | 819 | 0 | b.length = 1; | 820 | 0 | b.arrayZ = const_cast<unsigned char *>(endchar_str); | 821 | 0 | } | 822 | | | 823 | 1.16k | last++; // Skip over gid | 824 | 1.16k | unsigned int fd = acc.fdSelect->get_fd (old_glyph); | 825 | 1.16k | if (unlikely (fd >= acc.fdCount)) | 826 | 0 | return false; | 827 | 1.16k | if (unlikely (!encode_str (get_parsed_charstring (gid), fd, buffArray.arrayZ[gid], encode_prefix))) | 828 | 1 | return false; | 829 | 1.16k | } | 830 | 457 | if (endchar_op != OpCode_Invalid) | 831 | 0 | for (; last < num_glyphs; last++) | 832 | 0 | { | 833 | | // Hack to point vector to static string. | 834 | 0 | auto &b = buffArray.arrayZ[last]; | 835 | 0 | b.length = 1; | 836 | 0 | b.arrayZ = const_cast<unsigned char *>(endchar_str); | 837 | 0 | } | 838 | | | 839 | 457 | return true; | 840 | 458 | } |
|
841 | | |
842 | | bool encode_subrs (const parsed_cs_str_vec_t &subrs, const subr_remap_t& remap, unsigned int fd, str_buff_vec_t &buffArray) const |
843 | 2.08k | { |
844 | 2.08k | unsigned int count = remap.get_population (); |
845 | | |
846 | 2.08k | if (unlikely (!buffArray.resize_exact (count))) |
847 | 1 | return false; |
848 | 4.72k | for (unsigned int new_num = 0; new_num < count; new_num++) |
849 | 2.64k | { |
850 | 2.64k | hb_codepoint_t old_num = remap.backward (new_num); |
851 | 2.64k | assert (old_num != CFF_UNDEF_CODE); |
852 | | |
853 | 2.64k | if (unlikely (!encode_str (subrs[old_num], fd, buffArray[new_num]))) |
854 | 1 | return false; |
855 | 2.64k | } |
856 | 2.07k | return true; |
857 | 2.08k | } CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::encode_subrs(CFF::parsed_cs_str_vec_t const&, CFF::subr_remap_t const&, unsigned int, hb_vector_t<hb_vector_t<unsigned char, false>, false>&) const Line | Count | Source | 843 | 1.12k | { | 844 | 1.12k | unsigned int count = remap.get_population (); | 845 | | | 846 | 1.12k | if (unlikely (!buffArray.resize_exact (count))) | 847 | 0 | return false; | 848 | 2.21k | for (unsigned int new_num = 0; new_num < count; new_num++) | 849 | 1.09k | { | 850 | 1.09k | hb_codepoint_t old_num = remap.backward (new_num); | 851 | 1.09k | assert (old_num != CFF_UNDEF_CODE); | 852 | | | 853 | 1.09k | if (unlikely (!encode_str (subrs[old_num], fd, buffArray[new_num]))) | 854 | 0 | return false; | 855 | 1.09k | } | 856 | 1.12k | return true; | 857 | 1.12k | } |
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::encode_subrs(CFF::parsed_cs_str_vec_t const&, CFF::subr_remap_t const&, unsigned int, hb_vector_t<hb_vector_t<unsigned char, false>, false>&) const Line | Count | Source | 843 | 961 | { | 844 | 961 | unsigned int count = remap.get_population (); | 845 | | | 846 | 961 | if (unlikely (!buffArray.resize_exact (count))) | 847 | 1 | return false; | 848 | 2.50k | for (unsigned int new_num = 0; new_num < count; new_num++) | 849 | 1.55k | { | 850 | 1.55k | hb_codepoint_t old_num = remap.backward (new_num); | 851 | 1.55k | assert (old_num != CFF_UNDEF_CODE); | 852 | | | 853 | 1.55k | if (unlikely (!encode_str (subrs[old_num], fd, buffArray[new_num]))) | 854 | 1 | return false; | 855 | 1.55k | } | 856 | 959 | return true; | 857 | 960 | } |
|
858 | | |
859 | | bool encode_globalsubrs (str_buff_vec_t &buffArray) |
860 | 995 | { |
861 | 995 | return encode_subrs (*parsed_global_subrs, remaps.global_remap, 0, buffArray); |
862 | 995 | } CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::encode_globalsubrs(hb_vector_t<hb_vector_t<unsigned char, false>, false>&) Line | Count | Source | 860 | 538 | { | 861 | 538 | return encode_subrs (*parsed_global_subrs, remaps.global_remap, 0, buffArray); | 862 | 538 | } |
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::encode_globalsubrs(hb_vector_t<hb_vector_t<unsigned char, false>, false>&) Line | Count | Source | 860 | 457 | { | 861 | 457 | return encode_subrs (*parsed_global_subrs, remaps.global_remap, 0, buffArray); | 862 | 457 | } |
|
863 | | |
864 | | bool encode_localsubrs (unsigned int fd, str_buff_vec_t &buffArray) const |
865 | 1.08k | { |
866 | 1.08k | return encode_subrs ((*parsed_local_subrs)[fd], remaps.local_remaps[fd], fd, buffArray); |
867 | 1.08k | } CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::encode_localsubrs(unsigned int, hb_vector_t<hb_vector_t<unsigned char, false>, false>&) const Line | Count | Source | 865 | 582 | { | 866 | 582 | return encode_subrs ((*parsed_local_subrs)[fd], remaps.local_remaps[fd], fd, buffArray); | 867 | 582 | } |
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::encode_localsubrs(unsigned int, hb_vector_t<hb_vector_t<unsigned char, false>, false>&) const Line | Count | Source | 865 | 504 | { | 866 | 504 | return encode_subrs ((*parsed_local_subrs)[fd], remaps.local_remaps[fd], fd, buffArray); | 867 | 504 | } |
|
868 | | |
869 | | protected: |
870 | | struct drop_hints_param_t |
871 | | { |
872 | | drop_hints_param_t () |
873 | | : seen_moveto (false), |
874 | | ends_in_hint (false), |
875 | | all_dropped (false), |
876 | 359 | vsindex_dropped (false) {} CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::drop_hints_param_t::drop_hints_param_t() Line | Count | Source | 876 | 250 | vsindex_dropped (false) {} |
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::drop_hints_param_t::drop_hints_param_t() Line | Count | Source | 876 | 109 | vsindex_dropped (false) {} |
|
877 | | |
878 | | bool seen_moveto; |
879 | | bool ends_in_hint; |
880 | | bool all_dropped; |
881 | | bool vsindex_dropped; |
882 | | }; |
883 | | |
884 | | bool drop_hints_in_subr (parsed_cs_str_t &str, unsigned int pos, |
885 | | parsed_cs_str_vec_t &subrs, unsigned int subr_num, |
886 | | const subr_subset_param_t ¶m, drop_hints_param_t &drop) |
887 | 707 | { |
888 | 707 | drop.ends_in_hint = false; |
889 | 707 | bool has_hint = drop_hints_in_str (subrs[subr_num], param, drop); |
890 | | |
891 | | /* if this subr ends with a stem hint (i.e., not a number; potential argument for moveto), |
892 | | * then this entire subroutine must be a hint. drop its call. */ |
893 | 707 | if (drop.ends_in_hint) |
894 | 47 | { |
895 | 47 | str.values[pos].set_hinting (); |
896 | | /* if this subr call is at the end of the parent subr, propagate the flag |
897 | | * otherwise reset the flag */ |
898 | 47 | if (!str.at_end (pos)) |
899 | 30 | drop.ends_in_hint = false; |
900 | 47 | } |
901 | 660 | else if (drop.all_dropped) |
902 | 196 | { |
903 | 196 | str.values[pos].set_hinting (); |
904 | 196 | } |
905 | | |
906 | 707 | return has_hint; |
907 | 707 | } CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::drop_hints_in_subr(CFF::parsed_cs_str_t&, unsigned int, CFF::parsed_cs_str_vec_t&, unsigned int, CFF::subr_subset_param_t const&, CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::drop_hints_param_t&) Line | Count | Source | 887 | 195 | { | 888 | 195 | drop.ends_in_hint = false; | 889 | 195 | bool has_hint = drop_hints_in_str (subrs[subr_num], param, drop); | 890 | | | 891 | | /* if this subr ends with a stem hint (i.e., not a number; potential argument for moveto), | 892 | | * then this entire subroutine must be a hint. drop its call. */ | 893 | 195 | if (drop.ends_in_hint) | 894 | 18 | { | 895 | 18 | str.values[pos].set_hinting (); | 896 | | /* if this subr call is at the end of the parent subr, propagate the flag | 897 | | * otherwise reset the flag */ | 898 | 18 | if (!str.at_end (pos)) | 899 | 10 | drop.ends_in_hint = false; | 900 | 18 | } | 901 | 177 | else if (drop.all_dropped) | 902 | 12 | { | 903 | 12 | str.values[pos].set_hinting (); | 904 | 12 | } | 905 | | | 906 | 195 | return has_hint; | 907 | 195 | } |
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::drop_hints_in_subr(CFF::parsed_cs_str_t&, unsigned int, CFF::parsed_cs_str_vec_t&, unsigned int, CFF::subr_subset_param_t const&, CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::drop_hints_param_t&) Line | Count | Source | 887 | 512 | { | 888 | 512 | drop.ends_in_hint = false; | 889 | 512 | bool has_hint = drop_hints_in_str (subrs[subr_num], param, drop); | 890 | | | 891 | | /* if this subr ends with a stem hint (i.e., not a number; potential argument for moveto), | 892 | | * then this entire subroutine must be a hint. drop its call. */ | 893 | 512 | if (drop.ends_in_hint) | 894 | 29 | { | 895 | 29 | str.values[pos].set_hinting (); | 896 | | /* if this subr call is at the end of the parent subr, propagate the flag | 897 | | * otherwise reset the flag */ | 898 | 29 | if (!str.at_end (pos)) | 899 | 20 | drop.ends_in_hint = false; | 900 | 29 | } | 901 | 483 | else if (drop.all_dropped) | 902 | 184 | { | 903 | 184 | str.values[pos].set_hinting (); | 904 | 184 | } | 905 | | | 906 | 512 | return has_hint; | 907 | 512 | } |
|
908 | | |
909 | | /* returns true if it sees a hint op before the first moveto */ |
910 | | bool drop_hints_in_str (parsed_cs_str_t &str, const subr_subset_param_t ¶m, drop_hints_param_t &drop) |
911 | 1.06k | { |
912 | 1.06k | bool seen_hint = false; |
913 | | |
914 | 1.06k | unsigned count = str.values.length; |
915 | 1.06k | auto *values = str.values.arrayZ; |
916 | 19.6k | for (unsigned int pos = 0; pos < count; pos++) |
917 | 18.5k | { |
918 | 18.5k | bool has_hint = false; |
919 | 18.5k | switch (values[pos].op) |
920 | 18.5k | { |
921 | 537 | case OpCode_callsubr: |
922 | 537 | has_hint = drop_hints_in_subr (str, pos, |
923 | 537 | *param.parsed_local_subrs, values[pos].subr_num, |
924 | 537 | param, drop); |
925 | 537 | break; |
926 | | |
927 | 170 | case OpCode_callgsubr: |
928 | 170 | has_hint = drop_hints_in_subr (str, pos, |
929 | 170 | *param.parsed_global_subrs, values[pos].subr_num, |
930 | 170 | param, drop); |
931 | 170 | break; |
932 | | |
933 | 378 | case OpCode_rmoveto: |
934 | 519 | case OpCode_hmoveto: |
935 | 624 | case OpCode_vmoveto: |
936 | 624 | drop.seen_moveto = true; |
937 | 624 | break; |
938 | | |
939 | 428 | case OpCode_hintmask: |
940 | 572 | case OpCode_cntrmask: |
941 | 572 | if (drop.seen_moveto) |
942 | 400 | { |
943 | 400 | values[pos].set_hinting (); |
944 | 400 | break; |
945 | 400 | } |
946 | 572 | HB_FALLTHROUGH; |
947 | | |
948 | 319 | case OpCode_hstemhm: |
949 | 453 | case OpCode_vstemhm: |
950 | 648 | case OpCode_hstem: |
951 | 869 | case OpCode_vstem: |
952 | 869 | has_hint = true; |
953 | 869 | values[pos].set_hinting (); |
954 | 869 | if (str.at_end (pos)) |
955 | 37 | drop.ends_in_hint = true; |
956 | 869 | break; |
957 | | |
958 | 21 | case OpCode_dotsection: |
959 | 21 | values[pos].set_hinting (); |
960 | 21 | break; |
961 | | |
962 | 15.9k | default: |
963 | | /* NONE */ |
964 | 15.9k | break; |
965 | 18.5k | } |
966 | 18.5k | if (has_hint) |
967 | 983 | { |
968 | 5.27k | for (int i = pos - 1; i >= 0; i--) |
969 | 5.06k | { |
970 | 5.06k | parsed_cs_op_t &csop = values[(unsigned)i]; |
971 | 5.06k | if (csop.is_hinting ()) |
972 | 769 | break; |
973 | 4.29k | csop.set_hinting (); |
974 | 4.29k | if (csop.op == OpCode_vsindexcs) |
975 | 1 | drop.vsindex_dropped = true; |
976 | 4.29k | } |
977 | 983 | seen_hint |= has_hint; |
978 | 983 | } |
979 | 18.5k | } |
980 | | |
981 | | /* Raise all_dropped flag if all operators except return are dropped from a subr. |
982 | | * It may happen even after seeing the first moveto if a subr contains |
983 | | * only (usually one) hintmask operator, then calls to this subr can be dropped. |
984 | | */ |
985 | 1.06k | drop.all_dropped = true; |
986 | 4.67k | for (unsigned int pos = 0; pos < count; pos++) |
987 | 4.43k | { |
988 | 4.43k | parsed_cs_op_t &csop = values[pos]; |
989 | 4.43k | if (csop.op == OpCode_return) |
990 | 30 | break; |
991 | 4.40k | if (!csop.is_hinting ()) |
992 | 790 | { |
993 | 790 | drop.all_dropped = false; |
994 | 790 | break; |
995 | 790 | } |
996 | 4.40k | } |
997 | | |
998 | 1.06k | return seen_hint; |
999 | 1.06k | } CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::drop_hints_in_str(CFF::parsed_cs_str_t&, CFF::subr_subset_param_t const&, CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::drop_hints_param_t&) Line | Count | Source | 911 | 445 | { | 912 | 445 | bool seen_hint = false; | 913 | | | 914 | 445 | unsigned count = str.values.length; | 915 | 445 | auto *values = str.values.arrayZ; | 916 | 8.30k | for (unsigned int pos = 0; pos < count; pos++) | 917 | 7.85k | { | 918 | 7.85k | bool has_hint = false; | 919 | 7.85k | switch (values[pos].op) | 920 | 7.85k | { | 921 | 84 | case OpCode_callsubr: | 922 | 84 | has_hint = drop_hints_in_subr (str, pos, | 923 | 84 | *param.parsed_local_subrs, values[pos].subr_num, | 924 | 84 | param, drop); | 925 | 84 | break; | 926 | | | 927 | 111 | case OpCode_callgsubr: | 928 | 111 | has_hint = drop_hints_in_subr (str, pos, | 929 | 111 | *param.parsed_global_subrs, values[pos].subr_num, | 930 | 111 | param, drop); | 931 | 111 | break; | 932 | | | 933 | 100 | case OpCode_rmoveto: | 934 | 184 | case OpCode_hmoveto: | 935 | 225 | case OpCode_vmoveto: | 936 | 225 | drop.seen_moveto = true; | 937 | 225 | break; | 938 | | | 939 | 218 | case OpCode_hintmask: | 940 | 313 | case OpCode_cntrmask: | 941 | 313 | if (drop.seen_moveto) | 942 | 215 | { | 943 | 215 | values[pos].set_hinting (); | 944 | 215 | break; | 945 | 215 | } | 946 | 313 | HB_FALLTHROUGH; | 947 | | | 948 | 145 | case OpCode_hstemhm: | 949 | 201 | case OpCode_vstemhm: | 950 | 336 | case OpCode_hstem: | 951 | 513 | case OpCode_vstem: | 952 | 513 | has_hint = true; | 953 | 513 | values[pos].set_hinting (); | 954 | 513 | if (str.at_end (pos)) | 955 | 10 | drop.ends_in_hint = true; | 956 | 513 | break; | 957 | | | 958 | 21 | case OpCode_dotsection: | 959 | 21 | values[pos].set_hinting (); | 960 | 21 | break; | 961 | | | 962 | 6.68k | default: | 963 | | /* NONE */ | 964 | 6.68k | break; | 965 | 7.85k | } | 966 | 7.85k | if (has_hint) | 967 | 557 | { | 968 | 3.08k | for (int i = pos - 1; i >= 0; i--) | 969 | 2.95k | { | 970 | 2.95k | parsed_cs_op_t &csop = values[(unsigned)i]; | 971 | 2.95k | if (csop.is_hinting ()) | 972 | 429 | break; | 973 | 2.52k | csop.set_hinting (); | 974 | 2.52k | if (csop.op == OpCode_vsindexcs) | 975 | 0 | drop.vsindex_dropped = true; | 976 | 2.52k | } | 977 | 557 | seen_hint |= has_hint; | 978 | 557 | } | 979 | 7.85k | } | 980 | | | 981 | | /* Raise all_dropped flag if all operators except return are dropped from a subr. | 982 | | * It may happen even after seeing the first moveto if a subr contains | 983 | | * only (usually one) hintmask operator, then calls to this subr can be dropped. | 984 | | */ | 985 | 445 | drop.all_dropped = true; | 986 | 3.15k | for (unsigned int pos = 0; pos < count; pos++) | 987 | 3.15k | { | 988 | 3.15k | parsed_cs_op_t &csop = values[pos]; | 989 | 3.15k | if (csop.op == OpCode_return) | 990 | 30 | break; | 991 | 3.12k | if (!csop.is_hinting ()) | 992 | 414 | { | 993 | 414 | drop.all_dropped = false; | 994 | 414 | break; | 995 | 414 | } | 996 | 3.12k | } | 997 | | | 998 | 445 | return seen_hint; | 999 | 445 | } |
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::drop_hints_in_str(CFF::parsed_cs_str_t&, CFF::subr_subset_param_t const&, CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::drop_hints_param_t&) Line | Count | Source | 911 | 621 | { | 912 | 621 | bool seen_hint = false; | 913 | | | 914 | 621 | unsigned count = str.values.length; | 915 | 621 | auto *values = str.values.arrayZ; | 916 | 11.3k | for (unsigned int pos = 0; pos < count; pos++) | 917 | 10.7k | { | 918 | 10.7k | bool has_hint = false; | 919 | 10.7k | switch (values[pos].op) | 920 | 10.7k | { | 921 | 453 | case OpCode_callsubr: | 922 | 453 | has_hint = drop_hints_in_subr (str, pos, | 923 | 453 | *param.parsed_local_subrs, values[pos].subr_num, | 924 | 453 | param, drop); | 925 | 453 | break; | 926 | | | 927 | 59 | case OpCode_callgsubr: | 928 | 59 | has_hint = drop_hints_in_subr (str, pos, | 929 | 59 | *param.parsed_global_subrs, values[pos].subr_num, | 930 | 59 | param, drop); | 931 | 59 | break; | 932 | | | 933 | 278 | case OpCode_rmoveto: | 934 | 335 | case OpCode_hmoveto: | 935 | 399 | case OpCode_vmoveto: | 936 | 399 | drop.seen_moveto = true; | 937 | 399 | break; | 938 | | | 939 | 210 | case OpCode_hintmask: | 940 | 259 | case OpCode_cntrmask: | 941 | 259 | if (drop.seen_moveto) | 942 | 185 | { | 943 | 185 | values[pos].set_hinting (); | 944 | 185 | break; | 945 | 185 | } | 946 | 259 | HB_FALLTHROUGH; | 947 | | | 948 | 174 | case OpCode_hstemhm: | 949 | 252 | case OpCode_vstemhm: | 950 | 312 | case OpCode_hstem: | 951 | 356 | case OpCode_vstem: | 952 | 356 | has_hint = true; | 953 | 356 | values[pos].set_hinting (); | 954 | 356 | if (str.at_end (pos)) | 955 | 27 | drop.ends_in_hint = true; | 956 | 356 | break; | 957 | | | 958 | 0 | case OpCode_dotsection: | 959 | 0 | values[pos].set_hinting (); | 960 | 0 | break; | 961 | | | 962 | 9.25k | default: | 963 | | /* NONE */ | 964 | 9.25k | break; | 965 | 10.7k | } | 966 | 10.7k | if (has_hint) | 967 | 426 | { | 968 | 2.19k | for (int i = pos - 1; i >= 0; i--) | 969 | 2.10k | { | 970 | 2.10k | parsed_cs_op_t &csop = values[(unsigned)i]; | 971 | 2.10k | if (csop.is_hinting ()) | 972 | 340 | break; | 973 | 1.76k | csop.set_hinting (); | 974 | 1.76k | if (csop.op == OpCode_vsindexcs) | 975 | 1 | drop.vsindex_dropped = true; | 976 | 1.76k | } | 977 | 426 | seen_hint |= has_hint; | 978 | 426 | } | 979 | 10.7k | } | 980 | | | 981 | | /* Raise all_dropped flag if all operators except return are dropped from a subr. | 982 | | * It may happen even after seeing the first moveto if a subr contains | 983 | | * only (usually one) hintmask operator, then calls to this subr can be dropped. | 984 | | */ | 985 | 621 | drop.all_dropped = true; | 986 | 1.52k | for (unsigned int pos = 0; pos < count; pos++) | 987 | 1.27k | { | 988 | 1.27k | parsed_cs_op_t &csop = values[pos]; | 989 | 1.27k | if (csop.op == OpCode_return) | 990 | 0 | break; | 991 | 1.27k | if (!csop.is_hinting ()) | 992 | 376 | { | 993 | 376 | drop.all_dropped = false; | 994 | 376 | break; | 995 | 376 | } | 996 | 1.27k | } | 997 | | | 998 | 621 | return seen_hint; | 999 | 621 | } |
|
1000 | | |
1001 | | bool closure_subroutines (const parsed_cs_str_vec_t& global_subrs, |
1002 | | const hb_vector_t<parsed_cs_str_vec_t>& local_subrs) |
1003 | 201 | { |
1004 | 201 | closures.reset (); |
1005 | 201 | for (auto _ : plan->new_to_old_gid_list) |
1006 | 345 | { |
1007 | 345 | hb_codepoint_t new_glyph = _.first; |
1008 | 345 | hb_codepoint_t old_glyph = _.second; |
1009 | 345 | unsigned int fd = acc.fdSelect->get_fd (old_glyph); |
1010 | 345 | if (unlikely (fd >= acc.fdCount)) |
1011 | 0 | return false; |
1012 | | |
1013 | | // Note: const cast is safe here because the collect_subr_refs_in_str only performs a |
1014 | | // closure and does not modify any of the charstrings. |
1015 | 345 | subr_subset_param_t param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (new_glyph)), |
1016 | 345 | const_cast<parsed_cs_str_vec_t*> (&global_subrs), |
1017 | 345 | const_cast<parsed_cs_str_vec_t*> (&local_subrs[fd]), |
1018 | 345 | &closures.global_closure, |
1019 | 345 | &closures.local_closures[fd], |
1020 | 345 | plan->flags & HB_SUBSET_FLAGS_NO_HINTING); |
1021 | 345 | collect_subr_refs_in_str (get_parsed_charstring (new_glyph), param); |
1022 | 345 | } |
1023 | | |
1024 | 201 | return true; |
1025 | 201 | } CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::closure_subroutines(CFF::parsed_cs_str_vec_t const&, hb_vector_t<CFF::parsed_cs_str_vec_t, false> const&) Line | Count | Source | 1003 | 117 | { | 1004 | 117 | closures.reset (); | 1005 | 117 | for (auto _ : plan->new_to_old_gid_list) | 1006 | 237 | { | 1007 | 237 | hb_codepoint_t new_glyph = _.first; | 1008 | 237 | hb_codepoint_t old_glyph = _.second; | 1009 | 237 | unsigned int fd = acc.fdSelect->get_fd (old_glyph); | 1010 | 237 | if (unlikely (fd >= acc.fdCount)) | 1011 | 0 | return false; | 1012 | | | 1013 | | // Note: const cast is safe here because the collect_subr_refs_in_str only performs a | 1014 | | // closure and does not modify any of the charstrings. | 1015 | 237 | subr_subset_param_t param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (new_glyph)), | 1016 | 237 | const_cast<parsed_cs_str_vec_t*> (&global_subrs), | 1017 | 237 | const_cast<parsed_cs_str_vec_t*> (&local_subrs[fd]), | 1018 | 237 | &closures.global_closure, | 1019 | 237 | &closures.local_closures[fd], | 1020 | 237 | plan->flags & HB_SUBSET_FLAGS_NO_HINTING); | 1021 | 237 | collect_subr_refs_in_str (get_parsed_charstring (new_glyph), param); | 1022 | 237 | } | 1023 | | | 1024 | 117 | return true; | 1025 | 117 | } |
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::closure_subroutines(CFF::parsed_cs_str_vec_t const&, hb_vector_t<CFF::parsed_cs_str_vec_t, false> const&) Line | Count | Source | 1003 | 84 | { | 1004 | 84 | closures.reset (); | 1005 | 84 | for (auto _ : plan->new_to_old_gid_list) | 1006 | 108 | { | 1007 | 108 | hb_codepoint_t new_glyph = _.first; | 1008 | 108 | hb_codepoint_t old_glyph = _.second; | 1009 | 108 | unsigned int fd = acc.fdSelect->get_fd (old_glyph); | 1010 | 108 | if (unlikely (fd >= acc.fdCount)) | 1011 | 0 | return false; | 1012 | | | 1013 | | // Note: const cast is safe here because the collect_subr_refs_in_str only performs a | 1014 | | // closure and does not modify any of the charstrings. | 1015 | 108 | subr_subset_param_t param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (new_glyph)), | 1016 | 108 | const_cast<parsed_cs_str_vec_t*> (&global_subrs), | 1017 | 108 | const_cast<parsed_cs_str_vec_t*> (&local_subrs[fd]), | 1018 | 108 | &closures.global_closure, | 1019 | 108 | &closures.local_closures[fd], | 1020 | 108 | plan->flags & HB_SUBSET_FLAGS_NO_HINTING); | 1021 | 108 | collect_subr_refs_in_str (get_parsed_charstring (new_glyph), param); | 1022 | 108 | } | 1023 | | | 1024 | 84 | return true; | 1025 | 84 | } |
|
1026 | | |
1027 | | void collect_subr_refs_in_subr (unsigned int subr_num, parsed_cs_str_vec_t &subrs, |
1028 | | hb_set_t *closure, |
1029 | | const subr_subset_param_t ¶m) |
1030 | 359 | { |
1031 | 359 | if (closure->has (subr_num)) |
1032 | 86 | return; |
1033 | 273 | closure->add (subr_num); |
1034 | 273 | collect_subr_refs_in_str (subrs[subr_num], param); |
1035 | 273 | } CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::collect_subr_refs_in_subr(unsigned int, CFF::parsed_cs_str_vec_t&, hb_set_t*, CFF::subr_subset_param_t const&) Line | Count | Source | 1030 | 135 | { | 1031 | 135 | if (closure->has (subr_num)) | 1032 | 34 | return; | 1033 | 101 | closure->add (subr_num); | 1034 | 101 | collect_subr_refs_in_str (subrs[subr_num], param); | 1035 | 101 | } |
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::collect_subr_refs_in_subr(unsigned int, CFF::parsed_cs_str_vec_t&, hb_set_t*, CFF::subr_subset_param_t const&) Line | Count | Source | 1030 | 224 | { | 1031 | 224 | if (closure->has (subr_num)) | 1032 | 52 | return; | 1033 | 172 | closure->add (subr_num); | 1034 | 172 | collect_subr_refs_in_str (subrs[subr_num], param); | 1035 | 172 | } |
|
1036 | | |
1037 | | void collect_subr_refs_in_str (const parsed_cs_str_t &str, |
1038 | | const subr_subset_param_t ¶m) |
1039 | 618 | { |
1040 | 618 | if (!str.has_calls ()) |
1041 | 361 | return; |
1042 | | |
1043 | 257 | for (auto &opstr : str.values) |
1044 | 3.24k | { |
1045 | 3.24k | if (!param.drop_hints || !opstr.is_hinting ()) |
1046 | 2.43k | { |
1047 | 2.43k | switch (opstr.op) |
1048 | 2.43k | { |
1049 | 253 | case OpCode_callsubr: |
1050 | 253 | collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_local_subrs, |
1051 | 253 | param.local_closure, param); |
1052 | 253 | break; |
1053 | | |
1054 | 106 | case OpCode_callgsubr: |
1055 | 106 | collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_global_subrs, |
1056 | 106 | param.global_closure, param); |
1057 | 106 | break; |
1058 | | |
1059 | 2.07k | default: break; |
1060 | 2.43k | } |
1061 | 2.43k | } |
1062 | 3.24k | } |
1063 | 257 | } CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::collect_subr_refs_in_str(CFF::parsed_cs_str_t const&, CFF::subr_subset_param_t const&) Line | Count | Source | 1039 | 338 | { | 1040 | 338 | if (!str.has_calls ()) | 1041 | 200 | return; | 1042 | | | 1043 | 138 | for (auto &opstr : str.values) | 1044 | 471 | { | 1045 | 471 | if (!param.drop_hints || !opstr.is_hinting ()) | 1046 | 324 | { | 1047 | 324 | switch (opstr.op) | 1048 | 324 | { | 1049 | 64 | case OpCode_callsubr: | 1050 | 64 | collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_local_subrs, | 1051 | 64 | param.local_closure, param); | 1052 | 64 | break; | 1053 | | | 1054 | 71 | case OpCode_callgsubr: | 1055 | 71 | collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_global_subrs, | 1056 | 71 | param.global_closure, param); | 1057 | 71 | break; | 1058 | | | 1059 | 189 | default: break; | 1060 | 324 | } | 1061 | 324 | } | 1062 | 471 | } | 1063 | 138 | } |
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::collect_subr_refs_in_str(CFF::parsed_cs_str_t const&, CFF::subr_subset_param_t const&) Line | Count | Source | 1039 | 280 | { | 1040 | 280 | if (!str.has_calls ()) | 1041 | 161 | return; | 1042 | | | 1043 | 119 | for (auto &opstr : str.values) | 1044 | 2.76k | { | 1045 | 2.76k | if (!param.drop_hints || !opstr.is_hinting ()) | 1046 | 2.11k | { | 1047 | 2.11k | switch (opstr.op) | 1048 | 2.11k | { | 1049 | 189 | case OpCode_callsubr: | 1050 | 189 | collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_local_subrs, | 1051 | 189 | param.local_closure, param); | 1052 | 189 | break; | 1053 | | | 1054 | 35 | case OpCode_callgsubr: | 1055 | 35 | collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_global_subrs, | 1056 | 35 | param.global_closure, param); | 1057 | 35 | break; | 1058 | | | 1059 | 1.88k | default: break; | 1060 | 2.11k | } | 1061 | 2.11k | } | 1062 | 2.76k | } | 1063 | 119 | } |
|
1064 | | |
1065 | | bool encode_str (const parsed_cs_str_t &str, const unsigned int fd, str_buff_t &buff, bool encode_prefix = true) const |
1066 | 5.09k | { |
1067 | 5.09k | str_encoder_t encoder (buff); |
1068 | 5.09k | encoder.reset (); |
1069 | 5.09k | bool hinting = !(plan->flags & HB_SUBSET_FLAGS_NO_HINTING); |
1070 | | /* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints, |
1071 | | * re-insert it at the beginning of charstreing */ |
1072 | 5.09k | if (encode_prefix && str.has_prefix () && !hinting && str.is_hint_dropped ()) |
1073 | 42 | { |
1074 | 42 | encoder.encode_num_cs (str.prefix_num ()); |
1075 | 42 | if (str.prefix_op () != OpCode_Invalid) |
1076 | 4 | encoder.encode_op (str.prefix_op ()); |
1077 | 42 | } |
1078 | | |
1079 | 5.09k | unsigned size = 0; |
1080 | 5.09k | for (auto &opstr : str.values) |
1081 | 43.0k | { |
1082 | 43.0k | size += opstr.length; |
1083 | 43.0k | if (opstr.op == OpCode_callsubr || opstr.op == OpCode_callgsubr) |
1084 | 4.15k | size += 3; |
1085 | 43.0k | } |
1086 | 5.09k | if (!buff.alloc (buff.length + size, true)) |
1087 | 4 | return false; |
1088 | | |
1089 | 5.08k | for (auto &opstr : str.values) |
1090 | 43.0k | { |
1091 | 43.0k | if (hinting || !opstr.is_hinting ()) |
1092 | 41.4k | { |
1093 | 41.4k | switch (opstr.op) |
1094 | 41.4k | { |
1095 | 2.83k | case OpCode_callsubr: |
1096 | 2.83k | encoder.encode_int (remaps.local_remaps[fd].biased_num (opstr.subr_num)); |
1097 | 2.83k | encoder.copy_str (opstr.ptr, opstr.length); |
1098 | 2.83k | break; |
1099 | | |
1100 | 1.02k | case OpCode_callgsubr: |
1101 | 1.02k | encoder.encode_int (remaps.global_remap.biased_num (opstr.subr_num)); |
1102 | 1.02k | encoder.copy_str (opstr.ptr, opstr.length); |
1103 | 1.02k | break; |
1104 | | |
1105 | 37.6k | default: |
1106 | 37.6k | encoder.copy_str (opstr.ptr, opstr.length); |
1107 | 37.6k | break; |
1108 | 41.4k | } |
1109 | 41.4k | } |
1110 | 43.0k | } |
1111 | 5.08k | return !encoder.in_error (); |
1112 | 5.08k | } CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::encode_str(CFF::parsed_cs_str_t const&, unsigned int, hb_vector_t<unsigned char, false>&, bool) const Line | Count | Source | 1066 | 2.37k | { | 1067 | 2.37k | str_encoder_t encoder (buff); | 1068 | 2.37k | encoder.reset (); | 1069 | 2.37k | bool hinting = !(plan->flags & HB_SUBSET_FLAGS_NO_HINTING); | 1070 | | /* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints, | 1071 | | * re-insert it at the beginning of charstreing */ | 1072 | 2.37k | if (encode_prefix && str.has_prefix () && !hinting && str.is_hint_dropped ()) | 1073 | 38 | { | 1074 | 38 | encoder.encode_num_cs (str.prefix_num ()); | 1075 | 38 | if (str.prefix_op () != OpCode_Invalid) | 1076 | 0 | encoder.encode_op (str.prefix_op ()); | 1077 | 38 | } | 1078 | | | 1079 | 2.37k | unsigned size = 0; | 1080 | 2.37k | for (auto &opstr : str.values) | 1081 | 20.6k | { | 1082 | 20.6k | size += opstr.length; | 1083 | 20.6k | if (opstr.op == OpCode_callsubr || opstr.op == OpCode_callgsubr) | 1084 | 1.50k | size += 3; | 1085 | 20.6k | } | 1086 | 2.37k | if (!buff.alloc (buff.length + size, true)) | 1087 | 2 | return false; | 1088 | | | 1089 | 2.37k | for (auto &opstr : str.values) | 1090 | 20.6k | { | 1091 | 20.6k | if (hinting || !opstr.is_hinting ()) | 1092 | 19.9k | { | 1093 | 19.9k | switch (opstr.op) | 1094 | 19.9k | { | 1095 | 611 | case OpCode_callsubr: | 1096 | 611 | encoder.encode_int (remaps.local_remaps[fd].biased_num (opstr.subr_num)); | 1097 | 611 | encoder.copy_str (opstr.ptr, opstr.length); | 1098 | 611 | break; | 1099 | | | 1100 | 854 | case OpCode_callgsubr: | 1101 | 854 | encoder.encode_int (remaps.global_remap.biased_num (opstr.subr_num)); | 1102 | 854 | encoder.copy_str (opstr.ptr, opstr.length); | 1103 | 854 | break; | 1104 | | | 1105 | 18.4k | default: | 1106 | 18.4k | encoder.copy_str (opstr.ptr, opstr.length); | 1107 | 18.4k | break; | 1108 | 19.9k | } | 1109 | 19.9k | } | 1110 | 20.6k | } | 1111 | 2.37k | return !encoder.in_error (); | 1112 | 2.37k | } |
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::encode_str(CFF::parsed_cs_str_t const&, unsigned int, hb_vector_t<unsigned char, false>&, bool) const Line | Count | Source | 1066 | 2.71k | { | 1067 | 2.71k | str_encoder_t encoder (buff); | 1068 | 2.71k | encoder.reset (); | 1069 | 2.71k | bool hinting = !(plan->flags & HB_SUBSET_FLAGS_NO_HINTING); | 1070 | | /* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints, | 1071 | | * re-insert it at the beginning of charstreing */ | 1072 | 2.71k | if (encode_prefix && str.has_prefix () && !hinting && str.is_hint_dropped ()) | 1073 | 4 | { | 1074 | 4 | encoder.encode_num_cs (str.prefix_num ()); | 1075 | 4 | if (str.prefix_op () != OpCode_Invalid) | 1076 | 4 | encoder.encode_op (str.prefix_op ()); | 1077 | 4 | } | 1078 | | | 1079 | 2.71k | unsigned size = 0; | 1080 | 2.71k | for (auto &opstr : str.values) | 1081 | 22.3k | { | 1082 | 22.3k | size += opstr.length; | 1083 | 22.3k | if (opstr.op == OpCode_callsubr || opstr.op == OpCode_callgsubr) | 1084 | 2.65k | size += 3; | 1085 | 22.3k | } | 1086 | 2.71k | if (!buff.alloc (buff.length + size, true)) | 1087 | 2 | return false; | 1088 | | | 1089 | 2.71k | for (auto &opstr : str.values) | 1090 | 22.3k | { | 1091 | 22.3k | if (hinting || !opstr.is_hinting ()) | 1092 | 21.5k | { | 1093 | 21.5k | switch (opstr.op) | 1094 | 21.5k | { | 1095 | 2.22k | case OpCode_callsubr: | 1096 | 2.22k | encoder.encode_int (remaps.local_remaps[fd].biased_num (opstr.subr_num)); | 1097 | 2.22k | encoder.copy_str (opstr.ptr, opstr.length); | 1098 | 2.22k | break; | 1099 | | | 1100 | 167 | case OpCode_callgsubr: | 1101 | 167 | encoder.encode_int (remaps.global_remap.biased_num (opstr.subr_num)); | 1102 | 167 | encoder.copy_str (opstr.ptr, opstr.length); | 1103 | 167 | break; | 1104 | | | 1105 | 19.1k | default: | 1106 | 19.1k | encoder.copy_str (opstr.ptr, opstr.length); | 1107 | 19.1k | break; | 1108 | 21.5k | } | 1109 | 21.5k | } | 1110 | 22.3k | } | 1111 | 2.71k | return !encoder.in_error (); | 1112 | 2.71k | } |
|
1113 | | |
1114 | | void compact_parsed_subrs () const |
1115 | 0 | { |
1116 | 0 | for (auto &cs : parsed_global_subrs_storage) |
1117 | 0 | cs.compact (); |
1118 | 0 | for (auto &vec : parsed_local_subrs_storage) |
1119 | 0 | for (auto &cs : vec) |
1120 | 0 | cs.compact (); |
1121 | 0 | } Unexecuted instantiation: CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::compact_parsed_subrs() const Unexecuted instantiation: CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::compact_parsed_subrs() const |
1122 | | |
1123 | | void populate_subset_accelerator () const |
1124 | 1.00k | { |
1125 | 1.00k | if (!plan->inprogress_accelerator) return; |
1126 | | |
1127 | 0 | compact_parsed_subrs (); |
1128 | |
|
1129 | 0 | acc.cff_accelerator = |
1130 | 0 | cff_subset_accelerator_t::create(acc.blob, |
1131 | 0 | parsed_charstrings, |
1132 | 0 | parsed_global_subrs_storage, |
1133 | 0 | parsed_local_subrs_storage); |
1134 | 0 | } CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::populate_subset_accelerator() const Line | Count | Source | 1124 | 542 | { | 1125 | 542 | if (!plan->inprogress_accelerator) return; | 1126 | | | 1127 | 0 | compact_parsed_subrs (); | 1128 | |
| 1129 | 0 | acc.cff_accelerator = | 1130 | 0 | cff_subset_accelerator_t::create(acc.blob, | 1131 | 0 | parsed_charstrings, | 1132 | 0 | parsed_global_subrs_storage, | 1133 | 0 | parsed_local_subrs_storage); | 1134 | 0 | } |
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::populate_subset_accelerator() const Line | Count | Source | 1124 | 459 | { | 1125 | 459 | if (!plan->inprogress_accelerator) return; | 1126 | | | 1127 | 0 | compact_parsed_subrs (); | 1128 | |
| 1129 | 0 | acc.cff_accelerator = | 1130 | 0 | cff_subset_accelerator_t::create(acc.blob, | 1131 | 0 | parsed_charstrings, | 1132 | 0 | parsed_global_subrs_storage, | 1133 | 0 | parsed_local_subrs_storage); | 1134 | 0 | } |
|
1135 | | |
1136 | | const parsed_cs_str_t& get_parsed_charstring (unsigned i) const |
1137 | 3.14k | { |
1138 | 3.14k | if (cached_charstrings) return *(cached_charstrings[i]); |
1139 | 3.14k | return parsed_charstrings[i]; |
1140 | 3.14k | } CFF::subr_subsetter_t<cff1_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned short, 2u> >, OT::cff1::accelerator_subset_t const, CFF::cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, 14u>::get_parsed_charstring(unsigned int) const Line | Count | Source | 1137 | 1.75k | { | 1138 | 1.75k | if (cached_charstrings) return *(cached_charstrings[i]); | 1139 | 1.75k | return parsed_charstrings[i]; | 1140 | 1.75k | } |
CFF::subr_subsetter_t<cff2_subr_subsetter_t, CFF::Subrs<OT::IntType<unsigned int, 4u> >, OT::cff2::accelerator_subset_t const, CFF::cff2_cs_interp_env_t<CFF::blend_arg_t>, cff2_cs_opset_subr_subset_t, 65535u>::get_parsed_charstring(unsigned int) const Line | Count | Source | 1137 | 1.38k | { | 1138 | 1.38k | if (cached_charstrings) return *(cached_charstrings[i]); | 1139 | 1.38k | return parsed_charstrings[i]; | 1140 | 1.38k | } |
|
1141 | | |
1142 | | protected: |
1143 | | const ACC &acc; |
1144 | | const hb_subset_plan_t *plan; |
1145 | | |
1146 | | subr_closures_t closures; |
1147 | | |
1148 | | hb_vector_t<const parsed_cs_str_t*> cached_charstrings; |
1149 | | const parsed_cs_str_vec_t* parsed_global_subrs; |
1150 | | const hb_vector_t<parsed_cs_str_vec_t>* parsed_local_subrs; |
1151 | | |
1152 | | subr_remaps_t remaps; |
1153 | | |
1154 | | private: |
1155 | | |
1156 | | parsed_cs_str_vec_t parsed_charstrings; |
1157 | | parsed_cs_str_vec_t parsed_global_subrs_storage; |
1158 | | hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs_storage; |
1159 | | typedef typename SUBRS::count_type subr_count_type; |
1160 | | }; |
1161 | | |
1162 | | } /* namespace CFF */ |
1163 | | |
1164 | | HB_INTERNAL bool |
1165 | | hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, |
1166 | | unsigned int fdCount, |
1167 | | const CFF::FDSelect &src, /* IN */ |
1168 | | unsigned int &subset_fd_count /* OUT */, |
1169 | | unsigned int &subset_fdselect_size /* OUT */, |
1170 | | unsigned int &subset_fdselect_format /* OUT */, |
1171 | | hb_vector_t<CFF::code_pair_t> &fdselect_ranges /* OUT */, |
1172 | | hb_inc_bimap_t &fdmap /* OUT */); |
1173 | | |
1174 | | HB_INTERNAL bool |
1175 | | hb_serialize_cff_fdselect (hb_serialize_context_t *c, |
1176 | | unsigned int num_glyphs, |
1177 | | const CFF::FDSelect &src, |
1178 | | unsigned int fd_count, |
1179 | | unsigned int fdselect_format, |
1180 | | unsigned int size, |
1181 | | const hb_vector_t<CFF::code_pair_t> &fdselect_ranges); |
1182 | | |
1183 | | #endif /* HB_SUBSET_CFF_COMMON_HH */ |