forked from minhngoc25a/freetype2
[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:
parent
3bd79cc257
commit
9f62d2ca06
52
ChangeLog
52
ChangeLog
@ -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>
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
}
|
||||
|
||||
|
||||
|
@ -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: */
|
||||
|
@ -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 )
|
||||
|
@ -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 )
|
||||
|
@ -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 );
|
||||
|
@ -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;
|
||||
|
@ -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++ )
|
||||
|
@ -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 );
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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_
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user