Imported Upstream version 2.6.7
[platform/upstream/harfbuzz.git] / src / hb-subset-cff1.cc
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 {
44   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
52   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
62   static bool is_std_std (unsigned int sid) { return sid < num_std_strings; }
63   static unsigned int offset_sid (unsigned int sid) { return sid + num_std_strings; }
64   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 {
69   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 {
85   void init (const cff1_top_dict_values_t *base_= &Null (cff1_top_dict_values_t))
86   {
87     SUPER::init ();
88     base = base_;
89   }
90
91   void fini () { SUPER::fini (); }
92
93   unsigned get_count () const { return base->get_count () + SUPER::get_count (); }
94   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   }
101   const cff1_top_dict_val_t &operator [] (unsigned int i) const { return get_value (i); }
102
103   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 {
116   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 {
128   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 {
188   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 {
206   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   }
232   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
240   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
246   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
253   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 */
271   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 {
289   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:
322   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 {
339   cff1_subr_subsetter_t (const OT::cff1::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_)
340     : subr_subsetter_t (acc_, plan_) {}
341
342   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 {
364   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
387   ~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
402   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, supp_size;
406     hb_codepoint_t  code, last_code = CFF_UNDEF_CODE;
407     hb_vector_t<hb_codepoint_t> supp_codes;
408
409     subset_enc_code_ranges.resize (0);
410     supp_size = 0;
411     supp_codes.init ();
412
413     subset_enc_num_codes = plan->num_output_glyphs () - 1;
414     unsigned int glyph;
415     for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
416     {
417       hb_codepoint_t  old_glyph;
418       if (!plan->old_gid_for_new_gid (glyph, &old_glyph))
419       {
420         /* Retain the code for the old missing glyph ID */
421         old_glyph = glyph;
422       }
423       code = acc.glyph_to_code (old_glyph);
424       if (code == CFF_UNDEF_CODE)
425       {
426         subset_enc_num_codes = glyph - 1;
427         break;
428       }
429
430       if ((last_code == CFF_UNDEF_CODE) || (code != last_code + 1))
431       {
432         code_pair_t pair = { code, glyph };
433         subset_enc_code_ranges.push (pair);
434       }
435       last_code = code;
436
437       if (encoding != &Null (Encoding))
438       {
439         hb_codepoint_t  sid = acc.glyph_to_sid (old_glyph);
440         encoding->get_supplement_codes (sid, supp_codes);
441         for (unsigned int i = 0; i < supp_codes.length; i++)
442         {
443           code_pair_t pair = { supp_codes[i], sid };
444           subset_enc_supp_codes.push (pair);
445         }
446         supp_size += SuppEncoding::static_size * supp_codes.length;
447       }
448     }
449     supp_codes.fini ();
450
451     subset_enc_code_ranges.complete (glyph);
452
453     assert (subset_enc_num_codes <= 0xFF);
454     size0 = Encoding0::min_size + HBUINT8::static_size * subset_enc_num_codes;
455     size1 = Encoding1::min_size + Encoding1_Range::static_size * subset_enc_code_ranges.length;
456
457     if (size0 < size1)
458       subset_enc_format = 0;
459     else
460       subset_enc_format = 1;
461   }
462
463   void plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
464   {
465     unsigned int  size0, size_ranges;
466     hb_codepoint_t  sid, last_sid = CFF_UNDEF_CODE;
467
468     subset_charset_ranges.resize (0);
469     unsigned int glyph;
470     for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
471     {
472       hb_codepoint_t  old_glyph;
473       if (!plan->old_gid_for_new_gid (glyph, &old_glyph))
474       {
475         /* Retain the SID for the old missing glyph ID */
476         old_glyph = glyph;
477       }
478       sid = acc.glyph_to_sid (old_glyph);
479
480       if (!acc.is_CID ())
481         sid = sidmap.add (sid);
482
483       if ((last_sid == CFF_UNDEF_CODE) || (sid != last_sid + 1))
484       {
485         code_pair_t pair = { sid, glyph };
486         subset_charset_ranges.push (pair);
487       }
488       last_sid = sid;
489     }
490
491     bool two_byte = subset_charset_ranges.complete (glyph);
492
493     size0 = Charset0::min_size + HBUINT16::static_size * (plan->num_output_glyphs () - 1);
494     if (!two_byte)
495       size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.length;
496     else
497       size_ranges = Charset2::min_size + Charset2_Range::static_size * subset_charset_ranges.length;
498
499     if (size0 < size_ranges)
500       subset_charset_format = 0;
501     else if (!two_byte)
502       subset_charset_format = 1;
503     else
504       subset_charset_format = 2;
505   }
506
507   bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc)
508   {
509     sidmap.reset ();
510
511     for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
512     {
513       unsigned int sid = acc.topDict.nameSIDs[i];
514       if (sid != CFF_UNDEF_SID)
515       {
516         (void)sidmap.add (sid);
517         topDictModSIDs[i] = sidmap[sid];
518       }
519     }
520
521     if (acc.fdArray != &Null (CFF1FDArray))
522       for (unsigned int i = 0; i < orig_fdcount; i++)
523         if (fdmap.has (i))
524           (void)sidmap.add (acc.fontDicts[i].fontName);
525
526     return true;
527   }
528
529   bool create (const OT::cff1::accelerator_subset_t &acc,
530                hb_subset_plan_t *plan)
531   {
532     /* make sure notdef is first */
533     hb_codepoint_t old_glyph;
534     if (!plan->old_gid_for_new_gid (0, &old_glyph) || (old_glyph != 0)) return false;
535
536     num_glyphs = plan->num_output_glyphs ();
537     orig_fdcount = acc.fdCount;
538     drop_hints = plan->drop_hints;
539     desubroutinize = plan->desubroutinize;
540
541     /* check whether the subset renumbers any glyph IDs */
542     gid_renum = false;
543     for (hb_codepoint_t new_glyph = 0; new_glyph < plan->num_output_glyphs (); new_glyph++)
544     {
545       if (!plan->old_gid_for_new_gid(new_glyph, &old_glyph))
546         continue;
547       if (new_glyph != old_glyph) {
548         gid_renum = true;
549         break;
550       }
551     }
552
553     subset_charset = gid_renum || !acc.is_predef_charset ();
554     subset_encoding = !acc.is_CID() && !acc.is_predef_encoding ();
555
556     /* top dict INDEX */
557     {
558       /* Add encoding/charset to a (copy of) top dict as necessary */
559       topdict_mod.init (&acc.topDict);
560       bool need_to_add_enc = (subset_encoding && !acc.topDict.has_op (OpCode_Encoding));
561       bool need_to_add_set = (subset_charset && !acc.topDict.has_op (OpCode_charset));
562       if (need_to_add_enc || need_to_add_set)
563       {
564         if (need_to_add_enc)
565           topdict_mod.add_op (OpCode_Encoding);
566         if (need_to_add_set)
567           topdict_mod.add_op (OpCode_charset);
568       }
569     }
570
571     /* Determine re-mapping of font index as fdmap among other info */
572     if (acc.fdSelect != &Null (CFF1FDSelect))
573     {
574         if (unlikely (!hb_plan_subset_cff_fdselect (plan,
575                                   orig_fdcount,
576                                   *acc.fdSelect,
577                                   subset_fdcount,
578                                   info.fd_select.size,
579                                   subset_fdselect_format,
580                                   subset_fdselect_ranges,
581                                   fdmap)))
582         return false;
583     }
584     else
585       fdmap.identity (1);
586
587     /* remove unused SIDs & reassign SIDs */
588     {
589       /* SIDs for name strings in dicts are added before glyph names so they fit in 16-bit int range */
590       if (unlikely (!collect_sids_in_dicts (acc)))
591         return false;
592       if (unlikely (sidmap.get_population () > 0x8000)) /* assumption: a dict won't reference that many strings */
593         return false;
594
595       if (subset_charset) plan_subset_charset (acc, plan);
596
597       topdict_mod.reassignSIDs (sidmap);
598     }
599
600     if (desubroutinize)
601     {
602       /* Flatten global & local subrs */
603       subr_flattener_t<const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_flatten_t, OpCode_endchar>
604                     flattener(acc, plan);
605       if (!flattener.flatten (subset_charstrings))
606         return false;
607     }
608     else
609     {
610       cff1_subr_subsetter_t       subr_subsetter (acc, plan);
611
612       /* Subset subrs: collect used subroutines, leaving all unused ones behind */
613       if (!subr_subsetter.subset ())
614         return false;
615
616       /* encode charstrings, global subrs, local subrs with new subroutine numbers */
617       if (!subr_subsetter.encode_charstrings (subset_charstrings))
618         return false;
619
620       if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
621         return false;
622
623       /* local subrs */
624       if (!subset_localsubrs.resize (orig_fdcount))
625         return false;
626       for (unsigned int fd = 0; fd < orig_fdcount; fd++)
627       {
628         subset_localsubrs[fd].init ();
629         if (fdmap.has (fd))
630         {
631           if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd]))
632             return false;
633         }
634       }
635     }
636
637     /* Encoding */
638     if (subset_encoding)
639       plan_subset_encoding (acc, plan);
640
641     /* private dicts & local subrs */
642     if (!acc.is_CID ())
643       fontdicts_mod.push (cff1_font_dict_values_mod_t ());
644     else
645     {
646       + hb_iter (acc.fontDicts)
647       | hb_filter ([&] (const cff1_font_dict_values_t &_)
648         { return fdmap.has (&_ - &acc.fontDicts[0]); } )
649       | hb_map ([&] (const cff1_font_dict_values_t &_)
650         {
651           cff1_font_dict_values_mod_t mod;
652           mod.init (&_, sidmap[_.fontName]);
653           return mod;
654         })
655       | hb_sink (fontdicts_mod)
656       ;
657     }
658
659     return ((subset_charstrings.length == plan->num_output_glyphs ())
660            && (fontdicts_mod.length == subset_fdcount));
661   }
662
663   cff1_top_dict_values_mod_t    topdict_mod;
664   cff1_sub_table_info_t         info;
665
666   unsigned int    num_glyphs;
667   unsigned int    orig_fdcount;
668   unsigned int    subset_fdcount;
669   unsigned int    subset_fdselect_format;
670   hb_vector_t<code_pair_t>   subset_fdselect_ranges;
671
672   /* font dict index remap table from fullset FDArray to subset FDArray.
673    * set to CFF_UNDEF_CODE if excluded from subset */
674   hb_inc_bimap_t   fdmap;
675
676   str_buff_vec_t                subset_charstrings;
677   str_buff_vec_t                subset_globalsubrs;
678   hb_vector_t<str_buff_vec_t>   subset_localsubrs;
679   hb_vector_t<cff1_font_dict_values_mod_t>  fontdicts_mod;
680
681   bool          drop_hints;
682
683   bool          gid_renum;
684   bool          subset_encoding;
685   uint8_t       subset_enc_format;
686   unsigned int  subset_enc_num_codes;
687   range_list_t  subset_enc_code_ranges;
688   hb_vector_t<code_pair_t>  subset_enc_supp_codes;
689
690   uint8_t       subset_charset_format;
691   range_list_t  subset_charset_ranges;
692   bool          subset_charset;
693
694   remap_sid_t   sidmap;
695   unsigned int  topDictModSIDs[name_dict_values_t::ValCount];
696
697   bool          desubroutinize;
698 };
699
700 static bool _serialize_cff1 (hb_serialize_context_t *c,
701                              cff_subset_plan &plan,
702                              const OT::cff1::accelerator_subset_t  &acc,
703                              unsigned int num_glyphs)
704 {
705   /* private dicts & local subrs */
706   for (int i = (int)acc.privateDicts.length; --i >= 0 ;)
707   {
708     if (plan.fdmap.has (i))
709     {
710       objidx_t  subrs_link = 0;
711       if (plan.subset_localsubrs[i].length > 0)
712       {
713         CFF1Subrs *dest = c->start_embed <CFF1Subrs> ();
714         if (unlikely (!dest)) return false;
715         c->push ();
716         if (likely (dest && dest->serialize (c, plan.subset_localsubrs[i])))
717           subrs_link = c->pop_pack ();
718         else
719         {
720           c->pop_discard ();
721           return false;
722         }
723       }
724
725       PrivateDict *pd = c->start_embed<PrivateDict> ();
726       if (unlikely (!pd)) return false;
727       c->push ();
728       cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
729       /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
730       if (likely (pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link)))
731       {
732         unsigned fd = plan.fdmap[i];
733         plan.fontdicts_mod[fd].privateDictInfo.size = c->length ();
734         plan.fontdicts_mod[fd].privateDictInfo.link = c->pop_pack ();
735       }
736       else
737       {
738         c->pop_discard ();
739         return false;
740       }
741     }
742   }
743
744   if (!acc.is_CID ())
745     plan.info.privateDictInfo = plan.fontdicts_mod[0].privateDictInfo;
746
747   /* CharStrings */
748   {
749     CFF1CharStrings  *cs = c->start_embed<CFF1CharStrings> ();
750     if (unlikely (!cs)) return false;
751     c->push ();
752     if (likely (cs->serialize (c, plan.subset_charstrings)))
753       plan.info.char_strings_link = c->pop_pack ();
754     else
755     {
756       c->pop_discard ();
757       return false;
758     }
759   }
760
761   /* FDArray (FD Index) */
762   if (acc.fdArray != &Null (CFF1FDArray))
763   {
764     CFF1FDArray *fda = c->start_embed<CFF1FDArray> ();
765     if (unlikely (!fda)) return false;
766     c->push ();
767     cff1_font_dict_op_serializer_t  fontSzr;
768     auto it = + hb_zip (+ hb_iter (plan.fontdicts_mod), + hb_iter (plan.fontdicts_mod));
769     if (likely (fda->serialize (c, it, fontSzr)))
770       plan.info.fd_array_link = c->pop_pack (false);
771     else
772     {
773       c->pop_discard ();
774       return false;
775     }
776   }
777
778   /* FDSelect */
779   if (acc.fdSelect != &Null (CFF1FDSelect))
780   {
781     c->push ();
782     if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *acc.fdSelect, acc.fdCount,
783                                            plan.subset_fdselect_format, plan.info.fd_select.size,
784                                            plan.subset_fdselect_ranges)))
785       plan.info.fd_select.link = c->pop_pack ();
786     else
787     {
788       c->pop_discard ();
789       return false;
790     }
791   }
792
793   /* Charset */
794   if (plan.subset_charset)
795   {
796     Charset *dest = c->start_embed<Charset> ();
797     if (unlikely (!dest)) return false;
798     c->push ();
799     if (likely (dest->serialize (c,
800                                  plan.subset_charset_format,
801                                  plan.num_glyphs,
802                                  plan.subset_charset_ranges)))
803       plan.info.charset_link = c->pop_pack ();
804     else
805     {
806       c->pop_discard ();
807       return false;
808     }
809   }
810
811   /* Encoding */
812   if (plan.subset_encoding)
813   {
814     Encoding *dest = c->start_embed<Encoding> ();
815     if (unlikely (!dest)) return false;
816     c->push ();
817     if (likely (dest->serialize (c,
818                                  plan.subset_enc_format,
819                                  plan.subset_enc_num_codes,
820                                  plan.subset_enc_code_ranges,
821                                  plan.subset_enc_supp_codes)))
822       plan.info.encoding_link = c->pop_pack ();
823     else
824     {
825       c->pop_discard ();
826       return false;
827     }
828   }
829
830   /* global subrs */
831   {
832     c->push ();
833     CFF1Subrs *dest = c->start_embed <CFF1Subrs> ();
834     if (unlikely (!dest)) return false;
835     if (likely (dest->serialize (c, plan.subset_globalsubrs)))
836       c->pop_pack ();
837     else
838     {
839       c->pop_discard ();
840       return false;
841     }
842   }
843
844   /* String INDEX */
845   {
846     CFF1StringIndex *dest = c->start_embed<CFF1StringIndex> ();
847     if (unlikely (!dest)) return false;
848     c->push ();
849     if (likely (dest->serialize (c, *acc.stringIndex, plan.sidmap)))
850       c->pop_pack ();
851     else
852     {
853       c->pop_discard ();
854       return false;
855     }
856   }
857
858   OT::cff1 *cff = c->allocate_min<OT::cff1> ();
859   if (unlikely (!cff))
860     return false;
861
862   /* header */
863   cff->version.major = 0x01;
864   cff->version.minor = 0x00;
865   cff->nameIndex = cff->min_size;
866   cff->offSize = 4; /* unused? */
867
868   /* name INDEX */
869   if (unlikely (!(*acc.nameIndex).copy (c))) return false;
870
871   /* top dict INDEX */
872   {
873     /* serialize singleton TopDict */
874     TopDict *top = c->start_embed<TopDict> ();
875     if (!top) return false;
876     c->push ();
877     cff1_top_dict_op_serializer_t topSzr;
878     unsigned top_size = 0;
879     top_dict_modifiers_t  modifier (plan.info, plan.topDictModSIDs);
880     if (likely (top->serialize (c, plan.topdict_mod, topSzr, modifier)))
881     {
882       top_size = c->length ();
883       c->pop_pack (false);
884     }
885     else
886     {
887       c->pop_discard ();
888       return false;
889     }
890     /* serialize INDEX header for above */
891     CFF1Index *dest = c->start_embed<CFF1Index> ();
892     if (!dest) return false;
893     return dest->serialize_header (c, hb_iter (hb_array_t<unsigned> (&top_size, 1)));
894   }
895 }
896
897 static bool
898 _hb_subset_cff1 (const OT::cff1::accelerator_subset_t  &acc,
899                 hb_subset_context_t     *c)
900 {
901   cff_subset_plan cff_plan;
902
903   if (unlikely (!cff_plan.create (acc, c->plan)))
904   {
905     DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan.");
906     return false;
907   }
908
909   return _serialize_cff1 (c->serializer, cff_plan, acc, c->plan->num_output_glyphs ());
910 }
911
912 /**
913  * hb_subset_cff1:
914  * Subsets the CFF table according to a provided plan.
915  *
916  * Return value: subsetted cff table.
917  **/
918 bool
919 hb_subset_cff1 (hb_subset_context_t *c)
920 {
921   OT::cff1::accelerator_subset_t acc;
922   acc.init (c->plan->source);
923   bool result = likely (acc.is_valid ()) && _hb_subset_cff1 (acc, c);
924   acc.fini ();
925
926   return result;
927 }
928
929
930 #endif