Home | History | Annotate | Download | only in src
      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 {
     54   bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
     55   {
     56     TRACE_SANITIZE (this);
     57 
     58     return_trace (likely (c->check_struct (this) && (format == 0 || format == 3 || format == 4) &&
     59 			  (format == 0)?
     60 			  u.format0.sanitize (c, fdcount):
     61 			    ((format == 3)?
     62 			    u.format3.sanitize (c, fdcount):
     63 			    u.format4.sanitize (c, fdcount))));
     64   }
     65 
     66   bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs)
     67   {
     68     TRACE_SERIALIZE (this);
     69     unsigned int size = src.get_size (num_glyphs);
     70     CFF2FDSelect *dest = c->allocate_size<CFF2FDSelect> (size);
     71     if (unlikely (dest == nullptr)) return_trace (false);
     72     memcpy (dest, &src, size);
     73     return_trace (true);
     74   }
     75 
     76   unsigned int calculate_serialized_size (unsigned int num_glyphs) const
     77   { return get_size (num_glyphs); }
     78 
     79   unsigned int get_size (unsigned int num_glyphs) const
     80   {
     81     unsigned int size = format.static_size;
     82     if (format == 0)
     83       size += u.format0.get_size (num_glyphs);
     84     else if (format == 3)
     85       size += u.format3.get_size ();
     86     else
     87       size += u.format4.get_size ();
     88     return size;
     89   }
     90 
     91   hb_codepoint_t get_fd (hb_codepoint_t glyph) const
     92   {
     93     if (this == &Null(CFF2FDSelect))
     94       return 0;
     95     if (format == 0)
     96       return u.format0.get_fd (glyph);
     97     else if (format == 3)
     98       return u.format3.get_fd (glyph);
     99     else
    100       return u.format4.get_fd (glyph);
    101   }
    102 
    103   HBUINT8       format;
    104   union {
    105     FDSelect0   format0;
    106     FDSelect3   format3;
    107     FDSelect4   format4;
    108   } u;
    109 
    110   DEFINE_SIZE_MIN (2);
    111 };
    112 
    113 struct CFF2VariationStore
    114 {
    115   bool sanitize (hb_sanitize_context_t *c) const
    116   {
    117     TRACE_SANITIZE (this);
    118     return_trace (likely (c->check_struct (this)) && c->check_range (&varStore, size) && varStore.sanitize (c));
    119   }
    120 
    121   bool serialize (hb_serialize_context_t *c, const CFF2VariationStore *varStore)
    122   {
    123     TRACE_SERIALIZE (this);
    124     unsigned int size_ = varStore->get_size ();
    125     CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (size_);
    126     if (unlikely (dest == nullptr)) return_trace (false);
    127     memcpy (dest, varStore, size_);
    128     return_trace (true);
    129   }
    130 
    131   unsigned int get_size () const { return HBUINT16::static_size + size; }
    132 
    133   HBUINT16	size;
    134   VariationStore  varStore;
    135 
    136   DEFINE_SIZE_MIN (2 + VariationStore::min_size);
    137 };
    138 
    139 struct CFF2TopDictValues : TopDictValues<>
    140 {
    141   void init ()
    142   {
    143     TopDictValues<>::init ();
    144     vstoreOffset = 0;
    145     FDSelectOffset = 0;
    146   }
    147   void fini () { TopDictValues<>::fini (); }
    148 
    149   unsigned int calculate_serialized_size () const
    150   {
    151     unsigned int size = 0;
    152     for (unsigned int i = 0; i < get_count (); i++)
    153     {
    154       OpCode op = get_value (i).op;
    155       switch (op)
    156       {
    157 	case OpCode_vstore:
    158 	case OpCode_FDSelect:
    159 	  size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op);
    160 	  break;
    161 	default:
    162 	  size += TopDictValues<>::calculate_serialized_op_size (get_value (i));
    163 	  break;
    164       }
    165     }
    166     return size;
    167   }
    168 
    169   unsigned int  vstoreOffset;
    170   unsigned int  FDSelectOffset;
    171 };
    172 
    173 struct CFF2TopDictOpSet : TopDictOpSet<>
    174 {
    175   static void process_op (OpCode op, NumInterpEnv& env, CFF2TopDictValues& dictval)
    176   {
    177     switch (op) {
    178       case OpCode_FontMatrix:
    179 	{
    180 	  DictVal val;
    181 	  val.init ();
    182 	  dictval.add_op (op, env.substr);
    183 	  env.clear_args ();
    184 	}
    185 	break;
    186 
    187       case OpCode_vstore:
    188 	dictval.vstoreOffset = env.argStack.pop_uint ();
    189 	env.clear_args ();
    190 	break;
    191       case OpCode_FDSelect:
    192 	dictval.FDSelectOffset = env.argStack.pop_uint ();
    193 	env.clear_args ();
    194 	break;
    195 
    196       default:
    197 	SUPER::process_op (op, env, dictval);
    198 	/* Record this operand below if stack is empty, otherwise done */
    199 	if (!env.argStack.is_empty ()) return;
    200     }
    201 
    202     if (unlikely (env.in_error ())) return;
    203 
    204     dictval.add_op (op, env.substr);
    205   }
    206 
    207   typedef TopDictOpSet<> SUPER;
    208 };
    209 
    210 struct CFF2FontDictValues : DictValues<OpStr>
    211 {
    212   void init ()
    213   {
    214     DictValues<OpStr>::init ();
    215     privateDictInfo.init ();
    216   }
    217   void fini () { DictValues<OpStr>::fini (); }
    218 
    219   TableInfo    privateDictInfo;
    220 };
    221 
    222 struct CFF2FontDictOpSet : DictOpSet
    223 {
    224   static void process_op (OpCode op, NumInterpEnv& env, CFF2FontDictValues& dictval)
    225   {
    226     switch (op) {
    227       case OpCode_Private:
    228 	dictval.privateDictInfo.offset = env.argStack.pop_uint ();
    229 	dictval.privateDictInfo.size = env.argStack.pop_uint ();
    230 	env.clear_args ();
    231 	break;
    232 
    233       default:
    234 	SUPER::process_op (op, env);
    235 	if (!env.argStack.is_empty ())
    236 	  return;
    237     }
    238 
    239     if (unlikely (env.in_error ())) return;
    240 
    241     dictval.add_op (op, env.substr);
    242   }
    243 
    244   private:
    245   typedef DictOpSet SUPER;
    246 };
    247 
    248 template <typename VAL>
    249 struct CFF2PrivateDictValues_Base : DictValues<VAL>
    250 {
    251   void init ()
    252   {
    253     DictValues<VAL>::init ();
    254     subrsOffset = 0;
    255     localSubrs = &Null(CFF2Subrs);
    256     ivs = 0;
    257   }
    258   void fini () { DictValues<VAL>::fini (); }
    259 
    260   unsigned int calculate_serialized_size () const
    261   {
    262     unsigned int size = 0;
    263     for (unsigned int i = 0; i < DictValues<VAL>::get_count; i++)
    264       if (DictValues<VAL>::get_value (i).op == OpCode_Subrs)
    265 	size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
    266       else
    267 	size += DictValues<VAL>::get_value (i).str.len;
    268     return size;
    269   }
    270 
    271   unsigned int      subrsOffset;
    272   const CFF2Subrs   *localSubrs;
    273   unsigned int      ivs;
    274 };
    275 
    276 typedef CFF2PrivateDictValues_Base<OpStr> CFF2PrivateDictValues_Subset;
    277 typedef CFF2PrivateDictValues_Base<NumDictVal> CFF2PrivateDictValues;
    278 
    279 struct CFF2PrivDictInterpEnv : NumInterpEnv
    280 {
    281   void init (const ByteStr &str)
    282   {
    283     NumInterpEnv::init (str);
    284     ivs = 0;
    285     seen_vsindex = false;
    286   }
    287 
    288   void process_vsindex ()
    289   {
    290     if (likely (!seen_vsindex))
    291     {
    292       set_ivs (argStack.pop_uint ());
    293     }
    294     seen_vsindex = true;
    295   }
    296 
    297   unsigned int get_ivs () const { return ivs; }
    298   void	 set_ivs (unsigned int ivs_) { ivs = ivs_; }
    299 
    300   protected:
    301   unsigned int  ivs;
    302   bool	  seen_vsindex;
    303 };
    304 
    305 struct CFF2PrivateDictOpSet : DictOpSet
    306 {
    307   static void process_op (OpCode op, CFF2PrivDictInterpEnv& env, CFF2PrivateDictValues& dictval)
    308   {
    309     NumDictVal val;
    310     val.init ();
    311 
    312     switch (op) {
    313       case OpCode_StdHW:
    314       case OpCode_StdVW:
    315       case OpCode_BlueScale:
    316       case OpCode_BlueShift:
    317       case OpCode_BlueFuzz:
    318       case OpCode_ExpansionFactor:
    319       case OpCode_LanguageGroup:
    320 	val.single_val = env.argStack.pop_num ();
    321 	env.clear_args ();
    322 	break;
    323       case OpCode_BlueValues:
    324       case OpCode_OtherBlues:
    325       case OpCode_FamilyBlues:
    326       case OpCode_FamilyOtherBlues:
    327       case OpCode_StemSnapH:
    328       case OpCode_StemSnapV:
    329 	env.clear_args ();
    330 	break;
    331       case OpCode_Subrs:
    332 	dictval.subrsOffset = env.argStack.pop_uint ();
    333 	env.clear_args ();
    334 	break;
    335       case OpCode_vsindexdict:
    336 	env.process_vsindex ();
    337 	dictval.ivs = env.get_ivs ();
    338 	env.clear_args ();
    339 	break;
    340       case OpCode_blenddict:
    341 	break;
    342 
    343       default:
    344 	DictOpSet::process_op (op, env);
    345 	if (!env.argStack.is_empty ()) return;
    346 	break;
    347     }
    348 
    349     if (unlikely (env.in_error ())) return;
    350 
    351     dictval.add_op (op, env.substr, val);
    352   }
    353 };
    354 
    355 struct CFF2PrivateDictOpSet_Subset : DictOpSet
    356 {
    357   static void process_op (OpCode op, CFF2PrivDictInterpEnv& env, CFF2PrivateDictValues_Subset& dictval)
    358   {
    359     switch (op) {
    360       case OpCode_BlueValues:
    361       case OpCode_OtherBlues:
    362       case OpCode_FamilyBlues:
    363       case OpCode_FamilyOtherBlues:
    364       case OpCode_StdHW:
    365       case OpCode_StdVW:
    366       case OpCode_BlueScale:
    367       case OpCode_BlueShift:
    368       case OpCode_BlueFuzz:
    369       case OpCode_StemSnapH:
    370       case OpCode_StemSnapV:
    371       case OpCode_LanguageGroup:
    372       case OpCode_ExpansionFactor:
    373 	env.clear_args ();
    374 	break;
    375 
    376       case OpCode_blenddict:
    377 	env.clear_args ();
    378 	return;
    379 
    380       case OpCode_Subrs:
    381 	dictval.subrsOffset = env.argStack.pop_uint ();
    382 	env.clear_args ();
    383 	break;
    384 
    385       default:
    386 	SUPER::process_op (op, env);
    387 	if (!env.argStack.is_empty ()) return;
    388 	break;
    389     }
    390 
    391     if (unlikely (env.in_error ())) return;
    392 
    393     dictval.add_op (op, env.substr);
    394   }
    395 
    396   private:
    397   typedef DictOpSet SUPER;
    398 };
    399 
    400 typedef DictInterpreter<CFF2TopDictOpSet, CFF2TopDictValues> CFF2TopDict_Interpreter;
    401 typedef DictInterpreter<CFF2FontDictOpSet, CFF2FontDictValues> CFF2FontDict_Interpreter;
    402 
    403 }; /* namespace CFF */
    404 
    405 namespace OT {
    406 
    407 using namespace CFF;
    408 
    409 struct cff2
    410 {
    411   static const hb_tag_t tableTag	= HB_OT_TAG_cff2;
    412 
    413   bool sanitize (hb_sanitize_context_t *c) const
    414   {
    415     TRACE_SANITIZE (this);
    416     return_trace (c->check_struct (this) &&
    417 		  likely (version.major == 2));
    418   }
    419 
    420   template <typename PRIVOPSET, typename PRIVDICTVAL>
    421   struct accelerator_templ_t
    422   {
    423     void init (hb_face_t *face)
    424     {
    425       topDict.init ();
    426       fontDicts.init ();
    427       privateDicts.init ();
    428 
    429       this->blob = sc.reference_table<cff2> (face);
    430 
    431       /* setup for run-time santization */
    432       sc.init (this->blob);
    433       sc.start_processing ();
    434 
    435       const OT::cff2 *cff2 = this->blob->template as<OT::cff2> ();
    436 
    437       if (cff2 == &Null(OT::cff2))
    438       { fini (); return; }
    439 
    440       { /* parse top dict */
    441 	ByteStr topDictStr (cff2 + cff2->topDict, cff2->topDictSize);
    442 	if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; }
    443 	CFF2TopDict_Interpreter top_interp;
    444 	top_interp.env.init (topDictStr);
    445 	topDict.init ();
    446 	if (unlikely (!top_interp.interpret (topDict))) { fini (); return; }
    447       }
    448 
    449       globalSubrs = &StructAtOffset<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize);
    450       varStore = &StructAtOffsetOrNull<CFF2VariationStore> (cff2, topDict.vstoreOffset);
    451       charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset);
    452       fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset);
    453       fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset);
    454 
    455       if (((varStore != &Null(CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
    456 	  (charStrings == &Null(CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) ||
    457 	  (globalSubrs == &Null(CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) ||
    458 	  (fdArray == &Null(CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) ||
    459 	  (((fdSelect != &Null(CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count)))))
    460       { fini (); return; }
    461 
    462       num_glyphs = charStrings->count;
    463       if (num_glyphs != sc.get_num_glyphs ())
    464       { fini (); return; }
    465 
    466       fdCount = fdArray->count;
    467       privateDicts.resize (fdCount);
    468 
    469       /* parse font dicts and gather private dicts */
    470       for (unsigned int i = 0; i < fdCount; i++)
    471       {
    472 	const ByteStr fontDictStr = (*fdArray)[i];
    473 	if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
    474 	CFF2FontDictValues  *font;
    475 	CFF2FontDict_Interpreter font_interp;
    476 	font_interp.env.init (fontDictStr);
    477 	font = fontDicts.push ();
    478 	if (unlikely (font == &Crap(CFF2FontDictValues))) { fini (); return; }
    479 	font->init ();
    480 	if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
    481 
    482 	const ByteStr privDictStr (StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size);
    483 	if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
    484 	DictInterpreter<PRIVOPSET, PRIVDICTVAL, CFF2PrivDictInterpEnv>  priv_interp;
    485 	priv_interp.env.init(privDictStr);
    486 	privateDicts[i].init ();
    487 	if (unlikely (!priv_interp.interpret (privateDicts[i]))) { fini (); return; }
    488 
    489 	privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (privDictStr.str, privateDicts[i].subrsOffset);
    490 	if (privateDicts[i].localSubrs != &Null(CFF2Subrs) &&
    491 	  unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
    492 	{ fini (); return; }
    493       }
    494     }
    495 
    496     void fini ()
    497     {
    498       sc.end_processing ();
    499       fontDicts.fini_deep ();
    500       privateDicts.fini_deep ();
    501       hb_blob_destroy (blob);
    502       blob = nullptr;
    503     }
    504 
    505     bool is_valid () const { return blob != nullptr; }
    506 
    507     protected:
    508     hb_blob_t	       *blob;
    509     hb_sanitize_context_t   sc;
    510 
    511     public:
    512     CFF2TopDictValues	 topDict;
    513     const CFF2Subrs	   *globalSubrs;
    514     const CFF2VariationStore  *varStore;
    515     const CFF2CharStrings     *charStrings;
    516     const CFF2FDArray	 *fdArray;
    517     const CFF2FDSelect	*fdSelect;
    518     unsigned int	      fdCount;
    519 
    520     hb_vector_t<CFF2FontDictValues>     fontDicts;
    521     hb_vector_t<PRIVDICTVAL>  privateDicts;
    522 
    523     unsigned int	    num_glyphs;
    524   };
    525 
    526   struct accelerator_t : accelerator_templ_t<CFF2PrivateDictOpSet, CFF2PrivateDictValues>
    527   {
    528     HB_INTERNAL bool get_extents (hb_font_t *font,
    529 				  hb_codepoint_t glyph,
    530 				  hb_glyph_extents_t *extents) const;
    531   };
    532 
    533   typedef accelerator_templ_t<CFF2PrivateDictOpSet_Subset, CFF2PrivateDictValues_Subset> accelerator_subset_t;
    534 
    535   bool subset (hb_subset_plan_t *plan) const
    536   {
    537     hb_blob_t *cff2_prime = nullptr;
    538 
    539     bool success = true;
    540     if (hb_subset_cff2 (plan, &cff2_prime)) {
    541       success = success && plan->add_table (HB_OT_TAG_cff2, cff2_prime);
    542       hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (plan->source);
    543       success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob);
    544       hb_blob_destroy (head_blob);
    545     } else {
    546       success = false;
    547     }
    548     hb_blob_destroy (cff2_prime);
    549 
    550     return success;
    551   }
    552 
    553   public:
    554   FixedVersion<HBUINT8> version;	/* Version of CFF2 table. set to 0x0200u */
    555   OffsetTo<TopDict, HBUINT8, false> topDict;   /* headerSize = Offset to Top DICT. */
    556   HBUINT16       topDictSize;	   /* Top DICT size */
    557 
    558   public:
    559   DEFINE_SIZE_STATIC (5);
    560 };
    561 
    562 struct cff2_accelerator_t : cff2::accelerator_t {};
    563 } /* namespace OT */
    564 
    565 #endif /* HB_OT_CFF2_TABLE_HH */
    566