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