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:
Ewald Hew 2017-09-25 07:54:02 +02:00 committed by Werner Lemberg
parent 77c1b331f6
commit 9668255965
2 changed files with 451 additions and 3 deletions

View File

@ -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

View File

@ -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 )