bf76a3edec485c4da0ef8e34b0486a7fbd1038cf
[platform/upstream/harfbuzz.git] / src / hb-subset-cff2.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-cff2-table.hh"
29 #include "hb-set.h"
30 #include "hb-subset-cff2.hh"
31 #include "hb-subset-plan.hh"
32 #include "hb-subset-cff-common.hh"
33 #include "hb-cff2-interp-cs.hh"
34
35 using namespace CFF;
36
37 struct cff2_sub_table_offsets_t : cff_sub_table_offsets_t
38 {
39   cff2_sub_table_offsets_t ()
40     : cff_sub_table_offsets_t (),
41       varStoreOffset (0)
42   {}
43
44   unsigned int  varStoreOffset;
45 };
46
47 struct cff2_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<>
48 {
49   bool serialize (hb_serialize_context_t *c,
50                   const op_str_t &opstr,
51                   const cff2_sub_table_offsets_t &offsets) const
52   {
53     TRACE_SERIALIZE (this);
54
55     switch (opstr.op)
56     {
57       case OpCode_vstore:
58         return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.varStoreOffset));
59
60       default:
61         return_trace (cff_top_dict_op_serializer_t<>::serialize (c, opstr, offsets));
62     }
63   }
64
65   unsigned int calculate_serialized_size (const op_str_t &opstr) const
66   {
67     switch (opstr.op)
68     {
69       case OpCode_vstore:
70         return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
71
72       default:
73         return cff_top_dict_op_serializer_t<>::calculate_serialized_size (opstr);
74     }
75   }
76 };
77
78 struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t>
79 {
80   static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param)
81   {
82     switch (op)
83     {
84       case OpCode_return:
85       case OpCode_endchar:
86         /* dummy opcodes in CFF2. ignore */
87         break;
88
89       case OpCode_hstem:
90       case OpCode_hstemhm:
91       case OpCode_vstem:
92       case OpCode_vstemhm:
93       case OpCode_hintmask:
94       case OpCode_cntrmask:
95         if (param.drop_hints)
96         {
97           env.clear_args ();
98           return;
99         }
100         HB_FALLTHROUGH;
101
102       default:
103         SUPER::flush_args_and_op (op, env, param);
104         break;
105     }
106   }
107
108   static void flush_args (cff2_cs_interp_env_t &env, flatten_param_t& param)
109   {
110     for (unsigned int i = 0; i < env.argStack.get_count ();)
111     {
112       const blend_arg_t &arg = env.argStack[i];
113       if (arg.blending ())
114       {
115         if (unlikely (!((arg.numValues > 0) && (env.argStack.get_count () >= arg.numValues))))
116         {
117           env.set_error ();
118           return;
119         }
120         flatten_blends (arg, i, env, param);
121         i += arg.numValues;
122       }
123       else
124       {
125         str_encoder_t  encoder (param.flatStr);
126         encoder.encode_num (arg);
127         i++;
128       }
129     }
130     SUPER::flush_args (env, param);
131   }
132
133   static void flatten_blends (const blend_arg_t &arg, unsigned int i, cff2_cs_interp_env_t &env, flatten_param_t& param)
134   {
135     /* flatten the default values */
136     str_encoder_t  encoder (param.flatStr);
137     for (unsigned int j = 0; j < arg.numValues; j++)
138     {
139       const blend_arg_t &arg1 = env.argStack[i + j];
140       if (unlikely (!((arg1.blending () && (arg.numValues == arg1.numValues) && (arg1.valueIndex == j) &&
141               (arg1.deltas.length == env.get_region_count ())))))
142       {
143         env.set_error ();
144         return;
145       }
146       encoder.encode_num (arg1);
147     }
148     /* flatten deltas for each value */
149     for (unsigned int j = 0; j < arg.numValues; j++)
150     {
151       const blend_arg_t &arg1 = env.argStack[i + j];
152       for (unsigned int k = 0; k < arg1.deltas.length; k++)
153         encoder.encode_num (arg1.deltas[k]);
154     }
155     /* flatten the number of values followed by blend operator */
156     encoder.encode_int (arg.numValues);
157     encoder.encode_op (OpCode_blendcs);
158   }
159
160   static void flush_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param)
161   {
162     switch (op)
163     {
164       case OpCode_return:
165       case OpCode_endchar:
166         return;
167       default:
168         str_encoder_t  encoder (param.flatStr);
169         encoder.encode_op (op);
170     }
171   }
172
173   private:
174   typedef cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t> SUPER;
175   typedef cs_opset_t<blend_arg_t, cff2_cs_opset_flatten_t, cff2_cs_opset_flatten_t, cff2_cs_interp_env_t, flatten_param_t> CSOPSET;
176 };
177
178 struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t>
179 {
180   static void process_op (op_code_t op, cff2_cs_interp_env_t &env, subr_subset_param_t& param)
181   {
182     switch (op) {
183
184       case OpCode_return:
185         param.current_parsed_str->set_parsed ();
186         env.returnFromSubr ();
187         param.set_current_str (env, false);
188         break;
189
190       case OpCode_endchar:
191         param.current_parsed_str->set_parsed ();
192         SUPER::process_op (op, env, param);
193         break;
194
195       case OpCode_callsubr:
196         process_call_subr (op, CSType_LocalSubr, env, param, env.localSubrs, param.local_closure);
197         break;
198
199       case OpCode_callgsubr:
200         process_call_subr (op, CSType_GlobalSubr, env, param, env.globalSubrs, param.global_closure);
201         break;
202
203       default:
204         SUPER::process_op (op, env, param);
205         param.current_parsed_str->add_op (op, env.str_ref);
206         break;
207     }
208   }
209
210   protected:
211   static void process_call_subr (op_code_t op, cs_type_t type,
212                                  cff2_cs_interp_env_t &env, subr_subset_param_t& param,
213                                  cff2_biased_subrs_t& subrs, hb_set_t *closure)
214   {
215     byte_str_ref_t    str_ref = env.str_ref;
216     env.callSubr (subrs, type);
217     param.current_parsed_str->add_call_op (op, str_ref, env.context.subr_num);
218     hb_set_add (closure, env.context.subr_num);
219     param.set_current_str (env, true);
220   }
221
222   private:
223   typedef cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t> SUPER;
224 };
225
226 struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_subr_subset_t>
227 {
228   cff2_subr_subsetter_t (const OT::cff2::accelerator_subset_t &acc, const hb_subset_plan_t *plan)
229     : subr_subsetter_t (acc, plan) {}
230
231   static void finalize_parsed_str (cff2_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
232   {
233     /* vsindex is inserted at the beginning of the charstring as necessary */
234     if (env.seen_vsindex ())
235     {
236       number_t  ivs;
237       ivs.set_int ((int)env.get_ivs ());
238       charstring.set_prefix (ivs, OpCode_vsindexcs);
239     }
240   }
241 };
242
243 struct cff2_subset_plan {
244   cff2_subset_plan ()
245     : final_size (0),
246       orig_fdcount (0),
247       subset_fdcount(1),
248       subset_fdselect_format (0),
249       drop_hints (false),
250       desubroutinize (false)
251   {
252     subset_fdselect_ranges.init ();
253     fdmap.init ();
254     subset_charstrings.init ();
255     subset_globalsubrs.init ();
256     subset_localsubrs.init ();
257     privateDictInfos.init ();
258   }
259
260   ~cff2_subset_plan ()
261   {
262     subset_fdselect_ranges.fini ();
263     fdmap.fini ();
264     subset_charstrings.fini_deep ();
265     subset_globalsubrs.fini_deep ();
266     subset_localsubrs.fini_deep ();
267     privateDictInfos.fini ();
268   }
269
270   bool create (const OT::cff2::accelerator_subset_t &acc,
271               hb_subset_plan_t *plan)
272   {
273     final_size = 0;
274     orig_fdcount = acc.fdArray->count;
275
276     drop_hints = plan->drop_hints;
277     desubroutinize = plan->desubroutinize;
278
279     /* CFF2 header */
280     final_size += OT::cff2::static_size;
281
282     /* top dict */
283     {
284       cff2_top_dict_op_serializer_t topSzr;
285       offsets.topDictInfo.size = TopDict::calculate_serialized_size (acc.topDict, topSzr);
286       final_size += offsets.topDictInfo.size;
287     }
288
289     if (desubroutinize)
290     {
291       /* Flatten global & local subrs */
292       subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_flatten_t>
293                     flattener(acc, plan);
294       if (!flattener.flatten (subset_charstrings))
295         return false;
296
297       /* no global/local subroutines */
298       offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (1, 0, 0);
299     }
300     else
301     {
302       cff2_subr_subsetter_t     subr_subsetter (acc, plan);
303
304       /* Subset subrs: collect used subroutines, leaving all unused ones behind */
305       if (!subr_subsetter.subset ())
306         return false;
307
308       /* encode charstrings, global subrs, local subrs with new subroutine numbers */
309       if (!subr_subsetter.encode_charstrings (subset_charstrings))
310         return false;
311
312       if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
313         return false;
314
315       /* global subrs */
316       unsigned int dataSize = subset_globalsubrs.total_size ();
317       offsets.globalSubrsInfo.offSize = calcOffSize (dataSize);
318       offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize);
319
320       /* local subrs */
321       if (!offsets.localSubrsInfos.resize (orig_fdcount))
322         return false;
323       if (!subset_localsubrs.resize (orig_fdcount))
324         return false;
325       for (unsigned int fd = 0; fd < orig_fdcount; fd++)
326       {
327         subset_localsubrs[fd].init ();
328         offsets.localSubrsInfos[fd].init ();
329         if (fdmap.includes (fd))
330         {
331           if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd]))
332             return false;
333
334           unsigned int dataSize = subset_localsubrs[fd].total_size ();
335           if (dataSize > 0)
336           {
337             offsets.localSubrsInfos[fd].offset = final_size;
338             offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize);
339             offsets.localSubrsInfos[fd].size = CFF2Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize);
340           }
341         }
342       }
343     }
344
345     /* global subrs */
346     offsets.globalSubrsInfo.offset = final_size;
347     final_size += offsets.globalSubrsInfo.size;
348
349     /* variation store */
350     if (acc.varStore != &Null(CFF2VariationStore))
351     {
352       offsets.varStoreOffset = final_size;
353       final_size += acc.varStore->get_size ();
354     }
355
356     /* FDSelect */
357     if (acc.fdSelect != &Null(CFF2FDSelect))
358     {
359       offsets.FDSelectInfo.offset = final_size;
360       if (unlikely (!hb_plan_subset_cff_fdselect (plan,
361                                   orig_fdcount,
362                                   *(const FDSelect *)acc.fdSelect,
363                                   subset_fdcount,
364                                   offsets.FDSelectInfo.size,
365                                   subset_fdselect_format,
366                                   subset_fdselect_ranges,
367                                   fdmap)))
368         return false;
369
370       final_size += offsets.FDSelectInfo.size;
371     }
372     else
373       fdmap.identity (1);
374
375     /* FDArray (FDIndex) */
376     {
377       offsets.FDArrayInfo.offset = final_size;
378       cff_font_dict_op_serializer_t fontSzr;
379       unsigned int dictsSize = 0;
380       for (unsigned int i = 0; i < acc.fontDicts.length; i++)
381         if (fdmap.includes (i))
382           dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr);
383
384       offsets.FDArrayInfo.offSize = calcOffSize (dictsSize);
385       final_size += CFF2Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize);
386     }
387
388     /* CharStrings */
389     {
390       offsets.charStringsInfo.offset = final_size;
391       unsigned int dataSize = subset_charstrings.total_size ();
392       offsets.charStringsInfo.offSize = calcOffSize (dataSize);
393       final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->num_output_glyphs (), dataSize);
394     }
395
396     /* private dicts & local subrs */
397     offsets.privateDictsOffset = final_size;
398     for (unsigned int i = 0; i < orig_fdcount; i++)
399     {
400       if (fdmap.includes (i))
401       {
402         bool  has_localsubrs = offsets.localSubrsInfos[i].size > 0;
403         cff_private_dict_op_serializer_t privSzr (desubroutinize, drop_hints);
404         unsigned int  priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs);
405         table_info_t  privInfo = { final_size, priv_size, 0 };
406         privateDictInfos.push (privInfo);
407         final_size += privInfo.size;
408
409         if (!plan->desubroutinize && has_localsubrs)
410         {
411           offsets.localSubrsInfos[i].offset = final_size;
412           final_size += offsets.localSubrsInfos[i].size;
413         }
414       }
415     }
416
417     return true;
418   }
419
420   unsigned int get_final_size () const  { return final_size; }
421
422   unsigned int  final_size;
423   cff2_sub_table_offsets_t offsets;
424
425   unsigned int    orig_fdcount;
426   unsigned int    subset_fdcount;
427   unsigned int    subset_fdselect_format;
428   hb_vector_t<code_pair_t>   subset_fdselect_ranges;
429
430   remap_t   fdmap;
431
432   str_buff_vec_t            subset_charstrings;
433   str_buff_vec_t            subset_globalsubrs;
434   hb_vector_t<str_buff_vec_t> subset_localsubrs;
435   hb_vector_t<table_info_t>  privateDictInfos;
436
437   bool      drop_hints;
438   bool      desubroutinize;
439 };
440
441 static inline bool _write_cff2 (const cff2_subset_plan &plan,
442                                 const OT::cff2::accelerator_subset_t  &acc,
443                                 unsigned int num_glyphs,
444                                 unsigned int dest_sz,
445                                 void *dest)
446 {
447   hb_serialize_context_t c (dest, dest_sz);
448
449   OT::cff2 *cff2 = c.start_serialize<OT::cff2> ();
450   if (unlikely (!c.extend_min (*cff2)))
451     return false;
452
453   /* header */
454   cff2->version.major.set (0x02);
455   cff2->version.minor.set (0x00);
456   cff2->topDict.set (OT::cff2::static_size);
457
458   /* top dict */
459   {
460     assert (cff2->topDict == (unsigned) (c.head - c.start));
461     cff2->topDictSize.set (plan.offsets.topDictInfo.size);
462     TopDict &dict = cff2 + cff2->topDict;
463     cff2_top_dict_op_serializer_t topSzr;
464     if (unlikely (!dict.serialize (&c, acc.topDict, topSzr, plan.offsets)))
465     {
466       DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 top dict");
467       return false;
468     }
469   }
470
471   /* global subrs */
472   {
473     assert (cff2->topDict + plan.offsets.topDictInfo.size == (unsigned) (c.head - c.start));
474     CFF2Subrs *dest = c.start_embed <CFF2Subrs> ();
475     if (unlikely (dest == nullptr)) return false;
476     if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs)))
477     {
478       DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines");
479       return false;
480     }
481   }
482
483   /* variation store */
484   if (acc.varStore != &Null(CFF2VariationStore))
485   {
486     assert (plan.offsets.varStoreOffset == (unsigned) (c.head - c.start));
487     CFF2VariationStore *dest = c.start_embed<CFF2VariationStore> ();
488     if (unlikely (!dest->serialize (&c, acc.varStore)))
489     {
490       DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 Variation Store");
491       return false;
492     }
493   }
494
495   /* FDSelect */
496   if (acc.fdSelect != &Null(CFF2FDSelect))
497   {
498     assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start));
499
500     if (unlikely (!hb_serialize_cff_fdselect (&c, num_glyphs, *(const FDSelect *)acc.fdSelect, acc.fdArray->count,
501                                               plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
502                                               plan.subset_fdselect_ranges)))
503     {
504       DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 subset FDSelect");
505       return false;
506     }
507   }
508
509   /* FDArray (FD Index) */
510   {
511     assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start));
512     CFF2FDArray  *fda = c.start_embed<CFF2FDArray> ();
513     if (unlikely (fda == nullptr)) return false;
514     cff_font_dict_op_serializer_t  fontSzr;
515     if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
516                                    acc.fontDicts, plan.subset_fdcount, plan.fdmap,
517                                    fontSzr, plan.privateDictInfos)))
518     {
519       DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDArray");
520       return false;
521     }
522   }
523
524   /* CharStrings */
525   {
526     assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start));
527     CFF2CharStrings  *cs = c.start_embed<CFF2CharStrings> ();
528     if (unlikely (cs == nullptr)) return false;
529     if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
530     {
531       DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 CharStrings");
532       return false;
533     }
534   }
535
536   /* private dicts & local subrs */
537   assert (plan.offsets.privateDictsOffset == (unsigned) (c.head - c.start));
538   for (unsigned int i = 0; i < acc.privateDicts.length; i++)
539   {
540     if (plan.fdmap.includes (i))
541     {
542       PrivateDict  *pd = c.start_embed<PrivateDict> ();
543       if (unlikely (pd == nullptr)) return false;
544       unsigned int priv_size = plan.privateDictInfos[plan.fdmap[i]].size;
545       bool result;
546       cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
547       /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
548       unsigned int  subroffset = (plan.offsets.localSubrsInfos[i].size > 0)? priv_size: 0;
549       result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset);
550       if (unlikely (!result))
551       {
552         DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i);
553         return false;
554       }
555       if (plan.offsets.localSubrsInfos[i].size > 0)
556       {
557         CFF2Subrs *dest = c.start_embed <CFF2Subrs> ();
558         if (unlikely (dest == nullptr)) return false;
559         if (unlikely (!dest->serialize (&c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i])))
560         {
561           DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines");
562           return false;
563         }
564       }
565     }
566   }
567
568   assert (c.head == c.end);
569   c.end_serialize ();
570
571   return true;
572 }
573
574 static bool
575 _hb_subset_cff2 (const OT::cff2::accelerator_subset_t  &acc,
576                 const char                    *data,
577                 hb_subset_plan_t                *plan,
578                 hb_blob_t                      **prime /* OUT */)
579 {
580   cff2_subset_plan cff2_plan;
581
582   if (unlikely (!cff2_plan.create (acc, plan)))
583   {
584     DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff2 subsetting plan.");
585     return false;
586   }
587
588   unsigned int  cff2_prime_size = cff2_plan.get_final_size ();
589   char *cff2_prime_data = (char *) calloc (1, cff2_prime_size);
590
591   if (unlikely (!_write_cff2 (cff2_plan, acc, plan->num_output_glyphs (),
592                               cff2_prime_size, cff2_prime_data))) {
593     DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2.");
594     free (cff2_prime_data);
595     return false;
596   }
597
598   *prime = hb_blob_create (cff2_prime_data,
599                            cff2_prime_size,
600                            HB_MEMORY_MODE_READONLY,
601                            cff2_prime_data,
602                            free);
603   return true;
604 }
605
606 /**
607  * hb_subset_cff2:
608  * Subsets the CFF2 table according to a provided plan.
609  *
610  * Return value: subsetted cff2 table.
611  **/
612 bool
613 hb_subset_cff2 (hb_subset_plan_t *plan,
614                 hb_blob_t       **prime /* OUT */)
615 {
616   hb_blob_t *cff2_blob = hb_sanitize_context_t().reference_table<CFF::cff2> (plan->source);
617   const char *data = hb_blob_get_data(cff2_blob, nullptr);
618
619   OT::cff2::accelerator_subset_t acc;
620   acc.init(plan->source);
621   bool result = likely (acc.is_valid ()) &&
622                 _hb_subset_cff2 (acc, data, plan, prime);
623
624   hb_blob_destroy (cff2_blob);
625   acc.fini ();
626
627   return result;
628 }