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 { initCFF::point_t97 void init () 98 { 99 x.init (); 100 y.init (); 101 } 102 set_intCFF::point_t103 void set_int (int _x, int _y) 104 { 105 x.set_int (_x); 106 y.set_int (_y); 107 } 108 move_xCFF::point_t109 void move_x (const number_t &dx) { x += dx; } move_yCFF::point_t110 void move_y (const number_t &dy) { y += dy; } moveCFF::point_t111 void move (const number_t &dx, const number_t &dy) { move_x (dx); move_y (dy); } moveCFF::point_t112 void move (const point_t &d) { move_x (d.x); move_y (d.y); } 113 114 number_t x; 115 number_t y; 116 }; 117 118 template <typename ARG, typename SUBRS> 119 struct cs_interp_env_t : interp_env_t<ARG> 120 { initCFF::cs_interp_env_t121 void init (const byte_str_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_) 122 { 123 interp_env_t<ARG>::init (str); 124 125 context.init (str, CSType_CharString); 126 seen_moveto = true; 127 seen_hintmask = false; 128 hstem_count = 0; 129 vstem_count = 0; 130 hintmask_size = 0; 131 pt.init (); 132 callStack.init (); 133 globalSubrs.init (globalSubrs_); 134 localSubrs.init (localSubrs_); 135 } finiCFF::cs_interp_env_t136 void fini () 137 { 138 interp_env_t<ARG>::fini (); 139 140 callStack.fini (); 141 globalSubrs.fini (); 142 localSubrs.fini (); 143 } 144 in_errorCFF::cs_interp_env_t145 bool in_error () const 146 { 147 return callStack.in_error () || SUPER::in_error (); 148 } 149 pop_subr_numCFF::cs_interp_env_t150 bool pop_subr_num (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num) 151 { 152 subr_num = 0; 153 int n = SUPER::argStack.pop_int (); 154 n += biasedSubrs.get_bias (); 155 if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ()))) 156 return false; 157 158 subr_num = (unsigned int)n; 159 return true; 160 } 161 call_subrCFF::cs_interp_env_t162 void call_subr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type) 163 { 164 unsigned int subr_num = 0; 165 166 if (unlikely (!pop_subr_num (biasedSubrs, subr_num) 167 || callStack.get_count () >= kMaxCallLimit)) 168 { 169 SUPER::set_error (); 170 return; 171 } 172 context.str_ref = SUPER::str_ref; 173 callStack.push (context); 174 175 context.init ( biasedSubrs[subr_num], type, subr_num); 176 SUPER::str_ref = context.str_ref; 177 } 178 return_from_subrCFF::cs_interp_env_t179 void return_from_subr () 180 { 181 if (unlikely (SUPER::str_ref.in_error ())) 182 SUPER::set_error (); 183 context = callStack.pop (); 184 SUPER::str_ref = context.str_ref; 185 } 186 determine_hintmask_sizeCFF::cs_interp_env_t187 void determine_hintmask_size () 188 { 189 if (!seen_hintmask) 190 { 191 vstem_count += SUPER::argStack.get_count() / 2; 192 hintmask_size = (hstem_count + vstem_count + 7) >> 3; 193 seen_hintmask = true; 194 } 195 } 196 set_endcharCFF::cs_interp_env_t197 void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; } is_endcharCFF::cs_interp_env_t198 bool is_endchar () const { return endchar_flag; } 199 get_xCFF::cs_interp_env_t200 const number_t &get_x () const { return pt.x; } get_yCFF::cs_interp_env_t201 const number_t &get_y () const { return pt.y; } get_ptCFF::cs_interp_env_t202 const point_t &get_pt () const { return pt; } 203 movetoCFF::cs_interp_env_t204 void moveto (const point_t &pt_ ) { pt = pt_; } 205 206 public: 207 call_context_t context; 208 bool endchar_flag; 209 bool seen_moveto; 210 bool seen_hintmask; 211 212 unsigned int hstem_count; 213 unsigned int vstem_count; 214 unsigned int hintmask_size; 215 call_stack_t callStack; 216 biased_subrs_t<SUBRS> globalSubrs; 217 biased_subrs_t<SUBRS> localSubrs; 218 219 private: 220 point_t pt; 221 222 typedef interp_env_t<ARG> SUPER; 223 }; 224 225 template <typename ENV, typename PARAM> 226 struct path_procs_null_t 227 { rmovetoCFF::path_procs_null_t228 static void rmoveto (ENV &env, PARAM& param) {} hmovetoCFF::path_procs_null_t229 static void hmoveto (ENV &env, PARAM& param) {} vmovetoCFF::path_procs_null_t230 static void vmoveto (ENV &env, PARAM& param) {} rlinetoCFF::path_procs_null_t231 static void rlineto (ENV &env, PARAM& param) {} hlinetoCFF::path_procs_null_t232 static void hlineto (ENV &env, PARAM& param) {} vlinetoCFF::path_procs_null_t233 static void vlineto (ENV &env, PARAM& param) {} rrcurvetoCFF::path_procs_null_t234 static void rrcurveto (ENV &env, PARAM& param) {} rcurvelineCFF::path_procs_null_t235 static void rcurveline (ENV &env, PARAM& param) {} rlinecurveCFF::path_procs_null_t236 static void rlinecurve (ENV &env, PARAM& param) {} vvcurvetoCFF::path_procs_null_t237 static void vvcurveto (ENV &env, PARAM& param) {} hhcurvetoCFF::path_procs_null_t238 static void hhcurveto (ENV &env, PARAM& param) {} vhcurvetoCFF::path_procs_null_t239 static void vhcurveto (ENV &env, PARAM& param) {} hvcurvetoCFF::path_procs_null_t240 static void hvcurveto (ENV &env, PARAM& param) {} movetoCFF::path_procs_null_t241 static void moveto (ENV &env, PARAM& param, const point_t &pt) {} lineCFF::path_procs_null_t242 static void line (ENV &env, PARAM& param, const point_t &pt1) {} curveCFF::path_procs_null_t243 static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) {} hflexCFF::path_procs_null_t244 static void hflex (ENV &env, PARAM& param) {} flexCFF::path_procs_null_t245 static void flex (ENV &env, PARAM& param) {} hflex1CFF::path_procs_null_t246 static void hflex1 (ENV &env, PARAM& param) {} flex1CFF::path_procs_null_t247 static void flex1 (ENV &env, PARAM& param) {} 248 }; 249 250 template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM>> 251 struct cs_opset_t : opset_t<ARG> 252 { process_opCFF::cs_opset_t253 static void process_op (op_code_t op, ENV &env, PARAM& param) 254 { 255 switch (op) { 256 257 case OpCode_return: 258 env.return_from_subr (); 259 break; 260 case OpCode_endchar: 261 OPSET::check_width (op, env, param); 262 env.set_endchar (true); 263 OPSET::flush_args_and_op (op, env, param); 264 break; 265 266 case OpCode_fixedcs: 267 env.argStack.push_fixed_from_substr (env.str_ref); 268 break; 269 270 case OpCode_callsubr: 271 env.call_subr (env.localSubrs, CSType_LocalSubr); 272 break; 273 274 case OpCode_callgsubr: 275 env.call_subr (env.globalSubrs, CSType_GlobalSubr); 276 break; 277 278 case OpCode_hstem: 279 case OpCode_hstemhm: 280 OPSET::check_width (op, env, param); 281 OPSET::process_hstem (op, env, param); 282 break; 283 case OpCode_vstem: 284 case OpCode_vstemhm: 285 OPSET::check_width (op, env, param); 286 OPSET::process_vstem (op, env, param); 287 break; 288 case OpCode_hintmask: 289 case OpCode_cntrmask: 290 OPSET::check_width (op, env, param); 291 OPSET::process_hintmask (op, env, param); 292 break; 293 case OpCode_rmoveto: 294 OPSET::check_width (op, env, param); 295 PATH::rmoveto (env, param); 296 OPSET::process_post_move (op, env, param); 297 break; 298 case OpCode_hmoveto: 299 OPSET::check_width (op, env, param); 300 PATH::hmoveto (env, param); 301 OPSET::process_post_move (op, env, param); 302 break; 303 case OpCode_vmoveto: 304 OPSET::check_width (op, env, param); 305 PATH::vmoveto (env, param); 306 OPSET::process_post_move (op, env, param); 307 break; 308 case OpCode_rlineto: 309 PATH::rlineto (env, param); 310 process_post_path (op, env, param); 311 break; 312 case OpCode_hlineto: 313 PATH::hlineto (env, param); 314 process_post_path (op, env, param); 315 break; 316 case OpCode_vlineto: 317 PATH::vlineto (env, param); 318 process_post_path (op, env, param); 319 break; 320 case OpCode_rrcurveto: 321 PATH::rrcurveto (env, param); 322 process_post_path (op, env, param); 323 break; 324 case OpCode_rcurveline: 325 PATH::rcurveline (env, param); 326 process_post_path (op, env, param); 327 break; 328 case OpCode_rlinecurve: 329 PATH::rlinecurve (env, param); 330 process_post_path (op, env, param); 331 break; 332 case OpCode_vvcurveto: 333 PATH::vvcurveto (env, param); 334 process_post_path (op, env, param); 335 break; 336 case OpCode_hhcurveto: 337 PATH::hhcurveto (env, param); 338 process_post_path (op, env, param); 339 break; 340 case OpCode_vhcurveto: 341 PATH::vhcurveto (env, param); 342 process_post_path (op, env, param); 343 break; 344 case OpCode_hvcurveto: 345 PATH::hvcurveto (env, param); 346 process_post_path (op, env, param); 347 break; 348 349 case OpCode_hflex: 350 PATH::hflex (env, param); 351 OPSET::process_post_flex (op, env, param); 352 break; 353 354 case OpCode_flex: 355 PATH::flex (env, param); 356 OPSET::process_post_flex (op, env, param); 357 break; 358 359 case OpCode_hflex1: 360 PATH::hflex1 (env, param); 361 OPSET::process_post_flex (op, env, param); 362 break; 363 364 case OpCode_flex1: 365 PATH::flex1 (env, param); 366 OPSET::process_post_flex (op, env, param); 367 break; 368 369 default: 370 SUPER::process_op (op, env); 371 break; 372 } 373 } 374 process_hstemCFF::cs_opset_t375 static void process_hstem (op_code_t op, ENV &env, PARAM& param) 376 { 377 env.hstem_count += env.argStack.get_count () / 2; 378 OPSET::flush_args_and_op (op, env, param); 379 } 380 process_vstemCFF::cs_opset_t381 static void process_vstem (op_code_t op, ENV &env, PARAM& param) 382 { 383 env.vstem_count += env.argStack.get_count () / 2; 384 OPSET::flush_args_and_op (op, env, param); 385 } 386 process_hintmaskCFF::cs_opset_t387 static void process_hintmask (op_code_t op, ENV &env, PARAM& param) 388 { 389 env.determine_hintmask_size (); 390 if (likely (env.str_ref.avail (env.hintmask_size))) 391 { 392 OPSET::flush_hintmask (op, env, param); 393 env.str_ref.inc (env.hintmask_size); 394 } 395 } 396 process_post_flexCFF::cs_opset_t397 static void process_post_flex (op_code_t op, ENV &env, PARAM& param) 398 { 399 OPSET::flush_args_and_op (op, env, param); 400 } 401 check_widthCFF::cs_opset_t402 static void check_width (op_code_t op, ENV &env, PARAM& param) 403 {} 404 process_post_moveCFF::cs_opset_t405 static void process_post_move (op_code_t op, ENV &env, PARAM& param) 406 { 407 if (!env.seen_moveto) 408 { 409 env.determine_hintmask_size (); 410 env.seen_moveto = true; 411 } 412 OPSET::flush_args_and_op (op, env, param); 413 } 414 process_post_pathCFF::cs_opset_t415 static void process_post_path (op_code_t op, ENV &env, PARAM& param) 416 { 417 OPSET::flush_args_and_op (op, env, param); 418 } 419 flush_args_and_opCFF::cs_opset_t420 static void flush_args_and_op (op_code_t op, ENV &env, PARAM& param) 421 { 422 OPSET::flush_args (env, param); 423 OPSET::flush_op (op, env, param); 424 } 425 flush_argsCFF::cs_opset_t426 static void flush_args (ENV &env, PARAM& param) 427 { 428 env.pop_n_args (env.argStack.get_count ()); 429 } 430 flush_opCFF::cs_opset_t431 static void flush_op (op_code_t op, ENV &env, PARAM& param) 432 { 433 } 434 flush_hintmaskCFF::cs_opset_t435 static void flush_hintmask (op_code_t op, ENV &env, PARAM& param) 436 { 437 OPSET::flush_args_and_op (op, env, param); 438 } 439 is_number_opCFF::cs_opset_t440 static bool is_number_op (op_code_t op) 441 { 442 switch (op) 443 { 444 case OpCode_shortint: 445 case OpCode_fixedcs: 446 case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1: 447 case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3: 448 case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1: 449 case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3: 450 return true; 451 452 default: 453 /* 1-byte integer */ 454 return (OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast); 455 } 456 } 457 458 protected: 459 typedef opset_t<ARG> SUPER; 460 }; 461 462 template <typename PATH, typename ENV, typename PARAM> 463 struct path_procs_t 464 { rmovetoCFF::path_procs_t465 static void rmoveto (ENV &env, PARAM& param) 466 { 467 point_t pt1 = env.get_pt (); 468 const number_t &dy = env.pop_arg (); 469 const number_t &dx = env.pop_arg (); 470 pt1.move (dx, dy); 471 PATH::moveto (env, param, pt1); 472 } 473 hmovetoCFF::path_procs_t474 static void hmoveto (ENV &env, PARAM& param) 475 { 476 point_t pt1 = env.get_pt (); 477 pt1.move_x (env.pop_arg ()); 478 PATH::moveto (env, param, pt1); 479 } 480 vmovetoCFF::path_procs_t481 static void vmoveto (ENV &env, PARAM& param) 482 { 483 point_t pt1 = env.get_pt (); 484 pt1.move_y (env.pop_arg ()); 485 PATH::moveto (env, param, pt1); 486 } 487 rlinetoCFF::path_procs_t488 static void rlineto (ENV &env, PARAM& param) 489 { 490 for (unsigned int i = 0; i + 2 <= env.argStack.get_count (); i += 2) 491 { 492 point_t pt1 = env.get_pt (); 493 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 494 PATH::line (env, param, pt1); 495 } 496 } 497 hlinetoCFF::path_procs_t498 static void hlineto (ENV &env, PARAM& param) 499 { 500 point_t pt1; 501 unsigned int i = 0; 502 for (; i + 2 <= env.argStack.get_count (); i += 2) 503 { 504 pt1 = env.get_pt (); 505 pt1.move_x (env.eval_arg (i)); 506 PATH::line (env, param, pt1); 507 pt1.move_y (env.eval_arg (i+1)); 508 PATH::line (env, param, pt1); 509 } 510 if (i < env.argStack.get_count ()) 511 { 512 pt1 = env.get_pt (); 513 pt1.move_x (env.eval_arg (i)); 514 PATH::line (env, param, pt1); 515 } 516 } 517 vlinetoCFF::path_procs_t518 static void vlineto (ENV &env, PARAM& param) 519 { 520 point_t pt1; 521 unsigned int i = 0; 522 for (; i + 2 <= env.argStack.get_count (); i += 2) 523 { 524 pt1 = env.get_pt (); 525 pt1.move_y (env.eval_arg (i)); 526 PATH::line (env, param, pt1); 527 pt1.move_x (env.eval_arg (i+1)); 528 PATH::line (env, param, pt1); 529 } 530 if (i < env.argStack.get_count ()) 531 { 532 pt1 = env.get_pt (); 533 pt1.move_y (env.eval_arg (i)); 534 PATH::line (env, param, pt1); 535 } 536 } 537 rrcurvetoCFF::path_procs_t538 static void rrcurveto (ENV &env, PARAM& param) 539 { 540 for (unsigned int i = 0; i + 6 <= env.argStack.get_count (); i += 6) 541 { 542 point_t pt1 = env.get_pt (); 543 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 544 point_t pt2 = pt1; 545 pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); 546 point_t pt3 = pt2; 547 pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); 548 PATH::curve (env, param, pt1, pt2, pt3); 549 } 550 } 551 rcurvelineCFF::path_procs_t552 static void rcurveline (ENV &env, PARAM& param) 553 { 554 unsigned int arg_count = env.argStack.get_count (); 555 if (unlikely (arg_count < 8)) 556 return; 557 558 unsigned int i = 0; 559 unsigned int curve_limit = arg_count - 2; 560 for (; i + 6 <= curve_limit; i += 6) 561 { 562 point_t pt1 = env.get_pt (); 563 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 564 point_t pt2 = pt1; 565 pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); 566 point_t pt3 = pt2; 567 pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); 568 PATH::curve (env, param, pt1, pt2, pt3); 569 } 570 571 point_t pt1 = env.get_pt (); 572 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 573 PATH::line (env, param, pt1); 574 } 575 rlinecurveCFF::path_procs_t576 static void rlinecurve (ENV &env, PARAM& param) 577 { 578 unsigned int arg_count = env.argStack.get_count (); 579 if (unlikely (arg_count < 8)) 580 return; 581 582 unsigned int i = 0; 583 unsigned int line_limit = arg_count - 6; 584 for (; i + 2 <= line_limit; i += 2) 585 { 586 point_t pt1 = env.get_pt (); 587 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 588 PATH::line (env, param, pt1); 589 } 590 591 point_t pt1 = env.get_pt (); 592 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 593 point_t pt2 = pt1; 594 pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); 595 point_t pt3 = pt2; 596 pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); 597 PATH::curve (env, param, pt1, pt2, pt3); 598 } 599 vvcurvetoCFF::path_procs_t600 static void vvcurveto (ENV &env, PARAM& param) 601 { 602 unsigned int i = 0; 603 point_t pt1 = env.get_pt (); 604 if ((env.argStack.get_count () & 1) != 0) 605 pt1.move_x (env.eval_arg (i++)); 606 for (; i + 4 <= env.argStack.get_count (); i += 4) 607 { 608 pt1.move_y (env.eval_arg (i)); 609 point_t pt2 = pt1; 610 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 611 point_t pt3 = pt2; 612 pt3.move_y (env.eval_arg (i+3)); 613 PATH::curve (env, param, pt1, pt2, pt3); 614 pt1 = env.get_pt (); 615 } 616 } 617 hhcurvetoCFF::path_procs_t618 static void hhcurveto (ENV &env, PARAM& param) 619 { 620 unsigned int i = 0; 621 point_t pt1 = env.get_pt (); 622 if ((env.argStack.get_count () & 1) != 0) 623 pt1.move_y (env.eval_arg (i++)); 624 for (; i + 4 <= env.argStack.get_count (); i += 4) 625 { 626 pt1.move_x (env.eval_arg (i)); 627 point_t pt2 = pt1; 628 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 629 point_t pt3 = pt2; 630 pt3.move_x (env.eval_arg (i+3)); 631 PATH::curve (env, param, pt1, pt2, pt3); 632 pt1 = env.get_pt (); 633 } 634 } 635 vhcurvetoCFF::path_procs_t636 static void vhcurveto (ENV &env, PARAM& param) 637 { 638 point_t pt1, pt2, pt3; 639 unsigned int i = 0; 640 if ((env.argStack.get_count () % 8) >= 4) 641 { 642 point_t pt1 = env.get_pt (); 643 pt1.move_y (env.eval_arg (i)); 644 point_t pt2 = pt1; 645 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 646 point_t pt3 = pt2; 647 pt3.move_x (env.eval_arg (i+3)); 648 i += 4; 649 650 for (; i + 8 <= env.argStack.get_count (); i += 8) 651 { 652 PATH::curve (env, param, pt1, pt2, pt3); 653 pt1 = env.get_pt (); 654 pt1.move_x (env.eval_arg (i)); 655 pt2 = pt1; 656 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 657 pt3 = pt2; 658 pt3.move_y (env.eval_arg (i+3)); 659 PATH::curve (env, param, pt1, pt2, pt3); 660 661 pt1 = pt3; 662 pt1.move_y (env.eval_arg (i+4)); 663 pt2 = pt1; 664 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); 665 pt3 = pt2; 666 pt3.move_x (env.eval_arg (i+7)); 667 } 668 if (i < env.argStack.get_count ()) 669 pt3.move_y (env.eval_arg (i)); 670 PATH::curve (env, param, pt1, pt2, pt3); 671 } 672 else 673 { 674 for (; i + 8 <= env.argStack.get_count (); i += 8) 675 { 676 pt1 = env.get_pt (); 677 pt1.move_y (env.eval_arg (i)); 678 pt2 = pt1; 679 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 680 pt3 = pt2; 681 pt3.move_x (env.eval_arg (i+3)); 682 PATH::curve (env, param, pt1, pt2, pt3); 683 684 pt1 = pt3; 685 pt1.move_x (env.eval_arg (i+4)); 686 pt2 = pt1; 687 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); 688 pt3 = pt2; 689 pt3.move_y (env.eval_arg (i+7)); 690 if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0)) 691 pt3.move_x (env.eval_arg (i+8)); 692 PATH::curve (env, param, pt1, pt2, pt3); 693 } 694 } 695 } 696 hvcurvetoCFF::path_procs_t697 static void hvcurveto (ENV &env, PARAM& param) 698 { 699 point_t pt1, pt2, pt3; 700 unsigned int i = 0; 701 if ((env.argStack.get_count () % 8) >= 4) 702 { 703 point_t pt1 = env.get_pt (); 704 pt1.move_x (env.eval_arg (i)); 705 point_t pt2 = pt1; 706 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 707 point_t pt3 = pt2; 708 pt3.move_y (env.eval_arg (i+3)); 709 i += 4; 710 711 for (; i + 8 <= env.argStack.get_count (); i += 8) 712 { 713 PATH::curve (env, param, pt1, pt2, pt3); 714 pt1 = env.get_pt (); 715 pt1.move_y (env.eval_arg (i)); 716 pt2 = pt1; 717 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 718 pt3 = pt2; 719 pt3.move_x (env.eval_arg (i+3)); 720 PATH::curve (env, param, pt1, pt2, pt3); 721 722 pt1 = pt3; 723 pt1.move_x (env.eval_arg (i+4)); 724 pt2 = pt1; 725 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); 726 pt3 = pt2; 727 pt3.move_y (env.eval_arg (i+7)); 728 } 729 if (i < env.argStack.get_count ()) 730 pt3.move_x (env.eval_arg (i)); 731 PATH::curve (env, param, pt1, pt2, pt3); 732 } 733 else 734 { 735 for (; i + 8 <= env.argStack.get_count (); i += 8) 736 { 737 pt1 = env.get_pt (); 738 pt1.move_x (env.eval_arg (i)); 739 pt2 = pt1; 740 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 741 pt3 = pt2; 742 pt3.move_y (env.eval_arg (i+3)); 743 PATH::curve (env, param, pt1, pt2, pt3); 744 745 pt1 = pt3; 746 pt1.move_y (env.eval_arg (i+4)); 747 pt2 = pt1; 748 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); 749 pt3 = pt2; 750 pt3.move_x (env.eval_arg (i+7)); 751 if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0)) 752 pt3.move_y (env.eval_arg (i+8)); 753 PATH::curve (env, param, pt1, pt2, pt3); 754 } 755 } 756 } 757 758 /* default actions to be overridden */ movetoCFF::path_procs_t759 static void moveto (ENV &env, PARAM& param, const point_t &pt) 760 { env.moveto (pt); } 761 lineCFF::path_procs_t762 static void line (ENV &env, PARAM& param, const point_t &pt1) 763 { PATH::moveto (env, param, pt1); } 764 curveCFF::path_procs_t765 static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) 766 { PATH::moveto (env, param, pt3); } 767 hflexCFF::path_procs_t768 static void hflex (ENV &env, PARAM& param) 769 { 770 if (likely (env.argStack.get_count () == 7)) 771 { 772 point_t pt1 = env.get_pt (); 773 pt1.move_x (env.eval_arg (0)); 774 point_t pt2 = pt1; 775 pt2.move (env.eval_arg (1), env.eval_arg (2)); 776 point_t pt3 = pt2; 777 pt3.move_x (env.eval_arg (3)); 778 point_t pt4 = pt3; 779 pt4.move_x (env.eval_arg (4)); 780 point_t pt5 = pt4; 781 pt5.move_x (env.eval_arg (5)); 782 pt5.y = pt1.y; 783 point_t pt6 = pt5; 784 pt6.move_x (env.eval_arg (6)); 785 786 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); 787 } 788 else 789 env.set_error (); 790 } 791 flexCFF::path_procs_t792 static void flex (ENV &env, PARAM& param) 793 { 794 if (likely (env.argStack.get_count () == 13)) 795 { 796 point_t pt1 = env.get_pt (); 797 pt1.move (env.eval_arg (0), env.eval_arg (1)); 798 point_t pt2 = pt1; 799 pt2.move (env.eval_arg (2), env.eval_arg (3)); 800 point_t pt3 = pt2; 801 pt3.move (env.eval_arg (4), env.eval_arg (5)); 802 point_t pt4 = pt3; 803 pt4.move (env.eval_arg (6), env.eval_arg (7)); 804 point_t pt5 = pt4; 805 pt5.move (env.eval_arg (8), env.eval_arg (9)); 806 point_t pt6 = pt5; 807 pt6.move (env.eval_arg (10), env.eval_arg (11)); 808 809 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); 810 } 811 else 812 env.set_error (); 813 } 814 hflex1CFF::path_procs_t815 static void hflex1 (ENV &env, PARAM& param) 816 { 817 if (likely (env.argStack.get_count () == 9)) 818 { 819 point_t pt1 = env.get_pt (); 820 pt1.move (env.eval_arg (0), env.eval_arg (1)); 821 point_t pt2 = pt1; 822 pt2.move (env.eval_arg (2), env.eval_arg (3)); 823 point_t pt3 = pt2; 824 pt3.move_x (env.eval_arg (4)); 825 point_t pt4 = pt3; 826 pt4.move_x (env.eval_arg (5)); 827 point_t pt5 = pt4; 828 pt5.move (env.eval_arg (6), env.eval_arg (7)); 829 point_t pt6 = pt5; 830 pt6.move_x (env.eval_arg (8)); 831 pt6.y = env.get_pt ().y; 832 833 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); 834 } 835 else 836 env.set_error (); 837 } 838 flex1CFF::path_procs_t839 static void flex1 (ENV &env, PARAM& param) 840 { 841 if (likely (env.argStack.get_count () == 11)) 842 { 843 point_t d; 844 d.init (); 845 for (unsigned int i = 0; i < 10; i += 2) 846 d.move (env.eval_arg (i), env.eval_arg (i+1)); 847 848 point_t pt1 = env.get_pt (); 849 pt1.move (env.eval_arg (0), env.eval_arg (1)); 850 point_t pt2 = pt1; 851 pt2.move (env.eval_arg (2), env.eval_arg (3)); 852 point_t pt3 = pt2; 853 pt3.move (env.eval_arg (4), env.eval_arg (5)); 854 point_t pt4 = pt3; 855 pt4.move (env.eval_arg (6), env.eval_arg (7)); 856 point_t pt5 = pt4; 857 pt5.move (env.eval_arg (8), env.eval_arg (9)); 858 point_t pt6 = pt5; 859 860 if (fabs (d.x.to_real ()) > fabs (d.y.to_real ())) 861 { 862 pt6.move_x (env.eval_arg (10)); 863 pt6.y = env.get_pt ().y; 864 } 865 else 866 { 867 pt6.x = env.get_pt ().x; 868 pt6.move_y (env.eval_arg (10)); 869 } 870 871 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); 872 } 873 else 874 env.set_error (); 875 } 876 877 protected: curve2CFF::path_procs_t878 static void curve2 (ENV &env, PARAM& param, 879 const point_t &pt1, const point_t &pt2, const point_t &pt3, 880 const point_t &pt4, const point_t &pt5, const point_t &pt6) 881 { 882 PATH::curve (env, param, pt1, pt2, pt3); 883 PATH::curve (env, param, pt4, pt5, pt6); 884 } 885 }; 886 887 template <typename ENV, typename OPSET, typename PARAM> 888 struct cs_interpreter_t : interpreter_t<ENV> 889 { interpretCFF::cs_interpreter_t890 bool interpret (PARAM& param) 891 { 892 SUPER::env.set_endchar (false); 893 894 for (;;) { 895 OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); 896 if (unlikely (SUPER::env.in_error ())) 897 return false; 898 if (SUPER::env.is_endchar ()) 899 break; 900 } 901 902 return true; 903 } 904 905 private: 906 typedef interpreter_t<ENV> SUPER; 907 }; 908 909 } /* namespace CFF */ 910 911 #endif /* HB_CFF_INTERP_CS_COMMON_HH */ 912