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 const unsigned int kMaxOps = 10000; 61 struct call_stack_t : cff_stack_t<call_context_t, kMaxCallLimit> {}; 62 63 template <typename SUBRS> 64 struct biased_subrs_t 65 { initCFF::biased_subrs_t66 void init (const SUBRS *subrs_) 67 { 68 subrs = subrs_; 69 unsigned int nSubrs = get_count (); 70 if (nSubrs < 1240) 71 bias = 107; 72 else if (nSubrs < 33900) 73 bias = 1131; 74 else 75 bias = 32768; 76 } 77 finiCFF::biased_subrs_t78 void fini () {} 79 get_countCFF::biased_subrs_t80 unsigned int get_count () const { return subrs ? subrs->count : 0; } get_biasCFF::biased_subrs_t81 unsigned int get_bias () const { return bias; } 82 operator []CFF::biased_subrs_t83 hb_ubytes_t operator [] (unsigned int index) const 84 { 85 if (unlikely (!subrs || index >= subrs->count)) 86 return hb_ubytes_t (); 87 else 88 return (*subrs)[index]; 89 } 90 91 protected: 92 unsigned int bias; 93 const SUBRS *subrs; 94 }; 95 96 struct point_t 97 { set_intCFF::point_t98 void set_int (int _x, int _y) 99 { 100 x.set_int (_x); 101 y.set_int (_y); 102 } 103 move_xCFF::point_t104 void move_x (const number_t &dx) { x += dx; } move_yCFF::point_t105 void move_y (const number_t &dy) { y += dy; } moveCFF::point_t106 void move (const number_t &dx, const number_t &dy) { move_x (dx); move_y (dy); } moveCFF::point_t107 void move (const point_t &d) { move_x (d.x); move_y (d.y); } 108 109 number_t x; 110 number_t y; 111 }; 112 113 template <typename ARG, typename SUBRS> 114 struct cs_interp_env_t : interp_env_t<ARG> 115 { cs_interp_env_tCFF::cs_interp_env_t116 cs_interp_env_t (const hb_ubytes_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_) : 117 interp_env_t<ARG> (str) 118 { 119 context.init (str, CSType_CharString); 120 seen_moveto = true; 121 seen_hintmask = false; 122 hstem_count = 0; 123 vstem_count = 0; 124 hintmask_size = 0; 125 pt.set_int (0, 0); 126 globalSubrs.init (globalSubrs_); 127 localSubrs.init (localSubrs_); 128 } ~cs_interp_env_tCFF::cs_interp_env_t129 ~cs_interp_env_t () 130 { 131 globalSubrs.fini (); 132 localSubrs.fini (); 133 } 134 in_errorCFF::cs_interp_env_t135 bool in_error () const 136 { 137 return callStack.in_error () || SUPER::in_error (); 138 } 139 pop_subr_numCFF::cs_interp_env_t140 bool pop_subr_num (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num) 141 { 142 subr_num = 0; 143 int n = SUPER::argStack.pop_int (); 144 n += biasedSubrs.get_bias (); 145 if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ()))) 146 return false; 147 148 subr_num = (unsigned int)n; 149 return true; 150 } 151 call_subrCFF::cs_interp_env_t152 void call_subr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type) 153 { 154 unsigned int subr_num = 0; 155 156 if (unlikely (!pop_subr_num (biasedSubrs, subr_num) 157 || callStack.get_count () >= kMaxCallLimit)) 158 { 159 SUPER::set_error (); 160 return; 161 } 162 context.str_ref = SUPER::str_ref; 163 callStack.push (context); 164 165 context.init ( biasedSubrs[subr_num], type, subr_num); 166 SUPER::str_ref = context.str_ref; 167 } 168 return_from_subrCFF::cs_interp_env_t169 void return_from_subr () 170 { 171 if (unlikely (SUPER::str_ref.in_error ())) 172 SUPER::set_error (); 173 context = callStack.pop (); 174 SUPER::str_ref = context.str_ref; 175 } 176 determine_hintmask_sizeCFF::cs_interp_env_t177 void determine_hintmask_size () 178 { 179 if (!seen_hintmask) 180 { 181 vstem_count += SUPER::argStack.get_count() / 2; 182 hintmask_size = (hstem_count + vstem_count + 7) >> 3; 183 seen_hintmask = true; 184 } 185 } 186 set_endcharCFF::cs_interp_env_t187 void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; } is_endcharCFF::cs_interp_env_t188 bool is_endchar () const { return endchar_flag; } 189 get_xCFF::cs_interp_env_t190 const number_t &get_x () const { return pt.x; } get_yCFF::cs_interp_env_t191 const number_t &get_y () const { return pt.y; } get_ptCFF::cs_interp_env_t192 const point_t &get_pt () const { return pt; } 193 movetoCFF::cs_interp_env_t194 void moveto (const point_t &pt_ ) { pt = pt_; } 195 196 public: 197 call_context_t context; 198 bool endchar_flag; 199 bool seen_moveto; 200 bool seen_hintmask; 201 202 unsigned int hstem_count; 203 unsigned int vstem_count; 204 unsigned int hintmask_size; 205 call_stack_t callStack; 206 biased_subrs_t<SUBRS> globalSubrs; 207 biased_subrs_t<SUBRS> localSubrs; 208 209 private: 210 point_t pt; 211 212 typedef interp_env_t<ARG> SUPER; 213 }; 214 215 template <typename ENV, typename PARAM> 216 struct path_procs_null_t 217 { rmovetoCFF::path_procs_null_t218 static void rmoveto (ENV &env, PARAM& param) {} hmovetoCFF::path_procs_null_t219 static void hmoveto (ENV &env, PARAM& param) {} vmovetoCFF::path_procs_null_t220 static void vmoveto (ENV &env, PARAM& param) {} rlinetoCFF::path_procs_null_t221 static void rlineto (ENV &env, PARAM& param) {} hlinetoCFF::path_procs_null_t222 static void hlineto (ENV &env, PARAM& param) {} vlinetoCFF::path_procs_null_t223 static void vlineto (ENV &env, PARAM& param) {} rrcurvetoCFF::path_procs_null_t224 static void rrcurveto (ENV &env, PARAM& param) {} rcurvelineCFF::path_procs_null_t225 static void rcurveline (ENV &env, PARAM& param) {} rlinecurveCFF::path_procs_null_t226 static void rlinecurve (ENV &env, PARAM& param) {} vvcurvetoCFF::path_procs_null_t227 static void vvcurveto (ENV &env, PARAM& param) {} hhcurvetoCFF::path_procs_null_t228 static void hhcurveto (ENV &env, PARAM& param) {} vhcurvetoCFF::path_procs_null_t229 static void vhcurveto (ENV &env, PARAM& param) {} hvcurvetoCFF::path_procs_null_t230 static void hvcurveto (ENV &env, PARAM& param) {} movetoCFF::path_procs_null_t231 static void moveto (ENV &env, PARAM& param, const point_t &pt) {} lineCFF::path_procs_null_t232 static void line (ENV &env, PARAM& param, const point_t &pt1) {} curveCFF::path_procs_null_t233 static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) {} hflexCFF::path_procs_null_t234 static void hflex (ENV &env, PARAM& param) {} flexCFF::path_procs_null_t235 static void flex (ENV &env, PARAM& param) {} hflex1CFF::path_procs_null_t236 static void hflex1 (ENV &env, PARAM& param) {} flex1CFF::path_procs_null_t237 static void flex1 (ENV &env, PARAM& param) {} 238 }; 239 240 template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM>> 241 struct cs_opset_t : opset_t<ARG> 242 { process_opCFF::cs_opset_t243 static void process_op (op_code_t op, ENV &env, PARAM& param) 244 { 245 switch (op) { 246 247 case OpCode_return: 248 env.return_from_subr (); 249 break; 250 case OpCode_endchar: 251 OPSET::check_width (op, env, param); 252 env.set_endchar (true); 253 OPSET::flush_args_and_op (op, env, param); 254 break; 255 256 case OpCode_fixedcs: 257 env.argStack.push_fixed_from_substr (env.str_ref); 258 break; 259 260 case OpCode_callsubr: 261 env.call_subr (env.localSubrs, CSType_LocalSubr); 262 break; 263 264 case OpCode_callgsubr: 265 env.call_subr (env.globalSubrs, CSType_GlobalSubr); 266 break; 267 268 case OpCode_hstem: 269 case OpCode_hstemhm: 270 OPSET::check_width (op, env, param); 271 OPSET::process_hstem (op, env, param); 272 break; 273 case OpCode_vstem: 274 case OpCode_vstemhm: 275 OPSET::check_width (op, env, param); 276 OPSET::process_vstem (op, env, param); 277 break; 278 case OpCode_hintmask: 279 case OpCode_cntrmask: 280 OPSET::check_width (op, env, param); 281 OPSET::process_hintmask (op, env, param); 282 break; 283 case OpCode_rmoveto: 284 OPSET::check_width (op, env, param); 285 PATH::rmoveto (env, param); 286 OPSET::process_post_move (op, env, param); 287 break; 288 case OpCode_hmoveto: 289 OPSET::check_width (op, env, param); 290 PATH::hmoveto (env, param); 291 OPSET::process_post_move (op, env, param); 292 break; 293 case OpCode_vmoveto: 294 OPSET::check_width (op, env, param); 295 PATH::vmoveto (env, param); 296 OPSET::process_post_move (op, env, param); 297 break; 298 case OpCode_rlineto: 299 PATH::rlineto (env, param); 300 process_post_path (op, env, param); 301 break; 302 case OpCode_hlineto: 303 PATH::hlineto (env, param); 304 process_post_path (op, env, param); 305 break; 306 case OpCode_vlineto: 307 PATH::vlineto (env, param); 308 process_post_path (op, env, param); 309 break; 310 case OpCode_rrcurveto: 311 PATH::rrcurveto (env, param); 312 process_post_path (op, env, param); 313 break; 314 case OpCode_rcurveline: 315 PATH::rcurveline (env, param); 316 process_post_path (op, env, param); 317 break; 318 case OpCode_rlinecurve: 319 PATH::rlinecurve (env, param); 320 process_post_path (op, env, param); 321 break; 322 case OpCode_vvcurveto: 323 PATH::vvcurveto (env, param); 324 process_post_path (op, env, param); 325 break; 326 case OpCode_hhcurveto: 327 PATH::hhcurveto (env, param); 328 process_post_path (op, env, param); 329 break; 330 case OpCode_vhcurveto: 331 PATH::vhcurveto (env, param); 332 process_post_path (op, env, param); 333 break; 334 case OpCode_hvcurveto: 335 PATH::hvcurveto (env, param); 336 process_post_path (op, env, param); 337 break; 338 339 case OpCode_hflex: 340 PATH::hflex (env, param); 341 OPSET::process_post_flex (op, env, param); 342 break; 343 344 case OpCode_flex: 345 PATH::flex (env, param); 346 OPSET::process_post_flex (op, env, param); 347 break; 348 349 case OpCode_hflex1: 350 PATH::hflex1 (env, param); 351 OPSET::process_post_flex (op, env, param); 352 break; 353 354 case OpCode_flex1: 355 PATH::flex1 (env, param); 356 OPSET::process_post_flex (op, env, param); 357 break; 358 359 default: 360 SUPER::process_op (op, env); 361 break; 362 } 363 } 364 process_hstemCFF::cs_opset_t365 static void process_hstem (op_code_t op, ENV &env, PARAM& param) 366 { 367 env.hstem_count += env.argStack.get_count () / 2; 368 OPSET::flush_args_and_op (op, env, param); 369 } 370 process_vstemCFF::cs_opset_t371 static void process_vstem (op_code_t op, ENV &env, PARAM& param) 372 { 373 env.vstem_count += env.argStack.get_count () / 2; 374 OPSET::flush_args_and_op (op, env, param); 375 } 376 process_hintmaskCFF::cs_opset_t377 static void process_hintmask (op_code_t op, ENV &env, PARAM& param) 378 { 379 env.determine_hintmask_size (); 380 if (likely (env.str_ref.avail (env.hintmask_size))) 381 { 382 OPSET::flush_hintmask (op, env, param); 383 env.str_ref.inc (env.hintmask_size); 384 } 385 } 386 process_post_flexCFF::cs_opset_t387 static void process_post_flex (op_code_t op, ENV &env, PARAM& param) 388 { 389 OPSET::flush_args_and_op (op, env, param); 390 } 391 check_widthCFF::cs_opset_t392 static void check_width (op_code_t op, ENV &env, PARAM& param) 393 {} 394 process_post_moveCFF::cs_opset_t395 static void process_post_move (op_code_t op, ENV &env, PARAM& param) 396 { 397 if (!env.seen_moveto) 398 { 399 env.determine_hintmask_size (); 400 env.seen_moveto = true; 401 } 402 OPSET::flush_args_and_op (op, env, param); 403 } 404 process_post_pathCFF::cs_opset_t405 static void process_post_path (op_code_t op, ENV &env, PARAM& param) 406 { 407 OPSET::flush_args_and_op (op, env, param); 408 } 409 flush_args_and_opCFF::cs_opset_t410 static void flush_args_and_op (op_code_t op, ENV &env, PARAM& param) 411 { 412 OPSET::flush_args (env, param); 413 OPSET::flush_op (op, env, param); 414 } 415 flush_argsCFF::cs_opset_t416 static void flush_args (ENV &env, PARAM& param) 417 { 418 env.pop_n_args (env.argStack.get_count ()); 419 } 420 flush_opCFF::cs_opset_t421 static void flush_op (op_code_t op, ENV &env, PARAM& param) 422 { 423 } 424 flush_hintmaskCFF::cs_opset_t425 static void flush_hintmask (op_code_t op, ENV &env, PARAM& param) 426 { 427 OPSET::flush_args_and_op (op, env, param); 428 } 429 is_number_opCFF::cs_opset_t430 static bool is_number_op (op_code_t op) 431 { 432 switch (op) 433 { 434 case OpCode_shortint: 435 case OpCode_fixedcs: 436 case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1: 437 case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3: 438 case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1: 439 case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3: 440 return true; 441 442 default: 443 /* 1-byte integer */ 444 return (OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast); 445 } 446 } 447 448 protected: 449 typedef opset_t<ARG> SUPER; 450 }; 451 452 template <typename PATH, typename ENV, typename PARAM> 453 struct path_procs_t 454 { rmovetoCFF::path_procs_t455 static void rmoveto (ENV &env, PARAM& param) 456 { 457 point_t pt1 = env.get_pt (); 458 const number_t &dy = env.pop_arg (); 459 const number_t &dx = env.pop_arg (); 460 pt1.move (dx, dy); 461 PATH::moveto (env, param, pt1); 462 } 463 hmovetoCFF::path_procs_t464 static void hmoveto (ENV &env, PARAM& param) 465 { 466 point_t pt1 = env.get_pt (); 467 pt1.move_x (env.pop_arg ()); 468 PATH::moveto (env, param, pt1); 469 } 470 vmovetoCFF::path_procs_t471 static void vmoveto (ENV &env, PARAM& param) 472 { 473 point_t pt1 = env.get_pt (); 474 pt1.move_y (env.pop_arg ()); 475 PATH::moveto (env, param, pt1); 476 } 477 rlinetoCFF::path_procs_t478 static void rlineto (ENV &env, PARAM& param) 479 { 480 for (unsigned int i = 0; i + 2 <= env.argStack.get_count (); i += 2) 481 { 482 point_t pt1 = env.get_pt (); 483 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 484 PATH::line (env, param, pt1); 485 } 486 } 487 hlinetoCFF::path_procs_t488 static void hlineto (ENV &env, PARAM& param) 489 { 490 point_t pt1; 491 unsigned int i = 0; 492 for (; i + 2 <= env.argStack.get_count (); i += 2) 493 { 494 pt1 = env.get_pt (); 495 pt1.move_x (env.eval_arg (i)); 496 PATH::line (env, param, pt1); 497 pt1.move_y (env.eval_arg (i+1)); 498 PATH::line (env, param, pt1); 499 } 500 if (i < env.argStack.get_count ()) 501 { 502 pt1 = env.get_pt (); 503 pt1.move_x (env.eval_arg (i)); 504 PATH::line (env, param, pt1); 505 } 506 } 507 vlinetoCFF::path_procs_t508 static void vlineto (ENV &env, PARAM& param) 509 { 510 point_t pt1; 511 unsigned int i = 0; 512 for (; i + 2 <= env.argStack.get_count (); i += 2) 513 { 514 pt1 = env.get_pt (); 515 pt1.move_y (env.eval_arg (i)); 516 PATH::line (env, param, pt1); 517 pt1.move_x (env.eval_arg (i+1)); 518 PATH::line (env, param, pt1); 519 } 520 if (i < env.argStack.get_count ()) 521 { 522 pt1 = env.get_pt (); 523 pt1.move_y (env.eval_arg (i)); 524 PATH::line (env, param, pt1); 525 } 526 } 527 rrcurvetoCFF::path_procs_t528 static void rrcurveto (ENV &env, PARAM& param) 529 { 530 for (unsigned int i = 0; i + 6 <= env.argStack.get_count (); i += 6) 531 { 532 point_t pt1 = env.get_pt (); 533 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 534 point_t pt2 = pt1; 535 pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); 536 point_t pt3 = pt2; 537 pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); 538 PATH::curve (env, param, pt1, pt2, pt3); 539 } 540 } 541 rcurvelineCFF::path_procs_t542 static void rcurveline (ENV &env, PARAM& param) 543 { 544 unsigned int arg_count = env.argStack.get_count (); 545 if (unlikely (arg_count < 8)) 546 return; 547 548 unsigned int i = 0; 549 unsigned int curve_limit = arg_count - 2; 550 for (; i + 6 <= curve_limit; i += 6) 551 { 552 point_t pt1 = env.get_pt (); 553 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 554 point_t pt2 = pt1; 555 pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); 556 point_t pt3 = pt2; 557 pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); 558 PATH::curve (env, param, pt1, pt2, pt3); 559 } 560 561 point_t pt1 = env.get_pt (); 562 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 563 PATH::line (env, param, pt1); 564 } 565 rlinecurveCFF::path_procs_t566 static void rlinecurve (ENV &env, PARAM& param) 567 { 568 unsigned int arg_count = env.argStack.get_count (); 569 if (unlikely (arg_count < 8)) 570 return; 571 572 unsigned int i = 0; 573 unsigned int line_limit = arg_count - 6; 574 for (; i + 2 <= line_limit; i += 2) 575 { 576 point_t pt1 = env.get_pt (); 577 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 578 PATH::line (env, param, pt1); 579 } 580 581 point_t pt1 = env.get_pt (); 582 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 583 point_t pt2 = pt1; 584 pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); 585 point_t pt3 = pt2; 586 pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); 587 PATH::curve (env, param, pt1, pt2, pt3); 588 } 589 vvcurvetoCFF::path_procs_t590 static void vvcurveto (ENV &env, PARAM& param) 591 { 592 unsigned int i = 0; 593 point_t pt1 = env.get_pt (); 594 if ((env.argStack.get_count () & 1) != 0) 595 pt1.move_x (env.eval_arg (i++)); 596 for (; i + 4 <= env.argStack.get_count (); i += 4) 597 { 598 pt1.move_y (env.eval_arg (i)); 599 point_t pt2 = pt1; 600 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 601 point_t pt3 = pt2; 602 pt3.move_y (env.eval_arg (i+3)); 603 PATH::curve (env, param, pt1, pt2, pt3); 604 pt1 = env.get_pt (); 605 } 606 } 607 hhcurvetoCFF::path_procs_t608 static void hhcurveto (ENV &env, PARAM& param) 609 { 610 unsigned int i = 0; 611 point_t pt1 = env.get_pt (); 612 if ((env.argStack.get_count () & 1) != 0) 613 pt1.move_y (env.eval_arg (i++)); 614 for (; i + 4 <= env.argStack.get_count (); i += 4) 615 { 616 pt1.move_x (env.eval_arg (i)); 617 point_t pt2 = pt1; 618 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 619 point_t pt3 = pt2; 620 pt3.move_x (env.eval_arg (i+3)); 621 PATH::curve (env, param, pt1, pt2, pt3); 622 pt1 = env.get_pt (); 623 } 624 } 625 vhcurvetoCFF::path_procs_t626 static void vhcurveto (ENV &env, PARAM& param) 627 { 628 point_t pt1, pt2, pt3; 629 unsigned int i = 0; 630 if ((env.argStack.get_count () % 8) >= 4) 631 { 632 point_t pt1 = env.get_pt (); 633 pt1.move_y (env.eval_arg (i)); 634 point_t pt2 = pt1; 635 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 636 point_t pt3 = pt2; 637 pt3.move_x (env.eval_arg (i+3)); 638 i += 4; 639 640 for (; i + 8 <= env.argStack.get_count (); i += 8) 641 { 642 PATH::curve (env, param, pt1, pt2, pt3); 643 pt1 = env.get_pt (); 644 pt1.move_x (env.eval_arg (i)); 645 pt2 = pt1; 646 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 647 pt3 = pt2; 648 pt3.move_y (env.eval_arg (i+3)); 649 PATH::curve (env, param, pt1, pt2, pt3); 650 651 pt1 = pt3; 652 pt1.move_y (env.eval_arg (i+4)); 653 pt2 = pt1; 654 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); 655 pt3 = pt2; 656 pt3.move_x (env.eval_arg (i+7)); 657 } 658 if (i < env.argStack.get_count ()) 659 pt3.move_y (env.eval_arg (i)); 660 PATH::curve (env, param, pt1, pt2, pt3); 661 } 662 else 663 { 664 for (; i + 8 <= env.argStack.get_count (); i += 8) 665 { 666 pt1 = env.get_pt (); 667 pt1.move_y (env.eval_arg (i)); 668 pt2 = pt1; 669 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 670 pt3 = pt2; 671 pt3.move_x (env.eval_arg (i+3)); 672 PATH::curve (env, param, pt1, pt2, pt3); 673 674 pt1 = pt3; 675 pt1.move_x (env.eval_arg (i+4)); 676 pt2 = pt1; 677 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); 678 pt3 = pt2; 679 pt3.move_y (env.eval_arg (i+7)); 680 if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0)) 681 pt3.move_x (env.eval_arg (i+8)); 682 PATH::curve (env, param, pt1, pt2, pt3); 683 } 684 } 685 } 686 hvcurvetoCFF::path_procs_t687 static void hvcurveto (ENV &env, PARAM& param) 688 { 689 point_t pt1, pt2, pt3; 690 unsigned int i = 0; 691 if ((env.argStack.get_count () % 8) >= 4) 692 { 693 point_t pt1 = env.get_pt (); 694 pt1.move_x (env.eval_arg (i)); 695 point_t pt2 = pt1; 696 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 697 point_t pt3 = pt2; 698 pt3.move_y (env.eval_arg (i+3)); 699 i += 4; 700 701 for (; i + 8 <= env.argStack.get_count (); i += 8) 702 { 703 PATH::curve (env, param, pt1, pt2, pt3); 704 pt1 = env.get_pt (); 705 pt1.move_y (env.eval_arg (i)); 706 pt2 = pt1; 707 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 708 pt3 = pt2; 709 pt3.move_x (env.eval_arg (i+3)); 710 PATH::curve (env, param, pt1, pt2, pt3); 711 712 pt1 = pt3; 713 pt1.move_x (env.eval_arg (i+4)); 714 pt2 = pt1; 715 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); 716 pt3 = pt2; 717 pt3.move_y (env.eval_arg (i+7)); 718 } 719 if (i < env.argStack.get_count ()) 720 pt3.move_x (env.eval_arg (i)); 721 PATH::curve (env, param, pt1, pt2, pt3); 722 } 723 else 724 { 725 for (; i + 8 <= env.argStack.get_count (); i += 8) 726 { 727 pt1 = env.get_pt (); 728 pt1.move_x (env.eval_arg (i)); 729 pt2 = pt1; 730 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 731 pt3 = pt2; 732 pt3.move_y (env.eval_arg (i+3)); 733 PATH::curve (env, param, pt1, pt2, pt3); 734 735 pt1 = pt3; 736 pt1.move_y (env.eval_arg (i+4)); 737 pt2 = pt1; 738 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); 739 pt3 = pt2; 740 pt3.move_x (env.eval_arg (i+7)); 741 if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0)) 742 pt3.move_y (env.eval_arg (i+8)); 743 PATH::curve (env, param, pt1, pt2, pt3); 744 } 745 } 746 } 747 748 /* default actions to be overridden */ movetoCFF::path_procs_t749 static void moveto (ENV &env, PARAM& param, const point_t &pt) 750 { env.moveto (pt); } 751 lineCFF::path_procs_t752 static void line (ENV &env, PARAM& param, const point_t &pt1) 753 { PATH::moveto (env, param, pt1); } 754 curveCFF::path_procs_t755 static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) 756 { PATH::moveto (env, param, pt3); } 757 hflexCFF::path_procs_t758 static void hflex (ENV &env, PARAM& param) 759 { 760 if (likely (env.argStack.get_count () == 7)) 761 { 762 point_t pt1 = env.get_pt (); 763 pt1.move_x (env.eval_arg (0)); 764 point_t pt2 = pt1; 765 pt2.move (env.eval_arg (1), env.eval_arg (2)); 766 point_t pt3 = pt2; 767 pt3.move_x (env.eval_arg (3)); 768 point_t pt4 = pt3; 769 pt4.move_x (env.eval_arg (4)); 770 point_t pt5 = pt4; 771 pt5.move_x (env.eval_arg (5)); 772 pt5.y = pt1.y; 773 point_t pt6 = pt5; 774 pt6.move_x (env.eval_arg (6)); 775 776 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); 777 } 778 else 779 env.set_error (); 780 } 781 flexCFF::path_procs_t782 static void flex (ENV &env, PARAM& param) 783 { 784 if (likely (env.argStack.get_count () == 13)) 785 { 786 point_t pt1 = env.get_pt (); 787 pt1.move (env.eval_arg (0), env.eval_arg (1)); 788 point_t pt2 = pt1; 789 pt2.move (env.eval_arg (2), env.eval_arg (3)); 790 point_t pt3 = pt2; 791 pt3.move (env.eval_arg (4), env.eval_arg (5)); 792 point_t pt4 = pt3; 793 pt4.move (env.eval_arg (6), env.eval_arg (7)); 794 point_t pt5 = pt4; 795 pt5.move (env.eval_arg (8), env.eval_arg (9)); 796 point_t pt6 = pt5; 797 pt6.move (env.eval_arg (10), env.eval_arg (11)); 798 799 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); 800 } 801 else 802 env.set_error (); 803 } 804 hflex1CFF::path_procs_t805 static void hflex1 (ENV &env, PARAM& param) 806 { 807 if (likely (env.argStack.get_count () == 9)) 808 { 809 point_t pt1 = env.get_pt (); 810 pt1.move (env.eval_arg (0), env.eval_arg (1)); 811 point_t pt2 = pt1; 812 pt2.move (env.eval_arg (2), env.eval_arg (3)); 813 point_t pt3 = pt2; 814 pt3.move_x (env.eval_arg (4)); 815 point_t pt4 = pt3; 816 pt4.move_x (env.eval_arg (5)); 817 point_t pt5 = pt4; 818 pt5.move (env.eval_arg (6), env.eval_arg (7)); 819 point_t pt6 = pt5; 820 pt6.move_x (env.eval_arg (8)); 821 pt6.y = env.get_pt ().y; 822 823 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); 824 } 825 else 826 env.set_error (); 827 } 828 flex1CFF::path_procs_t829 static void flex1 (ENV &env, PARAM& param) 830 { 831 if (likely (env.argStack.get_count () == 11)) 832 { 833 point_t d; 834 for (unsigned int i = 0; i < 10; i += 2) 835 d.move (env.eval_arg (i), env.eval_arg (i+1)); 836 837 point_t pt1 = env.get_pt (); 838 pt1.move (env.eval_arg (0), env.eval_arg (1)); 839 point_t pt2 = pt1; 840 pt2.move (env.eval_arg (2), env.eval_arg (3)); 841 point_t pt3 = pt2; 842 pt3.move (env.eval_arg (4), env.eval_arg (5)); 843 point_t pt4 = pt3; 844 pt4.move (env.eval_arg (6), env.eval_arg (7)); 845 point_t pt5 = pt4; 846 pt5.move (env.eval_arg (8), env.eval_arg (9)); 847 point_t pt6 = pt5; 848 849 if (fabs (d.x.to_real ()) > fabs (d.y.to_real ())) 850 { 851 pt6.move_x (env.eval_arg (10)); 852 pt6.y = env.get_pt ().y; 853 } 854 else 855 { 856 pt6.x = env.get_pt ().x; 857 pt6.move_y (env.eval_arg (10)); 858 } 859 860 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); 861 } 862 else 863 env.set_error (); 864 } 865 866 protected: curve2CFF::path_procs_t867 static void curve2 (ENV &env, PARAM& param, 868 const point_t &pt1, const point_t &pt2, const point_t &pt3, 869 const point_t &pt4, const point_t &pt5, const point_t &pt6) 870 { 871 PATH::curve (env, param, pt1, pt2, pt3); 872 PATH::curve (env, param, pt4, pt5, pt6); 873 } 874 }; 875 876 template <typename ENV, typename OPSET, typename PARAM> 877 struct cs_interpreter_t : interpreter_t<ENV> 878 { cs_interpreter_tCFF::cs_interpreter_t879 cs_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {} 880 interpretCFF::cs_interpreter_t881 bool interpret (PARAM& param) 882 { 883 SUPER::env.set_endchar (false); 884 885 unsigned max_ops = kMaxOps; 886 for (;;) { 887 if (unlikely (!--max_ops)) 888 { 889 SUPER::env.set_error (); 890 break; 891 } 892 OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); 893 if (unlikely (SUPER::env.in_error ())) 894 return false; 895 if (SUPER::env.is_endchar ()) 896 break; 897 } 898 899 return true; 900 } 901 902 private: 903 typedef interpreter_t<ENV> SUPER; 904 }; 905 906 } /* namespace CFF */ 907 908 #endif /* HB_CFF_INTERP_CS_COMMON_HH */ 909