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