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
32namespace CFF {
33
34using namespace OT;
35
36enum cs_type_t {
37 CSType_CharString,
38 CSType_GlobalSubr,
39 CSType_LocalSubr
40};
41
42struct call_context_t
43{
44 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
51 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 */
59const unsigned int kMaxCallLimit = 10;
60struct call_stack_t : stack_t<call_context_t, kMaxCallLimit> {};
61
62template <typename SUBRS>
63struct biased_subrs_t
64{
65 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
77 void fini () {}
78
79 unsigned int get_count () const { return (subrs == nullptr)? 0: subrs->count; }
80 unsigned int get_bias () const { return bias; }
81
82 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
95struct point_t
96{
97 void init ()
98 {
99 x.init ();
100 y.init ();
101 }
102
103 void set_int (int _x, int _y)
104 {
105 x.set_int (_x);
106 y.set_int (_y);
107 }
108
109 void move_x (const number_t &dx) { x += dx; }
110 void move_y (const number_t &dy) { y += dy; }
111 void move (const number_t &dx, const number_t &dy) { move_x (dx); move_y (dy); }
112 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
118template <typename ARG, typename SUBRS>
119struct cs_interp_env_t : interp_env_t<ARG>
120{
121 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 }
136 void fini ()
137 {
138 interp_env_t<ARG>::fini ();
139
140 callStack.fini ();
141 globalSubrs.fini ();
142 localSubrs.fini ();
143 }
144
145 bool in_error () const
146 {
147 return callStack.in_error () || SUPER::in_error ();
148 }
149
150 bool popSubrNum (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num)
151 {
152 int n = SUPER::argStack.pop_int ();
153 n += biasedSubrs.get_bias ();
154 if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ())))
155 return false;
156
157 subr_num = (unsigned int)n;
158 return true;
159 }
160
161 void callSubr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type)
162 {
163 unsigned int subr_num;
164
165 if (unlikely (!popSubrNum (biasedSubrs, subr_num)
166 || callStack.get_count () >= kMaxCallLimit))
167 {
168 SUPER::set_error ();
169 return;
170 }
171 context.str_ref = SUPER::str_ref;
172 callStack.push (context);
173
174 context.init ( biasedSubrs[subr_num], type, subr_num);
175 SUPER::str_ref = context.str_ref;
176 }
177
178 void returnFromSubr ()
179 {
180 if (unlikely (SUPER::str_ref.in_error ()))
181 SUPER::set_error ();
182 context = callStack.pop ();
183 SUPER::str_ref = context.str_ref;
184 }
185
186 void determine_hintmask_size ()
187 {
188 if (!seen_hintmask)
189 {
190 vstem_count += SUPER::argStack.get_count() / 2;
191 hintmask_size = (hstem_count + vstem_count + 7) >> 3;
192 seen_hintmask = true;
193 }
194 }
195
196 void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; }
197 bool is_endchar () const { return endchar_flag; }
198
199 const number_t &get_x () const { return pt.x; }
200 const number_t &get_y () const { return pt.y; }
201 const point_t &get_pt () const { return pt; }
202
203 void moveto (const point_t &pt_ ) { pt = pt_; }
204
205 public:
206 call_context_t context;
207 bool endchar_flag;
208 bool seen_moveto;
209 bool seen_hintmask;
210
211 unsigned int hstem_count;
212 unsigned int vstem_count;
213 unsigned int hintmask_size;
214 call_stack_t callStack;
215 biased_subrs_t<SUBRS> globalSubrs;
216 biased_subrs_t<SUBRS> localSubrs;
217
218 private:
219 point_t pt;
220
221 typedef interp_env_t<ARG> SUPER;
222};
223
224template <typename ENV, typename PARAM>
225struct path_procs_null_t
226{
227 static void rmoveto (ENV &env, PARAM& param) {}
228 static void hmoveto (ENV &env, PARAM& param) {}
229 static void vmoveto (ENV &env, PARAM& param) {}
230 static void rlineto (ENV &env, PARAM& param) {}
231 static void hlineto (ENV &env, PARAM& param) {}
232 static void vlineto (ENV &env, PARAM& param) {}
233 static void rrcurveto (ENV &env, PARAM& param) {}
234 static void rcurveline (ENV &env, PARAM& param) {}
235 static void rlinecurve (ENV &env, PARAM& param) {}
236 static void vvcurveto (ENV &env, PARAM& param) {}
237 static void hhcurveto (ENV &env, PARAM& param) {}
238 static void vhcurveto (ENV &env, PARAM& param) {}
239 static void hvcurveto (ENV &env, PARAM& param) {}
240 static void moveto (ENV &env, PARAM& param, const point_t &pt) {}
241 static void line (ENV &env, PARAM& param, const point_t &pt1) {}
242 static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) {}
243 static void hflex (ENV &env, PARAM& param) {}
244 static void flex (ENV &env, PARAM& param) {}
245 static void hflex1 (ENV &env, PARAM& param) {}
246 static void flex1 (ENV &env, PARAM& param) {}
247};
248
249template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM> >
250struct cs_opset_t : opset_t<ARG>
251{
252 static void process_op (op_code_t op, ENV &env, PARAM& param)
253 {
254 switch (op) {
255
256 case OpCode_return:
257 env.returnFromSubr ();
258 break;
259 case OpCode_endchar:
260 OPSET::check_width (op, env, param);
261 env.set_endchar (true);
262 OPSET::flush_args_and_op (op, env, param);
263 break;
264
265 case OpCode_fixedcs:
266 env.argStack.push_fixed_from_substr (env.str_ref);
267 break;
268
269 case OpCode_callsubr:
270 env.callSubr (env.localSubrs, CSType_LocalSubr);
271 break;
272
273 case OpCode_callgsubr:
274 env.callSubr (env.globalSubrs, CSType_GlobalSubr);
275 break;
276
277 case OpCode_hstem:
278 case OpCode_hstemhm:
279 OPSET::check_width (op, env, param);
280 OPSET::process_hstem (op, env, param);
281 break;
282 case OpCode_vstem:
283 case OpCode_vstemhm:
284 OPSET::check_width (op, env, param);
285 OPSET::process_vstem (op, env, param);
286 break;
287 case OpCode_hintmask:
288 case OpCode_cntrmask:
289 OPSET::check_width (op, env, param);
290 OPSET::process_hintmask (op, env, param);
291 break;
292 case OpCode_rmoveto:
293 OPSET::check_width (op, env, param);
294 PATH::rmoveto (env, param);
295 OPSET::process_post_move (op, env, param);
296 break;
297 case OpCode_hmoveto:
298 OPSET::check_width (op, env, param);
299 PATH::hmoveto (env, param);
300 OPSET::process_post_move (op, env, param);
301 break;
302 case OpCode_vmoveto:
303 OPSET::check_width (op, env, param);
304 PATH::vmoveto (env, param);
305 OPSET::process_post_move (op, env, param);
306 break;
307 case OpCode_rlineto:
308 PATH::rlineto (env, param);
309 process_post_path (op, env, param);
310 break;
311 case OpCode_hlineto:
312 PATH::hlineto (env, param);
313 process_post_path (op, env, param);
314 break;
315 case OpCode_vlineto:
316 PATH::vlineto (env, param);
317 process_post_path (op, env, param);
318 break;
319 case OpCode_rrcurveto:
320 PATH::rrcurveto (env, param);
321 process_post_path (op, env, param);
322 break;
323 case OpCode_rcurveline:
324 PATH::rcurveline (env, param);
325 process_post_path (op, env, param);
326 break;
327 case OpCode_rlinecurve:
328 PATH::rlinecurve (env, param);
329 process_post_path (op, env, param);
330 break;
331 case OpCode_vvcurveto:
332 PATH::vvcurveto (env, param);
333 process_post_path (op, env, param);
334 break;
335 case OpCode_hhcurveto:
336 PATH::hhcurveto (env, param);
337 process_post_path (op, env, param);
338 break;
339 case OpCode_vhcurveto:
340 PATH::vhcurveto (env, param);
341 process_post_path (op, env, param);
342 break;
343 case OpCode_hvcurveto:
344 PATH::hvcurveto (env, param);
345 process_post_path (op, env, param);
346 break;
347
348 case OpCode_hflex:
349 PATH::hflex (env, param);
350 OPSET::process_post_flex (op, env, param);
351 break;
352
353 case OpCode_flex:
354 PATH::flex (env, param);
355 OPSET::process_post_flex (op, env, param);
356 break;
357
358 case OpCode_hflex1:
359 PATH::hflex1 (env, param);
360 OPSET::process_post_flex (op, env, param);
361 break;
362
363 case OpCode_flex1:
364 PATH::flex1 (env, param);
365 OPSET::process_post_flex (op, env, param);
366 break;
367
368 default:
369 SUPER::process_op (op, env);
370 break;
371 }
372 }
373
374 static void process_hstem (op_code_t op, ENV &env, PARAM& param)
375 {
376 env.hstem_count += env.argStack.get_count () / 2;
377 OPSET::flush_args_and_op (op, env, param);
378 }
379
380 static void process_vstem (op_code_t op, ENV &env, PARAM& param)
381 {
382 env.vstem_count += env.argStack.get_count () / 2;
383 OPSET::flush_args_and_op (op, env, param);
384 }
385
386 static void process_hintmask (op_code_t op, ENV &env, PARAM& param)
387 {
388 env.determine_hintmask_size ();
389 if (likely (env.str_ref.avail (env.hintmask_size)))
390 {
391 OPSET::flush_hintmask (op, env, param);
392 env.str_ref.inc (env.hintmask_size);
393 }
394 }
395
396 static void process_post_flex (op_code_t op, ENV &env, PARAM& param)
397 {
398 OPSET::flush_args_and_op (op, env, param);
399 }
400
401 static void check_width (op_code_t op, ENV &env, PARAM& param)
402 {}
403
404 static void process_post_move (op_code_t op, ENV &env, PARAM& param)
405 {
406 if (!env.seen_moveto)
407 {
408 env.determine_hintmask_size ();
409 env.seen_moveto = true;
410 }
411 OPSET::flush_args_and_op (op, env, param);
412 }
413
414 static void process_post_path (op_code_t op, ENV &env, PARAM& param)
415 {
416 OPSET::flush_args_and_op (op, env, param);
417 }
418
419 static void flush_args_and_op (op_code_t op, ENV &env, PARAM& param)
420 {
421 OPSET::flush_args (env, param);
422 OPSET::flush_op (op, env, param);
423 }
424
425 static void flush_args (ENV &env, PARAM& param)
426 {
427 env.pop_n_args (env.argStack.get_count ());
428 }
429
430 static void flush_op (op_code_t op, ENV &env, PARAM& param)
431 {
432 }
433
434 static void flush_hintmask (op_code_t op, ENV &env, PARAM& param)
435 {
436 OPSET::flush_args_and_op (op, env, param);
437 }
438
439 static bool is_number_op (op_code_t op)
440 {
441 switch (op)
442 {
443 case OpCode_shortint:
444 case OpCode_fixedcs:
445 case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1:
446 case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3:
447 case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
448 case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
449 return true;
450
451 default:
452 /* 1-byte integer */
453 return (OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast);
454 }
455 }
456
457 protected:
458 typedef opset_t<ARG> SUPER;
459};
460
461template <typename PATH, typename ENV, typename PARAM>
462struct path_procs_t
463{
464 static void rmoveto (ENV &env, PARAM& param)
465 {
466 point_t pt1 = env.get_pt ();
467 const number_t &dy = env.pop_arg ();
468 const number_t &dx = env.pop_arg ();
469 pt1.move (dx, dy);
470 PATH::moveto (env, param, pt1);
471 }
472
473 static void hmoveto (ENV &env, PARAM& param)
474 {
475 point_t pt1 = env.get_pt ();
476 pt1.move_x (env.pop_arg ());
477 PATH::moveto (env, param, pt1);
478 }
479
480 static void vmoveto (ENV &env, PARAM& param)
481 {
482 point_t pt1 = env.get_pt ();
483 pt1.move_y (env.pop_arg ());
484 PATH::moveto (env, param, pt1);
485 }
486
487 static void rlineto (ENV &env, PARAM& param)
488 {
489 for (unsigned int i = 0; i + 2 <= env.argStack.get_count (); i += 2)
490 {
491 point_t pt1 = env.get_pt ();
492 pt1.move (env.eval_arg (i), env.eval_arg (i+1));
493 PATH::line (env, param, pt1);
494 }
495 }
496
497 static void hlineto (ENV &env, PARAM& param)
498 {
499 point_t pt1;
500 unsigned int i = 0;
501 for (; i + 2 <= env.argStack.get_count (); i += 2)
502 {
503 pt1 = env.get_pt ();
504 pt1.move_x (env.eval_arg (i));
505 PATH::line (env, param, pt1);
506 pt1.move_y (env.eval_arg (i+1));
507 PATH::line (env, param, pt1);
508 }
509 if (i < env.argStack.get_count ())
510 {
511 pt1 = env.get_pt ();
512 pt1.move_x (env.eval_arg (i));
513 PATH::line (env, param, pt1);
514 }
515 }
516
517 static void vlineto (ENV &env, PARAM& param)
518 {
519 point_t pt1;
520 unsigned int i = 0;
521 for (; i + 2 <= env.argStack.get_count (); i += 2)
522 {
523 pt1 = env.get_pt ();
524 pt1.move_y (env.eval_arg (i));
525 PATH::line (env, param, pt1);
526 pt1.move_x (env.eval_arg (i+1));
527 PATH::line (env, param, pt1);
528 }
529 if (i < env.argStack.get_count ())
530 {
531 pt1 = env.get_pt ();
532 pt1.move_y (env.eval_arg (i));
533 PATH::line (env, param, pt1);
534 }
535 }
536
537 static void rrcurveto (ENV &env, PARAM& param)
538 {
539 for (unsigned int i = 0; i + 6 <= env.argStack.get_count (); i += 6)
540 {
541 point_t pt1 = env.get_pt ();
542 pt1.move (env.eval_arg (i), env.eval_arg (i+1));
543 point_t pt2 = pt1;
544 pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
545 point_t pt3 = pt2;
546 pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
547 PATH::curve (env, param, pt1, pt2, pt3);
548 }
549 }
550
551 static void rcurveline (ENV &env, PARAM& param)
552 {
553 unsigned int i = 0;
554 for (; i + 6 <= env.argStack.get_count (); 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 for (; i + 2 <= env.argStack.get_count (); i += 2)
565 {
566 point_t pt1 = env.get_pt ();
567 pt1.move (env.eval_arg (i), env.eval_arg (i+1));
568 PATH::line (env, param, pt1);
569 }
570 }
571
572 static void rlinecurve (ENV &env, PARAM& param)
573 {
574 unsigned int i = 0;
575 unsigned int line_limit = (env.argStack.get_count () % 6);
576 for (; i + 2 <= line_limit; i += 2)
577 {
578 point_t pt1 = env.get_pt ();
579 pt1.move (env.eval_arg (i), env.eval_arg (i+1));
580 PATH::line (env, param, pt1);
581 }
582 for (; i + 6 <= env.argStack.get_count (); i += 6)
583 {
584 point_t pt1 = env.get_pt ();
585 pt1.move (env.eval_arg (i), env.eval_arg (i+1));
586 point_t pt2 = pt1;
587 pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
588 point_t pt3 = pt2;
589 pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
590 PATH::curve (env, param, pt1, pt2, pt3);
591 }
592 }
593
594 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
612 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
630 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
691 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 */
753 static void moveto (ENV &env, PARAM& param, const point_t &pt)
754 { env.moveto (pt); }
755
756 static void line (ENV &env, PARAM& param, const point_t &pt1)
757 { PATH::moveto (env, param, pt1); }
758
759 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
762 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
786 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
809 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
833 static void flex1 (ENV &env, PARAM& param)
834 {
835 if (likely (env.argStack.get_count () == 11))
836 {
837 point_t d;
838 d.init ();
839 for (unsigned int i = 0; i < 10; i += 2)
840 d.move (env.eval_arg (i), env.eval_arg (i+1));
841
842 point_t pt1 = env.get_pt ();
843 pt1.move (env.eval_arg (0), env.eval_arg (1));
844 point_t pt2 = pt1;
845 pt2.move (env.eval_arg (2), env.eval_arg (3));
846 point_t pt3 = pt2;
847 pt3.move (env.eval_arg (4), env.eval_arg (5));
848 point_t pt4 = pt3;
849 pt4.move (env.eval_arg (6), env.eval_arg (7));
850 point_t pt5 = pt4;
851 pt5.move (env.eval_arg (8), env.eval_arg (9));
852 point_t pt6 = pt5;
853
854 if (fabs (d.x.to_real ()) > fabs (d.y.to_real ()))
855 {
856 pt6.move_x (env.eval_arg (10));
857 pt6.y = env.get_pt ().y;
858 }
859 else
860 {
861 pt6.x = env.get_pt ().x;
862 pt6.move_y (env.eval_arg (10));
863 }
864
865 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
866 }
867 else
868 env.set_error ();
869 }
870
871 protected:
872 static void curve2 (ENV &env, PARAM& param,
873 const point_t &pt1, const point_t &pt2, const point_t &pt3,
874 const point_t &pt4, const point_t &pt5, const point_t &pt6)
875 {
876 PATH::curve (env, param, pt1, pt2, pt3);
877 PATH::curve (env, param, pt4, pt5, pt6);
878 }
879};
880
881template <typename ENV, typename OPSET, typename PARAM>
882struct cs_interpreter_t : interpreter_t<ENV>
883{
884 bool interpret (PARAM& param)
885 {
886 SUPER::env.set_endchar (false);
887
888 for (;;) {
889 OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
890 if (unlikely (SUPER::env.in_error ()))
891 return false;
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