|
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 : buff (buff_), error (false) {} |
|
42 |
|
43 void reset () { buff.resize (0); } |
|
44 |
|
45 void encode_byte (unsigned char b) |
|
46 { |
|
47 if (unlikely (buff.push (b) == &Crap(unsigned char))) |
|
48 set_error (); |
|
49 } |
|
50 |
|
51 void encode_int (int v) |
|
52 { |
|
53 if ((-1131 <= v) && (v <= 1131)) |
|
54 { |
|
55 if ((-107 <= v) && (v <= 107)) |
|
56 encode_byte (v + 139); |
|
57 else if (v > 0) |
|
58 { |
|
59 v -= 108; |
|
60 encode_byte ((v >> 8) + OpCode_TwoBytePosInt0); |
|
61 encode_byte (v & 0xFF); |
|
62 } |
|
63 else |
|
64 { |
|
65 v = -v - 108; |
|
66 encode_byte ((v >> 8) + OpCode_TwoByteNegInt0); |
|
67 encode_byte (v & 0xFF); |
|
68 } |
|
69 } |
|
70 else |
|
71 { |
|
72 if (unlikely (v < -32768)) |
|
73 v = -32768; |
|
74 else if (unlikely (v > 32767)) |
|
75 v = 32767; |
|
76 encode_byte (OpCode_shortint); |
|
77 encode_byte ((v >> 8) & 0xFF); |
|
78 encode_byte (v & 0xFF); |
|
79 } |
|
80 } |
|
81 |
|
82 void encode_num (const number_t& n) |
|
83 { |
|
84 if (n.in_int_range ()) |
|
85 { |
|
86 encode_int (n.to_int ()); |
|
87 } |
|
88 else |
|
89 { |
|
90 int32_t v = n.to_fixed (); |
|
91 encode_byte (OpCode_fixedcs); |
|
92 encode_byte ((v >> 24) & 0xFF); |
|
93 encode_byte ((v >> 16) & 0xFF); |
|
94 encode_byte ((v >> 8) & 0xFF); |
|
95 encode_byte (v & 0xFF); |
|
96 } |
|
97 } |
|
98 |
|
99 void encode_op (op_code_t op) |
|
100 { |
|
101 if (Is_OpCode_ESC (op)) |
|
102 { |
|
103 encode_byte (OpCode_escape); |
|
104 encode_byte (Unmake_OpCode_ESC (op)); |
|
105 } |
|
106 else |
|
107 encode_byte (op); |
|
108 } |
|
109 |
|
110 void copy_str (const byte_str_t &str) |
|
111 { |
|
112 unsigned int offset = buff.length; |
|
113 buff.resize (offset + str.length); |
|
114 if (unlikely (buff.length < offset + str.length)) |
|
115 { |
|
116 set_error (); |
|
117 return; |
|
118 } |
|
119 memcpy (&buff[offset], &str[0], str.length); |
|
120 } |
|
121 |
|
122 bool is_error () const { return error; } |
|
123 |
|
124 protected: |
|
125 void set_error () { error = true; } |
|
126 |
|
127 str_buff_t &buff; |
|
128 bool error; |
|
129 }; |
|
130 |
|
131 struct cff_sub_table_offsets_t { |
|
132 cff_sub_table_offsets_t () : privateDictsOffset (0) |
|
133 { |
|
134 topDictInfo.init (); |
|
135 FDSelectInfo.init (); |
|
136 FDArrayInfo.init (); |
|
137 charStringsInfo.init (); |
|
138 globalSubrsInfo.init (); |
|
139 localSubrsInfos.init (); |
|
140 } |
|
141 |
|
142 ~cff_sub_table_offsets_t () { localSubrsInfos.fini (); } |
|
143 |
|
144 table_info_t topDictInfo; |
|
145 table_info_t FDSelectInfo; |
|
146 table_info_t FDArrayInfo; |
|
147 table_info_t charStringsInfo; |
|
148 unsigned int privateDictsOffset; |
|
149 table_info_t globalSubrsInfo; |
|
150 hb_vector_t<table_info_t> localSubrsInfos; |
|
151 }; |
|
152 |
|
153 template <typename OPSTR=op_str_t> |
|
154 struct cff_top_dict_op_serializer_t : op_serializer_t |
|
155 { |
|
156 bool serialize (hb_serialize_context_t *c, |
|
157 const OPSTR &opstr, |
|
158 const cff_sub_table_offsets_t &offsets) const |
|
159 { |
|
160 TRACE_SERIALIZE (this); |
|
161 |
|
162 switch (opstr.op) |
|
163 { |
|
164 case OpCode_CharStrings: |
|
165 return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charStringsInfo.offset)); |
|
166 |
|
167 case OpCode_FDArray: |
|
168 return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayInfo.offset)); |
|
169 |
|
170 case OpCode_FDSelect: |
|
171 return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectInfo.offset)); |
|
172 |
|
173 default: |
|
174 return_trace (copy_opstr (c, opstr)); |
|
175 } |
|
176 return_trace (true); |
|
177 } |
|
178 |
|
179 unsigned int calculate_serialized_size (const OPSTR &opstr) const |
|
180 { |
|
181 switch (opstr.op) |
|
182 { |
|
183 case OpCode_CharStrings: |
|
184 case OpCode_FDArray: |
|
185 case OpCode_FDSelect: |
|
186 return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); |
|
187 |
|
188 default: |
|
189 return opstr.str.length; |
|
190 } |
|
191 } |
|
192 }; |
|
193 |
|
194 struct cff_font_dict_op_serializer_t : op_serializer_t |
|
195 { |
|
196 bool serialize (hb_serialize_context_t *c, |
|
197 const op_str_t &opstr, |
|
198 const table_info_t &privateDictInfo) const |
|
199 { |
|
200 TRACE_SERIALIZE (this); |
|
201 |
|
202 if (opstr.op == OpCode_Private) |
|
203 { |
|
204 /* serialize the private dict size & offset as 2-byte & 4-byte integers */ |
|
205 if (unlikely (!UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) || |
|
206 !UnsizedByteStr::serialize_int4 (c, privateDictInfo.offset))) |
|
207 return_trace (false); |
|
208 |
|
209 /* serialize the opcode */ |
|
210 HBUINT8 *p = c->allocate_size<HBUINT8> (1); |
|
211 if (unlikely (p == nullptr)) return_trace (false); |
|
212 p->set (OpCode_Private); |
|
213 |
|
214 return_trace (true); |
|
215 } |
|
216 else |
|
217 { |
|
218 HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length); |
|
219 if (unlikely (d == nullptr)) return_trace (false); |
|
220 memcpy (d, &opstr.str[0], opstr.str.length); |
|
221 } |
|
222 return_trace (true); |
|
223 } |
|
224 |
|
225 unsigned int calculate_serialized_size (const op_str_t &opstr) const |
|
226 { |
|
227 if (opstr.op == OpCode_Private) |
|
228 return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private); |
|
229 else |
|
230 return opstr.str.length; |
|
231 } |
|
232 }; |
|
233 |
|
234 struct cff_private_dict_op_serializer_t : op_serializer_t |
|
235 { |
|
236 cff_private_dict_op_serializer_t (bool desubroutinize_, bool drop_hints_) |
|
237 : desubroutinize (desubroutinize_), drop_hints (drop_hints_) {} |
|
238 |
|
239 bool serialize (hb_serialize_context_t *c, |
|
240 const op_str_t &opstr, |
|
241 const unsigned int subrsOffset) const |
|
242 { |
|
243 TRACE_SERIALIZE (this); |
|
244 |
|
245 if (drop_hints && dict_opset_t::is_hint_op (opstr.op)) |
|
246 return true; |
|
247 if (opstr.op == OpCode_Subrs) |
|
248 { |
|
249 if (desubroutinize || (subrsOffset == 0)) |
|
250 return_trace (true); |
|
251 else |
|
252 return_trace (FontDict::serialize_offset2_op (c, opstr.op, subrsOffset)); |
|
253 } |
|
254 else |
|
255 return_trace (copy_opstr (c, opstr)); |
|
256 } |
|
257 |
|
258 unsigned int calculate_serialized_size (const op_str_t &opstr, |
|
259 bool has_localsubr=true) const |
|
260 { |
|
261 if (drop_hints && dict_opset_t::is_hint_op (opstr.op)) |
|
262 return 0; |
|
263 if (opstr.op == OpCode_Subrs) |
|
264 { |
|
265 if (desubroutinize || !has_localsubr) |
|
266 return 0; |
|
267 else |
|
268 return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (opstr.op); |
|
269 } |
|
270 else |
|
271 return opstr.str.length; |
|
272 } |
|
273 |
|
274 protected: |
|
275 const bool desubroutinize; |
|
276 const bool drop_hints; |
|
277 }; |
|
278 |
|
279 struct flatten_param_t |
|
280 { |
|
281 str_buff_t &flatStr; |
|
282 bool drop_hints; |
|
283 }; |
|
284 |
|
285 template <typename ACC, typename ENV, typename OPSET> |
|
286 struct subr_flattener_t |
|
287 { |
|
288 subr_flattener_t (const ACC &acc_, |
|
289 const hb_vector_t<hb_codepoint_t> &glyphs_, |
|
290 bool drop_hints_) : acc (acc_), glyphs (glyphs_), |
|
291 drop_hints (drop_hints_) {} |
|
292 |
|
293 bool flatten (str_buff_vec_t &flat_charstrings) |
|
294 { |
|
295 if (!flat_charstrings.resize (glyphs.length)) |
|
296 return false; |
|
297 for (unsigned int i = 0; i < glyphs.length; i++) |
|
298 flat_charstrings[i].init (); |
|
299 for (unsigned int i = 0; i < glyphs.length; i++) |
|
300 { |
|
301 hb_codepoint_t glyph = glyphs[i]; |
|
302 const byte_str_t str = (*acc.charStrings)[glyph]; |
|
303 unsigned int fd = acc.fdSelect->get_fd (glyph); |
|
304 if (unlikely (fd >= acc.fdCount)) |
|
305 return false; |
|
306 cs_interpreter_t<ENV, OPSET, flatten_param_t> interp; |
|
307 interp.env.init (str, acc, fd); |
|
308 flatten_param_t param = { flat_charstrings[i], drop_hints }; |
|
309 if (unlikely (!interp.interpret (param))) |
|
310 return false; |
|
311 } |
|
312 return true; |
|
313 } |
|
314 |
|
315 const ACC &acc; |
|
316 const hb_vector_t<hb_codepoint_t> &glyphs; |
|
317 bool drop_hints; |
|
318 }; |
|
319 |
|
320 struct subr_closures_t |
|
321 { |
|
322 subr_closures_t () : valid (false), global_closure (nullptr) |
|
323 { local_closures.init (); } |
|
324 |
|
325 void init (unsigned int fd_count) |
|
326 { |
|
327 valid = true; |
|
328 global_closure = hb_set_create (); |
|
329 if (global_closure == hb_set_get_empty ()) |
|
330 valid = false; |
|
331 if (!local_closures.resize (fd_count)) |
|
332 valid = false; |
|
333 |
|
334 for (unsigned int i = 0; i < local_closures.length; i++) |
|
335 { |
|
336 local_closures[i] = hb_set_create (); |
|
337 if (local_closures[i] == hb_set_get_empty ()) |
|
338 valid = false; |
|
339 } |
|
340 } |
|
341 |
|
342 void fini () |
|
343 { |
|
344 hb_set_destroy (global_closure); |
|
345 for (unsigned int i = 0; i < local_closures.length; i++) |
|
346 hb_set_destroy (local_closures[i]); |
|
347 local_closures.fini (); |
|
348 } |
|
349 |
|
350 void reset () |
|
351 { |
|
352 hb_set_clear (global_closure); |
|
353 for (unsigned int i = 0; i < local_closures.length; i++) |
|
354 hb_set_clear (local_closures[i]); |
|
355 } |
|
356 |
|
357 bool is_valid () const { return valid; } |
|
358 bool valid; |
|
359 hb_set_t *global_closure; |
|
360 hb_vector_t<hb_set_t *> local_closures; |
|
361 }; |
|
362 |
|
363 struct parsed_cs_op_t : op_str_t |
|
364 { |
|
365 void init (unsigned int subr_num_ = 0) |
|
366 { |
|
367 op_str_t::init (); |
|
368 subr_num = subr_num_; |
|
369 drop_flag = false; |
|
370 keep_flag = false; |
|
371 skip_flag = false; |
|
372 } |
|
373 |
|
374 void fini () { op_str_t::fini (); } |
|
375 |
|
376 bool for_drop () const { return drop_flag; } |
|
377 void set_drop () { if (!for_keep ()) drop_flag = true; } |
|
378 |
|
379 bool for_keep () const { return keep_flag; } |
|
380 void set_keep () { keep_flag = true; } |
|
381 |
|
382 bool for_skip () const { return skip_flag; } |
|
383 void set_skip () { skip_flag = true; } |
|
384 |
|
385 unsigned int subr_num; |
|
386 |
|
387 protected: |
|
388 bool drop_flag : 1; |
|
389 bool keep_flag : 1; |
|
390 bool skip_flag : 1; |
|
391 }; |
|
392 |
|
393 struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t> |
|
394 { |
|
395 void init () |
|
396 { |
|
397 SUPER::init (); |
|
398 parsed = false; |
|
399 hint_dropped = false; |
|
400 has_prefix_ = false; |
|
401 } |
|
402 |
|
403 void add_op (op_code_t op, const byte_str_ref_t& str_ref) |
|
404 { |
|
405 if (!is_parsed ()) |
|
406 SUPER::add_op (op, str_ref); |
|
407 } |
|
408 |
|
409 void add_call_op (op_code_t op, const byte_str_ref_t& str_ref, unsigned int subr_num) |
|
410 { |
|
411 if (!is_parsed ()) |
|
412 { |
|
413 unsigned int parsed_len = get_count (); |
|
414 if (likely (parsed_len > 0)) |
|
415 values[parsed_len-1].set_skip (); |
|
416 |
|
417 parsed_cs_op_t val; |
|
418 val.init (subr_num); |
|
419 SUPER::add_op (op, str_ref, val); |
|
420 } |
|
421 } |
|
422 |
|
423 void set_prefix (const number_t &num, op_code_t op = OpCode_Invalid) |
|
424 { |
|
425 has_prefix_ = true; |
|
426 prefix_op_ = op; |
|
427 prefix_num_ = num; |
|
428 } |
|
429 |
|
430 bool at_end (unsigned int pos) const |
|
431 { |
|
432 return ((pos + 1 >= values.length) /* CFF2 */ |
|
433 || (values[pos + 1].op == OpCode_return)); |
|
434 } |
|
435 |
|
436 bool is_parsed () const { return parsed; } |
|
437 void set_parsed () { parsed = true; } |
|
438 |
|
439 bool is_hint_dropped () const { return hint_dropped; } |
|
440 void set_hint_dropped () { hint_dropped = true; } |
|
441 |
|
442 bool is_vsindex_dropped () const { return vsindex_dropped; } |
|
443 void set_vsindex_dropped () { vsindex_dropped = true; } |
|
444 |
|
445 bool has_prefix () const { return has_prefix_; } |
|
446 op_code_t prefix_op () const { return prefix_op_; } |
|
447 const number_t &prefix_num () const { return prefix_num_; } |
|
448 |
|
449 protected: |
|
450 bool parsed; |
|
451 bool hint_dropped; |
|
452 bool vsindex_dropped; |
|
453 bool has_prefix_; |
|
454 op_code_t prefix_op_; |
|
455 number_t prefix_num_; |
|
456 |
|
457 private: |
|
458 typedef parsed_values_t<parsed_cs_op_t> SUPER; |
|
459 }; |
|
460 |
|
461 struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_t> |
|
462 { |
|
463 void init (unsigned int len_ = 0) |
|
464 { |
|
465 SUPER::init (); |
|
466 resize (len_); |
|
467 for (unsigned int i = 0; i < length; i++) |
|
468 (*this)[i].init (); |
|
469 } |
|
470 void fini () { SUPER::fini_deep (); } |
|
471 |
|
472 private: |
|
473 typedef hb_vector_t<parsed_cs_str_t> SUPER; |
|
474 }; |
|
475 |
|
476 struct subr_subset_param_t |
|
477 { |
|
478 void init (parsed_cs_str_t *parsed_charstring_, |
|
479 parsed_cs_str_vec_t *parsed_global_subrs_, parsed_cs_str_vec_t *parsed_local_subrs_, |
|
480 hb_set_t *global_closure_, hb_set_t *local_closure_, |
|
481 bool drop_hints_) |
|
482 { |
|
483 parsed_charstring = parsed_charstring_; |
|
484 current_parsed_str = parsed_charstring; |
|
485 parsed_global_subrs = parsed_global_subrs_; |
|
486 parsed_local_subrs = parsed_local_subrs_; |
|
487 global_closure = global_closure_; |
|
488 local_closure = local_closure_; |
|
489 drop_hints = drop_hints_; |
|
490 } |
|
491 |
|
492 parsed_cs_str_t *get_parsed_str_for_context (call_context_t &context) |
|
493 { |
|
494 switch (context.type) |
|
495 { |
|
496 case CSType_CharString: |
|
497 return parsed_charstring; |
|
498 |
|
499 case CSType_LocalSubr: |
|
500 if (likely (context.subr_num < parsed_local_subrs->length)) |
|
501 return &(*parsed_local_subrs)[context.subr_num]; |
|
502 break; |
|
503 |
|
504 case CSType_GlobalSubr: |
|
505 if (likely (context.subr_num < parsed_global_subrs->length)) |
|
506 return &(*parsed_global_subrs)[context.subr_num]; |
|
507 break; |
|
508 } |
|
509 return nullptr; |
|
510 } |
|
511 |
|
512 template <typename ENV> |
|
513 void set_current_str (ENV &env, bool calling) |
|
514 { |
|
515 parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context); |
|
516 if (likely (parsed_str != nullptr)) |
|
517 { |
|
518 /* If the called subroutine is parsed partially but not completely yet, |
|
519 * it must be because we are calling it recursively. |
|
520 * Handle it as an error. */ |
|
521 if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0))) |
|
522 env.set_error (); |
|
523 else |
|
524 current_parsed_str = parsed_str; |
|
525 } |
|
526 else |
|
527 env.set_error (); |
|
528 } |
|
529 |
|
530 parsed_cs_str_t *current_parsed_str; |
|
531 |
|
532 parsed_cs_str_t *parsed_charstring; |
|
533 parsed_cs_str_vec_t *parsed_global_subrs; |
|
534 parsed_cs_str_vec_t *parsed_local_subrs; |
|
535 hb_set_t *global_closure; |
|
536 hb_set_t *local_closure; |
|
537 bool drop_hints; |
|
538 }; |
|
539 |
|
540 struct subr_remap_t : remap_t |
|
541 { |
|
542 void create (hb_set_t *closure) |
|
543 { |
|
544 /* create a remapping of subroutine numbers from old to new. |
|
545 * no optimization based on usage counts. fonttools doesn't appear doing that either. |
|
546 */ |
|
547 reset (closure->get_max () + 1); |
|
548 for (hb_codepoint_t old_num = 0; old_num < length; old_num++) |
|
549 { |
|
550 if (hb_set_has (closure, old_num)) |
|
551 add (old_num); |
|
552 } |
|
553 |
|
554 if (get_count () < 1240) |
|
555 bias = 107; |
|
556 else if (get_count () < 33900) |
|
557 bias = 1131; |
|
558 else |
|
559 bias = 32768; |
|
560 } |
|
561 |
|
562 hb_codepoint_t operator[] (unsigned int old_num) const |
|
563 { |
|
564 if (old_num >= length) |
|
565 return CFF_UNDEF_CODE; |
|
566 else |
|
567 return remap_t::operator[] (old_num); |
|
568 } |
|
569 |
|
570 int biased_num (unsigned int old_num) const |
|
571 { |
|
572 hb_codepoint_t new_num = (*this)[old_num]; |
|
573 return (int)new_num - bias; |
|
574 } |
|
575 |
|
576 protected: |
|
577 int bias; |
|
578 }; |
|
579 |
|
580 struct subr_remap_ts |
|
581 { |
|
582 subr_remap_ts () |
|
583 { |
|
584 global_remap.init (); |
|
585 local_remaps.init (); |
|
586 } |
|
587 |
|
588 ~subr_remap_ts () { fini (); } |
|
589 |
|
590 void init (unsigned int fdCount) |
|
591 { |
|
592 local_remaps.resize (fdCount); |
|
593 for (unsigned int i = 0; i < fdCount; i++) |
|
594 local_remaps[i].init (); |
|
595 } |
|
596 |
|
597 void create (subr_closures_t& closures) |
|
598 { |
|
599 global_remap.create (closures.global_closure); |
|
600 for (unsigned int i = 0; i < local_remaps.length; i++) |
|
601 local_remaps[i].create (closures.local_closures[i]); |
|
602 } |
|
603 |
|
604 void fini () |
|
605 { |
|
606 global_remap.fini (); |
|
607 local_remaps.fini_deep (); |
|
608 } |
|
609 |
|
610 subr_remap_t global_remap; |
|
611 hb_vector_t<subr_remap_t> local_remaps; |
|
612 }; |
|
613 |
|
614 template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typename OPSET> |
|
615 struct subr_subsetter_t |
|
616 { |
|
617 subr_subsetter_t () |
|
618 { |
|
619 parsed_charstrings.init (); |
|
620 parsed_global_subrs.init (); |
|
621 parsed_local_subrs.init (); |
|
622 } |
|
623 |
|
624 ~subr_subsetter_t () |
|
625 { |
|
626 closures.fini (); |
|
627 remaps.fini (); |
|
628 parsed_charstrings.fini_deep (); |
|
629 parsed_global_subrs.fini_deep (); |
|
630 parsed_local_subrs.fini_deep (); |
|
631 } |
|
632 |
|
633 /* Subroutine subsetting with --no-desubroutinize runs in phases: |
|
634 * |
|
635 * 1. execute charstrings/subroutines to determine subroutine closures |
|
636 * 2. parse out all operators and numbers |
|
637 * 3. mark hint operators and operands for removal if --no-hinting |
|
638 * 4. re-encode all charstrings and subroutines with new subroutine numbers |
|
639 * |
|
640 * Phases #1 and #2 are done at the same time in collect_subrs (). |
|
641 * Phase #3 walks charstrings/subroutines forward then backward (hence parsing required), |
|
642 * because we can't tell if a number belongs to a hint op until we see the first moveto. |
|
643 * |
|
644 * Assumption: a callsubr/callgsubr operator must immediately follow a (biased) subroutine number |
|
645 * within the same charstring/subroutine, e.g., not split across a charstring and a subroutine. |
|
646 */ |
|
647 bool subset (ACC &acc, const hb_vector_t<hb_codepoint_t> &glyphs, bool drop_hints) |
|
648 { |
|
649 closures.init (acc.fdCount); |
|
650 remaps.init (acc.fdCount); |
|
651 |
|
652 parsed_charstrings.init (glyphs.length); |
|
653 parsed_global_subrs.init (acc.globalSubrs->count); |
|
654 parsed_local_subrs.resize (acc.fdCount); |
|
655 for (unsigned int i = 0; i < acc.fdCount; i++) |
|
656 { |
|
657 parsed_local_subrs[i].init (acc.privateDicts[i].localSubrs->count); |
|
658 } |
|
659 if (unlikely (!closures.valid)) |
|
660 return false; |
|
661 |
|
662 /* phase 1 & 2 */ |
|
663 for (unsigned int i = 0; i < glyphs.length; i++) |
|
664 { |
|
665 hb_codepoint_t glyph = glyphs[i]; |
|
666 const byte_str_t str = (*acc.charStrings)[glyph]; |
|
667 unsigned int fd = acc.fdSelect->get_fd (glyph); |
|
668 if (unlikely (fd >= acc.fdCount)) |
|
669 return false; |
|
670 |
|
671 cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp; |
|
672 interp.env.init (str, acc, fd); |
|
673 |
|
674 subr_subset_param_t param; |
|
675 param.init (&parsed_charstrings[i], |
|
676 &parsed_global_subrs, &parsed_local_subrs[fd], |
|
677 closures.global_closure, closures.local_closures[fd], |
|
678 drop_hints); |
|
679 |
|
680 if (unlikely (!interp.interpret (param))) |
|
681 return false; |
|
682 |
|
683 /* finalize parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */ |
|
684 SUBSETTER::finalize_parsed_str (interp.env, param, parsed_charstrings[i]); |
|
685 } |
|
686 |
|
687 if (drop_hints) |
|
688 { |
|
689 /* mark hint ops and arguments for drop */ |
|
690 for (unsigned int i = 0; i < glyphs.length; i++) |
|
691 { |
|
692 unsigned int fd = acc.fdSelect->get_fd (glyphs[i]); |
|
693 if (unlikely (fd >= acc.fdCount)) |
|
694 return false; |
|
695 subr_subset_param_t param; |
|
696 param.init (&parsed_charstrings[i], |
|
697 &parsed_global_subrs, &parsed_local_subrs[fd], |
|
698 closures.global_closure, closures.local_closures[fd], |
|
699 drop_hints); |
|
700 |
|
701 drop_hints_param_t drop; |
|
702 if (drop_hints_in_str (parsed_charstrings[i], param, drop)) |
|
703 { |
|
704 parsed_charstrings[i].set_hint_dropped (); |
|
705 if (drop.vsindex_dropped) |
|
706 parsed_charstrings[i].set_vsindex_dropped (); |
|
707 } |
|
708 } |
|
709 |
|
710 /* after dropping hints recreate closures of actually used subrs */ |
|
711 closures.reset (); |
|
712 for (unsigned int i = 0; i < glyphs.length; i++) |
|
713 { |
|
714 unsigned int fd = acc.fdSelect->get_fd (glyphs[i]); |
|
715 if (unlikely (fd >= acc.fdCount)) |
|
716 return false; |
|
717 subr_subset_param_t param; |
|
718 param.init (&parsed_charstrings[i], |
|
719 &parsed_global_subrs, &parsed_local_subrs[fd], |
|
720 closures.global_closure, closures.local_closures[fd], |
|
721 drop_hints); |
|
722 collect_subr_refs_in_str (parsed_charstrings[i], param); |
|
723 } |
|
724 } |
|
725 |
|
726 remaps.create (closures); |
|
727 |
|
728 return true; |
|
729 } |
|
730 |
|
731 bool encode_charstrings (ACC &acc, const hb_vector_t<hb_codepoint_t> &glyphs, str_buff_vec_t &buffArray) const |
|
732 { |
|
733 if (unlikely (!buffArray.resize (glyphs.length))) |
|
734 return false; |
|
735 for (unsigned int i = 0; i < glyphs.length; i++) |
|
736 { |
|
737 unsigned int fd = acc.fdSelect->get_fd (glyphs[i]); |
|
738 if (unlikely (fd >= acc.fdCount)) |
|
739 return false; |
|
740 if (unlikely (!encode_str (parsed_charstrings[i], fd, buffArray[i]))) |
|
741 return false; |
|
742 } |
|
743 return true; |
|
744 } |
|
745 |
|
746 bool encode_subrs (const parsed_cs_str_vec_t &subrs, const subr_remap_t& remap, unsigned int fd, str_buff_vec_t &buffArray) const |
|
747 { |
|
748 unsigned int count = remap.get_count (); |
|
749 |
|
750 if (unlikely (!buffArray.resize (count))) |
|
751 return false; |
|
752 for (unsigned int old_num = 0; old_num < subrs.length; old_num++) |
|
753 { |
|
754 hb_codepoint_t new_num = remap[old_num]; |
|
755 if (new_num != CFF_UNDEF_CODE) |
|
756 { |
|
757 if (unlikely (!encode_str (subrs[old_num], fd, buffArray[new_num]))) |
|
758 return false; |
|
759 } |
|
760 } |
|
761 return true; |
|
762 } |
|
763 |
|
764 bool encode_globalsubrs (str_buff_vec_t &buffArray) |
|
765 { |
|
766 return encode_subrs (parsed_global_subrs, remaps.global_remap, 0, buffArray); |
|
767 } |
|
768 |
|
769 bool encode_localsubrs (unsigned int fd, str_buff_vec_t &buffArray) const |
|
770 { |
|
771 return encode_subrs (parsed_local_subrs[fd], remaps.local_remaps[fd], fd, buffArray); |
|
772 } |
|
773 |
|
774 protected: |
|
775 struct drop_hints_param_t |
|
776 { |
|
777 drop_hints_param_t () |
|
778 : seen_moveto (false), |
|
779 ends_in_hint (false), |
|
780 vsindex_dropped (false) {} |
|
781 |
|
782 bool seen_moveto; |
|
783 bool ends_in_hint; |
|
784 bool vsindex_dropped; |
|
785 }; |
|
786 |
|
787 bool drop_hints_in_subr (parsed_cs_str_t &str, unsigned int pos, |
|
788 parsed_cs_str_vec_t &subrs, unsigned int subr_num, |
|
789 const subr_subset_param_t ¶m, drop_hints_param_t &drop) |
|
790 { |
|
791 drop.ends_in_hint = false; |
|
792 bool has_hint = drop_hints_in_str (subrs[subr_num], param, drop); |
|
793 |
|
794 /* if this subr ends with a stem hint (i.e., not a number a potential argument for moveto), |
|
795 * then this entire subroutine must be a hint. drop its call. */ |
|
796 if (drop.ends_in_hint) |
|
797 { |
|
798 str.values[pos].set_drop (); |
|
799 /* if this subr call is at the end of the parent subr, propagate the flag |
|
800 * otherwise reset the flag */ |
|
801 if (!str.at_end (pos)) |
|
802 drop.ends_in_hint = false; |
|
803 } |
|
804 |
|
805 return has_hint; |
|
806 } |
|
807 |
|
808 /* returns true if it sees a hint op before the first moveto */ |
|
809 bool drop_hints_in_str (parsed_cs_str_t &str, const subr_subset_param_t ¶m, drop_hints_param_t &drop) |
|
810 { |
|
811 bool seen_hint = false; |
|
812 |
|
813 for (unsigned int pos = 0; pos < str.values.length; pos++) |
|
814 { |
|
815 bool has_hint = false; |
|
816 switch (str.values[pos].op) |
|
817 { |
|
818 case OpCode_callsubr: |
|
819 has_hint = drop_hints_in_subr (str, pos, |
|
820 *param.parsed_local_subrs, str.values[pos].subr_num, |
|
821 param, drop); |
|
822 |
|
823 break; |
|
824 |
|
825 case OpCode_callgsubr: |
|
826 has_hint = drop_hints_in_subr (str, pos, |
|
827 *param.parsed_global_subrs, str.values[pos].subr_num, |
|
828 param, drop); |
|
829 break; |
|
830 |
|
831 case OpCode_rmoveto: |
|
832 case OpCode_hmoveto: |
|
833 case OpCode_vmoveto: |
|
834 drop.seen_moveto = true; |
|
835 break; |
|
836 |
|
837 case OpCode_hintmask: |
|
838 case OpCode_cntrmask: |
|
839 if (drop.seen_moveto) |
|
840 { |
|
841 str.values[pos].set_drop (); |
|
842 break; |
|
843 } |
|
844 HB_FALLTHROUGH; |
|
845 |
|
846 case OpCode_hstemhm: |
|
847 case OpCode_vstemhm: |
|
848 case OpCode_hstem: |
|
849 case OpCode_vstem: |
|
850 has_hint = true; |
|
851 str.values[pos].set_drop (); |
|
852 if (str.at_end (pos)) |
|
853 drop.ends_in_hint = true; |
|
854 break; |
|
855 |
|
856 case OpCode_dotsection: |
|
857 str.values[pos].set_drop (); |
|
858 break; |
|
859 |
|
860 default: |
|
861 /* NONE */ |
|
862 break; |
|
863 } |
|
864 if (has_hint) |
|
865 { |
|
866 for (int i = pos - 1; i >= 0; i--) |
|
867 { |
|
868 parsed_cs_op_t &csop = str.values[(unsigned)i]; |
|
869 if (csop.for_drop ()) |
|
870 break; |
|
871 csop.set_drop (); |
|
872 if (csop.op == OpCode_vsindexcs) |
|
873 drop.vsindex_dropped = true; |
|
874 } |
|
875 seen_hint |= has_hint; |
|
876 } |
|
877 } |
|
878 |
|
879 return seen_hint; |
|
880 } |
|
881 |
|
882 void collect_subr_refs_in_subr (parsed_cs_str_t &str, unsigned int pos, |
|
883 unsigned int subr_num, parsed_cs_str_vec_t &subrs, |
|
884 hb_set_t *closure, |
|
885 const subr_subset_param_t ¶m) |
|
886 { |
|
887 hb_set_add (closure, subr_num); |
|
888 collect_subr_refs_in_str (subrs[subr_num], param); |
|
889 } |
|
890 |
|
891 void collect_subr_refs_in_str (parsed_cs_str_t &str, const subr_subset_param_t ¶m) |
|
892 { |
|
893 for (unsigned int pos = 0; pos < str.values.length; pos++) |
|
894 { |
|
895 if (!str.values[pos].for_drop ()) |
|
896 { |
|
897 switch (str.values[pos].op) |
|
898 { |
|
899 case OpCode_callsubr: |
|
900 collect_subr_refs_in_subr (str, pos, |
|
901 str.values[pos].subr_num, *param.parsed_local_subrs, |
|
902 param.local_closure, param); |
|
903 break; |
|
904 |
|
905 case OpCode_callgsubr: |
|
906 collect_subr_refs_in_subr (str, pos, |
|
907 str.values[pos].subr_num, *param.parsed_global_subrs, |
|
908 param.global_closure, param); |
|
909 break; |
|
910 |
|
911 default: break; |
|
912 } |
|
913 } |
|
914 } |
|
915 } |
|
916 |
|
917 bool encode_str (const parsed_cs_str_t &str, const unsigned int fd, str_buff_t &buff) const |
|
918 { |
|
919 buff.init (); |
|
920 str_encoder_t encoder (buff); |
|
921 encoder.reset (); |
|
922 /* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints, |
|
923 * re-insert it at the beginning of charstreing */ |
|
924 if (str.has_prefix () && str.is_hint_dropped ()) |
|
925 { |
|
926 encoder.encode_num (str.prefix_num ()); |
|
927 if (str.prefix_op () != OpCode_Invalid) |
|
928 encoder.encode_op (str.prefix_op ()); |
|
929 } |
|
930 for (unsigned int i = 0; i < str.get_count(); i++) |
|
931 { |
|
932 const parsed_cs_op_t &opstr = str.values[i]; |
|
933 if (!opstr.for_drop () && !opstr.for_skip ()) |
|
934 { |
|
935 switch (opstr.op) |
|
936 { |
|
937 case OpCode_callsubr: |
|
938 encoder.encode_int (remaps.local_remaps[fd].biased_num (opstr.subr_num)); |
|
939 encoder.encode_op (OpCode_callsubr); |
|
940 break; |
|
941 |
|
942 case OpCode_callgsubr: |
|
943 encoder.encode_int (remaps.global_remap.biased_num (opstr.subr_num)); |
|
944 encoder.encode_op (OpCode_callgsubr); |
|
945 break; |
|
946 |
|
947 default: |
|
948 encoder.copy_str (opstr.str); |
|
949 break; |
|
950 } |
|
951 } |
|
952 } |
|
953 return !encoder.is_error (); |
|
954 } |
|
955 |
|
956 protected: |
|
957 subr_closures_t closures; |
|
958 |
|
959 parsed_cs_str_vec_t parsed_charstrings; |
|
960 parsed_cs_str_vec_t parsed_global_subrs; |
|
961 hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs; |
|
962 |
|
963 subr_remap_ts remaps; |
|
964 |
|
965 private: |
|
966 typedef typename SUBRS::count_type subr_count_type; |
|
967 }; |
|
968 |
|
969 } /* namespace CFF */ |
|
970 |
|
971 HB_INTERNAL bool |
|
972 hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs, |
|
973 unsigned int fdCount, |
|
974 const CFF::FDSelect &src, /* IN */ |
|
975 unsigned int &subset_fd_count /* OUT */, |
|
976 unsigned int &subset_fdselect_size /* OUT */, |
|
977 unsigned int &subset_fdselect_format /* OUT */, |
|
978 hb_vector_t<CFF::code_pair_t> &fdselect_ranges /* OUT */, |
|
979 CFF::remap_t &fdmap /* OUT */); |
|
980 |
|
981 HB_INTERNAL bool |
|
982 hb_serialize_cff_fdselect (hb_serialize_context_t *c, |
|
983 unsigned int num_glyphs, |
|
984 const CFF::FDSelect &src, |
|
985 unsigned int fd_count, |
|
986 unsigned int fdselect_format, |
|
987 unsigned int size, |
|
988 const hb_vector_t<CFF::code_pair_t> &fdselect_ranges); |
|
989 |
|
990 #endif /* HB_SUBSET_CFF_COMMON_HH */ |