1 /***************************************************************************/ 2 /* */ 3 /* cf2intrp.c */ 4 /* */ 5 /* Adobe's CFF Interpreter (body). */ 6 /* */ 7 /* Copyright 2007-2014 Adobe Systems Incorporated. */ 8 /* */ 9 /* This software, and all works of authorship, whether in source or */ 10 /* object code form as indicated by the copyright notice(s) included */ 11 /* herein (collectively, the "Work") is made available, and may only be */ 12 /* used, modified, and distributed under the FreeType Project License, */ 13 /* LICENSE.TXT. Additionally, subject to the terms and conditions of the */ 14 /* FreeType Project License, each contributor to the Work hereby grants */ 15 /* to any individual or legal entity exercising permissions granted by */ 16 /* the FreeType Project License and this section (hereafter, "You" or */ 17 /* "Your") a perpetual, worldwide, non-exclusive, no-charge, */ 18 /* royalty-free, irrevocable (except as stated in this section) patent */ 19 /* license to make, have made, use, offer to sell, sell, import, and */ 20 /* otherwise transfer the Work, where such license applies only to those */ 21 /* patent claims licensable by such contributor that are necessarily */ 22 /* infringed by their contribution(s) alone or by combination of their */ 23 /* contribution(s) with the Work to which such contribution(s) was */ 24 /* submitted. If You institute patent litigation against any entity */ 25 /* (including a cross-claim or counterclaim in a lawsuit) alleging that */ 26 /* the Work or a contribution incorporated within the Work constitutes */ 27 /* direct or contributory patent infringement, then any patent licenses */ 28 /* granted to You under this License for that Work shall terminate as of */ 29 /* the date such litigation is filed. */ 30 /* */ 31 /* By using, modifying, or distributing the Work you indicate that you */ 32 /* have read and understood the terms and conditions of the */ 33 /* FreeType Project License as well as those provided in this section, */ 34 /* and you accept them fully. */ 35 /* */ 36 /***************************************************************************/ 37 38 39 #include "cf2ft.h" 40 #include FT_INTERNAL_DEBUG_H 41 42 #include "cf2glue.h" 43 #include "cf2font.h" 44 #include "cf2stack.h" 45 #include "cf2hints.h" 46 #include "cf2intrp.h" 47 48 #include "cf2error.h" 49 50 #include "cffload.h" 51 52 53 /*************************************************************************/ 54 /* */ 55 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 56 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 57 /* messages during execution. */ 58 /* */ 59 #undef FT_COMPONENT 60 #define FT_COMPONENT trace_cf2interp 61 62 63 /* some operators are not implemented yet */ 64 #define CF2_FIXME FT_TRACE4(( "cf2_interpT2CharString:" \ 65 " operator not implemented yet\n" )) 66 67 68 69 FT_LOCAL_DEF( void ) 70 cf2_hintmask_init( CF2_HintMask hintmask, 71 FT_Error* error ) 72 { 73 FT_ZERO( hintmask ); 74 75 hintmask->error = error; 76 } 77 78 79 FT_LOCAL_DEF( FT_Bool ) 80 cf2_hintmask_isValid( const CF2_HintMask hintmask ) 81 { 82 return hintmask->isValid; 83 } 84 85 86 FT_LOCAL_DEF( FT_Bool ) 87 cf2_hintmask_isNew( const CF2_HintMask hintmask ) 88 { 89 return hintmask->isNew; 90 } 91 92 93 FT_LOCAL_DEF( void ) 94 cf2_hintmask_setNew( CF2_HintMask hintmask, 95 FT_Bool val ) 96 { 97 hintmask->isNew = val; 98 } 99 100 101 /* clients call `getMaskPtr' in order to iterate */ 102 /* through hint mask */ 103 104 FT_LOCAL_DEF( FT_Byte* ) 105 cf2_hintmask_getMaskPtr( CF2_HintMask hintmask ) 106 { 107 return hintmask->mask; 108 } 109 110 111 static size_t 112 cf2_hintmask_setCounts( CF2_HintMask hintmask, 113 size_t bitCount ) 114 { 115 if ( bitCount > CF2_MAX_HINTS ) 116 { 117 /* total of h and v stems must be <= 96 */ 118 CF2_SET_ERROR( hintmask->error, Invalid_Glyph_Format ); 119 return 0; 120 } 121 122 hintmask->bitCount = bitCount; 123 hintmask->byteCount = ( hintmask->bitCount + 7 ) / 8; 124 125 hintmask->isValid = TRUE; 126 hintmask->isNew = TRUE; 127 128 return bitCount; 129 } 130 131 132 /* consume the hintmask bytes from the charstring, advancing the src */ 133 /* pointer */ 134 static void 135 cf2_hintmask_read( CF2_HintMask hintmask, 136 CF2_Buffer charstring, 137 size_t bitCount ) 138 { 139 size_t i; 140 141 #ifndef CF2_NDEBUG 142 /* these are the bits in the final mask byte that should be zero */ 143 /* Note: this variable is only used in an assert expression below */ 144 /* and then only if CF2_NDEBUG is not defined */ 145 CF2_UInt mask = ( 1 << ( -(CF2_Int)bitCount & 7 ) ) - 1; 146 #endif 147 148 149 /* initialize counts and isValid */ 150 if ( cf2_hintmask_setCounts( hintmask, bitCount ) == 0 ) 151 return; 152 153 FT_ASSERT( hintmask->byteCount > 0 ); 154 155 FT_TRACE4(( " (maskbytes:" )); 156 157 /* set mask and advance interpreter's charstring pointer */ 158 for ( i = 0; i < hintmask->byteCount; i++ ) 159 { 160 hintmask->mask[i] = (FT_Byte)cf2_buf_readByte( charstring ); 161 FT_TRACE4(( " 0x%02X", hintmask->mask[i] )); 162 } 163 164 FT_TRACE4(( ")\n" )); 165 166 /* assert any unused bits in last byte are zero unless there's a prior */ 167 /* error */ 168 /* bitCount -> mask, 0 -> 0, 1 -> 7f, 2 -> 3f, ... 6 -> 3, 7 -> 1 */ 169 #ifndef CF2_NDEBUG 170 FT_ASSERT( ( hintmask->mask[hintmask->byteCount - 1] & mask ) == 0 || 171 *hintmask->error ); 172 #endif 173 } 174 175 176 FT_LOCAL_DEF( void ) 177 cf2_hintmask_setAll( CF2_HintMask hintmask, 178 size_t bitCount ) 179 { 180 size_t i; 181 CF2_UInt mask = ( 1 << ( -(CF2_Int)bitCount & 7 ) ) - 1; 182 183 184 /* initialize counts and isValid */ 185 if ( cf2_hintmask_setCounts( hintmask, bitCount ) == 0 ) 186 return; 187 188 FT_ASSERT( hintmask->byteCount > 0 ); 189 FT_ASSERT( hintmask->byteCount <= 190 sizeof ( hintmask->mask ) / sizeof ( hintmask->mask[0] ) ); 191 192 /* set mask to all ones */ 193 for ( i = 0; i < hintmask->byteCount; i++ ) 194 hintmask->mask[i] = 0xFF; 195 196 /* clear unused bits */ 197 /* bitCount -> mask, 0 -> 0, 1 -> 7f, 2 -> 3f, ... 6 -> 3, 7 -> 1 */ 198 hintmask->mask[hintmask->byteCount - 1] &= ~mask; 199 } 200 201 202 /* Type2 charstring opcodes */ 203 enum 204 { 205 cf2_cmdRESERVED_0, /* 0 */ 206 cf2_cmdHSTEM, /* 1 */ 207 cf2_cmdRESERVED_2, /* 2 */ 208 cf2_cmdVSTEM, /* 3 */ 209 cf2_cmdVMOVETO, /* 4 */ 210 cf2_cmdRLINETO, /* 5 */ 211 cf2_cmdHLINETO, /* 6 */ 212 cf2_cmdVLINETO, /* 7 */ 213 cf2_cmdRRCURVETO, /* 8 */ 214 cf2_cmdRESERVED_9, /* 9 */ 215 cf2_cmdCALLSUBR, /* 10 */ 216 cf2_cmdRETURN, /* 11 */ 217 cf2_cmdESC, /* 12 */ 218 cf2_cmdRESERVED_13, /* 13 */ 219 cf2_cmdENDCHAR, /* 14 */ 220 cf2_cmdVSINDEX, /* 15 */ 221 cf2_cmdBLEND, /* 16 */ 222 cf2_cmdRESERVED_17, /* 17 */ 223 cf2_cmdHSTEMHM, /* 18 */ 224 cf2_cmdHINTMASK, /* 19 */ 225 cf2_cmdCNTRMASK, /* 20 */ 226 cf2_cmdRMOVETO, /* 21 */ 227 cf2_cmdHMOVETO, /* 22 */ 228 cf2_cmdVSTEMHM, /* 23 */ 229 cf2_cmdRCURVELINE, /* 24 */ 230 cf2_cmdRLINECURVE, /* 25 */ 231 cf2_cmdVVCURVETO, /* 26 */ 232 cf2_cmdHHCURVETO, /* 27 */ 233 cf2_cmdEXTENDEDNMBR, /* 28 */ 234 cf2_cmdCALLGSUBR, /* 29 */ 235 cf2_cmdVHCURVETO, /* 30 */ 236 cf2_cmdHVCURVETO /* 31 */ 237 }; 238 239 enum 240 { 241 cf2_escDOTSECTION, /* 0 */ 242 cf2_escRESERVED_1, /* 1 */ 243 cf2_escRESERVED_2, /* 2 */ 244 cf2_escAND, /* 3 */ 245 cf2_escOR, /* 4 */ 246 cf2_escNOT, /* 5 */ 247 cf2_escRESERVED_6, /* 6 */ 248 cf2_escRESERVED_7, /* 7 */ 249 cf2_escRESERVED_8, /* 8 */ 250 cf2_escABS, /* 9 */ 251 cf2_escADD, /* 10 like otherADD */ 252 cf2_escSUB, /* 11 like otherSUB */ 253 cf2_escDIV, /* 12 */ 254 cf2_escRESERVED_13, /* 13 */ 255 cf2_escNEG, /* 14 */ 256 cf2_escEQ, /* 15 */ 257 cf2_escRESERVED_16, /* 16 */ 258 cf2_escRESERVED_17, /* 17 */ 259 cf2_escDROP, /* 18 */ 260 cf2_escRESERVED_19, /* 19 */ 261 cf2_escPUT, /* 20 like otherPUT */ 262 cf2_escGET, /* 21 like otherGET */ 263 cf2_escIFELSE, /* 22 like otherIFELSE */ 264 cf2_escRANDOM, /* 23 like otherRANDOM */ 265 cf2_escMUL, /* 24 like otherMUL */ 266 cf2_escRESERVED_25, /* 25 */ 267 cf2_escSQRT, /* 26 */ 268 cf2_escDUP, /* 27 like otherDUP */ 269 cf2_escEXCH, /* 28 like otherEXCH */ 270 cf2_escINDEX, /* 29 */ 271 cf2_escROLL, /* 30 */ 272 cf2_escRESERVED_31, /* 31 */ 273 cf2_escRESERVED_32, /* 32 */ 274 cf2_escRESERVED_33, /* 33 */ 275 cf2_escHFLEX, /* 34 */ 276 cf2_escFLEX, /* 35 */ 277 cf2_escHFLEX1, /* 36 */ 278 cf2_escFLEX1, /* 37 */ 279 cf2_escRESERVED_38 /* 38 & all higher */ 280 }; 281 282 283 /* `stemHintArray' does not change once we start drawing the outline. */ 284 static void 285 cf2_doStems( const CF2_Font font, 286 CF2_Stack opStack, 287 CF2_ArrStack stemHintArray, 288 CF2_Fixed* width, 289 FT_Bool* haveWidth, 290 CF2_Fixed hintOffset ) 291 { 292 CF2_UInt i; 293 CF2_UInt count = cf2_stack_count( opStack ); 294 FT_Bool hasWidthArg = (FT_Bool)( count & 1 ); 295 296 /* variable accumulates delta values from operand stack */ 297 CF2_Fixed position = hintOffset; 298 299 300 if ( hasWidthArg && !*haveWidth ) 301 *width = cf2_stack_getReal( opStack, 0 ) + 302 cf2_getNominalWidthX( font->decoder ); 303 304 if ( font->decoder->width_only ) 305 goto exit; 306 307 for ( i = hasWidthArg ? 1 : 0; i < count; i += 2 ) 308 { 309 /* construct a CF2_StemHint and push it onto the list */ 310 CF2_StemHintRec stemhint; 311 312 313 stemhint.min = 314 position += cf2_stack_getReal( opStack, i ); 315 stemhint.max = 316 position += cf2_stack_getReal( opStack, i + 1 ); 317 318 stemhint.used = FALSE; 319 stemhint.maxDS = 320 stemhint.minDS = 0; 321 322 cf2_arrstack_push( stemHintArray, &stemhint ); /* defer error check */ 323 } 324 325 cf2_stack_clear( opStack ); 326 327 exit: 328 /* cf2_doStems must define a width (may be default) */ 329 *haveWidth = TRUE; 330 } 331 332 333 static void 334 cf2_doFlex( CF2_Stack opStack, 335 CF2_Fixed* curX, 336 CF2_Fixed* curY, 337 CF2_GlyphPath glyphPath, 338 const FT_Bool* readFromStack, 339 FT_Bool doConditionalLastRead ) 340 { 341 CF2_Fixed vals[14]; 342 CF2_UInt index; 343 FT_Bool isHFlex; 344 CF2_Int top, i, j; 345 346 347 vals[0] = *curX; 348 vals[1] = *curY; 349 index = 0; 350 isHFlex = FT_BOOL( readFromStack[9] == FALSE ); 351 top = isHFlex ? 9 : 10; 352 353 for ( i = 0; i < top; i++ ) 354 { 355 vals[i + 2] = vals[i]; 356 if ( readFromStack[i] ) 357 vals[i + 2] += cf2_stack_getReal( opStack, index++ ); 358 } 359 360 if ( isHFlex ) 361 vals[9 + 2] = *curY; 362 363 if ( doConditionalLastRead ) 364 { 365 FT_Bool lastIsX = (FT_Bool)( cf2_fixedAbs( vals[10] - *curX ) > 366 cf2_fixedAbs( vals[11] - *curY ) ); 367 CF2_Fixed lastVal = cf2_stack_getReal( opStack, index ); 368 369 370 if ( lastIsX ) 371 { 372 vals[12] = vals[10] + lastVal; 373 vals[13] = *curY; 374 } 375 else 376 { 377 vals[12] = *curX; 378 vals[13] = vals[11] + lastVal; 379 } 380 } 381 else 382 { 383 if ( readFromStack[10] ) 384 vals[12] = vals[10] + cf2_stack_getReal( opStack, index++ ); 385 else 386 vals[12] = *curX; 387 388 if ( readFromStack[11] ) 389 vals[13] = vals[11] + cf2_stack_getReal( opStack, index ); 390 else 391 vals[13] = *curY; 392 } 393 394 for ( j = 0; j < 2; j++ ) 395 cf2_glyphpath_curveTo( glyphPath, vals[j * 6 + 2], 396 vals[j * 6 + 3], 397 vals[j * 6 + 4], 398 vals[j * 6 + 5], 399 vals[j * 6 + 6], 400 vals[j * 6 + 7] ); 401 402 cf2_stack_clear( opStack ); 403 404 *curX = vals[12]; 405 *curY = vals[13]; 406 } 407 408 409 /* Blend numOperands on the stack, */ 410 /* store results into the first numBlends values, */ 411 /* then pop remaining arguments. */ 412 static void 413 cf2_doBlend( const CFF_Blend blend, 414 CF2_Stack opStack, 415 CF2_UInt numBlends ) 416 { 417 CF2_UInt delta; 418 CF2_UInt base; 419 CF2_UInt i, j; 420 CF2_UInt numOperands = (CF2_UInt)( numBlends * blend->lenBV ); 421 422 423 base = cf2_stack_count( opStack ) - numOperands; 424 delta = base + numBlends; 425 426 for ( i = 0; i < numBlends; i++ ) 427 { 428 const CF2_Fixed* weight = &blend->BV[1]; 429 430 /* start with first term */ 431 CF2_Fixed sum = cf2_stack_getReal( opStack, i + base ); 432 433 434 for ( j = 1; j < blend->lenBV; j++ ) 435 sum += FT_MulFix( *weight++, cf2_stack_getReal( opStack, delta++ ) ); 436 437 /* store blended result */ 438 cf2_stack_setReal( opStack, i + base, sum ); 439 } 440 441 /* leave only `numBlends' results on stack */ 442 cf2_stack_pop( opStack, numOperands - numBlends ); 443 } 444 445 446 /* 447 * `error' is a shared error code used by many objects in this 448 * routine. Before the code continues from an error, it must check and 449 * record the error in `*error'. The idea is that this shared 450 * error code will record the first error encountered. If testing 451 * for an error anyway, the cost of `goto exit' is small, so we do it, 452 * even if continuing would be safe. In this case, `lastError' is 453 * set, so the testing and storing can be done in one place, at `exit'. 454 * 455 * Continuing after an error is intended for objects which do their own 456 * testing of `*error', e.g., array stack functions. This allows us to 457 * avoid an extra test after the call. 458 * 459 * Unimplemented opcodes are ignored. 460 * 461 */ 462 FT_LOCAL_DEF( void ) 463 cf2_interpT2CharString( CF2_Font font, 464 CF2_Buffer buf, 465 CF2_OutlineCallbacks callbacks, 466 const FT_Vector* translation, 467 FT_Bool doingSeac, 468 CF2_Fixed curX, 469 CF2_Fixed curY, 470 CF2_Fixed* width ) 471 { 472 /* lastError is used for errors that are immediately tested */ 473 FT_Error lastError = FT_Err_Ok; 474 475 /* pointer to parsed font object */ 476 CFF_Decoder* decoder = font->decoder; 477 478 FT_Error* error = &font->error; 479 FT_Memory memory = font->memory; 480 481 CF2_Fixed scaleY = font->innerTransform.d; 482 CF2_Fixed nominalWidthX = cf2_getNominalWidthX( decoder ); 483 484 /* save this for hinting seac accents */ 485 CF2_Fixed hintOriginY = curY; 486 487 CF2_Stack opStack = NULL; 488 FT_UInt stackSize; 489 FT_Byte op1; /* first opcode byte */ 490 491 CF2_F16Dot16 storage[CF2_STORAGE_SIZE]; /* for `put' and `get' */ 492 493 /* instruction limit; 20,000,000 matches Avalon */ 494 FT_UInt32 instructionLimit = 20000000UL; 495 496 CF2_ArrStackRec subrStack; 497 498 FT_Bool haveWidth; 499 CF2_Buffer charstring = NULL; 500 501 CF2_Int charstringIndex = -1; /* initialize to empty */ 502 503 /* TODO: placeholders for hint structures */ 504 505 /* objects used for hinting */ 506 CF2_ArrStackRec hStemHintArray; 507 CF2_ArrStackRec vStemHintArray; 508 509 CF2_HintMaskRec hintMask; 510 CF2_GlyphPathRec glyphPath; 511 512 513 FT_ZERO( &storage ); 514 515 /* initialize the remaining objects */ 516 cf2_arrstack_init( &subrStack, 517 memory, 518 error, 519 sizeof ( CF2_BufferRec ) ); 520 cf2_arrstack_init( &hStemHintArray, 521 memory, 522 error, 523 sizeof ( CF2_StemHintRec ) ); 524 cf2_arrstack_init( &vStemHintArray, 525 memory, 526 error, 527 sizeof ( CF2_StemHintRec ) ); 528 529 /* initialize CF2_StemHint arrays */ 530 cf2_hintmask_init( &hintMask, error ); 531 532 /* initialize path map to manage drawing operations */ 533 534 /* Note: last 4 params are used to handle `MoveToPermissive', which */ 535 /* may need to call `hintMap.Build' */ 536 /* TODO: MoveToPermissive is gone; are these still needed? */ 537 cf2_glyphpath_init( &glyphPath, 538 font, 539 callbacks, 540 scaleY, 541 /* hShift, */ 542 &hStemHintArray, 543 &vStemHintArray, 544 &hintMask, 545 hintOriginY, 546 &font->blues, 547 translation ); 548 549 /* 550 * Initialize state for width parsing. From the CFF Spec: 551 * 552 * The first stack-clearing operator, which must be one of hstem, 553 * hstemhm, vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto, 554 * rmoveto, or endchar, takes an additional argument - the width (as 555 * described earlier), which may be expressed as zero or one numeric 556 * argument. 557 * 558 * What we implement here uses the first validly specified width, but 559 * does not detect errors for specifying more than one width. 560 * 561 * If one of the above operators occurs without explicitly specifying 562 * a width, we assume the default width. 563 * 564 * CFF2 charstrings always return the default width (0). 565 * 566 */ 567 haveWidth = font->isCFF2 ? TRUE : FALSE; 568 *width = cf2_getDefaultWidthX( decoder ); 569 570 /* 571 * Note: At this point, all pointers to resources must be NULL 572 * and all local objects must be initialized. 573 * There must be no branches to `exit:' above this point. 574 * 575 */ 576 577 /* allocate an operand stack */ 578 stackSize = font->isCFF2 ? cf2_getMaxstack( decoder ) 579 : CF2_OPERAND_STACK_SIZE; 580 opStack = cf2_stack_init( memory, error, stackSize ); 581 582 if ( !opStack ) 583 { 584 lastError = FT_THROW( Out_Of_Memory ); 585 goto exit; 586 } 587 588 /* initialize subroutine stack by placing top level charstring as */ 589 /* first element (max depth plus one for the charstring) */ 590 /* Note: Caller owns and must finalize the first charstring. */ 591 /* Our copy of it does not change that requirement. */ 592 cf2_arrstack_setCount( &subrStack, CF2_MAX_SUBR + 1 ); 593 594 charstring = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack ); 595 *charstring = *buf; /* structure copy */ 596 597 charstringIndex = 0; /* entry is valid now */ 598 599 /* catch errors so far */ 600 if ( *error ) 601 goto exit; 602 603 /* main interpreter loop */ 604 while ( 1 ) 605 { 606 if ( cf2_buf_isEnd( charstring ) ) 607 { 608 /* If we've reached the end of the charstring, simulate a */ 609 /* cf2_cmdRETURN or cf2_cmdENDCHAR. */ 610 /* We do this for both CFF and CFF2. */ 611 if ( charstringIndex ) 612 op1 = cf2_cmdRETURN; /* end of buffer for subroutine */ 613 else 614 op1 = cf2_cmdENDCHAR; /* end of buffer for top level charstring */ 615 } 616 else 617 { 618 op1 = (FT_Byte)cf2_buf_readByte( charstring ); 619 620 /* Explicit RETURN and ENDCHAR in CFF2 should be ignored. */ 621 /* Note: Trace message will report 0 instead of 11 or 14. */ 622 if ( ( op1 == cf2_cmdRETURN || op1 == cf2_cmdENDCHAR ) && 623 font->isCFF2 ) 624 op1 = cf2_cmdRESERVED_0; 625 } 626 627 /* check for errors once per loop */ 628 if ( *error ) 629 goto exit; 630 631 instructionLimit--; 632 if ( instructionLimit == 0 ) 633 { 634 lastError = FT_THROW( Invalid_Glyph_Format ); 635 goto exit; 636 } 637 638 switch( op1 ) 639 { 640 case cf2_cmdRESERVED_0: 641 case cf2_cmdRESERVED_2: 642 case cf2_cmdRESERVED_9: 643 case cf2_cmdRESERVED_13: 644 case cf2_cmdRESERVED_17: 645 /* we may get here if we have a prior error */ 646 FT_TRACE4(( " unknown op (%d)\n", op1 )); 647 break; 648 649 case cf2_cmdVSINDEX: 650 FT_TRACE4(( " vsindex\n" )); 651 652 if ( !font->isCFF2 ) 653 break; /* clear stack & ignore */ 654 655 if ( font->blend.usedBV ) 656 { 657 /* vsindex not allowed after blend */ 658 lastError = FT_THROW( Invalid_Glyph_Format ); 659 goto exit; 660 } 661 662 { 663 FT_Int temp = cf2_stack_popInt( opStack ); 664 665 666 if ( temp >= 0 ) 667 font->vsindex = (FT_UInt)temp; 668 } 669 break; 670 671 case cf2_cmdBLEND: 672 { 673 FT_UInt numBlends; 674 675 676 FT_TRACE4(( " blend\n" )); 677 678 if ( !font->isCFF2 ) 679 break; /* clear stack & ignore */ 680 681 /* do we have a `blend' op in a non-variant font? */ 682 if ( !font->blend.font ) 683 { 684 lastError = FT_THROW( Invalid_Glyph_Format ); 685 goto exit; 686 } 687 688 /* check cached blend vector */ 689 if ( cff_blend_check_vector( &font->blend, 690 font->vsindex, 691 font->lenNDV, 692 font->NDV ) ) 693 { 694 lastError = cff_blend_build_vector( &font->blend, 695 font->vsindex, 696 font->lenNDV, 697 font->NDV ); 698 if ( lastError ) 699 goto exit; 700 } 701 702 /* do the blend */ 703 numBlends = (FT_UInt)cf2_stack_popInt( opStack ); 704 if ( numBlends > stackSize ) 705 { 706 lastError = FT_THROW( Invalid_Glyph_Format ); 707 goto exit; 708 } 709 710 cf2_doBlend( &font->blend, opStack, numBlends ); 711 712 font->blend.usedBV = TRUE; 713 } 714 continue; /* do not clear the stack */ 715 716 case cf2_cmdHSTEMHM: 717 case cf2_cmdHSTEM: 718 FT_TRACE4(( op1 == cf2_cmdHSTEMHM ? " hstemhm\n" : " hstem\n" )); 719 720 /* never add hints after the mask is computed */ 721 if ( cf2_hintmask_isValid( &hintMask ) ) 722 { 723 FT_TRACE4(( "cf2_interpT2CharString:" 724 " invalid horizontal hint mask\n" )); 725 break; 726 } 727 728 cf2_doStems( font, 729 opStack, 730 &hStemHintArray, 731 width, 732 &haveWidth, 733 0 ); 734 735 if ( font->decoder->width_only ) 736 goto exit; 737 738 break; 739 740 case cf2_cmdVSTEMHM: 741 case cf2_cmdVSTEM: 742 FT_TRACE4(( op1 == cf2_cmdVSTEMHM ? " vstemhm\n" : " vstem\n" )); 743 744 /* never add hints after the mask is computed */ 745 if ( cf2_hintmask_isValid( &hintMask ) ) 746 { 747 FT_TRACE4(( "cf2_interpT2CharString:" 748 " invalid vertical hint mask\n" )); 749 break; 750 } 751 752 cf2_doStems( font, 753 opStack, 754 &vStemHintArray, 755 width, 756 &haveWidth, 757 0 ); 758 759 if ( font->decoder->width_only ) 760 goto exit; 761 762 break; 763 764 case cf2_cmdVMOVETO: 765 FT_TRACE4(( " vmoveto\n" )); 766 767 if ( cf2_stack_count( opStack ) > 1 && !haveWidth ) 768 *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX; 769 770 /* width is defined or default after this */ 771 haveWidth = TRUE; 772 773 if ( font->decoder->width_only ) 774 goto exit; 775 776 curY += cf2_stack_popFixed( opStack ); 777 778 cf2_glyphpath_moveTo( &glyphPath, curX, curY ); 779 780 break; 781 782 case cf2_cmdRLINETO: 783 { 784 CF2_UInt index; 785 CF2_UInt count = cf2_stack_count( opStack ); 786 787 788 FT_TRACE4(( " rlineto\n" )); 789 790 for ( index = 0; index < count; index += 2 ) 791 { 792 curX += cf2_stack_getReal( opStack, index + 0 ); 793 curY += cf2_stack_getReal( opStack, index + 1 ); 794 795 cf2_glyphpath_lineTo( &glyphPath, curX, curY ); 796 } 797 798 cf2_stack_clear( opStack ); 799 } 800 continue; /* no need to clear stack again */ 801 802 case cf2_cmdHLINETO: 803 case cf2_cmdVLINETO: 804 { 805 CF2_UInt index; 806 CF2_UInt count = cf2_stack_count( opStack ); 807 808 FT_Bool isX = FT_BOOL( op1 == cf2_cmdHLINETO ); 809 810 811 FT_TRACE4(( isX ? " hlineto\n" : " vlineto\n" )); 812 813 for ( index = 0; index < count; index++ ) 814 { 815 CF2_Fixed v = cf2_stack_getReal( opStack, index ); 816 817 818 if ( isX ) 819 curX += v; 820 else 821 curY += v; 822 823 isX = !isX; 824 825 cf2_glyphpath_lineTo( &glyphPath, curX, curY ); 826 } 827 828 cf2_stack_clear( opStack ); 829 } 830 continue; 831 832 case cf2_cmdRCURVELINE: 833 case cf2_cmdRRCURVETO: 834 { 835 CF2_UInt count = cf2_stack_count( opStack ); 836 CF2_UInt index = 0; 837 838 839 FT_TRACE4(( op1 == cf2_cmdRCURVELINE ? " rcurveline\n" 840 : " rrcurveto\n" )); 841 842 while ( index + 6 <= count ) 843 { 844 CF2_Fixed x1 = cf2_stack_getReal( opStack, index + 0 ) + curX; 845 CF2_Fixed y1 = cf2_stack_getReal( opStack, index + 1 ) + curY; 846 CF2_Fixed x2 = cf2_stack_getReal( opStack, index + 2 ) + x1; 847 CF2_Fixed y2 = cf2_stack_getReal( opStack, index + 3 ) + y1; 848 CF2_Fixed x3 = cf2_stack_getReal( opStack, index + 4 ) + x2; 849 CF2_Fixed y3 = cf2_stack_getReal( opStack, index + 5 ) + y2; 850 851 852 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 ); 853 854 curX = x3; 855 curY = y3; 856 index += 6; 857 } 858 859 if ( op1 == cf2_cmdRCURVELINE ) 860 { 861 curX += cf2_stack_getReal( opStack, index + 0 ); 862 curY += cf2_stack_getReal( opStack, index + 1 ); 863 864 cf2_glyphpath_lineTo( &glyphPath, curX, curY ); 865 } 866 867 cf2_stack_clear( opStack ); 868 } 869 continue; /* no need to clear stack again */ 870 871 case cf2_cmdCALLGSUBR: 872 case cf2_cmdCALLSUBR: 873 { 874 CF2_Int subrNum; 875 876 877 FT_TRACE4(( op1 == cf2_cmdCALLGSUBR ? " callgsubr" 878 : " callsubr" )); 879 880 if ( charstringIndex > CF2_MAX_SUBR ) 881 { 882 /* max subr plus one for charstring */ 883 lastError = FT_THROW( Invalid_Glyph_Format ); 884 goto exit; /* overflow of stack */ 885 } 886 887 /* push our current CFF charstring region on subrStack */ 888 charstring = (CF2_Buffer) 889 cf2_arrstack_getPointer( 890 &subrStack, 891 (size_t)charstringIndex + 1 ); 892 893 /* set up the new CFF region and pointer */ 894 subrNum = cf2_stack_popInt( opStack ); 895 896 switch ( op1 ) 897 { 898 case cf2_cmdCALLGSUBR: 899 FT_TRACE4(( " (idx %d, entering level %d)\n", 900 subrNum + decoder->globals_bias, 901 charstringIndex + 1 )); 902 903 if ( cf2_initGlobalRegionBuffer( decoder, 904 subrNum, 905 charstring ) ) 906 { 907 lastError = FT_THROW( Invalid_Glyph_Format ); 908 goto exit; /* subroutine lookup or stream error */ 909 } 910 break; 911 912 default: 913 /* cf2_cmdCALLSUBR */ 914 FT_TRACE4(( " (idx %d, entering level %d)\n", 915 subrNum + decoder->locals_bias, 916 charstringIndex + 1 )); 917 918 if ( cf2_initLocalRegionBuffer( decoder, 919 subrNum, 920 charstring ) ) 921 { 922 lastError = FT_THROW( Invalid_Glyph_Format ); 923 goto exit; /* subroutine lookup or stream error */ 924 } 925 } 926 927 charstringIndex += 1; /* entry is valid now */ 928 } 929 continue; /* do not clear the stack */ 930 931 case cf2_cmdRETURN: 932 FT_TRACE4(( " return (leaving level %d)\n", charstringIndex )); 933 934 if ( charstringIndex < 1 ) 935 { 936 /* Note: cannot return from top charstring */ 937 lastError = FT_THROW( Invalid_Glyph_Format ); 938 goto exit; /* underflow of stack */ 939 } 940 941 /* restore position in previous charstring */ 942 charstring = (CF2_Buffer) 943 cf2_arrstack_getPointer( 944 &subrStack, 945 (CF2_UInt)--charstringIndex ); 946 continue; /* do not clear the stack */ 947 948 case cf2_cmdESC: 949 { 950 FT_Byte op2 = (FT_Byte)cf2_buf_readByte( charstring ); 951 952 953 /* first switch for 2-byte operators handles CFF2 */ 954 /* and opcodes that are reserved for both CFF and CFF2 */ 955 switch ( op2 ) 956 { 957 case cf2_escHFLEX: 958 { 959 static const FT_Bool readFromStack[12] = 960 { 961 TRUE /* dx1 */, FALSE /* dy1 */, 962 TRUE /* dx2 */, TRUE /* dy2 */, 963 TRUE /* dx3 */, FALSE /* dy3 */, 964 TRUE /* dx4 */, FALSE /* dy4 */, 965 TRUE /* dx5 */, FALSE /* dy5 */, 966 TRUE /* dx6 */, FALSE /* dy6 */ 967 }; 968 969 970 FT_TRACE4(( " hflex\n" )); 971 972 cf2_doFlex( opStack, 973 &curX, 974 &curY, 975 &glyphPath, 976 readFromStack, 977 FALSE /* doConditionalLastRead */ ); 978 } 979 continue; 980 981 case cf2_escFLEX: 982 { 983 static const FT_Bool readFromStack[12] = 984 { 985 TRUE /* dx1 */, TRUE /* dy1 */, 986 TRUE /* dx2 */, TRUE /* dy2 */, 987 TRUE /* dx3 */, TRUE /* dy3 */, 988 TRUE /* dx4 */, TRUE /* dy4 */, 989 TRUE /* dx5 */, TRUE /* dy5 */, 990 TRUE /* dx6 */, TRUE /* dy6 */ 991 }; 992 993 994 FT_TRACE4(( " flex\n" )); 995 996 cf2_doFlex( opStack, 997 &curX, 998 &curY, 999 &glyphPath, 1000 readFromStack, 1001 FALSE /* doConditionalLastRead */ ); 1002 } 1003 break; /* TODO: why is this not a continue? */ 1004 1005 case cf2_escHFLEX1: 1006 { 1007 static const FT_Bool readFromStack[12] = 1008 { 1009 TRUE /* dx1 */, TRUE /* dy1 */, 1010 TRUE /* dx2 */, TRUE /* dy2 */, 1011 TRUE /* dx3 */, FALSE /* dy3 */, 1012 TRUE /* dx4 */, FALSE /* dy4 */, 1013 TRUE /* dx5 */, TRUE /* dy5 */, 1014 TRUE /* dx6 */, FALSE /* dy6 */ 1015 }; 1016 1017 1018 FT_TRACE4(( " hflex1\n" )); 1019 1020 cf2_doFlex( opStack, 1021 &curX, 1022 &curY, 1023 &glyphPath, 1024 readFromStack, 1025 FALSE /* doConditionalLastRead */ ); 1026 } 1027 continue; 1028 1029 case cf2_escFLEX1: 1030 { 1031 static const FT_Bool readFromStack[12] = 1032 { 1033 TRUE /* dx1 */, TRUE /* dy1 */, 1034 TRUE /* dx2 */, TRUE /* dy2 */, 1035 TRUE /* dx3 */, TRUE /* dy3 */, 1036 TRUE /* dx4 */, TRUE /* dy4 */, 1037 TRUE /* dx5 */, TRUE /* dy5 */, 1038 FALSE /* dx6 */, FALSE /* dy6 */ 1039 }; 1040 1041 1042 FT_TRACE4(( " flex1\n" )); 1043 1044 cf2_doFlex( opStack, 1045 &curX, 1046 &curY, 1047 &glyphPath, 1048 readFromStack, 1049 TRUE /* doConditionalLastRead */ ); 1050 } 1051 continue; 1052 1053 /* these opcodes are reserved in both CFF & CFF2 */ 1054 case cf2_escRESERVED_1: 1055 case cf2_escRESERVED_2: 1056 case cf2_escRESERVED_6: 1057 case cf2_escRESERVED_7: 1058 case cf2_escRESERVED_8: 1059 case cf2_escRESERVED_13: 1060 case cf2_escRESERVED_16: 1061 case cf2_escRESERVED_17: 1062 case cf2_escRESERVED_19: 1063 case cf2_escRESERVED_25: 1064 case cf2_escRESERVED_31: 1065 case cf2_escRESERVED_32: 1066 case cf2_escRESERVED_33: 1067 FT_TRACE4(( " unknown op (12, %d)\n", op2 )); 1068 break; 1069 1070 default: 1071 { 1072 if ( font->isCFF2 || op2 >= cf2_escRESERVED_38 ) 1073 FT_TRACE4(( " unknown op (12, %d)\n", op2 )); 1074 else 1075 { 1076 /* second switch for 2-byte operators handles just CFF */ 1077 switch ( op2 ) 1078 { 1079 1080 case cf2_escDOTSECTION: 1081 /* something about `flip type of locking' -- ignore it */ 1082 FT_TRACE4(( " dotsection\n" )); 1083 1084 break; 1085 1086 case cf2_escAND: 1087 { 1088 CF2_F16Dot16 arg1; 1089 CF2_F16Dot16 arg2; 1090 1091 1092 FT_TRACE4(( " and\n" )); 1093 1094 arg2 = cf2_stack_popFixed( opStack ); 1095 arg1 = cf2_stack_popFixed( opStack ); 1096 1097 cf2_stack_pushInt( opStack, arg1 && arg2 ); 1098 } 1099 continue; /* do not clear the stack */ 1100 1101 case cf2_escOR: 1102 { 1103 CF2_F16Dot16 arg1; 1104 CF2_F16Dot16 arg2; 1105 1106 1107 FT_TRACE4(( " or\n" )); 1108 1109 arg2 = cf2_stack_popFixed( opStack ); 1110 arg1 = cf2_stack_popFixed( opStack ); 1111 1112 cf2_stack_pushInt( opStack, arg1 || arg2 ); 1113 } 1114 continue; /* do not clear the stack */ 1115 1116 case cf2_escNOT: 1117 { 1118 CF2_F16Dot16 arg; 1119 1120 1121 FT_TRACE4(( " not\n" )); 1122 1123 arg = cf2_stack_popFixed( opStack ); 1124 1125 cf2_stack_pushInt( opStack, !arg ); 1126 } 1127 continue; /* do not clear the stack */ 1128 1129 case cf2_escABS: 1130 { 1131 CF2_F16Dot16 arg; 1132 1133 1134 FT_TRACE4(( " abs\n" )); 1135 1136 arg = cf2_stack_popFixed( opStack ); 1137 1138 cf2_stack_pushFixed( opStack, FT_ABS( arg ) ); 1139 } 1140 continue; /* do not clear the stack */ 1141 1142 case cf2_escADD: 1143 { 1144 CF2_F16Dot16 summand1; 1145 CF2_F16Dot16 summand2; 1146 1147 1148 FT_TRACE4(( " add\n" )); 1149 1150 summand2 = cf2_stack_popFixed( opStack ); 1151 summand1 = cf2_stack_popFixed( opStack ); 1152 1153 cf2_stack_pushFixed( opStack, summand1 + summand2 ); 1154 } 1155 continue; /* do not clear the stack */ 1156 1157 case cf2_escSUB: 1158 { 1159 CF2_F16Dot16 minuend; 1160 CF2_F16Dot16 subtrahend; 1161 1162 1163 FT_TRACE4(( " sub\n" )); 1164 1165 subtrahend = cf2_stack_popFixed( opStack ); 1166 minuend = cf2_stack_popFixed( opStack ); 1167 1168 cf2_stack_pushFixed( opStack, minuend - subtrahend ); 1169 } 1170 continue; /* do not clear the stack */ 1171 1172 case cf2_escDIV: 1173 { 1174 CF2_F16Dot16 dividend; 1175 CF2_F16Dot16 divisor; 1176 1177 1178 FT_TRACE4(( " div\n" )); 1179 1180 divisor = cf2_stack_popFixed( opStack ); 1181 dividend = cf2_stack_popFixed( opStack ); 1182 1183 cf2_stack_pushFixed( opStack, FT_DivFix( dividend, divisor ) ); 1184 } 1185 continue; /* do not clear the stack */ 1186 1187 case cf2_escNEG: 1188 { 1189 CF2_F16Dot16 arg; 1190 1191 1192 FT_TRACE4(( " neg\n" )); 1193 1194 arg = cf2_stack_popFixed( opStack ); 1195 1196 cf2_stack_pushFixed( opStack, -arg ); 1197 } 1198 continue; /* do not clear the stack */ 1199 1200 case cf2_escEQ: 1201 { 1202 CF2_F16Dot16 arg1; 1203 CF2_F16Dot16 arg2; 1204 1205 1206 FT_TRACE4(( " eq\n" )); 1207 1208 arg2 = cf2_stack_popFixed( opStack ); 1209 arg1 = cf2_stack_popFixed( opStack ); 1210 1211 cf2_stack_pushInt( opStack, arg1 == arg2 ); 1212 } 1213 continue; /* do not clear the stack */ 1214 1215 case cf2_escDROP: 1216 FT_TRACE4(( " drop\n" )); 1217 1218 (void)cf2_stack_popFixed( opStack ); 1219 continue; /* do not clear the stack */ 1220 1221 case cf2_escPUT: 1222 { 1223 CF2_F16Dot16 val; 1224 CF2_Int idx; 1225 1226 1227 FT_TRACE4(( " put\n" )); 1228 1229 idx = cf2_stack_popInt( opStack ); 1230 val = cf2_stack_popFixed( opStack ); 1231 1232 if ( idx >= 0 && idx < CF2_STORAGE_SIZE ) 1233 storage[idx] = val; 1234 } 1235 continue; /* do not clear the stack */ 1236 1237 case cf2_escGET: 1238 { 1239 CF2_Int idx; 1240 1241 1242 FT_TRACE4(( " get\n" )); 1243 1244 idx = cf2_stack_popInt( opStack ); 1245 1246 if ( idx >= 0 && idx < CF2_STORAGE_SIZE ) 1247 cf2_stack_pushFixed( opStack, storage[idx] ); 1248 } 1249 continue; /* do not clear the stack */ 1250 1251 case cf2_escIFELSE: 1252 { 1253 CF2_F16Dot16 arg1; 1254 CF2_F16Dot16 arg2; 1255 CF2_F16Dot16 cond1; 1256 CF2_F16Dot16 cond2; 1257 1258 1259 FT_TRACE4(( " ifelse\n" )); 1260 1261 cond2 = cf2_stack_popFixed( opStack ); 1262 cond1 = cf2_stack_popFixed( opStack ); 1263 arg2 = cf2_stack_popFixed( opStack ); 1264 arg1 = cf2_stack_popFixed( opStack ); 1265 1266 cf2_stack_pushFixed( opStack, cond1 <= cond2 ? arg1 : arg2 ); 1267 } 1268 continue; /* do not clear the stack */ 1269 1270 case cf2_escRANDOM: /* in spec */ 1271 FT_TRACE4(( " random\n" )); 1272 1273 CF2_FIXME; 1274 break; 1275 1276 case cf2_escMUL: 1277 { 1278 CF2_F16Dot16 factor1; 1279 CF2_F16Dot16 factor2; 1280 1281 1282 FT_TRACE4(( " mul\n" )); 1283 1284 factor2 = cf2_stack_popFixed( opStack ); 1285 factor1 = cf2_stack_popFixed( opStack ); 1286 1287 cf2_stack_pushFixed( opStack, FT_MulFix( factor1, factor2 ) ); 1288 } 1289 continue; /* do not clear the stack */ 1290 1291 case cf2_escSQRT: 1292 { 1293 CF2_F16Dot16 arg; 1294 1295 1296 FT_TRACE4(( " sqrt\n" )); 1297 1298 arg = cf2_stack_popFixed( opStack ); 1299 if ( arg > 0 ) 1300 { 1301 FT_Fixed root = arg; 1302 FT_Fixed new_root; 1303 1304 1305 /* Babylonian method */ 1306 for (;;) 1307 { 1308 new_root = ( root + FT_DivFix( arg, root ) + 1 ) >> 1; 1309 if ( new_root == root ) 1310 break; 1311 root = new_root; 1312 } 1313 arg = new_root; 1314 } 1315 else 1316 arg = 0; 1317 1318 cf2_stack_pushFixed( opStack, arg ); 1319 } 1320 continue; /* do not clear the stack */ 1321 1322 case cf2_escDUP: 1323 { 1324 CF2_F16Dot16 arg; 1325 1326 1327 FT_TRACE4(( " dup\n" )); 1328 1329 arg = cf2_stack_popFixed( opStack ); 1330 1331 cf2_stack_pushFixed( opStack, arg ); 1332 cf2_stack_pushFixed( opStack, arg ); 1333 } 1334 continue; /* do not clear the stack */ 1335 1336 case cf2_escEXCH: 1337 { 1338 CF2_F16Dot16 arg1; 1339 CF2_F16Dot16 arg2; 1340 1341 1342 FT_TRACE4(( " exch\n" )); 1343 1344 arg2 = cf2_stack_popFixed( opStack ); 1345 arg1 = cf2_stack_popFixed( opStack ); 1346 1347 cf2_stack_pushFixed( opStack, arg2 ); 1348 cf2_stack_pushFixed( opStack, arg1 ); 1349 } 1350 continue; /* do not clear the stack */ 1351 1352 case cf2_escINDEX: 1353 { 1354 CF2_Int idx; 1355 CF2_UInt size; 1356 1357 1358 FT_TRACE4(( " index\n" )); 1359 1360 idx = cf2_stack_popInt( opStack ); 1361 size = cf2_stack_count( opStack ); 1362 1363 if ( size > 0 ) 1364 { 1365 /* for `cf2_stack_getReal', index 0 is bottom of stack */ 1366 CF2_UInt gr_idx; 1367 1368 1369 if ( idx < 0 ) 1370 gr_idx = size - 1; 1371 else if ( (CF2_UInt)idx >= size ) 1372 gr_idx = 0; 1373 else 1374 gr_idx = size - 1 - (CF2_UInt)idx; 1375 1376 cf2_stack_pushFixed( opStack, 1377 cf2_stack_getReal( opStack, gr_idx ) ); 1378 } 1379 } 1380 continue; /* do not clear the stack */ 1381 1382 case cf2_escROLL: 1383 { 1384 CF2_Int idx; 1385 CF2_Int count; 1386 1387 1388 FT_TRACE4(( " roll\n" )); 1389 1390 idx = cf2_stack_popInt( opStack ); 1391 count = cf2_stack_popInt( opStack ); 1392 1393 cf2_stack_roll( opStack, count, idx ); 1394 } 1395 continue; /* do not clear the stack */ 1396 1397 } /* end of 2nd switch checking op2 */ 1398 } 1399 } 1400 } /* end of 1st switch checking op2 */ 1401 } /* case cf2_cmdESC */ 1402 1403 break; 1404 1405 case cf2_cmdENDCHAR: 1406 FT_TRACE4(( " endchar\n" )); 1407 1408 if ( cf2_stack_count( opStack ) == 1 || 1409 cf2_stack_count( opStack ) == 5 ) 1410 { 1411 if ( !haveWidth ) 1412 *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX; 1413 } 1414 1415 /* width is defined or default after this */ 1416 haveWidth = TRUE; 1417 1418 if ( font->decoder->width_only ) 1419 goto exit; 1420 1421 /* close path if still open */ 1422 cf2_glyphpath_closeOpenPath( &glyphPath ); 1423 1424 /* disable seac for CFF2 (charstring ending with args on stack) */ 1425 if ( !font->isCFF2 && cf2_stack_count( opStack ) > 1 ) 1426 { 1427 /* must be either 4 or 5 -- */ 1428 /* this is a (deprecated) implied `seac' operator */ 1429 1430 CF2_Int achar; 1431 CF2_Int bchar; 1432 CF2_BufferRec component; 1433 CF2_Fixed dummyWidth; /* ignore component width */ 1434 FT_Error error2; 1435 1436 1437 if ( doingSeac ) 1438 { 1439 lastError = FT_THROW( Invalid_Glyph_Format ); 1440 goto exit; /* nested seac */ 1441 } 1442 1443 achar = cf2_stack_popInt( opStack ); 1444 bchar = cf2_stack_popInt( opStack ); 1445 1446 curY = cf2_stack_popFixed( opStack ); 1447 curX = cf2_stack_popFixed( opStack ); 1448 1449 error2 = cf2_getSeacComponent( decoder, achar, &component ); 1450 if ( error2 ) 1451 { 1452 lastError = error2; /* pass FreeType error through */ 1453 goto exit; 1454 } 1455 cf2_interpT2CharString( font, 1456 &component, 1457 callbacks, 1458 translation, 1459 TRUE, 1460 curX, 1461 curY, 1462 &dummyWidth ); 1463 cf2_freeSeacComponent( decoder, &component ); 1464 1465 error2 = cf2_getSeacComponent( decoder, bchar, &component ); 1466 if ( error2 ) 1467 { 1468 lastError = error2; /* pass FreeType error through */ 1469 goto exit; 1470 } 1471 cf2_interpT2CharString( font, 1472 &component, 1473 callbacks, 1474 translation, 1475 TRUE, 1476 0, 1477 0, 1478 &dummyWidth ); 1479 cf2_freeSeacComponent( decoder, &component ); 1480 } 1481 goto exit; 1482 1483 case cf2_cmdCNTRMASK: 1484 case cf2_cmdHINTMASK: 1485 /* the final \n in the tracing message gets added in */ 1486 /* `cf2_hintmask_read' (which also traces the mask bytes) */ 1487 FT_TRACE4(( op1 == cf2_cmdCNTRMASK ? " cntrmask" : " hintmask" )); 1488 1489 /* never add hints after the mask is computed */ 1490 if ( cf2_stack_count( opStack ) > 1 && 1491 cf2_hintmask_isValid( &hintMask ) ) 1492 { 1493 FT_TRACE4(( "cf2_interpT2CharString: invalid hint mask\n" )); 1494 break; 1495 } 1496 1497 /* if there are arguments on the stack, there this is an */ 1498 /* implied cf2_cmdVSTEMHM */ 1499 cf2_doStems( font, 1500 opStack, 1501 &vStemHintArray, 1502 width, 1503 &haveWidth, 1504 0 ); 1505 1506 if ( font->decoder->width_only ) 1507 goto exit; 1508 1509 if ( op1 == cf2_cmdHINTMASK ) 1510 { 1511 /* consume the hint mask bytes which follow the operator */ 1512 cf2_hintmask_read( &hintMask, 1513 charstring, 1514 cf2_arrstack_size( &hStemHintArray ) + 1515 cf2_arrstack_size( &vStemHintArray ) ); 1516 } 1517 else 1518 { 1519 /* 1520 * Consume the counter mask bytes which follow the operator: 1521 * Build a temporary hint map, just to place and lock those 1522 * stems participating in the counter mask. These are most 1523 * likely the dominant hstems, and are grouped together in a 1524 * few counter groups, not necessarily in correspondence 1525 * with the hint groups. This reduces the chances of 1526 * conflicts between hstems that are initially placed in 1527 * separate hint groups and then brought together. The 1528 * positions are copied back to `hStemHintArray', so we can 1529 * discard `counterMask' and `counterHintMap'. 1530 * 1531 */ 1532 CF2_HintMapRec counterHintMap; 1533 CF2_HintMaskRec counterMask; 1534 1535 1536 cf2_hintmap_init( &counterHintMap, 1537 font, 1538 &glyphPath.initialHintMap, 1539 &glyphPath.hintMoves, 1540 scaleY ); 1541 cf2_hintmask_init( &counterMask, error ); 1542 1543 cf2_hintmask_read( &counterMask, 1544 charstring, 1545 cf2_arrstack_size( &hStemHintArray ) + 1546 cf2_arrstack_size( &vStemHintArray ) ); 1547 cf2_hintmap_build( &counterHintMap, 1548 &hStemHintArray, 1549 &vStemHintArray, 1550 &counterMask, 1551 0, 1552 FALSE ); 1553 } 1554 break; 1555 1556 case cf2_cmdRMOVETO: 1557 FT_TRACE4(( " rmoveto\n" )); 1558 1559 if ( cf2_stack_count( opStack ) > 2 && !haveWidth ) 1560 *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX; 1561 1562 /* width is defined or default after this */ 1563 haveWidth = TRUE; 1564 1565 if ( font->decoder->width_only ) 1566 goto exit; 1567 1568 curY += cf2_stack_popFixed( opStack ); 1569 curX += cf2_stack_popFixed( opStack ); 1570 1571 cf2_glyphpath_moveTo( &glyphPath, curX, curY ); 1572 1573 break; 1574 1575 case cf2_cmdHMOVETO: 1576 FT_TRACE4(( " hmoveto\n" )); 1577 1578 if ( cf2_stack_count( opStack ) > 1 && !haveWidth ) 1579 *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX; 1580 1581 /* width is defined or default after this */ 1582 haveWidth = TRUE; 1583 1584 if ( font->decoder->width_only ) 1585 goto exit; 1586 1587 curX += cf2_stack_popFixed( opStack ); 1588 1589 cf2_glyphpath_moveTo( &glyphPath, curX, curY ); 1590 1591 break; 1592 1593 case cf2_cmdRLINECURVE: 1594 { 1595 CF2_UInt count = cf2_stack_count( opStack ); 1596 CF2_UInt index = 0; 1597 1598 1599 FT_TRACE4(( " rlinecurve\n" )); 1600 1601 while ( index + 6 < count ) 1602 { 1603 curX += cf2_stack_getReal( opStack, index + 0 ); 1604 curY += cf2_stack_getReal( opStack, index + 1 ); 1605 1606 cf2_glyphpath_lineTo( &glyphPath, curX, curY ); 1607 index += 2; 1608 } 1609 1610 while ( index < count ) 1611 { 1612 CF2_Fixed x1 = cf2_stack_getReal( opStack, index + 0 ) + curX; 1613 CF2_Fixed y1 = cf2_stack_getReal( opStack, index + 1 ) + curY; 1614 CF2_Fixed x2 = cf2_stack_getReal( opStack, index + 2 ) + x1; 1615 CF2_Fixed y2 = cf2_stack_getReal( opStack, index + 3 ) + y1; 1616 CF2_Fixed x3 = cf2_stack_getReal( opStack, index + 4 ) + x2; 1617 CF2_Fixed y3 = cf2_stack_getReal( opStack, index + 5 ) + y2; 1618 1619 1620 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 ); 1621 1622 curX = x3; 1623 curY = y3; 1624 index += 6; 1625 } 1626 1627 cf2_stack_clear( opStack ); 1628 } 1629 continue; /* no need to clear stack again */ 1630 1631 case cf2_cmdVVCURVETO: 1632 { 1633 CF2_UInt count, count1 = cf2_stack_count( opStack ); 1634 CF2_UInt index = 0; 1635 1636 1637 /* if `cf2_stack_count' isn't of the form 4n or 4n+1, */ 1638 /* we enforce it by clearing the second bit */ 1639 /* (and sorting the stack indexing to suit) */ 1640 count = count1 & ~2U; 1641 index += count1 - count; 1642 1643 FT_TRACE4(( " vvcurveto\n" )); 1644 1645 while ( index < count ) 1646 { 1647 CF2_Fixed x1, y1, x2, y2, x3, y3; 1648 1649 1650 if ( ( count - index ) & 1 ) 1651 { 1652 x1 = cf2_stack_getReal( opStack, index ) + curX; 1653 1654 index++; 1655 } 1656 else 1657 x1 = curX; 1658 1659 y1 = cf2_stack_getReal( opStack, index + 0 ) + curY; 1660 x2 = cf2_stack_getReal( opStack, index + 1 ) + x1; 1661 y2 = cf2_stack_getReal( opStack, index + 2 ) + y1; 1662 x3 = x2; 1663 y3 = cf2_stack_getReal( opStack, index + 3 ) + y2; 1664 1665 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 ); 1666 1667 curX = x3; 1668 curY = y3; 1669 index += 4; 1670 } 1671 1672 cf2_stack_clear( opStack ); 1673 } 1674 continue; /* no need to clear stack again */ 1675 1676 case cf2_cmdHHCURVETO: 1677 { 1678 CF2_UInt count, count1 = cf2_stack_count( opStack ); 1679 CF2_UInt index = 0; 1680 1681 1682 /* if `cf2_stack_count' isn't of the form 4n or 4n+1, */ 1683 /* we enforce it by clearing the second bit */ 1684 /* (and sorting the stack indexing to suit) */ 1685 count = count1 & ~2U; 1686 index += count1 - count; 1687 1688 FT_TRACE4(( " hhcurveto\n" )); 1689 1690 while ( index < count ) 1691 { 1692 CF2_Fixed x1, y1, x2, y2, x3, y3; 1693 1694 1695 if ( ( count - index ) & 1 ) 1696 { 1697 y1 = cf2_stack_getReal( opStack, index ) + curY; 1698 1699 index++; 1700 } 1701 else 1702 y1 = curY; 1703 1704 x1 = cf2_stack_getReal( opStack, index + 0 ) + curX; 1705 x2 = cf2_stack_getReal( opStack, index + 1 ) + x1; 1706 y2 = cf2_stack_getReal( opStack, index + 2 ) + y1; 1707 x3 = cf2_stack_getReal( opStack, index + 3 ) + x2; 1708 y3 = y2; 1709 1710 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 ); 1711 1712 curX = x3; 1713 curY = y3; 1714 index += 4; 1715 } 1716 1717 cf2_stack_clear( opStack ); 1718 } 1719 continue; /* no need to clear stack again */ 1720 1721 case cf2_cmdVHCURVETO: 1722 case cf2_cmdHVCURVETO: 1723 { 1724 CF2_UInt count, count1 = cf2_stack_count( opStack ); 1725 CF2_UInt index = 0; 1726 1727 FT_Bool alternate = FT_BOOL( op1 == cf2_cmdHVCURVETO ); 1728 1729 1730 /* if `cf2_stack_count' isn't of the form 8n, 8n+1, */ 1731 /* 8n+4, or 8n+5, we enforce it by clearing the */ 1732 /* second bit */ 1733 /* (and sorting the stack indexing to suit) */ 1734 count = count1 & ~2U; 1735 index += count1 - count; 1736 1737 FT_TRACE4(( alternate ? " hvcurveto\n" : " vhcurveto\n" )); 1738 1739 while ( index < count ) 1740 { 1741 CF2_Fixed x1, x2, x3, y1, y2, y3; 1742 1743 1744 if ( alternate ) 1745 { 1746 x1 = cf2_stack_getReal( opStack, index + 0 ) + curX; 1747 y1 = curY; 1748 x2 = cf2_stack_getReal( opStack, index + 1 ) + x1; 1749 y2 = cf2_stack_getReal( opStack, index + 2 ) + y1; 1750 y3 = cf2_stack_getReal( opStack, index + 3 ) + y2; 1751 1752 if ( count - index == 5 ) 1753 { 1754 x3 = cf2_stack_getReal( opStack, index + 4 ) + x2; 1755 1756 index++; 1757 } 1758 else 1759 x3 = x2; 1760 1761 alternate = FALSE; 1762 } 1763 else 1764 { 1765 x1 = curX; 1766 y1 = cf2_stack_getReal( opStack, index + 0 ) + curY; 1767 x2 = cf2_stack_getReal( opStack, index + 1 ) + x1; 1768 y2 = cf2_stack_getReal( opStack, index + 2 ) + y1; 1769 x3 = cf2_stack_getReal( opStack, index + 3 ) + x2; 1770 1771 if ( count - index == 5 ) 1772 { 1773 y3 = cf2_stack_getReal( opStack, index + 4 ) + y2; 1774 1775 index++; 1776 } 1777 else 1778 y3 = y2; 1779 1780 alternate = TRUE; 1781 } 1782 1783 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 ); 1784 1785 curX = x3; 1786 curY = y3; 1787 index += 4; 1788 } 1789 1790 cf2_stack_clear( opStack ); 1791 } 1792 continue; /* no need to clear stack again */ 1793 1794 case cf2_cmdEXTENDEDNMBR: 1795 { 1796 CF2_Int v; 1797 1798 CF2_Int byte1 = cf2_buf_readByte( charstring ); 1799 CF2_Int byte2 = cf2_buf_readByte( charstring ); 1800 1801 1802 v = (FT_Short)( ( byte1 << 8 ) | 1803 byte2 ); 1804 1805 FT_TRACE4(( " %d", v )); 1806 1807 cf2_stack_pushInt( opStack, v ); 1808 } 1809 continue; 1810 1811 default: 1812 /* numbers */ 1813 { 1814 if ( /* op1 >= 32 && */ op1 <= 246 ) 1815 { 1816 CF2_Int v; 1817 1818 1819 v = op1 - 139; 1820 1821 FT_TRACE4(( " %d", v )); 1822 1823 /* -107 .. 107 */ 1824 cf2_stack_pushInt( opStack, v ); 1825 } 1826 1827 else if ( /* op1 >= 247 && */ op1 <= 250 ) 1828 { 1829 CF2_Int v; 1830 1831 1832 v = op1; 1833 v -= 247; 1834 v *= 256; 1835 v += cf2_buf_readByte( charstring ); 1836 v += 108; 1837 1838 FT_TRACE4(( " %d", v )); 1839 1840 /* 108 .. 1131 */ 1841 cf2_stack_pushInt( opStack, v ); 1842 } 1843 1844 else if ( /* op1 >= 251 && */ op1 <= 254 ) 1845 { 1846 CF2_Int v; 1847 1848 1849 v = op1; 1850 v -= 251; 1851 v *= 256; 1852 v += cf2_buf_readByte( charstring ); 1853 v = -v - 108; 1854 1855 FT_TRACE4(( " %d", v )); 1856 1857 /* -1131 .. -108 */ 1858 cf2_stack_pushInt( opStack, v ); 1859 } 1860 1861 else /* op1 == 255 */ 1862 { 1863 CF2_Fixed v; 1864 1865 FT_UInt32 byte1 = (FT_UInt32)cf2_buf_readByte( charstring ); 1866 FT_UInt32 byte2 = (FT_UInt32)cf2_buf_readByte( charstring ); 1867 FT_UInt32 byte3 = (FT_UInt32)cf2_buf_readByte( charstring ); 1868 FT_UInt32 byte4 = (FT_UInt32)cf2_buf_readByte( charstring ); 1869 1870 1871 v = (CF2_Fixed)( ( byte1 << 24 ) | 1872 ( byte2 << 16 ) | 1873 ( byte3 << 8 ) | 1874 byte4 ); 1875 1876 FT_TRACE4(( " %.5f", v / 65536.0 )); 1877 1878 cf2_stack_pushFixed( opStack, v ); 1879 } 1880 } 1881 continue; /* don't clear stack */ 1882 1883 } /* end of switch statement checking `op1' */ 1884 1885 cf2_stack_clear( opStack ); 1886 1887 } /* end of main interpreter loop */ 1888 1889 /* we get here if the charstring ends without cf2_cmdENDCHAR */ 1890 FT_TRACE4(( "cf2_interpT2CharString:" 1891 " charstring ends without ENDCHAR\n" )); 1892 1893 exit: 1894 /* check whether last error seen is also the first one */ 1895 cf2_setError( error, lastError ); 1896 1897 if ( *error ) 1898 FT_TRACE4(( "charstring error %d\n", *error )); 1899 1900 /* free resources from objects we've used */ 1901 cf2_glyphpath_finalize( &glyphPath ); 1902 cf2_arrstack_finalize( &vStemHintArray ); 1903 cf2_arrstack_finalize( &hStemHintArray ); 1904 cf2_arrstack_finalize( &subrStack ); 1905 cf2_stack_free( opStack ); 1906 1907 FT_TRACE4(( "\n" )); 1908 1909 return; 1910 } 1911 1912 1913 /* END */ 1914