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