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 {
initCFF::call_context_t44   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 
finiCFF::call_context_t51   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 {
initCFF::biased_subrs_t65   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 
finiCFF::biased_subrs_t77   void fini () {}
78 
get_countCFF::biased_subrs_t79   unsigned int get_count () const { return (subrs == nullptr)? 0: subrs->count; }
get_biasCFF::biased_subrs_t80   unsigned int get_bias () const { return bias; }
81 
operator []CFF::biased_subrs_t82   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 {
initCFF::point_t97   void init ()
98   {
99     x.init ();
100     y.init ();
101   }
102 
set_intCFF::point_t103   void set_int (int _x, int _y)
104   {
105     x.set_int (_x);
106     y.set_int (_y);
107   }
108 
move_xCFF::point_t109   void move_x (const number_t &dx) { x += dx; }
move_yCFF::point_t110   void move_y (const number_t &dy) { y += dy; }
moveCFF::point_t111   void move (const number_t &dx, const number_t &dy) { move_x (dx); move_y (dy); }
moveCFF::point_t112   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 {
initCFF::cs_interp_env_t121   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   }
finiCFF::cs_interp_env_t136   void fini ()
137   {
138     interp_env_t<ARG>::fini ();
139 
140     callStack.fini ();
141     globalSubrs.fini ();
142     localSubrs.fini ();
143   }
144 
in_errorCFF::cs_interp_env_t145   bool in_error () const
146   {
147     return callStack.in_error () || SUPER::in_error ();
148   }
149 
popSubrNumCFF::cs_interp_env_t150   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 
callSubrCFF::cs_interp_env_t161   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 
returnFromSubrCFF::cs_interp_env_t178   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 
determine_hintmask_sizeCFF::cs_interp_env_t186   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 
set_endcharCFF::cs_interp_env_t196   void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; }
is_endcharCFF::cs_interp_env_t197   bool is_endchar () const { return endchar_flag; }
198 
get_xCFF::cs_interp_env_t199   const number_t &get_x () const { return pt.x; }
get_yCFF::cs_interp_env_t200   const number_t &get_y () const { return pt.y; }
get_ptCFF::cs_interp_env_t201   const point_t &get_pt () const { return pt; }
202 
movetoCFF::cs_interp_env_t203   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 {
rmovetoCFF::path_procs_null_t227   static void rmoveto (ENV &env, PARAM& param) {}
hmovetoCFF::path_procs_null_t228   static void hmoveto (ENV &env, PARAM& param) {}
vmovetoCFF::path_procs_null_t229   static void vmoveto (ENV &env, PARAM& param) {}
rlinetoCFF::path_procs_null_t230   static void rlineto (ENV &env, PARAM& param) {}
hlinetoCFF::path_procs_null_t231   static void hlineto (ENV &env, PARAM& param) {}
vlinetoCFF::path_procs_null_t232   static void vlineto (ENV &env, PARAM& param) {}
rrcurvetoCFF::path_procs_null_t233   static void rrcurveto (ENV &env, PARAM& param) {}
rcurvelineCFF::path_procs_null_t234   static void rcurveline (ENV &env, PARAM& param) {}
rlinecurveCFF::path_procs_null_t235   static void rlinecurve (ENV &env, PARAM& param) {}
vvcurvetoCFF::path_procs_null_t236   static void vvcurveto (ENV &env, PARAM& param) {}
hhcurvetoCFF::path_procs_null_t237   static void hhcurveto (ENV &env, PARAM& param) {}
vhcurvetoCFF::path_procs_null_t238   static void vhcurveto (ENV &env, PARAM& param) {}
hvcurvetoCFF::path_procs_null_t239   static void hvcurveto (ENV &env, PARAM& param) {}
movetoCFF::path_procs_null_t240   static void moveto (ENV &env, PARAM& param, const point_t &pt) {}
lineCFF::path_procs_null_t241   static void line (ENV &env, PARAM& param, const point_t &pt1) {}
curveCFF::path_procs_null_t242   static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) {}
hflexCFF::path_procs_null_t243   static void hflex (ENV &env, PARAM& param) {}
flexCFF::path_procs_null_t244   static void flex (ENV &env, PARAM& param) {}
hflex1CFF::path_procs_null_t245   static void hflex1 (ENV &env, PARAM& param) {}
flex1CFF::path_procs_null_t246   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 {
process_opCFF::cs_opset_t252   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 
process_hstemCFF::cs_opset_t374   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 
process_vstemCFF::cs_opset_t380   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 
process_hintmaskCFF::cs_opset_t386   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 
process_post_flexCFF::cs_opset_t396   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 
check_widthCFF::cs_opset_t401   static void check_width (op_code_t op, ENV &env, PARAM& param)
402   {}
403 
process_post_moveCFF::cs_opset_t404   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 
process_post_pathCFF::cs_opset_t414   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 
flush_args_and_opCFF::cs_opset_t419   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 
flush_argsCFF::cs_opset_t425   static void flush_args (ENV &env, PARAM& param)
426   {
427     env.pop_n_args (env.argStack.get_count ());
428   }
429 
flush_opCFF::cs_opset_t430   static void flush_op (op_code_t op, ENV &env, PARAM& param)
431   {
432   }
433 
flush_hintmaskCFF::cs_opset_t434   static void flush_hintmask (op_code_t op, ENV &env, PARAM& param)
435   {
436     OPSET::flush_args_and_op (op, env, param);
437   }
438 
is_number_opCFF::cs_opset_t439   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 {
rmovetoCFF::path_procs_t464   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 
hmovetoCFF::path_procs_t473   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 
vmovetoCFF::path_procs_t480   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 
rlinetoCFF::path_procs_t487   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 
hlinetoCFF::path_procs_t497   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 
vlinetoCFF::path_procs_t517   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 
rrcurvetoCFF::path_procs_t537   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 
rcurvelineCFF::path_procs_t551   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 
rlinecurveCFF::path_procs_t572   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 
vvcurvetoCFF::path_procs_t594   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 
hhcurvetoCFF::path_procs_t612   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 
vhcurvetoCFF::path_procs_t630   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 
hvcurvetoCFF::path_procs_t691   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 */
movetoCFF::path_procs_t753   static void moveto (ENV &env, PARAM& param, const point_t &pt)
754   { env.moveto (pt); }
755 
lineCFF::path_procs_t756   static void line (ENV &env, PARAM& param, const point_t &pt1)
757   { PATH::moveto (env, param, pt1); }
758 
curveCFF::path_procs_t759   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 
hflexCFF::path_procs_t762   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 
flexCFF::path_procs_t786   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 
hflex1CFF::path_procs_t809   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 
flex1CFF::path_procs_t833   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:
curve2CFF::path_procs_t872   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 {
interpretCFF::cs_interpreter_t884   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 */
906