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 {
set_intCFF::point_t97   void set_int (int _x, int _y)
98   {
99     x.set_int (_x);
100     y.set_int (_y);
101   }
102 
move_xCFF::point_t103   void move_x (const number_t &dx) { x += dx; }
move_yCFF::point_t104   void move_y (const number_t &dy) { y += dy; }
moveCFF::point_t105   void move (const number_t &dx, const number_t &dy) { move_x (dx); move_y (dy); }
moveCFF::point_t106   void move (const point_t &d) { move_x (d.x); move_y (d.y); }
107 
108   number_t  x;
109   number_t  y;
110 };
111 
112 template <typename ARG, typename SUBRS>
113 struct cs_interp_env_t : interp_env_t<ARG>
114 {
initCFF::cs_interp_env_t115   void init (const byte_str_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_)
116   {
117     interp_env_t<ARG>::init (str);
118 
119     context.init (str, CSType_CharString);
120     seen_moveto = true;
121     seen_hintmask = false;
122     hstem_count = 0;
123     vstem_count = 0;
124     hintmask_size = 0;
125     pt.set_int (0, 0);
126     callStack.init ();
127     globalSubrs.init (globalSubrs_);
128     localSubrs.init (localSubrs_);
129   }
finiCFF::cs_interp_env_t130   void fini ()
131   {
132     interp_env_t<ARG>::fini ();
133 
134     callStack.fini ();
135     globalSubrs.fini ();
136     localSubrs.fini ();
137   }
138 
in_errorCFF::cs_interp_env_t139   bool in_error () const
140   {
141     return callStack.in_error () || SUPER::in_error ();
142   }
143 
pop_subr_numCFF::cs_interp_env_t144   bool pop_subr_num (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num)
145   {
146     subr_num = 0;
147     int n = SUPER::argStack.pop_int ();
148     n += biasedSubrs.get_bias ();
149     if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ())))
150       return false;
151 
152     subr_num = (unsigned int)n;
153     return true;
154   }
155 
call_subrCFF::cs_interp_env_t156   void call_subr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type)
157   {
158     unsigned int subr_num = 0;
159 
160     if (unlikely (!pop_subr_num (biasedSubrs, subr_num)
161 		 || callStack.get_count () >= kMaxCallLimit))
162     {
163       SUPER::set_error ();
164       return;
165     }
166     context.str_ref = SUPER::str_ref;
167     callStack.push (context);
168 
169     context.init ( biasedSubrs[subr_num], type, subr_num);
170     SUPER::str_ref = context.str_ref;
171   }
172 
return_from_subrCFF::cs_interp_env_t173   void return_from_subr ()
174   {
175     if (unlikely (SUPER::str_ref.in_error ()))
176       SUPER::set_error ();
177     context = callStack.pop ();
178     SUPER::str_ref = context.str_ref;
179   }
180 
determine_hintmask_sizeCFF::cs_interp_env_t181   void determine_hintmask_size ()
182   {
183     if (!seen_hintmask)
184     {
185       vstem_count += SUPER::argStack.get_count() / 2;
186       hintmask_size = (hstem_count + vstem_count + 7) >> 3;
187       seen_hintmask = true;
188     }
189   }
190 
set_endcharCFF::cs_interp_env_t191   void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; }
is_endcharCFF::cs_interp_env_t192   bool is_endchar () const { return endchar_flag; }
193 
get_xCFF::cs_interp_env_t194   const number_t &get_x () const { return pt.x; }
get_yCFF::cs_interp_env_t195   const number_t &get_y () const { return pt.y; }
get_ptCFF::cs_interp_env_t196   const point_t &get_pt () const { return pt; }
197 
movetoCFF::cs_interp_env_t198   void moveto (const point_t &pt_ ) { pt = pt_; }
199 
200   public:
201   call_context_t   context;
202   bool	  endchar_flag;
203   bool	  seen_moveto;
204   bool	  seen_hintmask;
205 
206   unsigned int  hstem_count;
207   unsigned int  vstem_count;
208   unsigned int  hintmask_size;
209   call_stack_t	callStack;
210   biased_subrs_t<SUBRS>   globalSubrs;
211   biased_subrs_t<SUBRS>   localSubrs;
212 
213   private:
214   point_t	 pt;
215 
216   typedef interp_env_t<ARG> SUPER;
217 };
218 
219 template <typename ENV, typename PARAM>
220 struct path_procs_null_t
221 {
rmovetoCFF::path_procs_null_t222   static void rmoveto (ENV &env, PARAM& param) {}
hmovetoCFF::path_procs_null_t223   static void hmoveto (ENV &env, PARAM& param) {}
vmovetoCFF::path_procs_null_t224   static void vmoveto (ENV &env, PARAM& param) {}
rlinetoCFF::path_procs_null_t225   static void rlineto (ENV &env, PARAM& param) {}
hlinetoCFF::path_procs_null_t226   static void hlineto (ENV &env, PARAM& param) {}
vlinetoCFF::path_procs_null_t227   static void vlineto (ENV &env, PARAM& param) {}
rrcurvetoCFF::path_procs_null_t228   static void rrcurveto (ENV &env, PARAM& param) {}
rcurvelineCFF::path_procs_null_t229   static void rcurveline (ENV &env, PARAM& param) {}
rlinecurveCFF::path_procs_null_t230   static void rlinecurve (ENV &env, PARAM& param) {}
vvcurvetoCFF::path_procs_null_t231   static void vvcurveto (ENV &env, PARAM& param) {}
hhcurvetoCFF::path_procs_null_t232   static void hhcurveto (ENV &env, PARAM& param) {}
vhcurvetoCFF::path_procs_null_t233   static void vhcurveto (ENV &env, PARAM& param) {}
hvcurvetoCFF::path_procs_null_t234   static void hvcurveto (ENV &env, PARAM& param) {}
movetoCFF::path_procs_null_t235   static void moveto (ENV &env, PARAM& param, const point_t &pt) {}
lineCFF::path_procs_null_t236   static void line (ENV &env, PARAM& param, const point_t &pt1) {}
curveCFF::path_procs_null_t237   static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) {}
hflexCFF::path_procs_null_t238   static void hflex (ENV &env, PARAM& param) {}
flexCFF::path_procs_null_t239   static void flex (ENV &env, PARAM& param) {}
hflex1CFF::path_procs_null_t240   static void hflex1 (ENV &env, PARAM& param) {}
flex1CFF::path_procs_null_t241   static void flex1 (ENV &env, PARAM& param) {}
242 };
243 
244 template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM>>
245 struct cs_opset_t : opset_t<ARG>
246 {
process_opCFF::cs_opset_t247   static void process_op (op_code_t op, ENV &env, PARAM& param)
248   {
249     switch (op) {
250 
251       case OpCode_return:
252 	env.return_from_subr ();
253 	break;
254       case OpCode_endchar:
255 	OPSET::check_width (op, env, param);
256 	env.set_endchar (true);
257 	OPSET::flush_args_and_op (op, env, param);
258 	break;
259 
260       case OpCode_fixedcs:
261 	env.argStack.push_fixed_from_substr (env.str_ref);
262 	break;
263 
264       case OpCode_callsubr:
265 	env.call_subr (env.localSubrs, CSType_LocalSubr);
266 	break;
267 
268       case OpCode_callgsubr:
269 	env.call_subr (env.globalSubrs, CSType_GlobalSubr);
270 	break;
271 
272       case OpCode_hstem:
273       case OpCode_hstemhm:
274 	OPSET::check_width (op, env, param);
275 	OPSET::process_hstem (op, env, param);
276 	break;
277       case OpCode_vstem:
278       case OpCode_vstemhm:
279 	OPSET::check_width (op, env, param);
280 	OPSET::process_vstem (op, env, param);
281 	break;
282       case OpCode_hintmask:
283       case OpCode_cntrmask:
284 	OPSET::check_width (op, env, param);
285 	OPSET::process_hintmask (op, env, param);
286 	break;
287       case OpCode_rmoveto:
288 	OPSET::check_width (op, env, param);
289 	PATH::rmoveto (env, param);
290 	OPSET::process_post_move (op, env, param);
291 	break;
292       case OpCode_hmoveto:
293 	OPSET::check_width (op, env, param);
294 	PATH::hmoveto (env, param);
295 	OPSET::process_post_move (op, env, param);
296 	break;
297       case OpCode_vmoveto:
298 	OPSET::check_width (op, env, param);
299 	PATH::vmoveto (env, param);
300 	OPSET::process_post_move (op, env, param);
301 	break;
302       case OpCode_rlineto:
303 	PATH::rlineto (env, param);
304 	process_post_path (op, env, param);
305 	break;
306       case OpCode_hlineto:
307 	PATH::hlineto (env, param);
308 	process_post_path (op, env, param);
309 	break;
310       case OpCode_vlineto:
311 	PATH::vlineto (env, param);
312 	process_post_path (op, env, param);
313 	break;
314       case OpCode_rrcurveto:
315 	PATH::rrcurveto (env, param);
316 	process_post_path (op, env, param);
317 	break;
318       case OpCode_rcurveline:
319 	PATH::rcurveline (env, param);
320 	process_post_path (op, env, param);
321 	break;
322       case OpCode_rlinecurve:
323 	PATH::rlinecurve (env, param);
324 	process_post_path (op, env, param);
325 	break;
326       case OpCode_vvcurveto:
327 	PATH::vvcurveto (env, param);
328 	process_post_path (op, env, param);
329 	break;
330       case OpCode_hhcurveto:
331 	PATH::hhcurveto (env, param);
332 	process_post_path (op, env, param);
333 	break;
334       case OpCode_vhcurveto:
335 	PATH::vhcurveto (env, param);
336 	process_post_path (op, env, param);
337 	break;
338       case OpCode_hvcurveto:
339 	PATH::hvcurveto (env, param);
340 	process_post_path (op, env, param);
341 	break;
342 
343       case OpCode_hflex:
344 	PATH::hflex (env, param);
345 	OPSET::process_post_flex (op, env, param);
346 	break;
347 
348       case OpCode_flex:
349 	PATH::flex (env, param);
350 	OPSET::process_post_flex (op, env, param);
351 	break;
352 
353       case OpCode_hflex1:
354 	PATH::hflex1 (env, param);
355 	OPSET::process_post_flex (op, env, param);
356 	break;
357 
358       case OpCode_flex1:
359 	PATH::flex1 (env, param);
360 	OPSET::process_post_flex (op, env, param);
361 	break;
362 
363       default:
364 	SUPER::process_op (op, env);
365 	break;
366     }
367   }
368 
process_hstemCFF::cs_opset_t369   static void process_hstem (op_code_t op, ENV &env, PARAM& param)
370   {
371     env.hstem_count += env.argStack.get_count () / 2;
372     OPSET::flush_args_and_op (op, env, param);
373   }
374 
process_vstemCFF::cs_opset_t375   static void process_vstem (op_code_t op, ENV &env, PARAM& param)
376   {
377     env.vstem_count += env.argStack.get_count () / 2;
378     OPSET::flush_args_and_op (op, env, param);
379   }
380 
process_hintmaskCFF::cs_opset_t381   static void process_hintmask (op_code_t op, ENV &env, PARAM& param)
382   {
383     env.determine_hintmask_size ();
384     if (likely (env.str_ref.avail (env.hintmask_size)))
385     {
386       OPSET::flush_hintmask (op, env, param);
387       env.str_ref.inc (env.hintmask_size);
388     }
389   }
390 
process_post_flexCFF::cs_opset_t391   static void process_post_flex (op_code_t op, ENV &env, PARAM& param)
392   {
393     OPSET::flush_args_and_op (op, env, param);
394   }
395 
check_widthCFF::cs_opset_t396   static void check_width (op_code_t op, ENV &env, PARAM& param)
397   {}
398 
process_post_moveCFF::cs_opset_t399   static void process_post_move (op_code_t op, ENV &env, PARAM& param)
400   {
401     if (!env.seen_moveto)
402     {
403       env.determine_hintmask_size ();
404       env.seen_moveto = true;
405     }
406     OPSET::flush_args_and_op (op, env, param);
407   }
408 
process_post_pathCFF::cs_opset_t409   static void process_post_path (op_code_t op, ENV &env, PARAM& param)
410   {
411     OPSET::flush_args_and_op (op, env, param);
412   }
413 
flush_args_and_opCFF::cs_opset_t414   static void flush_args_and_op (op_code_t op, ENV &env, PARAM& param)
415   {
416     OPSET::flush_args (env, param);
417     OPSET::flush_op (op, env, param);
418   }
419 
flush_argsCFF::cs_opset_t420   static void flush_args (ENV &env, PARAM& param)
421   {
422     env.pop_n_args (env.argStack.get_count ());
423   }
424 
flush_opCFF::cs_opset_t425   static void flush_op (op_code_t op, ENV &env, PARAM& param)
426   {
427   }
428 
flush_hintmaskCFF::cs_opset_t429   static void flush_hintmask (op_code_t op, ENV &env, PARAM& param)
430   {
431     OPSET::flush_args_and_op (op, env, param);
432   }
433 
is_number_opCFF::cs_opset_t434   static bool is_number_op (op_code_t op)
435   {
436     switch (op)
437     {
438       case OpCode_shortint:
439       case OpCode_fixedcs:
440       case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1:
441       case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3:
442       case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
443       case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
444 	return true;
445 
446       default:
447 	/* 1-byte integer */
448 	return (OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast);
449     }
450   }
451 
452   protected:
453   typedef opset_t<ARG>  SUPER;
454 };
455 
456 template <typename PATH, typename ENV, typename PARAM>
457 struct path_procs_t
458 {
rmovetoCFF::path_procs_t459   static void rmoveto (ENV &env, PARAM& param)
460   {
461     point_t pt1 = env.get_pt ();
462     const number_t &dy = env.pop_arg ();
463     const number_t &dx = env.pop_arg ();
464     pt1.move (dx, dy);
465     PATH::moveto (env, param, pt1);
466   }
467 
hmovetoCFF::path_procs_t468   static void hmoveto (ENV &env, PARAM& param)
469   {
470     point_t pt1 = env.get_pt ();
471     pt1.move_x (env.pop_arg ());
472     PATH::moveto (env, param, pt1);
473   }
474 
vmovetoCFF::path_procs_t475   static void vmoveto (ENV &env, PARAM& param)
476   {
477     point_t pt1 = env.get_pt ();
478     pt1.move_y (env.pop_arg ());
479     PATH::moveto (env, param, pt1);
480   }
481 
rlinetoCFF::path_procs_t482   static void rlineto (ENV &env, PARAM& param)
483   {
484     for (unsigned int i = 0; i + 2 <= env.argStack.get_count (); i += 2)
485     {
486       point_t pt1 = env.get_pt ();
487       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
488       PATH::line (env, param, pt1);
489     }
490   }
491 
hlinetoCFF::path_procs_t492   static void hlineto (ENV &env, PARAM& param)
493   {
494     point_t pt1;
495     unsigned int i = 0;
496     for (; i + 2 <= env.argStack.get_count (); i += 2)
497     {
498       pt1 = env.get_pt ();
499       pt1.move_x (env.eval_arg (i));
500       PATH::line (env, param, pt1);
501       pt1.move_y (env.eval_arg (i+1));
502       PATH::line (env, param, pt1);
503     }
504     if (i < env.argStack.get_count ())
505     {
506       pt1 = env.get_pt ();
507       pt1.move_x (env.eval_arg (i));
508       PATH::line (env, param, pt1);
509     }
510   }
511 
vlinetoCFF::path_procs_t512   static void vlineto (ENV &env, PARAM& param)
513   {
514     point_t pt1;
515     unsigned int i = 0;
516     for (; i + 2 <= env.argStack.get_count (); i += 2)
517     {
518       pt1 = env.get_pt ();
519       pt1.move_y (env.eval_arg (i));
520       PATH::line (env, param, pt1);
521       pt1.move_x (env.eval_arg (i+1));
522       PATH::line (env, param, pt1);
523     }
524     if (i < env.argStack.get_count ())
525     {
526       pt1 = env.get_pt ();
527       pt1.move_y (env.eval_arg (i));
528       PATH::line (env, param, pt1);
529     }
530   }
531 
rrcurvetoCFF::path_procs_t532   static void rrcurveto (ENV &env, PARAM& param)
533   {
534     for (unsigned int i = 0; i + 6 <= env.argStack.get_count (); i += 6)
535     {
536       point_t pt1 = env.get_pt ();
537       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
538       point_t pt2 = pt1;
539       pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
540       point_t pt3 = pt2;
541       pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
542       PATH::curve (env, param, pt1, pt2, pt3);
543     }
544   }
545 
rcurvelineCFF::path_procs_t546   static void rcurveline (ENV &env, PARAM& param)
547   {
548     unsigned int arg_count = env.argStack.get_count ();
549     if (unlikely (arg_count < 8))
550       return;
551 
552     unsigned int i = 0;
553     unsigned int curve_limit = arg_count - 2;
554     for (; i + 6 <= curve_limit; 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 
565     point_t pt1 = env.get_pt ();
566     pt1.move (env.eval_arg (i), env.eval_arg (i+1));
567     PATH::line (env, param, pt1);
568   }
569 
rlinecurveCFF::path_procs_t570   static void rlinecurve (ENV &env, PARAM& param)
571   {
572     unsigned int arg_count = env.argStack.get_count ();
573     if (unlikely (arg_count < 8))
574       return;
575 
576     unsigned int i = 0;
577     unsigned int line_limit = arg_count - 6;
578     for (; i + 2 <= line_limit; i += 2)
579     {
580       point_t pt1 = env.get_pt ();
581       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
582       PATH::line (env, param, pt1);
583     }
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 
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       for (unsigned int i = 0; i < 10; i += 2)
839 	d.move (env.eval_arg (i), env.eval_arg (i+1));
840 
841       point_t pt1 = env.get_pt ();
842       pt1.move (env.eval_arg (0), env.eval_arg (1));
843       point_t pt2 = pt1;
844       pt2.move (env.eval_arg (2), env.eval_arg (3));
845       point_t pt3 = pt2;
846       pt3.move (env.eval_arg (4), env.eval_arg (5));
847       point_t pt4 = pt3;
848       pt4.move (env.eval_arg (6), env.eval_arg (7));
849       point_t pt5 = pt4;
850       pt5.move (env.eval_arg (8), env.eval_arg (9));
851       point_t pt6 = pt5;
852 
853       if (fabs (d.x.to_real ()) > fabs (d.y.to_real ()))
854       {
855 	pt6.move_x (env.eval_arg (10));
856 	pt6.y = env.get_pt ().y;
857       }
858       else
859       {
860 	pt6.x = env.get_pt ().x;
861 	pt6.move_y (env.eval_arg (10));
862       }
863 
864       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
865     }
866     else
867       env.set_error ();
868   }
869 
870   protected:
curve2CFF::path_procs_t871   static void curve2 (ENV &env, PARAM& param,
872 		      const point_t &pt1, const point_t &pt2, const point_t &pt3,
873 		      const point_t &pt4, const point_t &pt5, const point_t &pt6)
874   {
875     PATH::curve (env, param, pt1, pt2, pt3);
876     PATH::curve (env, param, pt4, pt5, pt6);
877   }
878 };
879 
880 template <typename ENV, typename OPSET, typename PARAM>
881 struct cs_interpreter_t : interpreter_t<ENV>
882 {
interpretCFF::cs_interpreter_t883   bool interpret (PARAM& param)
884   {
885     SUPER::env.set_endchar (false);
886 
887     for (;;) {
888       OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
889       if (unlikely (SUPER::env.in_error ()))
890 	return false;
891       if (SUPER::env.is_endchar ())
892 	break;
893     }
894 
895     return true;
896   }
897 
898   private:
899   typedef interpreter_t<ENV> SUPER;
900 };
901 
902 } /* namespace CFF */
903 
904 #endif /* HB_CFF_INTERP_CS_COMMON_HH */
905