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 == 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 
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 i = 0;
555     for (; i + 6 <= env.argStack.get_count (); i += 6)
556     {
557       point_t pt1 = env.get_pt ();
558       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
559       point_t pt2 = pt1;
560       pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
561       point_t pt3 = pt2;
562       pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
563       PATH::curve (env, param, pt1, pt2, pt3);
564     }
565     for (; i + 2 <= env.argStack.get_count (); i += 2)
566     {
567       point_t pt1 = env.get_pt ();
568       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
569       PATH::line (env, param, pt1);
570     }
571   }
572 
rlinecurveCFF::path_procs_t573   static void rlinecurve (ENV &env, PARAM& param)
574   {
575     unsigned int i = 0;
576     unsigned int line_limit = (env.argStack.get_count () % 6);
577     for (; i + 2 <= line_limit; i += 2)
578     {
579       point_t pt1 = env.get_pt ();
580       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
581       PATH::line (env, param, pt1);
582     }
583     for (; i + 6 <= env.argStack.get_count (); i += 6)
584     {
585       point_t pt1 = env.get_pt ();
586       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
587       point_t pt2 = pt1;
588       pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
589       point_t pt3 = pt2;
590       pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
591       PATH::curve (env, param, pt1, pt2, pt3);
592     }
593   }
594 
vvcurvetoCFF::path_procs_t595   static void vvcurveto (ENV &env, PARAM& param)
596   {
597     unsigned int i = 0;
598     point_t pt1 = env.get_pt ();
599     if ((env.argStack.get_count () & 1) != 0)
600       pt1.move_x (env.eval_arg (i++));
601     for (; i + 4 <= env.argStack.get_count (); i += 4)
602     {
603       pt1.move_y (env.eval_arg (i));
604       point_t pt2 = pt1;
605       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
606       point_t pt3 = pt2;
607       pt3.move_y (env.eval_arg (i+3));
608       PATH::curve (env, param, pt1, pt2, pt3);
609       pt1 = env.get_pt ();
610     }
611   }
612 
hhcurvetoCFF::path_procs_t613   static void hhcurveto (ENV &env, PARAM& param)
614   {
615     unsigned int i = 0;
616     point_t pt1 = env.get_pt ();
617     if ((env.argStack.get_count () & 1) != 0)
618       pt1.move_y (env.eval_arg (i++));
619     for (; i + 4 <= env.argStack.get_count (); i += 4)
620     {
621       pt1.move_x (env.eval_arg (i));
622       point_t pt2 = pt1;
623       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
624       point_t pt3 = pt2;
625       pt3.move_x (env.eval_arg (i+3));
626       PATH::curve (env, param, pt1, pt2, pt3);
627       pt1 = env.get_pt ();
628     }
629   }
630 
vhcurvetoCFF::path_procs_t631   static void vhcurveto (ENV &env, PARAM& param)
632   {
633     point_t pt1, pt2, pt3;
634     unsigned int i = 0;
635     if ((env.argStack.get_count () % 8) >= 4)
636     {
637       point_t pt1 = env.get_pt ();
638       pt1.move_y (env.eval_arg (i));
639       point_t pt2 = pt1;
640       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
641       point_t pt3 = pt2;
642       pt3.move_x (env.eval_arg (i+3));
643       i += 4;
644 
645       for (; i + 8 <= env.argStack.get_count (); i += 8)
646       {
647 	PATH::curve (env, param, pt1, pt2, pt3);
648 	pt1 = env.get_pt ();
649 	pt1.move_x (env.eval_arg (i));
650 	pt2 = pt1;
651 	pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
652 	pt3 = pt2;
653 	pt3.move_y (env.eval_arg (i+3));
654 	PATH::curve (env, param, pt1, pt2, pt3);
655 
656 	pt1 = pt3;
657 	pt1.move_y (env.eval_arg (i+4));
658 	pt2 = pt1;
659 	pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
660 	pt3 = pt2;
661 	pt3.move_x (env.eval_arg (i+7));
662       }
663       if (i < env.argStack.get_count ())
664 	pt3.move_y (env.eval_arg (i));
665       PATH::curve (env, param, pt1, pt2, pt3);
666     }
667     else
668     {
669       for (; i + 8 <= env.argStack.get_count (); i += 8)
670       {
671 	pt1 = env.get_pt ();
672 	pt1.move_y (env.eval_arg (i));
673 	pt2 = pt1;
674 	pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
675 	pt3 = pt2;
676 	pt3.move_x (env.eval_arg (i+3));
677 	PATH::curve (env, param, pt1, pt2, pt3);
678 
679 	pt1 = pt3;
680 	pt1.move_x (env.eval_arg (i+4));
681 	pt2 = pt1;
682 	pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
683 	pt3 = pt2;
684 	pt3.move_y (env.eval_arg (i+7));
685 	if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0))
686 	  pt3.move_x (env.eval_arg (i+8));
687 	PATH::curve (env, param, pt1, pt2, pt3);
688       }
689     }
690   }
691 
hvcurvetoCFF::path_procs_t692   static void hvcurveto (ENV &env, PARAM& param)
693   {
694     point_t pt1, pt2, pt3;
695     unsigned int i = 0;
696     if ((env.argStack.get_count () % 8) >= 4)
697     {
698       point_t pt1 = env.get_pt ();
699       pt1.move_x (env.eval_arg (i));
700       point_t pt2 = pt1;
701       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
702       point_t pt3 = pt2;
703       pt3.move_y (env.eval_arg (i+3));
704       i += 4;
705 
706       for (; i + 8 <= env.argStack.get_count (); i += 8)
707       {
708 	PATH::curve (env, param, pt1, pt2, pt3);
709 	pt1 = env.get_pt ();
710 	pt1.move_y (env.eval_arg (i));
711 	pt2 = pt1;
712 	pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
713 	pt3 = pt2;
714 	pt3.move_x (env.eval_arg (i+3));
715 	PATH::curve (env, param, pt1, pt2, pt3);
716 
717 	pt1 = pt3;
718 	pt1.move_x (env.eval_arg (i+4));
719 	pt2 = pt1;
720 	pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
721 	pt3 = pt2;
722 	pt3.move_y (env.eval_arg (i+7));
723       }
724       if (i < env.argStack.get_count ())
725 	pt3.move_x (env.eval_arg (i));
726       PATH::curve (env, param, pt1, pt2, pt3);
727     }
728     else
729     {
730       for (; i + 8 <= env.argStack.get_count (); i += 8)
731       {
732 	pt1 = env.get_pt ();
733 	pt1.move_x (env.eval_arg (i));
734 	pt2 = pt1;
735 	pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
736 	pt3 = pt2;
737 	pt3.move_y (env.eval_arg (i+3));
738 	PATH::curve (env, param, pt1, pt2, pt3);
739 
740 	pt1 = pt3;
741 	pt1.move_y (env.eval_arg (i+4));
742 	pt2 = pt1;
743 	pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
744 	pt3 = pt2;
745 	pt3.move_x (env.eval_arg (i+7));
746 	if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0))
747 	  pt3.move_y (env.eval_arg (i+8));
748 	PATH::curve (env, param, pt1, pt2, pt3);
749       }
750     }
751   }
752 
753   /* default actions to be overridden */
movetoCFF::path_procs_t754   static void moveto (ENV &env, PARAM& param, const point_t &pt)
755   { env.moveto (pt); }
756 
lineCFF::path_procs_t757   static void line (ENV &env, PARAM& param, const point_t &pt1)
758   { PATH::moveto (env, param, pt1); }
759 
curveCFF::path_procs_t760   static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
761   { PATH::moveto (env, param, pt3); }
762 
hflexCFF::path_procs_t763   static void hflex (ENV &env, PARAM& param)
764   {
765     if (likely (env.argStack.get_count () == 7))
766     {
767       point_t pt1 = env.get_pt ();
768       pt1.move_x (env.eval_arg (0));
769       point_t pt2 = pt1;
770       pt2.move (env.eval_arg (1), env.eval_arg (2));
771       point_t pt3 = pt2;
772       pt3.move_x (env.eval_arg (3));
773       point_t pt4 = pt3;
774       pt4.move_x (env.eval_arg (4));
775       point_t pt5 = pt4;
776       pt5.move_x (env.eval_arg (5));
777       pt5.y = pt1.y;
778       point_t pt6 = pt5;
779       pt6.move_x (env.eval_arg (6));
780 
781       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
782     }
783     else
784       env.set_error ();
785   }
786 
flexCFF::path_procs_t787   static void flex (ENV &env, PARAM& param)
788   {
789     if (likely (env.argStack.get_count () == 13))
790     {
791       point_t pt1 = env.get_pt ();
792       pt1.move (env.eval_arg (0), env.eval_arg (1));
793       point_t pt2 = pt1;
794       pt2.move (env.eval_arg (2), env.eval_arg (3));
795       point_t pt3 = pt2;
796       pt3.move (env.eval_arg (4), env.eval_arg (5));
797       point_t pt4 = pt3;
798       pt4.move (env.eval_arg (6), env.eval_arg (7));
799       point_t pt5 = pt4;
800       pt5.move (env.eval_arg (8), env.eval_arg (9));
801       point_t pt6 = pt5;
802       pt6.move (env.eval_arg (10), env.eval_arg (11));
803 
804       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
805     }
806     else
807       env.set_error ();
808   }
809 
hflex1CFF::path_procs_t810   static void hflex1 (ENV &env, PARAM& param)
811   {
812     if (likely (env.argStack.get_count () == 9))
813     {
814       point_t pt1 = env.get_pt ();
815       pt1.move (env.eval_arg (0), env.eval_arg (1));
816       point_t pt2 = pt1;
817       pt2.move (env.eval_arg (2), env.eval_arg (3));
818       point_t pt3 = pt2;
819       pt3.move_x (env.eval_arg (4));
820       point_t pt4 = pt3;
821       pt4.move_x (env.eval_arg (5));
822       point_t pt5 = pt4;
823       pt5.move (env.eval_arg (6), env.eval_arg (7));
824       point_t pt6 = pt5;
825       pt6.move_x (env.eval_arg (8));
826       pt6.y = env.get_pt ().y;
827 
828       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
829     }
830     else
831       env.set_error ();
832   }
833 
flex1CFF::path_procs_t834   static void flex1 (ENV &env, PARAM& param)
835   {
836     if (likely (env.argStack.get_count () == 11))
837     {
838       point_t d;
839       d.init ();
840       for (unsigned int i = 0; i < 10; i += 2)
841 	d.move (env.eval_arg (i), env.eval_arg (i+1));
842 
843       point_t pt1 = env.get_pt ();
844       pt1.move (env.eval_arg (0), env.eval_arg (1));
845       point_t pt2 = pt1;
846       pt2.move (env.eval_arg (2), env.eval_arg (3));
847       point_t pt3 = pt2;
848       pt3.move (env.eval_arg (4), env.eval_arg (5));
849       point_t pt4 = pt3;
850       pt4.move (env.eval_arg (6), env.eval_arg (7));
851       point_t pt5 = pt4;
852       pt5.move (env.eval_arg (8), env.eval_arg (9));
853       point_t pt6 = pt5;
854 
855       if (fabs (d.x.to_real ()) > fabs (d.y.to_real ()))
856       {
857 	pt6.move_x (env.eval_arg (10));
858 	pt6.y = env.get_pt ().y;
859       }
860       else
861       {
862 	pt6.x = env.get_pt ().x;
863 	pt6.move_y (env.eval_arg (10));
864       }
865 
866       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
867     }
868     else
869       env.set_error ();
870   }
871 
872   protected:
curve2CFF::path_procs_t873   static void curve2 (ENV &env, PARAM& param,
874 		      const point_t &pt1, const point_t &pt2, const point_t &pt3,
875 		      const point_t &pt4, const point_t &pt5, const point_t &pt6)
876   {
877     PATH::curve (env, param, pt1, pt2, pt3);
878     PATH::curve (env, param, pt4, pt5, pt6);
879   }
880 };
881 
882 template <typename ENV, typename OPSET, typename PARAM>
883 struct cs_interpreter_t : interpreter_t<ENV>
884 {
interpretCFF::cs_interpreter_t885   bool interpret (PARAM& param)
886   {
887     SUPER::env.set_endchar (false);
888 
889     for (;;) {
890       OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
891       if (unlikely (SUPER::env.in_error ()))
892 	return false;
893       if (SUPER::env.is_endchar ())
894 	break;
895     }
896 
897     return true;
898   }
899 
900   private:
901   typedef interpreter_t<ENV> SUPER;
902 };
903 
904 } /* namespace CFF */
905 
906 #endif /* HB_CFF_INTERP_CS_COMMON_HH */
907