[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:
parent
1a95d00210
commit
950f16969e
13
ChangeLog
13
ChangeLog
|
@ -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.
|
||||
|
|
|
@ -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' */
|
||||
|
|
|
@ -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:
|
||||
{
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
Loading…
Reference in New Issue