• 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  #ifndef HB_OT_CFF2_TABLE_HH
28  #define HB_OT_CFF2_TABLE_HH
29  
30  #include "hb-ot-head-table.hh"
31  #include "hb-ot-cff-common.hh"
32  #include "hb-subset-cff2.hh"
33  
34  namespace CFF {
35  
36  /*
37   * CFF2 -- Compact Font Format (CFF) Version 2
38   * https://docs.microsoft.com/en-us/typography/opentype/spec/cff2
39   */
40  #define HB_OT_TAG_cff2 HB_TAG('C','F','F','2')
41  
42  typedef CFFIndex<HBUINT32>  CFF2Index;
43  template <typename Type> struct CFF2IndexOf : CFFIndexOf<HBUINT32, Type> {};
44  
45  typedef CFF2Index         CFF2CharStrings;
46  typedef FDArray<HBUINT32> CFF2FDArray;
47  typedef Subrs<HBUINT32>   CFF2Subrs;
48  
49  typedef FDSelect3_4<HBUINT32, HBUINT16> FDSelect4;
50  typedef FDSelect3_4_Range<HBUINT32, HBUINT16> FDSelect4_Range;
51  
52  struct CFF2FDSelect
53  {
serializeCFF::CFF2FDSelect54    bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs)
55    {
56      TRACE_SERIALIZE (this);
57      unsigned int size = src.get_size (num_glyphs);
58      CFF2FDSelect *dest = c->allocate_size<CFF2FDSelect> (size);
59      if (unlikely (dest == nullptr)) return_trace (false);
60      memcpy (dest, &src, size);
61      return_trace (true);
62    }
63  
calculate_serialized_sizeCFF::CFF2FDSelect64    unsigned int calculate_serialized_size (unsigned int num_glyphs) const
65    { return get_size (num_glyphs); }
66  
get_sizeCFF::CFF2FDSelect67    unsigned int get_size (unsigned int num_glyphs) const
68    {
69      switch (format)
70      {
71      case 0: return format.static_size + u.format0.get_size (num_glyphs);
72      case 3: return format.static_size + u.format3.get_size ();
73      case 4: return format.static_size + u.format4.get_size ();
74      default:return 0;
75      }
76    }
77  
get_fdCFF::CFF2FDSelect78    hb_codepoint_t get_fd (hb_codepoint_t glyph) const
79    {
80      if (this == &Null (CFF2FDSelect))
81        return 0;
82  
83      switch (format)
84      {
85      case 0: return u.format0.get_fd (glyph);
86      case 3: return u.format3.get_fd (glyph);
87      case 4: return u.format4.get_fd (glyph);
88      default:return 0;
89      }
90    }
91  
sanitizeCFF::CFF2FDSelect92    bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
93    {
94      TRACE_SANITIZE (this);
95      if (unlikely (!c->check_struct (this)))
96        return_trace (false);
97  
98      switch (format)
99      {
100      case 0: return_trace (u.format0.sanitize (c, fdcount));
101      case 3: return_trace (u.format3.sanitize (c, fdcount));
102      case 4: return_trace (u.format4.sanitize (c, fdcount));
103      default:return_trace (false);
104      }
105    }
106  
107    HBUINT8	format;
108    union {
109    FDSelect0	format0;
110    FDSelect3	format3;
111    FDSelect4	format4;
112    } u;
113    public:
114    DEFINE_SIZE_MIN (2);
115  };
116  
117  struct CFF2VariationStore
118  {
sanitizeCFF::CFF2VariationStore119    bool sanitize (hb_sanitize_context_t *c) const
120    {
121      TRACE_SANITIZE (this);
122      return_trace (likely (c->check_struct (this)) && c->check_range (&varStore, size) && varStore.sanitize (c));
123    }
124  
serializeCFF::CFF2VariationStore125    bool serialize (hb_serialize_context_t *c, const CFF2VariationStore *varStore)
126    {
127      TRACE_SERIALIZE (this);
128      unsigned int size_ = varStore->get_size ();
129      CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (size_);
130      if (unlikely (dest == nullptr)) return_trace (false);
131      memcpy (dest, varStore, size_);
132      return_trace (true);
133    }
134  
get_sizeCFF::CFF2VariationStore135    unsigned int get_size () const { return HBUINT16::static_size + size; }
136  
137    HBUINT16	size;
138    VariationStore  varStore;
139  
140    DEFINE_SIZE_MIN (2 + VariationStore::min_size);
141  };
142  
143  struct cff2_top_dict_values_t : top_dict_values_t<>
144  {
initCFF::cff2_top_dict_values_t145    void init ()
146    {
147      top_dict_values_t<>::init ();
148      vstoreOffset = 0;
149      FDSelectOffset = 0;
150    }
finiCFF::cff2_top_dict_values_t151    void fini () { top_dict_values_t<>::fini (); }
152  
calculate_serialized_sizeCFF::cff2_top_dict_values_t153    unsigned int calculate_serialized_size () const
154    {
155      unsigned int size = 0;
156      for (unsigned int i = 0; i < get_count (); i++)
157      {
158        op_code_t op = get_value (i).op;
159        switch (op)
160        {
161  	case OpCode_vstore:
162  	case OpCode_FDSelect:
163  	  size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op);
164  	  break;
165  	default:
166  	  size += top_dict_values_t<>::calculate_serialized_op_size (get_value (i));
167  	  break;
168        }
169      }
170      return size;
171    }
172  
173    unsigned int  vstoreOffset;
174    unsigned int  FDSelectOffset;
175  };
176  
177  struct cff2_top_dict_opset_t : top_dict_opset_t<>
178  {
process_opCFF::cff2_top_dict_opset_t179    static void process_op (op_code_t op, num_interp_env_t& env, cff2_top_dict_values_t& dictval)
180    {
181      switch (op) {
182        case OpCode_FontMatrix:
183  	{
184  	  dict_val_t val;
185  	  val.init ();
186  	  dictval.add_op (op, env.str_ref);
187  	  env.clear_args ();
188  	}
189  	break;
190  
191        case OpCode_vstore:
192  	dictval.vstoreOffset = env.argStack.pop_uint ();
193  	env.clear_args ();
194  	break;
195        case OpCode_FDSelect:
196  	dictval.FDSelectOffset = env.argStack.pop_uint ();
197  	env.clear_args ();
198  	break;
199  
200        default:
201  	SUPER::process_op (op, env, dictval);
202  	/* Record this operand below if stack is empty, otherwise done */
203  	if (!env.argStack.is_empty ()) return;
204      }
205  
206      if (unlikely (env.in_error ())) return;
207  
208      dictval.add_op (op, env.str_ref);
209    }
210  
211    typedef top_dict_opset_t<> SUPER;
212  };
213  
214  struct cff2_font_dict_values_t : dict_values_t<op_str_t>
215  {
initCFF::cff2_font_dict_values_t216    void init ()
217    {
218      dict_values_t<op_str_t>::init ();
219      privateDictInfo.init ();
220    }
finiCFF::cff2_font_dict_values_t221    void fini () { dict_values_t<op_str_t>::fini (); }
222  
223    table_info_t    privateDictInfo;
224  };
225  
226  struct cff2_font_dict_opset_t : dict_opset_t
227  {
process_opCFF::cff2_font_dict_opset_t228    static void process_op (op_code_t op, num_interp_env_t& env, cff2_font_dict_values_t& dictval)
229    {
230      switch (op) {
231        case OpCode_Private:
232  	dictval.privateDictInfo.offset = env.argStack.pop_uint ();
233  	dictval.privateDictInfo.size = env.argStack.pop_uint ();
234  	env.clear_args ();
235  	break;
236  
237        default:
238  	SUPER::process_op (op, env);
239  	if (!env.argStack.is_empty ())
240  	  return;
241      }
242  
243      if (unlikely (env.in_error ())) return;
244  
245      dictval.add_op (op, env.str_ref);
246    }
247  
248    private:
249    typedef dict_opset_t SUPER;
250  };
251  
252  template <typename VAL>
253  struct cff2_private_dict_values_base_t : dict_values_t<VAL>
254  {
initCFF::cff2_private_dict_values_base_t255    void init ()
256    {
257      dict_values_t<VAL>::init ();
258      subrsOffset = 0;
259      localSubrs = &Null(CFF2Subrs);
260      ivs = 0;
261    }
finiCFF::cff2_private_dict_values_base_t262    void fini () { dict_values_t<VAL>::fini (); }
263  
calculate_serialized_sizeCFF::cff2_private_dict_values_base_t264    unsigned int calculate_serialized_size () const
265    {
266      unsigned int size = 0;
267      for (unsigned int i = 0; i < dict_values_t<VAL>::get_count; i++)
268        if (dict_values_t<VAL>::get_value (i).op == OpCode_Subrs)
269  	size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
270        else
271  	size += dict_values_t<VAL>::get_value (i).str.length;
272      return size;
273    }
274  
275    unsigned int      subrsOffset;
276    const CFF2Subrs   *localSubrs;
277    unsigned int      ivs;
278  };
279  
280  typedef cff2_private_dict_values_base_t<op_str_t> cff2_private_dict_values_subset_t;
281  typedef cff2_private_dict_values_base_t<num_dict_val_t> cff2_private_dict_values_t;
282  
283  struct cff2_priv_dict_interp_env_t : num_interp_env_t
284  {
initCFF::cff2_priv_dict_interp_env_t285    void init (const byte_str_t &str)
286    {
287      num_interp_env_t::init (str);
288      ivs = 0;
289      seen_vsindex = false;
290    }
291  
process_vsindexCFF::cff2_priv_dict_interp_env_t292    void process_vsindex ()
293    {
294      if (likely (!seen_vsindex))
295      {
296        set_ivs (argStack.pop_uint ());
297      }
298      seen_vsindex = true;
299    }
300  
get_ivsCFF::cff2_priv_dict_interp_env_t301    unsigned int get_ivs () const { return ivs; }
set_ivsCFF::cff2_priv_dict_interp_env_t302    void	 set_ivs (unsigned int ivs_) { ivs = ivs_; }
303  
304    protected:
305    unsigned int  ivs;
306    bool	  seen_vsindex;
307  };
308  
309  struct cff2_private_dict_opset_t : dict_opset_t
310  {
process_opCFF::cff2_private_dict_opset_t311    static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_dict_values_t& dictval)
312    {
313      num_dict_val_t val;
314      val.init ();
315  
316      switch (op) {
317        case OpCode_StdHW:
318        case OpCode_StdVW:
319        case OpCode_BlueScale:
320        case OpCode_BlueShift:
321        case OpCode_BlueFuzz:
322        case OpCode_ExpansionFactor:
323        case OpCode_LanguageGroup:
324  	val.single_val = env.argStack.pop_num ();
325  	env.clear_args ();
326  	break;
327        case OpCode_BlueValues:
328        case OpCode_OtherBlues:
329        case OpCode_FamilyBlues:
330        case OpCode_FamilyOtherBlues:
331        case OpCode_StemSnapH:
332        case OpCode_StemSnapV:
333  	env.clear_args ();
334  	break;
335        case OpCode_Subrs:
336  	dictval.subrsOffset = env.argStack.pop_uint ();
337  	env.clear_args ();
338  	break;
339        case OpCode_vsindexdict:
340  	env.process_vsindex ();
341  	dictval.ivs = env.get_ivs ();
342  	env.clear_args ();
343  	break;
344        case OpCode_blenddict:
345  	break;
346  
347        default:
348  	dict_opset_t::process_op (op, env);
349  	if (!env.argStack.is_empty ()) return;
350  	break;
351      }
352  
353      if (unlikely (env.in_error ())) return;
354  
355      dictval.add_op (op, env.str_ref, val);
356    }
357  };
358  
359  struct cff2_private_dict_opset_subset_t : dict_opset_t
360  {
process_opCFF::cff2_private_dict_opset_subset_t361    static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_dict_values_subset_t& dictval)
362    {
363      switch (op) {
364        case OpCode_BlueValues:
365        case OpCode_OtherBlues:
366        case OpCode_FamilyBlues:
367        case OpCode_FamilyOtherBlues:
368        case OpCode_StdHW:
369        case OpCode_StdVW:
370        case OpCode_BlueScale:
371        case OpCode_BlueShift:
372        case OpCode_BlueFuzz:
373        case OpCode_StemSnapH:
374        case OpCode_StemSnapV:
375        case OpCode_LanguageGroup:
376        case OpCode_ExpansionFactor:
377  	env.clear_args ();
378  	break;
379  
380        case OpCode_blenddict:
381  	env.clear_args ();
382  	return;
383  
384        case OpCode_Subrs:
385  	dictval.subrsOffset = env.argStack.pop_uint ();
386  	env.clear_args ();
387  	break;
388  
389        default:
390  	SUPER::process_op (op, env);
391  	if (!env.argStack.is_empty ()) return;
392  	break;
393      }
394  
395      if (unlikely (env.in_error ())) return;
396  
397      dictval.add_op (op, env.str_ref);
398    }
399  
400    private:
401    typedef dict_opset_t SUPER;
402  };
403  
404  typedef dict_interpreter_t<cff2_top_dict_opset_t, cff2_top_dict_values_t> cff2_top_dict_interpreter_t;
405  typedef dict_interpreter_t<cff2_font_dict_opset_t, cff2_font_dict_values_t> cff2_font_dict_interpreter_t;
406  
407  } /* namespace CFF */
408  
409  namespace OT {
410  
411  using namespace CFF;
412  
413  struct cff2
414  {
415    static constexpr hb_tag_t tableTag = HB_OT_TAG_cff2;
416  
sanitizeOT::cff2417    bool sanitize (hb_sanitize_context_t *c) const
418    {
419      TRACE_SANITIZE (this);
420      return_trace (c->check_struct (this) &&
421  		  likely (version.major == 2));
422    }
423  
424    template <typename PRIVOPSET, typename PRIVDICTVAL>
425    struct accelerator_templ_t
426    {
initOT::cff2::accelerator_templ_t427      void init (hb_face_t *face)
428      {
429        topDict.init ();
430        fontDicts.init ();
431        privateDicts.init ();
432  
433        this->blob = sc.reference_table<cff2> (face);
434  
435        /* setup for run-time santization */
436        sc.init (this->blob);
437        sc.start_processing ();
438  
439        const OT::cff2 *cff2 = this->blob->template as<OT::cff2> ();
440  
441        if (cff2 == &Null(OT::cff2))
442        { fini (); return; }
443  
444        { /* parse top dict */
445  	byte_str_t topDictStr (cff2 + cff2->topDict, cff2->topDictSize);
446  	if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; }
447  	cff2_top_dict_interpreter_t top_interp;
448  	top_interp.env.init (topDictStr);
449  	topDict.init ();
450  	if (unlikely (!top_interp.interpret (topDict))) { fini (); return; }
451        }
452  
453        globalSubrs = &StructAtOffset<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize);
454        varStore = &StructAtOffsetOrNull<CFF2VariationStore> (cff2, topDict.vstoreOffset);
455        charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset);
456        fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset);
457        fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset);
458  
459        if (((varStore != &Null(CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
460  	  (charStrings == &Null(CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) ||
461  	  (globalSubrs == &Null(CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) ||
462  	  (fdArray == &Null(CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) ||
463  	  (((fdSelect != &Null(CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count)))))
464        { fini (); return; }
465  
466        num_glyphs = charStrings->count;
467        if (num_glyphs != sc.get_num_glyphs ())
468        { fini (); return; }
469  
470        fdCount = fdArray->count;
471        privateDicts.resize (fdCount);
472  
473        /* parse font dicts and gather private dicts */
474        for (unsigned int i = 0; i < fdCount; i++)
475        {
476  	const byte_str_t fontDictStr = (*fdArray)[i];
477  	if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
478  	cff2_font_dict_values_t  *font;
479  	cff2_font_dict_interpreter_t font_interp;
480  	font_interp.env.init (fontDictStr);
481  	font = fontDicts.push ();
482  	if (unlikely (font == &Crap(cff2_font_dict_values_t))) { fini (); return; }
483  	font->init ();
484  	if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
485  
486  	const byte_str_t privDictStr (StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size);
487  	if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
488  	dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t>  priv_interp;
489  	priv_interp.env.init(privDictStr);
490  	privateDicts[i].init ();
491  	if (unlikely (!priv_interp.interpret (privateDicts[i]))) { fini (); return; }
492  
493  	privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset);
494  	if (privateDicts[i].localSubrs != &Null(CFF2Subrs) &&
495  	  unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
496  	{ fini (); return; }
497        }
498      }
499  
finiOT::cff2::accelerator_templ_t500      void fini ()
501      {
502        sc.end_processing ();
503        topDict.fini ();
504        fontDicts.fini_deep ();
505        privateDicts.fini_deep ();
506        hb_blob_destroy (blob);
507        blob = nullptr;
508      }
509  
is_validOT::cff2::accelerator_templ_t510      bool is_valid () const { return blob != nullptr; }
511  
512      protected:
513      hb_blob_t			*blob;
514      hb_sanitize_context_t	sc;
515  
516      public:
517      cff2_top_dict_values_t	topDict;
518      const CFF2Subrs		*globalSubrs;
519      const CFF2VariationStore	*varStore;
520      const CFF2CharStrings	*charStrings;
521      const CFF2FDArray		*fdArray;
522      const CFF2FDSelect		*fdSelect;
523      unsigned int		fdCount;
524  
525      hb_vector_t<cff2_font_dict_values_t>     fontDicts;
526      hb_vector_t<PRIVDICTVAL>  privateDicts;
527  
528      unsigned int	      num_glyphs;
529    };
530  
531    struct accelerator_t : accelerator_templ_t<cff2_private_dict_opset_t, cff2_private_dict_values_t>
532    {
533      HB_INTERNAL bool get_extents (hb_font_t *font,
534  				  hb_codepoint_t glyph,
535  				  hb_glyph_extents_t *extents) const;
536    };
537  
538    typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t;
539  
subsetOT::cff2540    bool subset (hb_subset_plan_t *plan) const
541    {
542      hb_blob_t *cff2_prime = nullptr;
543  
544      bool success = true;
545      if (hb_subset_cff2 (plan, &cff2_prime)) {
546        success = success && plan->add_table (HB_OT_TAG_cff2, cff2_prime);
547        hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (plan->source);
548        success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob);
549        hb_blob_destroy (head_blob);
550      } else {
551        success = false;
552      }
553      hb_blob_destroy (cff2_prime);
554  
555      return success;
556    }
557  
558    public:
559    FixedVersion<HBUINT8>		version;	/* Version of CFF2 table. set to 0x0200u */
560    NNOffsetTo<TopDict, HBUINT8>	topDict;	/* headerSize = Offset to Top DICT. */
561    HBUINT16			topDictSize;	/* Top DICT size */
562  
563    public:
564    DEFINE_SIZE_STATIC (5);
565  };
566  
567  struct cff2_accelerator_t : cff2::accelerator_t {};
568  } /* namespace OT */
569  
570  #endif /* HB_OT_CFF2_TABLE_HH */
571