• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 CSType {
37   CSType_CharString,
38   CSType_GlobalSubr,
39   CSType_LocalSubr
40 };
41 
42 struct CallContext
43 {
initCFF::CallContext44   void init (const SubByteStr substr_=SubByteStr (), CSType type_=CSType_CharString, unsigned int subr_num_=0)
45   {
46     substr = substr_;
47     type = type_;
48     subr_num = subr_num_;
49   }
50 
finiCFF::CallContext51   void fini () {}
52 
53   SubByteStr      substr;
54   CSType	  type;
55   unsigned int    subr_num;
56 };
57 
58 /* call stack */
59 const unsigned int kMaxCallLimit = 10;
60 struct CallStack : Stack<CallContext, kMaxCallLimit> {};
61 
62 template <typename SUBRS>
63 struct BiasedSubrs
64 {
initCFF::BiasedSubrs65   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::BiasedSubrs77   void fini () {}
78 
get_countCFF::BiasedSubrs79   unsigned int get_count () const { return (subrs == nullptr)? 0: subrs->count; }
get_biasCFF::BiasedSubrs80   unsigned int get_bias () const { return bias; }
81 
operator []CFF::BiasedSubrs82   ByteStr operator [] (unsigned int index) const
83   {
84     if (unlikely ((subrs == nullptr) || index >= subrs->count))
85       return Null(ByteStr);
86     else
87       return (*subrs)[index];
88   }
89 
90   protected:
91   unsigned int  bias;
92   const SUBRS   *subrs;
93 };
94 
95 struct Point
96 {
initCFF::Point97   void init ()
98   {
99     x.init ();
100     y.init ();
101   }
102 
set_intCFF::Point103   void set_int (int _x, int _y)
104   {
105     x.set_int (_x);
106     y.set_int (_y);
107   }
108 
move_xCFF::Point109   void move_x (const Number &dx) { x += dx; }
move_yCFF::Point110   void move_y (const Number &dy) { y += dy; }
moveCFF::Point111   void move (const Number &dx, const Number &dy) { move_x (dx); move_y (dy); }
moveCFF::Point112   void move (const Point &d) { move_x (d.x); move_y (d.y); }
113 
114   Number  x;
115   Number  y;
116 };
117 
118 template <typename ARG, typename SUBRS>
119 struct CSInterpEnv : InterpEnv<ARG>
120 {
initCFF::CSInterpEnv121   void init (const ByteStr &str, const SUBRS &globalSubrs_, const SUBRS &localSubrs_)
122   {
123     InterpEnv<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     pt.init ();
131     callStack.init ();
132     globalSubrs.init (globalSubrs_);
133     localSubrs.init (localSubrs_);
134   }
finiCFF::CSInterpEnv135   void fini ()
136   {
137     InterpEnv<ARG>::fini ();
138 
139     callStack.fini ();
140     globalSubrs.fini ();
141     localSubrs.fini ();
142   }
143 
in_errorCFF::CSInterpEnv144   bool in_error () const
145   {
146     return callStack.in_error () || SUPER::in_error ();
147   }
148 
popSubrNumCFF::CSInterpEnv149   bool popSubrNum (const BiasedSubrs<SUBRS>& biasedSubrs, unsigned int &subr_num)
150   {
151     int n = SUPER::argStack.pop_int ();
152     n += biasedSubrs.get_bias ();
153     if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ())))
154       return false;
155 
156     subr_num = (unsigned int)n;
157     return true;
158   }
159 
callSubrCFF::CSInterpEnv160   void callSubr (const BiasedSubrs<SUBRS>& biasedSubrs, CSType type)
161   {
162     unsigned int subr_num;
163 
164     if (unlikely (!popSubrNum (biasedSubrs, subr_num)
165 		 || callStack.get_count () >= kMaxCallLimit))
166     {
167       SUPER::set_error ();
168       return;
169     }
170     context.substr = SUPER::substr;
171     callStack.push (context);
172 
173     context.init ( biasedSubrs[subr_num], type, subr_num);
174     SUPER::substr = context.substr;
175   }
176 
returnFromSubrCFF::CSInterpEnv177   void returnFromSubr ()
178   {
179     if (unlikely (SUPER::substr.in_error ()))
180       SUPER::set_error ();
181     context = callStack.pop ();
182     SUPER::substr = context.substr;
183   }
184 
determine_hintmask_sizeCFF::CSInterpEnv185   void determine_hintmask_size ()
186   {
187     if (!seen_hintmask)
188     {
189       vstem_count += SUPER::argStack.get_count() / 2;
190       hintmask_size = (hstem_count + vstem_count + 7) >> 3;
191       seen_hintmask = true;
192     }
193   }
194 
set_endcharCFF::CSInterpEnv195   void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; }
is_endcharCFF::CSInterpEnv196   bool is_endchar () const { return endchar_flag; }
197 
get_xCFF::CSInterpEnv198   const Number &get_x () const { return pt.x; }
get_yCFF::CSInterpEnv199   const Number &get_y () const { return pt.y; }
get_ptCFF::CSInterpEnv200   const Point &get_pt () const { return pt; }
201 
movetoCFF::CSInterpEnv202   void moveto (const Point &pt_ ) { pt = pt_; }
203 
204   public:
205   CallContext   context;
206   bool	  endchar_flag;
207   bool	  seen_moveto;
208   bool	  seen_hintmask;
209 
210   unsigned int  hstem_count;
211   unsigned int  vstem_count;
212   unsigned int  hintmask_size;
213   CallStack	    callStack;
214   BiasedSubrs<SUBRS>   globalSubrs;
215   BiasedSubrs<SUBRS>   localSubrs;
216 
217   private:
218   Point	 pt;
219 
220   typedef InterpEnv<ARG> SUPER;
221 };
222 
223 template <typename ENV, typename PARAM>
224 struct PathProcsNull
225 {
rmovetoCFF::PathProcsNull226   static void rmoveto (ENV &env, PARAM& param) {}
hmovetoCFF::PathProcsNull227   static void hmoveto (ENV &env, PARAM& param) {}
vmovetoCFF::PathProcsNull228   static void vmoveto (ENV &env, PARAM& param) {}
rlinetoCFF::PathProcsNull229   static void rlineto (ENV &env, PARAM& param) {}
hlinetoCFF::PathProcsNull230   static void hlineto (ENV &env, PARAM& param) {}
vlinetoCFF::PathProcsNull231   static void vlineto (ENV &env, PARAM& param) {}
rrcurvetoCFF::PathProcsNull232   static void rrcurveto (ENV &env, PARAM& param) {}
rcurvelineCFF::PathProcsNull233   static void rcurveline (ENV &env, PARAM& param) {}
rlinecurveCFF::PathProcsNull234   static void rlinecurve (ENV &env, PARAM& param) {}
vvcurvetoCFF::PathProcsNull235   static void vvcurveto (ENV &env, PARAM& param) {}
hhcurvetoCFF::PathProcsNull236   static void hhcurveto (ENV &env, PARAM& param) {}
vhcurvetoCFF::PathProcsNull237   static void vhcurveto (ENV &env, PARAM& param) {}
hvcurvetoCFF::PathProcsNull238   static void hvcurveto (ENV &env, PARAM& param) {}
movetoCFF::PathProcsNull239   static void moveto (ENV &env, PARAM& param, const Point &pt) {}
lineCFF::PathProcsNull240   static void line (ENV &env, PARAM& param, const Point &pt1) {}
curveCFF::PathProcsNull241   static void curve (ENV &env, PARAM& param, const Point &pt1, const Point &pt2, const Point &pt3) {}
hflexCFF::PathProcsNull242   static void hflex (ENV &env, PARAM& param) {}
flexCFF::PathProcsNull243   static void flex (ENV &env, PARAM& param) {}
hflex1CFF::PathProcsNull244   static void hflex1 (ENV &env, PARAM& param) {}
flex1CFF::PathProcsNull245   static void flex1 (ENV &env, PARAM& param) {}
246 };
247 
248 template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=PathProcsNull<ENV, PARAM> >
249 struct CSOpSet : OpSet<ARG>
250 {
process_opCFF::CSOpSet251   static void process_op (OpCode op, ENV &env, PARAM& param)
252   {
253     switch (op) {
254 
255       case OpCode_return:
256 	env.returnFromSubr ();
257 	break;
258       case OpCode_endchar:
259 	OPSET::check_width (op, env, param);
260 	env.set_endchar (true);
261 	OPSET::flush_args_and_op (op, env, param);
262 	break;
263 
264       case OpCode_fixedcs:
265 	env.argStack.push_fixed_from_substr (env.substr);
266 	break;
267 
268       case OpCode_callsubr:
269 	env.callSubr (env.localSubrs, CSType_LocalSubr);
270 	break;
271 
272       case OpCode_callgsubr:
273 	env.callSubr (env.globalSubrs, CSType_GlobalSubr);
274 	break;
275 
276       case OpCode_hstem:
277       case OpCode_hstemhm:
278 	OPSET::check_width (op, env, param);
279 	OPSET::process_hstem (op, env, param);
280 	break;
281       case OpCode_vstem:
282       case OpCode_vstemhm:
283 	OPSET::check_width (op, env, param);
284 	OPSET::process_vstem (op, env, param);
285 	break;
286       case OpCode_hintmask:
287       case OpCode_cntrmask:
288 	OPSET::check_width (op, env, param);
289 	OPSET::process_hintmask (op, env, param);
290 	break;
291       case OpCode_rmoveto:
292 	OPSET::check_width (op, env, param);
293 	PATH::rmoveto (env, param);
294 	OPSET::process_post_move (op, env, param);
295 	break;
296       case OpCode_hmoveto:
297 	OPSET::check_width (op, env, param);
298 	PATH::hmoveto (env, param);
299 	OPSET::process_post_move (op, env, param);
300 	break;
301       case OpCode_vmoveto:
302 	OPSET::check_width (op, env, param);
303 	PATH::vmoveto (env, param);
304 	OPSET::process_post_move (op, env, param);
305 	break;
306       case OpCode_rlineto:
307 	PATH::rlineto (env, param);
308 	process_post_path (op, env, param);
309 	break;
310       case OpCode_hlineto:
311 	PATH::hlineto (env, param);
312 	process_post_path (op, env, param);
313 	break;
314       case OpCode_vlineto:
315 	PATH::vlineto (env, param);
316 	process_post_path (op, env, param);
317 	break;
318       case OpCode_rrcurveto:
319 	PATH::rrcurveto (env, param);
320 	process_post_path (op, env, param);
321 	break;
322       case OpCode_rcurveline:
323 	PATH::rcurveline (env, param);
324 	process_post_path (op, env, param);
325 	break;
326       case OpCode_rlinecurve:
327 	PATH::rlinecurve (env, param);
328 	process_post_path (op, env, param);
329 	break;
330       case OpCode_vvcurveto:
331 	PATH::vvcurveto (env, param);
332 	process_post_path (op, env, param);
333 	break;
334       case OpCode_hhcurveto:
335 	PATH::hhcurveto (env, param);
336 	process_post_path (op, env, param);
337 	break;
338       case OpCode_vhcurveto:
339 	PATH::vhcurveto (env, param);
340 	process_post_path (op, env, param);
341 	break;
342       case OpCode_hvcurveto:
343 	PATH::hvcurveto (env, param);
344 	process_post_path (op, env, param);
345 	break;
346 
347       case OpCode_hflex:
348 	PATH::hflex (env, param);
349 	OPSET::process_post_flex (op, env, param);
350 	break;
351 
352       case OpCode_flex:
353 	PATH::flex (env, param);
354 	OPSET::process_post_flex (op, env, param);
355 	break;
356 
357       case OpCode_hflex1:
358 	PATH::hflex1 (env, param);
359 	OPSET::process_post_flex (op, env, param);
360 	break;
361 
362       case OpCode_flex1:
363 	PATH::flex1 (env, param);
364 	OPSET::process_post_flex (op, env, param);
365 	break;
366 
367       default:
368 	SUPER::process_op (op, env);
369 	break;
370     }
371   }
372 
process_hstemCFF::CSOpSet373   static void process_hstem (OpCode op, ENV &env, PARAM& param)
374   {
375     env.hstem_count += env.argStack.get_count () / 2;
376     OPSET::flush_args_and_op (op, env, param);
377   }
378 
process_vstemCFF::CSOpSet379   static void process_vstem (OpCode op, ENV &env, PARAM& param)
380   {
381     env.vstem_count += env.argStack.get_count () / 2;
382     OPSET::flush_args_and_op (op, env, param);
383   }
384 
process_hintmaskCFF::CSOpSet385   static void process_hintmask (OpCode op, ENV &env, PARAM& param)
386   {
387     env.determine_hintmask_size ();
388     if (likely (env.substr.avail (env.hintmask_size)))
389     {
390       OPSET::flush_hintmask (op, env, param);
391       env.substr.inc (env.hintmask_size);
392     }
393   }
394 
process_post_flexCFF::CSOpSet395   static void process_post_flex (OpCode op, ENV &env, PARAM& param)
396   {
397     OPSET::flush_args_and_op (op, env, param);
398   }
399 
check_widthCFF::CSOpSet400   static void check_width (OpCode op, ENV &env, PARAM& param)
401   {}
402 
process_post_moveCFF::CSOpSet403   static void process_post_move (OpCode op, ENV &env, PARAM& param)
404   {
405     if (!env.seen_moveto)
406     {
407       env.determine_hintmask_size ();
408       env.seen_moveto = true;
409     }
410     OPSET::flush_args_and_op (op, env, param);
411   }
412 
process_post_pathCFF::CSOpSet413   static void process_post_path (OpCode op, ENV &env, PARAM& param)
414   {
415     OPSET::flush_args_and_op (op, env, param);
416   }
417 
flush_args_and_opCFF::CSOpSet418   static void flush_args_and_op (OpCode op, ENV &env, PARAM& param)
419   {
420     OPSET::flush_args (env, param);
421     OPSET::flush_op (op, env, param);
422   }
423 
flush_argsCFF::CSOpSet424   static void flush_args (ENV &env, PARAM& param)
425   {
426     env.pop_n_args (env.argStack.get_count ());
427   }
428 
flush_opCFF::CSOpSet429   static void flush_op (OpCode op, ENV &env, PARAM& param)
430   {
431   }
432 
flush_hintmaskCFF::CSOpSet433   static void flush_hintmask (OpCode op, ENV &env, PARAM& param)
434   {
435     OPSET::flush_args_and_op (op, env, param);
436   }
437 
is_number_opCFF::CSOpSet438   static bool is_number_op (OpCode op)
439   {
440     switch (op)
441     {
442       case OpCode_shortint:
443       case OpCode_fixedcs:
444       case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1:
445       case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3:
446       case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
447       case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
448 	return true;
449 
450       default:
451 	/* 1-byte integer */
452 	return (OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast);
453     }
454   }
455 
456   protected:
457   typedef OpSet<ARG>  SUPER;
458 };
459 
460 template <typename PATH, typename ENV, typename PARAM>
461 struct PathProcs
462 {
rmovetoCFF::PathProcs463   static void rmoveto (ENV &env, PARAM& param)
464   {
465     Point pt1 = env.get_pt ();
466     const Number &dy = env.pop_arg ();
467     const Number &dx = env.pop_arg ();
468     pt1.move (dx, dy);
469     PATH::moveto (env, param, pt1);
470   }
471 
hmovetoCFF::PathProcs472   static void hmoveto (ENV &env, PARAM& param)
473   {
474     Point pt1 = env.get_pt ();
475     pt1.move_x (env.pop_arg ());
476     PATH::moveto (env, param, pt1);
477   }
478 
vmovetoCFF::PathProcs479   static void vmoveto (ENV &env, PARAM& param)
480   {
481     Point pt1 = env.get_pt ();
482     pt1.move_y (env.pop_arg ());
483     PATH::moveto (env, param, pt1);
484   }
485 
rlinetoCFF::PathProcs486   static void rlineto (ENV &env, PARAM& param)
487   {
488     for (unsigned int i = 0; i + 2 <= env.argStack.get_count (); i += 2)
489     {
490       Point pt1 = env.get_pt ();
491       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
492       PATH::line (env, param, pt1);
493     }
494   }
495 
hlinetoCFF::PathProcs496   static void hlineto (ENV &env, PARAM& param)
497   {
498     Point pt1;
499     unsigned int i = 0;
500     for (; i + 2 <= env.argStack.get_count (); i += 2)
501     {
502       pt1 = env.get_pt ();
503       pt1.move_x (env.eval_arg (i));
504       PATH::line (env, param, pt1);
505       pt1.move_y (env.eval_arg (i+1));
506       PATH::line (env, param, pt1);
507     }
508     if (i < env.argStack.get_count ())
509     {
510       pt1 = env.get_pt ();
511       pt1.move_x (env.eval_arg (i));
512       PATH::line (env, param, pt1);
513     }
514   }
515 
vlinetoCFF::PathProcs516   static void vlineto (ENV &env, PARAM& param)
517   {
518     Point pt1;
519     unsigned int i = 0;
520     for (; i + 2 <= env.argStack.get_count (); i += 2)
521     {
522       pt1 = env.get_pt ();
523       pt1.move_y (env.eval_arg (i));
524       PATH::line (env, param, pt1);
525       pt1.move_x (env.eval_arg (i+1));
526       PATH::line (env, param, pt1);
527     }
528     if (i < env.argStack.get_count ())
529     {
530       pt1 = env.get_pt ();
531       pt1.move_y (env.eval_arg (i));
532       PATH::line (env, param, pt1);
533     }
534   }
535 
rrcurvetoCFF::PathProcs536   static void rrcurveto (ENV &env, PARAM& param)
537   {
538     for (unsigned int i = 0; i + 6 <= env.argStack.get_count (); i += 6)
539     {
540       Point pt1 = env.get_pt ();
541       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
542       Point pt2 = pt1;
543       pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
544       Point pt3 = pt2;
545       pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
546       PATH::curve (env, param, pt1, pt2, pt3);
547     }
548   }
549 
rcurvelineCFF::PathProcs550   static void rcurveline (ENV &env, PARAM& param)
551   {
552     unsigned int i = 0;
553     for (; i + 6 <= env.argStack.get_count (); i += 6)
554     {
555       Point pt1 = env.get_pt ();
556       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
557       Point pt2 = pt1;
558       pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
559       Point pt3 = pt2;
560       pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
561       PATH::curve (env, param, pt1, pt2, pt3);
562     }
563     for (; i + 2 <= env.argStack.get_count (); i += 2)
564     {
565       Point pt1 = env.get_pt ();
566       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
567       PATH::line (env, param, pt1);
568     }
569   }
570 
rlinecurveCFF::PathProcs571   static void rlinecurve (ENV &env, PARAM& param)
572   {
573     unsigned int i = 0;
574     unsigned int line_limit = (env.argStack.get_count () % 6);
575     for (; i + 2 <= line_limit; i += 2)
576     {
577       Point pt1 = env.get_pt ();
578       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
579       PATH::line (env, param, pt1);
580     }
581     for (; i + 6 <= env.argStack.get_count (); i += 6)
582     {
583       Point pt1 = env.get_pt ();
584       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
585       Point pt2 = pt1;
586       pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
587       Point pt3 = pt2;
588       pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
589       PATH::curve (env, param, pt1, pt2, pt3);
590     }
591   }
592 
vvcurvetoCFF::PathProcs593   static void vvcurveto (ENV &env, PARAM& param)
594   {
595     unsigned int i = 0;
596     Point pt1 = env.get_pt ();
597     if ((env.argStack.get_count () & 1) != 0)
598       pt1.move_x (env.eval_arg (i++));
599     for (; i + 4 <= env.argStack.get_count (); i += 4)
600     {
601       pt1.move_y (env.eval_arg (i));
602       Point pt2 = pt1;
603       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
604       Point pt3 = pt2;
605       pt3.move_y (env.eval_arg (i+3));
606       PATH::curve (env, param, pt1, pt2, pt3);
607       pt1 = env.get_pt ();
608     }
609   }
610 
hhcurvetoCFF::PathProcs611   static void hhcurveto (ENV &env, PARAM& param)
612   {
613     unsigned int i = 0;
614     Point pt1 = env.get_pt ();
615     if ((env.argStack.get_count () & 1) != 0)
616       pt1.move_y (env.eval_arg (i++));
617     for (; i + 4 <= env.argStack.get_count (); i += 4)
618     {
619       pt1.move_x (env.eval_arg (i));
620       Point pt2 = pt1;
621       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
622       Point pt3 = pt2;
623       pt3.move_x (env.eval_arg (i+3));
624       PATH::curve (env, param, pt1, pt2, pt3);
625       pt1 = env.get_pt ();
626     }
627   }
628 
vhcurvetoCFF::PathProcs629   static void vhcurveto (ENV &env, PARAM& param)
630   {
631     Point pt1, pt2, pt3;
632     unsigned int i = 0;
633     if ((env.argStack.get_count () % 8) >= 4)
634     {
635       Point pt1 = env.get_pt ();
636       pt1.move_y (env.eval_arg (i));
637       Point pt2 = pt1;
638       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
639       Point pt3 = pt2;
640       pt3.move_x (env.eval_arg (i+3));
641       i += 4;
642 
643       for (; i + 8 <= env.argStack.get_count (); i += 8)
644       {
645 	PATH::curve (env, param, pt1, pt2, pt3);
646 	pt1 = env.get_pt ();
647 	pt1.move_x (env.eval_arg (i));
648 	pt2 = pt1;
649 	pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
650 	pt3 = pt2;
651 	pt3.move_y (env.eval_arg (i+3));
652 	PATH::curve (env, param, pt1, pt2, pt3);
653 
654 	pt1 = pt3;
655 	pt1.move_y (env.eval_arg (i+4));
656 	pt2 = pt1;
657 	pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
658 	pt3 = pt2;
659 	pt3.move_x (env.eval_arg (i+7));
660       }
661       if (i < env.argStack.get_count ())
662 	pt3.move_y (env.eval_arg (i));
663       PATH::curve (env, param, pt1, pt2, pt3);
664     }
665     else
666     {
667       for (; i + 8 <= env.argStack.get_count (); i += 8)
668       {
669 	pt1 = env.get_pt ();
670 	pt1.move_y (env.eval_arg (i));
671 	pt2 = pt1;
672 	pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
673 	pt3 = pt2;
674 	pt3.move_x (env.eval_arg (i+3));
675 	PATH::curve (env, param, pt1, pt2, pt3);
676 
677 	pt1 = pt3;
678 	pt1.move_x (env.eval_arg (i+4));
679 	pt2 = pt1;
680 	pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
681 	pt3 = pt2;
682 	pt3.move_y (env.eval_arg (i+7));
683 	if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0))
684 	  pt3.move_x (env.eval_arg (i+8));
685 	PATH::curve (env, param, pt1, pt2, pt3);
686       }
687     }
688   }
689 
hvcurvetoCFF::PathProcs690   static void hvcurveto (ENV &env, PARAM& param)
691   {
692     Point pt1, pt2, pt3;
693     unsigned int i = 0;
694     if ((env.argStack.get_count () % 8) >= 4)
695     {
696       Point pt1 = env.get_pt ();
697       pt1.move_x (env.eval_arg (i));
698       Point pt2 = pt1;
699       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
700       Point pt3 = pt2;
701       pt3.move_y (env.eval_arg (i+3));
702       i += 4;
703 
704       for (; i + 8 <= env.argStack.get_count (); i += 8)
705       {
706 	PATH::curve (env, param, pt1, pt2, pt3);
707 	pt1 = env.get_pt ();
708 	pt1.move_y (env.eval_arg (i));
709 	pt2 = pt1;
710 	pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
711 	pt3 = pt2;
712 	pt3.move_x (env.eval_arg (i+3));
713 	PATH::curve (env, param, pt1, pt2, pt3);
714 
715 	pt1 = pt3;
716 	pt1.move_x (env.eval_arg (i+4));
717 	pt2 = pt1;
718 	pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
719 	pt3 = pt2;
720 	pt3.move_y (env.eval_arg (i+7));
721       }
722       if (i < env.argStack.get_count ())
723 	pt3.move_x (env.eval_arg (i));
724       PATH::curve (env, param, pt1, pt2, pt3);
725     }
726     else
727     {
728       for (; i + 8 <= env.argStack.get_count (); i += 8)
729       {
730 	pt1 = env.get_pt ();
731 	pt1.move_x (env.eval_arg (i));
732 	pt2 = pt1;
733 	pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
734 	pt3 = pt2;
735 	pt3.move_y (env.eval_arg (i+3));
736 	PATH::curve (env, param, pt1, pt2, pt3);
737 
738 	pt1 = pt3;
739 	pt1.move_y (env.eval_arg (i+4));
740 	pt2 = pt1;
741 	pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
742 	pt3 = pt2;
743 	pt3.move_x (env.eval_arg (i+7));
744 	if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0))
745 	  pt3.move_y (env.eval_arg (i+8));
746 	PATH::curve (env, param, pt1, pt2, pt3);
747       }
748     }
749   }
750 
751   /* default actions to be overridden */
movetoCFF::PathProcs752   static void moveto (ENV &env, PARAM& param, const Point &pt)
753   { env.moveto (pt); }
754 
lineCFF::PathProcs755   static void line (ENV &env, PARAM& param, const Point &pt1)
756   { PATH::moveto (env, param, pt1); }
757 
curveCFF::PathProcs758   static void curve (ENV &env, PARAM& param, const Point &pt1, const Point &pt2, const Point &pt3)
759   { PATH::moveto (env, param, pt3); }
760 
hflexCFF::PathProcs761   static void hflex (ENV &env, PARAM& param)
762   {
763     if (likely (env.argStack.get_count () == 7))
764     {
765       Point pt1 = env.get_pt ();
766       pt1.move_x (env.eval_arg (0));
767       Point pt2 = pt1;
768       pt2.move (env.eval_arg (1), env.eval_arg (2));
769       Point pt3 = pt2;
770       pt3.move_x (env.eval_arg (3));
771       Point pt4 = pt3;
772       pt4.move_x (env.eval_arg (4));
773       Point pt5 = pt4;
774       pt5.move_x (env.eval_arg (5));
775       pt5.y = pt1.y;
776       Point pt6 = pt5;
777       pt6.move_x (env.eval_arg (6));
778 
779       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
780     }
781     else
782       env.set_error ();
783   }
784 
flexCFF::PathProcs785   static void flex (ENV &env, PARAM& param)
786   {
787     if (likely (env.argStack.get_count () == 13))
788     {
789       Point pt1 = env.get_pt ();
790       pt1.move (env.eval_arg (0), env.eval_arg (1));
791       Point pt2 = pt1;
792       pt2.move (env.eval_arg (2), env.eval_arg (3));
793       Point pt3 = pt2;
794       pt3.move (env.eval_arg (4), env.eval_arg (5));
795       Point pt4 = pt3;
796       pt4.move (env.eval_arg (6), env.eval_arg (7));
797       Point pt5 = pt4;
798       pt5.move (env.eval_arg (8), env.eval_arg (9));
799       Point pt6 = pt5;
800       pt6.move (env.eval_arg (10), env.eval_arg (11));
801 
802       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
803     }
804     else
805       env.set_error ();
806   }
807 
hflex1CFF::PathProcs808   static void hflex1 (ENV &env, PARAM& param)
809   {
810     if (likely (env.argStack.get_count () == 9))
811     {
812       Point pt1 = env.get_pt ();
813       pt1.move (env.eval_arg (0), env.eval_arg (1));
814       Point pt2 = pt1;
815       pt2.move (env.eval_arg (2), env.eval_arg (3));
816       Point pt3 = pt2;
817       pt3.move_x (env.eval_arg (4));
818       Point pt4 = pt3;
819       pt4.move_x (env.eval_arg (5));
820       Point pt5 = pt4;
821       pt5.move (env.eval_arg (6), env.eval_arg (7));
822       Point pt6 = pt5;
823       pt6.move_x (env.eval_arg (8));
824       pt6.y = env.get_pt ().y;
825 
826       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
827     }
828     else
829       env.set_error ();
830   }
831 
flex1CFF::PathProcs832   static void flex1 (ENV &env, PARAM& param)
833   {
834     if (likely (env.argStack.get_count () == 11))
835     {
836       Point d;
837       d.init ();
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 pt1 = env.get_pt ();
842       pt1.move (env.eval_arg (0), env.eval_arg (1));
843       Point pt2 = pt1;
844       pt2.move (env.eval_arg (2), env.eval_arg (3));
845       Point pt3 = pt2;
846       pt3.move (env.eval_arg (4), env.eval_arg (5));
847       Point pt4 = pt3;
848       pt4.move (env.eval_arg (6), env.eval_arg (7));
849       Point pt5 = pt4;
850       pt5.move (env.eval_arg (8), env.eval_arg (9));
851       Point 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::PathProcs871   static void curve2 (ENV &env, PARAM& param,
872 		      const Point &pt1, const Point &pt2, const Point &pt3,
873 		      const Point &pt4, const Point &pt5, const Point &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 CSInterpreter : Interpreter<ENV>
882 {
interpretCFF::CSInterpreter883   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<ENV> SUPER;
900 };
901 
902 } /* namespace CFF */
903 
904 #endif /* HB_CFF_INTERP_CS_COMMON_HH */
905