diff options
-rw-r--r-- | src/cff/cf2intrp.c | 658 |
1 files changed, 346 insertions, 312 deletions
diff --git a/src/cff/cf2intrp.c b/src/cff/cf2intrp.c index 6b99cd73c..2dd13c66d 100644 --- a/src/cff/cf2intrp.c +++ b/src/cff/cf2intrp.c @@ -273,7 +273,8 @@ cf2_escHFLEX, /* 34 */ cf2_escFLEX, /* 35 */ cf2_escHFLEX1, /* 36 */ - cf2_escFLEX1 /* 37 */ + cf2_escFLEX1, /* 37 */ + cf2_escRESERVED_38 /* 38 & all higher */ }; @@ -587,14 +588,25 @@ { /* If we've reached the end of the charstring, simulate a */ /* cf2_cmdRETURN or cf2_cmdENDCHAR. */ + /* We do this for both CFF and CFF2. */ if ( charstringIndex ) op1 = cf2_cmdRETURN; /* end of buffer for subroutine */ else op1 = cf2_cmdENDCHAR; /* end of buffer for top level charstring */ } else + { op1 = (FT_Byte)cf2_buf_readByte( charstring ); + /* explicit RETURN and ENDCHAR in CFF2 should be ignored */ + /* Note: Trace message will report 0 instead of 11 or 14 */ + if ( ( op1 == cf2_cmdRETURN || op1 == cf2_cmdENDCHAR ) && + font->isCFF2 ) + { + op1 = cf2_cmdRESERVED_0; + } + } + /* check for errors once per loop */ if ( *error ) goto exit; @@ -619,6 +631,11 @@ case cf2_cmdVSINDEX: { + FT_TRACE4(( " %d\n" )); + + if ( !font->isCFF2 ) + break; /* clear stack & ignore */ + if ( font->blend.usedBV ) { /* vsindex not allowed after blend */ @@ -627,7 +644,6 @@ } font->vsindex = (FT_UInt)cf2_stack_popInt( opStack ); - FT_TRACE4(( " %d\n", font->vsindex )); break; } @@ -893,441 +909,456 @@ FT_Byte op2 = (FT_Byte)cf2_buf_readByte( charstring ); + /* first switch for 2-byte operators handles CFF2 */ + /* and opcodes that are reserved for both CFF and CFF2 */ switch ( op2 ) { - case cf2_escDOTSECTION: - /* something about `flip type of locking' -- ignore it */ - FT_TRACE4(( " dotsection\n" )); + case cf2_escHFLEX: + { + static const FT_Bool readFromStack[12] = + { + TRUE /* dx1 */, FALSE /* dy1 */, + TRUE /* dx2 */, TRUE /* dy2 */, + TRUE /* dx3 */, FALSE /* dy3 */, + TRUE /* dx4 */, FALSE /* dy4 */, + TRUE /* dx5 */, FALSE /* dy5 */, + TRUE /* dx6 */, FALSE /* dy6 */ + }; - break; - case cf2_escAND: - { - CF2_F16Dot16 arg1; - CF2_F16Dot16 arg2; + FT_TRACE4(( " hflex\n" )); + + cf2_doFlex( opStack, + &curX, + &curY, + &glyphPath, + readFromStack, + FALSE /* doConditionalLastRead */ ); + } + continue; + case cf2_escFLEX: + { + static const FT_Bool readFromStack[12] = + { + TRUE /* dx1 */, TRUE /* dy1 */, + TRUE /* dx2 */, TRUE /* dy2 */, + TRUE /* dx3 */, TRUE /* dy3 */, + TRUE /* dx4 */, TRUE /* dy4 */, + TRUE /* dx5 */, TRUE /* dy5 */, + TRUE /* dx6 */, TRUE /* dy6 */ + }; - FT_TRACE4(( " and\n" )); - arg2 = cf2_stack_popFixed( opStack ); - arg1 = cf2_stack_popFixed( opStack ); + FT_TRACE4(( " flex\n" )); - cf2_stack_pushInt( opStack, arg1 && arg2 ); + cf2_doFlex( opStack, + &curX, + &curY, + &glyphPath, + readFromStack, + FALSE /* doConditionalLastRead */ ); } - continue; /* do not clear the stack */ + break; /* TODO: why is this not a continue? */ - case cf2_escOR: + case cf2_escHFLEX1: { - CF2_F16Dot16 arg1; - CF2_F16Dot16 arg2; - + static const FT_Bool readFromStack[12] = + { + TRUE /* dx1 */, TRUE /* dy1 */, + TRUE /* dx2 */, TRUE /* dy2 */, + TRUE /* dx3 */, FALSE /* dy3 */, + TRUE /* dx4 */, FALSE /* dy4 */, + TRUE /* dx5 */, TRUE /* dy5 */, + TRUE /* dx6 */, FALSE /* dy6 */ + }; - FT_TRACE4(( " or\n" )); - arg2 = cf2_stack_popFixed( opStack ); - arg1 = cf2_stack_popFixed( opStack ); + FT_TRACE4(( " hflex1\n" )); - cf2_stack_pushInt( opStack, arg1 || arg2 ); + cf2_doFlex( opStack, + &curX, + &curY, + &glyphPath, + readFromStack, + FALSE /* doConditionalLastRead */ ); } - continue; /* do not clear the stack */ + continue; - case cf2_escNOT: + case cf2_escFLEX1: { - CF2_F16Dot16 arg; - + static const FT_Bool readFromStack[12] = + { + TRUE /* dx1 */, TRUE /* dy1 */, + TRUE /* dx2 */, TRUE /* dy2 */, + TRUE /* dx3 */, TRUE /* dy3 */, + TRUE /* dx4 */, TRUE /* dy4 */, + TRUE /* dx5 */, TRUE /* dy5 */, + FALSE /* dx6 */, FALSE /* dy6 */ + }; - FT_TRACE4(( " not\n" )); - arg = cf2_stack_popFixed( opStack ); + FT_TRACE4(( " flex1\n" )); - cf2_stack_pushInt( opStack, !arg ); + cf2_doFlex( opStack, + &curX, + &curY, + &glyphPath, + readFromStack, + TRUE /* doConditionalLastRead */ ); } - continue; /* do not clear the stack */ + continue; - case cf2_escABS: + /* these opcodes are reserved in both CFF & CFF2 */ + case cf2_escRESERVED_1: + case cf2_escRESERVED_2: + case cf2_escRESERVED_6: + case cf2_escRESERVED_7: + case cf2_escRESERVED_8: + case cf2_escRESERVED_13: + case cf2_escRESERVED_16: + case cf2_escRESERVED_17: + case cf2_escRESERVED_19: + case cf2_escRESERVED_25: + case cf2_escRESERVED_31: + case cf2_escRESERVED_32: + case cf2_escRESERVED_33: + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + break; + + default: { - CF2_F16Dot16 arg; + if ( font->isCFF2 || op2 >= cf2_escRESERVED_38 ) + FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + else + { + /* second switch for 2-byte operators handles just CFF */ + switch ( op2 ) + { + case cf2_escDOTSECTION: + /* something about `flip type of locking' -- ignore it */ + FT_TRACE4(( " dotsection\n" )); - FT_TRACE4(( " abs\n" )); + break; - arg = cf2_stack_popFixed( opStack ); + case cf2_escAND: + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; - cf2_stack_pushFixed( opStack, FT_ABS( arg ) ); - } - continue; /* do not clear the stack */ - case cf2_escADD: - { - CF2_F16Dot16 summand1; - CF2_F16Dot16 summand2; + FT_TRACE4(( " and\n" )); + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); - FT_TRACE4(( " add\n" )); + cf2_stack_pushInt( opStack, arg1 && arg2 ); + } + continue; /* do not clear the stack */ - summand2 = cf2_stack_popFixed( opStack ); - summand1 = cf2_stack_popFixed( opStack ); + case cf2_escOR: + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; - cf2_stack_pushFixed( opStack, summand1 + summand2 ); - } - continue; /* do not clear the stack */ - case cf2_escSUB: - { - CF2_F16Dot16 minuend; - CF2_F16Dot16 subtrahend; + FT_TRACE4(( " or\n" )); + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); - FT_TRACE4(( " sub\n" )); + cf2_stack_pushInt( opStack, arg1 || arg2 ); + } + continue; /* do not clear the stack */ - subtrahend = cf2_stack_popFixed( opStack ); - minuend = cf2_stack_popFixed( opStack ); + case cf2_escNOT: + { + CF2_F16Dot16 arg; - cf2_stack_pushFixed( opStack, minuend - subtrahend ); - } - continue; /* do not clear the stack */ - case cf2_escDIV: - { - CF2_F16Dot16 dividend; - CF2_F16Dot16 divisor; + FT_TRACE4(( " not\n" )); + arg = cf2_stack_popFixed( opStack ); - FT_TRACE4(( " div\n" )); + cf2_stack_pushInt( opStack, !arg ); + } + continue; /* do not clear the stack */ - divisor = cf2_stack_popFixed( opStack ); - dividend = cf2_stack_popFixed( opStack ); + case cf2_escABS: + { + CF2_F16Dot16 arg; - cf2_stack_pushFixed( opStack, FT_DivFix( dividend, divisor ) ); - } - continue; /* do not clear the stack */ - case cf2_escNEG: - { - CF2_F16Dot16 arg; + FT_TRACE4(( " abs\n" )); + arg = cf2_stack_popFixed( opStack ); - FT_TRACE4(( " neg\n" )); + cf2_stack_pushFixed( opStack, FT_ABS( arg ) ); + } + continue; /* do not clear the stack */ - arg = cf2_stack_popFixed( opStack ); + case cf2_escADD: + { + CF2_F16Dot16 summand1; + CF2_F16Dot16 summand2; - cf2_stack_pushFixed( opStack, -arg ); - } - continue; /* do not clear the stack */ - case cf2_escEQ: - { - CF2_F16Dot16 arg1; - CF2_F16Dot16 arg2; + FT_TRACE4(( " add\n" )); + summand2 = cf2_stack_popFixed( opStack ); + summand1 = cf2_stack_popFixed( opStack ); - FT_TRACE4(( " eq\n" )); + cf2_stack_pushFixed( opStack, summand1 + summand2 ); + } + continue; /* do not clear the stack */ - arg2 = cf2_stack_popFixed( opStack ); - arg1 = cf2_stack_popFixed( opStack ); + case cf2_escSUB: + { + CF2_F16Dot16 minuend; + CF2_F16Dot16 subtrahend; - cf2_stack_pushInt( opStack, arg1 == arg2 ); - } - continue; /* do not clear the stack */ - case cf2_escDROP: - FT_TRACE4(( " drop\n" )); + FT_TRACE4(( " sub\n" )); - (void)cf2_stack_popFixed( opStack ); - continue; /* do not clear the stack */ + subtrahend = cf2_stack_popFixed( opStack ); + minuend = cf2_stack_popFixed( opStack ); - case cf2_escPUT: - { - CF2_F16Dot16 val; - CF2_Int idx; + cf2_stack_pushFixed( opStack, minuend - subtrahend ); + } + continue; /* do not clear the stack */ + case cf2_escDIV: + { + CF2_F16Dot16 dividend; + CF2_F16Dot16 divisor; - FT_TRACE4(( " put\n" )); - idx = cf2_stack_popInt( opStack ); - val = cf2_stack_popFixed( opStack ); + FT_TRACE4(( " div\n" )); - if ( idx >= 0 && idx < CF2_STORAGE_SIZE ) - storage[idx] = val; - } - continue; /* do not clear the stack */ + divisor = cf2_stack_popFixed( opStack ); + dividend = cf2_stack_popFixed( opStack ); - case cf2_escGET: - { - CF2_Int idx; + cf2_stack_pushFixed( opStack, FT_DivFix( dividend, divisor ) ); + } + continue; /* do not clear the stack */ + case cf2_escNEG: + { + CF2_F16Dot16 arg; - FT_TRACE4(( " get\n" )); - idx = cf2_stack_popInt( opStack ); + FT_TRACE4(( " neg\n" )); - if ( idx >= 0 && idx < CF2_STORAGE_SIZE ) - cf2_stack_pushFixed( opStack, storage[idx] ); - } - continue; /* do not clear the stack */ + arg = cf2_stack_popFixed( opStack ); - case cf2_escIFELSE: - { - CF2_F16Dot16 arg1; - CF2_F16Dot16 arg2; - CF2_F16Dot16 cond1; - CF2_F16Dot16 cond2; + cf2_stack_pushFixed( opStack, -arg ); + } + continue; /* do not clear the stack */ + case cf2_escEQ: + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; - FT_TRACE4(( " ifelse\n" )); - cond2 = cf2_stack_popFixed( opStack ); - cond1 = cf2_stack_popFixed( opStack ); - arg2 = cf2_stack_popFixed( opStack ); - arg1 = cf2_stack_popFixed( opStack ); + FT_TRACE4(( " eq\n" )); - cf2_stack_pushFixed( opStack, cond1 <= cond2 ? arg1 : arg2 ); - } - continue; /* do not clear the stack */ + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); - case cf2_escRANDOM: /* in spec */ - FT_TRACE4(( " random\n" )); + cf2_stack_pushInt( opStack, arg1 == arg2 ); + } + continue; /* do not clear the stack */ - CF2_FIXME; - break; + case cf2_escDROP: + FT_TRACE4(( " drop\n" )); - case cf2_escMUL: - { - CF2_F16Dot16 factor1; - CF2_F16Dot16 factor2; + (void)cf2_stack_popFixed( opStack ); + continue; /* do not clear the stack */ + case cf2_escPUT: + { + CF2_F16Dot16 val; + CF2_Int idx; - FT_TRACE4(( " mul\n" )); - factor2 = cf2_stack_popFixed( opStack ); - factor1 = cf2_stack_popFixed( opStack ); + FT_TRACE4(( " put\n" )); - cf2_stack_pushFixed( opStack, FT_MulFix( factor1, factor2 ) ); - } - continue; /* do not clear the stack */ + idx = cf2_stack_popInt( opStack ); + val = cf2_stack_popFixed( opStack ); - case cf2_escSQRT: - { - CF2_F16Dot16 arg; + if ( idx >= 0 && idx < CF2_STORAGE_SIZE ) + storage[idx] = val; + } + continue; /* do not clear the stack */ + case cf2_escGET: + { + CF2_Int idx; - FT_TRACE4(( " sqrt\n" )); - arg = cf2_stack_popFixed( opStack ); - if ( arg > 0 ) - { - FT_Fixed root = arg; - FT_Fixed new_root; + FT_TRACE4(( " get\n" )); + idx = cf2_stack_popInt( opStack ); - /* Babylonian method */ - for (;;) - { - new_root = ( root + FT_DivFix( arg, root ) + 1 ) >> 1; - if ( new_root == root ) - break; - root = new_root; - } - arg = new_root; - } - else - arg = 0; + if ( idx >= 0 && idx < CF2_STORAGE_SIZE ) + cf2_stack_pushFixed( opStack, storage[idx] ); + } + continue; /* do not clear the stack */ - cf2_stack_pushFixed( opStack, arg ); - } - continue; /* do not clear the stack */ + case cf2_escIFELSE: + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; + CF2_F16Dot16 cond1; + CF2_F16Dot16 cond2; - case cf2_escDUP: - { - CF2_F16Dot16 arg; + FT_TRACE4(( " ifelse\n" )); - FT_TRACE4(( " dup\n" )); + cond2 = cf2_stack_popFixed( opStack ); + cond1 = cf2_stack_popFixed( opStack ); + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); - arg = cf2_stack_popFixed( opStack ); + cf2_stack_pushFixed( opStack, cond1 <= cond2 ? arg1 : arg2 ); + } + continue; /* do not clear the stack */ - cf2_stack_pushFixed( opStack, arg ); - cf2_stack_pushFixed( opStack, arg ); - } - continue; /* do not clear the stack */ + case cf2_escRANDOM: /* in spec */ + FT_TRACE4(( " random\n" )); - case cf2_escEXCH: - { - CF2_F16Dot16 arg1; - CF2_F16Dot16 arg2; + CF2_FIXME; + break; + case cf2_escMUL: + { + CF2_F16Dot16 factor1; + CF2_F16Dot16 factor2; - FT_TRACE4(( " exch\n" )); - arg2 = cf2_stack_popFixed( opStack ); - arg1 = cf2_stack_popFixed( opStack ); + FT_TRACE4(( " mul\n" )); - cf2_stack_pushFixed( opStack, arg2 ); - cf2_stack_pushFixed( opStack, arg1 ); - } - continue; /* do not clear the stack */ + factor2 = cf2_stack_popFixed( opStack ); + factor1 = cf2_stack_popFixed( opStack ); - case cf2_escINDEX: - { - CF2_Int idx; - CF2_UInt size; + cf2_stack_pushFixed( opStack, FT_MulFix( factor1, factor2 ) ); + } + continue; /* do not clear the stack */ + case cf2_escSQRT: + { + CF2_F16Dot16 arg; - FT_TRACE4(( " index\n" )); - idx = cf2_stack_popInt( opStack ); - size = cf2_stack_count( opStack ); + FT_TRACE4(( " sqrt\n" )); - if ( size > 0 ) - { - /* for `cf2_stack_getReal', index 0 is bottom of stack */ - CF2_UInt gr_idx; + arg = cf2_stack_popFixed( opStack ); + if ( arg > 0 ) + { + FT_Fixed root = arg; + FT_Fixed new_root; - if ( idx < 0 ) - gr_idx = size - 1; - else if ( (CF2_UInt)idx >= size ) - gr_idx = 0; - else - gr_idx = size - 1 - (CF2_UInt)idx; + /* Babylonian method */ + for (;;) + { + new_root = ( root + FT_DivFix( arg, root ) + 1 ) >> 1; + if ( new_root == root ) + break; + root = new_root; + } + arg = new_root; + } + else + arg = 0; - cf2_stack_pushFixed( opStack, - cf2_stack_getReal( opStack, gr_idx ) ); - } - } - continue; /* do not clear the stack */ + cf2_stack_pushFixed( opStack, arg ); + } + continue; /* do not clear the stack */ - case cf2_escROLL: - { - CF2_Int idx; - CF2_Int count; + case cf2_escDUP: + { + CF2_F16Dot16 arg; - FT_TRACE4(( " roll\n" )); + FT_TRACE4(( " dup\n" )); - idx = cf2_stack_popInt( opStack ); - count = cf2_stack_popInt( opStack ); + arg = cf2_stack_popFixed( opStack ); - cf2_stack_roll( opStack, count, idx ); - } - continue; /* do not clear the stack */ + cf2_stack_pushFixed( opStack, arg ); + cf2_stack_pushFixed( opStack, arg ); + } + continue; /* do not clear the stack */ - case cf2_escHFLEX: - { - static const FT_Bool readFromStack[12] = - { - TRUE /* dx1 */, FALSE /* dy1 */, - TRUE /* dx2 */, TRUE /* dy2 */, - TRUE /* dx3 */, FALSE /* dy3 */, - TRUE /* dx4 */, FALSE /* dy4 */, - TRUE /* dx5 */, FALSE /* dy5 */, - TRUE /* dx6 */, FALSE /* dy6 */ - }; + case cf2_escEXCH: + { + CF2_F16Dot16 arg1; + CF2_F16Dot16 arg2; - FT_TRACE4(( " hflex\n" )); + FT_TRACE4(( " exch\n" )); - cf2_doFlex( opStack, - &curX, - &curY, - &glyphPath, - readFromStack, - FALSE /* doConditionalLastRead */ ); - } - continue; + arg2 = cf2_stack_popFixed( opStack ); + arg1 = cf2_stack_popFixed( opStack ); - case cf2_escFLEX: - { - static const FT_Bool readFromStack[12] = - { - TRUE /* dx1 */, TRUE /* dy1 */, - TRUE /* dx2 */, TRUE /* dy2 */, - TRUE /* dx3 */, TRUE /* dy3 */, - TRUE /* dx4 */, TRUE /* dy4 */, - TRUE /* dx5 */, TRUE /* dy5 */, - TRUE /* dx6 */, TRUE /* dy6 */ - }; + cf2_stack_pushFixed( opStack, arg2 ); + cf2_stack_pushFixed( opStack, arg1 ); + } + continue; /* do not clear the stack */ + case cf2_escINDEX: + { + CF2_Int idx; + CF2_UInt size; - FT_TRACE4(( " flex\n" )); - cf2_doFlex( opStack, - &curX, - &curY, - &glyphPath, - readFromStack, - FALSE /* doConditionalLastRead */ ); - } - break; /* TODO: why is this not a continue? */ + FT_TRACE4(( " index\n" )); - case cf2_escHFLEX1: - { - static const FT_Bool readFromStack[12] = - { - TRUE /* dx1 */, TRUE /* dy1 */, - TRUE /* dx2 */, TRUE /* dy2 */, - TRUE /* dx3 */, FALSE /* dy3 */, - TRUE /* dx4 */, FALSE /* dy4 */, - TRUE /* dx5 */, TRUE /* dy5 */, - TRUE /* dx6 */, FALSE /* dy6 */ - }; + idx = cf2_stack_popInt( opStack ); + size = cf2_stack_count( opStack ); + if ( size > 0 ) + { + /* for `cf2_stack_getReal', index 0 is bottom of stack */ + CF2_UInt gr_idx; - FT_TRACE4(( " hflex1\n" )); - cf2_doFlex( opStack, - &curX, - &curY, - &glyphPath, - readFromStack, - FALSE /* doConditionalLastRead */ ); - } - continue; + if ( idx < 0 ) + gr_idx = size - 1; + else if ( (CF2_UInt)idx >= size ) + gr_idx = 0; + else + gr_idx = size - 1 - (CF2_UInt)idx; - case cf2_escFLEX1: - { - static const FT_Bool readFromStack[12] = - { - TRUE /* dx1 */, TRUE /* dy1 */, - TRUE /* dx2 */, TRUE /* dy2 */, - TRUE /* dx3 */, TRUE /* dy3 */, - TRUE /* dx4 */, TRUE /* dy4 */, - TRUE /* dx5 */, TRUE /* dy5 */, - FALSE /* dx6 */, FALSE /* dy6 */ - }; + cf2_stack_pushFixed( opStack, + cf2_stack_getReal( opStack, gr_idx ) ); + } + } + continue; /* do not clear the stack */ + case cf2_escROLL: + { + CF2_Int idx; + CF2_Int count; - FT_TRACE4(( " flex1\n" )); - cf2_doFlex( opStack, - &curX, - &curY, - &glyphPath, - readFromStack, - TRUE /* doConditionalLastRead */ ); - } - continue; + FT_TRACE4(( " roll\n" )); - case cf2_escRESERVED_1: - case cf2_escRESERVED_2: - case cf2_escRESERVED_6: - case cf2_escRESERVED_7: - case cf2_escRESERVED_8: - case cf2_escRESERVED_13: - case cf2_escRESERVED_16: - case cf2_escRESERVED_17: - case cf2_escRESERVED_19: - case cf2_escRESERVED_25: - case cf2_escRESERVED_31: - case cf2_escRESERVED_32: - case cf2_escRESERVED_33: - default: - FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + idx = cf2_stack_popInt( opStack ); + count = cf2_stack_popInt( opStack ); - }; /* end of switch statement checking `op2' */ + cf2_stack_roll( opStack, count, idx ); + } + continue; /* do not clear the stack */ - } /* case cf2_cmdESC */ - break; + } /* end of 2nd switch checking op2 */ + } + } + }; /* end of 1st switch checking op2 */ + } /* case cf2_cmdESC */ + break; /* break switch checking op1 */ case cf2_cmdENDCHAR: FT_TRACE4(( " endchar\n" )); @@ -1820,6 +1851,9 @@ /* check whether last error seen is also the first one */ cf2_setError( error, lastError ); + if ( *error ) + FT_TRACE4(( "charstring error %d\n", *error )); + /* free resources from objects we've used */ cf2_glyphpath_finalize( &glyphPath ); cf2_arrstack_finalize( &vStemHintArray ); |