xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-cff-interp-cs-common.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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   hb_ubytes_t operator [] (unsigned int index) const
83   {
84     if (unlikely (!subrs || index >= subrs->count))
85       return hb_ubytes_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 {
cs_interp_env_tCFF::cs_interp_env_t115   cs_interp_env_t (const hb_ubytes_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_) :
116     interp_env_t<ARG> (str)
117   {
118     context.init (str, CSType_CharString);
119     seen_moveto = true;
120     seen_hintmask = false;
121     hstem_count = 0;
122     vstem_count = 0;
123     hintmask_size = 0;
124     pt.set_int (0, 0);
125     globalSubrs.init (globalSubrs_);
126     localSubrs.init (localSubrs_);
127   }
~cs_interp_env_tCFF::cs_interp_env_t128   ~cs_interp_env_t ()
129   {
130     globalSubrs.fini ();
131     localSubrs.fini ();
132   }
133 
in_errorCFF::cs_interp_env_t134   bool in_error () const
135   {
136     return callStack.in_error () || SUPER::in_error ();
137   }
138 
pop_subr_numCFF::cs_interp_env_t139   bool pop_subr_num (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num)
140   {
141     subr_num = 0;
142     int n = SUPER::argStack.pop_int ();
143     n += biasedSubrs.get_bias ();
144     if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ())))
145       return false;
146 
147     subr_num = (unsigned int)n;
148     return true;
149   }
150 
call_subrCFF::cs_interp_env_t151   void call_subr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type)
152   {
153     unsigned int subr_num = 0;
154 
155     if (unlikely (!pop_subr_num (biasedSubrs, subr_num)
156 		 || callStack.get_count () >= kMaxCallLimit))
157     {
158       SUPER::set_error ();
159       return;
160     }
161     context.str_ref = SUPER::str_ref;
162     callStack.push (context);
163 
164     context.init ( biasedSubrs[subr_num], type, subr_num);
165     SUPER::str_ref = context.str_ref;
166   }
167 
return_from_subrCFF::cs_interp_env_t168   void return_from_subr ()
169   {
170     if (unlikely (SUPER::str_ref.in_error ()))
171       SUPER::set_error ();
172     context = callStack.pop ();
173     SUPER::str_ref = context.str_ref;
174   }
175 
determine_hintmask_sizeCFF::cs_interp_env_t176   void determine_hintmask_size ()
177   {
178     if (!seen_hintmask)
179     {
180       vstem_count += SUPER::argStack.get_count() / 2;
181       hintmask_size = (hstem_count + vstem_count + 7) >> 3;
182       seen_hintmask = true;
183     }
184   }
185 
set_endcharCFF::cs_interp_env_t186   void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; }
is_endcharCFF::cs_interp_env_t187   bool is_endchar () const { return endchar_flag; }
188 
get_xCFF::cs_interp_env_t189   const number_t &get_x () const { return pt.x; }
get_yCFF::cs_interp_env_t190   const number_t &get_y () const { return pt.y; }
get_ptCFF::cs_interp_env_t191   const point_t &get_pt () const { return pt; }
192 
movetoCFF::cs_interp_env_t193   void moveto (const point_t &pt_ ) { pt = pt_; }
194 
195   public:
196   call_context_t   context;
197   bool	  endchar_flag;
198   bool	  seen_moveto;
199   bool	  seen_hintmask;
200 
201   unsigned int  hstem_count;
202   unsigned int  vstem_count;
203   unsigned int  hintmask_size;
204   call_stack_t	callStack;
205   biased_subrs_t<SUBRS>   globalSubrs;
206   biased_subrs_t<SUBRS>   localSubrs;
207 
208   private:
209   point_t	 pt;
210 
211   typedef interp_env_t<ARG> SUPER;
212 };
213 
214 template <typename ENV, typename PARAM>
215 struct path_procs_null_t
216 {
rmovetoCFF::path_procs_null_t217   static void rmoveto (ENV &env, PARAM& param) {}
hmovetoCFF::path_procs_null_t218   static void hmoveto (ENV &env, PARAM& param) {}
vmovetoCFF::path_procs_null_t219   static void vmoveto (ENV &env, PARAM& param) {}
rlinetoCFF::path_procs_null_t220   static void rlineto (ENV &env, PARAM& param) {}
hlinetoCFF::path_procs_null_t221   static void hlineto (ENV &env, PARAM& param) {}
vlinetoCFF::path_procs_null_t222   static void vlineto (ENV &env, PARAM& param) {}
rrcurvetoCFF::path_procs_null_t223   static void rrcurveto (ENV &env, PARAM& param) {}
rcurvelineCFF::path_procs_null_t224   static void rcurveline (ENV &env, PARAM& param) {}
rlinecurveCFF::path_procs_null_t225   static void rlinecurve (ENV &env, PARAM& param) {}
vvcurvetoCFF::path_procs_null_t226   static void vvcurveto (ENV &env, PARAM& param) {}
hhcurvetoCFF::path_procs_null_t227   static void hhcurveto (ENV &env, PARAM& param) {}
vhcurvetoCFF::path_procs_null_t228   static void vhcurveto (ENV &env, PARAM& param) {}
hvcurvetoCFF::path_procs_null_t229   static void hvcurveto (ENV &env, PARAM& param) {}
movetoCFF::path_procs_null_t230   static void moveto (ENV &env, PARAM& param, const point_t &pt) {}
lineCFF::path_procs_null_t231   static void line (ENV &env, PARAM& param, const point_t &pt1) {}
curveCFF::path_procs_null_t232   static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) {}
hflexCFF::path_procs_null_t233   static void hflex (ENV &env, PARAM& param) {}
flexCFF::path_procs_null_t234   static void flex (ENV &env, PARAM& param) {}
hflex1CFF::path_procs_null_t235   static void hflex1 (ENV &env, PARAM& param) {}
flex1CFF::path_procs_null_t236   static void flex1 (ENV &env, PARAM& param) {}
237 };
238 
239 template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM>>
240 struct cs_opset_t : opset_t<ARG>
241 {
process_opCFF::cs_opset_t242   static void process_op (op_code_t op, ENV &env, PARAM& param)
243   {
244     switch (op) {
245 
246       case OpCode_return:
247 	env.return_from_subr ();
248 	break;
249       case OpCode_endchar:
250 	OPSET::check_width (op, env, param);
251 	env.set_endchar (true);
252 	OPSET::flush_args_and_op (op, env, param);
253 	break;
254 
255       case OpCode_fixedcs:
256 	env.argStack.push_fixed_from_substr (env.str_ref);
257 	break;
258 
259       case OpCode_callsubr:
260 	env.call_subr (env.localSubrs, CSType_LocalSubr);
261 	break;
262 
263       case OpCode_callgsubr:
264 	env.call_subr (env.globalSubrs, CSType_GlobalSubr);
265 	break;
266 
267       case OpCode_hstem:
268       case OpCode_hstemhm:
269 	OPSET::check_width (op, env, param);
270 	OPSET::process_hstem (op, env, param);
271 	break;
272       case OpCode_vstem:
273       case OpCode_vstemhm:
274 	OPSET::check_width (op, env, param);
275 	OPSET::process_vstem (op, env, param);
276 	break;
277       case OpCode_hintmask:
278       case OpCode_cntrmask:
279 	OPSET::check_width (op, env, param);
280 	OPSET::process_hintmask (op, env, param);
281 	break;
282       case OpCode_rmoveto:
283 	OPSET::check_width (op, env, param);
284 	PATH::rmoveto (env, param);
285 	OPSET::process_post_move (op, env, param);
286 	break;
287       case OpCode_hmoveto:
288 	OPSET::check_width (op, env, param);
289 	PATH::hmoveto (env, param);
290 	OPSET::process_post_move (op, env, param);
291 	break;
292       case OpCode_vmoveto:
293 	OPSET::check_width (op, env, param);
294 	PATH::vmoveto (env, param);
295 	OPSET::process_post_move (op, env, param);
296 	break;
297       case OpCode_rlineto:
298 	PATH::rlineto (env, param);
299 	process_post_path (op, env, param);
300 	break;
301       case OpCode_hlineto:
302 	PATH::hlineto (env, param);
303 	process_post_path (op, env, param);
304 	break;
305       case OpCode_vlineto:
306 	PATH::vlineto (env, param);
307 	process_post_path (op, env, param);
308 	break;
309       case OpCode_rrcurveto:
310 	PATH::rrcurveto (env, param);
311 	process_post_path (op, env, param);
312 	break;
313       case OpCode_rcurveline:
314 	PATH::rcurveline (env, param);
315 	process_post_path (op, env, param);
316 	break;
317       case OpCode_rlinecurve:
318 	PATH::rlinecurve (env, param);
319 	process_post_path (op, env, param);
320 	break;
321       case OpCode_vvcurveto:
322 	PATH::vvcurveto (env, param);
323 	process_post_path (op, env, param);
324 	break;
325       case OpCode_hhcurveto:
326 	PATH::hhcurveto (env, param);
327 	process_post_path (op, env, param);
328 	break;
329       case OpCode_vhcurveto:
330 	PATH::vhcurveto (env, param);
331 	process_post_path (op, env, param);
332 	break;
333       case OpCode_hvcurveto:
334 	PATH::hvcurveto (env, param);
335 	process_post_path (op, env, param);
336 	break;
337 
338       case OpCode_hflex:
339 	PATH::hflex (env, param);
340 	OPSET::process_post_flex (op, env, param);
341 	break;
342 
343       case OpCode_flex:
344 	PATH::flex (env, param);
345 	OPSET::process_post_flex (op, env, param);
346 	break;
347 
348       case OpCode_hflex1:
349 	PATH::hflex1 (env, param);
350 	OPSET::process_post_flex (op, env, param);
351 	break;
352 
353       case OpCode_flex1:
354 	PATH::flex1 (env, param);
355 	OPSET::process_post_flex (op, env, param);
356 	break;
357 
358       default:
359 	SUPER::process_op (op, env);
360 	break;
361     }
362   }
363 
process_hstemCFF::cs_opset_t364   static void process_hstem (op_code_t op, ENV &env, PARAM& param)
365   {
366     env.hstem_count += env.argStack.get_count () / 2;
367     OPSET::flush_args_and_op (op, env, param);
368   }
369 
process_vstemCFF::cs_opset_t370   static void process_vstem (op_code_t op, ENV &env, PARAM& param)
371   {
372     env.vstem_count += env.argStack.get_count () / 2;
373     OPSET::flush_args_and_op (op, env, param);
374   }
375 
process_hintmaskCFF::cs_opset_t376   static void process_hintmask (op_code_t op, ENV &env, PARAM& param)
377   {
378     env.determine_hintmask_size ();
379     if (likely (env.str_ref.avail (env.hintmask_size)))
380     {
381       OPSET::flush_hintmask (op, env, param);
382       env.str_ref.inc (env.hintmask_size);
383     }
384   }
385 
process_post_flexCFF::cs_opset_t386   static void process_post_flex (op_code_t op, ENV &env, PARAM& param)
387   {
388     OPSET::flush_args_and_op (op, env, param);
389   }
390 
check_widthCFF::cs_opset_t391   static void check_width (op_code_t op, ENV &env, PARAM& param)
392   {}
393 
process_post_moveCFF::cs_opset_t394   static void process_post_move (op_code_t op, ENV &env, PARAM& param)
395   {
396     if (!env.seen_moveto)
397     {
398       env.determine_hintmask_size ();
399       env.seen_moveto = true;
400     }
401     OPSET::flush_args_and_op (op, env, param);
402   }
403 
process_post_pathCFF::cs_opset_t404   static void process_post_path (op_code_t op, ENV &env, PARAM& param)
405   {
406     OPSET::flush_args_and_op (op, env, param);
407   }
408 
flush_args_and_opCFF::cs_opset_t409   static void flush_args_and_op (op_code_t op, ENV &env, PARAM& param)
410   {
411     OPSET::flush_args (env, param);
412     OPSET::flush_op (op, env, param);
413   }
414 
flush_argsCFF::cs_opset_t415   static void flush_args (ENV &env, PARAM& param)
416   {
417     env.pop_n_args (env.argStack.get_count ());
418   }
419 
flush_opCFF::cs_opset_t420   static void flush_op (op_code_t op, ENV &env, PARAM& param)
421   {
422   }
423 
flush_hintmaskCFF::cs_opset_t424   static void flush_hintmask (op_code_t op, ENV &env, PARAM& param)
425   {
426     OPSET::flush_args_and_op (op, env, param);
427   }
428 
is_number_opCFF::cs_opset_t429   static bool is_number_op (op_code_t op)
430   {
431     switch (op)
432     {
433       case OpCode_shortint:
434       case OpCode_fixedcs:
435       case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1:
436       case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3:
437       case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
438       case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
439 	return true;
440 
441       default:
442 	/* 1-byte integer */
443 	return (OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast);
444     }
445   }
446 
447   protected:
448   typedef opset_t<ARG>  SUPER;
449 };
450 
451 template <typename PATH, typename ENV, typename PARAM>
452 struct path_procs_t
453 {
rmovetoCFF::path_procs_t454   static void rmoveto (ENV &env, PARAM& param)
455   {
456     point_t pt1 = env.get_pt ();
457     const number_t &dy = env.pop_arg ();
458     const number_t &dx = env.pop_arg ();
459     pt1.move (dx, dy);
460     PATH::moveto (env, param, pt1);
461   }
462 
hmovetoCFF::path_procs_t463   static void hmoveto (ENV &env, PARAM& param)
464   {
465     point_t pt1 = env.get_pt ();
466     pt1.move_x (env.pop_arg ());
467     PATH::moveto (env, param, pt1);
468   }
469 
vmovetoCFF::path_procs_t470   static void vmoveto (ENV &env, PARAM& param)
471   {
472     point_t pt1 = env.get_pt ();
473     pt1.move_y (env.pop_arg ());
474     PATH::moveto (env, param, pt1);
475   }
476 
rlinetoCFF::path_procs_t477   static void rlineto (ENV &env, PARAM& param)
478   {
479     for (unsigned int i = 0; i + 2 <= env.argStack.get_count (); i += 2)
480     {
481       point_t pt1 = env.get_pt ();
482       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
483       PATH::line (env, param, pt1);
484     }
485   }
486 
hlinetoCFF::path_procs_t487   static void hlineto (ENV &env, PARAM& param)
488   {
489     point_t pt1;
490     unsigned int i = 0;
491     for (; i + 2 <= env.argStack.get_count (); i += 2)
492     {
493       pt1 = env.get_pt ();
494       pt1.move_x (env.eval_arg (i));
495       PATH::line (env, param, pt1);
496       pt1.move_y (env.eval_arg (i+1));
497       PATH::line (env, param, pt1);
498     }
499     if (i < env.argStack.get_count ())
500     {
501       pt1 = env.get_pt ();
502       pt1.move_x (env.eval_arg (i));
503       PATH::line (env, param, pt1);
504     }
505   }
506 
vlinetoCFF::path_procs_t507   static void vlineto (ENV &env, PARAM& param)
508   {
509     point_t pt1;
510     unsigned int i = 0;
511     for (; i + 2 <= env.argStack.get_count (); i += 2)
512     {
513       pt1 = env.get_pt ();
514       pt1.move_y (env.eval_arg (i));
515       PATH::line (env, param, pt1);
516       pt1.move_x (env.eval_arg (i+1));
517       PATH::line (env, param, pt1);
518     }
519     if (i < env.argStack.get_count ())
520     {
521       pt1 = env.get_pt ();
522       pt1.move_y (env.eval_arg (i));
523       PATH::line (env, param, pt1);
524     }
525   }
526 
rrcurvetoCFF::path_procs_t527   static void rrcurveto (ENV &env, PARAM& param)
528   {
529     for (unsigned int i = 0; i + 6 <= env.argStack.get_count (); i += 6)
530     {
531       point_t pt1 = env.get_pt ();
532       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
533       point_t pt2 = pt1;
534       pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
535       point_t pt3 = pt2;
536       pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
537       PATH::curve (env, param, pt1, pt2, pt3);
538     }
539   }
540 
rcurvelineCFF::path_procs_t541   static void rcurveline (ENV &env, PARAM& param)
542   {
543     unsigned int arg_count = env.argStack.get_count ();
544     if (unlikely (arg_count < 8))
545       return;
546 
547     unsigned int i = 0;
548     unsigned int curve_limit = arg_count - 2;
549     for (; i + 6 <= curve_limit; i += 6)
550     {
551       point_t pt1 = env.get_pt ();
552       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
553       point_t pt2 = pt1;
554       pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
555       point_t pt3 = pt2;
556       pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
557       PATH::curve (env, param, pt1, pt2, pt3);
558     }
559 
560     point_t pt1 = env.get_pt ();
561     pt1.move (env.eval_arg (i), env.eval_arg (i+1));
562     PATH::line (env, param, pt1);
563   }
564 
rlinecurveCFF::path_procs_t565   static void rlinecurve (ENV &env, PARAM& param)
566   {
567     unsigned int arg_count = env.argStack.get_count ();
568     if (unlikely (arg_count < 8))
569       return;
570 
571     unsigned int i = 0;
572     unsigned int line_limit = arg_count - 6;
573     for (; i + 2 <= line_limit; i += 2)
574     {
575       point_t pt1 = env.get_pt ();
576       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
577       PATH::line (env, param, pt1);
578     }
579 
580     point_t pt1 = env.get_pt ();
581     pt1.move (env.eval_arg (i), env.eval_arg (i+1));
582     point_t pt2 = pt1;
583     pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
584     point_t pt3 = pt2;
585     pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
586     PATH::curve (env, param, pt1, pt2, pt3);
587   }
588 
vvcurvetoCFF::path_procs_t589   static void vvcurveto (ENV &env, PARAM& param)
590   {
591     unsigned int i = 0;
592     point_t pt1 = env.get_pt ();
593     if ((env.argStack.get_count () & 1) != 0)
594       pt1.move_x (env.eval_arg (i++));
595     for (; i + 4 <= env.argStack.get_count (); i += 4)
596     {
597       pt1.move_y (env.eval_arg (i));
598       point_t pt2 = pt1;
599       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
600       point_t pt3 = pt2;
601       pt3.move_y (env.eval_arg (i+3));
602       PATH::curve (env, param, pt1, pt2, pt3);
603       pt1 = env.get_pt ();
604     }
605   }
606 
hhcurvetoCFF::path_procs_t607   static void hhcurveto (ENV &env, PARAM& param)
608   {
609     unsigned int i = 0;
610     point_t pt1 = env.get_pt ();
611     if ((env.argStack.get_count () & 1) != 0)
612       pt1.move_y (env.eval_arg (i++));
613     for (; i + 4 <= env.argStack.get_count (); i += 4)
614     {
615       pt1.move_x (env.eval_arg (i));
616       point_t pt2 = pt1;
617       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
618       point_t pt3 = pt2;
619       pt3.move_x (env.eval_arg (i+3));
620       PATH::curve (env, param, pt1, pt2, pt3);
621       pt1 = env.get_pt ();
622     }
623   }
624 
vhcurvetoCFF::path_procs_t625   static void vhcurveto (ENV &env, PARAM& param)
626   {
627     point_t pt1, pt2, pt3;
628     unsigned int i = 0;
629     if ((env.argStack.get_count () % 8) >= 4)
630     {
631       point_t pt1 = env.get_pt ();
632       pt1.move_y (env.eval_arg (i));
633       point_t pt2 = pt1;
634       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
635       point_t pt3 = pt2;
636       pt3.move_x (env.eval_arg (i+3));
637       i += 4;
638 
639       for (; i + 8 <= env.argStack.get_count (); i += 8)
640       {
641 	PATH::curve (env, param, pt1, pt2, pt3);
642 	pt1 = env.get_pt ();
643 	pt1.move_x (env.eval_arg (i));
644 	pt2 = pt1;
645 	pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
646 	pt3 = pt2;
647 	pt3.move_y (env.eval_arg (i+3));
648 	PATH::curve (env, param, pt1, pt2, pt3);
649 
650 	pt1 = pt3;
651 	pt1.move_y (env.eval_arg (i+4));
652 	pt2 = pt1;
653 	pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
654 	pt3 = pt2;
655 	pt3.move_x (env.eval_arg (i+7));
656       }
657       if (i < env.argStack.get_count ())
658 	pt3.move_y (env.eval_arg (i));
659       PATH::curve (env, param, pt1, pt2, pt3);
660     }
661     else
662     {
663       for (; i + 8 <= env.argStack.get_count (); i += 8)
664       {
665 	pt1 = env.get_pt ();
666 	pt1.move_y (env.eval_arg (i));
667 	pt2 = pt1;
668 	pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
669 	pt3 = pt2;
670 	pt3.move_x (env.eval_arg (i+3));
671 	PATH::curve (env, param, pt1, pt2, pt3);
672 
673 	pt1 = pt3;
674 	pt1.move_x (env.eval_arg (i+4));
675 	pt2 = pt1;
676 	pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
677 	pt3 = pt2;
678 	pt3.move_y (env.eval_arg (i+7));
679 	if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0))
680 	  pt3.move_x (env.eval_arg (i+8));
681 	PATH::curve (env, param, pt1, pt2, pt3);
682       }
683     }
684   }
685 
hvcurvetoCFF::path_procs_t686   static void hvcurveto (ENV &env, PARAM& param)
687   {
688     point_t pt1, pt2, pt3;
689     unsigned int i = 0;
690     if ((env.argStack.get_count () % 8) >= 4)
691     {
692       point_t pt1 = env.get_pt ();
693       pt1.move_x (env.eval_arg (i));
694       point_t pt2 = pt1;
695       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
696       point_t pt3 = pt2;
697       pt3.move_y (env.eval_arg (i+3));
698       i += 4;
699 
700       for (; i + 8 <= env.argStack.get_count (); i += 8)
701       {
702 	PATH::curve (env, param, pt1, pt2, pt3);
703 	pt1 = env.get_pt ();
704 	pt1.move_y (env.eval_arg (i));
705 	pt2 = pt1;
706 	pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
707 	pt3 = pt2;
708 	pt3.move_x (env.eval_arg (i+3));
709 	PATH::curve (env, param, pt1, pt2, pt3);
710 
711 	pt1 = pt3;
712 	pt1.move_x (env.eval_arg (i+4));
713 	pt2 = pt1;
714 	pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
715 	pt3 = pt2;
716 	pt3.move_y (env.eval_arg (i+7));
717       }
718       if (i < env.argStack.get_count ())
719 	pt3.move_x (env.eval_arg (i));
720       PATH::curve (env, param, pt1, pt2, pt3);
721     }
722     else
723     {
724       for (; i + 8 <= env.argStack.get_count (); i += 8)
725       {
726 	pt1 = env.get_pt ();
727 	pt1.move_x (env.eval_arg (i));
728 	pt2 = pt1;
729 	pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
730 	pt3 = pt2;
731 	pt3.move_y (env.eval_arg (i+3));
732 	PATH::curve (env, param, pt1, pt2, pt3);
733 
734 	pt1 = pt3;
735 	pt1.move_y (env.eval_arg (i+4));
736 	pt2 = pt1;
737 	pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
738 	pt3 = pt2;
739 	pt3.move_x (env.eval_arg (i+7));
740 	if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0))
741 	  pt3.move_y (env.eval_arg (i+8));
742 	PATH::curve (env, param, pt1, pt2, pt3);
743       }
744     }
745   }
746 
747   /* default actions to be overridden */
movetoCFF::path_procs_t748   static void moveto (ENV &env, PARAM& param, const point_t &pt)
749   { env.moveto (pt); }
750 
lineCFF::path_procs_t751   static void line (ENV &env, PARAM& param, const point_t &pt1)
752   { PATH::moveto (env, param, pt1); }
753 
curveCFF::path_procs_t754   static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
755   { PATH::moveto (env, param, pt3); }
756 
hflexCFF::path_procs_t757   static void hflex (ENV &env, PARAM& param)
758   {
759     if (likely (env.argStack.get_count () == 7))
760     {
761       point_t pt1 = env.get_pt ();
762       pt1.move_x (env.eval_arg (0));
763       point_t pt2 = pt1;
764       pt2.move (env.eval_arg (1), env.eval_arg (2));
765       point_t pt3 = pt2;
766       pt3.move_x (env.eval_arg (3));
767       point_t pt4 = pt3;
768       pt4.move_x (env.eval_arg (4));
769       point_t pt5 = pt4;
770       pt5.move_x (env.eval_arg (5));
771       pt5.y = pt1.y;
772       point_t pt6 = pt5;
773       pt6.move_x (env.eval_arg (6));
774 
775       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
776     }
777     else
778       env.set_error ();
779   }
780 
flexCFF::path_procs_t781   static void flex (ENV &env, PARAM& param)
782   {
783     if (likely (env.argStack.get_count () == 13))
784     {
785       point_t pt1 = env.get_pt ();
786       pt1.move (env.eval_arg (0), env.eval_arg (1));
787       point_t pt2 = pt1;
788       pt2.move (env.eval_arg (2), env.eval_arg (3));
789       point_t pt3 = pt2;
790       pt3.move (env.eval_arg (4), env.eval_arg (5));
791       point_t pt4 = pt3;
792       pt4.move (env.eval_arg (6), env.eval_arg (7));
793       point_t pt5 = pt4;
794       pt5.move (env.eval_arg (8), env.eval_arg (9));
795       point_t pt6 = pt5;
796       pt6.move (env.eval_arg (10), env.eval_arg (11));
797 
798       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
799     }
800     else
801       env.set_error ();
802   }
803 
hflex1CFF::path_procs_t804   static void hflex1 (ENV &env, PARAM& param)
805   {
806     if (likely (env.argStack.get_count () == 9))
807     {
808       point_t pt1 = env.get_pt ();
809       pt1.move (env.eval_arg (0), env.eval_arg (1));
810       point_t pt2 = pt1;
811       pt2.move (env.eval_arg (2), env.eval_arg (3));
812       point_t pt3 = pt2;
813       pt3.move_x (env.eval_arg (4));
814       point_t pt4 = pt3;
815       pt4.move_x (env.eval_arg (5));
816       point_t pt5 = pt4;
817       pt5.move (env.eval_arg (6), env.eval_arg (7));
818       point_t pt6 = pt5;
819       pt6.move_x (env.eval_arg (8));
820       pt6.y = env.get_pt ().y;
821 
822       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
823     }
824     else
825       env.set_error ();
826   }
827 
flex1CFF::path_procs_t828   static void flex1 (ENV &env, PARAM& param)
829   {
830     if (likely (env.argStack.get_count () == 11))
831     {
832       point_t d;
833       for (unsigned int i = 0; i < 10; i += 2)
834 	d.move (env.eval_arg (i), env.eval_arg (i+1));
835 
836       point_t pt1 = env.get_pt ();
837       pt1.move (env.eval_arg (0), env.eval_arg (1));
838       point_t pt2 = pt1;
839       pt2.move (env.eval_arg (2), env.eval_arg (3));
840       point_t pt3 = pt2;
841       pt3.move (env.eval_arg (4), env.eval_arg (5));
842       point_t pt4 = pt3;
843       pt4.move (env.eval_arg (6), env.eval_arg (7));
844       point_t pt5 = pt4;
845       pt5.move (env.eval_arg (8), env.eval_arg (9));
846       point_t pt6 = pt5;
847 
848       if (fabs (d.x.to_real ()) > fabs (d.y.to_real ()))
849       {
850 	pt6.move_x (env.eval_arg (10));
851 	pt6.y = env.get_pt ().y;
852       }
853       else
854       {
855 	pt6.x = env.get_pt ().x;
856 	pt6.move_y (env.eval_arg (10));
857       }
858 
859       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
860     }
861     else
862       env.set_error ();
863   }
864 
865   protected:
curve2CFF::path_procs_t866   static void curve2 (ENV &env, PARAM& param,
867 		      const point_t &pt1, const point_t &pt2, const point_t &pt3,
868 		      const point_t &pt4, const point_t &pt5, const point_t &pt6)
869   {
870     PATH::curve (env, param, pt1, pt2, pt3);
871     PATH::curve (env, param, pt4, pt5, pt6);
872   }
873 };
874 
875 template <typename ENV, typename OPSET, typename PARAM>
876 struct cs_interpreter_t : interpreter_t<ENV>
877 {
cs_interpreter_tCFF::cs_interpreter_t878   cs_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {}
879 
interpretCFF::cs_interpreter_t880   bool interpret (PARAM& param)
881   {
882     SUPER::env.set_endchar (false);
883 
884     unsigned max_ops = HB_CFF_MAX_OPS;
885     for (;;) {
886       OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
887       if (unlikely (SUPER::env.in_error () || !--max_ops))
888       {
889 	SUPER::env.set_error ();
890 	return false;
891       }
892       if (SUPER::env.is_endchar ())
893 	break;
894     }
895 
896     return true;
897   }
898 
899   private:
900   typedef interpreter_t<ENV> SUPER;
901 };
902 
903 } /* namespace CFF */
904 
905 #endif /* HB_CFF_INTERP_CS_COMMON_HH */
906