Extend Adobe interpreter (callothersubr).
* src/psaux/psintrp.c (cf2_interpT2CharString) <cf2_escCALLOTHERSUBR>: Copy code from `t1_decoder_parse_charstrings' (in `t1decode.c'). OtherSubr 3 (change hints) should reset the hintmask, so that the new hints are applied. Fix function calls and stack access.
This commit is contained in:
parent
77c1b331f6
commit
9668255965
15
ChangeLog
15
ChangeLog
|
@ -1,3 +1,14 @@
|
|||
2017-09-25 Ewald Hew <ewaldhew@gmail.com>
|
||||
|
||||
[psaux] Extend Adobe interpreter (callothersubr).
|
||||
|
||||
* src/psaux/psintrp.c (cf2_interpT2CharString)
|
||||
<cf2_escCALLOTHERSUBR>: Copy code from
|
||||
`t1_decoder_parse_charstrings' (in `t1decode.c').
|
||||
OtherSubr 3 (change hints) should reset the hintmask, so that the
|
||||
new hints are applied.
|
||||
Fix function calls and stack access.
|
||||
|
||||
2017-09-25 Ewald Hew <ewaldhew@gmail.com>
|
||||
|
||||
[psaux] Extend Adobe interpreter (pop).
|
||||
|
@ -30,7 +41,7 @@
|
|||
|
||||
2017-09-25 Ewald Hew <ewaldhew@gmail.com>
|
||||
|
||||
Extend Adobe interpreter (hints).
|
||||
[psaux] Extend Adobe interpreter (hints).
|
||||
|
||||
* src/psaux/psintrp.c (cf2_interpT2CharString) <cf2_cmdHSTEM,
|
||||
cf2_cmdVSTEM>: Add correction for left sidebearing in Type 1 mode.
|
||||
|
@ -61,7 +72,7 @@
|
|||
|
||||
2017-09-25 Ewald Hew <ewaldhew@gmail.com>
|
||||
|
||||
[psaux] Extend Adobe interpreter (`closepath').
|
||||
[psaux] Extend Adobe interpreter (closepath).
|
||||
|
||||
* src/psaux/psintrp.c (cf2_interpT2CharString) <c2f_cmdCLOSEPATH>:
|
||||
Use the right builder function. We can use the `haveWidth' boolean
|
||||
|
|
|
@ -1448,8 +1448,445 @@
|
|||
FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
|
||||
else
|
||||
{
|
||||
CF2_Int subr_no;
|
||||
CF2_Int arg_cnt;
|
||||
CF2_UInt count;
|
||||
CF2_UInt opIdx = 0;
|
||||
|
||||
FT_TRACE4(( " callothersubr\n" ));
|
||||
|
||||
subr_no = cf2_stack_popInt( opStack );
|
||||
arg_cnt = cf2_stack_popInt( opStack );
|
||||
|
||||
/***********************************************************/
|
||||
/* */
|
||||
/* remove all operands to callothersubr from the stack */
|
||||
/* */
|
||||
/* for handled othersubrs, where we know the number of */
|
||||
/* arguments, we increase the stack by the value of */
|
||||
/* known_othersubr_result_cnt */
|
||||
/* */
|
||||
/* for unhandled othersubrs the following pops adjust the */
|
||||
/* stack pointer as necessary */
|
||||
|
||||
count = cf2_stack_count( opStack );
|
||||
FT_ASSERT( arg_cnt <= count );
|
||||
|
||||
opIdx += count - arg_cnt;
|
||||
|
||||
known_othersubr_result_cnt = 0;
|
||||
result_cnt = 0;
|
||||
|
||||
/* XXX TODO: The checks to `arg_count == <whatever>' */
|
||||
/* might not be correct; an othersubr expects a certain */
|
||||
/* number of operands on the PostScript stack (as opposed */
|
||||
/* to the T1 stack) but it doesn't have to put them there */
|
||||
/* by itself; previous othersubrs might have left the */
|
||||
/* operands there if they were not followed by an */
|
||||
/* appropriate number of pops */
|
||||
/* */
|
||||
/* On the other hand, Adobe Reader 7.0.8 for Linux doesn't */
|
||||
/* accept a font that contains charstrings like */
|
||||
/* */
|
||||
/* 100 200 2 20 callothersubr */
|
||||
/* 300 1 20 callothersubr pop */
|
||||
/* */
|
||||
/* Perhaps this is the reason why BuildCharArray exists. */
|
||||
|
||||
switch ( subr_no )
|
||||
{
|
||||
case 0: /* end flex feature */
|
||||
if ( arg_cnt != 3 )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
if ( !decoder->flex_state ||
|
||||
decoder->num_flex_vectors != 7 )
|
||||
{
|
||||
FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):"
|
||||
" unexpected flex end\n" ));
|
||||
lastError = FT_THROW( Invalid_Glyph_Format );
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* the two `results' are popped by the following setcurrentpoint */
|
||||
cf2_stack_pushFixed( opStack, curX );
|
||||
cf2_stack_pushFixed( opStack, curY );
|
||||
known_othersubr_result_cnt = 2;
|
||||
break;
|
||||
|
||||
case 1: /* start flex feature */
|
||||
if ( arg_cnt != 0 )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
if ( ps_builder_start_point( &decoder->builder, curX, curY ) ||
|
||||
ps_builder_check_points( &decoder->builder, 6 ) )
|
||||
goto exit;
|
||||
|
||||
decoder->flex_state = 1;
|
||||
decoder->num_flex_vectors = 0;
|
||||
break;
|
||||
|
||||
case 2: /* add flex vectors */
|
||||
{
|
||||
FT_Int idx;
|
||||
|
||||
|
||||
if ( arg_cnt != 0 )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
if ( !decoder->flex_state )
|
||||
{
|
||||
FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):"
|
||||
" missing flex start\n" ));
|
||||
lastError = FT_THROW( Invalid_Glyph_Format );
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* note that we should not add a point for index 0; */
|
||||
/* this will move our current position to the flex */
|
||||
/* point without adding any point to the outline */
|
||||
idx = decoder->num_flex_vectors++;
|
||||
if ( idx > 0 && idx < 7 )
|
||||
{
|
||||
/* in malformed fonts it is possible to have other */
|
||||
/* opcodes in the middle of a flex (which don't */
|
||||
/* increase `num_flex_vectors'); we thus have to */
|
||||
/* check whether we can add a point */
|
||||
if ( ps_builder_check_points( &decoder->builder, 1 ) )
|
||||
{
|
||||
lastError = FT_THROW( Invalid_Glyph_Format );
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ps_builder_add_point( &decoder->builder,
|
||||
curX,
|
||||
curY,
|
||||
(FT_Byte)( idx == 3 || idx == 6 ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: /* change hints */
|
||||
if ( arg_cnt != 1 )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
cf2_arrstack_clear( &vStemHintArray );
|
||||
cf2_arrstack_clear( &hStemHintArray );
|
||||
|
||||
cf2_hintmask_init( &hintMask, error );
|
||||
hintMask.isValid = FALSE;
|
||||
hintMask.isNew = TRUE;
|
||||
|
||||
known_othersubr_result_cnt = 1;
|
||||
break;
|
||||
|
||||
case 12:
|
||||
case 13:
|
||||
/* counter control hints, clear stack */
|
||||
cf2_stack_clear( opStack );
|
||||
break;
|
||||
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
case 18: /* multiple masters */
|
||||
{
|
||||
PS_Blend blend = decoder->blend;
|
||||
FT_UInt num_points, nn, mm;
|
||||
CF2_UInt delta;
|
||||
CF2_UInt values;
|
||||
|
||||
|
||||
if ( !blend )
|
||||
{
|
||||
FT_ERROR(( "t1_decoder_parse_charstrings:"
|
||||
" unexpected multiple masters operator\n" ));
|
||||
lastError = FT_THROW( Invalid_Glyph_Format );
|
||||
goto exit;
|
||||
}
|
||||
|
||||
num_points = (FT_UInt)subr_no - 13 + ( subr_no == 18 );
|
||||
if ( arg_cnt != (FT_Int)( num_points * blend->num_designs ) )
|
||||
{
|
||||
FT_ERROR(( "t1_decoder_parse_charstrings:"
|
||||
" incorrect number of multiple masters arguments\n" ));
|
||||
lastError = FT_THROW( Invalid_Glyph_Format );
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* We want to compute */
|
||||
/* */
|
||||
/* a0*w0 + a1*w1 + ... + ak*wk */
|
||||
/* */
|
||||
/* but we only have a0, a1-a0, a2-a0, ..., ak-a0. */
|
||||
/* */
|
||||
/* However, given that w0 + w1 + ... + wk == 1, we can */
|
||||
/* rewrite it easily as */
|
||||
/* */
|
||||
/* a0 + (a1-a0)*w1 + (a2-a0)*w2 + ... + (ak-a0)*wk */
|
||||
/* */
|
||||
/* where k == num_designs-1. */
|
||||
/* */
|
||||
/* I guess that's why it's written in this `compact' */
|
||||
/* form. */
|
||||
/* */
|
||||
delta = opIdx + num_points;
|
||||
values = opIdx;
|
||||
for ( nn = 0; nn < num_points; nn++ )
|
||||
{
|
||||
CF2_Fixed tmp = cf2_stack_getReal( opStack, values );
|
||||
|
||||
|
||||
for ( mm = 1; mm < blend->num_designs; mm++ )
|
||||
tmp = ADD_INT32( tmp,
|
||||
FT_MulFix( cf2_stack_getReal( opStack, delta++ ),
|
||||
blend->weight_vector[mm] ) );
|
||||
|
||||
cf2_stack_setReal( opStack, values++, tmp );
|
||||
}
|
||||
cf2_stack_pop( opStack,
|
||||
arg_cnt - num_points );
|
||||
|
||||
known_othersubr_result_cnt = (FT_Int)num_points;
|
||||
break;
|
||||
}
|
||||
|
||||
case 19:
|
||||
/* <idx> 1 19 callothersubr */
|
||||
/* => replace elements starting from index cvi( <idx> ) */
|
||||
/* of BuildCharArray with WeightVector */
|
||||
{
|
||||
FT_Int idx;
|
||||
PS_Blend blend = decoder->blend;
|
||||
|
||||
|
||||
if ( arg_cnt != 1 || !blend )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
idx = cf2_stack_popInt( opStack );
|
||||
|
||||
if ( idx < 0 ||
|
||||
(FT_UInt)idx + blend->num_designs > decoder->len_buildchar )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
ft_memcpy( &decoder->buildchar[idx],
|
||||
blend->weight_vector,
|
||||
blend->num_designs *
|
||||
sizeof ( blend->weight_vector[0] ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case 20:
|
||||
/* <arg1> <arg2> 2 20 callothersubr pop */
|
||||
/* ==> push <arg1> + <arg2> onto T1 stack */
|
||||
{
|
||||
CF2_F16Dot16 summand1;
|
||||
CF2_F16Dot16 summand2;
|
||||
|
||||
if ( arg_cnt != 2 )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
summand2 = cf2_stack_popFixed( opStack );
|
||||
summand1 = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack,
|
||||
ADD_INT32( summand1,
|
||||
summand2 ) );
|
||||
known_othersubr_result_cnt = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 21:
|
||||
/* <arg1> <arg2> 2 21 callothersubr pop */
|
||||
/* ==> push <arg1> - <arg2> onto T1 stack */
|
||||
{
|
||||
CF2_F16Dot16 minuend;
|
||||
CF2_F16Dot16 subtrahend;
|
||||
|
||||
if ( arg_cnt != 2 )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
subtrahend = cf2_stack_popFixed( opStack );
|
||||
minuend = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack,
|
||||
SUB_INT32( minuend, subtrahend ) );
|
||||
known_othersubr_result_cnt = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 22:
|
||||
/* <arg1> <arg2> 2 22 callothersubr pop */
|
||||
/* ==> push <arg1> * <arg2> onto T1 stack */
|
||||
{
|
||||
CF2_F16Dot16 factor1;
|
||||
CF2_F16Dot16 factor2;
|
||||
|
||||
if ( arg_cnt != 2 )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
factor2 = cf2_stack_popFixed( opStack );
|
||||
factor1 = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack,
|
||||
FT_MulFix( factor1, factor2 ) );
|
||||
known_othersubr_result_cnt = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 23:
|
||||
/* <arg1> <arg2> 2 23 callothersubr pop */
|
||||
/* ==> push <arg1> / <arg2> onto T1 stack */
|
||||
{
|
||||
CF2_F16Dot16 dividend;
|
||||
CF2_F16Dot16 divisor;
|
||||
|
||||
if ( arg_cnt != 2 )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
divisor = cf2_stack_popFixed( opStack );
|
||||
dividend = cf2_stack_popFixed( opStack );
|
||||
|
||||
if ( divisor == 0 )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
cf2_stack_pushFixed( opStack,
|
||||
FT_DivFix( dividend, divisor ) );
|
||||
known_othersubr_result_cnt = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 24:
|
||||
/* <val> <idx> 2 24 callothersubr */
|
||||
/* ==> set BuildCharArray[cvi( <idx> )] = <val> */
|
||||
{
|
||||
CF2_Int idx;
|
||||
PS_Blend blend = decoder->blend;
|
||||
|
||||
|
||||
if ( arg_cnt != 2 || !blend )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
idx = cf2_stack_popInt( opStack );
|
||||
|
||||
if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
decoder->buildchar[idx] = cf2_stack_popFixed( opStack );
|
||||
}
|
||||
break;
|
||||
|
||||
case 25:
|
||||
/* <idx> 1 25 callothersubr pop */
|
||||
/* ==> push BuildCharArray[cvi( idx )] */
|
||||
/* onto T1 stack */
|
||||
{
|
||||
CF2_Int idx;
|
||||
PS_Blend blend = decoder->blend;
|
||||
|
||||
|
||||
if ( arg_cnt != 1 || !blend )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
idx = cf2_stack_popInt( opStack );
|
||||
|
||||
if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
cf2_stack_pushFixed( opStack,
|
||||
decoder->buildchar[idx] );
|
||||
known_othersubr_result_cnt = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case 26:
|
||||
/* <val> mark <idx> ==> set BuildCharArray[cvi( <idx> )] = <val>, */
|
||||
/* leave mark on T1 stack */
|
||||
/* <val> <idx> ==> set BuildCharArray[cvi( <idx> )] = <val> */
|
||||
XXX which routine has left its mark on the (PostScript) stack?;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 27:
|
||||
/* <res1> <res2> <val1> <val2> 4 27 callothersubr pop */
|
||||
/* ==> push <res1> onto T1 stack if <val1> <= <val2>, */
|
||||
/* otherwise push <res2> */
|
||||
{
|
||||
CF2_F16Dot16 arg1;
|
||||
CF2_F16Dot16 arg2;
|
||||
CF2_F16Dot16 cond1;
|
||||
CF2_F16Dot16 cond2;
|
||||
|
||||
if ( arg_cnt != 4 )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
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 );
|
||||
known_othersubr_result_cnt = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 28:
|
||||
/* 0 28 callothersubr pop */
|
||||
/* => push random value from interval [0, 1) onto stack */
|
||||
{
|
||||
CF2_F16Dot16 r;
|
||||
|
||||
if ( arg_cnt != 0 )
|
||||
goto Unexpected_OtherSubr;
|
||||
|
||||
/* only use the lower 16 bits of `random' */
|
||||
/* to generate a number in the range (0;1] */
|
||||
r = (CF2_F16Dot16)
|
||||
( ( decoder->current_subfont->random & 0xFFFF ) + 1 );
|
||||
|
||||
decoder->current_subfont->random =
|
||||
cff_random( decoder->current_subfont->random );
|
||||
|
||||
cf2_stack_pushFixed( opStack, r );
|
||||
known_othersubr_result_cnt = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( arg_cnt >= 0 && subr_no >= 0 )
|
||||
{
|
||||
FT_UInt i;
|
||||
|
||||
FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):"
|
||||
" unknown othersubr [%d %d], wish me luck\n",
|
||||
arg_cnt, subr_no ));
|
||||
|
||||
/* Store the unused args for this unhandled OtherSubr */
|
||||
|
||||
if ( arg_cnt > PS_STORAGE_SIZE )
|
||||
arg_cnt = PS_STORAGE_SIZE;
|
||||
result_cnt = arg_cnt;
|
||||
|
||||
for ( i = 1; i <= arg_cnt; i++ )
|
||||
{
|
||||
results[result_cnt - i] = cf2_stack_popFixed( opStack );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
|
||||
Unexpected_OtherSubr:
|
||||
FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):"
|
||||
" invalid othersubr [%d %d]\n", arg_cnt, subr_no ));
|
||||
lastError = FT_THROW( Invalid_Glyph_Format );
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
break;
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escPOP:
|
||||
if ( !font->isT1 )
|
||||
|
|
Loading…
Reference in New Issue