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