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 init ()
  39   {
  40     number_t::init ();
  41     deltas.init ();
  42   }
  43 
  44   void fini ()
  45   {
  46     number_t::fini ();
  47     deltas.fini_deep ();
  48   }
  49 
  50   void set_int (int v) { reset_blends (); number_t::set_int (v); }
  51   void set_fixed (int32_t v) { reset_blends (); number_t::set_fixed (v); }
  52   void set_real (double v) { reset_blends (); number_t::set_real (v); }
  53 
  54   void set_blends (unsigned int numValues_, unsigned int valueIndex_,
  55                           unsigned int numBlends, hb_array_t<const blend_arg_t> blends_)
  56   {
  57     numValues = numValues_;
  58     valueIndex = valueIndex_;
  59     deltas.resize (numBlends);
  60     for (unsigned int i = 0; i < numBlends; i++)
  61       deltas[i] = blends_[i];
  62   }
  63 
  64   bool blending () const { return deltas.length > 0; }
  65   void reset_blends ()
  66   {
  67     numValues = valueIndex = 0;
  68     deltas.resize (0);
  69   }
  70 
  71   unsigned int numValues;
  72   unsigned int valueIndex;
  73   hb_vector_t<number_t> deltas;
  74 };
  75 
  76 typedef interp_env_t<blend_arg_t> BlendInterpEnv;
  77 typedef biased_subrs_t<CFF2Subrs>   cff2_biased_subrs_t;
  78 
  79 struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
  80 {
  81   template <typename ACC>
  82   void init (const byte_str_t &str, ACC &acc, unsigned int fd,
  83                     const int *coords_=nullptr, unsigned int num_coords_=0)
  84   {
  85     SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
  86 
  87     coords = coords_;
  88     num_coords = num_coords_;
  89     varStore = acc.varStore;
  90     seen_blend = false;
  91     seen_vsindex_ = false;
  92     scalars.init ();
  93     do_blend = (coords != nullptr) && num_coords && (varStore != &Null(CFF2VariationStore));
  94     set_ivs (acc.privateDicts[fd].ivs);
  95   }
  96 
  97   void fini ()
  98   {
  99     scalars.fini ();
 100     SUPER::fini ();
 101   }
 102 
 103   op_code_t fetch_op ()
 104   {
 105     if (this->str_ref.avail ())
 106       return SUPER::fetch_op ();
 107 
 108     /* make up return or endchar op */
 109     if (this->callStack.is_empty ())
 110       return OpCode_endchar;
 111     else
 112       return OpCode_return;
 113   }
 114 
 115   const blend_arg_t& eval_arg (unsigned int i)
 116   {
 117     blend_arg_t  &arg = argStack[i];
 118     blend_arg (arg);
 119     return arg;
 120   }
 121 
 122   const blend_arg_t& pop_arg ()
 123   {
 124     blend_arg_t  &arg = argStack.pop ();
 125     blend_arg (arg);
 126     return arg;
 127   }
 128 
 129   void process_blend ()
 130   {
 131     if (!seen_blend)
 132     {
 133       region_count = varStore->varStore.get_region_index_count (get_ivs ());
 134       if (do_blend)
 135       {
 136         scalars.resize (region_count);
 137         varStore->varStore.get_scalars (get_ivs (),
 138                                         (int *)coords, num_coords,
 139                                         &scalars[0], region_count);
 140       }
 141       seen_blend = true;
 142     }
 143   }
 144 
 145   void process_vsindex ()
 146   {
 147     unsigned int  index = argStack.pop_uint ();
 148     if (unlikely (seen_vsindex () || seen_blend))
 149     {
 150       set_error ();
 151     }
 152     else
 153     {
 154       set_ivs (index);
 155     }
 156     seen_vsindex_ = true;
 157   }
 158 
 159   unsigned int get_region_count () const { return region_count; }
 160   void   set_region_count (unsigned int region_count_) { region_count = region_count_; }
 161   unsigned int get_ivs () const { return ivs; }
 162   void   set_ivs (unsigned int ivs_) { ivs = ivs_; }
 163   bool   seen_vsindex () const { return seen_vsindex_; }
 164 
 165   protected:
 166   void blend_arg (blend_arg_t &arg)
 167   {
 168     if (do_blend && arg.blending ())
 169     {
 170       if (likely (scalars.length == arg.deltas.length))
 171       {
 172         double v = arg.to_real ();
 173         for (unsigned int i = 0; i < scalars.length; i++)
 174         {
 175           v += (double)scalars[i] * arg.deltas[i].to_real ();
 176         }
 177         arg.set_real (v);
 178         arg.deltas.resize (0);
 179       }
 180     }
 181   }
 182 
 183   protected:
 184   const int     *coords;
 185   unsigned int  num_coords;
 186   const  CFF2VariationStore *varStore;
 187   unsigned int  region_count;
 188   unsigned int  ivs;
 189   hb_vector_t<float>  scalars;
 190   bool    do_blend;
 191   bool    seen_vsindex_;
 192   bool    seen_blend;
 193 
 194   typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER;
 195 };
 196 template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM> >
 197 struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH>
 198 {
 199   static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param)
 200   {
 201     switch (op) {
 202       case OpCode_callsubr:
 203       case OpCode_callgsubr:
 204         /* a subroutine number shoudln't be a blended value */
 205         if (unlikely (env.argStack.peek ().blending ()))
 206         {
 207           env.set_error ();
 208           break;
 209         }
 210         SUPER::process_op (op, env, param);
 211         break;
 212 
 213       case OpCode_blendcs:
 214         OPSET::process_blend (env, param);
 215         break;
 216 
 217       case OpCode_vsindexcs:
 218         if (unlikely (env.argStack.peek ().blending ()))
 219         {
 220           env.set_error ();
 221           break;
 222         }
 223         OPSET::process_vsindex (env, param);
 224         break;
 225 
 226       default:
 227         SUPER::process_op (op, env, param);
 228     }
 229   }
 230 
 231   static void process_blend (cff2_cs_interp_env_t &env, PARAM& param)
 232   {
 233     unsigned int n, k;
 234 
 235     env.process_blend ();
 236     k = env.get_region_count ();
 237     n = env.argStack.pop_uint ();
 238     /* copy the blend values into blend array of the default values */
 239     unsigned int start = env.argStack.get_count () - ((k+1) * n);
 240     /* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */
 241     if (unlikely (start > env.argStack.get_count ()))
 242     {
 243       env.set_error ();
 244       return;
 245     }
 246     for (unsigned int i = 0; i < n; i++)
 247     {
 248       const hb_array_t<const blend_arg_t>       blends = env.argStack.get_subarray (start + n + (i * k));
 249       env.argStack[start + i].set_blends (n, i, k, blends);
 250     }
 251 
 252     /* pop off blend values leaving default values now adorned with blend values */
 253     env.argStack.pop (k * n);
 254   }
 255 
 256   static void process_vsindex (cff2_cs_interp_env_t &env, PARAM& param)
 257   {
 258     env.process_vsindex ();
 259     env.clear_args ();
 260   }
 261 
 262   private:
 263   typedef cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH>  SUPER;
 264 };
 265 
 266 template <typename OPSET, typename PARAM>
 267 struct cff2_cs_interpreter_t : cs_interpreter_t<cff2_cs_interp_env_t, OPSET, PARAM> {};
 268 
 269 } /* namespace CFF */
 270 
 271 #endif /* HB_CFF2_INTERP_CS_HH */