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 CSType { 37 CSType_CharString, 38 CSType_GlobalSubr, 39 CSType_LocalSubr 40 }; 41 42 struct CallContext 43 { initCFF::CallContext44 void init (const SubByteStr substr_=SubByteStr (), CSType type_=CSType_CharString, unsigned int subr_num_=0) 45 { 46 substr = substr_; 47 type = type_; 48 subr_num = subr_num_; 49 } 50 finiCFF::CallContext51 void fini () {} 52 53 SubByteStr substr; 54 CSType type; 55 unsigned int subr_num; 56 }; 57 58 /* call stack */ 59 const unsigned int kMaxCallLimit = 10; 60 struct CallStack : Stack<CallContext, kMaxCallLimit> {}; 61 62 template <typename SUBRS> 63 struct BiasedSubrs 64 { initCFF::BiasedSubrs65 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::BiasedSubrs77 void fini () {} 78 get_countCFF::BiasedSubrs79 unsigned int get_count () const { return (subrs == nullptr)? 0: subrs->count; } get_biasCFF::BiasedSubrs80 unsigned int get_bias () const { return bias; } 81 operator []CFF::BiasedSubrs82 ByteStr operator [] (unsigned int index) const 83 { 84 if (unlikely ((subrs == nullptr) || index >= subrs->count)) 85 return Null(ByteStr); 86 else 87 return (*subrs)[index]; 88 } 89 90 protected: 91 unsigned int bias; 92 const SUBRS *subrs; 93 }; 94 95 struct Point 96 { initCFF::Point97 void init () 98 { 99 x.init (); 100 y.init (); 101 } 102 set_intCFF::Point103 void set_int (int _x, int _y) 104 { 105 x.set_int (_x); 106 y.set_int (_y); 107 } 108 move_xCFF::Point109 void move_x (const Number &dx) { x += dx; } move_yCFF::Point110 void move_y (const Number &dy) { y += dy; } moveCFF::Point111 void move (const Number &dx, const Number &dy) { move_x (dx); move_y (dy); } moveCFF::Point112 void move (const Point &d) { move_x (d.x); move_y (d.y); } 113 114 Number x; 115 Number y; 116 }; 117 118 template <typename ARG, typename SUBRS> 119 struct CSInterpEnv : InterpEnv<ARG> 120 { initCFF::CSInterpEnv121 void init (const ByteStr &str, const SUBRS &globalSubrs_, const SUBRS &localSubrs_) 122 { 123 InterpEnv<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 pt.init (); 131 callStack.init (); 132 globalSubrs.init (globalSubrs_); 133 localSubrs.init (localSubrs_); 134 } finiCFF::CSInterpEnv135 void fini () 136 { 137 InterpEnv<ARG>::fini (); 138 139 callStack.fini (); 140 globalSubrs.fini (); 141 localSubrs.fini (); 142 } 143 in_errorCFF::CSInterpEnv144 bool in_error () const 145 { 146 return callStack.in_error () || SUPER::in_error (); 147 } 148 popSubrNumCFF::CSInterpEnv149 bool popSubrNum (const BiasedSubrs<SUBRS>& biasedSubrs, unsigned int &subr_num) 150 { 151 int n = SUPER::argStack.pop_int (); 152 n += biasedSubrs.get_bias (); 153 if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ()))) 154 return false; 155 156 subr_num = (unsigned int)n; 157 return true; 158 } 159 callSubrCFF::CSInterpEnv160 void callSubr (const BiasedSubrs<SUBRS>& biasedSubrs, CSType type) 161 { 162 unsigned int subr_num; 163 164 if (unlikely (!popSubrNum (biasedSubrs, subr_num) 165 || callStack.get_count () >= kMaxCallLimit)) 166 { 167 SUPER::set_error (); 168 return; 169 } 170 context.substr = SUPER::substr; 171 callStack.push (context); 172 173 context.init ( biasedSubrs[subr_num], type, subr_num); 174 SUPER::substr = context.substr; 175 } 176 returnFromSubrCFF::CSInterpEnv177 void returnFromSubr () 178 { 179 if (unlikely (SUPER::substr.in_error ())) 180 SUPER::set_error (); 181 context = callStack.pop (); 182 SUPER::substr = context.substr; 183 } 184 determine_hintmask_sizeCFF::CSInterpEnv185 void determine_hintmask_size () 186 { 187 if (!seen_hintmask) 188 { 189 vstem_count += SUPER::argStack.get_count() / 2; 190 hintmask_size = (hstem_count + vstem_count + 7) >> 3; 191 seen_hintmask = true; 192 } 193 } 194 set_endcharCFF::CSInterpEnv195 void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; } is_endcharCFF::CSInterpEnv196 bool is_endchar () const { return endchar_flag; } 197 get_xCFF::CSInterpEnv198 const Number &get_x () const { return pt.x; } get_yCFF::CSInterpEnv199 const Number &get_y () const { return pt.y; } get_ptCFF::CSInterpEnv200 const Point &get_pt () const { return pt; } 201 movetoCFF::CSInterpEnv202 void moveto (const Point &pt_ ) { pt = pt_; } 203 204 public: 205 CallContext context; 206 bool endchar_flag; 207 bool seen_moveto; 208 bool seen_hintmask; 209 210 unsigned int hstem_count; 211 unsigned int vstem_count; 212 unsigned int hintmask_size; 213 CallStack callStack; 214 BiasedSubrs<SUBRS> globalSubrs; 215 BiasedSubrs<SUBRS> localSubrs; 216 217 private: 218 Point pt; 219 220 typedef InterpEnv<ARG> SUPER; 221 }; 222 223 template <typename ENV, typename PARAM> 224 struct PathProcsNull 225 { rmovetoCFF::PathProcsNull226 static void rmoveto (ENV &env, PARAM& param) {} hmovetoCFF::PathProcsNull227 static void hmoveto (ENV &env, PARAM& param) {} vmovetoCFF::PathProcsNull228 static void vmoveto (ENV &env, PARAM& param) {} rlinetoCFF::PathProcsNull229 static void rlineto (ENV &env, PARAM& param) {} hlinetoCFF::PathProcsNull230 static void hlineto (ENV &env, PARAM& param) {} vlinetoCFF::PathProcsNull231 static void vlineto (ENV &env, PARAM& param) {} rrcurvetoCFF::PathProcsNull232 static void rrcurveto (ENV &env, PARAM& param) {} rcurvelineCFF::PathProcsNull233 static void rcurveline (ENV &env, PARAM& param) {} rlinecurveCFF::PathProcsNull234 static void rlinecurve (ENV &env, PARAM& param) {} vvcurvetoCFF::PathProcsNull235 static void vvcurveto (ENV &env, PARAM& param) {} hhcurvetoCFF::PathProcsNull236 static void hhcurveto (ENV &env, PARAM& param) {} vhcurvetoCFF::PathProcsNull237 static void vhcurveto (ENV &env, PARAM& param) {} hvcurvetoCFF::PathProcsNull238 static void hvcurveto (ENV &env, PARAM& param) {} movetoCFF::PathProcsNull239 static void moveto (ENV &env, PARAM& param, const Point &pt) {} lineCFF::PathProcsNull240 static void line (ENV &env, PARAM& param, const Point &pt1) {} curveCFF::PathProcsNull241 static void curve (ENV &env, PARAM& param, const Point &pt1, const Point &pt2, const Point &pt3) {} hflexCFF::PathProcsNull242 static void hflex (ENV &env, PARAM& param) {} flexCFF::PathProcsNull243 static void flex (ENV &env, PARAM& param) {} hflex1CFF::PathProcsNull244 static void hflex1 (ENV &env, PARAM& param) {} flex1CFF::PathProcsNull245 static void flex1 (ENV &env, PARAM& param) {} 246 }; 247 248 template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=PathProcsNull<ENV, PARAM> > 249 struct CSOpSet : OpSet<ARG> 250 { process_opCFF::CSOpSet251 static void process_op (OpCode op, ENV &env, PARAM& param) 252 { 253 switch (op) { 254 255 case OpCode_return: 256 env.returnFromSubr (); 257 break; 258 case OpCode_endchar: 259 OPSET::check_width (op, env, param); 260 env.set_endchar (true); 261 OPSET::flush_args_and_op (op, env, param); 262 break; 263 264 case OpCode_fixedcs: 265 env.argStack.push_fixed_from_substr (env.substr); 266 break; 267 268 case OpCode_callsubr: 269 env.callSubr (env.localSubrs, CSType_LocalSubr); 270 break; 271 272 case OpCode_callgsubr: 273 env.callSubr (env.globalSubrs, CSType_GlobalSubr); 274 break; 275 276 case OpCode_hstem: 277 case OpCode_hstemhm: 278 OPSET::check_width (op, env, param); 279 OPSET::process_hstem (op, env, param); 280 break; 281 case OpCode_vstem: 282 case OpCode_vstemhm: 283 OPSET::check_width (op, env, param); 284 OPSET::process_vstem (op, env, param); 285 break; 286 case OpCode_hintmask: 287 case OpCode_cntrmask: 288 OPSET::check_width (op, env, param); 289 OPSET::process_hintmask (op, env, param); 290 break; 291 case OpCode_rmoveto: 292 OPSET::check_width (op, env, param); 293 PATH::rmoveto (env, param); 294 OPSET::process_post_move (op, env, param); 295 break; 296 case OpCode_hmoveto: 297 OPSET::check_width (op, env, param); 298 PATH::hmoveto (env, param); 299 OPSET::process_post_move (op, env, param); 300 break; 301 case OpCode_vmoveto: 302 OPSET::check_width (op, env, param); 303 PATH::vmoveto (env, param); 304 OPSET::process_post_move (op, env, param); 305 break; 306 case OpCode_rlineto: 307 PATH::rlineto (env, param); 308 process_post_path (op, env, param); 309 break; 310 case OpCode_hlineto: 311 PATH::hlineto (env, param); 312 process_post_path (op, env, param); 313 break; 314 case OpCode_vlineto: 315 PATH::vlineto (env, param); 316 process_post_path (op, env, param); 317 break; 318 case OpCode_rrcurveto: 319 PATH::rrcurveto (env, param); 320 process_post_path (op, env, param); 321 break; 322 case OpCode_rcurveline: 323 PATH::rcurveline (env, param); 324 process_post_path (op, env, param); 325 break; 326 case OpCode_rlinecurve: 327 PATH::rlinecurve (env, param); 328 process_post_path (op, env, param); 329 break; 330 case OpCode_vvcurveto: 331 PATH::vvcurveto (env, param); 332 process_post_path (op, env, param); 333 break; 334 case OpCode_hhcurveto: 335 PATH::hhcurveto (env, param); 336 process_post_path (op, env, param); 337 break; 338 case OpCode_vhcurveto: 339 PATH::vhcurveto (env, param); 340 process_post_path (op, env, param); 341 break; 342 case OpCode_hvcurveto: 343 PATH::hvcurveto (env, param); 344 process_post_path (op, env, param); 345 break; 346 347 case OpCode_hflex: 348 PATH::hflex (env, param); 349 OPSET::process_post_flex (op, env, param); 350 break; 351 352 case OpCode_flex: 353 PATH::flex (env, param); 354 OPSET::process_post_flex (op, env, param); 355 break; 356 357 case OpCode_hflex1: 358 PATH::hflex1 (env, param); 359 OPSET::process_post_flex (op, env, param); 360 break; 361 362 case OpCode_flex1: 363 PATH::flex1 (env, param); 364 OPSET::process_post_flex (op, env, param); 365 break; 366 367 default: 368 SUPER::process_op (op, env); 369 break; 370 } 371 } 372 process_hstemCFF::CSOpSet373 static void process_hstem (OpCode op, ENV &env, PARAM& param) 374 { 375 env.hstem_count += env.argStack.get_count () / 2; 376 OPSET::flush_args_and_op (op, env, param); 377 } 378 process_vstemCFF::CSOpSet379 static void process_vstem (OpCode op, ENV &env, PARAM& param) 380 { 381 env.vstem_count += env.argStack.get_count () / 2; 382 OPSET::flush_args_and_op (op, env, param); 383 } 384 process_hintmaskCFF::CSOpSet385 static void process_hintmask (OpCode op, ENV &env, PARAM& param) 386 { 387 env.determine_hintmask_size (); 388 if (likely (env.substr.avail (env.hintmask_size))) 389 { 390 OPSET::flush_hintmask (op, env, param); 391 env.substr.inc (env.hintmask_size); 392 } 393 } 394 process_post_flexCFF::CSOpSet395 static void process_post_flex (OpCode op, ENV &env, PARAM& param) 396 { 397 OPSET::flush_args_and_op (op, env, param); 398 } 399 check_widthCFF::CSOpSet400 static void check_width (OpCode op, ENV &env, PARAM& param) 401 {} 402 process_post_moveCFF::CSOpSet403 static void process_post_move (OpCode op, ENV &env, PARAM& param) 404 { 405 if (!env.seen_moveto) 406 { 407 env.determine_hintmask_size (); 408 env.seen_moveto = true; 409 } 410 OPSET::flush_args_and_op (op, env, param); 411 } 412 process_post_pathCFF::CSOpSet413 static void process_post_path (OpCode op, ENV &env, PARAM& param) 414 { 415 OPSET::flush_args_and_op (op, env, param); 416 } 417 flush_args_and_opCFF::CSOpSet418 static void flush_args_and_op (OpCode op, ENV &env, PARAM& param) 419 { 420 OPSET::flush_args (env, param); 421 OPSET::flush_op (op, env, param); 422 } 423 flush_argsCFF::CSOpSet424 static void flush_args (ENV &env, PARAM& param) 425 { 426 env.pop_n_args (env.argStack.get_count ()); 427 } 428 flush_opCFF::CSOpSet429 static void flush_op (OpCode op, ENV &env, PARAM& param) 430 { 431 } 432 flush_hintmaskCFF::CSOpSet433 static void flush_hintmask (OpCode op, ENV &env, PARAM& param) 434 { 435 OPSET::flush_args_and_op (op, env, param); 436 } 437 is_number_opCFF::CSOpSet438 static bool is_number_op (OpCode op) 439 { 440 switch (op) 441 { 442 case OpCode_shortint: 443 case OpCode_fixedcs: 444 case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1: 445 case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3: 446 case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1: 447 case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3: 448 return true; 449 450 default: 451 /* 1-byte integer */ 452 return (OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast); 453 } 454 } 455 456 protected: 457 typedef OpSet<ARG> SUPER; 458 }; 459 460 template <typename PATH, typename ENV, typename PARAM> 461 struct PathProcs 462 { rmovetoCFF::PathProcs463 static void rmoveto (ENV &env, PARAM& param) 464 { 465 Point pt1 = env.get_pt (); 466 const Number &dy = env.pop_arg (); 467 const Number &dx = env.pop_arg (); 468 pt1.move (dx, dy); 469 PATH::moveto (env, param, pt1); 470 } 471 hmovetoCFF::PathProcs472 static void hmoveto (ENV &env, PARAM& param) 473 { 474 Point pt1 = env.get_pt (); 475 pt1.move_x (env.pop_arg ()); 476 PATH::moveto (env, param, pt1); 477 } 478 vmovetoCFF::PathProcs479 static void vmoveto (ENV &env, PARAM& param) 480 { 481 Point pt1 = env.get_pt (); 482 pt1.move_y (env.pop_arg ()); 483 PATH::moveto (env, param, pt1); 484 } 485 rlinetoCFF::PathProcs486 static void rlineto (ENV &env, PARAM& param) 487 { 488 for (unsigned int i = 0; i + 2 <= env.argStack.get_count (); i += 2) 489 { 490 Point pt1 = env.get_pt (); 491 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 492 PATH::line (env, param, pt1); 493 } 494 } 495 hlinetoCFF::PathProcs496 static void hlineto (ENV &env, PARAM& param) 497 { 498 Point pt1; 499 unsigned int i = 0; 500 for (; i + 2 <= env.argStack.get_count (); i += 2) 501 { 502 pt1 = env.get_pt (); 503 pt1.move_x (env.eval_arg (i)); 504 PATH::line (env, param, pt1); 505 pt1.move_y (env.eval_arg (i+1)); 506 PATH::line (env, param, pt1); 507 } 508 if (i < env.argStack.get_count ()) 509 { 510 pt1 = env.get_pt (); 511 pt1.move_x (env.eval_arg (i)); 512 PATH::line (env, param, pt1); 513 } 514 } 515 vlinetoCFF::PathProcs516 static void vlineto (ENV &env, PARAM& param) 517 { 518 Point pt1; 519 unsigned int i = 0; 520 for (; i + 2 <= env.argStack.get_count (); i += 2) 521 { 522 pt1 = env.get_pt (); 523 pt1.move_y (env.eval_arg (i)); 524 PATH::line (env, param, pt1); 525 pt1.move_x (env.eval_arg (i+1)); 526 PATH::line (env, param, pt1); 527 } 528 if (i < env.argStack.get_count ()) 529 { 530 pt1 = env.get_pt (); 531 pt1.move_y (env.eval_arg (i)); 532 PATH::line (env, param, pt1); 533 } 534 } 535 rrcurvetoCFF::PathProcs536 static void rrcurveto (ENV &env, PARAM& param) 537 { 538 for (unsigned int i = 0; i + 6 <= env.argStack.get_count (); i += 6) 539 { 540 Point pt1 = env.get_pt (); 541 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 542 Point pt2 = pt1; 543 pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); 544 Point pt3 = pt2; 545 pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); 546 PATH::curve (env, param, pt1, pt2, pt3); 547 } 548 } 549 rcurvelineCFF::PathProcs550 static void rcurveline (ENV &env, PARAM& param) 551 { 552 unsigned int i = 0; 553 for (; i + 6 <= env.argStack.get_count (); i += 6) 554 { 555 Point pt1 = env.get_pt (); 556 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 557 Point pt2 = pt1; 558 pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); 559 Point pt3 = pt2; 560 pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); 561 PATH::curve (env, param, pt1, pt2, pt3); 562 } 563 for (; i + 2 <= env.argStack.get_count (); i += 2) 564 { 565 Point pt1 = env.get_pt (); 566 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 567 PATH::line (env, param, pt1); 568 } 569 } 570 rlinecurveCFF::PathProcs571 static void rlinecurve (ENV &env, PARAM& param) 572 { 573 unsigned int i = 0; 574 unsigned int line_limit = (env.argStack.get_count () % 6); 575 for (; i + 2 <= line_limit; i += 2) 576 { 577 Point pt1 = env.get_pt (); 578 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 579 PATH::line (env, param, pt1); 580 } 581 for (; i + 6 <= env.argStack.get_count (); i += 6) 582 { 583 Point pt1 = env.get_pt (); 584 pt1.move (env.eval_arg (i), env.eval_arg (i+1)); 585 Point pt2 = pt1; 586 pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); 587 Point pt3 = pt2; 588 pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); 589 PATH::curve (env, param, pt1, pt2, pt3); 590 } 591 } 592 vvcurvetoCFF::PathProcs593 static void vvcurveto (ENV &env, PARAM& param) 594 { 595 unsigned int i = 0; 596 Point pt1 = env.get_pt (); 597 if ((env.argStack.get_count () & 1) != 0) 598 pt1.move_x (env.eval_arg (i++)); 599 for (; i + 4 <= env.argStack.get_count (); i += 4) 600 { 601 pt1.move_y (env.eval_arg (i)); 602 Point pt2 = pt1; 603 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 604 Point pt3 = pt2; 605 pt3.move_y (env.eval_arg (i+3)); 606 PATH::curve (env, param, pt1, pt2, pt3); 607 pt1 = env.get_pt (); 608 } 609 } 610 hhcurvetoCFF::PathProcs611 static void hhcurveto (ENV &env, PARAM& param) 612 { 613 unsigned int i = 0; 614 Point pt1 = env.get_pt (); 615 if ((env.argStack.get_count () & 1) != 0) 616 pt1.move_y (env.eval_arg (i++)); 617 for (; i + 4 <= env.argStack.get_count (); i += 4) 618 { 619 pt1.move_x (env.eval_arg (i)); 620 Point pt2 = pt1; 621 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 622 Point pt3 = pt2; 623 pt3.move_x (env.eval_arg (i+3)); 624 PATH::curve (env, param, pt1, pt2, pt3); 625 pt1 = env.get_pt (); 626 } 627 } 628 vhcurvetoCFF::PathProcs629 static void vhcurveto (ENV &env, PARAM& param) 630 { 631 Point pt1, pt2, pt3; 632 unsigned int i = 0; 633 if ((env.argStack.get_count () % 8) >= 4) 634 { 635 Point pt1 = env.get_pt (); 636 pt1.move_y (env.eval_arg (i)); 637 Point pt2 = pt1; 638 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 639 Point pt3 = pt2; 640 pt3.move_x (env.eval_arg (i+3)); 641 i += 4; 642 643 for (; i + 8 <= env.argStack.get_count (); i += 8) 644 { 645 PATH::curve (env, param, pt1, pt2, pt3); 646 pt1 = env.get_pt (); 647 pt1.move_x (env.eval_arg (i)); 648 pt2 = pt1; 649 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 650 pt3 = pt2; 651 pt3.move_y (env.eval_arg (i+3)); 652 PATH::curve (env, param, pt1, pt2, pt3); 653 654 pt1 = pt3; 655 pt1.move_y (env.eval_arg (i+4)); 656 pt2 = pt1; 657 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); 658 pt3 = pt2; 659 pt3.move_x (env.eval_arg (i+7)); 660 } 661 if (i < env.argStack.get_count ()) 662 pt3.move_y (env.eval_arg (i)); 663 PATH::curve (env, param, pt1, pt2, pt3); 664 } 665 else 666 { 667 for (; i + 8 <= env.argStack.get_count (); i += 8) 668 { 669 pt1 = env.get_pt (); 670 pt1.move_y (env.eval_arg (i)); 671 pt2 = pt1; 672 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 673 pt3 = pt2; 674 pt3.move_x (env.eval_arg (i+3)); 675 PATH::curve (env, param, pt1, pt2, pt3); 676 677 pt1 = pt3; 678 pt1.move_x (env.eval_arg (i+4)); 679 pt2 = pt1; 680 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); 681 pt3 = pt2; 682 pt3.move_y (env.eval_arg (i+7)); 683 if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0)) 684 pt3.move_x (env.eval_arg (i+8)); 685 PATH::curve (env, param, pt1, pt2, pt3); 686 } 687 } 688 } 689 hvcurvetoCFF::PathProcs690 static void hvcurveto (ENV &env, PARAM& param) 691 { 692 Point pt1, pt2, pt3; 693 unsigned int i = 0; 694 if ((env.argStack.get_count () % 8) >= 4) 695 { 696 Point pt1 = env.get_pt (); 697 pt1.move_x (env.eval_arg (i)); 698 Point pt2 = pt1; 699 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 700 Point pt3 = pt2; 701 pt3.move_y (env.eval_arg (i+3)); 702 i += 4; 703 704 for (; i + 8 <= env.argStack.get_count (); i += 8) 705 { 706 PATH::curve (env, param, pt1, pt2, pt3); 707 pt1 = env.get_pt (); 708 pt1.move_y (env.eval_arg (i)); 709 pt2 = pt1; 710 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 711 pt3 = pt2; 712 pt3.move_x (env.eval_arg (i+3)); 713 PATH::curve (env, param, pt1, pt2, pt3); 714 715 pt1 = pt3; 716 pt1.move_x (env.eval_arg (i+4)); 717 pt2 = pt1; 718 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); 719 pt3 = pt2; 720 pt3.move_y (env.eval_arg (i+7)); 721 } 722 if (i < env.argStack.get_count ()) 723 pt3.move_x (env.eval_arg (i)); 724 PATH::curve (env, param, pt1, pt2, pt3); 725 } 726 else 727 { 728 for (; i + 8 <= env.argStack.get_count (); i += 8) 729 { 730 pt1 = env.get_pt (); 731 pt1.move_x (env.eval_arg (i)); 732 pt2 = pt1; 733 pt2.move (env.eval_arg (i+1), env.eval_arg (i+2)); 734 pt3 = pt2; 735 pt3.move_y (env.eval_arg (i+3)); 736 PATH::curve (env, param, pt1, pt2, pt3); 737 738 pt1 = pt3; 739 pt1.move_y (env.eval_arg (i+4)); 740 pt2 = pt1; 741 pt2.move (env.eval_arg (i+5), env.eval_arg (i+6)); 742 pt3 = pt2; 743 pt3.move_x (env.eval_arg (i+7)); 744 if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0)) 745 pt3.move_y (env.eval_arg (i+8)); 746 PATH::curve (env, param, pt1, pt2, pt3); 747 } 748 } 749 } 750 751 /* default actions to be overridden */ movetoCFF::PathProcs752 static void moveto (ENV &env, PARAM& param, const Point &pt) 753 { env.moveto (pt); } 754 lineCFF::PathProcs755 static void line (ENV &env, PARAM& param, const Point &pt1) 756 { PATH::moveto (env, param, pt1); } 757 curveCFF::PathProcs758 static void curve (ENV &env, PARAM& param, const Point &pt1, const Point &pt2, const Point &pt3) 759 { PATH::moveto (env, param, pt3); } 760 hflexCFF::PathProcs761 static void hflex (ENV &env, PARAM& param) 762 { 763 if (likely (env.argStack.get_count () == 7)) 764 { 765 Point pt1 = env.get_pt (); 766 pt1.move_x (env.eval_arg (0)); 767 Point pt2 = pt1; 768 pt2.move (env.eval_arg (1), env.eval_arg (2)); 769 Point pt3 = pt2; 770 pt3.move_x (env.eval_arg (3)); 771 Point pt4 = pt3; 772 pt4.move_x (env.eval_arg (4)); 773 Point pt5 = pt4; 774 pt5.move_x (env.eval_arg (5)); 775 pt5.y = pt1.y; 776 Point pt6 = pt5; 777 pt6.move_x (env.eval_arg (6)); 778 779 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); 780 } 781 else 782 env.set_error (); 783 } 784 flexCFF::PathProcs785 static void flex (ENV &env, PARAM& param) 786 { 787 if (likely (env.argStack.get_count () == 13)) 788 { 789 Point pt1 = env.get_pt (); 790 pt1.move (env.eval_arg (0), env.eval_arg (1)); 791 Point pt2 = pt1; 792 pt2.move (env.eval_arg (2), env.eval_arg (3)); 793 Point pt3 = pt2; 794 pt3.move (env.eval_arg (4), env.eval_arg (5)); 795 Point pt4 = pt3; 796 pt4.move (env.eval_arg (6), env.eval_arg (7)); 797 Point pt5 = pt4; 798 pt5.move (env.eval_arg (8), env.eval_arg (9)); 799 Point pt6 = pt5; 800 pt6.move (env.eval_arg (10), env.eval_arg (11)); 801 802 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); 803 } 804 else 805 env.set_error (); 806 } 807 hflex1CFF::PathProcs808 static void hflex1 (ENV &env, PARAM& param) 809 { 810 if (likely (env.argStack.get_count () == 9)) 811 { 812 Point pt1 = env.get_pt (); 813 pt1.move (env.eval_arg (0), env.eval_arg (1)); 814 Point pt2 = pt1; 815 pt2.move (env.eval_arg (2), env.eval_arg (3)); 816 Point pt3 = pt2; 817 pt3.move_x (env.eval_arg (4)); 818 Point pt4 = pt3; 819 pt4.move_x (env.eval_arg (5)); 820 Point pt5 = pt4; 821 pt5.move (env.eval_arg (6), env.eval_arg (7)); 822 Point pt6 = pt5; 823 pt6.move_x (env.eval_arg (8)); 824 pt6.y = env.get_pt ().y; 825 826 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); 827 } 828 else 829 env.set_error (); 830 } 831 flex1CFF::PathProcs832 static void flex1 (ENV &env, PARAM& param) 833 { 834 if (likely (env.argStack.get_count () == 11)) 835 { 836 Point d; 837 d.init (); 838 for (unsigned int i = 0; i < 10; i += 2) 839 d.move (env.eval_arg (i), env.eval_arg (i+1)); 840 841 Point pt1 = env.get_pt (); 842 pt1.move (env.eval_arg (0), env.eval_arg (1)); 843 Point pt2 = pt1; 844 pt2.move (env.eval_arg (2), env.eval_arg (3)); 845 Point pt3 = pt2; 846 pt3.move (env.eval_arg (4), env.eval_arg (5)); 847 Point pt4 = pt3; 848 pt4.move (env.eval_arg (6), env.eval_arg (7)); 849 Point pt5 = pt4; 850 pt5.move (env.eval_arg (8), env.eval_arg (9)); 851 Point pt6 = pt5; 852 853 if (fabs (d.x.to_real ()) > fabs (d.y.to_real ())) 854 { 855 pt6.move_x (env.eval_arg (10)); 856 pt6.y = env.get_pt ().y; 857 } 858 else 859 { 860 pt6.x = env.get_pt ().x; 861 pt6.move_y (env.eval_arg (10)); 862 } 863 864 curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6); 865 } 866 else 867 env.set_error (); 868 } 869 870 protected: curve2CFF::PathProcs871 static void curve2 (ENV &env, PARAM& param, 872 const Point &pt1, const Point &pt2, const Point &pt3, 873 const Point &pt4, const Point &pt5, const Point &pt6) 874 { 875 PATH::curve (env, param, pt1, pt2, pt3); 876 PATH::curve (env, param, pt4, pt5, pt6); 877 } 878 }; 879 880 template <typename ENV, typename OPSET, typename PARAM> 881 struct CSInterpreter : Interpreter<ENV> 882 { interpretCFF::CSInterpreter883 bool interpret (PARAM& param) 884 { 885 SUPER::env.set_endchar (false); 886 887 for (;;) { 888 OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); 889 if (unlikely (SUPER::env.in_error ())) 890 return false; 891 if (SUPER::env.is_endchar ()) 892 break; 893 } 894 895 return true; 896 } 897 898 private: 899 typedef Interpreter<ENV> SUPER; 900 }; 901 902 } /* namespace CFF */ 903 904 #endif /* HB_CFF_INTERP_CS_COMMON_HH */ 905