[cff] Implement missing operators in new engine (except `random').

* src/cff/cf2font.h (CF2_STORAGE_SIZE): New macro.

* src/cff/cf2intrp.c (cf2_interpT2CharString): Implement the
following operators: abs, add, and, div, drop, dup, eq, exch, get,
ifelse, index, mul, neg, not, or, put, roll, sqrt, sub.

* src/cff/cf2stack.h, src/cff/cf2stack.c (cf2_stack_roll): New
auxiliary function for `roll' operator.
This commit is contained in:
Werner Lemberg 2016-02-07 11:39:54 +01:00
parent 1a95d00210
commit 950f16969e
5 changed files with 369 additions and 78 deletions

View File

@ -1,3 +1,16 @@
2016-02-07 Werner Lemberg <wl@gnu.org>
[cff] Implement missing operators in new engine (except `random').
* src/cff/cf2font.h (CF2_STORAGE_SIZE): New macro.
* src/cff/cf2intrp.c (cf2_interpT2CharString): Implement the
following operators: abs, add, and, div, drop, dup, eq, exch, get,
ifelse, index, mul, neg, not, or, put, roll, sqrt, sub.
* src/cff/cf2stack.h, src/cff/cf2stack.c (cf2_stack_roll): New
auxiliary function for `roll' operator.
2016-02-06 Werner Lemberg <wl@gnu.org>
[cff] Fix some Type 2 operators in old CFF engine.

View File

@ -54,6 +54,7 @@ FT_BEGIN_HEADER
/* (Hiragino Kaku Gothic ProN W3; */
/* 8.2d6e1; 2014-12-19) that exceed */
/* this limit */
#define CF2_STORAGE_SIZE 32
/* typedef is in `cf2glue.h' */

View File

@ -447,6 +447,8 @@
CF2_Stack opStack = NULL;
FT_Byte op1; /* first opcode byte */
CF2_F16Dot16 storage[CF2_STORAGE_SIZE]; /* for `put' and `get' */
/* instruction limit; 20,000,000 matches Avalon */
FT_UInt32 instructionLimit = 20000000UL;
@ -834,84 +836,189 @@
break;
/* TODO: should these operators be supported? */
case cf2_escAND: /* in spec */
FT_TRACE4(( " and\n" ));
case cf2_escAND:
{
CF2_F16Dot16 arg1;
CF2_F16Dot16 arg2;
CF2_FIXME;
break;
case cf2_escOR: /* in spec */
FT_TRACE4(( " or\n" ));
FT_TRACE4(( " and\n" ));
CF2_FIXME;
break;
arg2 = cf2_stack_popFixed( opStack );
arg1 = cf2_stack_popFixed( opStack );
case cf2_escNOT: /* in spec */
FT_TRACE4(( " not\n" ));
cf2_stack_pushInt( opStack, arg1 && arg2 );
}
continue; /* do not clear the stack */
CF2_FIXME;
break;
case cf2_escOR:
{
CF2_F16Dot16 arg1;
CF2_F16Dot16 arg2;
case cf2_escABS: /* in spec */
FT_TRACE4(( " abs\n" ));
CF2_FIXME;
break;
FT_TRACE4(( " or\n" ));
case cf2_escADD: /* in spec */
FT_TRACE4(( " add\n" ));
arg2 = cf2_stack_popFixed( opStack );
arg1 = cf2_stack_popFixed( opStack );
CF2_FIXME;
break;
cf2_stack_pushInt( opStack, arg1 || arg2 );
}
continue; /* do not clear the stack */
case cf2_escSUB: /* in spec */
FT_TRACE4(( " sub\n" ));
case cf2_escNOT:
{
CF2_F16Dot16 arg;
CF2_FIXME;
break;
case cf2_escDIV: /* in spec */
FT_TRACE4(( " div\n" ));
FT_TRACE4(( " not\n" ));
CF2_FIXME;
break;
arg = cf2_stack_popFixed( opStack );
case cf2_escNEG: /* in spec */
FT_TRACE4(( " neg\n" ));
cf2_stack_pushInt( opStack, !arg );
}
continue; /* do not clear the stack */
CF2_FIXME;
break;
case cf2_escABS:
{
CF2_F16Dot16 arg;
case cf2_escEQ: /* in spec */
FT_TRACE4(( " eq\n" ));
CF2_FIXME;
break;
FT_TRACE4(( " abs\n" ));
case cf2_escDROP: /* in spec */
arg = cf2_stack_popFixed( opStack );
cf2_stack_pushFixed( opStack, FT_ABS( arg ) );
}
continue; /* do not clear the stack */
case cf2_escADD:
{
CF2_F16Dot16 summand1;
CF2_F16Dot16 summand2;
FT_TRACE4(( " add\n" ));
summand2 = cf2_stack_popFixed( opStack );
summand1 = cf2_stack_popFixed( opStack );
cf2_stack_pushFixed( opStack, summand1 + summand2 );
}
continue; /* do not clear the stack */
case cf2_escSUB:
{
CF2_F16Dot16 minuend;
CF2_F16Dot16 subtrahend;
FT_TRACE4(( " sub\n" ));
subtrahend = cf2_stack_popFixed( opStack );
minuend = cf2_stack_popFixed( opStack );
cf2_stack_pushFixed( opStack, minuend - subtrahend );
}
continue; /* do not clear the stack */
case cf2_escDIV:
{
CF2_F16Dot16 dividend;
CF2_F16Dot16 divisor;
FT_TRACE4(( " div\n" ));
divisor = cf2_stack_popFixed( opStack );
dividend = cf2_stack_popFixed( opStack );
cf2_stack_pushFixed( opStack, FT_DivFix( dividend, divisor ) );
}
continue; /* do not clear the stack */
case cf2_escNEG:
{
CF2_F16Dot16 arg;
FT_TRACE4(( " neg\n" ));
arg = cf2_stack_popFixed( opStack );
cf2_stack_pushFixed( opStack, -arg );
}
continue; /* do not clear the stack */
case cf2_escEQ:
{
CF2_F16Dot16 arg1;
CF2_F16Dot16 arg2;
FT_TRACE4(( " eq\n" ));
arg2 = cf2_stack_popFixed( opStack );
arg1 = cf2_stack_popFixed( opStack );
cf2_stack_pushInt( opStack, arg1 == arg2 );
}
continue; /* do not clear the stack */
case cf2_escDROP:
FT_TRACE4(( " drop\n" ));
CF2_FIXME;
break;
(void)cf2_stack_popFixed( opStack );
continue; /* do not clear the stack */
case cf2_escPUT: /* in spec */
FT_TRACE4(( " put\n" ));
case cf2_escPUT:
{
CF2_F16Dot16 val;
CF2_Int idx;
CF2_FIXME;
break;
case cf2_escGET: /* in spec */
FT_TRACE4(( " get\n" ));
FT_TRACE4(( " put\n" ));
CF2_FIXME;
break;
idx = cf2_stack_popInt( opStack );
val = cf2_stack_popFixed( opStack );
case cf2_escIFELSE: /* in spec */
FT_TRACE4(( " ifelse\n" ));
if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
storage[idx] = val;
}
continue; /* do not clear the stack */
CF2_FIXME;
break;
case cf2_escGET:
{
CF2_Int idx;
FT_TRACE4(( " get\n" ));
idx = cf2_stack_popInt( opStack );
if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
cf2_stack_pushFixed( opStack, storage[idx] );
}
continue; /* do not clear the stack */
case cf2_escIFELSE:
{
CF2_F16Dot16 arg1;
CF2_F16Dot16 arg2;
CF2_F16Dot16 cond1;
CF2_F16Dot16 cond2;
FT_TRACE4(( " ifelse\n" ));
cond2 = cf2_stack_popFixed( opStack );
cond1 = cf2_stack_popFixed( opStack );
arg2 = cf2_stack_popFixed( opStack );
arg1 = cf2_stack_popFixed( opStack );
cf2_stack_pushFixed( opStack, cond1 <= cond2 ? arg1 : arg2 );
}
continue; /* do not clear the stack */
case cf2_escRANDOM: /* in spec */
FT_TRACE4(( " random\n" ));
@ -919,41 +1026,126 @@
CF2_FIXME;
break;
case cf2_escMUL: /* in spec */
FT_TRACE4(( " mul\n" ));
case cf2_escMUL:
{
CF2_F16Dot16 factor1;
CF2_F16Dot16 factor2;
CF2_FIXME;
break;
case cf2_escSQRT: /* in spec */
FT_TRACE4(( " sqrt\n" ));
FT_TRACE4(( " mul\n" ));
CF2_FIXME;
break;
factor2 = cf2_stack_popFixed( opStack );
factor1 = cf2_stack_popFixed( opStack );
case cf2_escDUP: /* in spec */
FT_TRACE4(( " dup\n" ));
cf2_stack_pushFixed( opStack, FT_MulFix( factor1, factor2 ) );
}
continue; /* do not clear the stack */
CF2_FIXME;
break;
case cf2_escSQRT:
{
CF2_F16Dot16 arg;
case cf2_escEXCH: /* in spec */
FT_TRACE4(( " exch\n" ));
CF2_FIXME;
break;
FT_TRACE4(( " sqrt\n" ));
case cf2_escINDEX: /* in spec */
FT_TRACE4(( " index\n" ));
arg = cf2_stack_popFixed( opStack );
if ( arg > 0 )
{
FT_Fixed root = arg;
FT_Fixed new_root;
CF2_FIXME;
break;
case cf2_escROLL: /* in spec */
FT_TRACE4(( " roll\n" ));
/* 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_FIXME;
break;
cf2_stack_pushFixed( opStack, arg );
}
continue; /* do not clear the stack */
case cf2_escDUP:
{
CF2_F16Dot16 arg;
FT_TRACE4(( " dup\n" ));
arg = cf2_stack_popFixed( opStack );
cf2_stack_pushFixed( opStack, arg );
cf2_stack_pushFixed( opStack, arg );
}
continue; /* do not clear the stack */
case cf2_escEXCH:
{
CF2_F16Dot16 arg1;
CF2_F16Dot16 arg2;
FT_TRACE4(( " exch\n" ));
arg2 = cf2_stack_popFixed( opStack );
arg1 = cf2_stack_popFixed( opStack );
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(( " index\n" ));
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;
if ( idx < 0 )
gr_idx = size - 1;
else if ( (CF2_UInt)idx >= size )
gr_idx = 0;
else
gr_idx = size - 1 - (CF2_UInt)idx;
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(( " roll\n" ));
idx = cf2_stack_popInt( opStack );
count = cf2_stack_popInt( opStack );
cf2_stack_roll( opStack, count, idx );
}
continue; /* do not clear the stack */
case cf2_escHFLEX:
{

View File

@ -145,7 +145,7 @@
/* Note: type mismatch is silently cast */
/* TODO: check this */
/* TODO: check this */
FT_LOCAL_DEF( CF2_Fixed )
cf2_stack_popFixed( CF2_Stack stack )
{
@ -170,7 +170,7 @@
/* Note: type mismatch is silently cast */
/* TODO: check this */
/* TODO: check this */
FT_LOCAL_DEF( CF2_Fixed )
cf2_stack_getReal( CF2_Stack stack,
CF2_UInt idx )
@ -195,6 +195,86 @@
}
FT_LOCAL( void )
cf2_stack_roll( CF2_Stack stack,
CF2_Int count,
CF2_Int shift )
{
/* we initialize this variable to avoid compiler warnings */
CF2_StackNumber last = { { 0 }, CF2_NumberInt };
CF2_Int start_idx, idx, i;
if ( count < 2 )
return; /* nothing to do (values 0 and 1), or undefined value */
if ( (CF2_UInt)count > cf2_stack_count( stack ) )
{
CF2_SET_ERROR( stack->error, Stack_Overflow );
return;
}
if ( shift < 0 )
shift = -( ( -shift ) % count );
else
shift %= count;
if ( shift == 0 )
return; /* nothing to do */
/* We use the following algorithm to do the rolling, */
/* which needs two temporary variables only. */
/* */
/* Example: */
/* */
/* count = 8 */
/* shift = 2 */
/* */
/* stack indices before roll: 7 6 5 4 3 2 1 0 */
/* stack indices after roll: 1 0 7 6 5 4 3 2 */
/* */
/* The value of index 0 gets moved to index 2, while */
/* the old value of index 2 gets moved to index 4, */
/* and so on. We thus have the following copying */
/* chains for shift value 2. */
/* */
/* 0 -> 2 -> 4 -> 6 -> 0 */
/* 1 -> 3 -> 5 -> 7 -> 1 */
/* */
/* If `count' and `shift' are incommensurable, we */
/* have a single chain only. Otherwise, increase */
/* the start index by 1 after the first chain, then */
/* do the next chain until all elements in all */
/* chains are handled. */
start_idx = -1;
idx = -1;
for ( i = 0; i < count; i++ )
{
CF2_StackNumber tmp;
if ( start_idx == idx )
{
start_idx++;
idx = start_idx;
last = stack->buffer[idx];
}
idx += shift;
if ( idx >= count )
idx -= count;
else if ( idx < 0 )
idx += count;
tmp = stack->buffer[idx];
stack->buffer[idx] = last;
last = tmp;
}
}
FT_LOCAL_DEF( void )
cf2_stack_clear( CF2_Stack stack )
{

View File

@ -93,6 +93,11 @@ FT_BEGIN_HEADER
cf2_stack_getReal( CF2_Stack stack,
CF2_UInt idx );
FT_LOCAL( void )
cf2_stack_roll( CF2_Stack stack,
CF2_Int count,
CF2_Int idx );
FT_LOCAL( void )
cf2_stack_clear( CF2_Stack stack );