[cff] Implement CFF2 support (1/2).

This commit does not contain the blend code for font variation
support, which follows in another commit.

You should ignore whitespace while inspecting this commit.

* include/freetype/internal/tttypes.h (TT_Face): Add `isCFF2'
member.

* src/cff/cf2font.h (CF2_Font): Add `isCFF2' member.

* src/cff/cf2ft.c (cf2_decoder_parse_charstrings): Handle `isCFF2'
flag.
(cf2_getMaxstack): New function.
* src/cff/cf2ft.h: Updated.

* src/cff/cf2intrp.c (cf2_escRESERVED_38): New enum.
(cf2_interpT2CharString): Handle CFF2 differences.
Add tracing message for errors.

* src/cff/cffdrivr.c (cff_get_glyph_name, cff_get_name_index):
Update for CFF2.

* src/cff/cffload.c (FT_FIXED_ONE): New macro.
(cff_index_init, cff_index_load_offsets, cff_index_access_element,
cff_index_get_name, cff_ft_select_get, cff_load_private_dict,
cff_subfont_load, cff_font_load): Handle CFF2.
* src/cff/cffload.h: Updated.

* src/cff/cffobjs.c (cff_face_init): Handle CFF2.

* src/cff/cffparse.c (cff_parse_maxstack): New function.
(CFFCODE_TOPDICT, CFFCODE_PRIVATE): Removed
* src/cff/cffparse.h (CFF2_MAX_STACK, CFF2_DEFAULT_STACK): New
macros.
(CFF2_CODE_TOPDICT, CFF2_CODE_FONTDICT, CFF2_CODE_PRIVATE): New
macros.

* src/cff/cfftoken.h: Add fields for CFF2 dictionaries (but no blend
stuff).

* src/cff/cfftypes.h (CFF_Index): Add `hdr_size' field.
(CFF_FontRecDict): Add `maxstack' field.
(CFF_Private): Add `subfont' field.
(CFF_Font): Add `top_dict_length' and `cff2' fields.

* src/sfnt/sfobjs.c (sfnt_load_face): Handle `CFF2' table.
This commit is contained in:
Dave Arnold 2016-12-15 20:27:47 +01:00 committed by Werner Lemberg
parent 3bd79cc257
commit 9f62d2ca06
16 changed files with 792 additions and 405 deletions

View File

@ -1,3 +1,55 @@
2016-12-15 Dave Arnold <darnold@adobe.com>
Werner Lemberg <wl@gnu.org>
[cff] Implement CFF2 support (1/2).
This commit does not contain the blend code for font variation
support, which follows in another commit.
You should ignore whitespace while inspecting this commit.
* include/freetype/internal/tttypes.h (TT_Face): Add `isCFF2'
member.
* src/cff/cf2font.h (CF2_Font): Add `isCFF2' member.
* src/cff/cf2ft.c (cf2_decoder_parse_charstrings): Handle `isCFF2'
flag.
(cf2_getMaxstack): New function.
* src/cff/cf2ft.h: Updated.
* src/cff/cf2intrp.c (cf2_escRESERVED_38): New enum.
(cf2_interpT2CharString): Handle CFF2 differences.
Add tracing message for errors.
* src/cff/cffdrivr.c (cff_get_glyph_name, cff_get_name_index):
Update for CFF2.
* src/cff/cffload.c (FT_FIXED_ONE): New macro.
(cff_index_init, cff_index_load_offsets, cff_index_access_element,
cff_index_get_name, cff_ft_select_get, cff_load_private_dict,
cff_subfont_load, cff_font_load): Handle CFF2.
* src/cff/cffload.h: Updated.
* src/cff/cffobjs.c (cff_face_init): Handle CFF2.
* src/cff/cffparse.c (cff_parse_maxstack): New function.
(CFFCODE_TOPDICT, CFFCODE_PRIVATE): Removed
* src/cff/cffparse.h (CFF2_MAX_STACK, CFF2_DEFAULT_STACK): New
macros.
(CFF2_CODE_TOPDICT, CFF2_CODE_FONTDICT, CFF2_CODE_PRIVATE): New
macros.
* src/cff/cfftoken.h: Add fields for CFF2 dictionaries (but no blend
stuff).
* src/cff/cfftypes.h (CFF_Index): Add `hdr_size' field.
(CFF_FontRecDict): Add `maxstack' field.
(CFF_Private): Add `subfont' field.
(CFF_Font): Add `top_dict_length' and `cff2' fields.
* src/sfnt/sfobjs.c (sfnt_load_face): Handle `CFF2' table.
2016-12-15 Werner Lemberg <wl@gnu.org>
Dave Arnold <darnold@adobe.com>

View File

@ -1419,6 +1419,8 @@ FT_BEGIN_HEADER
FT_ULong glyf_len;
FT_ULong glyf_offset; /* since 2.7.1 */
FT_Bool isCFF2; /* since 2.7.1 */
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
FT_Bool doblend;
GX_Blend blend;

View File

@ -234,7 +234,8 @@
}
/* set up values for the current FontDict and matrix */
/* set up values for the current FontDict and matrix; */
/* called for each glyph to be rendered */
/* caller's transform is adjusted for subpixel positioning */
static void
@ -423,7 +424,8 @@
/* compute blue zones for this instance */
cf2_blues_init( &font->blues, font );
}
} /* needExtraSetup */
}

View File

@ -63,6 +63,7 @@ FT_BEGIN_HEADER
FT_Memory memory;
FT_Error error; /* shared error for this instance */
FT_Bool isCFF2;
CF2_RenderingFlags renderingFlags;
/* variables that depend on Transform: */

View File

@ -366,6 +366,9 @@
&hinted,
&scaled );
/* copy isCFF2 boolean from TT_Face to CF2_Font */
font->isCFF2 = builder->face->isCFF2;
font->renderingFlags = 0;
if ( hinted )
font->renderingFlags |= CF2_FlagsHinted;
@ -413,6 +416,16 @@
}
/* get maxstack value from CFF2 Top DICT */
FT_LOCAL_DEF( FT_UInt )
cf2_getMaxstack( CFF_Decoder* decoder )
{
FT_ASSERT( decoder && decoder->cff );
return decoder->cff->top_font.font_dict.maxstack;
}
/* get `y_ppem' from `CFF_Size' */
FT_LOCAL_DEF( CF2_Fixed )
cf2_getPpemY( CFF_Decoder* decoder )

View File

@ -65,6 +65,10 @@ FT_BEGIN_HEADER
cf2_getSubfont( CFF_Decoder* decoder );
FT_LOCAL( FT_UInt )
cf2_getMaxstack( CFF_Decoder* decoder );
FT_LOCAL( CF2_Fixed )
cf2_getPpemY( CFF_Decoder* decoder );
FT_LOCAL( CF2_Fixed )

View File

@ -273,7 +273,8 @@
cf2_escHFLEX, /* 34 */
cf2_escFLEX, /* 35 */
cf2_escHFLEX1, /* 36 */
cf2_escFLEX1 /* 37 */
cf2_escFLEX1, /* 37 */
cf2_escRESERVED_38 /* 38 & all higher */
};
@ -445,6 +446,7 @@
CF2_Fixed hintOriginY = curY;
CF2_Stack opStack = NULL;
FT_UInt stackSize;
FT_Byte op1; /* first opcode byte */
CF2_F16Dot16 storage[CF2_STORAGE_SIZE]; /* for `put' and `get' */
@ -520,19 +522,24 @@
* If one of the above operators occurs without explicitly specifying
* a width, we assume the default width.
*
* CFF2 charstrings always return the default width (0).
*
*/
haveWidth = FALSE;
haveWidth = font->isCFF2 ? TRUE : FALSE;
*width = cf2_getDefaultWidthX( decoder );
/*
* Note: at this point, all pointers to resources must be NULL
* and all local objects must be initialized.
* There must be no branches to exit: above this point.
* Note: At this point, all pointers to resources must be NULL
* and all local objects must be initialized.
* There must be no branches to `exit:' above this point.
*
*/
/* allocate an operand stack */
opStack = cf2_stack_init( memory, error, CF2_OPERAND_STACK_SIZE );
stackSize = font->isCFF2 ? cf2_getMaxstack( decoder )
: CF2_OPERAND_STACK_SIZE;
opStack = cf2_stack_init( memory, error, stackSize );
if ( !opStack )
{
lastError = FT_THROW( Out_Of_Memory );
@ -561,14 +568,23 @@
{
/* If we've reached the end of the charstring, simulate a */
/* cf2_cmdRETURN or cf2_cmdENDCHAR. */
/* We do this for both CFF and CFF2. */
if ( charstringIndex )
op1 = cf2_cmdRETURN; /* end of buffer for subroutine */
else
op1 = cf2_cmdENDCHAR; /* end of buffer for top level charstring */
}
else
{
op1 = (FT_Byte)cf2_buf_readByte( charstring );
/* Explicit RETURN and ENDCHAR in CFF2 should be ignored. */
/* Note: Trace message will report 0 instead of 11 or 14. */
if ( ( op1 == cf2_cmdRETURN || op1 == cf2_cmdENDCHAR ) &&
font->isCFF2 )
op1 = cf2_cmdRESERVED_0;
}
/* check for errors once per loop */
if ( *error )
goto exit;
@ -830,6 +846,8 @@
FT_Byte op2 = (FT_Byte)cf2_buf_readByte( charstring );
/* first switch for 2-byte operators handles CFF2 */
/* and opcodes that are reserved for both CFF and CFF2 */
switch ( op2 )
{
case cf2_escHFLEX:
@ -928,6 +946,7 @@
}
continue;
/* these opcodes are reserved in both CFF & CFF2 */
case cf2_escRESERVED_1:
case cf2_escRESERVED_2:
case cf2_escRESERVED_6:
@ -944,329 +963,339 @@
FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
break;
case cf2_escDOTSECTION:
/* something about `flip type of locking' -- ignore it */
FT_TRACE4(( " dotsection\n" ));
break;
case cf2_escAND:
{
CF2_F16Dot16 arg1;
CF2_F16Dot16 arg2;
FT_TRACE4(( " and\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_escOR:
{
CF2_F16Dot16 arg1;
CF2_F16Dot16 arg2;
FT_TRACE4(( " or\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_escNOT:
{
CF2_F16Dot16 arg;
FT_TRACE4(( " not\n" ));
arg = cf2_stack_popFixed( opStack );
cf2_stack_pushInt( opStack, !arg );
}
continue; /* do not clear the stack */
case cf2_escABS:
{
CF2_F16Dot16 arg;
FT_TRACE4(( " abs\n" ));
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" ));
(void)cf2_stack_popFixed( opStack );
continue; /* do not clear the stack */
case cf2_escPUT:
{
CF2_F16Dot16 val;
CF2_Int idx;
FT_TRACE4(( " put\n" ));
idx = cf2_stack_popInt( opStack );
val = cf2_stack_popFixed( opStack );
if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
storage[idx] = val;
}
continue; /* do not clear the stack */
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" ));
CF2_FIXME;
break;
case cf2_escMUL:
{
CF2_F16Dot16 factor1;
CF2_F16Dot16 factor2;
FT_TRACE4(( " mul\n" ));
factor2 = cf2_stack_popFixed( opStack );
factor1 = cf2_stack_popFixed( opStack );
cf2_stack_pushFixed( opStack, FT_MulFix( factor1, factor2 ) );
}
continue; /* do not clear the stack */
case cf2_escSQRT:
{
CF2_F16Dot16 arg;
FT_TRACE4(( " sqrt\n" ));
arg = cf2_stack_popFixed( opStack );
if ( arg > 0 )
{
FT_Fixed root = arg;
FT_Fixed new_root;
/* 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_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 */
default:
FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
{
if ( font->isCFF2 || op2 >= cf2_escRESERVED_38 )
FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
else
{
/* second switch for 2-byte operators handles just CFF */
switch ( op2 )
{
}; /* end of switch statement checking `op2' */
case cf2_escDOTSECTION:
/* something about `flip type of locking' -- ignore it */
FT_TRACE4(( " dotsection\n" ));
break;
case cf2_escAND:
{
CF2_F16Dot16 arg1;
CF2_F16Dot16 arg2;
FT_TRACE4(( " and\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_escOR:
{
CF2_F16Dot16 arg1;
CF2_F16Dot16 arg2;
FT_TRACE4(( " or\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_escNOT:
{
CF2_F16Dot16 arg;
FT_TRACE4(( " not\n" ));
arg = cf2_stack_popFixed( opStack );
cf2_stack_pushInt( opStack, !arg );
}
continue; /* do not clear the stack */
case cf2_escABS:
{
CF2_F16Dot16 arg;
FT_TRACE4(( " abs\n" ));
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" ));
(void)cf2_stack_popFixed( opStack );
continue; /* do not clear the stack */
case cf2_escPUT:
{
CF2_F16Dot16 val;
CF2_Int idx;
FT_TRACE4(( " put\n" ));
idx = cf2_stack_popInt( opStack );
val = cf2_stack_popFixed( opStack );
if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
storage[idx] = val;
}
continue; /* do not clear the stack */
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" ));
CF2_FIXME;
break;
case cf2_escMUL:
{
CF2_F16Dot16 factor1;
CF2_F16Dot16 factor2;
FT_TRACE4(( " mul\n" ));
factor2 = cf2_stack_popFixed( opStack );
factor1 = cf2_stack_popFixed( opStack );
cf2_stack_pushFixed( opStack, FT_MulFix( factor1, factor2 ) );
}
continue; /* do not clear the stack */
case cf2_escSQRT:
{
CF2_F16Dot16 arg;
FT_TRACE4(( " sqrt\n" ));
arg = cf2_stack_popFixed( opStack );
if ( arg > 0 )
{
FT_Fixed root = arg;
FT_Fixed new_root;
/* 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_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 */
} /* end of 2nd switch checking op2 */
}
}
} /* end of 1st switch checking op2 */
} /* case cf2_cmdESC */
break;
case cf2_cmdENDCHAR:
@ -1288,7 +1317,8 @@
/* close path if still open */
cf2_glyphpath_closeOpenPath( &glyphPath );
if ( cf2_stack_count( opStack ) > 1 )
/* disable seac for CFF2 (charstring ending with args on stack) */
if ( !font->isCFF2 && cf2_stack_count( opStack ) > 1 )
{
/* must be either 4 or 5 -- */
/* this is a (deprecated) implied `seac' operator */
@ -1760,6 +1790,9 @@
/* check whether last error seen is also the first one */
cf2_setError( error, lastError );
if ( *error )
FT_TRACE4(( "charstring error %d\n", *error ));
/* free resources from objects we've used */
cf2_glyphpath_finalize( &glyphPath );
cf2_arrstack_finalize( &vStemHintArray );

View File

@ -295,6 +295,35 @@
FT_Error error;
/* CFF2 table does not have glyph names; */
/* we need to use `post' table method */
if ( font->version_major == 2 )
{
FT_Library library = FT_FACE_LIBRARY( face );
FT_Module sfnt_module = FT_Get_Module( library, "sfnt" );
FT_Service_GlyphDict service =
(FT_Service_GlyphDict)ft_module_get_service(
sfnt_module,
FT_SERVICE_ID_GLYPH_DICT,
0 );
if ( service && service->get_name )
return service->get_name( FT_FACE( face ),
glyph_index,
buffer,
buffer_max );
else
{
FT_ERROR(( "cff_get_glyph_name:"
" cannot get glyph name from a CFF2 font\n"
" "
" without the `PSNames' module\n" ));
error = FT_THROW( Missing_Module );
goto Exit;
}
}
if ( !font->psnames )
{
FT_ERROR(( "cff_get_glyph_name:"
@ -336,6 +365,31 @@
cff = (CFF_FontRec *)face->extra.data;
charset = &cff->charset;
/* CFF2 table does not have glyph names; */
/* we need to use `post' table method */
if ( cff->version_major == 2 )
{
FT_Library library = FT_FACE_LIBRARY( face );
FT_Module sfnt_module = FT_Get_Module( library, "sfnt" );
FT_Service_GlyphDict service =
(FT_Service_GlyphDict)ft_module_get_service(
sfnt_module,
FT_SERVICE_ID_GLYPH_DICT,
0 );
if ( service && service->name_index )
return service->name_index( FT_FACE( face ), glyph_name );
else
{
FT_ERROR(( "cff_get_name_index:"
" cannot get glyph index from a CFF2 font\n"
" "
" without the `PSNames' module\n" ));
return 0;
}
}
FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS );
if ( !psnames )
return 0;

View File

@ -29,6 +29,9 @@
#include "cfferrs.h"
#define FT_FIXED_ONE ( (FT_Fixed)0x10000 )
#if 1
static const FT_UShort cff_isoadobe_charset[229] =
@ -225,19 +228,33 @@
static FT_Error
cff_index_init( CFF_Index idx,
FT_Stream stream,
FT_Bool load )
FT_Bool load,
FT_Bool cff2 )
{
FT_Error error;
FT_Memory memory = stream->memory;
FT_UShort count;
FT_UInt count;
FT_ZERO( idx );
idx->stream = stream;
idx->start = FT_STREAM_POS();
if ( !FT_READ_USHORT( count ) &&
count > 0 )
if ( cff2 )
{
if ( FT_READ_ULONG( count ) )
goto Exit;
idx->hdr_size = 5;
}
else
{
if ( FT_READ_USHORT( count ) )
goto Exit;
idx->hdr_size = 3;
}
if ( count > 0 )
{
FT_Byte offsize;
FT_ULong size;
@ -258,7 +275,7 @@
idx->off_size = offsize;
size = (FT_ULong)( count + 1 ) * offsize;
idx->data_offset = idx->start + 3 + size;
idx->data_offset = idx->start + idx->hdr_size + size;
if ( FT_STREAM_SKIP( size - offsize ) )
goto Exit;
@ -335,7 +352,7 @@
data_size = (FT_ULong)( idx->count + 1 ) * offsize;
if ( FT_NEW_ARRAY( idx->offsets, idx->count + 1 ) ||
FT_STREAM_SEEK( idx->start + 3 ) ||
FT_STREAM_SEEK( idx->start + idx->hdr_size ) ||
FT_FRAME_ENTER( data_size ) )
goto Exit;
@ -493,7 +510,7 @@
FT_ULong pos = element * idx->off_size;
if ( FT_STREAM_SEEK( idx->start + 3 + pos ) )
if ( FT_STREAM_SEEK( idx->start + idx->hdr_size + pos ) )
goto Exit;
off1 = cff_index_read_offset( idx, &error );
@ -589,13 +606,18 @@
FT_UInt element )
{
CFF_Index idx = &font->name_index;
FT_Memory memory = idx->stream->memory;
FT_Memory memory;
FT_Byte* bytes;
FT_ULong byte_len;
FT_Error error;
FT_String* name = 0;
if ( !idx->stream ) /* CFF2 does not include a name index */
goto Exit;
memory = idx->stream->memory;
error = cff_index_access_element( idx, element, &bytes, &byte_len );
if ( error )
goto Exit;
@ -724,6 +746,10 @@
{
FT_Byte fd = 0;
/* if there is no FDSelect, return zero */
/* Note: CFF2 with just one Font Dict has no FDSelect */
if ( fdselect->data == NULL )
goto Exit;
switch ( fdselect->format )
{
@ -777,6 +803,7 @@
;
}
Exit:
return fd;
}
@ -1356,10 +1383,13 @@
priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L );
priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 );
stackSize = CFF_MAX_STACK_DEPTH + 1;
priv->subfont = subfont;
stackSize = font->cff2 ? font->top_font.font_dict.maxstack
: CFF_MAX_STACK_DEPTH + 1;
if ( cff_parser_init( &parser,
CFF_CODE_PRIVATE,
font->cff2 ? CFF2_CODE_PRIVATE : CFF_CODE_PRIVATE,
priv,
font->library,
stackSize,
@ -1393,12 +1423,19 @@
}
/* There are 3 ways to call this function, distinguished by code. */
/* */
/* . CFF_CODE_TOPDICT for either a CFF Top DICT or a CFF Font DICT */
/* . CFF2_CODE_TOPDICT for CFF2 Top DICT */
/* . CFF2_CODE_FONTDICT for CFF2 Font DICT */
static FT_Error
cff_subfont_load( CFF_SubFont subfont,
CFF_Index idx,
FT_UInt font_index,
FT_Stream stream,
FT_ULong base_offset,
FT_UInt code,
CFF_Font font )
{
FT_Error error;
@ -1408,11 +1445,16 @@
CFF_FontRecDict top = &subfont->font_dict;
CFF_Private priv = &subfont->private_dict;
FT_UInt stackSize = CFF_MAX_STACK_DEPTH;
FT_Bool cff2 = ( code == CFF2_CODE_TOPDICT ||
code == CFF2_CODE_FONTDICT );
FT_UInt stackSize = cff2 ? CFF2_DEFAULT_STACK
: CFF_MAX_STACK_DEPTH;
/* Note: We use default stack size for CFF2 Font DICT because */
/* Top and Font DICTs are not allowed to have blend operators. */
if ( cff_parser_init( &parser,
CFF_CODE_TOPDICT,
code,
&subfont->font_dict,
font->library,
stackSize,
@ -1444,14 +1486,35 @@
top->cid_ordering = 0xFFFFU;
top->cid_font_name = 0xFFFFU;
error = cff_index_access_element( idx, font_index, &dict, &dict_len );
/* set default stack size */
top->maxstack = cff2 ? CFF2_DEFAULT_STACK : 48;
if ( idx->count ) /* count is nonzero for a real index */
error = cff_index_access_element( idx, font_index, &dict, &dict_len );
else
{
/* CFF2 has a fake top dict index; */
/* simulate `cff_index_access_element' */
/* Note: macros implicitly use `stream' and set `error' */
if ( FT_STREAM_SEEK( idx->data_offset ) ||
FT_FRAME_EXTRACT( idx->data_size, dict ) )
goto Exit;
dict_len = idx->data_size;
}
if ( !error )
{
FT_TRACE4(( " top dictionary:\n" ));
error = cff_parser_run( &parser, dict, dict + dict_len );
}
cff_index_forget_element( idx, &dict );
/* clean up regardless of error */
if ( idx->count )
cff_index_forget_element( idx, &dict );
else
FT_FRAME_RELEASE( dict );
if ( error )
goto Exit;
@ -1460,7 +1523,11 @@
if ( top->cid_registry != 0xFFFFU )
goto Exit;
/* parse the private dictionary, if any */
/* Parse the private dictionary, if any. */
/* */
/* CFF2 does not have a private dictionary in the Top DICT */
/* but may have one in a Font DICT. We need to parse */
/* the latter here in order to load any local subrs. */
error = cff_load_private_dict( font, subfont );
if ( error )
goto Exit;
@ -1472,7 +1539,7 @@
priv->local_subrs_offset ) )
goto Exit;
error = cff_index_init( &subfont->local_subrs_index, stream, 1 );
error = cff_index_init( &subfont->local_subrs_index, stream, 1, cff2 );
if ( error )
goto Exit;
@ -1506,18 +1573,18 @@
FT_Stream stream,
FT_Int face_index,
CFF_Font font,
FT_Bool pure_cff )
FT_Bool pure_cff,
FT_Bool cff2 )
{
static const FT_Frame_Field cff_header_fields[] =
{
#undef FT_STRUCTURE
#define FT_STRUCTURE CFF_FontRec
FT_FRAME_START( 4 ),
FT_FRAME_START( 3 ),
FT_FRAME_BYTE( version_major ),
FT_FRAME_BYTE( version_minor ),
FT_FRAME_BYTE( header_size ),
FT_FRAME_BYTE( absolute_offsize ),
FT_FRAME_END
};
@ -1538,40 +1605,80 @@
font->library = library;
font->stream = stream;
font->memory = memory;
font->cff2 = cff2;
font->base_offset = base_offset;
/* read CFF font header */
if ( FT_STREAM_READ_FIELDS( cff_header_fields, font ) )
goto Exit;
/* check format */
if ( font->version_major != 1 ||
font->header_size < 4 ||
font->absolute_offsize > 4 )
if ( cff2 )
{
FT_TRACE2(( " not a CFF font header\n" ));
error = FT_THROW( Unknown_File_Format );
goto Exit;
if ( font->version_major != 2 ||
font->header_size < 5 )
{
FT_TRACE2(( " not a CFF2 font header\n" ));
error = FT_THROW( Unknown_File_Format );
goto Exit;
}
if ( FT_READ_USHORT( font->top_dict_length ) )
goto Exit;
}
else
{
if ( font->version_major != 1 ||
font->header_size < 4 )
{
FT_TRACE2(( " not a CFF font header\n" ));
error = FT_THROW( Unknown_File_Format );
goto Exit;
}
}
/* skip the rest of the header */
if ( FT_STREAM_SKIP( font->header_size - 4 ) )
if ( FT_STREAM_SEEK( base_offset + font->header_size ) )
goto Exit;
/* read the name, top dict, string and global subrs index */
if ( FT_SET_ERROR( cff_index_init( &font->name_index,
stream, 0 ) ) ||
FT_SET_ERROR( cff_index_init( &font->font_dict_index,
stream, 0 ) ) ||
FT_SET_ERROR( cff_index_init( &string_index,
stream, 1 ) ) ||
FT_SET_ERROR( cff_index_init( &font->global_subrs_index,
stream, 1 ) ) ||
FT_SET_ERROR( cff_index_get_pointers( &string_index,
&font->strings,
&font->string_pool,
&font->string_pool_size ) ) )
goto Exit;
if ( cff2 )
{
/* For CFF2, the top dict data immediately follow the header */
/* and the length is stored in the header `offSize' field; */
/* there is no index for it. */
/* */
/* Use the `font_dict_index' to save the current position */
/* and length of data, but leave count at zero as an indicator. */
FT_ZERO( &font->font_dict_index );
font->font_dict_index.data_offset = FT_STREAM_POS();
font->font_dict_index.data_size = font->top_dict_length;
/* skip the top dict data for now, we will parse it later */
if ( FT_STREAM_SKIP( font->top_dict_length ) )
goto Exit;
/* next, read the global subrs index */
if ( FT_SET_ERROR( cff_index_init( &font->global_subrs_index,
stream, 1, cff2 ) ) )
goto Exit;
}
else
{
/* for CFF, read the name, top dict, string and global subrs index */
if ( FT_SET_ERROR( cff_index_init( &font->name_index,
stream, 0, cff2 ) ) ||
FT_SET_ERROR( cff_index_init( &font->font_dict_index,
stream, 0, cff2 ) ) ||
FT_SET_ERROR( cff_index_init( &string_index,
stream, 1, cff2 ) ) ||
FT_SET_ERROR( cff_index_init( &font->global_subrs_index,
stream, 1, cff2 ) ) ||
FT_SET_ERROR( cff_index_get_pointers( &string_index,
&font->strings,
&font->string_pool,
&font->string_pool_size ) ) )
goto Exit;
}
font->num_strings = string_index.count;
@ -1617,6 +1724,7 @@
subfont_index,
stream,
base_offset,
cff2 ? CFF2_CODE_TOPDICT : CFF_CODE_TOPDICT,
font );
if ( error )
goto Exit;
@ -1624,12 +1732,13 @@
if ( FT_STREAM_SEEK( base_offset + dict->charstrings_offset ) )
goto Exit;
error = cff_index_init( &font->charstrings_index, stream, 0 );
error = cff_index_init( &font->charstrings_index, stream, 0, cff2 );
if ( error )
goto Exit;
/* now, check for a CID font */
if ( dict->cid_registry != 0xFFFFU )
/* now, check for a CID or CFF2 font */
if ( dict->cid_registry != 0xFFFFU ||
cff2 )
{
CFF_IndexRec fd_index;
CFF_SubFont sub = NULL;
@ -1641,10 +1750,12 @@
if ( FT_STREAM_SEEK( base_offset + dict->cid_fd_array_offset ) )
goto Exit;
error = cff_index_init( &fd_index, stream, 0 );
error = cff_index_init( &fd_index, stream, 0, cff2 );
if ( error )
goto Exit;
/* Font Dicts are not limited to 256 for CFF2. */
/* TODO: support this for CFF2 */
if ( fd_index.count > CFF_MAX_CID_FONTS )
{
FT_TRACE0(( "cff_font_load: FD array too large in CID font\n" ));
@ -1670,16 +1781,20 @@
idx,
stream,
base_offset,
cff2 ? CFF2_CODE_FONTDICT
: CFF_CODE_TOPDICT,
font );
if ( error )
goto Fail_CID;
}
/* now load the FD Select array */
error = CFF_Load_FD_Select( &font->fd_select,
font->charstrings_index.count,
stream,
base_offset + dict->cid_fd_select_offset );
/* now load the FD Select array; */
/* CFF2 omits FDSelect if there is only one FD */
if ( !cff2 || fd_index.count > 1 )
error = CFF_Load_FD_Select( &font->fd_select,
font->charstrings_index.count,
stream,
base_offset + dict->cid_fd_select_offset );
Fail_CID:
cff_index_done( &fd_index );
@ -1707,7 +1822,7 @@
goto Exit;
/* read the Charset and Encoding tables if available */
if ( font->num_glyphs > 0 )
if ( !cff2 && font->num_glyphs > 0 )
{
FT_Bool invert = FT_BOOL( dict->cid_registry != 0xFFFFU && pure_cff );
@ -1755,7 +1870,7 @@
cff_index_done( &font->charstrings_index );
/* release font dictionaries, but only if working with */
/* a CID keyed CFF font */
/* a CID keyed CFF font or a CFF2 font */
if ( font->num_subfonts > 0 )
{
for ( idx = 0; idx < font->num_subfonts; idx++ )

View File

@ -60,11 +60,12 @@ FT_BEGIN_HEADER
FT_LOCAL( FT_Error )
cff_font_load( FT_Library library,
FT_Stream stream,
FT_Int face_index,
CFF_Font font,
FT_Bool pure_cff );
cff_font_load( FT_Library library,
FT_Stream stream,
FT_Int face_index,
CFF_Font font,
FT_Bool pure_cff,
FT_Bool cff2 );
FT_LOCAL( void )
cff_font_done( CFF_Font font );

View File

@ -491,6 +491,7 @@
FT_Service_PsCMaps psnames;
PSHinter_Service pshinter;
FT_Bool pure_cff = 1;
FT_Bool cff2 = 0;
FT_Bool sfnt_format = 0;
FT_Library library = cffface->driver->root.library;
@ -553,8 +554,18 @@
goto Exit;
}
/* now load the CFF part of the file */
error = face->goto_table( face, TTAG_CFF, stream, 0 );
/* now load the CFF part of the file; */
/* give priority to CFF2 */
error = face->goto_table( face, TTAG_CFF2, stream, 0 );
if ( !error )
{
cff2 = 1;
face->isCFF2 = cff2;
}
if ( FT_ERR_EQ( error, Table_Missing ) )
error = face->goto_table( face, TTAG_CFF, stream, 0 );
if ( error )
goto Exit;
}
@ -579,7 +590,12 @@
goto Exit;
face->extra.data = cff;
error = cff_font_load( library, stream, face_index, cff, pure_cff );
error = cff_font_load( library,
stream,
face_index,
cff,
pure_cff,
cff2 );
if ( error )
goto Exit;

View File

@ -823,6 +823,35 @@
}
/* maxstack operator increases parser and operand stacks for CFF2 */
static FT_Error
cff_parse_maxstack( CFF_Parser parser )
{
/* maxstack operator can only be used in a Top DICT */
CFF_FontRecDict dict = (CFF_FontRecDict)parser->object;
FT_Byte** data = parser->stack;
FT_Error error = FT_Err_Ok;
if ( !dict )
{
error = FT_THROW( Invalid_File_Format );
goto Exit;
}
dict->maxstack = (FT_UInt)cff_parse_num( parser, data++ );
if ( dict->maxstack > CFF2_MAX_STACK )
dict->maxstack = CFF2_MAX_STACK;
if ( dict->maxstack < CFF2_DEFAULT_STACK )
dict->maxstack = CFF2_DEFAULT_STACK;
FT_TRACE4(( " %d\n", dict->maxstack ));
Exit:
return error;
}
#define CFF_FIELD_NUM( code, name, id ) \
CFF_FIELD( code, name, id, cff_kind_num )
#define CFF_FIELD_FIXED( code, name, id ) \
@ -834,9 +863,6 @@
#define CFF_FIELD_BOOL( code, name, id ) \
CFF_FIELD( code, name, id, cff_kind_bool )
#define CFFCODE_TOPDICT 0x1000
#define CFFCODE_PRIVATE 0x2000
#ifndef FT_CONFIG_OPTION_PIC

View File

@ -28,10 +28,17 @@
FT_BEGIN_HEADER
/* CFF uses constant parser stack size; */
/* CFF2 can increase from default 193 */
#define CFF_MAX_STACK_DEPTH 96
#define CFF2_MAX_STACK 513
#define CFF2_DEFAULT_STACK 193
#define CFF_CODE_TOPDICT 0x1000
#define CFF_CODE_PRIVATE 0x2000
#define CFF_CODE_TOPDICT 0x1000
#define CFF_CODE_PRIVATE 0x2000
#define CFF2_CODE_TOPDICT 0x3000
#define CFF2_CODE_FONTDICT 0x4000
#define CFF2_CODE_PRIVATE 0x5000
typedef struct CFF_ParserRec_

View File

@ -20,7 +20,7 @@
#define FT_STRUCTURE CFF_FontRecDictRec
#undef CFFCODE
#define CFFCODE CFFCODE_TOPDICT
#define CFFCODE CFF_CODE_TOPDICT
CFF_FIELD_STRING ( 0, version, "Version" )
CFF_FIELD_STRING ( 1, notice, "Notice" )
@ -78,7 +78,7 @@
#undef FT_STRUCTURE
#define FT_STRUCTURE CFF_PrivateRec
#undef CFFCODE
#define CFFCODE CFFCODE_PRIVATE
#define CFFCODE CFF_CODE_PRIVATE
CFF_FIELD_DELTA ( 6, blue_values, 14, "BlueValues" )
CFF_FIELD_DELTA ( 7, other_blues, 10, "OtherBlues" )
@ -102,4 +102,46 @@
CFF_FIELD_NUM ( 21, nominal_width, "nominalWidthX" )
#undef FT_STRUCTURE
#define FT_STRUCTURE CFF_FontRecDictRec
#undef CFFCODE
#define CFFCODE CFF2_CODE_TOPDICT
CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" )
CFF_FIELD_NUM ( 17, charstrings_offset, "CharStrings" )
CFF_FIELD_NUM ( 0x124, cid_fd_array_offset, "FDArray" )
CFF_FIELD_NUM ( 0x125, cid_fd_select_offset, "FDSelect" )
CFF_FIELD_CALLBACK( 25, maxstack, "maxstack" )
#undef FT_STRUCTURE
#define FT_STRUCTURE CFF_FontRecDictRec
#undef CFFCODE
#define CFFCODE CFF2_CODE_FONTDICT
CFF_FIELD_CALLBACK( 18, private_dict, "Private" )
CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" )
#undef FT_STRUCTURE
#define FT_STRUCTURE CFF_PrivateRec
#undef CFFCODE
#define CFFCODE CFF2_CODE_PRIVATE
CFF_FIELD_DELTA ( 6, blue_values, 14, "BlueValues" )
CFF_FIELD_DELTA ( 7, other_blues, 10, "OtherBlues" )
CFF_FIELD_DELTA ( 8, family_blues, 14, "FamilyBlues" )
CFF_FIELD_DELTA ( 9, family_other_blues, 10, "FamilyOtherBlues" )
CFF_FIELD_FIXED_1000( 0x109, blue_scale, "BlueScale" )
CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" )
CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" )
CFF_FIELD_NUM ( 10, standard_width, "StdHW" )
CFF_FIELD_NUM ( 11, standard_height, "StdVW" )
CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" )
CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" )
CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" )
CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" )
CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" )
/* END */

View File

@ -64,6 +64,7 @@ FT_BEGIN_HEADER
{
FT_Stream stream;
FT_ULong start;
FT_UInt hdr_size;
FT_UInt count;
FT_Byte off_size;
FT_ULong data_offset;
@ -151,9 +152,16 @@ FT_BEGIN_HEADER
FT_UShort num_designs;
FT_UShort num_axes;
/* fields for CFF2 */
FT_UInt maxstack;
} CFF_FontRecDictRec, *CFF_FontRecDict;
/* forward reference */
typedef struct CFF_SubFontRec_* CFF_SubFont;
typedef struct CFF_PrivateRec_
{
FT_Byte num_blue_values;
@ -186,6 +194,9 @@ FT_BEGIN_HEADER
FT_Pos default_width;
FT_Pos nominal_width;
/* fields for CFF2 */
CFF_SubFont subfont;
} CFF_PrivateRec, *CFF_Private;
@ -213,10 +224,11 @@ FT_BEGIN_HEADER
CFF_FontRecDictRec font_dict;
CFF_PrivateRec private_dict;
CFF_IndexRec local_subrs_index;
FT_Byte** local_subrs; /* array of pointers into Local Subrs INDEX data */
CFF_IndexRec local_subrs_index;
FT_Byte** local_subrs; /* array of pointers */
/* into Local Subrs INDEX data */
} CFF_SubFontRec, *CFF_SubFont;
} CFF_SubFontRec;
#define CFF_MAX_CID_FONTS 256
@ -226,7 +238,7 @@ FT_BEGIN_HEADER
{
FT_Library library;
FT_Stream stream;
FT_Memory memory;
FT_Memory memory; /* TODO: take this from stream->memory? */
FT_ULong base_offset; /* offset to start of CFF */
FT_UInt num_faces;
FT_UInt num_glyphs;
@ -234,8 +246,10 @@ FT_BEGIN_HEADER
FT_Byte version_major;
FT_Byte version_minor;
FT_Byte header_size;
FT_Byte absolute_offsize;
FT_UInt top_dict_length; /* cff2 only */
FT_Bool cff2;
CFF_IndexRec name_index;
CFF_IndexRec top_dict_index;

View File

@ -1106,12 +1106,14 @@
/* do we have outlines in there? */
#ifdef FT_CONFIG_OPTION_INCREMENTAL
has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 ||
tt_face_lookup_table( face, TTAG_glyf ) != 0 ||
tt_face_lookup_table( face, TTAG_CFF ) != 0 );
has_outline = FT_BOOL( face->root.internal->incremental_interface ||
tt_face_lookup_table( face, TTAG_glyf ) != NULL ||
tt_face_lookup_table( face, TTAG_CFF ) != NULL ||
tt_face_lookup_table( face, TTAG_CFF2 ) != NULL );
#else
has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 ||
tt_face_lookup_table( face, TTAG_CFF ) != 0 );
has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != NULL ||
tt_face_lookup_table( face, TTAG_CFF ) != NULL ||
tt_face_lookup_table( face, TTAG_CFF2 ) != NULL );
#endif
is_apple_sbit = 0;
@ -1354,6 +1356,9 @@
tt_face_lookup_table( face, TTAG_fvar ) != 0 &&
tt_face_lookup_table( face, TTAG_gvar ) != 0 )
flags |= FT_FACE_FLAG_MULTIPLE_MASTERS;
if ( tt_face_lookup_table( face, TTAG_CFF2 ) != 0 &&
tt_face_lookup_table( face, TTAG_fvar ) != 0 )
flags |= FT_FACE_FLAG_MULTIPLE_MASTERS;
#endif
root->face_flags = flags;