tor-browser

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

hb-cff2-interp-cs.hh (8655B)


      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 #ifndef HB_CFF2_INTERP_CS_HH
     27 #define HB_CFF2_INTERP_CS_HH
     28 
     29 #include "hb.hh"
     30 #include "hb-cff-interp-cs-common.hh"
     31 
     32 namespace CFF {
     33 
     34 using namespace OT;
     35 
     36 struct blend_arg_t : number_t
     37 {
     38  void set_int (int v) { reset_blends (); number_t::set_int (v); }
     39  void set_fixed (int32_t v) { reset_blends (); number_t::set_fixed (v); }
     40  void set_real (double v) { reset_blends (); number_t::set_real (v); }
     41 
     42  void set_blends (unsigned int numValues_, unsigned int valueIndex_,
     43 	   hb_array_t<const blend_arg_t> blends_)
     44  {
     45    numValues = numValues_;
     46    valueIndex = valueIndex_;
     47    unsigned numBlends = blends_.length;
     48    if (unlikely (!deltas.resize_exact (numBlends)))
     49      return;
     50    for (unsigned int i = 0; i < numBlends; i++)
     51      deltas.arrayZ[i] = blends_.arrayZ[i];
     52  }
     53 
     54  bool blending () const { return deltas.length > 0; }
     55  void reset_blends ()
     56  {
     57    numValues = valueIndex = 0;
     58    deltas.shrink (0);
     59  }
     60 
     61  unsigned int numValues;
     62  unsigned int valueIndex;
     63  hb_vector_t<number_t> deltas;
     64 };
     65 
     66 typedef biased_subrs_t<CFF2Subrs>   cff2_biased_subrs_t;
     67 
     68 template <typename ELEM>
     69 struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
     70 {
     71  template <typename ACC>
     72  cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd,
     73 		const int *coords_=nullptr, unsigned int num_coords_=0)
     74    : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs),
     75      region_count (0), cached_scalars_vector (&acc.cached_scalars_vector)
     76  {
     77    coords = coords_;
     78    num_coords = num_coords_;
     79    varStore = acc.varStore;
     80    do_blend = num_coords && varStore->size;
     81    set_ivs (acc.privateDicts[fd].ivs);
     82  }
     83 
     84  ~cff2_cs_interp_env_t ()
     85  {
     86    release_scalars_vector (scalars);
     87  }
     88 
     89  hb_vector_t<float> *acquire_scalars_vector () const
     90  {
     91    hb_vector_t<float> *scalars = cached_scalars_vector->get_acquire ();
     92 
     93    if (!scalars || !cached_scalars_vector->cmpexch (scalars, nullptr))
     94    {
     95      scalars = (hb_vector_t<float> *) hb_calloc (1, sizeof (hb_vector_t<float>));
     96      if (unlikely (!scalars))
     97 return nullptr;
     98      scalars->init ();
     99    }
    100 
    101    return scalars;
    102  }
    103 
    104  void release_scalars_vector (hb_vector_t<float> *scalars) const
    105  {
    106    if (!scalars)
    107      return;
    108 
    109    scalars->clear ();
    110 
    111    if (!cached_scalars_vector->cmpexch (nullptr, scalars))
    112    {
    113      scalars->fini ();
    114      hb_free (scalars);
    115    }
    116    scalars = nullptr;
    117  }
    118 
    119  op_code_t fetch_op ()
    120  {
    121    if (this->str_ref.avail ())
    122      return SUPER::fetch_op ();
    123 
    124    /* make up return or endchar op */
    125    if (this->callStack.is_empty ())
    126      return OpCode_endchar;
    127    else
    128      return OpCode_return;
    129  }
    130 
    131  const ELEM& eval_arg (unsigned int i)
    132  {
    133    return SUPER::argStack[i];
    134  }
    135 
    136  const ELEM& pop_arg ()
    137  {
    138    return SUPER::argStack.pop ();
    139  }
    140 
    141  void process_blend ()
    142  {
    143    if (!seen_blend)
    144    {
    145      scalars = acquire_scalars_vector ();
    146      if (unlikely (!scalars))
    147 SUPER::set_error ();
    148      else
    149      {
    150 region_count = varStore->varStore.get_region_index_count (get_ivs ());
    151 if (do_blend)
    152 {
    153   if (unlikely (!scalars->resize_exact (region_count)))
    154     SUPER::set_error ();
    155   else
    156     varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
    157 					   &(*scalars)[0], region_count);
    158 }
    159      }
    160      seen_blend = true;
    161    }
    162  }
    163 
    164  void process_vsindex ()
    165  {
    166    unsigned int  index = SUPER::argStack.pop_uint ();
    167    if (unlikely (seen_vsindex () || seen_blend))
    168    {
    169     SUPER::set_error ();
    170    }
    171    else
    172    {
    173      set_ivs (index);
    174    }
    175    seen_vsindex_ = true;
    176  }
    177 
    178  unsigned int get_region_count () const { return region_count; }
    179  void	 set_region_count (unsigned int region_count_) { region_count = region_count_; }
    180  unsigned int get_ivs () const { return ivs; }
    181  void	 set_ivs (unsigned int ivs_) { ivs = ivs_; }
    182  bool	 seen_vsindex () const { return seen_vsindex_; }
    183 
    184  double blend_deltas (hb_array_t<const ELEM> deltas) const
    185  {
    186    double v = 0;
    187    if (do_blend)
    188    {
    189      if (likely (scalars && scalars->length == deltas.length))
    190      {
    191        unsigned count = scalars->length;
    192 for (unsigned i = 0; i < count; i++)
    193   v += (double) scalars->arrayZ[i] * deltas.arrayZ[i].to_real ();
    194      }
    195    }
    196    return v;
    197  }
    198 
    199  bool have_coords () const { return num_coords; }
    200 
    201  protected:
    202  const int     *coords;
    203  unsigned int  num_coords;
    204  const	 CFF2ItemVariationStore *varStore;
    205  unsigned int  region_count;
    206  unsigned int  ivs;
    207  hb_vector_t<float>  *scalars = nullptr;
    208  hb_atomic_t<hb_vector_t<float> *> *cached_scalars_vector = nullptr;
    209  bool	  do_blend;
    210  bool	  seen_vsindex_ = false;
    211  bool	  seen_blend = false;
    212 
    213  typedef cs_interp_env_t<ELEM, CFF2Subrs> SUPER;
    214 };
    215 template <typename OPSET, typename PARAM, typename ELEM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t<ELEM>, PARAM>>
    216 struct cff2_cs_opset_t : cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH>
    217 {
    218  static void process_op (op_code_t op, cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
    219  {
    220    switch (op) {
    221      case OpCode_callsubr:
    222      case OpCode_callgsubr:
    223 /* a subroutine number shouldn't be a blended value */
    224 #if 0
    225 if (unlikely (env.argStack.peek ().blending ()))
    226 {
    227   env.set_error ();
    228   break;
    229 }
    230 #endif
    231 SUPER::process_op (op, env, param);
    232 break;
    233 
    234      case OpCode_blendcs:
    235 OPSET::process_blend (env, param);
    236 break;
    237 
    238      case OpCode_vsindexcs:
    239 #if 0
    240 if (unlikely (env.argStack.peek ().blending ()))
    241 {
    242   env.set_error ();
    243   break;
    244 }
    245 #endif
    246 OPSET::process_vsindex (env, param);
    247 break;
    248 
    249      default:
    250 SUPER::process_op (op, env, param);
    251    }
    252  }
    253 
    254  template <typename T = ELEM,
    255     hb_enable_if (hb_is_same (T, blend_arg_t))>
    256  static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
    257 			 ELEM &arg,
    258 			 const hb_array_t<const ELEM> blends,
    259 			 unsigned n, unsigned i)
    260  {
    261    if (env.have_coords ())
    262      arg.set_int (round (arg.to_real () + env.blend_deltas (blends)));
    263    else
    264      arg.set_blends (n, i, blends);
    265  }
    266  template <typename T = ELEM,
    267     hb_enable_if (!hb_is_same (T, blend_arg_t))>
    268  static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
    269 			 ELEM &arg,
    270 			 const hb_array_t<const ELEM> blends,
    271 			 unsigned n, unsigned i)
    272  {
    273    arg.set_real (arg.to_real () + env.blend_deltas (blends));
    274  }
    275 
    276  static void process_blend (cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
    277  {
    278    unsigned int n, k;
    279 
    280    env.process_blend ();
    281    k = env.get_region_count ();
    282    n = env.argStack.pop_uint ();
    283    /* copy the blend values into blend array of the default values */
    284    unsigned int start = env.argStack.get_count () - ((k+1) * n);
    285    /* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */
    286    if (unlikely (start > env.argStack.get_count ()))
    287    {
    288      env.set_error ();
    289      return;
    290    }
    291    for (unsigned int i = 0; i < n; i++)
    292    {
    293      const hb_array_t<const ELEM> blends = env.argStack.sub_array (start + n + (i * k), k);
    294      process_arg_blend (env, env.argStack[start + i], blends, n, i);
    295    }
    296 
    297    /* pop off blend values leaving default values now adorned with blend values */
    298    env.argStack.pop (k * n);
    299  }
    300 
    301  static void process_vsindex (cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
    302  {
    303    env.process_vsindex ();
    304    env.clear_args ();
    305  }
    306 
    307  private:
    308  typedef cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH>  SUPER;
    309 };
    310 
    311 template <typename OPSET, typename PARAM, typename ELEM>
    312 using cff2_cs_interpreter_t = cs_interpreter_t<cff2_cs_interp_env_t<ELEM>, OPSET, PARAM>;
    313 
    314 } /* namespace CFF */
    315 
    316 #endif /* HB_CFF2_INTERP_CS_HH */