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 == nullptr) ? 0 : subrs->count; } 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 == 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 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 i = 0; 555 for (; i + 6 <= env.argStack.get_count (); i += 6) 556 { 557 point_t pt1 = env.get_pt (); 558 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 559 point_t pt2 = pt1; 560 pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); 561 point_t pt3 = pt2; 562 pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); 563 PATH::curve (env, param, pt1, pt2, pt3); 564 } 565 for (; i + 2 <= env.argStack.get_count (); i += 2) 566 { 567 point_t pt1 = env.get_pt (); 568 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 569 PATH::line (env, param, pt1); 570 } 571 } 572 rlinecurveCFF::path_procs_t573 static void rlinecurve (ENV &env, PARAM& param) 574 { 575 unsigned int i = 0; 576 unsigned int line_limit = (env.argStack.get_count () % 6); 577 for (; i + 2 <= line_limit; i += 2) 578 { 579 point_t pt1 = env.get_pt (); 580 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 581 PATH::line (env, param, pt1); 582 } 583 for (; i + 6 <= env.argStack.get_count (); i += 6) 584 { 585 point_t pt1 = env.get_pt (); 586 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 587 point_t pt2 = pt1; 588 pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); 589 point_t pt3 = pt2; 590 pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); 591 PATH::curve (env, param, pt1, pt2, pt3); 592 } 593 } 594 vvcurvetoCFF::path_procs_t595 static void vvcurveto (ENV &env, PARAM& param) 596 { 597 unsigned int i = 0; 598 point_t pt1 = env.get_pt (); 599 if ((env.argStack.get_count () & 1) != 0) 600 pt1.move_x (env.eval_arg (i++)); 601 for (; i + 4 <= env.argStack.get_count (); i += 4) 602 { 603 pt1.move_y (env.eval_arg (i)); 604 point_t pt2 = pt1; 605 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 606 point_t pt3 = pt2; 607 pt3.move_y (env.eval_arg (i+3)); 608 PATH::curve (env, param, pt1, pt2, pt3); 609 pt1 = env.get_pt (); 610 } 611 } 612 hhcurvetoCFF::path_procs_t613 static void hhcurveto (ENV &env, PARAM& param) 614 { 615 unsigned int i = 0; 616 point_t pt1 = env.get_pt (); 617 if ((env.argStack.get_count () & 1) != 0) 618 pt1.move_y (env.eval_arg (i++)); 619 for (; i + 4 <= env.argStack.get_count (); i += 4) 620 { 621 pt1.move_x (env.eval_arg (i)); 622 point_t pt2 = pt1; 623 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 624 point_t pt3 = pt2; 625 pt3.move_x (env.eval_arg (i+3)); 626 PATH::curve (env, param, pt1, pt2, pt3); 627 pt1 = env.get_pt (); 628 } 629 } 630 vhcurvetoCFF::path_procs_t631 static void vhcurveto (ENV &env, PARAM& param) 632 { 633 point_t pt1, pt2, pt3; 634 unsigned int i = 0; 635 if ((env.argStack.get_count () % 8) >= 4) 636 { 637 point_t pt1 = env.get_pt (); 638 pt1.move_y (env.eval_arg (i)); 639 point_t pt2 = pt1; 640 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 641 point_t pt3 = pt2; 642 pt3.move_x (env.eval_arg (i+3)); 643 i += 4; 644 645 for (; i + 8 <= env.argStack.get_count (); i += 8) 646 { 647 PATH::curve (env, param, pt1, pt2, pt3); 648 pt1 = env.get_pt (); 649 pt1.move_x (env.eval_arg (i)); 650 pt2 = pt1; 651 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 652 pt3 = pt2; 653 pt3.move_y (env.eval_arg (i+3)); 654 PATH::curve (env, param, pt1, pt2, pt3); 655 656 pt1 = pt3; 657 pt1.move_y (env.eval_arg (i+4)); 658 pt2 = pt1; 659 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); 660 pt3 = pt2; 661 pt3.move_x (env.eval_arg (i+7)); 662 } 663 if (i < env.argStack.get_count ()) 664 pt3.move_y (env.eval_arg (i)); 665 PATH::curve (env, param, pt1, pt2, pt3); 666 } 667 else 668 { 669 for (; i + 8 <= env.argStack.get_count (); i += 8) 670 { 671 pt1 = env.get_pt (); 672 pt1.move_y (env.eval_arg (i)); 673 pt2 = pt1; 674 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 675 pt3 = pt2; 676 pt3.move_x (env.eval_arg (i+3)); 677 PATH::curve (env, param, pt1, pt2, pt3); 678 679 pt1 = pt3; 680 pt1.move_x (env.eval_arg (i+4)); 681 pt2 = pt1; 682 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); 683 pt3 = pt2; 684 pt3.move_y (env.eval_arg (i+7)); 685 if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0)) 686 pt3.move_x (env.eval_arg (i+8)); 687 PATH::curve (env, param, pt1, pt2, pt3); 688 } 689 } 690 } 691 hvcurvetoCFF::path_procs_t692 static void hvcurveto (ENV &env, PARAM& param) 693 { 694 point_t pt1, pt2, pt3; 695 unsigned int i = 0; 696 if ((env.argStack.get_count () % 8) >= 4) 697 { 698 point_t pt1 = env.get_pt (); 699 pt1.move_x (env.eval_arg (i)); 700 point_t pt2 = pt1; 701 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 702 point_t pt3 = pt2; 703 pt3.move_y (env.eval_arg (i+3)); 704 i += 4; 705 706 for (; i + 8 <= env.argStack.get_count (); i += 8) 707 { 708 PATH::curve (env, param, pt1, pt2, pt3); 709 pt1 = env.get_pt (); 710 pt1.move_y (env.eval_arg (i)); 711 pt2 = pt1; 712 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 713 pt3 = pt2; 714 pt3.move_x (env.eval_arg (i+3)); 715 PATH::curve (env, param, pt1, pt2, pt3); 716 717 pt1 = pt3; 718 pt1.move_x (env.eval_arg (i+4)); 719 pt2 = pt1; 720 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); 721 pt3 = pt2; 722 pt3.move_y (env.eval_arg (i+7)); 723 } 724 if (i < env.argStack.get_count ()) 725 pt3.move_x (env.eval_arg (i)); 726 PATH::curve (env, param, pt1, pt2, pt3); 727 } 728 else 729 { 730 for (; i + 8 <= env.argStack.get_count (); i += 8) 731 { 732 pt1 = env.get_pt (); 733 pt1.move_x (env.eval_arg (i)); 734 pt2 = pt1; 735 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 736 pt3 = pt2; 737 pt3.move_y (env.eval_arg (i+3)); 738 PATH::curve (env, param, pt1, pt2, pt3); 739 740 pt1 = pt3; 741 pt1.move_y (env.eval_arg (i+4)); 742 pt2 = pt1; 743 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); 744 pt3 = pt2; 745 pt3.move_x (env.eval_arg (i+7)); 746 if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0)) 747 pt3.move_y (env.eval_arg (i+8)); 748 PATH::curve (env, param, pt1, pt2, pt3); 749 } 750 } 751 } 752 753 /* default actions to be overridden */ movetoCFF::path_procs_t754 static void moveto (ENV &env, PARAM& param, const point_t &pt) 755 { env.moveto (pt); } 756 lineCFF::path_procs_t757 static void line (ENV &env, PARAM& param, const point_t &pt1) 758 { PATH::moveto (env, param, pt1); } 759 curveCFF::path_procs_t760 static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) 761 { PATH::moveto (env, param, pt3); } 762 hflexCFF::path_procs_t763 static void hflex (ENV &env, PARAM& param) 764 { 765 if (likely (env.argStack.get_count () == 7)) 766 { 767 point_t pt1 = env.get_pt (); 768 pt1.move_x (env.eval_arg (0)); 769 point_t pt2 = pt1; 770 pt2.move (env.eval_arg (1), env.eval_arg (2)); 771 point_t pt3 = pt2; 772 pt3.move_x (env.eval_arg (3)); 773 point_t pt4 = pt3; 774 pt4.move_x (env.eval_arg (4)); 775 point_t pt5 = pt4; 776 pt5.move_x (env.eval_arg (5)); 777 pt5.y = pt1.y; 778 point_t pt6 = pt5; 779 pt6.move_x (env.eval_arg (6)); 780 781 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); 782 } 783 else 784 env.set_error (); 785 } 786 flexCFF::path_procs_t787 static void flex (ENV &env, PARAM& param) 788 { 789 if (likely (env.argStack.get_count () == 13)) 790 { 791 point_t pt1 = env.get_pt (); 792 pt1.move (env.eval_arg (0), env.eval_arg (1)); 793 point_t pt2 = pt1; 794 pt2.move (env.eval_arg (2), env.eval_arg (3)); 795 point_t pt3 = pt2; 796 pt3.move (env.eval_arg (4), env.eval_arg (5)); 797 point_t pt4 = pt3; 798 pt4.move (env.eval_arg (6), env.eval_arg (7)); 799 point_t pt5 = pt4; 800 pt5.move (env.eval_arg (8), env.eval_arg (9)); 801 point_t pt6 = pt5; 802 pt6.move (env.eval_arg (10), env.eval_arg (11)); 803 804 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); 805 } 806 else 807 env.set_error (); 808 } 809 hflex1CFF::path_procs_t810 static void hflex1 (ENV &env, PARAM& param) 811 { 812 if (likely (env.argStack.get_count () == 9)) 813 { 814 point_t pt1 = env.get_pt (); 815 pt1.move (env.eval_arg (0), env.eval_arg (1)); 816 point_t pt2 = pt1; 817 pt2.move (env.eval_arg (2), env.eval_arg (3)); 818 point_t pt3 = pt2; 819 pt3.move_x (env.eval_arg (4)); 820 point_t pt4 = pt3; 821 pt4.move_x (env.eval_arg (5)); 822 point_t pt5 = pt4; 823 pt5.move (env.eval_arg (6), env.eval_arg (7)); 824 point_t pt6 = pt5; 825 pt6.move_x (env.eval_arg (8)); 826 pt6.y = env.get_pt ().y; 827 828 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); 829 } 830 else 831 env.set_error (); 832 } 833 flex1CFF::path_procs_t834 static void flex1 (ENV &env, PARAM& param) 835 { 836 if (likely (env.argStack.get_count () == 11)) 837 { 838 point_t d; 839 d.init (); 840 for (unsigned int i = 0; i < 10; i += 2) 841 d.move (env.eval_arg (i), env.eval_arg (i+1)); 842 843 point_t pt1 = env.get_pt (); 844 pt1.move (env.eval_arg (0), env.eval_arg (1)); 845 point_t pt2 = pt1; 846 pt2.move (env.eval_arg (2), env.eval_arg (3)); 847 point_t pt3 = pt2; 848 pt3.move (env.eval_arg (4), env.eval_arg (5)); 849 point_t pt4 = pt3; 850 pt4.move (env.eval_arg (6), env.eval_arg (7)); 851 point_t pt5 = pt4; 852 pt5.move (env.eval_arg (8), env.eval_arg (9)); 853 point_t pt6 = pt5; 854 855 if (fabs (d.x.to_real ()) > fabs (d.y.to_real ())) 856 { 857 pt6.move_x (env.eval_arg (10)); 858 pt6.y = env.get_pt ().y; 859 } 860 else 861 { 862 pt6.x = env.get_pt ().x; 863 pt6.move_y (env.eval_arg (10)); 864 } 865 866 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); 867 } 868 else 869 env.set_error (); 870 } 871 872 protected: curve2CFF::path_procs_t873 static void curve2 (ENV &env, PARAM& param, 874 const point_t &pt1, const point_t &pt2, const point_t &pt3, 875 const point_t &pt4, const point_t &pt5, const point_t &pt6) 876 { 877 PATH::curve (env, param, pt1, pt2, pt3); 878 PATH::curve (env, param, pt4, pt5, pt6); 879 } 880 }; 881 882 template <typename ENV, typename OPSET, typename PARAM> 883 struct cs_interpreter_t : interpreter_t<ENV> 884 { interpretCFF::cs_interpreter_t885 bool interpret (PARAM& param) 886 { 887 SUPER::env.set_endchar (false); 888 889 for (;;) { 890 OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); 891 if (unlikely (SUPER::env.in_error ())) 892 return false; 893 if (SUPER::env.is_endchar ()) 894 break; 895 } 896 897 return true; 898 } 899 900 private: 901 typedef interpreter_t<ENV> SUPER; 902 }; 903 904 } /* namespace CFF */ 905 906 #endif /* HB_CFF_INTERP_CS_COMMON_HH */ 907