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 : cff_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 ? subrs->count : 0; }
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 || 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 
pop_subr_numCFF::cs_interp_env_t150   bool pop_subr_num (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num)
151   {
152     subr_num = 0;
153     int n = SUPER::argStack.pop_int ();
154     n += biasedSubrs.get_bias ();
155     if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ())))
156       return false;
157 
158     subr_num = (unsigned int)n;
159     return true;
160   }
161 
call_subrCFF::cs_interp_env_t162   void call_subr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type)
163   {
164     unsigned int subr_num = 0;
165 
166     if (unlikely (!pop_subr_num (biasedSubrs, subr_num)
167 		 || callStack.get_count () >= kMaxCallLimit))
168     {
169       SUPER::set_error ();
170       return;
171     }
172     context.str_ref = SUPER::str_ref;
173     callStack.push (context);
174 
175     context.init ( biasedSubrs[subr_num], type, subr_num);
176     SUPER::str_ref = context.str_ref;
177   }
178 
return_from_subrCFF::cs_interp_env_t179   void return_from_subr ()
180   {
181     if (unlikely (SUPER::str_ref.in_error ()))
182       SUPER::set_error ();
183     context = callStack.pop ();
184     SUPER::str_ref = context.str_ref;
185   }
186 
determine_hintmask_sizeCFF::cs_interp_env_t187   void determine_hintmask_size ()
188   {
189     if (!seen_hintmask)
190     {
191       vstem_count += SUPER::argStack.get_count() / 2;
192       hintmask_size = (hstem_count + vstem_count + 7) >> 3;
193       seen_hintmask = true;
194     }
195   }
196 
set_endcharCFF::cs_interp_env_t197   void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; }
is_endcharCFF::cs_interp_env_t198   bool is_endchar () const { return endchar_flag; }
199 
get_xCFF::cs_interp_env_t200   const number_t &get_x () const { return pt.x; }
get_yCFF::cs_interp_env_t201   const number_t &get_y () const { return pt.y; }
get_ptCFF::cs_interp_env_t202   const point_t &get_pt () const { return pt; }
203 
movetoCFF::cs_interp_env_t204   void moveto (const point_t &pt_ ) { pt = pt_; }
205 
206   public:
207   call_context_t   context;
208   bool	  endchar_flag;
209   bool	  seen_moveto;
210   bool	  seen_hintmask;
211 
212   unsigned int  hstem_count;
213   unsigned int  vstem_count;
214   unsigned int  hintmask_size;
215   call_stack_t	callStack;
216   biased_subrs_t<SUBRS>   globalSubrs;
217   biased_subrs_t<SUBRS>   localSubrs;
218 
219   private:
220   point_t	 pt;
221 
222   typedef interp_env_t<ARG> SUPER;
223 };
224 
225 template <typename ENV, typename PARAM>
226 struct path_procs_null_t
227 {
rmovetoCFF::path_procs_null_t228   static void rmoveto (ENV &env, PARAM& param) {}
hmovetoCFF::path_procs_null_t229   static void hmoveto (ENV &env, PARAM& param) {}
vmovetoCFF::path_procs_null_t230   static void vmoveto (ENV &env, PARAM& param) {}
rlinetoCFF::path_procs_null_t231   static void rlineto (ENV &env, PARAM& param) {}
hlinetoCFF::path_procs_null_t232   static void hlineto (ENV &env, PARAM& param) {}
vlinetoCFF::path_procs_null_t233   static void vlineto (ENV &env, PARAM& param) {}
rrcurvetoCFF::path_procs_null_t234   static void rrcurveto (ENV &env, PARAM& param) {}
rcurvelineCFF::path_procs_null_t235   static void rcurveline (ENV &env, PARAM& param) {}
rlinecurveCFF::path_procs_null_t236   static void rlinecurve (ENV &env, PARAM& param) {}
vvcurvetoCFF::path_procs_null_t237   static void vvcurveto (ENV &env, PARAM& param) {}
hhcurvetoCFF::path_procs_null_t238   static void hhcurveto (ENV &env, PARAM& param) {}
vhcurvetoCFF::path_procs_null_t239   static void vhcurveto (ENV &env, PARAM& param) {}
hvcurvetoCFF::path_procs_null_t240   static void hvcurveto (ENV &env, PARAM& param) {}
movetoCFF::path_procs_null_t241   static void moveto (ENV &env, PARAM& param, const point_t &pt) {}
lineCFF::path_procs_null_t242   static void line (ENV &env, PARAM& param, const point_t &pt1) {}
curveCFF::path_procs_null_t243   static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) {}
hflexCFF::path_procs_null_t244   static void hflex (ENV &env, PARAM& param) {}
flexCFF::path_procs_null_t245   static void flex (ENV &env, PARAM& param) {}
hflex1CFF::path_procs_null_t246   static void hflex1 (ENV &env, PARAM& param) {}
flex1CFF::path_procs_null_t247   static void flex1 (ENV &env, PARAM& param) {}
248 };
249 
250 template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM>>
251 struct cs_opset_t : opset_t<ARG>
252 {
process_opCFF::cs_opset_t253   static void process_op (op_code_t op, ENV &env, PARAM& param)
254   {
255     switch (op) {
256 
257       case OpCode_return:
258 	env.return_from_subr ();
259 	break;
260       case OpCode_endchar:
261 	OPSET::check_width (op, env, param);
262 	env.set_endchar (true);
263 	OPSET::flush_args_and_op (op, env, param);
264 	break;
265 
266       case OpCode_fixedcs:
267 	env.argStack.push_fixed_from_substr (env.str_ref);
268 	break;
269 
270       case OpCode_callsubr:
271 	env.call_subr (env.localSubrs, CSType_LocalSubr);
272 	break;
273 
274       case OpCode_callgsubr:
275 	env.call_subr (env.globalSubrs, CSType_GlobalSubr);
276 	break;
277 
278       case OpCode_hstem:
279       case OpCode_hstemhm:
280 	OPSET::check_width (op, env, param);
281 	OPSET::process_hstem (op, env, param);
282 	break;
283       case OpCode_vstem:
284       case OpCode_vstemhm:
285 	OPSET::check_width (op, env, param);
286 	OPSET::process_vstem (op, env, param);
287 	break;
288       case OpCode_hintmask:
289       case OpCode_cntrmask:
290 	OPSET::check_width (op, env, param);
291 	OPSET::process_hintmask (op, env, param);
292 	break;
293       case OpCode_rmoveto:
294 	OPSET::check_width (op, env, param);
295 	PATH::rmoveto (env, param);
296 	OPSET::process_post_move (op, env, param);
297 	break;
298       case OpCode_hmoveto:
299 	OPSET::check_width (op, env, param);
300 	PATH::hmoveto (env, param);
301 	OPSET::process_post_move (op, env, param);
302 	break;
303       case OpCode_vmoveto:
304 	OPSET::check_width (op, env, param);
305 	PATH::vmoveto (env, param);
306 	OPSET::process_post_move (op, env, param);
307 	break;
308       case OpCode_rlineto:
309 	PATH::rlineto (env, param);
310 	process_post_path (op, env, param);
311 	break;
312       case OpCode_hlineto:
313 	PATH::hlineto (env, param);
314 	process_post_path (op, env, param);
315 	break;
316       case OpCode_vlineto:
317 	PATH::vlineto (env, param);
318 	process_post_path (op, env, param);
319 	break;
320       case OpCode_rrcurveto:
321 	PATH::rrcurveto (env, param);
322 	process_post_path (op, env, param);
323 	break;
324       case OpCode_rcurveline:
325 	PATH::rcurveline (env, param);
326 	process_post_path (op, env, param);
327 	break;
328       case OpCode_rlinecurve:
329 	PATH::rlinecurve (env, param);
330 	process_post_path (op, env, param);
331 	break;
332       case OpCode_vvcurveto:
333 	PATH::vvcurveto (env, param);
334 	process_post_path (op, env, param);
335 	break;
336       case OpCode_hhcurveto:
337 	PATH::hhcurveto (env, param);
338 	process_post_path (op, env, param);
339 	break;
340       case OpCode_vhcurveto:
341 	PATH::vhcurveto (env, param);
342 	process_post_path (op, env, param);
343 	break;
344       case OpCode_hvcurveto:
345 	PATH::hvcurveto (env, param);
346 	process_post_path (op, env, param);
347 	break;
348 
349       case OpCode_hflex:
350 	PATH::hflex (env, param);
351 	OPSET::process_post_flex (op, env, param);
352 	break;
353 
354       case OpCode_flex:
355 	PATH::flex (env, param);
356 	OPSET::process_post_flex (op, env, param);
357 	break;
358 
359       case OpCode_hflex1:
360 	PATH::hflex1 (env, param);
361 	OPSET::process_post_flex (op, env, param);
362 	break;
363 
364       case OpCode_flex1:
365 	PATH::flex1 (env, param);
366 	OPSET::process_post_flex (op, env, param);
367 	break;
368 
369       default:
370 	SUPER::process_op (op, env);
371 	break;
372     }
373   }
374 
process_hstemCFF::cs_opset_t375   static void process_hstem (op_code_t op, ENV &env, PARAM& param)
376   {
377     env.hstem_count += env.argStack.get_count () / 2;
378     OPSET::flush_args_and_op (op, env, param);
379   }
380 
process_vstemCFF::cs_opset_t381   static void process_vstem (op_code_t op, ENV &env, PARAM& param)
382   {
383     env.vstem_count += env.argStack.get_count () / 2;
384     OPSET::flush_args_and_op (op, env, param);
385   }
386 
process_hintmaskCFF::cs_opset_t387   static void process_hintmask (op_code_t op, ENV &env, PARAM& param)
388   {
389     env.determine_hintmask_size ();
390     if (likely (env.str_ref.avail (env.hintmask_size)))
391     {
392       OPSET::flush_hintmask (op, env, param);
393       env.str_ref.inc (env.hintmask_size);
394     }
395   }
396 
process_post_flexCFF::cs_opset_t397   static void process_post_flex (op_code_t op, ENV &env, PARAM& param)
398   {
399     OPSET::flush_args_and_op (op, env, param);
400   }
401 
check_widthCFF::cs_opset_t402   static void check_width (op_code_t op, ENV &env, PARAM& param)
403   {}
404 
process_post_moveCFF::cs_opset_t405   static void process_post_move (op_code_t op, ENV &env, PARAM& param)
406   {
407     if (!env.seen_moveto)
408     {
409       env.determine_hintmask_size ();
410       env.seen_moveto = true;
411     }
412     OPSET::flush_args_and_op (op, env, param);
413   }
414 
process_post_pathCFF::cs_opset_t415   static void process_post_path (op_code_t op, ENV &env, PARAM& param)
416   {
417     OPSET::flush_args_and_op (op, env, param);
418   }
419 
flush_args_and_opCFF::cs_opset_t420   static void flush_args_and_op (op_code_t op, ENV &env, PARAM& param)
421   {
422     OPSET::flush_args (env, param);
423     OPSET::flush_op (op, env, param);
424   }
425 
flush_argsCFF::cs_opset_t426   static void flush_args (ENV &env, PARAM& param)
427   {
428     env.pop_n_args (env.argStack.get_count ());
429   }
430 
flush_opCFF::cs_opset_t431   static void flush_op (op_code_t op, ENV &env, PARAM& param)
432   {
433   }
434 
flush_hintmaskCFF::cs_opset_t435   static void flush_hintmask (op_code_t op, ENV &env, PARAM& param)
436   {
437     OPSET::flush_args_and_op (op, env, param);
438   }
439 
is_number_opCFF::cs_opset_t440   static bool is_number_op (op_code_t op)
441   {
442     switch (op)
443     {
444       case OpCode_shortint:
445       case OpCode_fixedcs:
446       case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1:
447       case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3:
448       case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
449       case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
450 	return true;
451 
452       default:
453 	/* 1-byte integer */
454 	return (OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast);
455     }
456   }
457 
458   protected:
459   typedef opset_t<ARG>  SUPER;
460 };
461 
462 template <typename PATH, typename ENV, typename PARAM>
463 struct path_procs_t
464 {
rmovetoCFF::path_procs_t465   static void rmoveto (ENV &env, PARAM& param)
466   {
467     point_t pt1 = env.get_pt ();
468     const number_t &dy = env.pop_arg ();
469     const number_t &dx = env.pop_arg ();
470     pt1.move (dx, dy);
471     PATH::moveto (env, param, pt1);
472   }
473 
hmovetoCFF::path_procs_t474   static void hmoveto (ENV &env, PARAM& param)
475   {
476     point_t pt1 = env.get_pt ();
477     pt1.move_x (env.pop_arg ());
478     PATH::moveto (env, param, pt1);
479   }
480 
vmovetoCFF::path_procs_t481   static void vmoveto (ENV &env, PARAM& param)
482   {
483     point_t pt1 = env.get_pt ();
484     pt1.move_y (env.pop_arg ());
485     PATH::moveto (env, param, pt1);
486   }
487 
rlinetoCFF::path_procs_t488   static void rlineto (ENV &env, PARAM& param)
489   {
490     for (unsigned int i = 0; i + 2 <= env.argStack.get_count (); i += 2)
491     {
492       point_t pt1 = env.get_pt ();
493       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
494       PATH::line (env, param, pt1);
495     }
496   }
497 
hlinetoCFF::path_procs_t498   static void hlineto (ENV &env, PARAM& param)
499   {
500     point_t pt1;
501     unsigned int i = 0;
502     for (; i + 2 <= env.argStack.get_count (); i += 2)
503     {
504       pt1 = env.get_pt ();
505       pt1.move_x (env.eval_arg (i));
506       PATH::line (env, param, pt1);
507       pt1.move_y (env.eval_arg (i+1));
508       PATH::line (env, param, pt1);
509     }
510     if (i < env.argStack.get_count ())
511     {
512       pt1 = env.get_pt ();
513       pt1.move_x (env.eval_arg (i));
514       PATH::line (env, param, pt1);
515     }
516   }
517 
vlinetoCFF::path_procs_t518   static void vlineto (ENV &env, PARAM& param)
519   {
520     point_t pt1;
521     unsigned int i = 0;
522     for (; i + 2 <= env.argStack.get_count (); i += 2)
523     {
524       pt1 = env.get_pt ();
525       pt1.move_y (env.eval_arg (i));
526       PATH::line (env, param, pt1);
527       pt1.move_x (env.eval_arg (i+1));
528       PATH::line (env, param, pt1);
529     }
530     if (i < env.argStack.get_count ())
531     {
532       pt1 = env.get_pt ();
533       pt1.move_y (env.eval_arg (i));
534       PATH::line (env, param, pt1);
535     }
536   }
537 
rrcurvetoCFF::path_procs_t538   static void rrcurveto (ENV &env, PARAM& param)
539   {
540     for (unsigned int i = 0; i + 6 <= env.argStack.get_count (); i += 6)
541     {
542       point_t pt1 = env.get_pt ();
543       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
544       point_t pt2 = pt1;
545       pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
546       point_t pt3 = pt2;
547       pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
548       PATH::curve (env, param, pt1, pt2, pt3);
549     }
550   }
551 
rcurvelineCFF::path_procs_t552   static void rcurveline (ENV &env, PARAM& param)
553   {
554     unsigned int arg_count = env.argStack.get_count ();
555     if (unlikely (arg_count < 8))
556       return;
557 
558     unsigned int i = 0;
559     unsigned int curve_limit = arg_count - 2;
560     for (; i + 6 <= curve_limit; i += 6)
561     {
562       point_t pt1 = env.get_pt ();
563       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
564       point_t pt2 = pt1;
565       pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
566       point_t pt3 = pt2;
567       pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
568       PATH::curve (env, param, pt1, pt2, pt3);
569     }
570 
571     point_t pt1 = env.get_pt ();
572     pt1.move (env.eval_arg (i), env.eval_arg (i+1));
573     PATH::line (env, param, pt1);
574   }
575 
rlinecurveCFF::path_procs_t576   static void rlinecurve (ENV &env, PARAM& param)
577   {
578     unsigned int arg_count = env.argStack.get_count ();
579     if (unlikely (arg_count < 8))
580       return;
581 
582     unsigned int i = 0;
583     unsigned int line_limit = arg_count - 6;
584     for (; i + 2 <= line_limit; i += 2)
585     {
586       point_t pt1 = env.get_pt ();
587       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
588       PATH::line (env, param, pt1);
589     }
590 
591     point_t pt1 = env.get_pt ();
592     pt1.move (env.eval_arg (i), env.eval_arg (i+1));
593     point_t pt2 = pt1;
594     pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
595     point_t pt3 = pt2;
596     pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
597     PATH::curve (env, param, pt1, pt2, pt3);
598   }
599 
vvcurvetoCFF::path_procs_t600   static void vvcurveto (ENV &env, PARAM& param)
601   {
602     unsigned int i = 0;
603     point_t pt1 = env.get_pt ();
604     if ((env.argStack.get_count () & 1) != 0)
605       pt1.move_x (env.eval_arg (i++));
606     for (; i + 4 <= env.argStack.get_count (); i += 4)
607     {
608       pt1.move_y (env.eval_arg (i));
609       point_t pt2 = pt1;
610       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
611       point_t pt3 = pt2;
612       pt3.move_y (env.eval_arg (i+3));
613       PATH::curve (env, param, pt1, pt2, pt3);
614       pt1 = env.get_pt ();
615     }
616   }
617 
hhcurvetoCFF::path_procs_t618   static void hhcurveto (ENV &env, PARAM& param)
619   {
620     unsigned int i = 0;
621     point_t pt1 = env.get_pt ();
622     if ((env.argStack.get_count () & 1) != 0)
623       pt1.move_y (env.eval_arg (i++));
624     for (; i + 4 <= env.argStack.get_count (); i += 4)
625     {
626       pt1.move_x (env.eval_arg (i));
627       point_t pt2 = pt1;
628       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
629       point_t pt3 = pt2;
630       pt3.move_x (env.eval_arg (i+3));
631       PATH::curve (env, param, pt1, pt2, pt3);
632       pt1 = env.get_pt ();
633     }
634   }
635 
vhcurvetoCFF::path_procs_t636   static void vhcurveto (ENV &env, PARAM& param)
637   {
638     point_t pt1, pt2, pt3;
639     unsigned int i = 0;
640     if ((env.argStack.get_count () % 8) >= 4)
641     {
642       point_t pt1 = env.get_pt ();
643       pt1.move_y (env.eval_arg (i));
644       point_t pt2 = pt1;
645       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
646       point_t pt3 = pt2;
647       pt3.move_x (env.eval_arg (i+3));
648       i += 4;
649 
650       for (; i + 8 <= env.argStack.get_count (); i += 8)
651       {
652 	PATH::curve (env, param, pt1, pt2, pt3);
653 	pt1 = env.get_pt ();
654 	pt1.move_x (env.eval_arg (i));
655 	pt2 = pt1;
656 	pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
657 	pt3 = pt2;
658 	pt3.move_y (env.eval_arg (i+3));
659 	PATH::curve (env, param, pt1, pt2, pt3);
660 
661 	pt1 = pt3;
662 	pt1.move_y (env.eval_arg (i+4));
663 	pt2 = pt1;
664 	pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
665 	pt3 = pt2;
666 	pt3.move_x (env.eval_arg (i+7));
667       }
668       if (i < env.argStack.get_count ())
669 	pt3.move_y (env.eval_arg (i));
670       PATH::curve (env, param, pt1, pt2, pt3);
671     }
672     else
673     {
674       for (; i + 8 <= env.argStack.get_count (); i += 8)
675       {
676 	pt1 = env.get_pt ();
677 	pt1.move_y (env.eval_arg (i));
678 	pt2 = pt1;
679 	pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
680 	pt3 = pt2;
681 	pt3.move_x (env.eval_arg (i+3));
682 	PATH::curve (env, param, pt1, pt2, pt3);
683 
684 	pt1 = pt3;
685 	pt1.move_x (env.eval_arg (i+4));
686 	pt2 = pt1;
687 	pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
688 	pt3 = pt2;
689 	pt3.move_y (env.eval_arg (i+7));
690 	if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0))
691 	  pt3.move_x (env.eval_arg (i+8));
692 	PATH::curve (env, param, pt1, pt2, pt3);
693       }
694     }
695   }
696 
hvcurvetoCFF::path_procs_t697   static void hvcurveto (ENV &env, PARAM& param)
698   {
699     point_t pt1, pt2, pt3;
700     unsigned int i = 0;
701     if ((env.argStack.get_count () % 8) >= 4)
702     {
703       point_t pt1 = env.get_pt ();
704       pt1.move_x (env.eval_arg (i));
705       point_t pt2 = pt1;
706       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
707       point_t pt3 = pt2;
708       pt3.move_y (env.eval_arg (i+3));
709       i += 4;
710 
711       for (; i + 8 <= env.argStack.get_count (); i += 8)
712       {
713 	PATH::curve (env, param, pt1, pt2, pt3);
714 	pt1 = env.get_pt ();
715 	pt1.move_y (env.eval_arg (i));
716 	pt2 = pt1;
717 	pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
718 	pt3 = pt2;
719 	pt3.move_x (env.eval_arg (i+3));
720 	PATH::curve (env, param, pt1, pt2, pt3);
721 
722 	pt1 = pt3;
723 	pt1.move_x (env.eval_arg (i+4));
724 	pt2 = pt1;
725 	pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
726 	pt3 = pt2;
727 	pt3.move_y (env.eval_arg (i+7));
728       }
729       if (i < env.argStack.get_count ())
730 	pt3.move_x (env.eval_arg (i));
731       PATH::curve (env, param, pt1, pt2, pt3);
732     }
733     else
734     {
735       for (; i + 8 <= env.argStack.get_count (); i += 8)
736       {
737 	pt1 = env.get_pt ();
738 	pt1.move_x (env.eval_arg (i));
739 	pt2 = pt1;
740 	pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
741 	pt3 = pt2;
742 	pt3.move_y (env.eval_arg (i+3));
743 	PATH::curve (env, param, pt1, pt2, pt3);
744 
745 	pt1 = pt3;
746 	pt1.move_y (env.eval_arg (i+4));
747 	pt2 = pt1;
748 	pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
749 	pt3 = pt2;
750 	pt3.move_x (env.eval_arg (i+7));
751 	if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0))
752 	  pt3.move_y (env.eval_arg (i+8));
753 	PATH::curve (env, param, pt1, pt2, pt3);
754       }
755     }
756   }
757 
758   /* default actions to be overridden */
movetoCFF::path_procs_t759   static void moveto (ENV &env, PARAM& param, const point_t &pt)
760   { env.moveto (pt); }
761 
lineCFF::path_procs_t762   static void line (ENV &env, PARAM& param, const point_t &pt1)
763   { PATH::moveto (env, param, pt1); }
764 
curveCFF::path_procs_t765   static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
766   { PATH::moveto (env, param, pt3); }
767 
hflexCFF::path_procs_t768   static void hflex (ENV &env, PARAM& param)
769   {
770     if (likely (env.argStack.get_count () == 7))
771     {
772       point_t pt1 = env.get_pt ();
773       pt1.move_x (env.eval_arg (0));
774       point_t pt2 = pt1;
775       pt2.move (env.eval_arg (1), env.eval_arg (2));
776       point_t pt3 = pt2;
777       pt3.move_x (env.eval_arg (3));
778       point_t pt4 = pt3;
779       pt4.move_x (env.eval_arg (4));
780       point_t pt5 = pt4;
781       pt5.move_x (env.eval_arg (5));
782       pt5.y = pt1.y;
783       point_t pt6 = pt5;
784       pt6.move_x (env.eval_arg (6));
785 
786       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
787     }
788     else
789       env.set_error ();
790   }
791 
flexCFF::path_procs_t792   static void flex (ENV &env, PARAM& param)
793   {
794     if (likely (env.argStack.get_count () == 13))
795     {
796       point_t pt1 = env.get_pt ();
797       pt1.move (env.eval_arg (0), env.eval_arg (1));
798       point_t pt2 = pt1;
799       pt2.move (env.eval_arg (2), env.eval_arg (3));
800       point_t pt3 = pt2;
801       pt3.move (env.eval_arg (4), env.eval_arg (5));
802       point_t pt4 = pt3;
803       pt4.move (env.eval_arg (6), env.eval_arg (7));
804       point_t pt5 = pt4;
805       pt5.move (env.eval_arg (8), env.eval_arg (9));
806       point_t pt6 = pt5;
807       pt6.move (env.eval_arg (10), env.eval_arg (11));
808 
809       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
810     }
811     else
812       env.set_error ();
813   }
814 
hflex1CFF::path_procs_t815   static void hflex1 (ENV &env, PARAM& param)
816   {
817     if (likely (env.argStack.get_count () == 9))
818     {
819       point_t pt1 = env.get_pt ();
820       pt1.move (env.eval_arg (0), env.eval_arg (1));
821       point_t pt2 = pt1;
822       pt2.move (env.eval_arg (2), env.eval_arg (3));
823       point_t pt3 = pt2;
824       pt3.move_x (env.eval_arg (4));
825       point_t pt4 = pt3;
826       pt4.move_x (env.eval_arg (5));
827       point_t pt5 = pt4;
828       pt5.move (env.eval_arg (6), env.eval_arg (7));
829       point_t pt6 = pt5;
830       pt6.move_x (env.eval_arg (8));
831       pt6.y = env.get_pt ().y;
832 
833       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
834     }
835     else
836       env.set_error ();
837   }
838 
flex1CFF::path_procs_t839   static void flex1 (ENV &env, PARAM& param)
840   {
841     if (likely (env.argStack.get_count () == 11))
842     {
843       point_t d;
844       d.init ();
845       for (unsigned int i = 0; i < 10; i += 2)
846 	d.move (env.eval_arg (i), env.eval_arg (i+1));
847 
848       point_t pt1 = env.get_pt ();
849       pt1.move (env.eval_arg (0), env.eval_arg (1));
850       point_t pt2 = pt1;
851       pt2.move (env.eval_arg (2), env.eval_arg (3));
852       point_t pt3 = pt2;
853       pt3.move (env.eval_arg (4), env.eval_arg (5));
854       point_t pt4 = pt3;
855       pt4.move (env.eval_arg (6), env.eval_arg (7));
856       point_t pt5 = pt4;
857       pt5.move (env.eval_arg (8), env.eval_arg (9));
858       point_t pt6 = pt5;
859 
860       if (fabs (d.x.to_real ()) > fabs (d.y.to_real ()))
861       {
862 	pt6.move_x (env.eval_arg (10));
863 	pt6.y = env.get_pt ().y;
864       }
865       else
866       {
867 	pt6.x = env.get_pt ().x;
868 	pt6.move_y (env.eval_arg (10));
869       }
870 
871       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
872     }
873     else
874       env.set_error ();
875   }
876 
877   protected:
curve2CFF::path_procs_t878   static void curve2 (ENV &env, PARAM& param,
879 		      const point_t &pt1, const point_t &pt2, const point_t &pt3,
880 		      const point_t &pt4, const point_t &pt5, const point_t &pt6)
881   {
882     PATH::curve (env, param, pt1, pt2, pt3);
883     PATH::curve (env, param, pt4, pt5, pt6);
884   }
885 };
886 
887 template <typename ENV, typename OPSET, typename PARAM>
888 struct cs_interpreter_t : interpreter_t<ENV>
889 {
interpretCFF::cs_interpreter_t890   bool interpret (PARAM& param)
891   {
892     SUPER::env.set_endchar (false);
893 
894     for (;;) {
895       OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
896       if (unlikely (SUPER::env.in_error ()))
897 	return false;
898       if (SUPER::env.is_endchar ())
899 	break;
900     }
901 
902     return true;
903   }
904 
905   private:
906   typedef interpreter_t<ENV> SUPER;
907 };
908 
909 } /* namespace CFF */
910 
911 #endif /* HB_CFF_INTERP_CS_COMMON_HH */
912