tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

hb-ot-cff2-table.hh (16242B)


      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-cff-common.hh"
     31 #include "hb-subset-cff-common.hh"
     32 #include "hb-draw.hh"
     33 #include "hb-paint.hh"
     34 
     35 namespace CFF {
     36 
     37 /*
     38 * CFF2 -- Compact Font Format (CFF) Version 2
     39 * https://docs.microsoft.com/en-us/typography/opentype/spec/cff2
     40 */
     41 #define HB_OT_TAG_CFF2 HB_TAG('C','F','F','2')
     42 
     43 typedef CFF2Index         CFF2CharStrings;
     44 typedef Subrs<HBUINT32>   CFF2Subrs;
     45 
     46 typedef FDSelect3_4<HBUINT32, HBUINT16> FDSelect4;
     47 typedef FDSelect3_4_Range<HBUINT32, HBUINT16> FDSelect4_Range;
     48 
     49 struct CFF2FDSelect
     50 {
     51  bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs)
     52  {
     53    TRACE_SERIALIZE (this);
     54    unsigned int size = src.get_size (num_glyphs);
     55    CFF2FDSelect *dest = c->allocate_size<CFF2FDSelect> (size);
     56    if (unlikely (!dest)) return_trace (false);
     57    hb_memcpy (dest, &src, size);
     58    return_trace (true);
     59  }
     60 
     61  unsigned int get_size (unsigned int num_glyphs) const
     62  {
     63    switch (format)
     64    {
     65    case 0: hb_barrier (); return format.static_size + u.format0.get_size (num_glyphs);
     66    case 3: hb_barrier (); return format.static_size + u.format3.get_size ();
     67    case 4: hb_barrier (); return format.static_size + u.format4.get_size ();
     68    default:return 0;
     69    }
     70  }
     71 
     72  hb_codepoint_t get_fd (hb_codepoint_t glyph) const
     73  {
     74    if (this == &Null (CFF2FDSelect))
     75      return 0;
     76 
     77    switch (format)
     78    {
     79    case 0: hb_barrier (); return u.format0.get_fd (glyph);
     80    case 3: hb_barrier (); return u.format3.get_fd (glyph);
     81    case 4: hb_barrier (); return u.format4.get_fd (glyph);
     82    default:return 0;
     83    }
     84  }
     85 
     86  bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
     87  {
     88    TRACE_SANITIZE (this);
     89    if (unlikely (!c->check_struct (this)))
     90      return_trace (false);
     91    hb_barrier ();
     92 
     93    switch (format)
     94    {
     95    case 0: hb_barrier (); return_trace (u.format0.sanitize (c, fdcount));
     96    case 3: hb_barrier (); return_trace (u.format3.sanitize (c, fdcount));
     97    case 4: hb_barrier (); return_trace (u.format4.sanitize (c, fdcount));
     98    default:return_trace (false);
     99    }
    100  }
    101 
    102  HBUINT8	format;
    103  union {
    104  FDSelect0	format0;
    105  FDSelect3	format3;
    106  FDSelect4	format4;
    107  } u;
    108  public:
    109  DEFINE_SIZE_MIN (2);
    110 };
    111 
    112 struct CFF2ItemVariationStore
    113 {
    114  bool sanitize (hb_sanitize_context_t *c) const
    115  {
    116    TRACE_SANITIZE (this);
    117    return_trace (c->check_struct (this) &&
    118 	  hb_barrier () &&
    119 	  c->check_range (&varStore, size) &&
    120 	  varStore.sanitize (c));
    121  }
    122 
    123  bool serialize (hb_serialize_context_t *c, const CFF2ItemVariationStore *varStore)
    124  {
    125    TRACE_SERIALIZE (this);
    126    unsigned int size_ = varStore->get_size ();
    127    CFF2ItemVariationStore *dest = c->allocate_size<CFF2ItemVariationStore> (size_);
    128    if (unlikely (!dest)) return_trace (false);
    129    hb_memcpy (dest, varStore, size_);
    130    return_trace (true);
    131  }
    132 
    133  unsigned int get_size () const { return HBUINT16::static_size + size; }
    134 
    135  HBUINT16	size;
    136  ItemVariationStore  varStore;
    137 
    138  DEFINE_SIZE_MIN (2 + ItemVariationStore::min_size);
    139 };
    140 
    141 struct cff2_top_dict_values_t : top_dict_values_t<>
    142 {
    143  void init ()
    144  {
    145    top_dict_values_t<>::init ();
    146    vstoreOffset = 0;
    147    FDSelectOffset = 0;
    148  }
    149  void fini () { top_dict_values_t<>::fini (); }
    150 
    151  int  vstoreOffset;
    152  int  FDSelectOffset;
    153 };
    154 
    155 struct cff2_top_dict_opset_t : top_dict_opset_t<>
    156 {
    157  static void process_op (op_code_t op, num_interp_env_t& env, cff2_top_dict_values_t& dictval)
    158  {
    159    switch (op) {
    160      case OpCode_FontMatrix:
    161 {
    162   dict_val_t val;
    163   val.init ();
    164   dictval.add_op (op, env.str_ref);
    165   env.clear_args ();
    166 }
    167 break;
    168 
    169      case OpCode_vstore:
    170 dictval.vstoreOffset = env.argStack.pop_int ();
    171 env.clear_args ();
    172 break;
    173      case OpCode_FDSelect:
    174 dictval.FDSelectOffset = env.argStack.pop_int ();
    175 env.clear_args ();
    176 break;
    177 
    178      default:
    179 SUPER::process_op (op, env, dictval);
    180 /* Record this operand below if stack is empty, otherwise done */
    181 if (!env.argStack.is_empty ()) return;
    182    }
    183 
    184    if (unlikely (env.in_error ())) return;
    185 
    186    dictval.add_op (op, env.str_ref);
    187  }
    188 
    189  typedef top_dict_opset_t<> SUPER;
    190 };
    191 
    192 struct cff2_font_dict_values_t : dict_values_t<op_str_t>
    193 {
    194  void init ()
    195  {
    196    dict_values_t<op_str_t>::init ();
    197    privateDictInfo.init ();
    198  }
    199  void fini () { dict_values_t<op_str_t>::fini (); }
    200 
    201  table_info_t    privateDictInfo;
    202 };
    203 
    204 struct cff2_font_dict_opset_t : dict_opset_t
    205 {
    206  static void process_op (op_code_t op, num_interp_env_t& env, cff2_font_dict_values_t& dictval)
    207  {
    208    switch (op) {
    209      case OpCode_Private:
    210 dictval.privateDictInfo.offset = env.argStack.pop_uint ();
    211 dictval.privateDictInfo.size = env.argStack.pop_uint ();
    212 env.clear_args ();
    213 break;
    214 
    215      default:
    216 SUPER::process_op (op, env);
    217 if (!env.argStack.is_empty ())
    218   return;
    219    }
    220 
    221    if (unlikely (env.in_error ())) return;
    222 
    223    dictval.add_op (op, env.str_ref);
    224  }
    225 
    226  private:
    227  typedef dict_opset_t SUPER;
    228 };
    229 
    230 template <typename VAL>
    231 struct cff2_private_dict_values_base_t : dict_values_t<VAL>
    232 {
    233  void init ()
    234  {
    235    dict_values_t<VAL>::init ();
    236    subrsOffset = 0;
    237    localSubrs = &Null (CFF2Subrs);
    238    ivs = 0;
    239  }
    240  void fini () { dict_values_t<VAL>::fini (); }
    241 
    242  int                subrsOffset;
    243  const CFF2Subrs   *localSubrs;
    244  unsigned int      ivs;
    245 };
    246 
    247 typedef cff2_private_dict_values_base_t<op_str_t> cff2_private_dict_values_subset_t;
    248 typedef cff2_private_dict_values_base_t<num_dict_val_t> cff2_private_dict_values_t;
    249 
    250 struct cff2_priv_dict_interp_env_t : num_interp_env_t
    251 {
    252  cff2_priv_dict_interp_env_t (const hb_ubytes_t &str) :
    253    num_interp_env_t (str) {}
    254 
    255  void process_vsindex ()
    256  {
    257    if (likely (!seen_vsindex))
    258    {
    259      set_ivs (argStack.pop_uint ());
    260    }
    261    seen_vsindex = true;
    262  }
    263 
    264  unsigned int get_ivs () const { return ivs; }
    265  void	 set_ivs (unsigned int ivs_) { ivs = ivs_; }
    266 
    267  protected:
    268  unsigned int  ivs = 0;
    269  bool	  seen_vsindex = false;
    270 };
    271 
    272 struct cff2_private_dict_opset_t : dict_opset_t
    273 {
    274  static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_dict_values_t& dictval)
    275  {
    276    num_dict_val_t val;
    277    val.init ();
    278 
    279    switch (op) {
    280      case OpCode_StdHW:
    281      case OpCode_StdVW:
    282      case OpCode_BlueScale:
    283      case OpCode_BlueShift:
    284      case OpCode_BlueFuzz:
    285      case OpCode_ExpansionFactor:
    286      case OpCode_LanguageGroup:
    287      case OpCode_BlueValues:
    288      case OpCode_OtherBlues:
    289      case OpCode_FamilyBlues:
    290      case OpCode_FamilyOtherBlues:
    291      case OpCode_StemSnapH:
    292      case OpCode_StemSnapV:
    293 env.clear_args ();
    294 break;
    295      case OpCode_Subrs:
    296 dictval.subrsOffset = env.argStack.pop_int ();
    297 env.clear_args ();
    298 break;
    299      case OpCode_vsindexdict:
    300 env.process_vsindex ();
    301 dictval.ivs = env.get_ivs ();
    302 env.clear_args ();
    303 break;
    304      case OpCode_blenddict:
    305 break;
    306 
    307      default:
    308 dict_opset_t::process_op (op, env);
    309 if (!env.argStack.is_empty ()) return;
    310 break;
    311    }
    312 
    313    if (unlikely (env.in_error ())) return;
    314 
    315    dictval.add_op (op, env.str_ref, val);
    316  }
    317 };
    318 
    319 struct cff2_private_dict_opset_subset_t : dict_opset_t
    320 {
    321  static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_dict_values_subset_t& dictval)
    322  {
    323    switch (op) {
    324      case OpCode_BlueValues:
    325      case OpCode_OtherBlues:
    326      case OpCode_FamilyBlues:
    327      case OpCode_FamilyOtherBlues:
    328      case OpCode_StdHW:
    329      case OpCode_StdVW:
    330      case OpCode_BlueScale:
    331      case OpCode_BlueShift:
    332      case OpCode_BlueFuzz:
    333      case OpCode_StemSnapH:
    334      case OpCode_StemSnapV:
    335      case OpCode_LanguageGroup:
    336      case OpCode_ExpansionFactor:
    337 env.clear_args ();
    338 break;
    339 
    340      case OpCode_blenddict:
    341 env.clear_args ();
    342 return;
    343 
    344      case OpCode_Subrs:
    345 dictval.subrsOffset = env.argStack.pop_int ();
    346 env.clear_args ();
    347 break;
    348 
    349      default:
    350 SUPER::process_op (op, env);
    351 if (!env.argStack.is_empty ()) return;
    352 break;
    353    }
    354 
    355    if (unlikely (env.in_error ())) return;
    356 
    357    dictval.add_op (op, env.str_ref);
    358  }
    359 
    360  private:
    361  typedef dict_opset_t SUPER;
    362 };
    363 
    364 typedef dict_interpreter_t<cff2_top_dict_opset_t, cff2_top_dict_values_t> cff2_top_dict_interpreter_t;
    365 typedef dict_interpreter_t<cff2_font_dict_opset_t, cff2_font_dict_values_t> cff2_font_dict_interpreter_t;
    366 
    367 struct CFF2FDArray : FDArray<HBUINT32>
    368 {
    369  /* FDArray::serialize does not compile without this partial specialization */
    370  template <typename ITER, typename OP_SERIALIZER>
    371  bool serialize (hb_serialize_context_t *c, ITER it, OP_SERIALIZER& opszr)
    372  { return FDArray<HBUINT32>::serialize<cff2_font_dict_values_t, table_info_t> (c, it, opszr); }
    373 };
    374 
    375 } /* namespace CFF */
    376 
    377 namespace OT {
    378 
    379 using namespace CFF;
    380 
    381 struct cff2
    382 {
    383  static constexpr hb_tag_t tableTag = HB_OT_TAG_CFF2;
    384 
    385  bool sanitize (hb_sanitize_context_t *c) const
    386  {
    387    TRACE_SANITIZE (this);
    388    return_trace (c->check_struct (this) &&
    389 	  hb_barrier () &&
    390 	  likely (version.major == 2));
    391  }
    392 
    393  template <typename PRIVOPSET, typename PRIVDICTVAL>
    394  struct accelerator_templ_t
    395  {
    396    static constexpr hb_tag_t tableTag = cff2::tableTag;
    397 
    398    accelerator_templ_t (hb_face_t *face)
    399    {
    400      if (!face) return;
    401 
    402      topDict.init ();
    403      fontDicts.init ();
    404      privateDicts.init ();
    405 
    406      this->blob = sc.reference_table<cff2> (face);
    407 
    408      /* setup for run-time sanitization */
    409      sc.init (this->blob);
    410      sc.start_processing ();
    411 
    412      const OT::cff2 *cff2 = this->blob->template as<OT::cff2> ();
    413 
    414      if (cff2 == &Null (OT::cff2))
    415        goto fail;
    416 
    417      { /* parse top dict */
    418 hb_ubytes_t topDictStr = (cff2 + cff2->topDict).as_ubytes (cff2->topDictSize);
    419 if (unlikely (!topDictStr.sanitize (&sc))) goto fail;
    420 hb_barrier ();
    421 num_interp_env_t env (topDictStr);
    422 cff2_top_dict_interpreter_t top_interp (env);
    423 topDict.init ();
    424 if (unlikely (!top_interp.interpret (topDict))) goto fail;
    425      }
    426 
    427      globalSubrs = &StructAtOffsetOrNull<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize, sc);
    428      varStore = &StructAtOffsetOrNull<CFF2ItemVariationStore> (cff2, topDict.vstoreOffset, sc);
    429      charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset, sc);
    430      fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset, sc);
    431      fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset, sc, fdArray->count);
    432 
    433      if (charStrings == &Null (CFF2CharStrings) ||
    434   globalSubrs == &Null (CFF2Subrs) ||
    435   fdArray == &Null (CFF2FDArray))
    436        goto fail;
    437 
    438      num_glyphs = charStrings->count;
    439      if (num_glyphs != sc.get_num_glyphs ())
    440        goto fail;
    441 
    442      fdCount = fdArray->count;
    443      if (!privateDicts.resize (fdCount))
    444        goto fail;
    445 
    446      /* parse font dicts and gather private dicts */
    447      for (unsigned int i = 0; i < fdCount; i++)
    448      {
    449 const hb_ubytes_t fontDictStr = (*fdArray)[i];
    450 if (unlikely (!fontDictStr.sanitize (&sc))) goto fail;
    451 hb_barrier ();
    452 cff2_font_dict_values_t  *font;
    453 num_interp_env_t env (fontDictStr);
    454 cff2_font_dict_interpreter_t font_interp (env);
    455 font = fontDicts.push ();
    456 if (unlikely (font == &Crap (cff2_font_dict_values_t))) goto fail;
    457 font->init ();
    458 if (unlikely (!font_interp.interpret (*font))) goto fail;
    459 
    460 const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
    461 if (unlikely (font->privateDictInfo.size &&
    462 	      privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail;
    463 cff2_priv_dict_interp_env_t env2 (privDictStr);
    464 dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2);
    465 privateDicts[i].init ();
    466 if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail;
    467 
    468 privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset, sc);
    469      }
    470 
    471      return;
    472 
    473      fail:
    474        _fini ();
    475    }
    476    ~accelerator_templ_t () { _fini (); }
    477    void _fini ()
    478    {
    479      sc.end_processing ();
    480      topDict.fini ();
    481      fontDicts.fini ();
    482      privateDicts.fini ();
    483      hb_blob_destroy (blob);
    484      blob = nullptr;
    485 
    486      auto *scalars = cached_scalars_vector.get_acquire ();
    487      if (scalars && cached_scalars_vector.cmpexch (scalars, nullptr))
    488      {
    489 scalars->fini ();
    490 hb_free (scalars);
    491      }
    492    }
    493 
    494    hb_vector_t<uint16_t> *create_glyph_to_sid_map () const
    495    {
    496      return nullptr;
    497    }
    498 
    499    hb_blob_t *get_blob () const { return blob; }
    500 
    501    bool is_valid () const { return blob; }
    502 
    503    protected:
    504    hb_sanitize_context_t	sc;
    505 
    506    public:
    507    hb_blob_t			*blob = nullptr;
    508    cff2_top_dict_values_t	topDict;
    509    const CFF2Subrs		*globalSubrs = nullptr;
    510    const CFF2ItemVariationStore	*varStore = nullptr;
    511    const CFF2CharStrings	*charStrings = nullptr;
    512    const CFF2FDArray		*fdArray = nullptr;
    513    const CFF2FDSelect		*fdSelect = nullptr;
    514    unsigned int		fdCount = 0;
    515 
    516    hb_vector_t<cff2_font_dict_values_t>     fontDicts;
    517    hb_vector_t<PRIVDICTVAL>  privateDicts;
    518 
    519    mutable hb_atomic_t<hb_vector_t<float> *> cached_scalars_vector;
    520 
    521    unsigned int	      num_glyphs = 0;
    522  };
    523 
    524  struct accelerator_t : accelerator_templ_t<cff2_private_dict_opset_t, cff2_private_dict_values_t>
    525  {
    526    accelerator_t (hb_face_t *face) : accelerator_templ_t (face) {}
    527 
    528    HB_INTERNAL bool get_extents (hb_font_t *font,
    529 			  hb_codepoint_t glyph,
    530 			  hb_glyph_extents_t *extents) const;
    531    HB_INTERNAL bool get_extents_at (hb_font_t *font,
    532 			     hb_codepoint_t glyph,
    533 			     hb_glyph_extents_t *extents,
    534 			     hb_array_t<const int> coords) const;
    535    HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
    536    HB_INTERNAL bool get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t<const int> coords) const;
    537  };
    538 
    539  struct accelerator_subset_t : accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t>
    540  {
    541    accelerator_subset_t (hb_face_t *face) : SUPER (face) {}
    542    ~accelerator_subset_t ()
    543    {
    544      if (cff_accelerator)
    545 cff_subset_accelerator_t::destroy (cff_accelerator);
    546    }
    547 
    548    HB_INTERNAL bool subset (hb_subset_context_t *c) const;
    549    HB_INTERNAL bool serialize (hb_serialize_context_t *c,
    550 			struct cff2_subset_plan &plan,
    551 			hb_array_t<int> normalized_coords) const;
    552 
    553    mutable CFF::cff_subset_accelerator_t* cff_accelerator = nullptr;
    554 
    555    typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> SUPER;
    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  cff2_accelerator_t (hb_face_t *face) : cff2::accelerator_t (face) {}
    569 };
    570 
    571 struct cff2_subset_accelerator_t : cff2::accelerator_subset_t {
    572  cff2_subset_accelerator_t (hb_face_t *face) : cff2::accelerator_subset_t (face) {}
    573 };
    574 
    575 } /* namespace OT */
    576 
    577 #endif /* HB_OT_CFF2_TABLE_HH */