tor-browser

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

hb-cff-interp-cs-common.hh (24089B)


      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_CFF_INTERP_CS_COMMON_HH
     27 #define HB_CFF_INTERP_CS_COMMON_HH
     28 
     29 #include "hb.hh"
     30 #include "hb-cff-interp-common.hh"
     31 
     32 namespace CFF {
     33 
     34 using namespace OT;
     35 
     36 enum cs_type_t {
     37  CSType_CharString,
     38  CSType_GlobalSubr,
     39  CSType_LocalSubr
     40 };
     41 
     42 struct call_context_t
     43 {
     44  void init (const byte_str_ref_t substr_=byte_str_ref_t (), cs_type_t type_=CSType_CharString, unsigned int subr_num_=0)
     45  {
     46    str_ref = substr_;
     47    type = type_;
     48    subr_num = subr_num_;
     49  }
     50 
     51  void fini () {}
     52 
     53  byte_str_ref_t  str_ref;
     54  cs_type_t	  type;
     55  unsigned int    subr_num;
     56 };
     57 
     58 /* call stack */
     59 const unsigned int kMaxCallLimit = 10;
     60 struct call_stack_t : cff_stack_t<call_context_t, kMaxCallLimit> {};
     61 
     62 template <typename SUBRS>
     63 struct biased_subrs_t
     64 {
     65  void init (const SUBRS *subrs_)
     66  {
     67    subrs = subrs_;
     68    unsigned int  nSubrs = get_count ();
     69    if (nSubrs < 1240)
     70      bias = 107;
     71    else if (nSubrs < 33900)
     72      bias = 1131;
     73    else
     74      bias = 32768;
     75  }
     76 
     77  void fini () {}
     78 
     79  unsigned int get_count () const { return subrs ? subrs->count : 0; }
     80  unsigned int get_bias () const  { return bias; }
     81 
     82  hb_ubytes_t operator [] (unsigned int index) const
     83  {
     84    if (unlikely (!subrs || index >= subrs->count))
     85      return hb_ubytes_t ();
     86    else
     87      return (*subrs)[index];
     88  }
     89 
     90  protected:
     91  unsigned int  bias;
     92  const SUBRS   *subrs;
     93 };
     94 
     95 struct point_t
     96 {
     97  void set_int (int _x, int _y)
     98  {
     99    x.set_int (_x);
    100    y.set_int (_y);
    101  }
    102 
    103  void move_x (const number_t &dx) { x += dx; }
    104  void move_y (const number_t &dy) { y += dy; }
    105  void move (const number_t &dx, const number_t &dy) { move_x (dx); move_y (dy); }
    106  void move (const point_t &d) { move_x (d.x); move_y (d.y); }
    107 
    108  number_t  x;
    109  number_t  y;
    110 };
    111 
    112 template <typename ARG, typename SUBRS>
    113 struct cs_interp_env_t : interp_env_t<ARG>
    114 {
    115  cs_interp_env_t (const hb_ubytes_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_) :
    116    interp_env_t<ARG> (str)
    117  {
    118    context.init (str, CSType_CharString);
    119    seen_moveto = true;
    120    seen_hintmask = false;
    121    hstem_count = 0;
    122    vstem_count = 0;
    123    hintmask_size = 0;
    124    pt.set_int (0, 0);
    125    globalSubrs.init (globalSubrs_);
    126    localSubrs.init (localSubrs_);
    127  }
    128  ~cs_interp_env_t ()
    129  {
    130    globalSubrs.fini ();
    131    localSubrs.fini ();
    132  }
    133 
    134  bool in_error () const
    135  {
    136    return callStack.in_error () || SUPER::in_error ();
    137  }
    138 
    139  bool pop_subr_num (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num)
    140  {
    141    subr_num = 0;
    142    int n = SUPER::argStack.pop_int ();
    143    n += biasedSubrs.get_bias ();
    144    if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ())))
    145      return false;
    146 
    147    subr_num = (unsigned int)n;
    148    return true;
    149  }
    150 
    151  void call_subr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type)
    152  {
    153    unsigned int subr_num = 0;
    154 
    155    if (unlikely (!pop_subr_num (biasedSubrs, subr_num)
    156 	 || callStack.get_count () >= kMaxCallLimit))
    157    {
    158      SUPER::set_error ();
    159      return;
    160    }
    161    context.str_ref = SUPER::str_ref;
    162    callStack.push (context);
    163 
    164    context.init ( biasedSubrs[subr_num], type, subr_num);
    165    SUPER::str_ref = context.str_ref;
    166  }
    167 
    168  void return_from_subr ()
    169  {
    170    if (unlikely (SUPER::str_ref.in_error ()))
    171      SUPER::set_error ();
    172    context = callStack.pop ();
    173    SUPER::str_ref = context.str_ref;
    174  }
    175 
    176  void determine_hintmask_size ()
    177  {
    178    if (!seen_hintmask)
    179    {
    180      vstem_count += SUPER::argStack.get_count() / 2;
    181      hintmask_size = (hstem_count + vstem_count + 7) >> 3;
    182      seen_hintmask = true;
    183    }
    184  }
    185 
    186  void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; }
    187  bool is_endchar () const { return endchar_flag; }
    188 
    189  const number_t &get_x () const { return pt.x; }
    190  const number_t &get_y () const { return pt.y; }
    191  const point_t &get_pt () const { return pt; }
    192 
    193  void moveto (const point_t &pt_ ) { pt = pt_; }
    194 
    195  public:
    196  call_context_t   context;
    197  bool	  endchar_flag;
    198  bool	  seen_moveto;
    199  bool	  seen_hintmask;
    200 
    201  unsigned int  hstem_count;
    202  unsigned int  vstem_count;
    203  unsigned int  hintmask_size;
    204  call_stack_t	callStack;
    205  biased_subrs_t<SUBRS>   globalSubrs;
    206  biased_subrs_t<SUBRS>   localSubrs;
    207 
    208  private:
    209  point_t	 pt;
    210 
    211  typedef interp_env_t<ARG> SUPER;
    212 };
    213 
    214 template <typename ENV, typename PARAM>
    215 struct path_procs_null_t
    216 {
    217  static void rmoveto (ENV &env, PARAM& param) {}
    218  static void hmoveto (ENV &env, PARAM& param) {}
    219  static void vmoveto (ENV &env, PARAM& param) {}
    220  static void rlineto (ENV &env, PARAM& param) {}
    221  static void hlineto (ENV &env, PARAM& param) {}
    222  static void vlineto (ENV &env, PARAM& param) {}
    223  static void rrcurveto (ENV &env, PARAM& param) {}
    224  static void rcurveline (ENV &env, PARAM& param) {}
    225  static void rlinecurve (ENV &env, PARAM& param) {}
    226  static void vvcurveto (ENV &env, PARAM& param) {}
    227  static void hhcurveto (ENV &env, PARAM& param) {}
    228  static void vhcurveto (ENV &env, PARAM& param) {}
    229  static void hvcurveto (ENV &env, PARAM& param) {}
    230  static void moveto (ENV &env, PARAM& param, const point_t &pt) {}
    231  static void line (ENV &env, PARAM& param, const point_t &pt1) {}
    232  static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) {}
    233  static void hflex (ENV &env, PARAM& param) {}
    234  static void flex (ENV &env, PARAM& param) {}
    235  static void hflex1 (ENV &env, PARAM& param) {}
    236  static void flex1 (ENV &env, PARAM& param) {}
    237 };
    238 
    239 template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM>>
    240 struct cs_opset_t : opset_t<ARG>
    241 {
    242  static void process_op (op_code_t op, ENV &env, PARAM& param)
    243  {
    244    switch (op) {
    245 
    246      case OpCode_return:
    247 env.return_from_subr ();
    248 break;
    249      case OpCode_endchar:
    250 OPSET::check_width (op, env, param);
    251 env.set_endchar (true);
    252 OPSET::flush_args_and_op (op, env, param);
    253 break;
    254 
    255      case OpCode_fixedcs:
    256 env.argStack.push_fixed_from_substr (env.str_ref);
    257 break;
    258 
    259      case OpCode_callsubr:
    260 env.call_subr (env.localSubrs, CSType_LocalSubr);
    261 break;
    262 
    263      case OpCode_callgsubr:
    264 env.call_subr (env.globalSubrs, CSType_GlobalSubr);
    265 break;
    266 
    267      case OpCode_hstem:
    268      case OpCode_hstemhm:
    269 OPSET::check_width (op, env, param);
    270 OPSET::process_hstem (op, env, param);
    271 break;
    272      case OpCode_vstem:
    273      case OpCode_vstemhm:
    274 OPSET::check_width (op, env, param);
    275 OPSET::process_vstem (op, env, param);
    276 break;
    277      case OpCode_hintmask:
    278      case OpCode_cntrmask:
    279 OPSET::check_width (op, env, param);
    280 OPSET::process_hintmask (op, env, param);
    281 break;
    282      case OpCode_rmoveto:
    283 OPSET::check_width (op, env, param);
    284 PATH::rmoveto (env, param);
    285 OPSET::process_post_move (op, env, param);
    286 break;
    287      case OpCode_hmoveto:
    288 OPSET::check_width (op, env, param);
    289 PATH::hmoveto (env, param);
    290 OPSET::process_post_move (op, env, param);
    291 break;
    292      case OpCode_vmoveto:
    293 OPSET::check_width (op, env, param);
    294 PATH::vmoveto (env, param);
    295 OPSET::process_post_move (op, env, param);
    296 break;
    297      case OpCode_rlineto:
    298 PATH::rlineto (env, param);
    299 process_post_path (op, env, param);
    300 break;
    301      case OpCode_hlineto:
    302 PATH::hlineto (env, param);
    303 process_post_path (op, env, param);
    304 break;
    305      case OpCode_vlineto:
    306 PATH::vlineto (env, param);
    307 process_post_path (op, env, param);
    308 break;
    309      case OpCode_rrcurveto:
    310 PATH::rrcurveto (env, param);
    311 process_post_path (op, env, param);
    312 break;
    313      case OpCode_rcurveline:
    314 PATH::rcurveline (env, param);
    315 process_post_path (op, env, param);
    316 break;
    317      case OpCode_rlinecurve:
    318 PATH::rlinecurve (env, param);
    319 process_post_path (op, env, param);
    320 break;
    321      case OpCode_vvcurveto:
    322 PATH::vvcurveto (env, param);
    323 process_post_path (op, env, param);
    324 break;
    325      case OpCode_hhcurveto:
    326 PATH::hhcurveto (env, param);
    327 process_post_path (op, env, param);
    328 break;
    329      case OpCode_vhcurveto:
    330 PATH::vhcurveto (env, param);
    331 process_post_path (op, env, param);
    332 break;
    333      case OpCode_hvcurveto:
    334 PATH::hvcurveto (env, param);
    335 process_post_path (op, env, param);
    336 break;
    337 
    338      case OpCode_hflex:
    339 PATH::hflex (env, param);
    340 OPSET::process_post_flex (op, env, param);
    341 break;
    342 
    343      case OpCode_flex:
    344 PATH::flex (env, param);
    345 OPSET::process_post_flex (op, env, param);
    346 break;
    347 
    348      case OpCode_hflex1:
    349 PATH::hflex1 (env, param);
    350 OPSET::process_post_flex (op, env, param);
    351 break;
    352 
    353      case OpCode_flex1:
    354 PATH::flex1 (env, param);
    355 OPSET::process_post_flex (op, env, param);
    356 break;
    357 
    358      default:
    359 SUPER::process_op (op, env);
    360 break;
    361    }
    362  }
    363 
    364  static void process_hstem (op_code_t op, ENV &env, PARAM& param)
    365  {
    366    env.hstem_count += env.argStack.get_count () / 2;
    367    OPSET::flush_args_and_op (op, env, param);
    368  }
    369 
    370  static void process_vstem (op_code_t op, ENV &env, PARAM& param)
    371  {
    372    env.vstem_count += env.argStack.get_count () / 2;
    373    OPSET::flush_args_and_op (op, env, param);
    374  }
    375 
    376  static void process_hintmask (op_code_t op, ENV &env, PARAM& param)
    377  {
    378    env.determine_hintmask_size ();
    379    if (likely (env.str_ref.avail (env.hintmask_size)))
    380    {
    381      OPSET::flush_hintmask (op, env, param);
    382      env.str_ref.inc (env.hintmask_size);
    383    }
    384  }
    385 
    386  static void process_post_flex (op_code_t op, ENV &env, PARAM& param)
    387  {
    388    OPSET::flush_args_and_op (op, env, param);
    389  }
    390 
    391  static void check_width (op_code_t op, ENV &env, PARAM& param)
    392  {}
    393 
    394  static void process_post_move (op_code_t op, ENV &env, PARAM& param)
    395  {
    396    if (!env.seen_moveto)
    397    {
    398      env.determine_hintmask_size ();
    399      env.seen_moveto = true;
    400    }
    401    OPSET::flush_args_and_op (op, env, param);
    402  }
    403 
    404  static void process_post_path (op_code_t op, ENV &env, PARAM& param)
    405  {
    406    OPSET::flush_args_and_op (op, env, param);
    407  }
    408 
    409  static void flush_args_and_op (op_code_t op, ENV &env, PARAM& param)
    410  {
    411    OPSET::flush_args (env, param);
    412    OPSET::flush_op (op, env, param);
    413  }
    414 
    415  static void flush_args (ENV &env, PARAM& param)
    416  {
    417    env.pop_n_args (env.argStack.get_count ());
    418  }
    419 
    420  static void flush_op (op_code_t op, ENV &env, PARAM& param)
    421  {
    422  }
    423 
    424  static void flush_hintmask (op_code_t op, ENV &env, PARAM& param)
    425  {
    426    OPSET::flush_args_and_op (op, env, param);
    427  }
    428 
    429  static bool is_number_op (op_code_t op)
    430  {
    431    switch (op)
    432    {
    433      case OpCode_shortint:
    434      case OpCode_fixedcs:
    435      case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1:
    436      case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3:
    437      case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
    438      case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
    439 return true;
    440 
    441      default:
    442 /* 1-byte integer */
    443 return (OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast);
    444    }
    445  }
    446 
    447  protected:
    448  typedef opset_t<ARG>  SUPER;
    449 };
    450 
    451 template <typename PATH, typename ENV, typename PARAM>
    452 struct path_procs_t
    453 {
    454  static void rmoveto (ENV &env, PARAM& param)
    455  {
    456    point_t pt1 = env.get_pt ();
    457    const number_t &dy = env.pop_arg ();
    458    const number_t &dx = env.pop_arg ();
    459    pt1.move (dx, dy);
    460    PATH::moveto (env, param, pt1);
    461  }
    462 
    463  static void hmoveto (ENV &env, PARAM& param)
    464  {
    465    point_t pt1 = env.get_pt ();
    466    pt1.move_x (env.pop_arg ());
    467    PATH::moveto (env, param, pt1);
    468  }
    469 
    470  static void vmoveto (ENV &env, PARAM& param)
    471  {
    472    point_t pt1 = env.get_pt ();
    473    pt1.move_y (env.pop_arg ());
    474    PATH::moveto (env, param, pt1);
    475  }
    476 
    477  static void rlineto (ENV &env, PARAM& param)
    478  {
    479    for (unsigned int i = 0; i + 2 <= env.argStack.get_count (); i += 2)
    480    {
    481      point_t pt1 = env.get_pt ();
    482      pt1.move (env.eval_arg (i), env.eval_arg (i+1));
    483      PATH::line (env, param, pt1);
    484    }
    485  }
    486 
    487  static void hlineto (ENV &env, PARAM& param)
    488  {
    489    point_t pt1;
    490    unsigned int i = 0;
    491    for (; i + 2 <= env.argStack.get_count (); i += 2)
    492    {
    493      pt1 = env.get_pt ();
    494      pt1.move_x (env.eval_arg (i));
    495      PATH::line (env, param, pt1);
    496      pt1.move_y (env.eval_arg (i+1));
    497      PATH::line (env, param, pt1);
    498    }
    499    if (i < env.argStack.get_count ())
    500    {
    501      pt1 = env.get_pt ();
    502      pt1.move_x (env.eval_arg (i));
    503      PATH::line (env, param, pt1);
    504    }
    505  }
    506 
    507  static void vlineto (ENV &env, PARAM& param)
    508  {
    509    point_t pt1;
    510    unsigned int i = 0;
    511    for (; i + 2 <= env.argStack.get_count (); i += 2)
    512    {
    513      pt1 = env.get_pt ();
    514      pt1.move_y (env.eval_arg (i));
    515      PATH::line (env, param, pt1);
    516      pt1.move_x (env.eval_arg (i+1));
    517      PATH::line (env, param, pt1);
    518    }
    519    if (i < env.argStack.get_count ())
    520    {
    521      pt1 = env.get_pt ();
    522      pt1.move_y (env.eval_arg (i));
    523      PATH::line (env, param, pt1);
    524    }
    525  }
    526 
    527  static void rrcurveto (ENV &env, PARAM& param)
    528  {
    529    for (unsigned int i = 0; i + 6 <= env.argStack.get_count (); i += 6)
    530    {
    531      point_t pt1 = env.get_pt ();
    532      pt1.move (env.eval_arg (i), env.eval_arg (i+1));
    533      point_t pt2 = pt1;
    534      pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
    535      point_t pt3 = pt2;
    536      pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
    537      PATH::curve (env, param, pt1, pt2, pt3);
    538    }
    539  }
    540 
    541  static void rcurveline (ENV &env, PARAM& param)
    542  {
    543    unsigned int arg_count = env.argStack.get_count ();
    544    if (unlikely (arg_count < 8))
    545      return;
    546 
    547    unsigned int i = 0;
    548    unsigned int curve_limit = arg_count - 2;
    549    for (; i + 6 <= curve_limit; i += 6)
    550    {
    551      point_t pt1 = env.get_pt ();
    552      pt1.move (env.eval_arg (i), env.eval_arg (i+1));
    553      point_t pt2 = pt1;
    554      pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
    555      point_t pt3 = pt2;
    556      pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
    557      PATH::curve (env, param, pt1, pt2, pt3);
    558    }
    559 
    560    point_t pt1 = env.get_pt ();
    561    pt1.move (env.eval_arg (i), env.eval_arg (i+1));
    562    PATH::line (env, param, pt1);
    563  }
    564 
    565  static void rlinecurve (ENV &env, PARAM& param)
    566  {
    567    unsigned int arg_count = env.argStack.get_count ();
    568    if (unlikely (arg_count < 8))
    569      return;
    570 
    571    unsigned int i = 0;
    572    unsigned int line_limit = arg_count - 6;
    573    for (; i + 2 <= line_limit; i += 2)
    574    {
    575      point_t pt1 = env.get_pt ();
    576      pt1.move (env.eval_arg (i), env.eval_arg (i+1));
    577      PATH::line (env, param, pt1);
    578    }
    579 
    580    point_t pt1 = env.get_pt ();
    581    pt1.move (env.eval_arg (i), env.eval_arg (i+1));
    582    point_t pt2 = pt1;
    583    pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
    584    point_t pt3 = pt2;
    585    pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
    586    PATH::curve (env, param, pt1, pt2, pt3);
    587  }
    588 
    589  static void vvcurveto (ENV &env, PARAM& param)
    590  {
    591    unsigned int i = 0;
    592    point_t pt1 = env.get_pt ();
    593    if ((env.argStack.get_count () & 1) != 0)
    594      pt1.move_x (env.eval_arg (i++));
    595    for (; i + 4 <= env.argStack.get_count (); i += 4)
    596    {
    597      pt1.move_y (env.eval_arg (i));
    598      point_t pt2 = pt1;
    599      pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
    600      point_t pt3 = pt2;
    601      pt3.move_y (env.eval_arg (i+3));
    602      PATH::curve (env, param, pt1, pt2, pt3);
    603      pt1 = env.get_pt ();
    604    }
    605  }
    606 
    607  static void hhcurveto (ENV &env, PARAM& param)
    608  {
    609    unsigned int i = 0;
    610    point_t pt1 = env.get_pt ();
    611    if ((env.argStack.get_count () & 1) != 0)
    612      pt1.move_y (env.eval_arg (i++));
    613    for (; i + 4 <= env.argStack.get_count (); i += 4)
    614    {
    615      pt1.move_x (env.eval_arg (i));
    616      point_t pt2 = pt1;
    617      pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
    618      point_t pt3 = pt2;
    619      pt3.move_x (env.eval_arg (i+3));
    620      PATH::curve (env, param, pt1, pt2, pt3);
    621      pt1 = env.get_pt ();
    622    }
    623  }
    624 
    625  static void vhcurveto (ENV &env, PARAM& param)
    626  {
    627    point_t pt1, pt2, pt3;
    628    unsigned int i = 0;
    629    if ((env.argStack.get_count () % 8) >= 4)
    630    {
    631      point_t pt1 = env.get_pt ();
    632      pt1.move_y (env.eval_arg (i));
    633      point_t pt2 = pt1;
    634      pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
    635      point_t pt3 = pt2;
    636      pt3.move_x (env.eval_arg (i+3));
    637      i += 4;
    638 
    639      for (; i + 8 <= env.argStack.get_count (); i += 8)
    640      {
    641 PATH::curve (env, param, pt1, pt2, pt3);
    642 pt1 = env.get_pt ();
    643 pt1.move_x (env.eval_arg (i));
    644 pt2 = pt1;
    645 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
    646 pt3 = pt2;
    647 pt3.move_y (env.eval_arg (i+3));
    648 PATH::curve (env, param, pt1, pt2, pt3);
    649 
    650 pt1 = pt3;
    651 pt1.move_y (env.eval_arg (i+4));
    652 pt2 = pt1;
    653 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
    654 pt3 = pt2;
    655 pt3.move_x (env.eval_arg (i+7));
    656      }
    657      if (i < env.argStack.get_count ())
    658 pt3.move_y (env.eval_arg (i));
    659      PATH::curve (env, param, pt1, pt2, pt3);
    660    }
    661    else
    662    {
    663      for (; i + 8 <= env.argStack.get_count (); i += 8)
    664      {
    665 pt1 = env.get_pt ();
    666 pt1.move_y (env.eval_arg (i));
    667 pt2 = pt1;
    668 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
    669 pt3 = pt2;
    670 pt3.move_x (env.eval_arg (i+3));
    671 PATH::curve (env, param, pt1, pt2, pt3);
    672 
    673 pt1 = pt3;
    674 pt1.move_x (env.eval_arg (i+4));
    675 pt2 = pt1;
    676 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
    677 pt3 = pt2;
    678 pt3.move_y (env.eval_arg (i+7));
    679 if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0))
    680   pt3.move_x (env.eval_arg (i+8));
    681 PATH::curve (env, param, pt1, pt2, pt3);
    682      }
    683    }
    684  }
    685 
    686  static void hvcurveto (ENV &env, PARAM& param)
    687  {
    688    point_t pt1, pt2, pt3;
    689    unsigned int i = 0;
    690    if ((env.argStack.get_count () % 8) >= 4)
    691    {
    692      point_t pt1 = env.get_pt ();
    693      pt1.move_x (env.eval_arg (i));
    694      point_t pt2 = pt1;
    695      pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
    696      point_t pt3 = pt2;
    697      pt3.move_y (env.eval_arg (i+3));
    698      i += 4;
    699 
    700      for (; i + 8 <= env.argStack.get_count (); i += 8)
    701      {
    702 PATH::curve (env, param, pt1, pt2, pt3);
    703 pt1 = env.get_pt ();
    704 pt1.move_y (env.eval_arg (i));
    705 pt2 = pt1;
    706 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
    707 pt3 = pt2;
    708 pt3.move_x (env.eval_arg (i+3));
    709 PATH::curve (env, param, pt1, pt2, pt3);
    710 
    711 pt1 = pt3;
    712 pt1.move_x (env.eval_arg (i+4));
    713 pt2 = pt1;
    714 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
    715 pt3 = pt2;
    716 pt3.move_y (env.eval_arg (i+7));
    717      }
    718      if (i < env.argStack.get_count ())
    719 pt3.move_x (env.eval_arg (i));
    720      PATH::curve (env, param, pt1, pt2, pt3);
    721    }
    722    else
    723    {
    724      for (; i + 8 <= env.argStack.get_count (); i += 8)
    725      {
    726 pt1 = env.get_pt ();
    727 pt1.move_x (env.eval_arg (i));
    728 pt2 = pt1;
    729 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
    730 pt3 = pt2;
    731 pt3.move_y (env.eval_arg (i+3));
    732 PATH::curve (env, param, pt1, pt2, pt3);
    733 
    734 pt1 = pt3;
    735 pt1.move_y (env.eval_arg (i+4));
    736 pt2 = pt1;
    737 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
    738 pt3 = pt2;
    739 pt3.move_x (env.eval_arg (i+7));
    740 if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0))
    741   pt3.move_y (env.eval_arg (i+8));
    742 PATH::curve (env, param, pt1, pt2, pt3);
    743      }
    744    }
    745  }
    746 
    747  /* default actions to be overridden */
    748  static void moveto (ENV &env, PARAM& param, const point_t &pt)
    749  { env.moveto (pt); }
    750 
    751  static void line (ENV &env, PARAM& param, const point_t &pt1)
    752  { PATH::moveto (env, param, pt1); }
    753 
    754  static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
    755  { PATH::moveto (env, param, pt3); }
    756 
    757  static void hflex (ENV &env, PARAM& param)
    758  {
    759    if (likely (env.argStack.get_count () == 7))
    760    {
    761      point_t pt1 = env.get_pt ();
    762      pt1.move_x (env.eval_arg (0));
    763      point_t pt2 = pt1;
    764      pt2.move (env.eval_arg (1), env.eval_arg (2));
    765      point_t pt3 = pt2;
    766      pt3.move_x (env.eval_arg (3));
    767      point_t pt4 = pt3;
    768      pt4.move_x (env.eval_arg (4));
    769      point_t pt5 = pt4;
    770      pt5.move_x (env.eval_arg (5));
    771      pt5.y = pt1.y;
    772      point_t pt6 = pt5;
    773      pt6.move_x (env.eval_arg (6));
    774 
    775      curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
    776    }
    777    else
    778      env.set_error ();
    779  }
    780 
    781  static void flex (ENV &env, PARAM& param)
    782  {
    783    if (likely (env.argStack.get_count () == 13))
    784    {
    785      point_t pt1 = env.get_pt ();
    786      pt1.move (env.eval_arg (0), env.eval_arg (1));
    787      point_t pt2 = pt1;
    788      pt2.move (env.eval_arg (2), env.eval_arg (3));
    789      point_t pt3 = pt2;
    790      pt3.move (env.eval_arg (4), env.eval_arg (5));
    791      point_t pt4 = pt3;
    792      pt4.move (env.eval_arg (6), env.eval_arg (7));
    793      point_t pt5 = pt4;
    794      pt5.move (env.eval_arg (8), env.eval_arg (9));
    795      point_t pt6 = pt5;
    796      pt6.move (env.eval_arg (10), env.eval_arg (11));
    797 
    798      curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
    799    }
    800    else
    801      env.set_error ();
    802  }
    803 
    804  static void hflex1 (ENV &env, PARAM& param)
    805  {
    806    if (likely (env.argStack.get_count () == 9))
    807    {
    808      point_t pt1 = env.get_pt ();
    809      pt1.move (env.eval_arg (0), env.eval_arg (1));
    810      point_t pt2 = pt1;
    811      pt2.move (env.eval_arg (2), env.eval_arg (3));
    812      point_t pt3 = pt2;
    813      pt3.move_x (env.eval_arg (4));
    814      point_t pt4 = pt3;
    815      pt4.move_x (env.eval_arg (5));
    816      point_t pt5 = pt4;
    817      pt5.move (env.eval_arg (6), env.eval_arg (7));
    818      point_t pt6 = pt5;
    819      pt6.move_x (env.eval_arg (8));
    820      pt6.y = env.get_pt ().y;
    821 
    822      curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
    823    }
    824    else
    825      env.set_error ();
    826  }
    827 
    828  static void flex1 (ENV &env, PARAM& param)
    829  {
    830    if (likely (env.argStack.get_count () == 11))
    831    {
    832      point_t d;
    833      for (unsigned int i = 0; i < 10; i += 2)
    834 d.move (env.eval_arg (i), env.eval_arg (i+1));
    835 
    836      point_t pt1 = env.get_pt ();
    837      pt1.move (env.eval_arg (0), env.eval_arg (1));
    838      point_t pt2 = pt1;
    839      pt2.move (env.eval_arg (2), env.eval_arg (3));
    840      point_t pt3 = pt2;
    841      pt3.move (env.eval_arg (4), env.eval_arg (5));
    842      point_t pt4 = pt3;
    843      pt4.move (env.eval_arg (6), env.eval_arg (7));
    844      point_t pt5 = pt4;
    845      pt5.move (env.eval_arg (8), env.eval_arg (9));
    846      point_t pt6 = pt5;
    847 
    848      if (fabs (d.x.to_real ()) > fabs (d.y.to_real ()))
    849      {
    850 pt6.move_x (env.eval_arg (10));
    851 pt6.y = env.get_pt ().y;
    852      }
    853      else
    854      {
    855 pt6.x = env.get_pt ().x;
    856 pt6.move_y (env.eval_arg (10));
    857      }
    858 
    859      curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
    860    }
    861    else
    862      env.set_error ();
    863  }
    864 
    865  protected:
    866  static void curve2 (ENV &env, PARAM& param,
    867 	      const point_t &pt1, const point_t &pt2, const point_t &pt3,
    868 	      const point_t &pt4, const point_t &pt5, const point_t &pt6)
    869  {
    870    PATH::curve (env, param, pt1, pt2, pt3);
    871    PATH::curve (env, param, pt4, pt5, pt6);
    872  }
    873 };
    874 
    875 template <typename ENV, typename OPSET, typename PARAM>
    876 struct cs_interpreter_t : interpreter_t<ENV>
    877 {
    878  cs_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {}
    879 
    880  bool interpret (PARAM& param)
    881  {
    882    SUPER::env.set_endchar (false);
    883 
    884    unsigned max_ops = HB_CFF_MAX_OPS;
    885    for (;;) {
    886      OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
    887      if (unlikely (SUPER::env.in_error () || !--max_ops))
    888      {
    889 SUPER::env.set_error ();
    890 return false;
    891      }
    892      if (SUPER::env.is_endchar ())
    893 break;
    894    }
    895 
    896    return true;
    897  }
    898 
    899  private:
    900  typedef interpreter_t<ENV> SUPER;
    901 };
    902 
    903 } /* namespace CFF */
    904 
    905 #endif /* HB_CFF_INTERP_CS_COMMON_HH */