ref: 9f62d2ca061e23948fad738830f4d274abfe75e9
parent: 3bd79cc257499f1850a1bace21f3ae371e3b40f0
author: Dave Arnold <[email protected]>
date: Thu Dec 15 15:27:47 EST 2016
[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.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,55 @@
+2016-12-15 Dave Arnold <[email protected]>
+ Werner Lemberg <[email protected]>
+
+ [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 <[email protected]>
Dave Arnold <[email protected]>
--- a/include/freetype/internal/tttypes.h
+++ b/include/freetype/internal/tttypes.h
@@ -1419,6 +1419,8 @@
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;
--- a/src/cff/cf2font.c
+++ b/src/cff/cf2font.c
@@ -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 */
}
--- a/src/cff/cf2font.h
+++ b/src/cff/cf2font.h
@@ -63,6 +63,7 @@
FT_Memory memory;
FT_Error error; /* shared error for this instance */
+ FT_Bool isCFF2;
CF2_RenderingFlags renderingFlags;
/* variables that depend on Transform: */
--- a/src/cff/cf2ft.c
+++ b/src/cff/cf2ft.c
@@ -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;
@@ -410,6 +413,16 @@
FT_ASSERT( decoder && decoder->current_subfont );
return decoder->current_subfont;
+ }
+
+
+ /* 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;
}
--- a/src/cff/cf2ft.h
+++ b/src/cff/cf2ft.h
@@ -65,6 +65,10 @@
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 )
--- a/src/cff/cf2intrp.c
+++ b/src/cff/cf2intrp.c
@@ -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,6 +568,7 @@
{
/* 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
@@ -567,8 +575,16 @@
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:
+ default:
{
- CF2_F16Dot16 arg1;
- CF2_F16Dot16 arg2;
+ 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 )
+ {
+ case cf2_escDOTSECTION:
+ /* something about `flip type of locking' -- ignore it */
+ FT_TRACE4(( " dotsection\n" ));
- FT_TRACE4(( " and\n" ));
+ break;
- arg2 = cf2_stack_popFixed( opStack );
- arg1 = cf2_stack_popFixed( opStack );
+ case cf2_escAND:
+ {
+ CF2_F16Dot16 arg1;
+ CF2_F16Dot16 arg2;
- cf2_stack_pushInt( opStack, arg1 && arg2 );
- }
- continue; /* do not clear the stack */
- case cf2_escOR:
- {
- CF2_F16Dot16 arg1;
- CF2_F16Dot16 arg2;
+ FT_TRACE4(( " and\n" ));
+ arg2 = cf2_stack_popFixed( opStack );
+ arg1 = cf2_stack_popFixed( opStack );
- FT_TRACE4(( " or\n" ));
+ cf2_stack_pushInt( opStack, arg1 && arg2 );
+ }
+ continue; /* do not clear the stack */
- arg2 = cf2_stack_popFixed( opStack );
- arg1 = cf2_stack_popFixed( opStack );
+ case cf2_escOR:
+ {
+ CF2_F16Dot16 arg1;
+ CF2_F16Dot16 arg2;
- cf2_stack_pushInt( opStack, arg1 || arg2 );
- }
- continue; /* do not clear the stack */
- case cf2_escNOT:
- {
- CF2_F16Dot16 arg;
+ FT_TRACE4(( " or\n" ));
+ arg2 = cf2_stack_popFixed( opStack );
+ arg1 = cf2_stack_popFixed( opStack );
- FT_TRACE4(( " not\n" ));
+ cf2_stack_pushInt( opStack, arg1 || arg2 );
+ }
+ continue; /* do not clear the stack */
- arg = cf2_stack_popFixed( opStack );
+ case cf2_escNOT:
+ {
+ CF2_F16Dot16 arg;
- cf2_stack_pushInt( opStack, !arg );
- }
- continue; /* do not clear the stack */
- case cf2_escABS:
- {
- CF2_F16Dot16 arg;
+ FT_TRACE4(( " not\n" ));
+ arg = cf2_stack_popFixed( opStack );
- FT_TRACE4(( " abs\n" ));
+ cf2_stack_pushInt( opStack, !arg );
+ }
+ continue; /* do not clear the stack */
- arg = cf2_stack_popFixed( opStack );
+ case cf2_escABS:
+ {
+ CF2_F16Dot16 arg;
- cf2_stack_pushFixed( opStack, FT_ABS( arg ) );
- }
- continue; /* do not clear the stack */
- case cf2_escADD:
- {
- CF2_F16Dot16 summand1;
- CF2_F16Dot16 summand2;
+ FT_TRACE4(( " abs\n" ));
+ arg = cf2_stack_popFixed( opStack );
- FT_TRACE4(( " add\n" ));
+ cf2_stack_pushFixed( opStack, FT_ABS( arg ) );
+ }
+ continue; /* do not clear the stack */
- summand2 = cf2_stack_popFixed( opStack );
- summand1 = cf2_stack_popFixed( opStack );
+ case cf2_escADD:
+ {
+ CF2_F16Dot16 summand1;
+ CF2_F16Dot16 summand2;
- cf2_stack_pushFixed( opStack, summand1 + summand2 );
- }
- continue; /* do not clear the stack */
- case cf2_escSUB:
- {
- CF2_F16Dot16 minuend;
- CF2_F16Dot16 subtrahend;
+ FT_TRACE4(( " add\n" ));
+ summand2 = cf2_stack_popFixed( opStack );
+ summand1 = cf2_stack_popFixed( opStack );
- FT_TRACE4(( " sub\n" ));
+ cf2_stack_pushFixed( opStack, summand1 + summand2 );
+ }
+ continue; /* do not clear the stack */
- subtrahend = cf2_stack_popFixed( opStack );
- minuend = cf2_stack_popFixed( opStack );
+ case cf2_escSUB:
+ {
+ CF2_F16Dot16 minuend;
+ CF2_F16Dot16 subtrahend;
- cf2_stack_pushFixed( opStack, minuend - subtrahend );
- }
- continue; /* do not clear the stack */
- case cf2_escDIV:
- {
- CF2_F16Dot16 dividend;
- CF2_F16Dot16 divisor;
+ FT_TRACE4(( " sub\n" ));
+ subtrahend = cf2_stack_popFixed( opStack );
+ minuend = cf2_stack_popFixed( opStack );
- FT_TRACE4(( " div\n" ));
+ cf2_stack_pushFixed( opStack, minuend - subtrahend );
+ }
+ continue; /* do not clear the stack */
- divisor = cf2_stack_popFixed( opStack );
- dividend = cf2_stack_popFixed( opStack );
+ case cf2_escDIV:
+ {
+ CF2_F16Dot16 dividend;
+ CF2_F16Dot16 divisor;
- cf2_stack_pushFixed( opStack, FT_DivFix( dividend, divisor ) );
- }
- continue; /* do not clear the stack */
- case cf2_escNEG:
- {
- CF2_F16Dot16 arg;
+ FT_TRACE4(( " div\n" ));
+ divisor = cf2_stack_popFixed( opStack );
+ dividend = cf2_stack_popFixed( opStack );
- FT_TRACE4(( " neg\n" ));
+ cf2_stack_pushFixed( opStack, FT_DivFix( dividend, divisor ) );
+ }
+ continue; /* do not clear the stack */
- arg = cf2_stack_popFixed( opStack );
+ case cf2_escNEG:
+ {
+ CF2_F16Dot16 arg;
- cf2_stack_pushFixed( opStack, -arg );
- }
- continue; /* do not clear the stack */
- case cf2_escEQ:
- {
- CF2_F16Dot16 arg1;
- CF2_F16Dot16 arg2;
+ FT_TRACE4(( " neg\n" ));
+ arg = cf2_stack_popFixed( opStack );
- FT_TRACE4(( " eq\n" ));
+ cf2_stack_pushFixed( opStack, -arg );
+ }
+ continue; /* do not clear the stack */
- arg2 = cf2_stack_popFixed( opStack );
- arg1 = cf2_stack_popFixed( opStack );
+ case cf2_escEQ:
+ {
+ CF2_F16Dot16 arg1;
+ CF2_F16Dot16 arg2;
- cf2_stack_pushInt( opStack, arg1 == arg2 );
- }
- continue; /* do not clear the stack */
- case cf2_escDROP:
- FT_TRACE4(( " drop\n" ));
+ FT_TRACE4(( " eq\n" ));
- (void)cf2_stack_popFixed( opStack );
- continue; /* do not clear the stack */
+ arg2 = cf2_stack_popFixed( opStack );
+ arg1 = cf2_stack_popFixed( opStack );
- case cf2_escPUT:
- {
- CF2_F16Dot16 val;
- CF2_Int idx;
+ cf2_stack_pushInt( opStack, arg1 == arg2 );
+ }
+ continue; /* do not clear the stack */
+ case cf2_escDROP:
+ FT_TRACE4(( " drop\n" ));
- FT_TRACE4(( " put\n" ));
+ (void)cf2_stack_popFixed( opStack );
+ continue; /* do not clear the stack */
- idx = cf2_stack_popInt( opStack );
- val = cf2_stack_popFixed( opStack );
+ case cf2_escPUT:
+ {
+ CF2_F16Dot16 val;
+ CF2_Int idx;
- if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
- storage[idx] = val;
- }
- continue; /* do not clear the stack */
- case cf2_escGET:
- {
- CF2_Int idx;
+ FT_TRACE4(( " put\n" ));
+ idx = cf2_stack_popInt( opStack );
+ val = cf2_stack_popFixed( opStack );
- FT_TRACE4(( " get\n" ));
+ if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
+ storage[idx] = val;
+ }
+ continue; /* do not clear the stack */
- idx = cf2_stack_popInt( opStack );
+ case cf2_escGET:
+ {
+ CF2_Int idx;
- 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(( " get\n" ));
+ idx = cf2_stack_popInt( opStack );
- FT_TRACE4(( " ifelse\n" ));
+ if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
+ cf2_stack_pushFixed( opStack, storage[idx] );
+ }
+ continue; /* do not clear the stack */
- cond2 = cf2_stack_popFixed( opStack );
- cond1 = cf2_stack_popFixed( opStack );
- arg2 = cf2_stack_popFixed( opStack );
- arg1 = cf2_stack_popFixed( opStack );
+ case cf2_escIFELSE:
+ {
+ CF2_F16Dot16 arg1;
+ CF2_F16Dot16 arg2;
+ CF2_F16Dot16 cond1;
+ CF2_F16Dot16 cond2;
- cf2_stack_pushFixed( opStack, cond1 <= cond2 ? arg1 : arg2 );
- }
- continue; /* do not clear the stack */
- case cf2_escRANDOM: /* in spec */
- FT_TRACE4(( " random\n" ));
+ FT_TRACE4(( " ifelse\n" ));
- CF2_FIXME;
- break;
+ cond2 = cf2_stack_popFixed( opStack );
+ cond1 = cf2_stack_popFixed( opStack );
+ arg2 = cf2_stack_popFixed( opStack );
+ arg1 = cf2_stack_popFixed( opStack );
- case cf2_escMUL:
- {
- CF2_F16Dot16 factor1;
- CF2_F16Dot16 factor2;
+ cf2_stack_pushFixed( opStack, cond1 <= cond2 ? arg1 : arg2 );
+ }
+ continue; /* do not clear the stack */
+ case cf2_escRANDOM: /* in spec */
+ FT_TRACE4(( " random\n" ));
- FT_TRACE4(( " mul\n" ));
+ CF2_FIXME;
+ break;
- factor2 = cf2_stack_popFixed( opStack );
- factor1 = cf2_stack_popFixed( opStack );
+ case cf2_escMUL:
+ {
+ CF2_F16Dot16 factor1;
+ CF2_F16Dot16 factor2;
- cf2_stack_pushFixed( opStack, FT_MulFix( factor1, factor2 ) );
- }
- continue; /* do not clear the stack */
- case cf2_escSQRT:
- {
- CF2_F16Dot16 arg;
+ FT_TRACE4(( " mul\n" ));
+ factor2 = cf2_stack_popFixed( opStack );
+ factor1 = cf2_stack_popFixed( opStack );
- FT_TRACE4(( " sqrt\n" ));
+ cf2_stack_pushFixed( opStack, FT_MulFix( factor1, factor2 ) );
+ }
+ continue; /* do not clear the stack */
- arg = cf2_stack_popFixed( opStack );
- if ( arg > 0 )
- {
- FT_Fixed root = arg;
- FT_Fixed new_root;
+ case cf2_escSQRT:
+ {
+ CF2_F16Dot16 arg;
- /* 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;
+ FT_TRACE4(( " sqrt\n" ));
- cf2_stack_pushFixed( opStack, arg );
- }
- continue; /* do not clear the stack */
+ arg = cf2_stack_popFixed( opStack );
+ if ( arg > 0 )
+ {
+ FT_Fixed root = arg;
+ FT_Fixed new_root;
- case cf2_escDUP:
- {
- CF2_F16Dot16 arg;
+ /* 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;
- FT_TRACE4(( " dup\n" ));
+ cf2_stack_pushFixed( opStack, arg );
+ }
+ continue; /* do not clear the stack */
- arg = cf2_stack_popFixed( opStack );
+ case cf2_escDUP:
+ {
+ CF2_F16Dot16 arg;
- 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(( " dup\n" ));
+ arg = cf2_stack_popFixed( opStack );
- FT_TRACE4(( " exch\n" ));
+ cf2_stack_pushFixed( opStack, arg );
+ cf2_stack_pushFixed( opStack, arg );
+ }
+ continue; /* do not clear the stack */
- arg2 = cf2_stack_popFixed( opStack );
- arg1 = cf2_stack_popFixed( opStack );
+ case cf2_escEXCH:
+ {
+ CF2_F16Dot16 arg1;
+ CF2_F16Dot16 arg2;
- 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(( " exch\n" ));
+ arg2 = cf2_stack_popFixed( opStack );
+ arg1 = cf2_stack_popFixed( opStack );
- FT_TRACE4(( " index\n" ));
+ cf2_stack_pushFixed( opStack, arg2 );
+ cf2_stack_pushFixed( opStack, arg1 );
+ }
+ continue; /* do not clear the stack */
- idx = cf2_stack_popInt( opStack );
- size = cf2_stack_count( opStack );
+ case cf2_escINDEX:
+ {
+ CF2_Int idx;
+ CF2_UInt size;
- if ( size > 0 )
- {
- /* for `cf2_stack_getReal', index 0 is bottom of stack */
- CF2_UInt gr_idx;
+ FT_TRACE4(( " index\n" ));
- if ( idx < 0 )
- gr_idx = size - 1;
- else if ( (CF2_UInt)idx >= size )
- gr_idx = 0;
- else
- gr_idx = size - 1 - (CF2_UInt)idx;
+ idx = cf2_stack_popInt( opStack );
+ size = cf2_stack_count( opStack );
- cf2_stack_pushFixed( opStack,
- cf2_stack_getReal( opStack, gr_idx ) );
- }
- }
- continue; /* do not clear the stack */
+ if ( size > 0 )
+ {
+ /* for `cf2_stack_getReal', index 0 is bottom of stack */
+ CF2_UInt gr_idx;
- case cf2_escROLL:
- {
- CF2_Int idx;
- CF2_Int count;
+ if ( idx < 0 )
+ gr_idx = size - 1;
+ else if ( (CF2_UInt)idx >= size )
+ gr_idx = 0;
+ else
+ gr_idx = size - 1 - (CF2_UInt)idx;
- FT_TRACE4(( " roll\n" ));
+ cf2_stack_pushFixed( opStack,
+ cf2_stack_getReal( opStack, gr_idx ) );
+ }
+ }
+ continue; /* do not clear the stack */
- idx = cf2_stack_popInt( opStack );
- count = cf2_stack_popInt( opStack );
+ case cf2_escROLL:
+ {
+ CF2_Int idx;
+ CF2_Int count;
- cf2_stack_roll( opStack, count, idx );
- }
- continue; /* do not clear the stack */
- default:
- FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
+ FT_TRACE4(( " roll\n" ));
- }; /* end of switch statement checking `op2' */
+ 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 */
@@ -1759,6 +1789,9 @@
exit:
/* 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 );
--- a/src/cff/cffdrivr.c
+++ b/src/cff/cffdrivr.c
@@ -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:"
@@ -335,6 +364,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 )
--- a/src/cff/cffload.c
+++ b/src/cff/cffload.c
@@ -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,11 +228,12 @@
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 );
@@ -236,9 +240,22 @@
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,7 +606,7 @@
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;
@@ -596,6 +613,11 @@
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,6 +1423,12 @@
}
+ /* 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,
@@ -1399,6 +1435,7 @@
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,7 +1486,24 @@
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" ));
@@ -1451,7 +1510,11 @@
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,7 +1573,8 @@
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[] =
{
@@ -1513,11 +1581,10 @@
#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,6 +1605,7 @@
font->library = library;
font->stream = stream;
font->memory = memory;
+ font->cff2 = cff2;
font->base_offset = base_offset;
/* read CFF font header */
@@ -1544,35 +1612,74 @@
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;
if ( pure_cff )
@@ -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++ )
--- a/src/cff/cffload.h
+++ b/src/cff/cffload.h
@@ -60,11 +60,12 @@
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 );
--- a/src/cff/cffobjs.c
+++ b/src/cff/cffobjs.c
@@ -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;
--- a/src/cff/cffparse.c
+++ b/src/cff/cffparse.c
@@ -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 ) \
@@ -833,9 +862,6 @@
CFF_FIELD( code, name, id, cff_kind_string )
#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
--- a/src/cff/cffparse.h
+++ b/src/cff/cffparse.h
@@ -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_
--- a/src/cff/cfftoken.h
+++ b/src/cff/cfftoken.h
@@ -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" )
@@ -100,6 +100,48 @@
CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" )
CFF_FIELD_NUM ( 20, default_width, "defaultWidthX" )
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 */
--- a/src/cff/cfftypes.h
+++ b/src/cff/cfftypes.h
@@ -64,6 +64,7 @@
{
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_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_Pos default_width;
FT_Pos nominal_width;
+ /* fields for CFF2 */
+ CFF_SubFont subfont;
+
} CFF_PrivateRec, *CFF_Private;
@@ -213,10 +224,11 @@
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_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_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;
--- a/src/sfnt/sfobjs.c
+++ b/src/sfnt/sfobjs.c
@@ -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;
@@ -1353,6 +1355,9 @@
if ( tt_face_lookup_table( face, TTAG_glyf ) != 0 &&
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