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