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 #include "hb.hh"
28
29 #ifndef HB_NO_SUBSET_CFF
30
31 #include "hb-open-type.hh"
32 #include "hb-ot-cff1-table.hh"
33 #include "hb-set.h"
34 #include "hb-bimap.hh"
35 #include "hb-subset-plan.hh"
36 #include "hb-subset-cff-common.hh"
37 #include "hb-cff1-interp-cs.hh"
38
39 using namespace CFF;
40
41 struct remap_sid_t
42 {
get_populationremap_sid_t43 unsigned get_population () const { return vector.length; }
44
allocremap_sid_t45 void alloc (unsigned size)
46 {
47 map.alloc (size);
48 vector.alloc (size, true);
49 }
50
in_errorremap_sid_t51 bool in_error () const
52 { return map.in_error () || vector.in_error (); }
53
addremap_sid_t54 unsigned int add (unsigned int sid)
55 {
56 if (is_std_str (sid) || (sid == CFF_UNDEF_SID))
57 return sid;
58
59 sid = unoffset_sid (sid);
60 unsigned v = next;
61 if (map.set (sid, v, false))
62 {
63 vector.push (sid);
64 next++;
65 }
66 else
67 v = map.get (sid); // already exists
68 return offset_sid (v);
69 }
70
operator []remap_sid_t71 unsigned int operator[] (unsigned int sid) const
72 {
73 if (is_std_str (sid) || (sid == CFF_UNDEF_SID))
74 return sid;
75
76 return offset_sid (map.get (unoffset_sid (sid)));
77 }
78
79 static const unsigned int num_std_strings = 391;
80
is_std_strremap_sid_t81 static bool is_std_str (unsigned int sid) { return sid < num_std_strings; }
offset_sidremap_sid_t82 static unsigned int offset_sid (unsigned int sid) { return sid + num_std_strings; }
unoffset_sidremap_sid_t83 static unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; }
84 unsigned next = 0;
85
86 hb_map_t map;
87 hb_vector_t<unsigned> vector;
88 };
89
90 struct cff1_sub_table_info_t : cff_sub_table_info_t
91 {
cff1_sub_table_info_tcff1_sub_table_info_t92 cff1_sub_table_info_t ()
93 : cff_sub_table_info_t (),
94 encoding_link (0),
95 charset_link (0)
96 {
97 privateDictInfo.init ();
98 }
99
100 objidx_t encoding_link;
101 objidx_t charset_link;
102 table_info_t privateDictInfo;
103 };
104
105 /* a copy of a parsed out cff1_top_dict_values_t augmented with additional operators */
106 struct cff1_top_dict_values_mod_t : cff1_top_dict_values_t
107 {
initcff1_top_dict_values_mod_t108 void init (const cff1_top_dict_values_t *base_= &Null (cff1_top_dict_values_t))
109 {
110 SUPER::init ();
111 base = base_;
112 }
113
finicff1_top_dict_values_mod_t114 void fini () { SUPER::fini (); }
115
get_countcff1_top_dict_values_mod_t116 unsigned get_count () const { return base->get_count () + SUPER::get_count (); }
get_valuecff1_top_dict_values_mod_t117 const cff1_top_dict_val_t &get_value (unsigned int i) const
118 {
119 if (i < base->get_count ())
120 return (*base)[i];
121 else
122 return SUPER::values[i - base->get_count ()];
123 }
operator []cff1_top_dict_values_mod_t124 const cff1_top_dict_val_t &operator [] (unsigned int i) const { return get_value (i); }
125
reassignSIDscff1_top_dict_values_mod_t126 void reassignSIDs (const remap_sid_t& sidmap)
127 {
128 for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
129 nameSIDs[i] = sidmap[base->nameSIDs[i]];
130 }
131
132 protected:
133 typedef cff1_top_dict_values_t SUPER;
134 const cff1_top_dict_values_t *base;
135 };
136
137 struct top_dict_modifiers_t
138 {
top_dict_modifiers_ttop_dict_modifiers_t139 top_dict_modifiers_t (const cff1_sub_table_info_t &info_,
140 const unsigned int (&nameSIDs_)[name_dict_values_t::ValCount])
141 : info (info_),
142 nameSIDs (nameSIDs_)
143 {}
144
145 const cff1_sub_table_info_t &info;
146 const unsigned int (&nameSIDs)[name_dict_values_t::ValCount];
147 };
148
149 struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<cff1_top_dict_val_t>
150 {
serializecff1_top_dict_op_serializer_t151 bool serialize (hb_serialize_context_t *c,
152 const cff1_top_dict_val_t &opstr,
153 const top_dict_modifiers_t &mod) const
154 {
155 TRACE_SERIALIZE (this);
156
157 op_code_t op = opstr.op;
158 switch (op)
159 {
160 case OpCode_charset:
161 if (mod.info.charset_link)
162 return_trace (FontDict::serialize_link4_op(c, op, mod.info.charset_link, whence_t::Absolute));
163 else
164 goto fall_back;
165
166 case OpCode_Encoding:
167 if (mod.info.encoding_link)
168 return_trace (FontDict::serialize_link4_op(c, op, mod.info.encoding_link, whence_t::Absolute));
169 else
170 goto fall_back;
171
172 case OpCode_Private:
173 return_trace (UnsizedByteStr::serialize_int2 (c, mod.info.privateDictInfo.size) &&
174 Dict::serialize_link4_op (c, op, mod.info.privateDictInfo.link, whence_t::Absolute));
175
176 case OpCode_version:
177 case OpCode_Notice:
178 case OpCode_Copyright:
179 case OpCode_FullName:
180 case OpCode_FamilyName:
181 case OpCode_Weight:
182 case OpCode_PostScript:
183 case OpCode_BaseFontName:
184 case OpCode_FontName:
185 return_trace (FontDict::serialize_int2_op (c, op, mod.nameSIDs[name_dict_values_t::name_op_to_index (op)]));
186
187 case OpCode_ROS:
188 {
189 /* for registry & ordering, reassigned SIDs are serialized
190 * for supplement, the original byte string is copied along with the op code */
191 op_str_t supp_op;
192 supp_op.op = op;
193 if ( unlikely (!(opstr.length >= opstr.last_arg_offset + 3)))
194 return_trace (false);
195 supp_op.ptr = opstr.ptr + opstr.last_arg_offset;
196 supp_op.length = opstr.length - opstr.last_arg_offset;
197 return_trace (UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::registry]) &&
198 UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::ordering]) &&
199 copy_opstr (c, supp_op));
200 }
201 fall_back:
202 default:
203 return_trace (cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::serialize (c, opstr, mod.info));
204 }
205 return_trace (true);
206 }
207
208 };
209
210 struct cff1_font_dict_op_serializer_t : cff_font_dict_op_serializer_t
211 {
serializecff1_font_dict_op_serializer_t212 bool serialize (hb_serialize_context_t *c,
213 const op_str_t &opstr,
214 const cff1_font_dict_values_mod_t &mod) const
215 {
216 TRACE_SERIALIZE (this);
217
218 if (opstr.op == OpCode_FontName)
219 return_trace (FontDict::serialize_int2_op (c, opstr.op, mod.fontName));
220 else
221 return_trace (SUPER::serialize (c, opstr, mod.privateDictInfo));
222 }
223
224 private:
225 typedef cff_font_dict_op_serializer_t SUPER;
226 };
227
228 struct cff1_cs_opset_flatten_t : cff1_cs_opset_t<cff1_cs_opset_flatten_t, flatten_param_t>
229 {
flush_args_and_opcff1_cs_opset_flatten_t230 static void flush_args_and_op (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param)
231 {
232 if (env.arg_start > 0)
233 flush_width (env, param);
234
235 switch (op)
236 {
237 case OpCode_hstem:
238 case OpCode_hstemhm:
239 case OpCode_vstem:
240 case OpCode_vstemhm:
241 case OpCode_hintmask:
242 case OpCode_cntrmask:
243 case OpCode_dotsection:
244 if (param.drop_hints)
245 {
246 env.clear_args ();
247 return;
248 }
249 HB_FALLTHROUGH;
250
251 default:
252 SUPER::flush_args_and_op (op, env, param);
253 break;
254 }
255 }
flush_argscff1_cs_opset_flatten_t256 static void flush_args (cff1_cs_interp_env_t &env, flatten_param_t& param)
257 {
258 str_encoder_t encoder (param.flatStr);
259 for (unsigned int i = env.arg_start; i < env.argStack.get_count (); i++)
260 encoder.encode_num_cs (env.eval_arg (i));
261 SUPER::flush_args (env, param);
262 }
263
flush_opcff1_cs_opset_flatten_t264 static void flush_op (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param)
265 {
266 str_encoder_t encoder (param.flatStr);
267 encoder.encode_op (op);
268 }
269
flush_widthcff1_cs_opset_flatten_t270 static void flush_width (cff1_cs_interp_env_t &env, flatten_param_t& param)
271 {
272 assert (env.has_width);
273 str_encoder_t encoder (param.flatStr);
274 encoder.encode_num_cs (env.width);
275 }
276
flush_hintmaskcff1_cs_opset_flatten_t277 static void flush_hintmask (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param)
278 {
279 SUPER::flush_hintmask (op, env, param);
280 if (!param.drop_hints)
281 {
282 str_encoder_t encoder (param.flatStr);
283 for (unsigned int i = 0; i < env.hintmask_size; i++)
284 encoder.encode_byte (env.str_ref[i]);
285 }
286 }
287
288 private:
289 typedef cff1_cs_opset_t<cff1_cs_opset_flatten_t, flatten_param_t> SUPER;
290 };
291
292 struct range_list_t : hb_vector_t<code_pair_t>
293 {
294 /* replace the first glyph ID in the "glyph" field each range with a nLeft value */
completerange_list_t295 bool complete (unsigned int last_glyph)
296 {
297 hb_codepoint_t all_glyphs = 0;
298 unsigned count = this->length;
299 for (unsigned int i = count; i; i--)
300 {
301 code_pair_t &pair = arrayZ[i - 1];
302 unsigned int nLeft = last_glyph - pair.glyph - 1;
303 all_glyphs |= nLeft;
304 last_glyph = pair.glyph;
305 pair.glyph = nLeft;
306 }
307 bool two_byte = all_glyphs >= 0x100;
308 return two_byte;
309 }
310 };
311
312 struct cff1_cs_opset_subr_subset_t : cff1_cs_opset_t<cff1_cs_opset_subr_subset_t, subr_subset_param_t>
313 {
process_opcff1_cs_opset_subr_subset_t314 static void process_op (op_code_t op, cff1_cs_interp_env_t &env, subr_subset_param_t& param)
315 {
316 switch (op) {
317
318 case OpCode_return:
319 param.current_parsed_str->add_op (op, env.str_ref);
320 param.current_parsed_str->set_parsed ();
321 env.return_from_subr ();
322 param.set_current_str (env, false);
323 break;
324
325 case OpCode_endchar:
326 param.current_parsed_str->add_op (op, env.str_ref);
327 param.current_parsed_str->set_parsed ();
328 SUPER::process_op (op, env, param);
329 break;
330
331 case OpCode_callsubr:
332 process_call_subr (op, CSType_LocalSubr, env, param, env.localSubrs, param.local_closure);
333 break;
334
335 case OpCode_callgsubr:
336 process_call_subr (op, CSType_GlobalSubr, env, param, env.globalSubrs, param.global_closure);
337 break;
338
339 default:
340 SUPER::process_op (op, env, param);
341 param.current_parsed_str->add_op (op, env.str_ref);
342 break;
343 }
344 }
345
346 protected:
process_call_subrcff1_cs_opset_subr_subset_t347 static void process_call_subr (op_code_t op, cs_type_t type,
348 cff1_cs_interp_env_t &env, subr_subset_param_t& param,
349 cff1_biased_subrs_t& subrs, hb_set_t *closure)
350 {
351 byte_str_ref_t str_ref = env.str_ref;
352 env.call_subr (subrs, type);
353 param.current_parsed_str->add_call_op (op, str_ref, env.context.subr_num);
354 closure->add (env.context.subr_num);
355 param.set_current_str (env, true);
356 }
357
358 private:
359 typedef cff1_cs_opset_t<cff1_cs_opset_subr_subset_t, subr_subset_param_t> SUPER;
360 };
361
362 struct cff1_private_dict_op_serializer_t : op_serializer_t
363 {
cff1_private_dict_op_serializer_tcff1_private_dict_op_serializer_t364 cff1_private_dict_op_serializer_t (bool desubroutinize_, bool drop_hints_)
365 : desubroutinize (desubroutinize_), drop_hints (drop_hints_) {}
366
serializecff1_private_dict_op_serializer_t367 bool serialize (hb_serialize_context_t *c,
368 const op_str_t &opstr,
369 objidx_t subrs_link) const
370 {
371 TRACE_SERIALIZE (this);
372
373 if (drop_hints && dict_opset_t::is_hint_op (opstr.op))
374 return_trace (true);
375
376 if (opstr.op == OpCode_Subrs)
377 {
378 if (desubroutinize || !subrs_link)
379 return_trace (true);
380 else
381 return_trace (FontDict::serialize_link2_op (c, opstr.op, subrs_link));
382 }
383
384 return_trace (copy_opstr (c, opstr));
385 }
386
387 protected:
388 const bool desubroutinize;
389 const bool drop_hints;
390 };
391
392 struct cff1_subr_subsetter_t : subr_subsetter_t<cff1_subr_subsetter_t, CFF1Subrs, const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, OpCode_endchar>
393 {
cff1_subr_subsetter_tcff1_subr_subsetter_t394 cff1_subr_subsetter_t (const OT::cff1::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_)
395 : subr_subsetter_t (acc_, plan_) {}
396
complete_parsed_strcff1_subr_subsetter_t397 static void complete_parsed_str (cff1_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
398 {
399 /* insert width at the beginning of the charstring as necessary */
400 if (env.has_width)
401 charstring.set_prefix (env.width);
402
403 /* subroutines/charstring left on the call stack are legally left unmarked
404 * unmarked when a subroutine terminates with endchar. mark them.
405 */
406 param.current_parsed_str->set_parsed ();
407 for (unsigned int i = 0; i < env.callStack.get_count (); i++)
408 {
409 parsed_cs_str_t *parsed_str = param.get_parsed_str_for_context (env.callStack[i]);
410 if (likely (parsed_str))
411 parsed_str->set_parsed ();
412 else
413 env.set_error ();
414 }
415 }
416 };
417
418 namespace OT {
419 struct cff1_subset_plan
420 {
cff1_subset_planOT::cff1_subset_plan421 cff1_subset_plan ()
422 {
423 for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
424 topDictModSIDs[i] = CFF_UNDEF_SID;
425 }
426
plan_subset_encodingOT::cff1_subset_plan427 void plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
428 {
429 const Encoding *encoding = acc.encoding;
430 unsigned int size0, size1;
431 unsigned code, last_code = CFF_UNDEF_CODE - 1;
432 hb_vector_t<hb_codepoint_t> supp_codes;
433
434 if (unlikely (!subset_enc_code_ranges.resize (0)))
435 {
436 plan->check_success (false);
437 return;
438 }
439
440 supp_codes.init ();
441
442 code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID};
443 subset_enc_num_codes = plan->num_output_glyphs () - 1;
444 unsigned int glyph;
445 auto it = hb_iter (plan->new_to_old_gid_list);
446 if (it->first == 0) it++;
447 auto _ = *it;
448 for (glyph = 1; glyph < num_glyphs; glyph++)
449 {
450 hb_codepoint_t old_glyph;
451 if (glyph == _.first)
452 {
453 old_glyph = _.second;
454 _ = *++it;
455 }
456 else
457 {
458 /* Retain the SID for the old missing glyph ID */
459 old_glyph = glyph;
460 }
461 code = acc.glyph_to_code (old_glyph, &glyph_to_sid_cache);
462 if (code == CFF_UNDEF_CODE)
463 {
464 subset_enc_num_codes = glyph - 1;
465 break;
466 }
467
468 if (code != last_code + 1)
469 subset_enc_code_ranges.push (code_pair_t {code, glyph});
470 last_code = code;
471
472 if (encoding != &Null (Encoding))
473 {
474 hb_codepoint_t sid = acc.glyph_to_sid (old_glyph, &glyph_to_sid_cache);
475 encoding->get_supplement_codes (sid, supp_codes);
476 for (unsigned int i = 0; i < supp_codes.length; i++)
477 subset_enc_supp_codes.push (code_pair_t {supp_codes[i], sid});
478 }
479 }
480 supp_codes.fini ();
481
482 subset_enc_code_ranges.complete (glyph);
483
484 assert (subset_enc_num_codes <= 0xFF);
485 size0 = Encoding0::min_size + HBUINT8::static_size * subset_enc_num_codes;
486 size1 = Encoding1::min_size + Encoding1_Range::static_size * subset_enc_code_ranges.length;
487
488 if (size0 < size1)
489 subset_enc_format = 0;
490 else
491 subset_enc_format = 1;
492 }
493
plan_subset_charsetOT::cff1_subset_plan494 bool plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
495 {
496 unsigned int size0, size_ranges;
497 unsigned last_sid = CFF_UNDEF_CODE - 1;
498
499 if (unlikely (!subset_charset_ranges.resize (0)))
500 {
501 plan->check_success (false);
502 return false;
503 }
504
505 code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID};
506
507 unsigned num_glyphs = plan->num_output_glyphs ();
508
509 if (unlikely (!subset_charset_ranges.alloc (hb_min (num_glyphs,
510 acc.num_charset_entries))))
511 {
512 plan->check_success (false);
513 return false;
514 }
515
516 glyph_to_sid_map_t *glyph_to_sid_map = acc.cff_accelerator ?
517 acc.cff_accelerator->glyph_to_sid_map.get_acquire () :
518 nullptr;
519 bool created_map = false;
520 if (!glyph_to_sid_map && acc.cff_accelerator)
521 {
522 created_map = true;
523 glyph_to_sid_map = acc.create_glyph_to_sid_map ();
524 }
525
526 auto it = hb_iter (plan->new_to_old_gid_list);
527 if (it->first == 0) it++;
528 auto _ = *it;
529 bool not_is_cid = !acc.is_CID ();
530 bool skip = !not_is_cid && glyph_to_sid_map;
531 if (not_is_cid)
532 sidmap.alloc (num_glyphs);
533 for (hb_codepoint_t glyph = 1; glyph < num_glyphs; glyph++)
534 {
535 hb_codepoint_t old_glyph;
536 if (glyph == _.first)
537 {
538 old_glyph = _.second;
539 _ = *++it;
540 }
541 else
542 {
543 /* Retain the SID for the old missing glyph ID */
544 old_glyph = glyph;
545 }
546 unsigned sid = glyph_to_sid_map ?
547 glyph_to_sid_map->arrayZ[old_glyph].code :
548 acc.glyph_to_sid (old_glyph, &glyph_to_sid_cache);
549
550 if (not_is_cid)
551 sid = sidmap.add (sid);
552
553 if (sid != last_sid + 1)
554 subset_charset_ranges.push (code_pair_t {sid, glyph});
555
556 if (glyph == old_glyph && skip)
557 {
558 glyph = hb_min (_.first - 1, glyph_to_sid_map->arrayZ[old_glyph].glyph);
559 sid += glyph - old_glyph;
560 }
561 last_sid = sid;
562 }
563
564 if (created_map)
565 {
566 if ((!plan->accelerator && acc.cff_accelerator) ||
567 !acc.cff_accelerator->glyph_to_sid_map.cmpexch (nullptr, glyph_to_sid_map))
568 {
569 glyph_to_sid_map->~glyph_to_sid_map_t ();
570 hb_free (glyph_to_sid_map);
571 }
572 }
573
574 bool two_byte = subset_charset_ranges.complete (num_glyphs);
575
576 size0 = Charset0::get_size (plan->num_output_glyphs ());
577 if (!two_byte)
578 size_ranges = Charset1::get_size_for_ranges (subset_charset_ranges.length);
579 else
580 size_ranges = Charset2::get_size_for_ranges (subset_charset_ranges.length);
581
582 if (size0 < size_ranges)
583 subset_charset_format = 0;
584 else if (!two_byte)
585 subset_charset_format = 1;
586 else
587 subset_charset_format = 2;
588
589 return true;
590 }
591
collect_sids_in_dictsOT::cff1_subset_plan592 bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc)
593 {
594 for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
595 {
596 unsigned int sid = acc.topDict.nameSIDs[i];
597 if (sid != CFF_UNDEF_SID)
598 {
599 topDictModSIDs[i] = sidmap.add (sid);
600 }
601 }
602
603 if (acc.fdArray != &Null (CFF1FDArray))
604 for (unsigned int i = 0; i < orig_fdcount; i++)
605 if (fdmap.has (i))
606 (void)sidmap.add (acc.fontDicts[i].fontName);
607
608 return true;
609 }
610
createOT::cff1_subset_plan611 bool create (const OT::cff1::accelerator_subset_t &acc,
612 hb_subset_plan_t *plan)
613 {
614 /* make sure notdef is first */
615 hb_codepoint_t old_glyph;
616 if (!plan->old_gid_for_new_gid (0, &old_glyph) || (old_glyph != 0)) return false;
617
618 num_glyphs = plan->num_output_glyphs ();
619 orig_fdcount = acc.fdCount;
620 drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING;
621 desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE;
622
623 #ifdef HB_EXPERIMENTAL_API
624 min_charstrings_off_size = (plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS) ? 4 : 0;
625 #else
626 min_charstrings_off_size = 0;
627 #endif
628
629 subset_charset = !acc.is_predef_charset ();
630 if (!subset_charset)
631 /* check whether the subset renumbers any glyph IDs */
632 for (const auto &_ : plan->new_to_old_gid_list)
633 {
634 if (_.first != _.second)
635 {
636 subset_charset = true;
637 break;
638 }
639 }
640
641 subset_encoding = !acc.is_CID() && !acc.is_predef_encoding ();
642
643 /* top dict INDEX */
644 {
645 /* Add encoding/charset to a (copy of) top dict as necessary */
646 topdict_mod.init (&acc.topDict);
647 bool need_to_add_enc = (subset_encoding && !acc.topDict.has_op (OpCode_Encoding));
648 bool need_to_add_set = (subset_charset && !acc.topDict.has_op (OpCode_charset));
649 if (need_to_add_enc || need_to_add_set)
650 {
651 if (need_to_add_enc)
652 topdict_mod.add_op (OpCode_Encoding);
653 if (need_to_add_set)
654 topdict_mod.add_op (OpCode_charset);
655 }
656 }
657
658 /* Determine re-mapping of font index as fdmap among other info */
659 if (acc.fdSelect != &Null (CFF1FDSelect))
660 {
661 if (unlikely (!hb_plan_subset_cff_fdselect (plan,
662 orig_fdcount,
663 *acc.fdSelect,
664 subset_fdcount,
665 info.fd_select.size,
666 subset_fdselect_format,
667 subset_fdselect_ranges,
668 fdmap)))
669 return false;
670 }
671 else
672 fdmap.identity (1);
673
674 /* remove unused SIDs & reassign SIDs */
675 {
676 /* SIDs for name strings in dicts are added before glyph names so they fit in 16-bit int range */
677 if (unlikely (!collect_sids_in_dicts (acc)))
678 return false;
679 if (unlikely (sidmap.get_population () > 0x8000)) /* assumption: a dict won't reference that many strings */
680 return false;
681
682 if (subset_charset && !plan_subset_charset (acc, plan))
683 return false;
684
685 topdict_mod.reassignSIDs (sidmap);
686 }
687
688 if (desubroutinize)
689 {
690 /* Flatten global & local subrs */
691 subr_flattener_t<const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_flatten_t, OpCode_endchar>
692 flattener(acc, plan);
693 if (!flattener.flatten (subset_charstrings))
694 return false;
695 }
696 else
697 {
698 cff1_subr_subsetter_t subr_subsetter (acc, plan);
699
700 /* Subset subrs: collect used subroutines, leaving all unused ones behind */
701 if (!subr_subsetter.subset ())
702 return false;
703
704 /* encode charstrings, global subrs, local subrs with new subroutine numbers */
705 if (!subr_subsetter.encode_charstrings (subset_charstrings))
706 return false;
707
708 if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
709 return false;
710
711 /* local subrs */
712 if (!subset_localsubrs.resize (orig_fdcount))
713 return false;
714 for (unsigned int fd = 0; fd < orig_fdcount; fd++)
715 {
716 subset_localsubrs[fd].init ();
717 if (fdmap.has (fd))
718 {
719 if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd]))
720 return false;
721 }
722 }
723 }
724
725 /* Encoding */
726 if (subset_encoding)
727 plan_subset_encoding (acc, plan);
728
729 /* private dicts & local subrs */
730 if (!acc.is_CID ())
731 fontdicts_mod.push (cff1_font_dict_values_mod_t ());
732 else
733 {
734 + hb_iter (acc.fontDicts)
735 | hb_filter ([&] (const cff1_font_dict_values_t &_)
736 { return fdmap.has (&_ - &acc.fontDicts[0]); } )
737 | hb_map ([&] (const cff1_font_dict_values_t &_)
738 {
739 cff1_font_dict_values_mod_t mod;
740 mod.init (&_, sidmap[_.fontName]);
741 return mod;
742 })
743 | hb_sink (fontdicts_mod)
744 ;
745 }
746
747 return !plan->in_error () &&
748 (subset_charstrings.length == plan->num_output_glyphs ()) &&
749 (fontdicts_mod.length == subset_fdcount);
750 }
751
752 cff1_top_dict_values_mod_t topdict_mod;
753 cff1_sub_table_info_t info;
754
755 unsigned int num_glyphs;
756 unsigned int orig_fdcount = 0;
757 unsigned int subset_fdcount = 1;
758 unsigned int subset_fdselect_format = 0;
759 hb_vector_t<code_pair_t> subset_fdselect_ranges;
760
761 /* font dict index remap table from fullset FDArray to subset FDArray.
762 * set to CFF_UNDEF_CODE if excluded from subset */
763 hb_inc_bimap_t fdmap;
764
765 str_buff_vec_t subset_charstrings;
766 str_buff_vec_t subset_globalsubrs;
767 hb_vector_t<str_buff_vec_t> subset_localsubrs;
768 hb_vector_t<cff1_font_dict_values_mod_t> fontdicts_mod;
769
770 bool drop_hints = false;
771
772 bool gid_renum;
773 bool subset_encoding;
774 uint8_t subset_enc_format;
775 unsigned int subset_enc_num_codes;
776 range_list_t subset_enc_code_ranges;
777 hb_vector_t<code_pair_t> subset_enc_supp_codes;
778
779 uint8_t subset_charset_format;
780 range_list_t subset_charset_ranges;
781 bool subset_charset;
782
783 remap_sid_t sidmap;
784 unsigned int topDictModSIDs[name_dict_values_t::ValCount];
785
786 bool desubroutinize = false;
787
788 unsigned min_charstrings_off_size = 0;
789 };
790 } // namespace OT
791
_serialize_cff1_charstrings(hb_serialize_context_t * c,struct OT::cff1_subset_plan & plan,const OT::cff1::accelerator_subset_t & acc)792 static bool _serialize_cff1_charstrings (hb_serialize_context_t *c,
793 struct OT::cff1_subset_plan &plan,
794 const OT::cff1::accelerator_subset_t &acc)
795 {
796 c->push<CFF1CharStrings> ();
797
798 unsigned data_size = 0;
799 unsigned total_size = CFF1CharStrings::total_size (plan.subset_charstrings, &data_size, plan.min_charstrings_off_size);
800 if (unlikely (!c->start_zerocopy (total_size)))
801 return false;
802
803 auto *cs = c->start_embed<CFF1CharStrings> ();
804 if (unlikely (!cs->serialize (c, plan.subset_charstrings, &data_size, plan.min_charstrings_off_size))) {
805 c->pop_discard ();
806 return false;
807 }
808
809 plan.info.char_strings_link = c->pop_pack (false);
810 return true;
811 }
812
813 bool
serialize(hb_serialize_context_t * c,struct OT::cff1_subset_plan & plan) const814 OT::cff1::accelerator_subset_t::serialize (hb_serialize_context_t *c,
815 struct OT::cff1_subset_plan &plan) const
816 {
817 /* push charstrings onto the object stack first which will ensure it packs as the last
818 object in the table. Keeping the chastrings last satisfies the requirements for patching
819 via IFTB. If this ordering needs to be changed in the future, charstrings should be left
820 at the end whenever HB_SUBSET_FLAGS_ITFB_REQUIREMENTS is enabled. */
821 if (!_serialize_cff1_charstrings(c, plan, *this))
822 return false;
823
824 /* private dicts & local subrs */
825 for (int i = (int) privateDicts.length; --i >= 0 ;)
826 {
827 if (plan.fdmap.has (i))
828 {
829 objidx_t subrs_link = 0;
830 if (plan.subset_localsubrs[i].length > 0)
831 {
832 auto *dest = c->push <CFF1Subrs> ();
833 if (likely (dest->serialize (c, plan.subset_localsubrs[i])))
834 subrs_link = c->pop_pack ();
835 else
836 {
837 c->pop_discard ();
838 return false;
839 }
840 }
841
842 auto *pd = c->push<PrivateDict> ();
843 cff1_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
844 /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
845 if (likely (pd->serialize (c, privateDicts[i], privSzr, subrs_link)))
846 {
847 unsigned fd = plan.fdmap[i];
848 plan.fontdicts_mod[fd].privateDictInfo.size = c->length ();
849 plan.fontdicts_mod[fd].privateDictInfo.link = c->pop_pack ();
850 }
851 else
852 {
853 c->pop_discard ();
854 return false;
855 }
856 }
857 }
858
859 if (!is_CID ())
860 plan.info.privateDictInfo = plan.fontdicts_mod[0].privateDictInfo;
861
862 /* FDArray (FD Index) */
863 if (fdArray != &Null (CFF1FDArray))
864 {
865 auto *fda = c->push<CFF1FDArray> ();
866 cff1_font_dict_op_serializer_t fontSzr;
867 auto it = + hb_zip (+ hb_iter (plan.fontdicts_mod), + hb_iter (plan.fontdicts_mod));
868 if (likely (fda->serialize (c, it, fontSzr)))
869 plan.info.fd_array_link = c->pop_pack (false);
870 else
871 {
872 c->pop_discard ();
873 return false;
874 }
875 }
876
877 /* FDSelect */
878 if (fdSelect != &Null (CFF1FDSelect))
879 {
880 c->push ();
881 if (likely (hb_serialize_cff_fdselect (c, plan.num_glyphs, *fdSelect, fdCount,
882 plan.subset_fdselect_format, plan.info.fd_select.size,
883 plan.subset_fdselect_ranges)))
884 plan.info.fd_select.link = c->pop_pack ();
885 else
886 {
887 c->pop_discard ();
888 return false;
889 }
890 }
891
892 /* Charset */
893 if (plan.subset_charset)
894 {
895 auto *dest = c->push<Charset> ();
896 if (likely (dest->serialize (c,
897 plan.subset_charset_format,
898 plan.num_glyphs,
899 plan.subset_charset_ranges)))
900 plan.info.charset_link = c->pop_pack ();
901 else
902 {
903 c->pop_discard ();
904 return false;
905 }
906 }
907
908 /* Encoding */
909 if (plan.subset_encoding)
910 {
911 auto *dest = c->push<Encoding> ();
912 if (likely (dest->serialize (c,
913 plan.subset_enc_format,
914 plan.subset_enc_num_codes,
915 plan.subset_enc_code_ranges,
916 plan.subset_enc_supp_codes)))
917 plan.info.encoding_link = c->pop_pack ();
918 else
919 {
920 c->pop_discard ();
921 return false;
922 }
923 }
924
925 /* global subrs */
926 {
927 auto *dest = c->push <CFF1Subrs> ();
928 if (likely (dest->serialize (c, plan.subset_globalsubrs)))
929 c->pop_pack (false);
930 else
931 {
932 c->pop_discard ();
933 return false;
934 }
935 }
936
937 /* String INDEX */
938 {
939 auto *dest = c->push<CFF1StringIndex> ();
940 if (likely (!plan.sidmap.in_error () &&
941 dest->serialize (c, *stringIndex, plan.sidmap.vector)))
942 c->pop_pack ();
943 else
944 {
945 c->pop_discard ();
946 return false;
947 }
948 }
949
950 OT::cff1 *cff = c->allocate_min<OT::cff1> ();
951 if (unlikely (!cff))
952 return false;
953
954 /* header */
955 cff->version.major = 0x01;
956 cff->version.minor = 0x00;
957 cff->nameIndex = cff->min_size;
958 cff->offSize = 4; /* unused? */
959
960 /* name INDEX */
961 if (unlikely (!c->embed (*nameIndex))) return false;
962
963 /* top dict INDEX */
964 {
965 /* serialize singleton TopDict */
966 auto *top = c->push<TopDict> ();
967 cff1_top_dict_op_serializer_t topSzr;
968 unsigned top_size = 0;
969 top_dict_modifiers_t modifier (plan.info, plan.topDictModSIDs);
970 if (likely (top->serialize (c, plan.topdict_mod, topSzr, modifier)))
971 {
972 top_size = c->length ();
973 c->pop_pack (false);
974 }
975 else
976 {
977 c->pop_discard ();
978 return false;
979 }
980 /* serialize INDEX header for above */
981 auto *dest = c->start_embed<CFF1Index> ();
982 return dest->serialize_header (c, hb_iter (&top_size, 1), top_size);
983 }
984 }
985
986 bool
subset(hb_subset_context_t * c) const987 OT::cff1::accelerator_subset_t::subset (hb_subset_context_t *c) const
988 {
989 cff1_subset_plan cff_plan;
990
991 if (unlikely (!cff_plan.create (*this, c->plan)))
992 {
993 DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan.");
994 return false;
995 }
996
997 return serialize (c->serializer, cff_plan);
998 }
999
1000
1001 #endif
1002