[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:
parent
4b3ea5ca8f
commit
813aca51d2
30
ChangeLog
30
ChangeLog
|
@ -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.
|
||||
|
|
|
@ -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_TRACE4(( " blend\n" ));
|
||||
{
|
||||
FT_Int num_results = (FT_Int)( args[0] >> 16 );
|
||||
|
||||
goto Unimplemented;
|
||||
|
||||
FT_TRACE4(( " blend\n" ));
|
||||
|
||||
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
|
||||
{
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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 ) )
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
@ -972,7 +1015,7 @@
|
|||
if ( parser->top - parser->stack >= CFF_MAX_STACK_DEPTH )
|
||||
goto Stack_Overflow;
|
||||
|
||||
*parser->top ++ = p;
|
||||
*parser->top++ = p;
|
||||
|
||||
/* now, skip it */
|
||||
if ( v == 30 )
|
||||
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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" )
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue