xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-subset-cff1.cc (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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-plan.hh"
36 #include "hb-subset-cff-common.hh"
37 #include "hb-cff1-interp-cs.hh"
38 
39 using namespace CFF;
40 
41 struct remap_sid_t
42 {
get_populationremap_sid_t43   unsigned get_population () const { return vector.length; }
44 
allocremap_sid_t45   void alloc (unsigned size)
46   {
47     map.alloc (size);
48     vector.alloc (size, true);
49   }
50 
in_errorremap_sid_t51   bool in_error () const
52   { return map.in_error () || vector.in_error (); }
53 
addremap_sid_t54   unsigned int add (unsigned int sid)
55   {
56     if (is_std_str (sid) || (sid == CFF_UNDEF_SID))
57       return sid;
58 
59     sid = unoffset_sid (sid);
60     unsigned v = next;
61     if (map.set (sid, v, false))
62     {
63       vector.push (sid);
64       next++;
65     }
66     else
67       v = map.get (sid); // already exists
68     return offset_sid (v);
69   }
70 
operator []remap_sid_t71   unsigned int operator[] (unsigned int sid) const
72   {
73     if (is_std_str (sid) || (sid == CFF_UNDEF_SID))
74       return sid;
75 
76     return offset_sid (map.get (unoffset_sid (sid)));
77   }
78 
79   static const unsigned int num_std_strings = 391;
80 
is_std_strremap_sid_t81   static bool is_std_str (unsigned int sid) { return sid < num_std_strings; }
offset_sidremap_sid_t82   static unsigned int offset_sid (unsigned int sid) { return sid + num_std_strings; }
unoffset_sidremap_sid_t83   static unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; }
84   unsigned next = 0;
85 
86   hb_map_t map;
87   hb_vector_t<unsigned> vector;
88 };
89 
90 struct cff1_sub_table_info_t : cff_sub_table_info_t
91 {
cff1_sub_table_info_tcff1_sub_table_info_t92   cff1_sub_table_info_t ()
93     : cff_sub_table_info_t (),
94       encoding_link (0),
95       charset_link (0)
96    {
97     privateDictInfo.init ();
98   }
99 
100   objidx_t	encoding_link;
101   objidx_t	charset_link;
102   table_info_t	privateDictInfo;
103 };
104 
105 /* a copy of a parsed out cff1_top_dict_values_t augmented with additional operators */
106 struct cff1_top_dict_values_mod_t : cff1_top_dict_values_t
107 {
initcff1_top_dict_values_mod_t108   void init (const cff1_top_dict_values_t *base_= &Null (cff1_top_dict_values_t))
109   {
110     SUPER::init ();
111     base = base_;
112   }
113 
finicff1_top_dict_values_mod_t114   void fini () { SUPER::fini (); }
115 
get_countcff1_top_dict_values_mod_t116   unsigned get_count () const { return base->get_count () + SUPER::get_count (); }
get_valuecff1_top_dict_values_mod_t117   const cff1_top_dict_val_t &get_value (unsigned int i) const
118   {
119     if (i < base->get_count ())
120       return (*base)[i];
121     else
122       return SUPER::values[i - base->get_count ()];
123   }
operator []cff1_top_dict_values_mod_t124   const cff1_top_dict_val_t &operator [] (unsigned int i) const { return get_value (i); }
125 
reassignSIDscff1_top_dict_values_mod_t126   void reassignSIDs (const remap_sid_t& sidmap)
127   {
128     for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
129       nameSIDs[i] = sidmap[base->nameSIDs[i]];
130   }
131 
132   protected:
133   typedef cff1_top_dict_values_t SUPER;
134   const cff1_top_dict_values_t *base;
135 };
136 
137 struct top_dict_modifiers_t
138 {
top_dict_modifiers_ttop_dict_modifiers_t139   top_dict_modifiers_t (const cff1_sub_table_info_t &info_,
140 			const unsigned int (&nameSIDs_)[name_dict_values_t::ValCount])
141     : info (info_),
142       nameSIDs (nameSIDs_)
143   {}
144 
145   const cff1_sub_table_info_t &info;
146   const unsigned int	(&nameSIDs)[name_dict_values_t::ValCount];
147 };
148 
149 struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<cff1_top_dict_val_t>
150 {
serializecff1_top_dict_op_serializer_t151   bool serialize (hb_serialize_context_t *c,
152 		  const cff1_top_dict_val_t &opstr,
153 		  const top_dict_modifiers_t &mod) const
154   {
155     TRACE_SERIALIZE (this);
156 
157     op_code_t op = opstr.op;
158     switch (op)
159     {
160       case OpCode_charset:
161 	if (mod.info.charset_link)
162 	  return_trace (FontDict::serialize_link4_op(c, op, mod.info.charset_link, whence_t::Absolute));
163 	else
164 	  goto fall_back;
165 
166       case OpCode_Encoding:
167 	if (mod.info.encoding_link)
168 	  return_trace (FontDict::serialize_link4_op(c, op, mod.info.encoding_link, whence_t::Absolute));
169 	else
170 	  goto fall_back;
171 
172       case OpCode_Private:
173 	return_trace (UnsizedByteStr::serialize_int2 (c, mod.info.privateDictInfo.size) &&
174 		      Dict::serialize_link4_op (c, op, mod.info.privateDictInfo.link, whence_t::Absolute));
175 
176       case OpCode_version:
177       case OpCode_Notice:
178       case OpCode_Copyright:
179       case OpCode_FullName:
180       case OpCode_FamilyName:
181       case OpCode_Weight:
182       case OpCode_PostScript:
183       case OpCode_BaseFontName:
184       case OpCode_FontName:
185 	return_trace (FontDict::serialize_int2_op (c, op, mod.nameSIDs[name_dict_values_t::name_op_to_index (op)]));
186 
187       case OpCode_ROS:
188 	{
189 	  /* for registry & ordering, reassigned SIDs are serialized
190 	   * for supplement, the original byte string is copied along with the op code */
191 	  op_str_t supp_op;
192 	  supp_op.op = op;
193 	  if ( unlikely (!(opstr.length >= opstr.last_arg_offset + 3)))
194 	    return_trace (false);
195 	  supp_op.ptr = opstr.ptr + opstr.last_arg_offset;
196 	  supp_op.length = opstr.length - opstr.last_arg_offset;
197 	  return_trace (UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::registry]) &&
198 			UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::ordering]) &&
199 			copy_opstr (c, supp_op));
200 	}
201       fall_back:
202       default:
203 	return_trace (cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::serialize (c, opstr, mod.info));
204     }
205     return_trace (true);
206   }
207 
208 };
209 
210 struct cff1_font_dict_op_serializer_t : cff_font_dict_op_serializer_t
211 {
serializecff1_font_dict_op_serializer_t212   bool serialize (hb_serialize_context_t *c,
213 		  const op_str_t &opstr,
214 		  const cff1_font_dict_values_mod_t &mod) const
215   {
216     TRACE_SERIALIZE (this);
217 
218     if (opstr.op == OpCode_FontName)
219       return_trace (FontDict::serialize_int2_op (c, opstr.op, mod.fontName));
220     else
221       return_trace (SUPER::serialize (c, opstr, mod.privateDictInfo));
222   }
223 
224   private:
225   typedef cff_font_dict_op_serializer_t SUPER;
226 };
227 
228 struct cff1_cs_opset_flatten_t : cff1_cs_opset_t<cff1_cs_opset_flatten_t, flatten_param_t>
229 {
flush_args_and_opcff1_cs_opset_flatten_t230   static void flush_args_and_op (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param)
231   {
232     if (env.arg_start > 0)
233       flush_width (env, param);
234 
235     switch (op)
236     {
237       case OpCode_hstem:
238       case OpCode_hstemhm:
239       case OpCode_vstem:
240       case OpCode_vstemhm:
241       case OpCode_hintmask:
242       case OpCode_cntrmask:
243       case OpCode_dotsection:
244 	if (param.drop_hints)
245 	{
246 	  env.clear_args ();
247 	  return;
248 	}
249 	HB_FALLTHROUGH;
250 
251       default:
252 	SUPER::flush_args_and_op (op, env, param);
253 	break;
254     }
255   }
flush_argscff1_cs_opset_flatten_t256   static void flush_args (cff1_cs_interp_env_t &env, flatten_param_t& param)
257   {
258     str_encoder_t  encoder (param.flatStr);
259     for (unsigned int i = env.arg_start; i < env.argStack.get_count (); i++)
260       encoder.encode_num_cs (env.eval_arg (i));
261     SUPER::flush_args (env, param);
262   }
263 
flush_opcff1_cs_opset_flatten_t264   static void flush_op (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param)
265   {
266     str_encoder_t  encoder (param.flatStr);
267     encoder.encode_op (op);
268   }
269 
flush_widthcff1_cs_opset_flatten_t270   static void flush_width (cff1_cs_interp_env_t &env, flatten_param_t& param)
271   {
272     assert (env.has_width);
273     str_encoder_t  encoder (param.flatStr);
274     encoder.encode_num_cs (env.width);
275   }
276 
flush_hintmaskcff1_cs_opset_flatten_t277   static void flush_hintmask (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param)
278   {
279     SUPER::flush_hintmask (op, env, param);
280     if (!param.drop_hints)
281     {
282       str_encoder_t  encoder (param.flatStr);
283       for (unsigned int i = 0; i < env.hintmask_size; i++)
284 	encoder.encode_byte (env.str_ref[i]);
285     }
286   }
287 
288   private:
289   typedef cff1_cs_opset_t<cff1_cs_opset_flatten_t, flatten_param_t> SUPER;
290 };
291 
292 struct range_list_t : hb_vector_t<code_pair_t>
293 {
294   /* replace the first glyph ID in the "glyph" field each range with a nLeft value */
completerange_list_t295   bool complete (unsigned int last_glyph)
296   {
297     hb_codepoint_t all_glyphs = 0;
298     unsigned count = this->length;
299     for (unsigned int i = count; i; i--)
300     {
301       code_pair_t &pair = arrayZ[i - 1];
302       unsigned int nLeft = last_glyph - pair.glyph - 1;
303       all_glyphs |= nLeft;
304       last_glyph = pair.glyph;
305       pair.glyph = nLeft;
306     }
307     bool two_byte = all_glyphs >= 0x100;
308     return two_byte;
309   }
310 };
311 
312 struct cff1_cs_opset_subr_subset_t : cff1_cs_opset_t<cff1_cs_opset_subr_subset_t, subr_subset_param_t>
313 {
process_opcff1_cs_opset_subr_subset_t314   static void process_op (op_code_t op, cff1_cs_interp_env_t &env, subr_subset_param_t& param)
315   {
316     switch (op) {
317 
318       case OpCode_return:
319 	param.current_parsed_str->add_op (op, env.str_ref);
320 	param.current_parsed_str->set_parsed ();
321 	env.return_from_subr ();
322 	param.set_current_str (env, false);
323 	break;
324 
325       case OpCode_endchar:
326 	param.current_parsed_str->add_op (op, env.str_ref);
327 	param.current_parsed_str->set_parsed ();
328 	SUPER::process_op (op, env, param);
329 	break;
330 
331       case OpCode_callsubr:
332 	process_call_subr (op, CSType_LocalSubr, env, param, env.localSubrs, param.local_closure);
333 	break;
334 
335       case OpCode_callgsubr:
336 	process_call_subr (op, CSType_GlobalSubr, env, param, env.globalSubrs, param.global_closure);
337 	break;
338 
339       default:
340 	SUPER::process_op (op, env, param);
341 	param.current_parsed_str->add_op (op, env.str_ref);
342 	break;
343     }
344   }
345 
346   protected:
process_call_subrcff1_cs_opset_subr_subset_t347   static void process_call_subr (op_code_t op, cs_type_t type,
348 				 cff1_cs_interp_env_t &env, subr_subset_param_t& param,
349 				 cff1_biased_subrs_t& subrs, hb_set_t *closure)
350   {
351     byte_str_ref_t    str_ref = env.str_ref;
352     env.call_subr (subrs, type);
353     param.current_parsed_str->add_call_op (op, str_ref, env.context.subr_num);
354     closure->add (env.context.subr_num);
355     param.set_current_str (env, true);
356   }
357 
358   private:
359   typedef cff1_cs_opset_t<cff1_cs_opset_subr_subset_t, subr_subset_param_t> SUPER;
360 };
361 
362 struct cff1_private_dict_op_serializer_t : op_serializer_t
363 {
cff1_private_dict_op_serializer_tcff1_private_dict_op_serializer_t364   cff1_private_dict_op_serializer_t (bool desubroutinize_, bool drop_hints_)
365     : desubroutinize (desubroutinize_), drop_hints (drop_hints_) {}
366 
serializecff1_private_dict_op_serializer_t367   bool serialize (hb_serialize_context_t *c,
368 		  const op_str_t &opstr,
369 		  objidx_t subrs_link) const
370   {
371     TRACE_SERIALIZE (this);
372 
373     if (drop_hints && dict_opset_t::is_hint_op (opstr.op))
374       return_trace (true);
375 
376     if (opstr.op == OpCode_Subrs)
377     {
378       if (desubroutinize || !subrs_link)
379 	return_trace (true);
380       else
381 	return_trace (FontDict::serialize_link2_op (c, opstr.op, subrs_link));
382     }
383 
384     return_trace (copy_opstr (c, opstr));
385   }
386 
387   protected:
388   const bool desubroutinize;
389   const bool drop_hints;
390 };
391 
392 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>
393 {
cff1_subr_subsetter_tcff1_subr_subsetter_t394   cff1_subr_subsetter_t (const OT::cff1::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_)
395     : subr_subsetter_t (acc_, plan_) {}
396 
complete_parsed_strcff1_subr_subsetter_t397   static void complete_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))
411 	parsed_str->set_parsed ();
412       else
413 	env.set_error ();
414     }
415   }
416 };
417 
418 namespace OT {
419 struct cff1_subset_plan
420 {
cff1_subset_planOT::cff1_subset_plan421   cff1_subset_plan ()
422   {
423     for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
424       topDictModSIDs[i] = CFF_UNDEF_SID;
425   }
426 
plan_subset_encodingOT::cff1_subset_plan427   void plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
428   {
429     const Encoding *encoding = acc.encoding;
430     unsigned int  size0, size1;
431     unsigned code, last_code = CFF_UNDEF_CODE - 1;
432     hb_vector_t<hb_codepoint_t> supp_codes;
433 
434     if (unlikely (!subset_enc_code_ranges.resize (0)))
435     {
436       plan->check_success (false);
437       return;
438     }
439 
440     supp_codes.init ();
441 
442     code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID};
443     subset_enc_num_codes = plan->num_output_glyphs () - 1;
444     unsigned int glyph;
445     auto it = hb_iter (plan->new_to_old_gid_list);
446     if (it->first == 0) it++;
447     auto _ = *it;
448     for (glyph = 1; glyph < num_glyphs; glyph++)
449     {
450       hb_codepoint_t old_glyph;
451       if (glyph == _.first)
452       {
453 	old_glyph = _.second;
454 	_ = *++it;
455       }
456       else
457       {
458 	/* Retain the SID for the old missing glyph ID */
459 	old_glyph = glyph;
460       }
461       code = acc.glyph_to_code (old_glyph, &glyph_to_sid_cache);
462       if (code == CFF_UNDEF_CODE)
463       {
464 	subset_enc_num_codes = glyph - 1;
465 	break;
466       }
467 
468       if (code != last_code + 1)
469 	subset_enc_code_ranges.push (code_pair_t {code, glyph});
470       last_code = code;
471 
472       if (encoding != &Null (Encoding))
473       {
474 	hb_codepoint_t  sid = acc.glyph_to_sid (old_glyph, &glyph_to_sid_cache);
475 	encoding->get_supplement_codes (sid, supp_codes);
476 	for (unsigned int i = 0; i < supp_codes.length; i++)
477 	  subset_enc_supp_codes.push (code_pair_t {supp_codes[i], sid});
478       }
479     }
480     supp_codes.fini ();
481 
482     subset_enc_code_ranges.complete (glyph);
483 
484     assert (subset_enc_num_codes <= 0xFF);
485     size0 = Encoding0::min_size + HBUINT8::static_size * subset_enc_num_codes;
486     size1 = Encoding1::min_size + Encoding1_Range::static_size * subset_enc_code_ranges.length;
487 
488     if (size0 < size1)
489       subset_enc_format = 0;
490     else
491       subset_enc_format = 1;
492   }
493 
plan_subset_charsetOT::cff1_subset_plan494   bool plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
495   {
496     unsigned int  size0, size_ranges;
497     unsigned last_sid = CFF_UNDEF_CODE - 1;
498 
499     if (unlikely (!subset_charset_ranges.resize (0)))
500     {
501       plan->check_success (false);
502       return false;
503     }
504 
505     code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID};
506 
507     unsigned num_glyphs = plan->num_output_glyphs ();
508 
509     if (unlikely (!subset_charset_ranges.alloc (hb_min (num_glyphs,
510 							acc.num_charset_entries))))
511     {
512       plan->check_success (false);
513       return false;
514     }
515 
516     glyph_to_sid_map_t *glyph_to_sid_map = acc.cff_accelerator ?
517 					   acc.cff_accelerator->glyph_to_sid_map.get_acquire () :
518 					   nullptr;
519     bool created_map = false;
520     if (!glyph_to_sid_map && acc.cff_accelerator)
521     {
522       created_map = true;
523       glyph_to_sid_map = acc.create_glyph_to_sid_map ();
524     }
525 
526     auto it = hb_iter (plan->new_to_old_gid_list);
527     if (it->first == 0) it++;
528     auto _ = *it;
529     bool not_is_cid = !acc.is_CID ();
530     bool skip = !not_is_cid && glyph_to_sid_map;
531     if (not_is_cid)
532       sidmap.alloc (num_glyphs);
533     for (hb_codepoint_t glyph = 1; glyph < num_glyphs; glyph++)
534     {
535       hb_codepoint_t old_glyph;
536       if (glyph == _.first)
537       {
538 	old_glyph = _.second;
539 	_ = *++it;
540       }
541       else
542       {
543 	/* Retain the SID for the old missing glyph ID */
544 	old_glyph = glyph;
545       }
546       unsigned sid = glyph_to_sid_map ?
547 		     glyph_to_sid_map->arrayZ[old_glyph].code :
548 		     acc.glyph_to_sid (old_glyph, &glyph_to_sid_cache);
549 
550       if (not_is_cid)
551 	sid = sidmap.add (sid);
552 
553       if (sid != last_sid + 1)
554 	subset_charset_ranges.push (code_pair_t {sid, glyph});
555 
556       if (glyph == old_glyph && skip)
557       {
558 	glyph = hb_min (_.first - 1, glyph_to_sid_map->arrayZ[old_glyph].glyph);
559 	sid += glyph - old_glyph;
560       }
561       last_sid = sid;
562     }
563 
564     if (created_map)
565     {
566       if ((!plan->accelerator && acc.cff_accelerator) ||
567 	  !acc.cff_accelerator->glyph_to_sid_map.cmpexch (nullptr, glyph_to_sid_map))
568       {
569 	glyph_to_sid_map->~glyph_to_sid_map_t ();
570 	hb_free (glyph_to_sid_map);
571       }
572     }
573 
574     bool two_byte = subset_charset_ranges.complete (num_glyphs);
575 
576     size0 = Charset0::get_size (plan->num_output_glyphs ());
577     if (!two_byte)
578       size_ranges = Charset1::get_size_for_ranges (subset_charset_ranges.length);
579     else
580       size_ranges = Charset2::get_size_for_ranges (subset_charset_ranges.length);
581 
582     if (size0 < size_ranges)
583       subset_charset_format = 0;
584     else if (!two_byte)
585       subset_charset_format = 1;
586     else
587       subset_charset_format = 2;
588 
589     return true;
590   }
591 
collect_sids_in_dictsOT::cff1_subset_plan592   bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc)
593   {
594     for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
595     {
596       unsigned int sid = acc.topDict.nameSIDs[i];
597       if (sid != CFF_UNDEF_SID)
598       {
599 	topDictModSIDs[i] = sidmap.add (sid);
600       }
601     }
602 
603     if (acc.fdArray != &Null (CFF1FDArray))
604       for (unsigned int i = 0; i < orig_fdcount; i++)
605 	if (fdmap.has (i))
606 	  (void)sidmap.add (acc.fontDicts[i].fontName);
607 
608     return true;
609   }
610 
createOT::cff1_subset_plan611   bool create (const OT::cff1::accelerator_subset_t &acc,
612 	       hb_subset_plan_t *plan)
613   {
614     /* make sure notdef is first */
615     hb_codepoint_t old_glyph;
616     if (!plan->old_gid_for_new_gid (0, &old_glyph) || (old_glyph != 0)) return false;
617 
618     num_glyphs = plan->num_output_glyphs ();
619     orig_fdcount = acc.fdCount;
620     drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING;
621     desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE;
622 
623  #ifdef HB_EXPERIMENTAL_API
624     min_charstrings_off_size = (plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS) ? 4 : 0;
625  #else
626     min_charstrings_off_size = 0;
627  #endif
628 
629     subset_charset = !acc.is_predef_charset ();
630     if (!subset_charset)
631       /* check whether the subset renumbers any glyph IDs */
632       for (const auto &_ : plan->new_to_old_gid_list)
633       {
634 	if (_.first != _.second)
635 	{
636 	  subset_charset = true;
637 	  break;
638 	}
639       }
640 
641     subset_encoding = !acc.is_CID() && !acc.is_predef_encoding ();
642 
643     /* top dict INDEX */
644     {
645       /* Add encoding/charset to a (copy of) top dict as necessary */
646       topdict_mod.init (&acc.topDict);
647       bool need_to_add_enc = (subset_encoding && !acc.topDict.has_op (OpCode_Encoding));
648       bool need_to_add_set = (subset_charset && !acc.topDict.has_op (OpCode_charset));
649       if (need_to_add_enc || need_to_add_set)
650       {
651 	if (need_to_add_enc)
652 	  topdict_mod.add_op (OpCode_Encoding);
653 	if (need_to_add_set)
654 	  topdict_mod.add_op (OpCode_charset);
655       }
656     }
657 
658     /* Determine re-mapping of font index as fdmap among other info */
659     if (acc.fdSelect != &Null (CFF1FDSelect))
660     {
661 	if (unlikely (!hb_plan_subset_cff_fdselect (plan,
662 				  orig_fdcount,
663 				  *acc.fdSelect,
664 				  subset_fdcount,
665 				  info.fd_select.size,
666 				  subset_fdselect_format,
667 				  subset_fdselect_ranges,
668 				  fdmap)))
669 	return false;
670     }
671     else
672       fdmap.identity (1);
673 
674     /* remove unused SIDs & reassign SIDs */
675     {
676       /* SIDs for name strings in dicts are added before glyph names so they fit in 16-bit int range */
677       if (unlikely (!collect_sids_in_dicts (acc)))
678 	return false;
679       if (unlikely (sidmap.get_population () > 0x8000))	/* assumption: a dict won't reference that many strings */
680 	return false;
681 
682       if (subset_charset && !plan_subset_charset (acc, plan))
683         return false;
684 
685       topdict_mod.reassignSIDs (sidmap);
686     }
687 
688     if (desubroutinize)
689     {
690       /* Flatten global & local subrs */
691       subr_flattener_t<const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_flatten_t, OpCode_endchar>
692 		    flattener(acc, plan);
693       if (!flattener.flatten (subset_charstrings))
694 	return false;
695     }
696     else
697     {
698       cff1_subr_subsetter_t       subr_subsetter (acc, plan);
699 
700       /* Subset subrs: collect used subroutines, leaving all unused ones behind */
701       if (!subr_subsetter.subset ())
702 	return false;
703 
704       /* encode charstrings, global subrs, local subrs with new subroutine numbers */
705       if (!subr_subsetter.encode_charstrings (subset_charstrings))
706 	return false;
707 
708       if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
709 	return false;
710 
711       /* local subrs */
712       if (!subset_localsubrs.resize (orig_fdcount))
713 	return false;
714       for (unsigned int fd = 0; fd < orig_fdcount; fd++)
715       {
716 	subset_localsubrs[fd].init ();
717 	if (fdmap.has (fd))
718 	{
719 	  if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd]))
720 	    return false;
721 	}
722       }
723     }
724 
725     /* Encoding */
726     if (subset_encoding)
727       plan_subset_encoding (acc, plan);
728 
729     /* private dicts & local subrs */
730     if (!acc.is_CID ())
731       fontdicts_mod.push (cff1_font_dict_values_mod_t ());
732     else
733     {
734       + hb_iter (acc.fontDicts)
735       | hb_filter ([&] (const cff1_font_dict_values_t &_)
736 	{ return fdmap.has (&_ - &acc.fontDicts[0]); } )
737       | hb_map ([&] (const cff1_font_dict_values_t &_)
738 	{
739 	  cff1_font_dict_values_mod_t mod;
740 	  mod.init (&_, sidmap[_.fontName]);
741 	  return mod;
742 	})
743       | hb_sink (fontdicts_mod)
744       ;
745     }
746 
747     return !plan->in_error () &&
748 	   (subset_charstrings.length == plan->num_output_glyphs ()) &&
749 	   (fontdicts_mod.length == subset_fdcount);
750   }
751 
752   cff1_top_dict_values_mod_t	topdict_mod;
753   cff1_sub_table_info_t		info;
754 
755   unsigned int    num_glyphs;
756   unsigned int    orig_fdcount = 0;
757   unsigned int    subset_fdcount = 1;
758   unsigned int    subset_fdselect_format = 0;
759   hb_vector_t<code_pair_t>   subset_fdselect_ranges;
760 
761   /* font dict index remap table from fullset FDArray to subset FDArray.
762    * set to CFF_UNDEF_CODE if excluded from subset */
763   hb_inc_bimap_t   fdmap;
764 
765   str_buff_vec_t		subset_charstrings;
766   str_buff_vec_t		subset_globalsubrs;
767   hb_vector_t<str_buff_vec_t>	subset_localsubrs;
768   hb_vector_t<cff1_font_dict_values_mod_t>  fontdicts_mod;
769 
770   bool		drop_hints = false;
771 
772   bool		gid_renum;
773   bool		subset_encoding;
774   uint8_t	subset_enc_format;
775   unsigned int	subset_enc_num_codes;
776   range_list_t	subset_enc_code_ranges;
777   hb_vector_t<code_pair_t>  subset_enc_supp_codes;
778 
779   uint8_t	subset_charset_format;
780   range_list_t	subset_charset_ranges;
781   bool		subset_charset;
782 
783   remap_sid_t	sidmap;
784   unsigned int	topDictModSIDs[name_dict_values_t::ValCount];
785 
786   bool		desubroutinize = false;
787 
788   unsigned	min_charstrings_off_size = 0;
789 };
790 } // namespace OT
791 
_serialize_cff1_charstrings(hb_serialize_context_t * c,struct OT::cff1_subset_plan & plan,const OT::cff1::accelerator_subset_t & acc)792 static bool _serialize_cff1_charstrings (hb_serialize_context_t *c,
793                                          struct OT::cff1_subset_plan &plan,
794                                          const OT::cff1::accelerator_subset_t  &acc)
795 {
796   c->push<CFF1CharStrings> ();
797 
798   unsigned data_size = 0;
799   unsigned total_size = CFF1CharStrings::total_size (plan.subset_charstrings, &data_size, plan.min_charstrings_off_size);
800   if (unlikely (!c->start_zerocopy (total_size)))
801     return false;
802 
803   auto *cs = c->start_embed<CFF1CharStrings> ();
804   if (unlikely (!cs->serialize (c, plan.subset_charstrings, &data_size, plan.min_charstrings_off_size))) {
805     c->pop_discard ();
806     return false;
807   }
808 
809   plan.info.char_strings_link = c->pop_pack (false);
810   return true;
811 }
812 
813 bool
serialize(hb_serialize_context_t * c,struct OT::cff1_subset_plan & plan) const814 OT::cff1::accelerator_subset_t::serialize (hb_serialize_context_t *c,
815 					   struct OT::cff1_subset_plan &plan) const
816 {
817   /* push charstrings onto the object stack first which will ensure it packs as the last
818      object in the table. Keeping the chastrings last satisfies the requirements for patching
819      via IFTB. If this ordering needs to be changed in the future, charstrings should be left
820      at the end whenever HB_SUBSET_FLAGS_ITFB_REQUIREMENTS is enabled. */
821   if (!_serialize_cff1_charstrings(c, plan, *this))
822     return false;
823 
824   /* private dicts & local subrs */
825   for (int i = (int) privateDicts.length; --i >= 0 ;)
826   {
827     if (plan.fdmap.has (i))
828     {
829       objidx_t	subrs_link = 0;
830       if (plan.subset_localsubrs[i].length > 0)
831       {
832 	auto *dest = c->push <CFF1Subrs> ();
833 	if (likely (dest->serialize (c, plan.subset_localsubrs[i])))
834 	  subrs_link = c->pop_pack ();
835 	else
836 	{
837 	  c->pop_discard ();
838 	  return false;
839 	}
840       }
841 
842       auto *pd = c->push<PrivateDict> ();
843       cff1_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
844       /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
845       if (likely (pd->serialize (c, privateDicts[i], privSzr, subrs_link)))
846       {
847 	unsigned fd = plan.fdmap[i];
848 	plan.fontdicts_mod[fd].privateDictInfo.size = c->length ();
849 	plan.fontdicts_mod[fd].privateDictInfo.link = c->pop_pack ();
850       }
851       else
852       {
853 	c->pop_discard ();
854 	return false;
855       }
856     }
857   }
858 
859   if (!is_CID ())
860     plan.info.privateDictInfo = plan.fontdicts_mod[0].privateDictInfo;
861 
862   /* FDArray (FD Index) */
863   if (fdArray != &Null (CFF1FDArray))
864   {
865     auto *fda = c->push<CFF1FDArray> ();
866     cff1_font_dict_op_serializer_t  fontSzr;
867     auto it = + hb_zip (+ hb_iter (plan.fontdicts_mod), + hb_iter (plan.fontdicts_mod));
868     if (likely (fda->serialize (c, it, fontSzr)))
869       plan.info.fd_array_link = c->pop_pack (false);
870     else
871     {
872       c->pop_discard ();
873       return false;
874     }
875   }
876 
877   /* FDSelect */
878   if (fdSelect != &Null (CFF1FDSelect))
879   {
880     c->push ();
881     if (likely (hb_serialize_cff_fdselect (c, plan.num_glyphs, *fdSelect, fdCount,
882 					   plan.subset_fdselect_format, plan.info.fd_select.size,
883 					   plan.subset_fdselect_ranges)))
884       plan.info.fd_select.link = c->pop_pack ();
885     else
886     {
887       c->pop_discard ();
888       return false;
889     }
890   }
891 
892   /* Charset */
893   if (plan.subset_charset)
894   {
895     auto *dest = c->push<Charset> ();
896     if (likely (dest->serialize (c,
897 				 plan.subset_charset_format,
898 				 plan.num_glyphs,
899 				 plan.subset_charset_ranges)))
900       plan.info.charset_link = c->pop_pack ();
901     else
902     {
903       c->pop_discard ();
904       return false;
905     }
906   }
907 
908   /* Encoding */
909   if (plan.subset_encoding)
910   {
911     auto *dest = c->push<Encoding> ();
912     if (likely (dest->serialize (c,
913 				 plan.subset_enc_format,
914 				 plan.subset_enc_num_codes,
915 				 plan.subset_enc_code_ranges,
916 				 plan.subset_enc_supp_codes)))
917       plan.info.encoding_link = c->pop_pack ();
918     else
919     {
920       c->pop_discard ();
921       return false;
922     }
923   }
924 
925   /* global subrs */
926   {
927     auto *dest = c->push <CFF1Subrs> ();
928     if (likely (dest->serialize (c, plan.subset_globalsubrs)))
929       c->pop_pack (false);
930     else
931     {
932       c->pop_discard ();
933       return false;
934     }
935   }
936 
937   /* String INDEX */
938   {
939     auto *dest = c->push<CFF1StringIndex> ();
940     if (likely (!plan.sidmap.in_error () &&
941 		dest->serialize (c, *stringIndex, plan.sidmap.vector)))
942       c->pop_pack ();
943     else
944     {
945       c->pop_discard ();
946       return false;
947     }
948   }
949 
950   OT::cff1 *cff = c->allocate_min<OT::cff1> ();
951   if (unlikely (!cff))
952     return false;
953 
954   /* header */
955   cff->version.major = 0x01;
956   cff->version.minor = 0x00;
957   cff->nameIndex = cff->min_size;
958   cff->offSize = 4; /* unused? */
959 
960   /* name INDEX */
961   if (unlikely (!c->embed (*nameIndex))) return false;
962 
963   /* top dict INDEX */
964   {
965     /* serialize singleton TopDict */
966     auto *top = c->push<TopDict> ();
967     cff1_top_dict_op_serializer_t topSzr;
968     unsigned top_size = 0;
969     top_dict_modifiers_t  modifier (plan.info, plan.topDictModSIDs);
970     if (likely (top->serialize (c, plan.topdict_mod, topSzr, modifier)))
971     {
972       top_size = c->length ();
973       c->pop_pack (false);
974     }
975     else
976     {
977       c->pop_discard ();
978       return false;
979     }
980     /* serialize INDEX header for above */
981     auto *dest = c->start_embed<CFF1Index> ();
982     return dest->serialize_header (c, hb_iter (&top_size, 1), top_size);
983   }
984 }
985 
986 bool
subset(hb_subset_context_t * c) const987 OT::cff1::accelerator_subset_t::subset (hb_subset_context_t *c) const
988 {
989   cff1_subset_plan cff_plan;
990 
991   if (unlikely (!cff_plan.create (*this, c->plan)))
992   {
993     DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan.");
994     return false;
995   }
996 
997   return serialize (c->serializer, cff_plan);
998 }
999 
1000 
1001 #endif
1002