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