Imported Upstream version 2.3.1
[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-open-type.hh"
28 #include "hb-ot-cff1-table.hh"
29 #include "hb-set.h"
30 #include "hb-subset-cff1.hh"
31 #include "hb-subset-plan.hh"
32 #include "hb-subset-cff-common.hh"
33 #include "hb-cff1-interp-cs.hh"
34
35 using namespace CFF;
36
37 struct remap_sid_t : remap_t
38 {
39   unsigned int add (unsigned int sid)
40   {
41     if ((sid != CFF_UNDEF_SID) && !is_std_std (sid))
42       return offset_sid (remap_t::add (unoffset_sid (sid)));
43     else
44       return sid;
45   }
46
47   unsigned int operator[] (unsigned int sid) const
48   {
49     if (is_std_std (sid) || (sid == CFF_UNDEF_SID))
50       return sid;
51     else
52       return offset_sid (remap_t::operator [] (unoffset_sid (sid)));
53   }
54
55   static const unsigned int num_std_strings = 391;
56
57   static bool is_std_std (unsigned int sid) { return sid < num_std_strings; }
58   static unsigned int offset_sid (unsigned int sid) { return sid + num_std_strings; }
59   static unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; }
60 };
61
62 struct cff1_sub_table_offsets_t : cff_sub_table_offsets_t
63 {
64   cff1_sub_table_offsets_t ()
65     : cff_sub_table_offsets_t (),
66       nameIndexOffset (0),
67       encodingOffset (0)
68   {
69     stringIndexInfo.init ();
70     charsetInfo.init ();
71     privateDictInfo.init ();
72   }
73
74   unsigned int  nameIndexOffset;
75   table_info_t  stringIndexInfo;
76   unsigned int  encodingOffset;
77   table_info_t  charsetInfo;
78   table_info_t  privateDictInfo;
79 };
80
81 /* a copy of a parsed out cff1_top_dict_values_t augmented with additional operators */
82 struct cff1_top_dict_values_mod_t : cff1_top_dict_values_t
83 {
84   void init (const cff1_top_dict_values_t *base_= &Null(cff1_top_dict_values_t))
85   {
86     SUPER::init ();
87     base = base_;
88   }
89
90   void fini () { SUPER::fini (); }
91
92   unsigned get_count () const { return base->get_count () + SUPER::get_count (); }
93   const cff1_top_dict_val_t &get_value (unsigned int i) const
94   {
95     if (i < base->get_count ())
96       return (*base)[i];
97     else
98       return SUPER::values[i - base->get_count ()];
99   }
100   const cff1_top_dict_val_t &operator [] (unsigned int i) const { return get_value (i); }
101
102   void reassignSIDs (const remap_sid_t& sidmap)
103   {
104     for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
105       nameSIDs[i] = sidmap[base->nameSIDs[i]];
106   }
107
108   protected:
109   typedef cff1_top_dict_values_t SUPER;
110   const cff1_top_dict_values_t *base;
111 };
112
113 struct top_dict_modifiers_t
114 {
115   top_dict_modifiers_t (const cff1_sub_table_offsets_t &offsets_,
116                            const unsigned int (&nameSIDs_)[name_dict_values_t::ValCount])
117     : offsets (offsets_),
118       nameSIDs (nameSIDs_)
119   {}
120
121   const cff1_sub_table_offsets_t &offsets;
122   const unsigned int    (&nameSIDs)[name_dict_values_t::ValCount];
123 };
124
125 struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<cff1_top_dict_val_t>
126 {
127   bool serialize (hb_serialize_context_t *c,
128                   const cff1_top_dict_val_t &opstr,
129                   const top_dict_modifiers_t &mod) const
130   {
131     TRACE_SERIALIZE (this);
132
133     op_code_t op = opstr.op;
134     switch (op)
135     {
136       case OpCode_charset:
137         return_trace (FontDict::serialize_offset4_op(c, op, mod.offsets.charsetInfo.offset));
138
139       case OpCode_Encoding:
140         return_trace (FontDict::serialize_offset4_op(c, op, mod.offsets.encodingOffset));
141
142       case OpCode_Private:
143         {
144           if (unlikely (!UnsizedByteStr::serialize_int2 (c, mod.offsets.privateDictInfo.size)))
145             return_trace (false);
146           if (unlikely (!UnsizedByteStr::serialize_int4 (c, mod.offsets.privateDictInfo.offset)))
147             return_trace (false);
148           HBUINT8 *p = c->allocate_size<HBUINT8> (1);
149           if (unlikely (p == nullptr)) return_trace (false);
150           p->set (OpCode_Private);
151         }
152         break;
153
154       case OpCode_version:
155       case OpCode_Notice:
156       case OpCode_Copyright:
157       case OpCode_FullName:
158       case OpCode_FamilyName:
159       case OpCode_Weight:
160       case OpCode_PostScript:
161       case OpCode_BaseFontName:
162       case OpCode_FontName:
163         return_trace (FontDict::serialize_offset2_op(c, op, mod.nameSIDs[name_dict_values_t::name_op_to_index (op)]));
164
165       case OpCode_ROS:
166         {
167           /* for registry & ordering, reassigned SIDs are serialized
168            * for supplement, the original byte string is copied along with the op code */
169           op_str_t supp_op;
170           supp_op.op = op;
171           if ( unlikely (!(opstr.str.length >= opstr.last_arg_offset + 3)))
172             return_trace (false);
173           supp_op.str = byte_str_t (&opstr.str + opstr.last_arg_offset, opstr.str.length - opstr.last_arg_offset);
174           return_trace (UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::registry]) &&
175                         UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::ordering]) &&
176                         copy_opstr (c, supp_op));
177         }
178       default:
179         return_trace (cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::serialize (c, opstr, mod.offsets));
180     }
181     return_trace (true);
182   }
183
184   unsigned int calculate_serialized_size (const cff1_top_dict_val_t &opstr) const
185   {
186     op_code_t op = opstr.op;
187     switch (op)
188     {
189       case OpCode_charset:
190       case OpCode_Encoding:
191         return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op);
192
193       case OpCode_Private:
194         return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
195
196       case OpCode_version:
197       case OpCode_Notice:
198       case OpCode_Copyright:
199       case OpCode_FullName:
200       case OpCode_FamilyName:
201       case OpCode_Weight:
202       case OpCode_PostScript:
203       case OpCode_BaseFontName:
204       case OpCode_FontName:
205         return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (op);
206
207       case OpCode_ROS:
208         return ((OpCode_Size (OpCode_shortint) + 2) * 2) + (opstr.str.length - opstr.last_arg_offset)/* supplement + op */;
209
210       default:
211         return cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::calculate_serialized_size (opstr);
212     }
213   }
214 };
215
216 struct font_dict_values_mod_t
217 {
218   void init (const cff1_font_dict_values_t *base_,
219              unsigned int fontName_,
220              const table_info_t &privateDictInfo_)
221   {
222     base = base_;
223     fontName = fontName_;
224     privateDictInfo = privateDictInfo_;
225   }
226
227   unsigned get_count () const { return base->get_count (); }
228
229   const op_str_t &operator [] (unsigned int i) const { return (*base)[i]; }
230
231   const cff1_font_dict_values_t    *base;
232   table_info_t             privateDictInfo;
233   unsigned int          fontName;
234 };
235
236 struct cff1_font_dict_op_serializer_t : cff_font_dict_op_serializer_t
237 {
238   bool serialize (hb_serialize_context_t *c,
239                   const op_str_t &opstr,
240                   const font_dict_values_mod_t &mod) const
241   {
242     TRACE_SERIALIZE (this);
243
244     if (opstr.op == OpCode_FontName)
245       return_trace (FontDict::serialize_uint2_op (c, opstr.op, mod.fontName));
246     else
247       return_trace (SUPER::serialize (c, opstr, mod.privateDictInfo));
248   }
249
250   unsigned int calculate_serialized_size (const op_str_t &opstr) const
251   {
252     if (opstr.op == OpCode_FontName)
253       return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_FontName);
254     else
255       return SUPER::calculate_serialized_size (opstr);
256   }
257
258   private:
259   typedef cff_font_dict_op_serializer_t SUPER;
260 };
261
262 struct cff1_cs_opset_flatten_t : cff1_cs_opset_t<cff1_cs_opset_flatten_t, flatten_param_t>
263 {
264   static void flush_args_and_op (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param)
265   {
266     if (env.arg_start > 0)
267       flush_width (env, param);
268
269     switch (op)
270     {
271       case OpCode_hstem:
272       case OpCode_hstemhm:
273       case OpCode_vstem:
274       case OpCode_vstemhm:
275       case OpCode_hintmask:
276       case OpCode_cntrmask:
277       case OpCode_dotsection:
278         if (param.drop_hints)
279         {
280           env.clear_args ();
281           return;
282         }
283         HB_FALLTHROUGH;
284
285       default:
286         SUPER::flush_args_and_op (op, env, param);
287         break;
288     }
289   }
290   static void flush_args (cff1_cs_interp_env_t &env, flatten_param_t& param)
291   {
292     str_encoder_t  encoder (param.flatStr);
293     for (unsigned int i = env.arg_start; i < env.argStack.get_count (); i++)
294       encoder.encode_num (env.eval_arg (i));
295     SUPER::flush_args (env, param);
296   }
297
298   static void flush_op (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param)
299   {
300     str_encoder_t  encoder (param.flatStr);
301     encoder.encode_op (op);
302   }
303
304   static void flush_width (cff1_cs_interp_env_t &env, flatten_param_t& param)
305   {
306     assert (env.has_width);
307     str_encoder_t  encoder (param.flatStr);
308     encoder.encode_num (env.width);
309   }
310
311   static void flush_hintmask (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param)
312   {
313     SUPER::flush_hintmask (op, env, param);
314     if (!param.drop_hints)
315     {
316       str_encoder_t  encoder (param.flatStr);
317       for (unsigned int i = 0; i < env.hintmask_size; i++)
318         encoder.encode_byte (env.str_ref[i]);
319     }
320   }
321
322   private:
323   typedef cff1_cs_opset_t<cff1_cs_opset_flatten_t, flatten_param_t> SUPER;
324 };
325
326 struct range_list_t : hb_vector_t<code_pair_t>
327 {
328   /* replace the first glyph ID in the "glyph" field each range with a nLeft value */
329   bool finalize (unsigned int last_glyph)
330   {
331     bool  two_byte = false;
332     for (unsigned int i = (*this).length; i > 0; i--)
333     {
334       code_pair_t &pair = (*this)[i - 1];
335       unsigned int  nLeft = last_glyph - pair.glyph - 1;
336       if (nLeft >= 0x100)
337         two_byte = true;
338       last_glyph = pair.glyph;
339       pair.glyph = nLeft;
340     }
341     return two_byte;
342   }
343 };
344
345 struct cff1_cs_opset_subr_subset_t : cff1_cs_opset_t<cff1_cs_opset_subr_subset_t, subr_subset_param_t>
346 {
347   static void process_op (op_code_t op, cff1_cs_interp_env_t &env, subr_subset_param_t& param)
348   {
349     switch (op) {
350
351       case OpCode_return:
352         param.current_parsed_str->add_op (op, env.str_ref);
353         param.current_parsed_str->set_parsed ();
354         env.returnFromSubr ();
355         param.set_current_str (env, false);
356         break;
357
358       case OpCode_endchar:
359         param.current_parsed_str->add_op (op, env.str_ref);
360         param.current_parsed_str->set_parsed ();
361         SUPER::process_op (op, env, param);
362         break;
363
364       case OpCode_callsubr:
365         process_call_subr (op, CSType_LocalSubr, env, param, env.localSubrs, param.local_closure);
366         break;
367
368       case OpCode_callgsubr:
369         process_call_subr (op, CSType_GlobalSubr, env, param, env.globalSubrs, param.global_closure);
370         break;
371
372       default:
373         SUPER::process_op (op, env, param);
374         param.current_parsed_str->add_op (op, env.str_ref);
375         break;
376     }
377   }
378
379   protected:
380   static void process_call_subr (op_code_t op, cs_type_t type,
381                                  cff1_cs_interp_env_t &env, subr_subset_param_t& param,
382                                  cff1_biased_subrs_t& subrs, hb_set_t *closure)
383   {
384     byte_str_ref_t    str_ref = env.str_ref;
385     env.callSubr (subrs, type);
386     param.current_parsed_str->add_call_op (op, str_ref, env.context.subr_num);
387     hb_set_add (closure, env.context.subr_num);
388     param.set_current_str (env, true);
389   }
390
391   private:
392   typedef cff1_cs_opset_t<cff1_cs_opset_subr_subset_t, subr_subset_param_t> SUPER;
393 };
394
395 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>
396 {
397   static void finalize_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 != nullptr))
411         parsed_str->set_parsed ();
412       else
413         env.set_error ();
414     }
415   }
416 };
417
418 struct cff_subset_plan {
419   cff_subset_plan ()
420     : final_size (0),
421       offsets (),
422       orig_fdcount (0),
423       subset_fdcount (1),
424       subset_fdselect_format (0),
425       drop_hints (false),
426       desubroutinize(false)
427   {
428     topdict_sizes.init ();
429     topdict_sizes.resize (1);
430     topdict_mod.init ();
431     subset_fdselect_ranges.init ();
432     fdmap.init ();
433     subset_charstrings.init ();
434     subset_globalsubrs.init ();
435     subset_localsubrs.init ();
436     fontdicts_mod.init ();
437     subset_enc_code_ranges.init ();
438     subset_enc_supp_codes.init ();
439     subset_charset_ranges.init ();
440     sidmap.init ();
441     for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
442       topDictModSIDs[i] = CFF_UNDEF_SID;
443   }
444
445   ~cff_subset_plan ()
446   {
447     topdict_sizes.fini ();
448     topdict_mod.fini ();
449     subset_fdselect_ranges.fini ();
450     fdmap.fini ();
451     subset_charstrings.fini_deep ();
452     subset_globalsubrs.fini_deep ();
453     subset_localsubrs.fini_deep ();
454     fontdicts_mod.fini ();
455     subset_enc_code_ranges.fini ();
456     subset_enc_supp_codes.fini ();
457     subset_charset_ranges.fini ();
458     sidmap.fini ();
459   }
460
461   unsigned int plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
462   {
463     const Encoding *encoding = acc.encoding;
464     unsigned int  size0, size1, supp_size;
465     hb_codepoint_t  code, last_code = CFF_UNDEF_CODE;
466     hb_vector_t<hb_codepoint_t> supp_codes;
467
468     subset_enc_code_ranges.resize (0);
469     supp_size = 0;
470     supp_codes.init ();
471
472     subset_enc_num_codes = plan->glyphs.length - 1;
473     unsigned int glyph;
474     for (glyph = 1; glyph < plan->glyphs.length; glyph++)
475     {
476       hb_codepoint_t  orig_glyph = plan->glyphs[glyph];
477       code = acc.glyph_to_code (orig_glyph);
478       if (code == CFF_UNDEF_CODE)
479       {
480         subset_enc_num_codes = glyph - 1;
481         break;
482       }
483
484       if (code != last_code + 1)
485       {
486         code_pair_t pair = { code, glyph };
487         subset_enc_code_ranges.push (pair);
488       }
489       last_code = code;
490
491       if (encoding != &Null(Encoding))
492       {
493         hb_codepoint_t  sid = acc.glyph_to_sid (orig_glyph);
494         encoding->get_supplement_codes (sid, supp_codes);
495         for (unsigned int i = 0; i < supp_codes.length; i++)
496         {
497           code_pair_t pair = { supp_codes[i], sid };
498           subset_enc_supp_codes.push (pair);
499         }
500         supp_size += SuppEncoding::static_size * supp_codes.length;
501       }
502     }
503     supp_codes.fini ();
504
505     subset_enc_code_ranges.finalize (glyph);
506
507     assert (subset_enc_num_codes <= 0xFF);
508     size0 = Encoding0::min_size + HBUINT8::static_size * subset_enc_num_codes;
509     size1 = Encoding1::min_size + Encoding1_Range::static_size * subset_enc_code_ranges.length;
510
511     if (size0 < size1)
512       subset_enc_format = 0;
513     else
514       subset_enc_format = 1;
515
516     return Encoding::calculate_serialized_size (
517                         subset_enc_format,
518                         subset_enc_format? subset_enc_code_ranges.length: subset_enc_num_codes,
519                         subset_enc_supp_codes.length);
520   }
521
522   unsigned int plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
523   {
524     unsigned int  size0, size_ranges;
525     hb_codepoint_t  sid, last_sid = CFF_UNDEF_CODE;
526
527     subset_charset_ranges.resize (0);
528     unsigned int glyph;
529     for (glyph = 1; glyph < plan->glyphs.length; glyph++)
530     {
531       hb_codepoint_t  orig_glyph = plan->glyphs[glyph];
532       sid = acc.glyph_to_sid (orig_glyph);
533
534       if (!acc.is_CID ())
535         sid = sidmap.add (sid);
536
537       if (sid != last_sid + 1)
538       {
539         code_pair_t pair = { sid, glyph };
540         subset_charset_ranges.push (pair);
541       }
542       last_sid = sid;
543     }
544
545     bool two_byte = subset_charset_ranges.finalize (glyph);
546
547     size0 = Charset0::min_size + HBUINT16::static_size * (plan->glyphs.length - 1);
548     if (!two_byte)
549       size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.length;
550     else
551       size_ranges = Charset2::min_size + Charset2_Range::static_size * subset_charset_ranges.length;
552
553     if (size0 < size_ranges)
554       subset_charset_format = 0;
555     else if (!two_byte)
556       subset_charset_format = 1;
557     else
558       subset_charset_format = 2;
559
560     return Charset::calculate_serialized_size (
561                         subset_charset_format,
562                         subset_charset_format? subset_charset_ranges.length: plan->glyphs.length);
563   }
564
565   bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc)
566   {
567     if (unlikely (!sidmap.reset (acc.stringIndex->count)))
568       return false;
569
570     for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
571     {
572       unsigned int sid = acc.topDict.nameSIDs[i];
573       if (sid != CFF_UNDEF_SID)
574       {
575         (void)sidmap.add (sid);
576         topDictModSIDs[i] = sidmap[sid];
577       }
578     }
579
580     if (acc.fdArray != &Null(CFF1FDArray))
581       for (unsigned int i = 0; i < orig_fdcount; i++)
582         if (fdmap.includes (i))
583           (void)sidmap.add (acc.fontDicts[i].fontName);
584
585     return true;
586   }
587
588   bool create (const OT::cff1::accelerator_subset_t &acc,
589                       hb_subset_plan_t *plan)
590   {
591      /* make sure notdef is first */
592     if ((plan->glyphs.length == 0) || (plan->glyphs[0] != 0)) return false;
593
594     final_size = 0;
595     num_glyphs = plan->glyphs.length;
596     orig_fdcount = acc.fdCount;
597     drop_hints = plan->drop_hints;
598     desubroutinize = plan->desubroutinize;
599
600     /* check whether the subset renumbers any glyph IDs */
601     gid_renum = false;
602     for (unsigned int glyph = 0; glyph < plan->glyphs.length; glyph++)
603     {
604       if (plan->glyphs[glyph] != glyph) {
605         gid_renum = true;
606         break;
607       }
608     }
609
610     subset_charset = gid_renum || !acc.is_predef_charset ();
611     subset_encoding = !acc.is_CID() && !acc.is_predef_encoding ();
612
613     /* CFF header */
614     final_size += OT::cff1::static_size;
615
616     /* Name INDEX */
617     offsets.nameIndexOffset = final_size;
618     final_size += acc.nameIndex->get_size ();
619
620     /* top dict INDEX */
621     {
622       /* Add encoding/charset to a (copy of) top dict as necessary */
623       topdict_mod.init (&acc.topDict);
624       bool need_to_add_enc = (subset_encoding && !acc.topDict.has_op (OpCode_Encoding));
625       bool need_to_add_set = (subset_charset && !acc.topDict.has_op (OpCode_charset));
626       if (need_to_add_enc || need_to_add_set)
627       {
628         if (need_to_add_enc)
629           topdict_mod.add_op (OpCode_Encoding);
630         if (need_to_add_set)
631           topdict_mod.add_op (OpCode_charset);
632       }
633       offsets.topDictInfo.offset = final_size;
634       cff1_top_dict_op_serializer_t topSzr;
635       unsigned int topDictSize = TopDict::calculate_serialized_size (topdict_mod, topSzr);
636       offsets.topDictInfo.offSize = calcOffSize(topDictSize);
637       if (unlikely (offsets.topDictInfo.offSize > 4))
638         return false;
639       final_size += CFF1IndexOf<TopDict>::calculate_serialized_size<cff1_top_dict_values_mod_t>
640                                                 (offsets.topDictInfo.offSize,
641                                                  &topdict_mod, 1, topdict_sizes, topSzr);
642     }
643
644     /* Determine re-mapping of font index as fdmap among other info */
645     if (acc.fdSelect != &Null(CFF1FDSelect))
646     {
647         if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
648                                   orig_fdcount,
649                                   *acc.fdSelect,
650                                   subset_fdcount,
651                                   offsets.FDSelectInfo.size,
652                                   subset_fdselect_format,
653                                   subset_fdselect_ranges,
654                                   fdmap)))
655         return false;
656     }
657     else
658       fdmap.identity (1);
659
660     /* remove unused SIDs & reassign SIDs */
661     {
662       /* SIDs for name strings in dicts are added before glyph names so they fit in 16-bit int range */
663       if (unlikely (!collect_sids_in_dicts (acc)))
664         return false;
665       if (unlikely (sidmap.get_count () > 0x8000))      /* assumption: a dict won't reference that many strings */
666         return false;
667       if (subset_charset)
668         offsets.charsetInfo.size = plan_subset_charset (acc, plan);
669
670       topdict_mod.reassignSIDs (sidmap);
671     }
672
673     /* String INDEX */
674     {
675       offsets.stringIndexInfo.offset = final_size;
676       offsets.stringIndexInfo.size = acc.stringIndex->calculate_serialized_size (offsets.stringIndexInfo.offSize, sidmap);
677       final_size += offsets.stringIndexInfo.size;
678     }
679
680     if (desubroutinize)
681     {
682       /* Flatten global & local subrs */
683       subr_flattener_t<const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_flatten_t>
684                     flattener(acc, plan->glyphs, plan->drop_hints);
685       if (!flattener.flatten (subset_charstrings))
686         return false;
687
688       /* no global/local subroutines */
689       offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (1, 0, 0);
690     }
691     else
692     {
693       /* Subset subrs: collect used subroutines, leaving all unused ones behind */
694       if (!subr_subsetter.subset (acc, plan->glyphs, plan->drop_hints))
695         return false;
696
697       /* encode charstrings, global subrs, local subrs with new subroutine numbers */
698       if (!subr_subsetter.encode_charstrings (acc, plan->glyphs, subset_charstrings))
699         return false;
700
701       if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
702         return false;
703
704       /* global subrs */
705       unsigned int dataSize = subset_globalsubrs.total_size ();
706       offsets.globalSubrsInfo.offSize = calcOffSize (dataSize);
707       if (unlikely (offsets.globalSubrsInfo.offSize > 4))
708         return false;
709       offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize);
710
711       /* local subrs */
712       if (!offsets.localSubrsInfos.resize (orig_fdcount))
713         return false;
714       if (!subset_localsubrs.resize (orig_fdcount))
715         return false;
716       for (unsigned int fd = 0; fd < orig_fdcount; fd++)
717       {
718         subset_localsubrs[fd].init ();
719         offsets.localSubrsInfos[fd].init ();
720         if (fdmap.includes (fd))
721         {
722           if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd]))
723             return false;
724
725           unsigned int dataSize = subset_localsubrs[fd].total_size ();
726           if (dataSize > 0)
727           {
728             offsets.localSubrsInfos[fd].offset = final_size;
729             offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize);
730             if (unlikely (offsets.localSubrsInfos[fd].offSize > 4))
731               return false;
732             offsets.localSubrsInfos[fd].size = CFF1Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize);
733           }
734         }
735       }
736     }
737
738     /* global subrs */
739     offsets.globalSubrsInfo.offset = final_size;
740     final_size += offsets.globalSubrsInfo.size;
741
742     /* Encoding */
743     if (!subset_encoding)
744       offsets.encodingOffset = acc.topDict.EncodingOffset;
745     else
746     {
747       offsets.encodingOffset = final_size;
748       final_size += plan_subset_encoding (acc, plan);
749     }
750
751     /* Charset */
752     if (!subset_charset && acc.is_predef_charset ())
753       offsets.charsetInfo.offset = acc.topDict.CharsetOffset;
754     else
755       offsets.charsetInfo.offset = final_size;
756     final_size += offsets.charsetInfo.size;
757
758     /* FDSelect */
759     if (acc.fdSelect != &Null(CFF1FDSelect))
760     {
761       offsets.FDSelectInfo.offset = final_size;
762       final_size += offsets.FDSelectInfo.size;
763     }
764
765     /* FDArray (FDIndex) */
766     if (acc.fdArray != &Null(CFF1FDArray)) {
767       offsets.FDArrayInfo.offset = final_size;
768       cff1_font_dict_op_serializer_t fontSzr;
769       unsigned int dictsSize = 0;
770       for (unsigned int i = 0; i < acc.fontDicts.length; i++)
771         if (fdmap.includes (i))
772           dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr);
773
774       offsets.FDArrayInfo.offSize = calcOffSize (dictsSize);
775       if (unlikely (offsets.FDArrayInfo.offSize > 4))
776         return false;
777       final_size += CFF1Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize);
778     }
779
780     /* CharStrings */
781     {
782       offsets.charStringsInfo.offset = final_size;
783       unsigned int dataSize = subset_charstrings.total_size ();
784       offsets.charStringsInfo.offSize = calcOffSize (dataSize);
785       if (unlikely (offsets.charStringsInfo.offSize > 4))
786         return false;
787       final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.length, dataSize);
788     }
789
790     /* private dicts & local subrs */
791     offsets.privateDictInfo.offset = final_size;
792     for (unsigned int i = 0; i < orig_fdcount; i++)
793     {
794       if (fdmap.includes (i))
795       {
796         bool  has_localsubrs = offsets.localSubrsInfos[i].size > 0;
797         cff_private_dict_op_serializer_t privSzr (desubroutinize, plan->drop_hints);
798         unsigned int  priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs);
799         table_info_t  privInfo = { final_size, priv_size, 0 };
800         font_dict_values_mod_t fontdict_mod;
801         if (!acc.is_CID ())
802           fontdict_mod.init ( &Null(cff1_font_dict_values_t), CFF_UNDEF_SID, privInfo );
803         else
804           fontdict_mod.init ( &acc.fontDicts[i], sidmap[acc.fontDicts[i].fontName], privInfo );
805         fontdicts_mod.push (fontdict_mod);
806         final_size += privInfo.size;
807
808         if (!plan->desubroutinize && has_localsubrs)
809         {
810           offsets.localSubrsInfos[i].offset = final_size;
811           final_size += offsets.localSubrsInfos[i].size;
812         }
813       }
814     }
815
816     if (!acc.is_CID ())
817       offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo;
818
819     return ((subset_charstrings.length == plan->glyphs.length)
820            && (fontdicts_mod.length == subset_fdcount));
821   }
822
823   unsigned int get_final_size () const  { return final_size; }
824
825   unsigned int        final_size;
826   hb_vector_t<unsigned int>     topdict_sizes;
827   cff1_top_dict_values_mod_t    topdict_mod;
828   cff1_sub_table_offsets_t      offsets;
829
830   unsigned int    num_glyphs;
831   unsigned int    orig_fdcount;
832   unsigned int    subset_fdcount;
833   unsigned int    subset_fdselect_format;
834   hb_vector_t<code_pair_t>   subset_fdselect_ranges;
835
836   /* font dict index remap table from fullset FDArray to subset FDArray.
837    * set to CFF_UNDEF_CODE if excluded from subset */
838   remap_t   fdmap;
839
840   str_buff_vec_t                subset_charstrings;
841   str_buff_vec_t                subset_globalsubrs;
842   hb_vector_t<str_buff_vec_t>   subset_localsubrs;
843   hb_vector_t<font_dict_values_mod_t>  fontdicts_mod;
844
845   bool          drop_hints;
846
847   bool          gid_renum;
848   bool          subset_encoding;
849   uint8_t       subset_enc_format;
850   unsigned int  subset_enc_num_codes;
851   range_list_t  subset_enc_code_ranges;
852   hb_vector_t<code_pair_t>  subset_enc_supp_codes;
853
854   uint8_t       subset_charset_format;
855   range_list_t  subset_charset_ranges;
856   bool          subset_charset;
857
858   remap_sid_t   sidmap;
859   unsigned int  topDictModSIDs[name_dict_values_t::ValCount];
860
861   bool          desubroutinize;
862   cff1_subr_subsetter_t       subr_subsetter;
863 };
864
865 static inline bool _write_cff1 (const cff_subset_plan &plan,
866                                 const OT::cff1::accelerator_subset_t  &acc,
867                                 const hb_vector_t<hb_codepoint_t>& glyphs,
868                                 unsigned int dest_sz,
869                                 void *dest)
870 {
871   hb_serialize_context_t c (dest, dest_sz);
872
873   OT::cff1 *cff = c.start_serialize<OT::cff1> ();
874   if (unlikely (!c.extend_min (*cff)))
875     return false;
876
877   /* header */
878   cff->version.major.set (0x01);
879   cff->version.minor.set (0x00);
880   cff->nameIndex.set (cff->min_size);
881   cff->offSize.set (4); /* unused? */
882
883   /* name INDEX */
884   {
885     assert (cff->nameIndex == (unsigned) (c.head - c.start));
886     CFF1NameIndex *dest = c.start_embed<CFF1NameIndex> ();
887     if (unlikely (dest == nullptr)) return false;
888     if (unlikely (!dest->serialize (&c, *acc.nameIndex)))
889     {
890       DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF name INDEX");
891       return false;
892     }
893   }
894
895   /* top dict INDEX */
896   {
897     assert (plan.offsets.topDictInfo.offset == (unsigned) (c.head - c.start));
898     CFF1IndexOf<TopDict> *dest = c.start_embed< CFF1IndexOf<TopDict> > ();
899     if (dest == nullptr) return false;
900     cff1_top_dict_op_serializer_t topSzr;
901     top_dict_modifiers_t  modifier (plan.offsets, plan.topDictModSIDs);
902     if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize,
903                                     &plan.topdict_mod, 1,
904                                     plan.topdict_sizes, topSzr, modifier)))
905     {
906       DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict");
907       return false;
908     }
909   }
910
911   /* String INDEX */
912   {
913     assert (plan.offsets.stringIndexInfo.offset == (unsigned) (c.head - c.start));
914     CFF1StringIndex *dest = c.start_embed<CFF1StringIndex> ();
915     if (unlikely (dest == nullptr)) return false;
916     if (unlikely (!dest->serialize (&c, *acc.stringIndex, plan.offsets.stringIndexInfo.offSize, plan.sidmap)))
917     {
918       DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF string INDEX");
919       return false;
920     }
921   }
922
923   /* global subrs */
924   {
925     assert (plan.offsets.globalSubrsInfo.offset != 0);
926     assert (plan.offsets.globalSubrsInfo.offset == (unsigned) (c.head - c.start));
927
928     CFF1Subrs *dest = c.start_embed <CFF1Subrs> ();
929     if (unlikely (dest == nullptr)) return false;
930     if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs)))
931     {
932       DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines");
933       return false;
934     }
935   }
936
937   /* Encoding */
938   if (plan.subset_encoding)
939   {
940     assert (plan.offsets.encodingOffset == (unsigned) (c.head - c.start));
941     Encoding *dest = c.start_embed<Encoding> ();
942     if (unlikely (dest == nullptr)) return false;
943     if (unlikely (!dest->serialize (&c,
944                                     plan.subset_enc_format,
945                                     plan.subset_enc_num_codes,
946                                     plan.subset_enc_code_ranges,
947                                     plan.subset_enc_supp_codes)))
948     {
949       DEBUG_MSG (SUBSET, nullptr, "failed to serialize Encoding");
950       return false;
951     }
952   }
953
954   /* Charset */
955   if (plan.subset_charset)
956   {
957     assert (plan.offsets.charsetInfo.offset == (unsigned) (c.head - c.start));
958     Charset *dest = c.start_embed<Charset> ();
959     if (unlikely (dest == nullptr)) return false;
960     if (unlikely (!dest->serialize (&c,
961                                     plan.subset_charset_format,
962                                     plan.num_glyphs,
963                                     plan.subset_charset_ranges)))
964     {
965       DEBUG_MSG (SUBSET, nullptr, "failed to serialize Charset");
966       return false;
967     }
968   }
969
970   /* FDSelect */
971   if (acc.fdSelect != &Null(CFF1FDSelect))
972   {
973     assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start));
974
975     if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.length, *acc.fdSelect, acc.fdCount,
976                                               plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
977                                               plan.subset_fdselect_ranges)))
978     {
979       DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF subset FDSelect");
980       return false;
981     }
982   }
983
984   /* FDArray (FD Index) */
985   if (acc.fdArray != &Null(CFF1FDArray))
986   {
987     assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start));
988     CFF1FDArray  *fda = c.start_embed<CFF1FDArray> ();
989     if (unlikely (fda == nullptr)) return false;
990     cff1_font_dict_op_serializer_t  fontSzr;
991     if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
992                                    plan.fontdicts_mod,
993                                    fontSzr)))
994     {
995       DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray");
996       return false;
997     }
998   }
999
1000   /* CharStrings */
1001   {
1002     assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start));
1003     CFF1CharStrings  *cs = c.start_embed<CFF1CharStrings> ();
1004     if (unlikely (cs == nullptr)) return false;
1005     if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
1006     {
1007       DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF CharStrings");
1008       return false;
1009     }
1010   }
1011
1012   /* private dicts & local subrs */
1013   assert (plan.offsets.privateDictInfo.offset == (unsigned) (c.head - c.start));
1014   for (unsigned int i = 0; i < acc.privateDicts.length; i++)
1015   {
1016     if (plan.fdmap.includes (i))
1017     {
1018       PrivateDict  *pd = c.start_embed<PrivateDict> ();
1019       if (unlikely (pd == nullptr)) return false;
1020       unsigned int priv_size = plan.fontdicts_mod[plan.fdmap[i]].privateDictInfo.size;
1021       bool result;
1022       cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
1023       /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
1024       unsigned int  subroffset = (plan.offsets.localSubrsInfos[i].size > 0)? priv_size: 0;
1025       result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset);
1026       if (unlikely (!result))
1027       {
1028         DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i);
1029         return false;
1030       }
1031       if (plan.offsets.localSubrsInfos[i].size > 0)
1032       {
1033         CFF1Subrs *dest = c.start_embed <CFF1Subrs> ();
1034         if (unlikely (dest == nullptr)) return false;
1035         if (unlikely (!dest->serialize (&c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i])))
1036         {
1037           DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines");
1038           return false;
1039         }
1040       }
1041     }
1042   }
1043
1044   assert (c.head == c.end);
1045   c.end_serialize ();
1046
1047   return true;
1048 }
1049
1050 static bool
1051 _hb_subset_cff1 (const OT::cff1::accelerator_subset_t  &acc,
1052                 const char              *data,
1053                 hb_subset_plan_t        *plan,
1054                 hb_blob_t               **prime /* OUT */)
1055 {
1056   cff_subset_plan cff_plan;
1057
1058   if (unlikely (!cff_plan.create (acc, plan)))
1059   {
1060     DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan.");
1061     return false;
1062   }
1063
1064   unsigned int  cff_prime_size = cff_plan.get_final_size ();
1065   char *cff_prime_data = (char *) calloc (1, cff_prime_size);
1066
1067   if (unlikely (!_write_cff1 (cff_plan, acc, plan->glyphs,
1068                               cff_prime_size, cff_prime_data))) {
1069     DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff.");
1070     free (cff_prime_data);
1071     return false;
1072   }
1073
1074   *prime = hb_blob_create (cff_prime_data,
1075                            cff_prime_size,
1076                            HB_MEMORY_MODE_READONLY,
1077                            cff_prime_data,
1078                            free);
1079   return true;
1080 }
1081
1082 /**
1083  * hb_subset_cff1:
1084  * Subsets the CFF table according to a provided plan.
1085  *
1086  * Return value: subsetted cff table.
1087  **/
1088 bool
1089 hb_subset_cff1 (hb_subset_plan_t *plan,
1090                 hb_blob_t       **prime /* OUT */)
1091 {
1092   hb_blob_t *cff_blob = hb_sanitize_context_t().reference_table<CFF::cff1> (plan->source);
1093   const char *data = hb_blob_get_data(cff_blob, nullptr);
1094
1095   OT::cff1::accelerator_subset_t acc;
1096   acc.init(plan->source);
1097   bool result = likely (acc.is_valid ()) &&
1098                         _hb_subset_cff1 (acc, data, plan, prime);
1099   hb_blob_destroy (cff_blob);
1100   acc.fini ();
1101
1102   return result;
1103 }