[cff] Make old CFF engine show MM CFFs (without variations).

The new code only displays the first master in the font.

* src/cff/cffgload.c (cff_decode_parse_charstrings): Add new
parameter to allow function calls from dictionaries also.
<cff_op_blend>: Partially implement it.
Update all callers.
* src/cff/cffgload.h: Updated.

* src/cff/cffparse.c (cff_parser_init): Add new parameter to pass the
number of Multiple Master designs.
Update all callers.
(cff_parse_multiple_master): New function to rudimentarily parse
operator.
(cff_parser_run): Handle `T2' operator.
* src/cff/cffparse.h: Updated.
(CFF_ParserRec): Add `num_designs' field.

* src/cff/cffload.c: Updated.

* src/cff/cfftoken.h: Handle `MultipleMaster' operator.

* src/cff/cfftypes.h (CFF_FontRecDictRec): Add `num_designs' field.

* src/sfnt/sfobjs.c (sfnt_init_face): Don't handle `fvar' table for
MM CFFs.
This commit is contained in:
Werner Lemberg 2016-02-14 16:03:15 +01:00
parent 4b3ea5ca8f
commit 813aca51d2
9 changed files with 317 additions and 15 deletions

View File

@ -1,3 +1,33 @@
2016-02-14 Werner Lemberg <wl@gnu.org>
[cff] Make old CFF engine show MM CFFs (without variations).
The new code only displays the first master in the font.
* src/cff/cffgload.c (cff_decode_parse_charstrings): Add new
parameter to allow function calls from dictionaries also.
<cff_op_blend>: Partially implement it.
Update all callers.
* src/cff/cffgload.h: Updated.
* src/cff/cffparse.c (cff_parser_init): Add new parameter to pass the
number of Multiple Master designs.
Update all callers.
(cff_parse_multiple_master): New function to rudimentarily parse
operator.
(cff_parser_run): Handle `T2' operator.
* src/cff/cffparse.h: Updated.
(CFF_ParserRec): Add `num_designs' field.
* src/cff/cffload.c: Updated.
* src/cff/cfftoken.h: Handle `MultipleMaster' operator.
* src/cff/cfftypes.h (CFF_FontRecDictRec): Add `num_designs' field.
* src/sfnt/sfobjs.c (sfnt_init_face): Don't handle `fvar' table for
MM CFFs.
2016-02-09 Werner Lemberg <wl@gnu.org>
[docmaker] Don't emit trailing newlines.

View File

@ -826,7 +826,7 @@
/* the seac operator must not be nested */
decoder->seac = TRUE;
error = cff_decoder_parse_charstrings( decoder, charstring,
charstring_len );
charstring_len, 0 );
decoder->seac = FALSE;
cff_free_glyph_data( face, &charstring, charstring_len );
@ -856,7 +856,7 @@
/* the seac operator must not be nested */
decoder->seac = TRUE;
error = cff_decoder_parse_charstrings( decoder, charstring,
charstring_len );
charstring_len, 0 );
decoder->seac = FALSE;
cff_free_glyph_data( face, &charstring, charstring_len );
@ -895,13 +895,17 @@
/* */
/* charstring_len :: The length in bytes of the charstring stream. */
/* */
/* in_dict :: Set to 1 if function is called from top or */
/* private DICT (needed for Multiple Master CFFs). */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
FT_LOCAL_DEF( FT_Error )
cff_decoder_parse_charstrings( CFF_Decoder* decoder,
FT_Byte* charstring_base,
FT_ULong charstring_len )
FT_ULong charstring_len,
FT_Bool in_dict )
{
FT_Error error;
CFF_Decoder_Zone* zone;
@ -913,6 +917,8 @@
FT_Fixed* stack;
FT_Int charstring_type =
decoder->cff->top_font.font_dict.charstring_type;
FT_UShort num_designs =
decoder->cff->top_font.font_dict.num_designs;
T2_Hints_Funcs hinter;
@ -1241,6 +1247,44 @@
if ( op == cff_op_unknown )
continue;
/* in Multiple Master CFFs, T2 charstrings can appear in */
/* dictionaries, but some operators are prohibited */
if ( in_dict )
{
switch ( op )
{
case cff_op_hstem:
case cff_op_vstem:
case cff_op_vmoveto:
case cff_op_rlineto:
case cff_op_hlineto:
case cff_op_vlineto:
case cff_op_rrcurveto:
case cff_op_hstemhm:
case cff_op_hintmask:
case cff_op_cntrmask:
case cff_op_rmoveto:
case cff_op_hmoveto:
case cff_op_vstemhm:
case cff_op_rcurveline:
case cff_op_rlinecurve:
case cff_op_vvcurveto:
case cff_op_hhcurveto:
case cff_op_vhcurveto:
case cff_op_hvcurveto:
case cff_op_hflex:
case cff_op_flex:
case cff_op_hflex1:
case cff_op_flex1:
case cff_op_callsubr:
case cff_op_callgsubr:
goto MM_Error;
default:
break;
}
}
/* check arguments */
req_args = cff_argument_counts[op];
if ( req_args & CFF_COUNT_CHECK_WIDTH )
@ -1278,7 +1322,9 @@
case cff_op_endchar:
/* If there is a width specified for endchar, we either have */
/* 1 argument or 5 arguments. We like to argue. */
set_width_ok = ( num_args == 5 ) || ( num_args == 1 );
set_width_ok = in_dict
? 0
: ( ( num_args == 5 ) || ( num_args == 1 ) );
break;
default:
@ -1971,6 +2017,10 @@
return error;
case cff_op_endchar:
/* in dictionaries, `endchar' simply indicates end of data */
if ( in_dict )
return error;
FT_TRACE4(( " endchar\n" ));
/* We are going to emulate the seac operator. */
@ -2236,9 +2286,25 @@
case cff_op_blend:
/* this operator was removed from the Type2 specification */
/* in version 16-March-2000 */
{
FT_Int num_results = (FT_Int)( args[0] >> 16 );
FT_TRACE4(( " blend\n" ));
goto Unimplemented;
if ( num_results < 0 )
goto Syntax_Error;
if ( num_results * (FT_Int)num_designs > num_args )
goto Stack_Underflow;
/* since we currently don't handle interpolation of multiple */
/* master fonts, return the `num_results' values of the */
/* first master */
args -= num_results * ( num_designs - 1 );
num_args -= num_results * ( num_designs - 1 );
}
break;
case cff_op_dotsection:
/* this operator is deprecated and ignored by the parser */
@ -2535,6 +2601,11 @@
Fail:
return error;
MM_Error:
FT_TRACE4(( "cff_decoder_parse_charstrings:"
" invalid opcode found in top DICT charstring\n"));
return FT_THROW( Invalid_File_Format );
Syntax_Error:
FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error\n" ));
return FT_THROW( Invalid_File_Format );
@ -2608,7 +2679,8 @@
if ( !error )
error = cff_decoder_parse_charstrings( &decoder,
charstring,
charstring_len );
charstring_len,
0 );
cff_free_glyph_data( face, &charstring, &charstring_len );
}
@ -2859,7 +2931,8 @@
if ( driver->hinting_engine == FT_CFF_HINTING_FREETYPE )
error = cff_decoder_parse_charstrings( &decoder,
charstring,
charstring_len );
charstring_len,
0 );
else
#endif
{

View File

@ -227,7 +227,8 @@ FT_BEGIN_HEADER
FT_LOCAL( FT_Error )
cff_decoder_parse_charstrings( CFF_Decoder* decoder,
FT_Byte* charstring_base,
FT_ULong charstring_len );
FT_ULong charstring_len,
FT_Bool in_dict );
#endif
FT_LOCAL( FT_Error )

View File

@ -1316,7 +1316,11 @@
CFF_Private priv = &font->private_dict;
cff_parser_init( &parser, CFF_CODE_TOPDICT, &font->font_dict, library );
cff_parser_init( &parser,
CFF_CODE_TOPDICT,
&font->font_dict,
library,
0 );
/* set defaults */
FT_MEM_ZERO( top, sizeof ( *top ) );
@ -1370,7 +1374,11 @@
priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L );
priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 );
cff_parser_init( &parser, CFF_CODE_PRIVATE, priv, library );
cff_parser_init( &parser,
CFF_CODE_PRIVATE,
priv,
library,
top->num_designs );
if ( FT_STREAM_SEEK( base_offset + font->font_dict.private_offset ) ||
FT_FRAME_ENTER( font->font_dict.private_size ) )

View File

@ -39,7 +39,8 @@
cff_parser_init( CFF_Parser parser,
FT_UInt code,
void* object,
FT_Library library)
FT_Library library,
FT_UShort num_designs )
{
FT_MEM_ZERO( parser, sizeof ( *parser ) );
@ -47,6 +48,7 @@
parser->object_code = code;
parser->object = object;
parser->library = library;
parser->num_designs = num_designs;
}
@ -649,6 +651,47 @@
}
/* We assume that the `MultipleMaster' operator comes before any */
/* top DICT operators that contain T2 charstrings. Otherwise, */
/* `num_designs' is zero, leading to errors in handling the */
/* `blend' operator later on. */
static FT_Error
cff_parse_multiple_master( CFF_Parser parser )
{
CFF_FontRecDict dict = (CFF_FontRecDict)parser->object;
FT_Error error;
FT_TRACE1(( "Multiple Master CFFs not supported yet,"
" handling first master design only\n" ));
error = FT_ERR( Stack_Underflow );
/* currently, we handle only the first argument */
if ( parser->top >= parser->stack + 5 )
{
FT_Long num_designs = cff_parse_num( parser->stack );
if ( num_designs > 16 || num_designs < 2 )
{
FT_ERROR(( "cff_parse_multiple_master:"
" Invalid number of designs\n" ));
error = FT_THROW( Invalid_File_Format );
}
else
{
dict->num_designs = (FT_UShort)num_designs;
parser->num_designs = dict->num_designs;
error = FT_Err_Ok;
}
}
return error;
}
static FT_Error
cff_parse_cid_ros( CFF_Parser parser )
{
@ -1001,6 +1044,133 @@
else if ( v > 246 )
p += 1;
}
else if ( v == 31 )
{
/* a Type 2 charstring */
CFF_Decoder decoder;
CFF_FontRec cff_rec;
FT_Byte* charstring_base;
FT_ULong charstring_len;
FT_Fixed* stack;
FT_Byte* q;
charstring_base = ++p;
/* search `endchar' operator */
for (;;)
{
if ( p >= limit )
goto Exit;
if ( *p == 14 )
break;
p++;
}
charstring_len = (FT_ULong)( p - charstring_base ) + 1;
/* construct CFF_Decoder object */
FT_MEM_ZERO( &decoder, sizeof ( decoder ) );
FT_MEM_ZERO( &cff_rec, sizeof ( cff_rec ) );
cff_rec.top_font.font_dict.num_designs = parser->num_designs;
decoder.cff = &cff_rec;
error = cff_decoder_parse_charstrings( &decoder,
charstring_base,
charstring_len,
1 );
/* Now copy the stack data in the temporary decoder object, */
/* converting it back to charstring number representations */
/* (this is ugly, I know). */
/* */
/* We overwrite the original top DICT charstring under the */
/* assumption that the charstring representation of the result */
/* of `cff_decoder_parse_charstrings' is shorter, which should */
/* be always true. */
q = charstring_base - 1;
stack = decoder.stack;
while ( stack < decoder.top )
{
FT_ULong num;
FT_Bool neg;
if ( parser->top - parser->stack >= CFF_MAX_STACK_DEPTH )
goto Stack_Overflow;
*parser->top++ = q;
if ( *stack < 0 )
{
num = (FT_ULong)-*stack;
neg = 1;
}
else
{
num = (FT_ULong)*stack;
neg = 0;
}
if ( num & 0xFFFFU )
{
if ( neg )
num = (FT_ULong)-num;
*q++ = 255;
*q++ = ( num & 0xFF000000U ) >> 24;
*q++ = ( num & 0x00FF0000U ) >> 16;
*q++ = ( num & 0x0000FF00U ) >> 8;
*q++ = num & 0x000000FFU;
}
else
{
num >>= 16;
if ( neg )
{
if ( num <= 107 )
*q++ = (FT_Byte)( 139 - num );
else if ( num <= 1131 )
{
*q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 251 );
*q++ = (FT_Byte)( ( num - 108 ) & 0xFF );
}
else
{
num = (FT_ULong)-num;
*q++ = 28;
*q++ = (FT_Byte)( num >> 8 );
*q++ = (FT_Byte)( num & 0xFF );
}
}
else
{
if ( num <= 107 )
*q++ = (FT_Byte)( num + 139 );
else if ( num <= 1131 )
{
*q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 247 );
*q++ = (FT_Byte)( ( num - 108 ) & 0xFF );
}
else
{
*q++ = 28;
*q++ = (FT_Byte)( num >> 8 );
*q++ = (FT_Byte)( num & 0xFF );
}
}
}
stack++;
}
}
else
{
/* This is not a number, hence it's an operator. Compute its code */

View File

@ -47,6 +47,8 @@ FT_BEGIN_HEADER
FT_UInt object_code;
void* object;
FT_UShort num_designs; /* a copy of `CFF_FontRecDict->num_designs' */
} CFF_ParserRec, *CFF_Parser;
@ -54,7 +56,8 @@ FT_BEGIN_HEADER
cff_parser_init( CFF_Parser parser,
FT_UInt code,
void* object,
FT_Library library);
FT_Library library,
FT_UShort num_designs );
FT_LOCAL( FT_Error )
cff_parser_run( CFF_Parser parser,

View File

@ -38,6 +38,9 @@
CFF_FIELD_NUM ( 13, unique_id, "UniqueID" )
CFF_FIELD_CALLBACK( 5, font_bbox, "FontBBox" )
CFF_FIELD_NUM ( 0x108, stroke_width, "StrokeWidth" )
#if 0
CFF_FIELD_DELTA ( 14, xuid, 16, "XUID" )
#endif
CFF_FIELD_NUM ( 15, charset_offset, "charset" )
CFF_FIELD_NUM ( 16, encoding_offset, "Encoding" )
CFF_FIELD_NUM ( 17, charstrings_offset, "CharStrings" )
@ -48,8 +51,13 @@
#if 0
CFF_FIELD_STRING ( 0x116, base_font_name, "BaseFontName" )
CFF_FIELD_DELTA ( 0x117, base_font_blend, 16, "BaseFontBlend" )
#endif
/* the next two operators were removed from the Type2 specification */
/* in version 16-March-2000 */
CFF_FIELD_CALLBACK( 0x118, multiple_master, "MultipleMaster" )
CFF_FIELD_CALLBACK( 0x119, blend_axis_types, "BlendAxisTypes" )
#if 0
CFF_FIELD_CALLBACK( 0x11A, blend_axis_types, "BlendAxisTypes" )
#endif
CFF_FIELD_CALLBACK( 0x11E, cid_ros, "ROS" )

View File

@ -145,6 +145,11 @@ FT_BEGIN_HEADER
FT_ULong cid_fd_select_offset;
FT_UInt cid_font_name;
/* the next field comes from the data of the deprecated */
/* `MultipleMaster' operator; it is needed to parse the (also */
/* deprecated) `blend' operator in Type 2 charstrings */
FT_UShort num_designs;
} CFF_FontRecDictRec, *CFF_FontRecDict;

View File

@ -949,6 +949,10 @@
instance_size * num_instances > fvar_len )
num_instances = 0;
/* we don't support Multiple Master CFFs yet */
if ( !face->goto_table( face, TTAG_CFF, stream, 0 ) )
num_instances = 0;
/* we support at most 2^15 - 1 instances */
if ( num_instances >= ( 1U << 15 ) - 1 )
{