diff options
Diffstat (limited to 'third_party/freetype/src/cff')
37 files changed, 3181 insertions, 613 deletions
diff --git a/third_party/freetype/src/cff/cf2arrst.c b/third_party/freetype/src/cff/cf2arrst.c index 89f3e9f1d7..6796450fe1 100644 --- a/third_party/freetype/src/cff/cf2arrst.c +++ b/third_party/freetype/src/cff/cf2arrst.c @@ -58,7 +58,7 @@ FT_Error* error, size_t sizeItem ) { - FT_ASSERT( arrstack != NULL ); + FT_ASSERT( arrstack ); /* initialize the structure */ arrstack->memory = memory; @@ -78,7 +78,7 @@ FT_Memory memory = arrstack->memory; /* for FT_FREE */ - FT_ASSERT( arrstack != NULL ); + FT_ASSERT( arrstack ); arrstack->allocated = 0; arrstack->count = 0; @@ -95,7 +95,7 @@ cf2_arrstack_setNumElements( CF2_ArrStack arrstack, size_t numElements ) { - FT_ASSERT( arrstack != NULL ); + FT_ASSERT( arrstack ); { FT_Error error = FT_Err_Ok; /* for FT_REALLOC */ @@ -140,7 +140,7 @@ cf2_arrstack_setCount( CF2_ArrStack arrstack, size_t numElements ) { - FT_ASSERT( arrstack != NULL ); + FT_ASSERT( arrstack ); if ( numElements > arrstack->allocated ) { @@ -157,7 +157,7 @@ FT_LOCAL_DEF( void ) cf2_arrstack_clear( CF2_ArrStack arrstack ) { - FT_ASSERT( arrstack != NULL ); + FT_ASSERT( arrstack ); arrstack->count = 0; } @@ -167,7 +167,7 @@ FT_LOCAL_DEF( size_t ) cf2_arrstack_size( const CF2_ArrStack arrstack ) { - FT_ASSERT( arrstack != NULL ); + FT_ASSERT( arrstack ); return arrstack->count; } @@ -176,7 +176,7 @@ FT_LOCAL_DEF( void* ) cf2_arrstack_getBuffer( const CF2_ArrStack arrstack ) { - FT_ASSERT( arrstack != NULL ); + FT_ASSERT( arrstack ); return arrstack->ptr; } @@ -190,7 +190,7 @@ void* newPtr; - FT_ASSERT( arrstack != NULL ); + FT_ASSERT( arrstack ); if ( idx >= arrstack->count ) { @@ -212,7 +212,7 @@ cf2_arrstack_push( CF2_ArrStack arrstack, const void* ptr ) { - FT_ASSERT( arrstack != NULL ); + FT_ASSERT( arrstack ); if ( arrstack->count == arrstack->allocated ) { @@ -225,7 +225,7 @@ } } - FT_ASSERT( ptr != NULL ); + FT_ASSERT( ptr ); { size_t offset = arrstack->count * arrstack->sizeItem; diff --git a/third_party/freetype/src/cff/cf2arrst.h b/third_party/freetype/src/cff/cf2arrst.h index ff5ad8b126..3c21a3b672 100644 --- a/third_party/freetype/src/cff/cf2arrst.h +++ b/third_party/freetype/src/cff/cf2arrst.h @@ -36,8 +36,8 @@ /***************************************************************************/ -#ifndef __CF2ARRST_H__ -#define __CF2ARRST_H__ +#ifndef CF2ARRST_H_ +#define CF2ARRST_H_ #include "cf2error.h" @@ -94,7 +94,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CF2ARRST_H__ */ +#endif /* CF2ARRST_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cf2blues.h b/third_party/freetype/src/cff/cf2blues.h index 2f38fcad8f..96fb60f38d 100644 --- a/third_party/freetype/src/cff/cf2blues.h +++ b/third_party/freetype/src/cff/cf2blues.h @@ -65,8 +65,8 @@ */ -#ifndef __CF2BLUES_H__ -#define __CF2BLUES_H__ +#ifndef CF2BLUES_H_ +#define CF2BLUES_H_ #include "cf2glue.h" @@ -179,7 +179,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CF2BLUES_H__ */ +#endif /* CF2BLUES_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cf2error.c b/third_party/freetype/src/cff/cf2error.c index b5595a3d1f..e3dd69f50d 100644 --- a/third_party/freetype/src/cff/cf2error.c +++ b/third_party/freetype/src/cff/cf2error.c @@ -44,7 +44,7 @@ cf2_setError( FT_Error* error, FT_Error value ) { - if ( error && *error == 0 ) + if ( error && !*error ) *error = value; } diff --git a/third_party/freetype/src/cff/cf2error.h b/third_party/freetype/src/cff/cf2error.h index 6453ebcb7b..512edd1d21 100644 --- a/third_party/freetype/src/cff/cf2error.h +++ b/third_party/freetype/src/cff/cf2error.h @@ -36,13 +36,13 @@ /***************************************************************************/ -#ifndef __CF2ERROR_H__ -#define __CF2ERROR_H__ +#ifndef CF2ERROR_H_ +#define CF2ERROR_H_ #include FT_MODULE_ERRORS_H -#undef __FTERRORS_H__ +#undef FTERRORS_H_ #undef FT_ERR_PREFIX #define FT_ERR_PREFIX CF2_Err_ @@ -70,7 +70,7 @@ FT_BEGIN_HEADER * Upon a function call if the error code is anything other than * `FT_Err_Ok', which is guaranteed to be zero, we * will return without altering that error. This will allow the - * error to propogate and be handled at the appropriate location in + * error to propagate and be handled at the appropriate location in * the code. * * This allows a style of code where the error code is initialized @@ -113,7 +113,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CF2ERROR_H__ */ +#endif /* CF2ERROR_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cf2fixed.h b/third_party/freetype/src/cff/cf2fixed.h index d6d9faf8e5..2e4b5032fa 100644 --- a/third_party/freetype/src/cff/cf2fixed.h +++ b/third_party/freetype/src/cff/cf2fixed.h @@ -36,8 +36,8 @@ /***************************************************************************/ -#ifndef __CF2FIXED_H__ -#define __CF2FIXED_H__ +#ifndef CF2FIXED_H_ +#define CF2FIXED_H_ FT_BEGIN_HEADER @@ -51,8 +51,8 @@ FT_BEGIN_HEADER #define CF2_FIXED_MAX ( (CF2_Fixed)0x7FFFFFFFL ) #define CF2_FIXED_MIN ( (CF2_Fixed)0x80000000L ) -#define CF2_FIXED_ONE 0x10000L -#define CF2_FIXED_EPSILON 0x0001 +#define CF2_FIXED_ONE ( (CF2_Fixed)0x10000L ) +#define CF2_FIXED_EPSILON ( (CF2_Fixed)0x0001 ) /* in C 89, left and right shift of negative numbers is */ /* implementation specific behaviour in the general case */ @@ -89,7 +89,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CF2FIXED_H__ */ +#endif /* CF2FIXED_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cf2font.c b/third_party/freetype/src/cff/cf2font.c index 83fd348f2d..a86e3619b4 100644 --- a/third_party/freetype/src/cff/cf2font.c +++ b/third_party/freetype/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 @@ -246,6 +247,9 @@ FT_Bool needExtraSetup = FALSE; + CFF_VStoreRec* vstore; + FT_Bool hasVariations = FALSE; + /* character space units */ CF2_Fixed boldenX = font->syntheticEmboldeningAmountX; CF2_Fixed boldenY = font->syntheticEmboldeningAmountY; @@ -253,6 +257,9 @@ CFF_SubFont subFont; CF2_Fixed ppem; + CF2_UInt lenNormalizedV = 0; + FT_Fixed* normalizedV = NULL; + /* clear previous error */ font->error = FT_Err_Ok; @@ -266,6 +273,48 @@ needExtraSetup = TRUE; } + /* check for variation vectors */ + vstore = cf2_getVStore( decoder ); + hasVariations = ( vstore->dataCount != 0 ); + + if ( hasVariations ) + { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* check whether Private DICT in this subfont needs to be reparsed */ + font->error = cf2_getNormalizedVector( decoder, + &lenNormalizedV, + &normalizedV ); + if ( font->error ) + return; + + if ( cff_blend_check_vector( &subFont->blend, + subFont->private_dict.vsindex, + lenNormalizedV, + normalizedV ) ) + { + /* blend has changed, reparse */ + cff_load_private_dict( decoder->cff, + subFont, + lenNormalizedV, + normalizedV ); + needExtraSetup = TRUE; + } +#endif + + /* copy from subfont */ + font->blend.font = subFont->blend.font; + + /* clear state of charstring blend */ + font->blend.usedBV = FALSE; + + /* initialize value for charstring */ + font->vsindex = subFont->private_dict.vsindex; + + /* store vector inputs for blends in charstring */ + font->lenNDV = lenNormalizedV; + font->NDV = normalizedV; + } + /* if ppem has changed, we need to recompute some cached data */ /* note: because of CID font matrix concatenation, ppem and transform */ /* do not necessarily track. */ @@ -423,7 +472,8 @@ /* compute blue zones for this instance */ cf2_blues_init( &font->blues, font ); - } + + } /* needExtraSetup */ } diff --git a/third_party/freetype/src/cff/cf2font.h b/third_party/freetype/src/cff/cf2font.h index 86cf02f49d..17ecd17bbb 100644 --- a/third_party/freetype/src/cff/cf2font.h +++ b/third_party/freetype/src/cff/cf2font.h @@ -36,12 +36,13 @@ /***************************************************************************/ -#ifndef __CF2FONT_H__ -#define __CF2FONT_H__ +#ifndef CF2FONT_H_ +#define CF2FONT_H_ #include "cf2ft.h" #include "cf2blues.h" +#include "cffload.h" FT_BEGIN_HEADER @@ -54,6 +55,7 @@ FT_BEGIN_HEADER /* (Hiragino Kaku Gothic ProN W3; */ /* 8.2d6e1; 2014-12-19) that exceed */ /* this limit */ +#define CF2_STORAGE_SIZE 32 /* typedef is in `cf2glue.h' */ @@ -62,6 +64,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: */ @@ -73,6 +76,12 @@ FT_BEGIN_HEADER CF2_Matrix outerTransform; /* post hinting; includes rotations */ CF2_Fixed ppem; /* transform-dependent */ + /* variation data */ + CFF_BlendRec blend; /* cached charstring blend vector */ + CF2_UInt vsindex; /* current vsindex */ + CF2_UInt lenNDV; /* current length NDV or zero */ + FT_Fixed* NDV; /* ptr to current NDV or NULL */ + CF2_Int unitsPerEm; CF2_Fixed syntheticEmboldeningAmountX; /* character space units */ @@ -115,7 +124,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CF2FONT_H__ */ +#endif /* CF2FONT_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cf2ft.c b/third_party/freetype/src/cff/cf2ft.c index d2544a2345..c0d067e94e 100644 --- a/third_party/freetype/src/cff/cf2ft.c +++ b/third_party/freetype/src/cff/cf2ft.c @@ -104,7 +104,8 @@ FT_Memory memory = font->memory; - (void)memory; + FT_FREE( font->blend.lastNDV ); + FT_FREE( font->blend.BV ); } } @@ -239,7 +240,7 @@ FT_Memory memory, FT_Error* error ) { - FT_MEM_ZERO( outline, sizeof ( CF2_OutlineRec ) ); + FT_ZERO( outline ); outline->root.memory = memory; outline->root.error = error; @@ -311,7 +312,7 @@ font = (CF2_Font)decoder->cff->cf2_instance.data; /* on first glyph, allocate instance structure */ - if ( decoder->cff->cf2_instance.data == NULL ) + if ( !decoder->cff->cf2_instance.data ) { decoder->cff->cf2_instance.finalizer = (FT_Generic_Finalizer)cf2_free_instance; @@ -366,6 +367,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 +417,44 @@ } + /* get pointer to VStore structure */ + FT_LOCAL_DEF( CFF_VStore ) + cf2_getVStore( CFF_Decoder* decoder ) + { + FT_ASSERT( decoder && decoder->cff ); + + return &decoder->cff->vstore; + } + + + /* 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; + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* Get normalized design vector for current render request; */ + /* return pointer and length. */ + /* */ + /* Note: Uses FT_Fixed not CF2_Fixed for the vector. */ + FT_LOCAL_DEF( FT_Error ) + cf2_getNormalizedVector( CFF_Decoder* decoder, + CF2_UInt *len, + FT_Fixed* *vec ) + { + FT_ASSERT( decoder && decoder->builder.face ); + FT_ASSERT( vec && len ); + + return cff_get_var_blend( decoder->builder.face, len, vec, NULL ); + } +#endif + + /* get `y_ppem' from `CFF_Size' */ FT_LOCAL_DEF( CF2_Fixed ) cf2_getPpemY( CFF_Decoder* decoder ) @@ -544,14 +586,17 @@ /* return 0 on success */ FT_LOCAL_DEF( CF2_Int ) cf2_initGlobalRegionBuffer( CFF_Decoder* decoder, - CF2_UInt idx, + CF2_Int subrNum, CF2_Buffer buf ) { + CF2_UInt idx; + + FT_ASSERT( decoder ); FT_ZERO( buf ); - idx += (CF2_UInt)decoder->globals_bias; + idx = (CF2_UInt)( subrNum + decoder->globals_bias ); if ( idx >= decoder->num_globals ) return TRUE; /* error */ @@ -628,14 +673,17 @@ FT_LOCAL_DEF( CF2_Int ) cf2_initLocalRegionBuffer( CFF_Decoder* decoder, - CF2_UInt idx, + CF2_Int subrNum, CF2_Buffer buf ) { + CF2_UInt idx; + + FT_ASSERT( decoder ); FT_ZERO( buf ); - idx += (CF2_UInt)decoder->locals_bias; + idx = (CF2_UInt)( subrNum + decoder->locals_bias ); if ( idx >= decoder->num_locals ) return TRUE; /* error */ diff --git a/third_party/freetype/src/cff/cf2ft.h b/third_party/freetype/src/cff/cf2ft.h index 3073df382f..b054a6e950 100644 --- a/third_party/freetype/src/cff/cf2ft.h +++ b/third_party/freetype/src/cff/cf2ft.h @@ -36,8 +36,8 @@ /***************************************************************************/ -#ifndef __CF2FT_H__ -#define __CF2FT_H__ +#ifndef CF2FT_H_ +#define CF2FT_H_ #include "cf2types.h" @@ -64,6 +64,18 @@ FT_BEGIN_HEADER FT_LOCAL( CFF_SubFont ) cf2_getSubfont( CFF_Decoder* decoder ); + FT_LOCAL( CFF_VStore ) + cf2_getVStore( CFF_Decoder* decoder ); + + FT_LOCAL( FT_UInt ) + cf2_getMaxstack( CFF_Decoder* decoder ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_LOCAL( FT_Error ) + cf2_getNormalizedVector( CFF_Decoder* decoder, + CF2_UInt *len, + FT_Fixed* *vec ); +#endif FT_LOCAL( CF2_Fixed ) cf2_getPpemY( CFF_Decoder* decoder ); @@ -99,7 +111,7 @@ FT_BEGIN_HEADER FT_LOCAL( CF2_Int ) cf2_initGlobalRegionBuffer( CFF_Decoder* decoder, - CF2_UInt idx, + CF2_Int subrNum, CF2_Buffer buf ); FT_LOCAL( FT_Error ) cf2_getSeacComponent( CFF_Decoder* decoder, @@ -110,7 +122,7 @@ FT_BEGIN_HEADER CF2_Buffer buf ); FT_LOCAL( CF2_Int ) cf2_initLocalRegionBuffer( CFF_Decoder* decoder, - CF2_UInt idx, + CF2_Int subrNum, CF2_Buffer buf ); FT_LOCAL( CF2_Fixed ) @@ -141,7 +153,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CF2FT_H__ */ +#endif /* CF2FT_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cf2glue.h b/third_party/freetype/src/cff/cf2glue.h index a24da39e93..56a7c248f4 100644 --- a/third_party/freetype/src/cff/cf2glue.h +++ b/third_party/freetype/src/cff/cf2glue.h @@ -36,8 +36,8 @@ /***************************************************************************/ -#ifndef __CF2GLUE_H__ -#define __CF2GLUE_H__ +#ifndef CF2GLUE_H_ +#define CF2GLUE_H_ /* common includes for other modules */ @@ -138,7 +138,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CF2GLUE_H__ */ +#endif /* CF2GLUE_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cf2hints.c b/third_party/freetype/src/cff/cf2hints.c index 0e27000210..c8f7dfeba6 100644 --- a/third_party/freetype/src/cff/cf2hints.c +++ b/third_party/freetype/src/cff/cf2hints.c @@ -401,10 +401,10 @@ /* calculate all four possibilities; moves down are negative */ CF2_Fixed downMoveDown = 0 - fracDown; CF2_Fixed upMoveDown = 0 - fracUp; - CF2_Fixed downMoveUp = fracDown == 0 + CF2_Fixed downMoveUp = ( fracDown == 0 ) ? 0 : cf2_intToFixed( 1 ) - fracDown; - CF2_Fixed upMoveUp = fracUp == 0 + CF2_Fixed upMoveUp = ( fracUp == 0 ) ? 0 : cf2_intToFixed( 1 ) - fracUp; @@ -587,8 +587,9 @@ } /* paired edges must be in proper order */ - FT_ASSERT( !isPair || - topHintEdge->csCoord >= bottomHintEdge->csCoord ); + if ( isPair && + topHintEdge->csCoord < bottomHintEdge->csCoord ) + return; /* linear search to find index value of insertion point */ indexInsert = 0; diff --git a/third_party/freetype/src/cff/cf2hints.h b/third_party/freetype/src/cff/cf2hints.h index f25d91bf89..a8984542a0 100644 --- a/third_party/freetype/src/cff/cf2hints.h +++ b/third_party/freetype/src/cff/cf2hints.h @@ -36,8 +36,8 @@ /***************************************************************************/ -#ifndef __CF2HINTS_H__ -#define __CF2HINTS_H__ +#ifndef CF2HINTS_H_ +#define CF2HINTS_H_ FT_BEGIN_HEADER @@ -220,7 +220,7 @@ FT_BEGIN_HEADER /* character space miter limit threshold */ CF2_Fixed miterLimit; - /* vertical/horzizontal snap distance in character space */ + /* vertical/horizontal snap distance in character space */ CF2_Fixed snapThreshold; FT_Vector offsetStart0; /* first and second points of first */ @@ -283,7 +283,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CF2HINTS_H__ */ +#endif /* CF2HINTS_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cf2intrp.c b/third_party/freetype/src/cff/cf2intrp.c index ff3fa9aaaa..6bf298a4d6 100644 --- a/third_party/freetype/src/cff/cf2intrp.c +++ b/third_party/freetype/src/cff/cf2intrp.c @@ -47,6 +47,8 @@ #include "cf2error.h" +#include "cffload.h" + /*************************************************************************/ /* */ @@ -184,7 +186,7 @@ return; FT_ASSERT( hintmask->byteCount > 0 ); - FT_ASSERT( hintmask->byteCount < + FT_ASSERT( hintmask->byteCount <= sizeof ( hintmask->mask ) / sizeof ( hintmask->mask[0] ) ); /* set mask to all ones */ @@ -215,8 +217,8 @@ cf2_cmdESC, /* 12 */ cf2_cmdRESERVED_13, /* 13 */ cf2_cmdENDCHAR, /* 14 */ - cf2_cmdRESERVED_15, /* 15 */ - cf2_cmdRESERVED_16, /* 16 */ + cf2_cmdVSINDEX, /* 15 */ + cf2_cmdBLEND, /* 16 */ cf2_cmdRESERVED_17, /* 17 */ cf2_cmdHSTEMHM, /* 18 */ cf2_cmdHINTMASK, /* 19 */ @@ -273,7 +275,8 @@ cf2_escHFLEX, /* 34 */ cf2_escFLEX, /* 35 */ cf2_escHFLEX1, /* 36 */ - cf2_escFLEX1 /* 37 */ + cf2_escFLEX1, /* 37 */ + cf2_escRESERVED_38 /* 38 & all higher */ }; @@ -293,7 +296,8 @@ /* variable accumulates delta values from operand stack */ CF2_Fixed position = hintOffset; - if ( hasWidthArg && ! *haveWidth ) + + if ( hasWidthArg && !*haveWidth ) *width = cf2_stack_getReal( opStack, 0 ) + cf2_getNominalWidthX( font->decoder ); @@ -343,7 +347,7 @@ vals[0] = *curX; vals[1] = *curY; index = 0; - isHFlex = readFromStack[9] == FALSE; + isHFlex = FT_BOOL( readFromStack[9] == FALSE ); top = isHFlex ? 9 : 10; for ( i = 0; i < top; i++ ) @@ -402,6 +406,43 @@ } + /* Blend numOperands on the stack, */ + /* store results into the first numBlends values, */ + /* then pop remaining arguments. */ + static void + cf2_doBlend( const CFF_Blend blend, + CF2_Stack opStack, + CF2_UInt numBlends ) + { + CF2_UInt delta; + CF2_UInt base; + CF2_UInt i, j; + CF2_UInt numOperands = (CF2_UInt)( numBlends * blend->lenBV ); + + + base = cf2_stack_count( opStack ) - numOperands; + delta = base + numBlends; + + for ( i = 0; i < numBlends; i++ ) + { + const CF2_Fixed* weight = &blend->BV[1]; + + /* start with first term */ + CF2_Fixed sum = cf2_stack_getReal( opStack, i + base ); + + + for ( j = 1; j < blend->lenBV; j++ ) + sum += FT_MulFix( *weight++, cf2_stack_getReal( opStack, delta++ ) ); + + /* store blended result */ + cf2_stack_setReal( opStack, i + base, sum ); + } + + /* leave only `numBlends' results on stack */ + cf2_stack_pop( opStack, numOperands - numBlends ); + } + + /* * `error' is a shared error code used by many objects in this * routine. Before the code continues from an error, it must check and @@ -444,8 +485,11 @@ 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' */ + /* instruction limit; 20,000,000 matches Avalon */ FT_UInt32 instructionLimit = 20000000UL; @@ -466,6 +510,8 @@ CF2_GlyphPathRec glyphPath; + FT_ZERO( &storage ); + /* initialize the remaining objects */ cf2_arrstack_init( &subrStack, memory, @@ -515,19 +561,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 ); + 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 ); @@ -556,14 +607,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; @@ -581,13 +641,78 @@ case cf2_cmdRESERVED_2: case cf2_cmdRESERVED_9: case cf2_cmdRESERVED_13: - case cf2_cmdRESERVED_15: - case cf2_cmdRESERVED_16: case cf2_cmdRESERVED_17: /* we may get here if we have a prior error */ FT_TRACE4(( " unknown op (%d)\n", op1 )); break; + case cf2_cmdVSINDEX: + FT_TRACE4(( " vsindex\n" )); + + if ( !font->isCFF2 ) + break; /* clear stack & ignore */ + + if ( font->blend.usedBV ) + { + /* vsindex not allowed after blend */ + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + { + FT_Int temp = cf2_stack_popInt( opStack ); + + + if ( temp >= 0 ) + font->vsindex = (FT_UInt)temp; + } + break; + + case cf2_cmdBLEND: + { + FT_UInt numBlends; + + + FT_TRACE4(( " blend\n" )); + + if ( !font->isCFF2 ) + break; /* clear stack & ignore */ + + /* do we have a `blend' op in a non-variant font? */ + if ( !font->blend.font ) + { + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + /* check cached blend vector */ + if ( cff_blend_check_vector( &font->blend, + font->vsindex, + font->lenNDV, + font->NDV ) ) + { + lastError = cff_blend_build_vector( &font->blend, + font->vsindex, + font->lenNDV, + font->NDV ); + if ( lastError ) + goto exit; + } + + /* do the blend */ + numBlends = (FT_UInt)cf2_stack_popInt( opStack ); + if ( numBlends > stackSize ) + { + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + cf2_doBlend( &font->blend, opStack, numBlends ); + + font->blend.usedBV = TRUE; + } + continue; /* do not clear the stack */ + case cf2_cmdHSTEMHM: case cf2_cmdHSTEM: FT_TRACE4(( op1 == cf2_cmdHSTEMHM ? " hstemhm\n" : " hstem\n" )); @@ -608,7 +733,7 @@ 0 ); if ( font->decoder->width_only ) - goto exit; + goto exit; break; @@ -632,7 +757,7 @@ 0 ); if ( font->decoder->width_only ) - goto exit; + goto exit; break; @@ -646,7 +771,7 @@ haveWidth = TRUE; if ( font->decoder->width_only ) - goto exit; + goto exit; curY += cf2_stack_popFixed( opStack ); @@ -680,7 +805,7 @@ CF2_UInt index; CF2_UInt count = cf2_stack_count( opStack ); - FT_Bool isX = op1 == cf2_cmdHLINETO; + FT_Bool isX = FT_BOOL( op1 == cf2_cmdHLINETO ); FT_TRACE4(( isX ? " hlineto\n" : " vlineto\n" )); @@ -746,7 +871,7 @@ case cf2_cmdCALLGSUBR: case cf2_cmdCALLSUBR: { - CF2_UInt subrIndex; + CF2_Int subrNum; FT_TRACE4(( op1 == cf2_cmdCALLGSUBR ? " callgsubr" @@ -766,17 +891,17 @@ (size_t)charstringIndex + 1 ); /* set up the new CFF region and pointer */ - subrIndex = (CF2_UInt)cf2_stack_popInt( opStack ); + subrNum = cf2_stack_popInt( opStack ); switch ( op1 ) { case cf2_cmdCALLGSUBR: FT_TRACE4(( " (idx %d, entering level %d)\n", - subrIndex + (CF2_UInt)decoder->globals_bias, + subrNum + decoder->globals_bias, charstringIndex + 1 )); if ( cf2_initGlobalRegionBuffer( decoder, - subrIndex, + subrNum, charstring ) ) { lastError = FT_THROW( Invalid_Glyph_Format ); @@ -787,11 +912,11 @@ default: /* cf2_cmdCALLSUBR */ FT_TRACE4(( " (idx %d, entering level %d)\n", - subrIndex + (CF2_UInt)decoder->locals_bias, + subrNum + decoder->locals_bias, charstringIndex + 1 )); if ( cf2_initLocalRegionBuffer( decoder, - subrIndex, + subrNum, charstring ) ) { lastError = FT_THROW( Invalid_Glyph_Format ); @@ -825,135 +950,10 @@ 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_escDOTSECTION: - /* something about `flip type of locking' -- ignore it */ - FT_TRACE4(( " dotsection\n" )); - - break; - - /* TODO: should these operators be supported? */ - case cf2_escAND: /* in spec */ - FT_TRACE4(( " and\n" )); - - CF2_FIXME; - break; - - case cf2_escOR: /* in spec */ - FT_TRACE4(( " or\n" )); - - CF2_FIXME; - break; - - case cf2_escNOT: /* in spec */ - FT_TRACE4(( " not\n" )); - - CF2_FIXME; - break; - - case cf2_escABS: /* in spec */ - FT_TRACE4(( " abs\n" )); - - CF2_FIXME; - break; - - case cf2_escADD: /* in spec */ - FT_TRACE4(( " add\n" )); - - CF2_FIXME; - break; - - case cf2_escSUB: /* in spec */ - FT_TRACE4(( " sub\n" )); - - CF2_FIXME; - break; - - case cf2_escDIV: /* in spec */ - FT_TRACE4(( " div\n" )); - - CF2_FIXME; - break; - - case cf2_escNEG: /* in spec */ - FT_TRACE4(( " neg\n" )); - - CF2_FIXME; - break; - - case cf2_escEQ: /* in spec */ - FT_TRACE4(( " eq\n" )); - - CF2_FIXME; - break; - - case cf2_escDROP: /* in spec */ - FT_TRACE4(( " drop\n" )); - - CF2_FIXME; - break; - - case cf2_escPUT: /* in spec */ - FT_TRACE4(( " put\n" )); - - CF2_FIXME; - break; - - case cf2_escGET: /* in spec */ - FT_TRACE4(( " get\n" )); - - CF2_FIXME; - break; - - case cf2_escIFELSE: /* in spec */ - FT_TRACE4(( " ifelse\n" )); - - CF2_FIXME; - break; - - case cf2_escRANDOM: /* in spec */ - FT_TRACE4(( " random\n" )); - - CF2_FIXME; - break; - - case cf2_escMUL: /* in spec */ - FT_TRACE4(( " mul\n" )); - - CF2_FIXME; - break; - - case cf2_escSQRT: /* in spec */ - FT_TRACE4(( " sqrt\n" )); - - CF2_FIXME; - break; - - case cf2_escDUP: /* in spec */ - FT_TRACE4(( " dup\n" )); - - CF2_FIXME; - break; - - case cf2_escEXCH: /* in spec */ - FT_TRACE4(( " exch\n" )); - - CF2_FIXME; - break; - - case cf2_escINDEX: /* in spec */ - FT_TRACE4(( " index\n" )); - - CF2_FIXME; - break; - - case cf2_escROLL: /* in spec */ - FT_TRACE4(( " roll\n" )); - - CF2_FIXME; - break; - case cf2_escHFLEX: { static const FT_Bool readFromStack[12] = @@ -1050,6 +1050,7 @@ } continue; + /* these opcodes are reserved in both CFF & CFF2 */ case cf2_escRESERVED_1: case cf2_escRESERVED_2: case cf2_escRESERVED_6: @@ -1063,12 +1064,342 @@ case cf2_escRESERVED_31: case cf2_escRESERVED_32: case cf2_escRESERVED_33: - default: FT_TRACE4(( " unknown op (12, %d)\n", op2 )); + break; + + default: + { + 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" )); + + 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" )); - }; /* end of switch statement checking `op2' */ + 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: @@ -1085,12 +1416,13 @@ haveWidth = TRUE; if ( font->decoder->width_only ) - goto exit; + goto exit; /* 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 */ @@ -1117,8 +1449,8 @@ error2 = cf2_getSeacComponent( decoder, achar, &component ); if ( error2 ) { - lastError = error2; /* pass FreeType error through */ - goto exit; + lastError = error2; /* pass FreeType error through */ + goto exit; } cf2_interpT2CharString( font, &component, @@ -1172,7 +1504,7 @@ 0 ); if ( font->decoder->width_only ) - goto exit; + goto exit; if ( op1 == cf2_cmdHINTMASK ) { @@ -1231,7 +1563,7 @@ haveWidth = TRUE; if ( font->decoder->width_only ) - goto exit; + goto exit; curY += cf2_stack_popFixed( opStack ); curX += cf2_stack_popFixed( opStack ); @@ -1250,7 +1582,7 @@ haveWidth = TRUE; if ( font->decoder->width_only ) - goto exit; + goto exit; curX += cf2_stack_popFixed( opStack ); @@ -1319,7 +1651,7 @@ { x1 = cf2_stack_getReal( opStack, index ) + curX; - ++index; + index++; } else x1 = curX; @@ -1364,7 +1696,7 @@ { y1 = cf2_stack_getReal( opStack, index ) + curY; - ++index; + index++; } else y1 = curY; @@ -1392,7 +1724,7 @@ CF2_UInt count, count1 = cf2_stack_count( opStack ); CF2_UInt index = 0; - FT_Bool alternate = op1 == cf2_cmdHVCURVETO; + FT_Bool alternate = FT_BOOL( op1 == cf2_cmdHVCURVETO ); /* if `cf2_stack_count' isn't of the form 8n, 8n+1, */ @@ -1421,7 +1753,7 @@ { x3 = cf2_stack_getReal( opStack, index + 4 ) + x2; - ++index; + index++; } else x3 = x2; @@ -1440,7 +1772,7 @@ { y3 = cf2_stack_getReal( opStack, index + 4 ) + y2; - ++index; + index++; } else y3 = y2; @@ -1463,9 +1795,12 @@ { CF2_Int v; + CF2_Int byte1 = cf2_buf_readByte( charstring ); + CF2_Int byte2 = cf2_buf_readByte( charstring ); + - v = (FT_Short)( ( cf2_buf_readByte( charstring ) << 8 ) | - cf2_buf_readByte( charstring ) ); + v = (FT_Short)( ( byte1 << 8 ) | + byte2 ); FT_TRACE4(( " %d", v )); @@ -1527,14 +1862,18 @@ { CF2_Fixed v; + FT_UInt32 byte1 = (FT_UInt32)cf2_buf_readByte( charstring ); + FT_UInt32 byte2 = (FT_UInt32)cf2_buf_readByte( charstring ); + FT_UInt32 byte3 = (FT_UInt32)cf2_buf_readByte( charstring ); + FT_UInt32 byte4 = (FT_UInt32)cf2_buf_readByte( charstring ); - v = (CF2_Fixed) - ( ( (FT_UInt32)cf2_buf_readByte( charstring ) << 24 ) | - ( (FT_UInt32)cf2_buf_readByte( charstring ) << 16 ) | - ( (FT_UInt32)cf2_buf_readByte( charstring ) << 8 ) | - (FT_UInt32)cf2_buf_readByte( charstring ) ); - FT_TRACE4(( " %.2f", v / 65536.0 )); + v = (CF2_Fixed)( ( byte1 << 24 ) | + ( byte2 << 16 ) | + ( byte3 << 8 ) | + byte4 ); + + FT_TRACE4(( " %.5f", v / 65536.0 )); cf2_stack_pushFixed( opStack, v ); } @@ -1555,6 +1894,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 ); diff --git a/third_party/freetype/src/cff/cf2intrp.h b/third_party/freetype/src/cff/cf2intrp.h index b5d8947838..ec030e8944 100644 --- a/third_party/freetype/src/cff/cf2intrp.h +++ b/third_party/freetype/src/cff/cf2intrp.h @@ -36,8 +36,8 @@ /***************************************************************************/ -#ifndef __CF2INTRP_H__ -#define __CF2INTRP_H__ +#ifndef CF2INTRP_H_ +#define CF2INTRP_H_ #include "cf2ft.h" @@ -77,7 +77,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CF2INTRP_H__ */ +#endif /* CF2INTRP_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cf2read.h b/third_party/freetype/src/cff/cf2read.h index 7ef7c8c149..b0b0db803a 100644 --- a/third_party/freetype/src/cff/cf2read.h +++ b/third_party/freetype/src/cff/cf2read.h @@ -36,8 +36,8 @@ /***************************************************************************/ -#ifndef __CF2READ_H__ -#define __CF2READ_H__ +#ifndef CF2READ_H_ +#define CF2READ_H_ FT_BEGIN_HEADER @@ -62,7 +62,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CF2READ_H__ */ +#endif /* CF2READ_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cf2stack.c b/third_party/freetype/src/cff/cf2stack.c index 8332b5d91a..12a026d21d 100644 --- a/third_party/freetype/src/cff/cf2stack.c +++ b/third_party/freetype/src/cff/cf2stack.c @@ -51,21 +51,31 @@ /* `error'). */ FT_LOCAL_DEF( CF2_Stack ) cf2_stack_init( FT_Memory memory, - FT_Error* e ) + FT_Error* e, + FT_UInt stackSize ) { - FT_Error error = FT_Err_Ok; /* for FT_QNEW */ + FT_Error error = FT_Err_Ok; /* for FT_NEW */ CF2_Stack stack = NULL; - if ( !FT_QNEW( stack ) ) + if ( !FT_NEW( stack ) ) { - /* initialize the structure; FT_QNEW zeroes it */ + /* initialize the structure; FT_NEW zeroes it */ stack->memory = memory; stack->error = e; - stack->top = &stack->buffer[0]; /* empty stack */ } + /* allocate the stack buffer */ + if ( FT_NEW_ARRAY( stack->buffer, stackSize ) ) + { + FT_FREE( stack ); + return NULL; + } + + stack->stackSize = stackSize; + stack->top = stack->buffer; /* empty stack */ + return stack; } @@ -77,6 +87,8 @@ { FT_Memory memory = stack->memory; + /* free the buffer */ + FT_FREE( stack->buffer ); /* free the main structure */ FT_FREE( stack ); @@ -87,7 +99,7 @@ FT_LOCAL_DEF( CF2_UInt ) cf2_stack_count( CF2_Stack stack ) { - return (CF2_UInt)( stack->top - &stack->buffer[0] ); + return (CF2_UInt)( stack->top - stack->buffer ); } @@ -95,7 +107,7 @@ cf2_stack_pushInt( CF2_Stack stack, CF2_Int val ) { - if ( stack->top == &stack->buffer[CF2_OPERAND_STACK_SIZE] ) + if ( stack->top == stack->buffer + stack->stackSize ) { CF2_SET_ERROR( stack->error, Stack_Overflow ); return; /* stack overflow */ @@ -103,7 +115,7 @@ stack->top->u.i = val; stack->top->type = CF2_NumberInt; - ++stack->top; + stack->top++; } @@ -111,7 +123,7 @@ cf2_stack_pushFixed( CF2_Stack stack, CF2_Fixed val ) { - if ( stack->top == &stack->buffer[CF2_OPERAND_STACK_SIZE] ) + if ( stack->top == stack->buffer + stack->stackSize ) { CF2_SET_ERROR( stack->error, Stack_Overflow ); return; /* stack overflow */ @@ -119,7 +131,7 @@ stack->top->u.r = val; stack->top->type = CF2_NumberFixed; - ++stack->top; + stack->top++; } @@ -127,7 +139,7 @@ FT_LOCAL_DEF( CF2_Int ) cf2_stack_popInt( CF2_Stack stack ) { - if ( stack->top == &stack->buffer[0] ) + if ( stack->top == stack->buffer ) { CF2_SET_ERROR( stack->error, Stack_Underflow ); return 0; /* underflow */ @@ -138,24 +150,24 @@ return 0; /* type mismatch */ } - --stack->top; + stack->top--; return stack->top->u.i; } /* Note: type mismatch is silently cast */ - /* TODO: check this */ + /* TODO: check this */ FT_LOCAL_DEF( CF2_Fixed ) cf2_stack_popFixed( CF2_Stack stack ) { - if ( stack->top == &stack->buffer[0] ) + if ( stack->top == stack->buffer ) { CF2_SET_ERROR( stack->error, Stack_Underflow ); return cf2_intToFixed( 0 ); /* underflow */ } - --stack->top; + stack->top--; switch ( stack->top->type ) { @@ -170,12 +182,12 @@ /* Note: type mismatch is silently cast */ - /* TODO: check this */ + /* TODO: check this */ FT_LOCAL_DEF( CF2_Fixed ) cf2_stack_getReal( CF2_Stack stack, CF2_UInt idx ) { - FT_ASSERT( cf2_stack_count( stack ) <= CF2_OPERAND_STACK_SIZE ); + FT_ASSERT( cf2_stack_count( stack ) <= stack->stackSize ); if ( idx >= cf2_stack_count( stack ) ) { @@ -195,10 +207,121 @@ } + /* provide random access to stack */ + FT_LOCAL_DEF( void ) + cf2_stack_setReal( CF2_Stack stack, + CF2_UInt idx, + CF2_Fixed val ) + { + if ( idx > cf2_stack_count( stack ) ) + { + CF2_SET_ERROR( stack->error, Stack_Overflow ); + return; + } + + stack->buffer[idx].u.r = val; + stack->buffer[idx].type = CF2_NumberFixed; + } + + + /* discard (pop) num values from stack */ + FT_LOCAL_DEF( void ) + cf2_stack_pop( CF2_Stack stack, + CF2_UInt num ) + { + if ( num > cf2_stack_count( stack ) ) + { + CF2_SET_ERROR( stack->error, Stack_Underflow ); + return; + } + stack->top -= num; + } + + + FT_LOCAL_DEF( void ) + cf2_stack_roll( CF2_Stack stack, + CF2_Int count, + CF2_Int shift ) + { + /* we initialize this variable to avoid compiler warnings */ + CF2_StackNumber last = { { 0 }, CF2_NumberInt }; + + CF2_Int start_idx, idx, i; + + + if ( count < 2 ) + return; /* nothing to do (values 0 and 1), or undefined value */ + + if ( (CF2_UInt)count > cf2_stack_count( stack ) ) + { + CF2_SET_ERROR( stack->error, Stack_Overflow ); + return; + } + + if ( shift < 0 ) + shift = -( ( -shift ) % count ); + else + shift %= count; + + if ( shift == 0 ) + return; /* nothing to do */ + + /* We use the following algorithm to do the rolling, */ + /* which needs two temporary variables only. */ + /* */ + /* Example: */ + /* */ + /* count = 8 */ + /* shift = 2 */ + /* */ + /* stack indices before roll: 7 6 5 4 3 2 1 0 */ + /* stack indices after roll: 1 0 7 6 5 4 3 2 */ + /* */ + /* The value of index 0 gets moved to index 2, while */ + /* the old value of index 2 gets moved to index 4, */ + /* and so on. We thus have the following copying */ + /* chains for shift value 2. */ + /* */ + /* 0 -> 2 -> 4 -> 6 -> 0 */ + /* 1 -> 3 -> 5 -> 7 -> 1 */ + /* */ + /* If `count' and `shift' are incommensurable, we */ + /* have a single chain only. Otherwise, increase */ + /* the start index by 1 after the first chain, then */ + /* do the next chain until all elements in all */ + /* chains are handled. */ + + start_idx = -1; + idx = -1; + for ( i = 0; i < count; i++ ) + { + CF2_StackNumber tmp; + + + if ( start_idx == idx ) + { + start_idx++; + idx = start_idx; + last = stack->buffer[idx]; + } + + idx += shift; + if ( idx >= count ) + idx -= count; + else if ( idx < 0 ) + idx += count; + + tmp = stack->buffer[idx]; + stack->buffer[idx] = last; + last = tmp; + } + } + + FT_LOCAL_DEF( void ) cf2_stack_clear( CF2_Stack stack ) { - stack->top = &stack->buffer[0]; + stack->top = stack->buffer; } diff --git a/third_party/freetype/src/cff/cf2stack.h b/third_party/freetype/src/cff/cf2stack.h index 7d6d1961fe..ef08eefe41 100644 --- a/third_party/freetype/src/cff/cf2stack.h +++ b/third_party/freetype/src/cff/cf2stack.h @@ -36,8 +36,8 @@ /***************************************************************************/ -#ifndef __CF2STACK_H__ -#define __CF2STACK_H__ +#ifndef CF2STACK_H_ +#define CF2STACK_H_ FT_BEGIN_HEADER @@ -62,15 +62,17 @@ FT_BEGIN_HEADER { FT_Memory memory; FT_Error* error; - CF2_StackNumber buffer[CF2_OPERAND_STACK_SIZE]; + CF2_StackNumber* buffer; CF2_StackNumber* top; + FT_UInt stackSize; } CF2_StackRec, *CF2_Stack; FT_LOCAL( CF2_Stack ) cf2_stack_init( FT_Memory memory, - FT_Error* error ); + FT_Error* error, + FT_UInt stackSize ); FT_LOCAL( void ) cf2_stack_free( CF2_Stack stack ); @@ -92,6 +94,19 @@ FT_BEGIN_HEADER FT_LOCAL( CF2_Fixed ) cf2_stack_getReal( CF2_Stack stack, CF2_UInt idx ); + FT_LOCAL( void ) + cf2_stack_setReal( CF2_Stack stack, + CF2_UInt idx, + CF2_Fixed val ); + + FT_LOCAL( void ) + cf2_stack_pop( CF2_Stack stack, + CF2_UInt num ); + + FT_LOCAL( void ) + cf2_stack_roll( CF2_Stack stack, + CF2_Int count, + CF2_Int idx ); FT_LOCAL( void ) cf2_stack_clear( CF2_Stack stack ); @@ -100,7 +115,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CF2STACK_H__ */ +#endif /* CF2STACK_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cf2types.h b/third_party/freetype/src/cff/cf2types.h index ac6a02266e..5b7e1239af 100644 --- a/third_party/freetype/src/cff/cf2types.h +++ b/third_party/freetype/src/cff/cf2types.h @@ -36,8 +36,8 @@ /***************************************************************************/ -#ifndef __CF2TYPES_H__ -#define __CF2TYPES_H__ +#ifndef CF2TYPES_H_ +#define CF2TYPES_H_ #include <ft2build.h> #include FT_FREETYPE_H @@ -72,7 +72,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CF2TYPES_H__ */ +#endif /* CF2TYPES_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cff.c b/third_party/freetype/src/cff/cff.c index bb2cfb5253..545fb202c9 100644 --- a/third_party/freetype/src/cff/cff.c +++ b/third_party/freetype/src/cff/cff.c @@ -4,7 +4,7 @@ /* */ /* FreeType OpenType driver component (body only). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2017 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ diff --git a/third_party/freetype/src/cff/cffcmap.c b/third_party/freetype/src/cff/cffcmap.c index e7538e9840..4adce7a54d 100644 --- a/third_party/freetype/src/cff/cffcmap.c +++ b/third_party/freetype/src/cff/cffcmap.c @@ -4,7 +4,7 @@ /* */ /* CFF character mapping table (cmap) support (body). */ /* */ -/* Copyright 2002-2015 by */ +/* Copyright 2002-2017 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -104,15 +104,21 @@ } - FT_DEFINE_CMAP_CLASS(cff_cmap_encoding_class_rec, + FT_DEFINE_CMAP_CLASS( + cff_cmap_encoding_class_rec, + sizeof ( CFF_CMapStdRec ), - (FT_CMap_InitFunc) cff_cmap_encoding_init, - (FT_CMap_DoneFunc) cff_cmap_encoding_done, - (FT_CMap_CharIndexFunc)cff_cmap_encoding_char_index, - (FT_CMap_CharNextFunc) cff_cmap_encoding_char_next, + (FT_CMap_InitFunc) cff_cmap_encoding_init, /* init */ + (FT_CMap_DoneFunc) cff_cmap_encoding_done, /* done */ + (FT_CMap_CharIndexFunc)cff_cmap_encoding_char_index, /* char_index */ + (FT_CMap_CharNextFunc) cff_cmap_encoding_char_next, /* char_next */ - NULL, NULL, NULL, NULL, NULL + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */ ) @@ -202,15 +208,22 @@ } - FT_DEFINE_CMAP_CLASS(cff_cmap_unicode_class_rec, + FT_DEFINE_CMAP_CLASS( + cff_cmap_unicode_class_rec, + sizeof ( PS_UnicodesRec ), - (FT_CMap_InitFunc) cff_cmap_unicode_init, - (FT_CMap_DoneFunc) cff_cmap_unicode_done, - (FT_CMap_CharIndexFunc)cff_cmap_unicode_char_index, - (FT_CMap_CharNextFunc) cff_cmap_unicode_char_next, + (FT_CMap_InitFunc) cff_cmap_unicode_init, /* init */ + (FT_CMap_DoneFunc) cff_cmap_unicode_done, /* done */ + (FT_CMap_CharIndexFunc)cff_cmap_unicode_char_index, /* char_index */ + (FT_CMap_CharNextFunc) cff_cmap_unicode_char_next, /* char_next */ - NULL, NULL, NULL, NULL, NULL + (FT_CMap_CharVarIndexFunc) NULL, /* char_var_index */ + (FT_CMap_CharVarIsDefaultFunc)NULL, /* char_var_default */ + (FT_CMap_VariantListFunc) NULL, /* variant_list */ + (FT_CMap_CharVariantListFunc) NULL, /* charvariant_list */ + (FT_CMap_VariantCharListFunc) NULL /* variantchar_list */ ) + /* END */ diff --git a/third_party/freetype/src/cff/cffcmap.h b/third_party/freetype/src/cff/cffcmap.h index 6eaed636ec..7792e04248 100644 --- a/third_party/freetype/src/cff/cffcmap.h +++ b/third_party/freetype/src/cff/cffcmap.h @@ -4,7 +4,7 @@ /* */ /* CFF character mapping table (cmap) support (specification). */ /* */ -/* Copyright 2002-2015 by */ +/* Copyright 2002-2017 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,8 +16,8 @@ /***************************************************************************/ -#ifndef __CFFCMAP_H__ -#define __CFFCMAP_H__ +#ifndef CFFCMAP_H_ +#define CFFCMAP_H_ #include "cffobjs.h" @@ -61,7 +61,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CFFCMAP_H__ */ +#endif /* CFFCMAP_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cffdrivr.c b/third_party/freetype/src/cff/cffdrivr.c index a718b7a002..467b3edc70 100644 --- a/third_party/freetype/src/cff/cffdrivr.c +++ b/third_party/freetype/src/cff/cffdrivr.c @@ -4,7 +4,7 @@ /* */ /* OpenType font driver implementation (body). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2017 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -32,6 +32,10 @@ #include "cffcmap.h" #include "cffparse.h" +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include FT_SERVICE_MULTIPLE_MASTERS_H +#endif + #include "cfferrs.h" #include "cffpic.h" @@ -207,6 +211,13 @@ if ( flags & FT_LOAD_VERTICAL_LAYOUT ) { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* no fast retrieval for blended MM fonts without VVAR table */ + if ( !ttface->is_default_instance && + !( ttface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) + return FT_THROW( Unimplemented_Feature ); +#endif + /* check whether we have data from the `vmtx' table at all; */ /* otherwise we extract the info from the CFF glyphstrings */ /* (instead of synthesizing a global value using the `OS/2' */ @@ -232,6 +243,13 @@ } else { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* no fast retrieval for blended MM fonts without HVAR table */ + if ( !ttface->is_default_instance && + !( ttface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) + return FT_THROW( Unimplemented_Feature ); +#endif + /* check whether we have data from the `hmtx' table at all */ if ( !ttface->horizontal.number_Of_HMetrics ) goto Missing_Table; @@ -291,6 +309,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:" @@ -332,6 +379,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; @@ -358,8 +430,9 @@ FT_DEFINE_SERVICE_GLYPHDICTREC( cff_service_glyph_dict, - (FT_GlyphDict_GetNameFunc) cff_get_glyph_name, - (FT_GlyphDict_NameIndexFunc)cff_get_name_index + + (FT_GlyphDict_GetNameFunc) cff_get_glyph_name, /* get_name */ + (FT_GlyphDict_NameIndexFunc)cff_get_name_index /* name_index */ ) @@ -383,11 +456,11 @@ FT_Error error = FT_Err_Ok; - if ( cff && cff->font_info == NULL ) + if ( cff && !cff->font_info ) { - CFF_FontRecDict dict = &cff->top_font.font_dict; + CFF_FontRecDict dict = &cff->top_font.font_dict; PS_FontInfoRec *font_info = NULL; - FT_Memory memory = face->root.memory; + FT_Memory memory = face->root.memory; if ( FT_ALLOC( font_info, sizeof ( *font_info ) ) ) @@ -421,11 +494,14 @@ FT_DEFINE_SERVICE_PSINFOREC( cff_service_ps_info, - (PS_GetFontInfoFunc) cff_ps_get_font_info, - (PS_GetFontExtraFunc) NULL, - (PS_HasGlyphNamesFunc) cff_ps_has_glyph_names, - (PS_GetFontPrivateFunc)NULL, /* unsupported with CFF fonts */ - (PS_GetFontValueFunc) NULL /* not implemented */ + + (PS_GetFontInfoFunc) cff_ps_get_font_info, /* ps_get_font_info */ + (PS_GetFontExtraFunc) NULL, /* ps_get_font_extra */ + (PS_HasGlyphNamesFunc) cff_ps_has_glyph_names, /* ps_has_glyph_names */ + /* unsupported with CFF fonts */ + (PS_GetFontPrivateFunc)NULL, /* ps_get_font_private */ + /* not implemented */ + (PS_GetFontValueFunc) NULL /* ps_get_font_value */ ) @@ -444,14 +520,15 @@ /* following the OpenType specification 1.7, we return the name stored */ /* in the `name' table for a CFF wrapped into an SFNT container */ - if ( sfnt ) + if ( FT_IS_SFNT( FT_FACE( face ) ) && sfnt ) { FT_Library library = FT_FACE_LIBRARY( face ); FT_Module sfnt_module = FT_Get_Module( library, "sfnt" ); FT_Service_PsFontName service = (FT_Service_PsFontName)ft_module_get_service( sfnt_module, - FT_SERVICE_ID_POSTSCRIPT_FONT_NAME ); + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, + 0 ); if ( service && service->get_ps_font_name ) @@ -464,7 +541,8 @@ FT_DEFINE_SERVICE_PSFONTNAMEREC( cff_service_ps_name, - (FT_PsName_GetFunc)cff_get_ps_name + + (FT_PsName_GetFunc)cff_get_ps_name /* get_ps_font_name */ ) @@ -489,21 +567,21 @@ FT_Library library = FT_FACE_LIBRARY( face ); - cmap_info->language = 0; - cmap_info->format = 0; - if ( cmap->clazz != &CFF_CMAP_ENCODING_CLASS_REC_GET && cmap->clazz != &CFF_CMAP_UNICODE_CLASS_REC_GET ) { FT_Module sfnt = FT_Get_Module( library, "sfnt" ); FT_Service_TTCMaps service = (FT_Service_TTCMaps)ft_module_get_service( sfnt, - FT_SERVICE_ID_TT_CMAP ); + FT_SERVICE_ID_TT_CMAP, + 0 ); if ( service && service->get_cmap_info ) error = service->get_cmap_info( charmap, cmap_info ); } + else + error = FT_THROW( Invalid_CharMap_Format ); return error; } @@ -511,7 +589,8 @@ FT_DEFINE_SERVICE_TTCMAPSREC( cff_service_get_cmap_info, - (TT_CMap_Info_GetFunc)cff_get_cmap_info + + (TT_CMap_Info_GetFunc)cff_get_cmap_info /* get_cmap_info */ ) @@ -542,7 +621,7 @@ if ( registry ) { - if ( cff->registry == NULL ) + if ( !cff->registry ) cff->registry = cff_index_get_sid_string( cff, dict->cid_registry ); *registry = cff->registry; @@ -550,7 +629,7 @@ if ( ordering ) { - if ( cff->ordering == NULL ) + if ( !cff->ordering ) cff->ordering = cff_index_get_sid_string( cff, dict->cid_ordering ); *ordering = cff->ordering; @@ -641,9 +720,13 @@ FT_DEFINE_SERVICE_CIDREC( cff_service_cid_info, - (FT_CID_GetRegistryOrderingSupplementFunc)cff_get_ros, - (FT_CID_GetIsInternallyCIDKeyedFunc) cff_get_is_cid, - (FT_CID_GetCIDFromGlyphIndexFunc) cff_get_cid_from_glyph_index + + (FT_CID_GetRegistryOrderingSupplementFunc) + cff_get_ros, /* get_ros */ + (FT_CID_GetIsInternallyCIDKeyedFunc) + cff_get_is_cid, /* get_is_cid */ + (FT_CID_GetCIDFromGlyphIndexFunc) + cff_get_cid_from_glyph_index /* get_cid_from_glyph_index */ ) @@ -654,26 +737,62 @@ static FT_Error cff_property_set( FT_Module module, /* CFF_Driver */ const char* property_name, - const void* value ) + const void* value, + FT_Bool value_is_string ) { FT_Error error = FT_Err_Ok; CFF_Driver driver = (CFF_Driver)module; +#ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_UNUSED( value_is_string ); +#endif + if ( !ft_strcmp( property_name, "darkening-parameters" ) ) { - FT_Int* darken_params = (FT_Int*)value; + FT_Int* darken_params; + FT_Int x1, y1, x2, y2, x3, y3, x4, y4; - FT_Int x1 = darken_params[0]; - FT_Int y1 = darken_params[1]; - FT_Int x2 = darken_params[2]; - FT_Int y2 = darken_params[3]; - FT_Int x3 = darken_params[4]; - FT_Int y3 = darken_params[5]; - FT_Int x4 = darken_params[6]; - FT_Int y4 = darken_params[7]; +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_Int dp[8]; + if ( value_is_string ) + { + const char* s = (const char*)value; + char* ep; + int i; + + + /* eight comma-separated numbers */ + for ( i = 0; i < 7; i++ ) + { + dp[i] = (FT_Int)ft_strtol( s, &ep, 10 ); + if ( *ep != ',' || s == ep ) + return FT_THROW( Invalid_Argument ); + + s = ep + 1; + } + + dp[7] = (FT_Int)ft_strtol( s, &ep, 10 ); + if ( !( *ep == '\0' || *ep == ' ' ) || s == ep ) + return FT_THROW( Invalid_Argument ); + + darken_params = dp; + } + else +#endif + darken_params = (FT_Int*)value; + + x1 = darken_params[0]; + y1 = darken_params[1]; + x2 = darken_params[2]; + y2 = darken_params[3]; + x3 = darken_params[4]; + y3 = darken_params[5]; + x4 = darken_params[6]; + y4 = darken_params[7]; + if ( x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 || y1 < 0 || y2 < 0 || y3 < 0 || y4 < 0 || x1 > x2 || x2 > x3 || x3 > x4 || @@ -693,24 +812,62 @@ } else if ( !ft_strcmp( property_name, "hinting-engine" ) ) { - FT_UInt* hinting_engine = (FT_UInt*)value; +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + { + const char* s = (const char*)value; -#ifndef CFF_CONFIG_OPTION_OLD_ENGINE - if ( *hinting_engine != FT_CFF_HINTING_ADOBE ) - error = FT_ERR( Unimplemented_Feature ); + if ( !ft_strcmp( s, "adobe" ) ) + driver->hinting_engine = FT_CFF_HINTING_ADOBE; +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + else if ( !ft_strcmp( s, "freetype" ) ) + driver->hinting_engine = FT_CFF_HINTING_FREETYPE; +#endif + else + return FT_THROW( Invalid_Argument ); + } else #endif - driver->hinting_engine = *hinting_engine; + { + FT_UInt* hinting_engine = (FT_UInt*)value; - return error; + if ( *hinting_engine == FT_CFF_HINTING_ADOBE +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + || *hinting_engine == FT_CFF_HINTING_FREETYPE +#endif + ) + driver->hinting_engine = *hinting_engine; + else + error = FT_ERR( Unimplemented_Feature ); + + return error; + } } else if ( !ft_strcmp( property_name, "no-stem-darkening" ) ) { - FT_Bool* no_stem_darkening = (FT_Bool*)value; +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + { + const char* s = (const char*)value; + long nsd = ft_strtol( s, NULL, 10 ); + + + if ( nsd == 0 ) + driver->no_stem_darkening = 0; + else if ( nsd == 1 ) + driver->no_stem_darkening = 1; + else + return FT_THROW( Invalid_Argument ); + } + else +#endif + { + FT_Bool* no_stem_darkening = (FT_Bool*)value; - driver->no_stem_darkening = *no_stem_darkening; + driver->no_stem_darkening = *no_stem_darkening; + } return error; } @@ -776,8 +933,92 @@ FT_DEFINE_SERVICE_PROPERTIESREC( cff_service_properties, - (FT_Properties_SetFunc)cff_property_set, - (FT_Properties_GetFunc)cff_property_get ) + + (FT_Properties_SetFunc)cff_property_set, /* set_property */ + (FT_Properties_GetFunc)cff_property_get ) /* get_property */ + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + /* + * MULTIPLE MASTER SERVICE + * + */ + + static FT_Error + cff_set_mm_blend( CFF_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + return mm->set_mm_blend( FT_FACE( face ), num_coords, coords ); + } + + + static FT_Error + cff_get_mm_blend( CFF_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + return mm->get_mm_blend( FT_FACE( face ), num_coords, coords ); + } + + + static FT_Error + cff_get_mm_var( CFF_Face face, + FT_MM_Var* *master ) + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + return mm->get_mm_var( FT_FACE( face ), master ); + } + + + static FT_Error + cff_set_var_design( CFF_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + return mm->set_var_design( FT_FACE( face ), num_coords, coords ); + } + + + static FT_Error + cff_get_var_design( CFF_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + return mm->get_var_design( FT_FACE( face ), num_coords, coords ); + } + + + FT_DEFINE_SERVICE_MULTIMASTERSREC( + cff_service_multi_masters, + + (FT_Get_MM_Func) NULL, /* get_mm */ + (FT_Set_MM_Design_Func) NULL, /* set_mm_design */ + (FT_Set_MM_Blend_Func) cff_set_mm_blend, /* set_mm_blend */ + (FT_Get_MM_Blend_Func) cff_get_mm_blend, /* get_mm_blend */ + (FT_Get_MM_Var_Func) cff_get_mm_var, /* get_mm_var */ + (FT_Set_Var_Design_Func)cff_set_var_design, /* set_var_design */ + (FT_Get_Var_Design_Func)cff_get_var_design, /* get_var_design */ + + (FT_Get_Var_Blend_Func) cff_get_var_blend, /* get_var_blend */ + (FT_Done_Blend_Func) cff_done_blend /* done_blend */ + ) +#endif /*************************************************************************/ @@ -792,9 +1033,24 @@ /*************************************************************************/ /*************************************************************************/ -#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES +#if !defined FT_CONFIG_OPTION_NO_GLYPH_NAMES && \ + defined TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_DEFINE_SERVICEDESCREC8( + cff_services, + + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CFF, + FT_SERVICE_ID_MULTI_MASTERS, &CFF_SERVICE_MULTI_MASTERS_GET, + FT_SERVICE_ID_POSTSCRIPT_INFO, &CFF_SERVICE_PS_INFO_GET, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &CFF_SERVICE_PS_NAME_GET, + FT_SERVICE_ID_GLYPH_DICT, &CFF_SERVICE_GLYPH_DICT_GET, + FT_SERVICE_ID_TT_CMAP, &CFF_SERVICE_GET_CMAP_INFO_GET, + FT_SERVICE_ID_CID, &CFF_SERVICE_CID_INFO_GET, + FT_SERVICE_ID_PROPERTIES, &CFF_SERVICE_PROPERTIES_GET + ) +#elif !defined FT_CONFIG_OPTION_NO_GLYPH_NAMES FT_DEFINE_SERVICEDESCREC7( cff_services, + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CFF, FT_SERVICE_ID_POSTSCRIPT_INFO, &CFF_SERVICE_PS_INFO_GET, FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &CFF_SERVICE_PS_NAME_GET, @@ -803,9 +1059,22 @@ FT_SERVICE_ID_CID, &CFF_SERVICE_CID_INFO_GET, FT_SERVICE_ID_PROPERTIES, &CFF_SERVICE_PROPERTIES_GET ) +#elif defined TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_DEFINE_SERVICEDESCREC7( + cff_services, + + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CFF, + FT_SERVICE_ID_MULTI_MASTERS, &CFF_SERVICE_MULTI_MASTERS_GET, + FT_SERVICE_ID_POSTSCRIPT_INFO, &CFF_SERVICE_PS_INFO_GET, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &CFF_SERVICE_PS_NAME_GET, + FT_SERVICE_ID_TT_CMAP, &CFF_SERVICE_GET_CMAP_INFO_GET, + FT_SERVICE_ID_CID, &CFF_SERVICE_CID_INFO_GET, + FT_SERVICE_ID_PROPERTIES, &CFF_SERVICE_PROPERTIES_GET + ) #else FT_DEFINE_SERVICEDESCREC6( cff_services, + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CFF, FT_SERVICE_ID_POSTSCRIPT_INFO, &CFF_SERVICE_PS_INFO_GET, FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &CFF_SERVICE_PS_NAME_GET, @@ -835,7 +1104,7 @@ #endif result = ft_service_list_lookup( CFF_SERVICES_GET, module_interface ); - if ( result != NULL ) + if ( result ) return result; /* `driver' is not yet evaluated in non-PIC mode */ @@ -865,42 +1134,41 @@ FT_DEFINE_DRIVER( cff_driver_class, - FT_MODULE_FONT_DRIVER | - FT_MODULE_DRIVER_SCALABLE | - FT_MODULE_DRIVER_HAS_HINTER, + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + FT_MODULE_DRIVER_HAS_HINTER | + FT_MODULE_DRIVER_HINTS_LIGHTLY, sizeof ( CFF_DriverRec ), "cff", 0x10000L, 0x20000L, - 0, /* module-specific interface */ + NULL, /* module-specific interface */ - cff_driver_init, - cff_driver_done, - cff_get_interface, + cff_driver_init, /* FT_Module_Constructor module_init */ + cff_driver_done, /* FT_Module_Destructor module_done */ + cff_get_interface, /* FT_Module_Requester get_interface */ - /* now the specific driver fields */ sizeof ( TT_FaceRec ), sizeof ( CFF_SizeRec ), sizeof ( CFF_GlyphSlotRec ), - cff_face_init, - cff_face_done, - cff_size_init, - cff_size_done, - cff_slot_init, - cff_slot_done, - - cff_glyph_load, + cff_face_init, /* FT_Face_InitFunc init_face */ + cff_face_done, /* FT_Face_DoneFunc done_face */ + cff_size_init, /* FT_Size_InitFunc init_size */ + cff_size_done, /* FT_Size_DoneFunc done_size */ + cff_slot_init, /* FT_Slot_InitFunc init_slot */ + cff_slot_done, /* FT_Slot_DoneFunc done_slot */ - cff_get_kerning, - 0, /* FT_Face_AttachFunc */ - cff_get_advances, + cff_glyph_load, /* FT_Slot_LoadFunc load_glyph */ - cff_size_request, + cff_get_kerning, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + cff_get_advances, /* FT_Face_GetAdvancesFunc get_advances */ - CFF_SIZE_SELECT + cff_size_request, /* FT_Size_RequestFunc request_size */ + CFF_SIZE_SELECT /* FT_Size_SelectFunc select_size */ ) diff --git a/third_party/freetype/src/cff/cffdrivr.h b/third_party/freetype/src/cff/cffdrivr.h index 9527f5e149..05381e66db 100644 --- a/third_party/freetype/src/cff/cffdrivr.h +++ b/third_party/freetype/src/cff/cffdrivr.h @@ -4,7 +4,7 @@ /* */ /* High-level OpenType driver interface (specification). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2017 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,8 +16,8 @@ /***************************************************************************/ -#ifndef __CFFDRIVER_H__ -#define __CFFDRIVER_H__ +#ifndef CFFDRIVER_H_ +#define CFFDRIVER_H_ #include <ft2build.h> @@ -32,7 +32,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CFFDRIVER_H__ */ +#endif /* CFFDRIVER_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cfferrs.h b/third_party/freetype/src/cff/cfferrs.h index 543bdb07c2..40808c1051 100644 --- a/third_party/freetype/src/cff/cfferrs.h +++ b/third_party/freetype/src/cff/cfferrs.h @@ -4,7 +4,7 @@ /* */ /* CFF error codes (specification only). */ /* */ -/* Copyright 2001-2015 by */ +/* Copyright 2001-2017 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -22,12 +22,12 @@ /* */ /*************************************************************************/ -#ifndef __CFFERRS_H__ -#define __CFFERRS_H__ +#ifndef CFFERRS_H_ +#define CFFERRS_H_ #include FT_MODULE_ERRORS_H -#undef __FTERRORS_H__ +#undef FTERRORS_H_ #undef FT_ERR_PREFIX #define FT_ERR_PREFIX CFF_Err_ @@ -36,7 +36,7 @@ #include FT_ERRORS_H -#endif /* __CFFERRS_H__ */ +#endif /* CFFERRS_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cffgload.c b/third_party/freetype/src/cff/cffgload.c index 5f57403e22..f8e80c100d 100644 --- a/third_party/freetype/src/cff/cffgload.c +++ b/third_party/freetype/src/cff/cffgload.c @@ -4,7 +4,7 @@ /* */ /* OpenType Glyph Loader (body). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2017 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -391,7 +391,7 @@ /* clear everything */ - FT_MEM_ZERO( decoder, sizeof ( *decoder ) ); + FT_ZERO( decoder ); /* initialize builder */ cff_builder_init( &decoder->builder, face, size, slot, hinting ); @@ -680,7 +680,7 @@ #endif /* FT_CONFIG_OPTION_INCREMENTAL */ { - CFF_Font cff = (CFF_Font)(face->extra.data); + CFF_Font cff = (CFF_Font)(face->extra.data); return cff_index_access_element( &cff->charstrings_index, glyph_index, @@ -826,7 +826,7 @@ /* the seac operator must not be nested */ decoder->seac = TRUE; error = cff_decoder_parse_charstrings( decoder, charstring, - charstring_len ); + charstring_len, 0 ); decoder->seac = FALSE; cff_free_glyph_data( face, &charstring, charstring_len ); @@ -856,7 +856,7 @@ /* the seac operator must not be nested */ decoder->seac = TRUE; error = cff_decoder_parse_charstrings( decoder, charstring, - charstring_len ); + charstring_len, 0 ); decoder->seac = FALSE; cff_free_glyph_data( face, &charstring, charstring_len ); @@ -895,13 +895,17 @@ /* */ /* charstring_len :: The length in bytes of the charstring stream. */ /* */ + /* in_dict :: Set to 1 if function is called from top or */ + /* private DICT (needed for Multiple Master CFFs). */ + /* */ /* <Return> */ /* FreeType error code. 0 means success. */ /* */ FT_LOCAL_DEF( FT_Error ) cff_decoder_parse_charstrings( CFF_Decoder* decoder, FT_Byte* charstring_base, - FT_ULong charstring_len ) + FT_ULong charstring_len, + FT_Bool in_dict ) { FT_Error error; CFF_Decoder_Zone* zone; @@ -913,6 +917,10 @@ FT_Fixed* stack; FT_Int charstring_type = decoder->cff->top_font.font_dict.charstring_type; + FT_UShort num_designs = + decoder->cff->top_font.font_dict.num_designs; + FT_UShort num_axes = + decoder->cff->top_font.font_dict.num_axes; T2_Hints_Funcs hinter; @@ -1018,7 +1026,7 @@ if ( !( val & 0xFFFFL ) ) FT_TRACE4(( " %hd", (FT_Short)( (FT_UInt32)val >> 16 ) )); else - FT_TRACE4(( " %.2f", val / 65536.0 )); + FT_TRACE4(( " %.5f", val / 65536.0 )); #endif } @@ -1241,6 +1249,44 @@ if ( op == cff_op_unknown ) continue; + /* in Multiple Master CFFs, T2 charstrings can appear in */ + /* dictionaries, but some operators are prohibited */ + if ( in_dict ) + { + switch ( op ) + { + case cff_op_hstem: + case cff_op_vstem: + case cff_op_vmoveto: + case cff_op_rlineto: + case cff_op_hlineto: + case cff_op_vlineto: + case cff_op_rrcurveto: + case cff_op_hstemhm: + case cff_op_hintmask: + case cff_op_cntrmask: + case cff_op_rmoveto: + case cff_op_hmoveto: + case cff_op_vstemhm: + case cff_op_rcurveline: + case cff_op_rlinecurve: + case cff_op_vvcurveto: + case cff_op_hhcurveto: + case cff_op_vhcurveto: + case cff_op_hvcurveto: + case cff_op_hflex: + case cff_op_flex: + case cff_op_hflex1: + case cff_op_flex1: + case cff_op_callsubr: + case cff_op_callgsubr: + goto MM_Error; + + default: + break; + } + } + /* check arguments */ req_args = cff_argument_counts[op]; if ( req_args & CFF_COUNT_CHECK_WIDTH ) @@ -1278,7 +1324,9 @@ case cff_op_endchar: /* If there is a width specified for endchar, we either have */ /* 1 argument or 5 arguments. We like to argue. */ - set_width_ok = ( num_args == 5 ) || ( num_args == 1 ); + set_width_ok = in_dict + ? 0 + : ( ( num_args == 5 ) || ( num_args == 1 ) ); break; default: @@ -1971,6 +2019,10 @@ return error; case cff_op_endchar: + /* in dictionaries, `endchar' simply indicates end of data */ + if ( in_dict ) + return error; + FT_TRACE4(( " endchar\n" )); /* We are going to emulate the seac operator. */ @@ -2082,15 +2134,14 @@ if ( args[0] > 0 ) { - FT_Int count = 9; - FT_Fixed root = args[0]; + FT_Fixed root = args[0]; FT_Fixed new_root; for (;;) { new_root = ( root + FT_DivFix( args[0], root ) + 1 ) >> 1; - if ( new_root == root || count <= 0 ) + if ( new_root == root ) break; root = new_root; } @@ -2199,6 +2250,10 @@ FT_TRACE4(( " put\n" )); + /* the Type2 specification before version 16-March-2000 */ + /* didn't give a hard-coded size limit of the temporary */ + /* storage array; instead, an argument of the */ + /* `MultipleMaster' operator set the size */ if ( idx >= 0 && idx < CFF_MAX_TRANS_ELEMENTS ) decoder->buildchar[idx] = val; } @@ -2221,14 +2276,68 @@ break; case cff_op_store: - FT_TRACE4(( " store\n")); + /* this operator was removed from the Type2 specification */ + /* in version 16-March-2000 */ - goto Unimplemented; + /* since we currently don't handle interpolation of multiple */ + /* master fonts, this is a no-op */ + FT_TRACE4(( " store\n")); + break; case cff_op_load: - FT_TRACE4(( " load\n" )); + /* this operator was removed from the Type2 specification */ + /* in version 16-March-2000 */ + { + FT_Int reg_idx = (FT_Int)args[0]; + FT_Int idx = (FT_Int)args[1]; + FT_Int count = (FT_Int)args[2]; + + + FT_TRACE4(( " load\n" )); + + /* since we currently don't handle interpolation of multiple */ + /* master fonts, we store a vector [1 0 0 ...] in the */ + /* temporary storage array regardless of the Registry index */ + if ( reg_idx >= 0 && reg_idx <= 2 && + idx >= 0 && idx < CFF_MAX_TRANS_ELEMENTS && + count >= 0 && count <= num_axes ) + { + FT_Int end, i; + + + end = FT_MIN( idx + count, CFF_MAX_TRANS_ELEMENTS ); + + if ( idx < end ) + decoder->buildchar[idx] = 1 << 16; + + for ( i = idx + 1; i < end; i++ ) + decoder->buildchar[i] = 0; + } + } + break; - goto Unimplemented; + case cff_op_blend: + /* this operator was removed from the Type2 specification */ + /* in version 16-March-2000 */ + { + FT_Int num_results = (FT_Int)( args[0] >> 16 ); + + + FT_TRACE4(( " blend\n" )); + + if ( num_results < 0 ) + goto Syntax_Error; + + if ( num_results * (FT_Int)num_designs > num_args ) + goto Stack_Underflow; + + /* since we currently don't handle interpolation of multiple */ + /* master fonts, return the `num_results' values of the */ + /* first master */ + args -= num_results * ( num_designs - 1 ); + num_args -= num_results * ( num_designs - 1 ); + } + break; case cff_op_dotsection: /* this operator is deprecated and ignored by the parser */ @@ -2336,7 +2445,7 @@ case cff_op_and: { - FT_Fixed cond = args[0] && args[1]; + FT_Fixed cond = ( args[0] && args[1] ); FT_TRACE4(( " and\n" )); @@ -2348,7 +2457,7 @@ case cff_op_or: { - FT_Fixed cond = args[0] || args[1]; + FT_Fixed cond = ( args[0] || args[1] ); FT_TRACE4(( " or\n" )); @@ -2358,11 +2467,23 @@ } break; - case cff_op_eq: + case cff_op_not: { FT_Fixed cond = !args[0]; + FT_TRACE4(( " not\n" )); + + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + + case cff_op_eq: + { + FT_Fixed cond = ( args[0] == args[1] ); + + FT_TRACE4(( " eq\n" )); args[0] = cond ? 0x10000L : 0; @@ -2489,7 +2610,6 @@ break; default: - Unimplemented: FT_ERROR(( "Unimplemented opcode: %d", ip[-1] )); if ( ip[-1] == 12 ) @@ -2513,6 +2633,11 @@ Fail: return error; + MM_Error: + FT_TRACE4(( "cff_decoder_parse_charstrings:" + " invalid opcode found in top DICT charstring\n")); + return FT_THROW( Invalid_File_Format ); + Syntax_Error: FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error\n" )); return FT_THROW( Invalid_File_Format ); @@ -2586,7 +2711,8 @@ if ( !error ) error = cff_decoder_parse_charstrings( &decoder, charstring, - charstring_len ); + charstring_len, + 0 ); cff_free_glyph_data( face, &charstring, &charstring_len ); } @@ -2816,6 +2942,7 @@ cff_decoder_init( &decoder, face, size, glyph, hinting, FT_LOAD_TARGET_MODE( load_flags ) ); + /* this is for pure CFFs */ if ( load_flags & FT_LOAD_ADVANCE_ONLY ) decoder.width_only = TRUE; @@ -2837,7 +2964,8 @@ if ( driver->hinting_engine == FT_CFF_HINTING_FREETYPE ) error = cff_decoder_parse_charstrings( &decoder, charstring, - charstring_len ); + charstring_len, + 0 ); else #endif { diff --git a/third_party/freetype/src/cff/cffgload.h b/third_party/freetype/src/cff/cffgload.h index 5f2655f3d9..0fa93b4398 100644 --- a/third_party/freetype/src/cff/cffgload.h +++ b/third_party/freetype/src/cff/cffgload.h @@ -4,7 +4,7 @@ /* */ /* OpenType Glyph Loader (specification). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2017 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,8 +16,8 @@ /***************************************************************************/ -#ifndef __CFFGLOAD_H__ -#define __CFFGLOAD_H__ +#ifndef CFFGLOAD_H_ +#define CFFGLOAD_H_ #include <ft2build.h> @@ -227,7 +227,8 @@ FT_BEGIN_HEADER FT_LOCAL( FT_Error ) cff_decoder_parse_charstrings( CFF_Decoder* decoder, FT_Byte* charstring_base, - FT_ULong charstring_len ); + FT_ULong charstring_len, + FT_Bool in_dict ); #endif FT_LOCAL( FT_Error ) @@ -239,7 +240,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CFFGLOAD_H__ */ +#endif /* CFFGLOAD_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cffload.c b/third_party/freetype/src/cff/cffload.c index c61222d651..935e612a09 100644 --- a/third_party/freetype/src/cff/cffload.c +++ b/third_party/freetype/src/cff/cffload.c @@ -4,7 +4,7 @@ /* */ /* OpenType and CFF data/program tables loader (body). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2017 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -23,12 +23,20 @@ #include FT_TRUETYPE_TAGS_H #include FT_TYPE1_TABLES_H +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include FT_MULTIPLE_MASTERS_H +#include FT_SERVICE_MULTIPLE_MASTERS_H +#endif + #include "cffload.h" #include "cffparse.h" #include "cfferrs.h" +#define FT_FIXED_ONE ( (FT_Fixed)0x10000 ) + + #if 1 static const FT_UShort cff_isoadobe_charset[229] = @@ -225,19 +233,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_MEM_ZERO( idx, sizeof ( *idx ) ); + 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 +280,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; @@ -310,7 +332,7 @@ FT_FRAME_RELEASE( idx->bytes ); FT_FREE( idx->offsets ); - FT_MEM_ZERO( idx, sizeof ( *idx ) ); + FT_ZERO( idx ); } } @@ -323,7 +345,7 @@ FT_Memory memory = stream->memory; - if ( idx->count > 0 && idx->offsets == NULL ) + if ( idx->count > 0 && !idx->offsets ) { FT_Byte offsize = idx->off_size; FT_ULong data_size; @@ -335,7 +357,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; @@ -382,28 +404,31 @@ static FT_Error cff_index_get_pointers( CFF_Index idx, FT_Byte*** table, - FT_Byte** pool ) + FT_Byte** pool, + FT_ULong* pool_size ) { FT_Error error = FT_Err_Ok; FT_Memory memory = idx->stream->memory; FT_Byte** t = NULL; FT_Byte* new_bytes = NULL; + FT_ULong new_size; *table = NULL; - if ( idx->offsets == NULL ) + if ( !idx->offsets ) { error = cff_index_load_offsets( idx ); if ( error ) goto Exit; } - if ( idx->count > 0 && - !FT_NEW_ARRAY( t, idx->count + 1 ) && - ( !pool || !FT_ALLOC( new_bytes, - idx->data_size + idx->count ) ) ) + new_size = idx->data_size + idx->count; + + if ( idx->count > 0 && + !FT_NEW_ARRAY( t, idx->count + 1 ) && + ( !pool || !FT_ALLOC( new_bytes, new_size ) ) ) { FT_ULong n, cur_offset; FT_ULong extra = 0; @@ -459,6 +484,8 @@ if ( pool ) *pool = new_bytes; + if ( pool_size ) + *pool_size = new_size; } Exit: @@ -488,7 +515,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 ); @@ -501,8 +528,8 @@ { element++; off2 = cff_index_read_offset( idx, &error ); - } - while ( off2 == 0 && element < idx->count ); + + } while ( off2 == 0 && element < idx->count ); } } else /* use offsets table */ @@ -584,20 +611,26 @@ 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; if ( !FT_ALLOC( name, byte_len + 1 ) ) { - FT_MEM_COPY( name, bytes, byte_len ); + if ( byte_len ) + FT_MEM_COPY( name, bytes, byte_len ); name[byte_len] = 0; } cff_index_forget_element( idx, &bytes ); @@ -719,6 +752,11 @@ FT_Byte fd = 0; + /* if there is no FDSelect, return zero */ + /* Note: CFF2 with just one Font Dict has no FDSelect */ + if ( !fdselect->data ) + goto Exit; + switch ( fdselect->format ) { case 0: @@ -771,6 +809,7 @@ ; } + Exit: return fd; } @@ -809,7 +848,7 @@ /* When multiple GIDs map to the same CID, we choose the lowest */ /* GID. This is not described in any spec, but it matches the */ /* behaviour of recent Acroread versions. */ - for ( j = (FT_Long)num_glyphs - 1; j >= 0 ; j-- ) + for ( j = (FT_Long)num_glyphs - 1; j >= 0; j-- ) charset->cids[charset->sids[j]] = (FT_UShort)j; charset->max_cid = max_cid; @@ -871,8 +910,8 @@ FT_UShort glyph_sid; - /* If the the offset is greater than 2, we have to parse the */ - /* charset table. */ + /* If the offset is greater than 2, we have to parse the charset */ + /* table. */ if ( offset > 2 ) { FT_UInt j; @@ -1049,6 +1088,512 @@ static void + cff_vstore_done( CFF_VStoreRec* vstore, + FT_Memory memory ) + { + FT_UInt i; + + + /* free regionList and axisLists */ + if ( vstore->varRegionList ) + { + for ( i = 0; i < vstore->regionCount; i++ ) + FT_FREE( vstore->varRegionList[i].axisList ); + } + FT_FREE( vstore->varRegionList ); + + /* free varData and indices */ + if ( vstore->varData ) + { + for ( i = 0; i < vstore->dataCount; i++ ) + FT_FREE( vstore->varData[i].regionIndices ); + } + FT_FREE( vstore->varData ); + } + + + /* convert 2.14 to Fixed */ + #define FT_fdot14ToFixed( x ) ( (FT_Fixed)( (FT_ULong)(x) << 2 ) ) + + + static FT_Error + cff_vstore_load( CFF_VStoreRec* vstore, + FT_Stream stream, + FT_ULong base_offset, + FT_ULong offset ) + { + FT_Memory memory = stream->memory; + FT_Error error = FT_ERR( Invalid_File_Format ); + + FT_ULong* dataOffsetArray = NULL; + FT_UInt i, j; + + + /* no offset means no vstore to parse */ + if ( offset ) + { + FT_UInt vsOffset; + FT_UInt format; + FT_ULong regionListOffset; + + + /* we need to parse the table to determine its size; */ + /* skip table length */ + if ( FT_STREAM_SEEK( base_offset + offset ) || + FT_STREAM_SKIP( 2 ) ) + goto Exit; + + /* actual variation store begins after the length */ + vsOffset = FT_STREAM_POS(); + + /* check the header */ + if ( FT_READ_USHORT( format ) ) + goto Exit; + if ( format != 1 ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* read top level fields */ + if ( FT_READ_ULONG( regionListOffset ) || + FT_READ_USHORT( vstore->dataCount ) ) + goto Exit; + + /* make temporary copy of item variation data offsets; */ + /* we'll parse region list first, then come back */ + if ( FT_NEW_ARRAY( dataOffsetArray, vstore->dataCount ) ) + goto Exit; + + for ( i = 0; i < vstore->dataCount; i++ ) + { + if ( FT_READ_ULONG( dataOffsetArray[i] ) ) + goto Exit; + } + + /* parse regionList and axisLists */ + if ( FT_STREAM_SEEK( vsOffset + regionListOffset ) || + FT_READ_USHORT( vstore->axisCount ) || + FT_READ_USHORT( vstore->regionCount ) ) + goto Exit; + + if ( FT_NEW_ARRAY( vstore->varRegionList, vstore->regionCount ) ) + goto Exit; + + for ( i = 0; i < vstore->regionCount; i++ ) + { + CFF_VarRegion* region = &vstore->varRegionList[i]; + + + if ( FT_NEW_ARRAY( region->axisList, vstore->axisCount ) ) + goto Exit; + + for ( j = 0; j < vstore->axisCount; j++ ) + { + CFF_AxisCoords* axis = ®ion->axisList[j]; + + FT_Int16 start14, peak14, end14; + + + if ( FT_READ_SHORT( start14 ) || + FT_READ_SHORT( peak14 ) || + FT_READ_SHORT( end14 ) ) + goto Exit; + + axis->startCoord = FT_fdot14ToFixed( start14 ); + axis->peakCoord = FT_fdot14ToFixed( peak14 ); + axis->endCoord = FT_fdot14ToFixed( end14 ); + } + } + + /* use dataOffsetArray now to parse varData items */ + if ( FT_NEW_ARRAY( vstore->varData, vstore->dataCount ) ) + goto Exit; + + for ( i = 0; i < vstore->dataCount; i++ ) + { + CFF_VarData* data = &vstore->varData[i]; + + + if ( FT_STREAM_SEEK( vsOffset + dataOffsetArray[i] ) ) + goto Exit; + + /* ignore `itemCount' and `shortDeltaCount' */ + /* because CFF2 has no delta sets */ + if ( FT_STREAM_SKIP( 4 ) ) + goto Exit; + + /* Note: just record values; consistency is checked later */ + /* by cff_blend_build_vector when it consumes `vstore' */ + + if ( FT_READ_USHORT( data->regionIdxCount ) ) + goto Exit; + + if ( FT_NEW_ARRAY( data->regionIndices, data->regionIdxCount ) ) + goto Exit; + + for ( j = 0; j < data->regionIdxCount; j++ ) + { + if ( FT_READ_USHORT( data->regionIndices[j] ) ) + goto Exit; + } + } + } + + error = FT_Err_Ok; + + Exit: + FT_FREE( dataOffsetArray ); + if ( error ) + cff_vstore_done( vstore, memory ); + + return error; + } + + + /* Clear blend stack (after blend values are consumed). */ + /* */ + /* TODO: Should do this in cff_run_parse, but subFont */ + /* ref is not available there. */ + /* */ + /* Allocation is not changed when stack is cleared. */ + FT_LOCAL_DEF( void ) + cff_blend_clear( CFF_SubFont subFont ) + { + subFont->blend_top = subFont->blend_stack; + subFont->blend_used = 0; + } + + + /* Blend numOperands on the stack, */ + /* store results into the first numBlends values, */ + /* then pop remaining arguments. */ + /* */ + /* This is comparable to `cf2_doBlend' but */ + /* the cffparse stack is different and can't be written. */ + /* Blended values are written to a different buffer, */ + /* using reserved operator 255. */ + /* */ + /* Blend calculation is done in 16.16 fixed point. */ + FT_LOCAL_DEF( FT_Error ) + cff_blend_doBlend( CFF_SubFont subFont, + CFF_Parser parser, + FT_UInt numBlends ) + { + FT_UInt delta; + FT_UInt base; + FT_UInt i, j; + FT_UInt size; + + CFF_Blend blend = &subFont->blend; + + FT_Memory memory = subFont->blend.font->memory; /* for FT_REALLOC */ + FT_Error error = FT_Err_Ok; /* for FT_REALLOC */ + + /* compute expected number of operands for this blend */ + FT_UInt numOperands = (FT_UInt)( numBlends * blend->lenBV ); + FT_UInt count = (FT_UInt)( parser->top - 1 - parser->stack ); + + + if ( numOperands > count ) + { + FT_TRACE4(( " cff_blend_doBlend: Stack underflow %d args\n", count )); + + error = FT_THROW( Stack_Underflow ); + goto Exit; + } + + /* check whether we have room for `numBlends' values at `blend_top' */ + size = 5 * numBlends; /* add 5 bytes per entry */ + if ( subFont->blend_used + size > subFont->blend_alloc ) + { + FT_Byte* blend_stack_old = subFont->blend_stack; + FT_Byte* blend_top_old = subFont->blend_top; + + + /* increase or allocate `blend_stack' and reset `blend_top'; */ + /* prepare to append `numBlends' values to the buffer */ + if ( FT_REALLOC( subFont->blend_stack, + subFont->blend_alloc, + subFont->blend_alloc + size ) ) + goto Exit; + + subFont->blend_top = subFont->blend_stack + subFont->blend_used; + subFont->blend_alloc += size; + + /* iterate over the parser stack and adjust pointers */ + /* if the reallocated buffer has a different address */ + if ( blend_stack_old && + subFont->blend_stack != blend_stack_old ) + { + FT_PtrDist offset = subFont->blend_stack - blend_stack_old; + FT_Byte** p; + + + for ( p = parser->stack; p < parser->top; p++ ) + { + if ( *p >= blend_stack_old && *p < blend_top_old ) + *p += offset; + } + } + } + subFont->blend_used += size; + + base = count - numOperands; /* index of first blend arg */ + delta = base + numBlends; /* index of first delta arg */ + + for ( i = 0; i < numBlends; i++ ) + { + const FT_Int32* weight = &blend->BV[1]; + FT_Int32 sum; + + + /* convert inputs to 16.16 fixed point */ + sum = cff_parse_num( parser, &parser->stack[i + base] ) * 65536; + + for ( j = 1; j < blend->lenBV; j++ ) + sum += FT_MulFix( *weight++, + cff_parse_num( parser, + &parser->stack[delta++] ) * 65536 ); + + /* point parser stack to new value on blend_stack */ + parser->stack[i + base] = subFont->blend_top; + + /* Push blended result as Type 2 5-byte fixed point number. This */ + /* will not conflict with actual DICTs because 255 is a reserved */ + /* opcode in both CFF and CFF2 DICTs. See `cff_parse_num' for */ + /* decode of this, which rounds to an integer. */ + *subFont->blend_top++ = 255; + *subFont->blend_top++ = ( (FT_UInt32)sum & 0xFF000000U ) >> 24; + *subFont->blend_top++ = ( (FT_UInt32)sum & 0x00FF0000U ) >> 16; + *subFont->blend_top++ = ( (FT_UInt32)sum & 0x0000FF00U ) >> 8; + *subFont->blend_top++ = (FT_UInt32)sum & 0x000000FFU; + } + + /* leave only numBlends results on parser stack */ + parser->top = &parser->stack[base + numBlends]; + + Exit: + return error; + } + + + /* Compute a blend vector from variation store index and normalized */ + /* vector based on pseudo-code in OpenType Font Variations Overview. */ + /* */ + /* Note: lenNDV == 0 produces a default blend vector, (1,0,0,...). */ + FT_LOCAL_DEF( FT_Error ) + cff_blend_build_vector( CFF_Blend blend, + FT_UInt vsindex, + FT_UInt lenNDV, + FT_Fixed* NDV ) + { + FT_Error error = FT_Err_Ok; /* for FT_REALLOC */ + FT_Memory memory = blend->font->memory; /* for FT_REALLOC */ + + FT_UInt len; + CFF_VStore vs; + CFF_VarData* varData; + FT_UInt master; + + + FT_ASSERT( lenNDV == 0 || NDV ); + + blend->builtBV = FALSE; + + vs = &blend->font->vstore; + + /* VStore and fvar must be consistent */ + if ( lenNDV != 0 && lenNDV != vs->axisCount ) + { + FT_TRACE4(( " cff_blend_build_vector: Axis count mismatch\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( vsindex >= vs->dataCount ) + { + FT_TRACE4(( " cff_blend_build_vector: vsindex out of range\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* select the item variation data structure */ + varData = &vs->varData[vsindex]; + + /* prepare buffer for the blend vector */ + len = varData->regionIdxCount + 1; /* add 1 for default component */ + if ( FT_REALLOC( blend->BV, + blend->lenBV * sizeof( *blend->BV ), + len * sizeof( *blend->BV ) ) ) + goto Exit; + + blend->lenBV = len; + + /* outer loop steps through master designs to be blended */ + for ( master = 0; master < len; master++ ) + { + FT_UInt j; + FT_UInt idx; + CFF_VarRegion* varRegion; + + + /* default factor is always one */ + if ( master == 0 ) + { + blend->BV[master] = FT_FIXED_ONE; + FT_TRACE4(( " build blend vector len %d\n" + " [ %f ", + len, + blend->BV[master] / 65536.0 )); + continue; + } + + /* VStore array does not include default master, so subtract one */ + idx = varData->regionIndices[master - 1]; + varRegion = &vs->varRegionList[idx]; + + if ( idx >= vs->regionCount ) + { + FT_TRACE4(( " cff_blend_build_vector:" + " region index out of range\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* Note: `lenNDV' could be zero. */ + /* In that case, build default blend vector (1,0,0...). */ + /* In the normal case, initialize each component to 1 */ + /* before inner loop. */ + if ( lenNDV != 0 ) + blend->BV[master] = FT_FIXED_ONE; /* default */ + + /* inner loop steps through axes in this region */ + for ( j = 0; j < lenNDV; j++ ) + { + CFF_AxisCoords* axis = &varRegion->axisList[j]; + FT_Fixed axisScalar; + + + /* compute the scalar contribution of this axis; */ + /* ignore invalid ranges */ + if ( axis->startCoord > axis->peakCoord || + axis->peakCoord > axis->endCoord ) + axisScalar = FT_FIXED_ONE; + + else if ( axis->startCoord < 0 && + axis->endCoord > 0 && + axis->peakCoord != 0 ) + axisScalar = FT_FIXED_ONE; + + /* peak of 0 means ignore this axis */ + else if ( axis->peakCoord == 0 ) + axisScalar = FT_FIXED_ONE; + + /* ignore this region if coords are out of range */ + else if ( NDV[j] < axis->startCoord || + NDV[j] > axis->endCoord ) + axisScalar = 0; + + /* calculate a proportional factor */ + else + { + if ( NDV[j] == axis->peakCoord ) + axisScalar = FT_FIXED_ONE; + else if ( NDV[j] < axis->peakCoord ) + axisScalar = FT_DivFix( NDV[j] - axis->startCoord, + axis->peakCoord - axis->startCoord ); + else + axisScalar = FT_DivFix( axis->endCoord - NDV[j], + axis->endCoord - axis->peakCoord ); + } + + /* take product of all the axis scalars */ + blend->BV[master] = FT_MulFix( blend->BV[master], axisScalar ); + } + + FT_TRACE4(( ", %f ", + blend->BV[master] / 65536.0 )); + } + + FT_TRACE4(( "]\n" )); + + /* record the parameters used to build the blend vector */ + blend->lastVsindex = vsindex; + + if ( lenNDV != 0 ) + { + /* user has set a normalized vector */ + if ( FT_REALLOC( blend->lastNDV, + blend->lenNDV * sizeof ( *NDV ), + lenNDV * sizeof ( *NDV ) ) ) + goto Exit; + + blend->lenNDV = lenNDV; + FT_MEM_COPY( blend->lastNDV, + NDV, + lenNDV * sizeof ( *NDV ) ); + } + + blend->builtBV = TRUE; + + Exit: + return error; + } + + + /* `lenNDV' is zero for default vector; */ + /* return TRUE if blend vector needs to be built. */ + FT_LOCAL_DEF( FT_Bool ) + cff_blend_check_vector( CFF_Blend blend, + FT_UInt vsindex, + FT_UInt lenNDV, + FT_Fixed* NDV ) + { + if ( !blend->builtBV || + blend->lastVsindex != vsindex || + blend->lenNDV != lenNDV || + ( lenNDV && + memcmp( NDV, + blend->lastNDV, + lenNDV * sizeof ( *NDV ) ) != 0 ) ) + { + /* need to build blend vector */ + return TRUE; + } + + return FALSE; + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + FT_LOCAL_DEF( FT_Error ) + cff_get_var_blend( CFF_Face face, + FT_UInt *num_coords, + FT_Fixed* *coords, + FT_MM_Var* *mm_var ) + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + return mm->get_var_blend( FT_FACE( face ), num_coords, coords, mm_var ); + } + + + FT_LOCAL_DEF( void ) + cff_done_blend( CFF_Face face ) + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + mm->done_blend( FT_FACE( face ) ); + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + + static void cff_encoding_done( CFF_Encoding encoding ) { encoding->format = 0; @@ -1300,26 +1845,127 @@ } + /* Parse private dictionary; first call is always from `cff_face_init', */ + /* so NDV has not been set for CFF2 variation. */ + /* */ + /* `cff_slot_load' must call this function each time NDV changes. */ + FT_LOCAL_DEF( FT_Error ) + cff_load_private_dict( CFF_Font font, + CFF_SubFont subfont, + FT_UInt lenNDV, + FT_Fixed* NDV ) + { + FT_Error error = FT_Err_Ok; + CFF_ParserRec parser; + CFF_FontRecDict top = &subfont->font_dict; + CFF_Private priv = &subfont->private_dict; + FT_Stream stream = font->stream; + FT_UInt stackSize; + + + /* store handle needed to access memory, vstore for blend; */ + /* we need this for clean-up even if there is no private DICT */ + subfont->blend.font = font; + subfont->blend.usedBV = FALSE; /* clear state */ + + if ( !top->private_offset || !top->private_size ) + goto Exit2; /* no private DICT, do nothing */ + + /* set defaults */ + FT_ZERO( priv ); + + priv->blue_shift = 7; + priv->blue_fuzz = 1; + priv->lenIV = -1; + priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); + priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 ); + + /* provide inputs for blend calculations */ + priv->subfont = subfont; + subfont->lenNDV = lenNDV; + subfont->NDV = NDV; + + stackSize = font->cff2 ? font->top_font.font_dict.maxstack + : CFF_MAX_STACK_DEPTH + 1; + + if ( cff_parser_init( &parser, + font->cff2 ? CFF2_CODE_PRIVATE : CFF_CODE_PRIVATE, + priv, + font->library, + stackSize, + top->num_designs, + top->num_axes ) ) + goto Exit; + + if ( FT_STREAM_SEEK( font->base_offset + top->private_offset ) || + FT_FRAME_ENTER( top->private_size ) ) + goto Exit; + + FT_TRACE4(( " private dictionary:\n" )); + error = cff_parser_run( &parser, + (FT_Byte*)stream->cursor, + (FT_Byte*)stream->limit ); + FT_FRAME_EXIT(); + + if ( error ) + goto Exit; + + /* ensure that `num_blue_values' is even */ + priv->num_blue_values &= ~1; + + Exit: + /* clean up */ + cff_blend_clear( subfont ); /* clear blend stack */ + cff_parser_done( &parser ); /* free parser stack */ + + Exit2: + /* no clean up (parser not initialized) */ + return error; + } + + + /* 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 font, + cff_subfont_load( CFF_SubFont subfont, CFF_Index idx, FT_UInt font_index, FT_Stream stream, FT_ULong base_offset, - FT_Library library ) + FT_UInt code, + CFF_Font font ) { FT_Error error; CFF_ParserRec parser; FT_Byte* dict = NULL; FT_ULong dict_len; - CFF_FontRecDict top = &font->font_dict; - CFF_Private priv = &font->private_dict; - - - cff_parser_init( &parser, CFF_CODE_TOPDICT, &font->font_dict, library ); + CFF_FontRecDict top = &subfont->font_dict; + CFF_Private priv = &subfont->private_dict; + + FT_Bool cff2 = FT_BOOL( 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. */ + error = cff_parser_init( &parser, + code, + &subfont->font_dict, + font->library, + stackSize, + 0, + 0 ); + if ( error ) + goto Exit; /* set defaults */ - FT_MEM_ZERO( top, sizeof ( *top ) ); + FT_ZERO( top ); top->underline_position = -( 100L << 16 ); top->underline_thickness = 50L << 16; @@ -1342,14 +1988,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; @@ -1358,35 +2025,14 @@ if ( top->cid_registry != 0xFFFFU ) goto Exit; - /* parse the private dictionary, if any */ - if ( top->private_offset && top->private_size ) - { - /* set defaults */ - FT_MEM_ZERO( priv, sizeof ( *priv ) ); - - priv->blue_shift = 7; - priv->blue_fuzz = 1; - priv->lenIV = -1; - priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); - priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 ); - - cff_parser_init( &parser, CFF_CODE_PRIVATE, priv, library ); - - if ( FT_STREAM_SEEK( base_offset + font->font_dict.private_offset ) || - FT_FRAME_ENTER( font->font_dict.private_size ) ) - goto Exit; - - FT_TRACE4(( " private dictionary:\n" )); - error = cff_parser_run( &parser, - (FT_Byte*)stream->cursor, - (FT_Byte*)stream->limit ); - FT_FRAME_EXIT(); - if ( error ) - goto Exit; - - /* ensure that `num_blue_values' is even */ - priv->num_blue_values &= ~1; - } + /* 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, 0, 0 ); + if ( error ) + goto Exit; /* read the local subrs, if any */ if ( priv->local_subrs_offset ) @@ -1395,17 +2041,19 @@ priv->local_subrs_offset ) ) goto Exit; - error = cff_index_init( &font->local_subrs_index, stream, 1 ); + error = cff_index_init( &subfont->local_subrs_index, stream, 1, cff2 ); if ( error ) goto Exit; - error = cff_index_get_pointers( &font->local_subrs_index, - &font->local_subrs, NULL ); + error = cff_index_get_pointers( &subfont->local_subrs_index, + &subfont->local_subrs, NULL, NULL ); if ( error ) goto Exit; } Exit: + cff_parser_done( &parser ); /* free parser stack */ + return error; } @@ -1418,6 +2066,10 @@ { cff_index_done( &subfont->local_subrs_index ); FT_FREE( subfont->local_subrs ); + + FT_FREE( subfont->blend.lastNDV ); + FT_FREE( subfont->blend.BV ); + FT_FREE( subfont->blend_stack ); } } @@ -1427,18 +2079,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 }; @@ -1453,42 +2105,131 @@ FT_ZERO( font ); FT_ZERO( &string_index ); - font->stream = stream; - font->memory = memory; - dict = &font->top_font.font_dict; - base_offset = FT_STREAM_POS(); + dict = &font->top_font.font_dict; + base_offset = FT_STREAM_POS(); + + 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 + { + FT_Byte absolute_offset; + + + if ( FT_READ_BYTE( absolute_offset ) ) + goto Exit; + + if ( font->version_major != 1 || + font->header_size < 4 || + absolute_offset > 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 ) ) + { + /* For pure CFFs we have read only four bytes so far. Contrary to */ + /* other formats like SFNT those bytes doesn't define a signature; */ + /* it is thus possible that the font isn't a CFF at all. */ + if ( pure_cff ) + { + FT_TRACE2(( " not a CFF file\n" )); + error = FT_THROW( Unknown_File_Format ); + } 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 ) ) ) - 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 ) ) ) + { + if ( pure_cff ) + { + FT_TRACE2(( " not a CFF file\n" )); + error = FT_THROW( Unknown_File_Format ); + } + goto Exit; + } + + /* font names must not be empty */ + if ( font->name_index.data_size < font->name_index.count ) + { + /* for pure CFFs, we still haven't checked enough bytes */ + /* to be sure that it is a CFF at all */ + error = pure_cff ? FT_THROW( Unknown_File_Format ) + : FT_THROW( Invalid_File_Format ); + goto Exit; + } + + if ( 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; + + /* there must be a Top DICT index entry for each name index entry */ + if ( font->name_index.count > font->font_dict_index.count ) + { + FT_ERROR(( "cff_font_load:" + " not enough entries in Top DICT index\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + } font->num_strings = string_index.count; @@ -1534,34 +2275,47 @@ subfont_index, stream, base_offset, - library ); + cff2 ? CFF2_CODE_TOPDICT : CFF_CODE_TOPDICT, + font ); if ( error ) goto Exit; 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; FT_UInt idx; + /* for CFF2, read the Variation Store if available; */ + /* this must follow the Top DICT parse and precede any Private DICT */ + error = cff_vstore_load( &font->vstore, + stream, + base_offset, + dict->vstore_offset ); + if ( error ) + goto Exit; + /* this is a CID-keyed font, we must now allocate a table of */ /* sub-fonts, then load each of them separately */ 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" )); @@ -1582,17 +2336,25 @@ { sub = font->subfonts[idx]; FT_TRACE4(( "parsing subfont %u\n", idx )); - error = cff_subfont_load( sub, &fd_index, idx, - stream, base_offset, library ); + error = cff_subfont_load( sub, + &fd_index, + 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 ); @@ -1614,13 +2376,13 @@ font->num_glyphs = font->charstrings_index.count; error = cff_index_get_pointers( &font->global_subrs_index, - &font->global_subrs, NULL ); + &font->global_subrs, NULL, NULL ); if ( error ) 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 ); @@ -1668,7 +2430,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++ ) @@ -1680,6 +2442,7 @@ cff_encoding_done( &font->encoding ); cff_charset_done( &font->charset, font->stream ); + cff_vstore_done( &font->vstore, memory ); cff_subfont_done( memory, &font->top_font ); diff --git a/third_party/freetype/src/cff/cffload.h b/third_party/freetype/src/cff/cffload.h index 459e7b0446..8be645261b 100644 --- a/third_party/freetype/src/cff/cffload.h +++ b/third_party/freetype/src/cff/cffload.h @@ -4,7 +4,7 @@ /* */ /* OpenType & CFF data/program tables loader (specification). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2017 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,12 +16,14 @@ /***************************************************************************/ -#ifndef __CFFLOAD_H__ -#define __CFFLOAD_H__ +#ifndef CFFLOAD_H_ +#define CFFLOAD_H_ #include <ft2build.h> #include "cfftypes.h" +#include "cffparse.h" +#include "cffobjs.h" /* for CFF_Face */ FT_BEGIN_HEADER @@ -60,24 +62,62 @@ 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 ); + FT_LOCAL( FT_Error ) + cff_load_private_dict( CFF_Font font, + CFF_SubFont subfont, + FT_UInt lenNDV, + FT_Fixed* NDV ); + FT_LOCAL( FT_Byte ) cff_fd_select_get( CFF_FDSelect fdselect, FT_UInt glyph_index ); + FT_LOCAL( FT_Bool ) + cff_blend_check_vector( CFF_Blend blend, + FT_UInt vsindex, + FT_UInt lenNDV, + FT_Fixed* NDV ); + + FT_LOCAL( FT_Error ) + cff_blend_build_vector( CFF_Blend blend, + FT_UInt vsindex, + FT_UInt lenNDV, + FT_Fixed* NDV ); + + FT_LOCAL( void ) + cff_blend_clear( CFF_SubFont subFont ); + + FT_LOCAL( FT_Error ) + cff_blend_doBlend( CFF_SubFont subfont, + CFF_Parser parser, + FT_UInt numBlends ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_LOCAL( FT_Error ) + cff_get_var_blend( CFF_Face face, + FT_UInt *num_coords, + FT_Fixed* *coords, + FT_MM_Var* *mm_var ); + + FT_LOCAL( void ) + cff_done_blend( CFF_Face face ); +#endif + FT_END_HEADER -#endif /* __CFFLOAD_H__ */ +#endif /* CFFLOAD_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cffobjs.c b/third_party/freetype/src/cff/cffobjs.c index 0e0d5b034b..a63935002c 100644 --- a/third_party/freetype/src/cff/cffobjs.c +++ b/third_party/freetype/src/cff/cffobjs.c @@ -4,7 +4,7 @@ /* */ /* OpenType objects manager (body). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2017 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -114,7 +114,7 @@ FT_UInt n, count; - FT_MEM_ZERO( priv, sizeof ( *priv ) ); + FT_ZERO( priv ); count = priv->num_blue_values = cpriv->num_blue_values; for ( n = 0; n < count; n++ ) @@ -450,7 +450,7 @@ FT_Int idx; - for ( idx = 1; idx <= style_name_length; ++idx ) + for ( idx = 1; idx <= style_name_length; idx++ ) { if ( family_name[family_name_length - idx] != style_name[style_name_length - idx] ) @@ -469,7 +469,7 @@ family_name[idx] == ' ' || family_name[idx] == '_' || family_name[idx] == '+' ) ) - --idx; + idx--; if ( idx > 0 ) family_name[idx + 1] = '\0'; @@ -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; @@ -516,6 +517,7 @@ goto Exit; /* check whether we have a valid OpenType file */ + FT_TRACE2(( " " )); error = sfnt->init_face( stream, face, face_index, num_params, params ); if ( !error ) { @@ -553,8 +555,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,14 +591,22 @@ 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; /* if we are performing a simple font format check, exit immediately */ /* (this is here for pure CFF) */ if ( face_index < 0 ) + { + cffface->num_faces = (FT_Long)cff->num_faces; return FT_Err_Ok; + } cff->pshinter = pshinter; cff->psnames = psnames; @@ -622,22 +642,112 @@ FT_TRACE4(( "SIDs\n" )); /* dump string index, including default strings for convenience */ - for ( idx = 0; idx < cff->num_strings + 390; idx++ ) + for ( idx = 0; idx <= 390; idx++ ) { s = cff_index_get_sid_string( cff, idx ); if ( s ) - FT_TRACE4((" %5d %s\n", idx, s )); + FT_TRACE4(( " %5d %s\n", idx, s )); + } + + /* In Multiple Master CFFs, two SIDs hold the Normalize Design */ + /* Vector (NDV) and Convert Design Vector (CDV) charstrings, */ + /* which may contain NULL bytes in the middle of the data, too. */ + /* We thus access `cff->strings' directly. */ + for ( idx = 1; idx < cff->num_strings; idx++ ) + { + FT_Byte* s1 = cff->strings[idx - 1]; + FT_Byte* s2 = cff->strings[idx]; + FT_PtrDist s1len = s2 - s1 - 1; /* without the final NULL byte */ + FT_PtrDist l; + + + FT_TRACE4(( " %5d ", idx + 390 )); + for ( l = 0; l < s1len; l++ ) + FT_TRACE4(( "%c", s1[l] )); + FT_TRACE4(( "\n" )); + } + + /* print last element */ + if ( cff->num_strings ) + { + FT_Byte* s1 = cff->strings[cff->num_strings - 1]; + FT_Byte* s2 = cff->string_pool + cff->string_pool_size; + FT_PtrDist s1len = s2 - s1 - 1; + FT_PtrDist l; + + + FT_TRACE4(( " %5d ", cff->num_strings + 390 )); + for ( l = 0; l < s1len; l++ ) + FT_TRACE4(( "%c", s1[l] )); + FT_TRACE4(( "\n" )); } } #endif /* FT_DEBUG_LEVEL_TRACE */ + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + FT_Int instance_index = face_index >> 16; + + + if ( FT_HAS_MULTIPLE_MASTERS( cffface ) && + mm && + instance_index > 0 ) + { + FT_MM_Var* mm_var; + + + error = mm->get_mm_var( cffface, NULL ); + if ( error ) + goto Exit; + + mm->get_var_blend( cffface, NULL, NULL, &mm_var ); + + if ( mm_var->namedstyle ) + { + FT_Var_Named_Style* named_style; + FT_String* style_name; + + + /* in `face_index', the instance index starts with value 1 */ + named_style = mm_var->namedstyle + instance_index - 1; + error = sfnt->get_name( face, + (FT_UShort)named_style->strid, + &style_name ); + if ( error ) + goto Exit; + + /* set style name; if already set, replace it */ + if ( face->root.style_name ) + FT_FREE( face->root.style_name ); + face->root.style_name = style_name; + + /* finally, select the named instance */ + error = mm->set_var_design( cffface, + mm_var->num_axis, + named_style->coords ); + if ( error ) + goto Exit; + } + } + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + + if ( !dict->has_font_matrix ) dict->units_per_em = pure_cff ? 1000 : face->root.units_per_EM; - /* Normalize the font matrix so that `matrix->yy' is 1; the */ - /* scaling is done with `units_per_em' then (at this point, */ - /* it already contains the scaling factor, but without */ - /* normalization of the matrix). */ + /* Normalize the font matrix so that `matrix->yy' is 1; if */ + /* it is zero, we use `matrix->yx' instead. The scaling is */ + /* done with `units_per_em' then (at this point, it already */ + /* contains the scaling factor, but without normalization */ + /* of the matrix). */ /* */ /* Note that the offsets must be expressed in integer font */ /* units. */ @@ -646,9 +756,12 @@ FT_Matrix* matrix = &dict->font_matrix; FT_Vector* offset = &dict->font_offset; FT_ULong* upm = &dict->units_per_em; - FT_Fixed temp = FT_ABS( matrix->yy ); + FT_Fixed temp; + temp = matrix->yy ? FT_ABS( matrix->yy ) + : FT_ABS( matrix->yx ); + if ( temp != 0x10000L ) { *upm = (FT_ULong)FT_DivFix( (FT_Long)*upm, temp ); @@ -716,7 +829,10 @@ matrix = &sub->font_matrix; offset = &sub->font_offset; upm = &sub->units_per_em; - temp = FT_ABS( matrix->yy ); + + temp = matrix->yy ? FT_ABS( matrix->yy ) + : FT_ABS( matrix->yx ); + if ( temp != 0x10000L ) { @@ -968,7 +1084,7 @@ error = FT_Err_Ok; /* if no Unicode charmap was previously selected, select this one */ - if ( cffface->charmap == NULL && nn != (FT_UInt)cffface->num_charmaps ) + if ( !cffface->charmap && nn != (FT_UInt)cffface->num_charmaps ) cffface->charmap = cffface->charmaps[nn]; Skip_Unicode: @@ -1036,6 +1152,11 @@ FT_FREE( face->extra.data ); } } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + cff_done_blend( face ); + face->blend = NULL; +#endif } @@ -1052,7 +1173,7 @@ driver->hinting_engine = FT_CFF_HINTING_ADOBE; #endif - driver->no_stem_darkening = FALSE; + driver->no_stem_darkening = TRUE; driver->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; driver->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1; diff --git a/third_party/freetype/src/cff/cffobjs.h b/third_party/freetype/src/cff/cffobjs.h index 3cc953143b..5d26977dc5 100644 --- a/third_party/freetype/src/cff/cffobjs.h +++ b/third_party/freetype/src/cff/cffobjs.h @@ -4,7 +4,7 @@ /* */ /* OpenType objects manager (specification). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2017 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,8 +16,8 @@ /***************************************************************************/ -#ifndef __CFFOBJS_H__ -#define __CFFOBJS_H__ +#ifndef CFFOBJS_H_ +#define CFFOBJS_H_ #include <ft2build.h> @@ -179,7 +179,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CFFOBJS_H__ */ +#endif /* CFFOBJS_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cffparse.c b/third_party/freetype/src/cff/cffparse.c index 063b3517c5..819332b3e8 100644 --- a/third_party/freetype/src/cff/cffparse.c +++ b/third_party/freetype/src/cff/cffparse.c @@ -4,7 +4,7 @@ /* */ /* CFF token stream parser (body) */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2017 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -23,6 +23,8 @@ #include "cfferrs.h" #include "cffpic.h" +#include "cffgload.h" +#include "cffload.h" /*************************************************************************/ @@ -35,18 +37,52 @@ #define FT_COMPONENT trace_cffparse - FT_LOCAL_DEF( void ) + FT_LOCAL_DEF( FT_Error ) cff_parser_init( CFF_Parser parser, FT_UInt code, void* object, - FT_Library library) + FT_Library library, + FT_UInt stackSize, + FT_UShort num_designs, + FT_UShort num_axes ) { - FT_MEM_ZERO( parser, sizeof ( *parser ) ); + FT_Memory memory = library->memory; /* for FT_NEW_ARRAY */ + FT_Error error; /* for FT_NEW_ARRAY */ + + + FT_ZERO( parser ); +#if 0 parser->top = parser->stack; +#endif parser->object_code = code; parser->object = object; parser->library = library; + parser->num_designs = num_designs; + parser->num_axes = num_axes; + + /* allocate the stack buffer */ + if ( FT_NEW_ARRAY( parser->stack, stackSize ) ) + { + FT_FREE( parser->stack ); + goto Exit; + } + + parser->stackSize = stackSize; + parser->top = parser->stack; /* empty stack */ + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + cff_parser_done( CFF_Parser parser ) + { + FT_Memory memory = parser->library->memory; /* for FT_FREE */ + + + FT_FREE( parser->stack ); } @@ -397,24 +433,54 @@ /* read a number, either integer or real */ - static FT_Long - cff_parse_num( FT_Byte** d ) + FT_LOCAL_DEF( FT_Long ) + cff_parse_num( CFF_Parser parser, + FT_Byte** d ) { - return **d == 30 ? ( cff_parse_real( d[0], d[1], 0, NULL ) >> 16 ) - : cff_parse_integer( d[0], d[1] ); + if ( **d == 30 ) + { + /* binary-coded decimal is truncated to integer */ + return cff_parse_real( *d, parser->limit, 0, NULL ) >> 16; + } + + else if ( **d == 255 ) + { + /* 16.16 fixed point is used internally for CFF2 blend results. */ + /* Since these are trusted values, a limit check is not needed. */ + + /* After the 255, 4 bytes give the number. */ + /* The blend value is converted to integer, with rounding; */ + /* due to the right-shift we don't need the lowest byte. */ +#if 0 + return (FT_Short)( + ( ( ( (FT_UInt32)*( d[0] + 1 ) << 24 ) | + ( (FT_UInt32)*( d[0] + 2 ) << 16 ) | + ( (FT_UInt32)*( d[0] + 3 ) << 8 ) | + (FT_UInt32)*( d[0] + 4 ) ) + 0x8000U ) >> 16 ); +#else + return (FT_Short)( + ( ( ( (FT_UInt32)*( d[0] + 1 ) << 16 ) | + ( (FT_UInt32)*( d[0] + 2 ) << 8 ) | + (FT_UInt32)*( d[0] + 3 ) ) + 0x80U ) >> 8 ); +#endif + } + + else + return cff_parse_integer( *d, parser->limit ); } /* read a floating point number, either integer or real */ static FT_Fixed - do_fixed( FT_Byte** d, - FT_Long scaling ) + do_fixed( CFF_Parser parser, + FT_Byte** d, + FT_Long scaling ) { if ( **d == 30 ) - return cff_parse_real( d[0], d[1], scaling, NULL ); + return cff_parse_real( *d, parser->limit, scaling, NULL ); else { - FT_Long val = cff_parse_integer( d[0], d[1] ); + FT_Long val = cff_parse_integer( *d, parser->limit ); if ( scaling ) @@ -442,19 +508,21 @@ /* read a floating point number, either integer or real */ static FT_Fixed - cff_parse_fixed( FT_Byte** d ) + cff_parse_fixed( CFF_Parser parser, + FT_Byte** d ) { - return do_fixed( d, 0 ); + return do_fixed( parser, d, 0 ); } /* read a floating point number, either integer or real, */ /* but return `10^scaling' times the number read in */ static FT_Fixed - cff_parse_fixed_scaled( FT_Byte** d, - FT_Long scaling ) + cff_parse_fixed_scaled( CFF_Parser parser, + FT_Byte** d, + FT_Long scaling ) { - return do_fixed( d, scaling ); + return do_fixed( parser, d, scaling ); } @@ -462,13 +530,14 @@ /* and return it as precise as possible -- `scaling' returns */ /* the scaling factor (as a power of 10) */ static FT_Fixed - cff_parse_fixed_dynamic( FT_Byte** d, - FT_Long* scaling ) + cff_parse_fixed_dynamic( CFF_Parser parser, + FT_Byte** d, + FT_Long* scaling ) { FT_ASSERT( scaling ); if ( **d == 30 ) - return cff_parse_real( d[0], d[1], 0, scaling ); + return cff_parse_real( *d, parser->limit, 0, scaling ); else { FT_Long number; @@ -516,7 +585,11 @@ if ( parser->top >= parser->stack + 6 ) { - FT_Long scaling; + FT_Fixed values[6]; + FT_Long scalings[6]; + + FT_Long min_scaling, max_scaling; + int i; error = FT_Err_Ok; @@ -525,22 +598,36 @@ /* We expect a well-formed font matrix, this is, the matrix elements */ /* `xx' and `yy' are of approximately the same magnitude. To avoid */ - /* loss of precision, we use the magnitude of element `xx' to scale */ - /* all other elements. The scaling factor is then contained in the */ - /* `units_per_em' value. */ + /* loss of precision, we use the magnitude of the largest matrix */ + /* element to scale all other elements. The scaling factor is then */ + /* contained in the `units_per_em' value. */ - matrix->xx = cff_parse_fixed_dynamic( data++, &scaling ); + max_scaling = FT_LONG_MIN; + min_scaling = FT_LONG_MAX; - scaling = -scaling; + for ( i = 0; i < 6; i++ ) + { + values[i] = cff_parse_fixed_dynamic( parser, data++, &scalings[i] ); + if ( values[i] ) + { + if ( scalings[i] > max_scaling ) + max_scaling = scalings[i]; + if ( scalings[i] < min_scaling ) + min_scaling = scalings[i]; + } + } - if ( scaling < 0 || scaling > 9 ) + if ( max_scaling < -9 || + max_scaling > 0 || + ( max_scaling - min_scaling ) < 0 || + ( max_scaling - min_scaling ) > 9 ) { /* Return default matrix in case of unlikely values. */ FT_TRACE1(( "cff_parse_font_matrix:" - " strange scaling value for xx element (%d),\n" + " strange scaling values (minimum %d, maximum %d),\n" " " - " using default matrix\n", scaling )); + " using default matrix\n", min_scaling, max_scaling )); matrix->xx = 0x10000L; matrix->yx = 0; @@ -553,13 +640,42 @@ goto Exit; } - matrix->yx = cff_parse_fixed_scaled( data++, scaling ); - matrix->xy = cff_parse_fixed_scaled( data++, scaling ); - matrix->yy = cff_parse_fixed_scaled( data++, scaling ); - offset->x = cff_parse_fixed_scaled( data++, scaling ); - offset->y = cff_parse_fixed_scaled( data, scaling ); + for ( i = 0; i < 6; i++ ) + { + FT_Fixed value = values[i]; + FT_Long divisor, half_divisor; + + + if ( !value ) + continue; - *upm = (FT_ULong)power_tens[scaling]; + divisor = power_tens[max_scaling - scalings[i]]; + half_divisor = divisor >> 1; + + if ( value < 0 ) + { + if ( FT_LONG_MIN + half_divisor < value ) + values[i] = ( value - half_divisor ) / divisor; + else + values[i] = FT_LONG_MIN / divisor; + } + else + { + if ( FT_LONG_MAX - half_divisor > value ) + values[i] = ( value + half_divisor ) / divisor; + else + values[i] = FT_LONG_MAX / divisor; + } + } + + matrix->xx = values[0]; + matrix->yx = values[1]; + matrix->xy = values[2]; + matrix->yy = values[3]; + offset->x = values[4]; + offset->y = values[5]; + + *upm = (FT_ULong)power_tens[-max_scaling]; FT_TRACE4(( " [%f %f %f %f %f %f]\n", (double)matrix->xx / *upm / 65536, @@ -588,10 +704,10 @@ if ( parser->top >= parser->stack + 4 ) { - bbox->xMin = FT_RoundFix( cff_parse_fixed( data++ ) ); - bbox->yMin = FT_RoundFix( cff_parse_fixed( data++ ) ); - bbox->xMax = FT_RoundFix( cff_parse_fixed( data++ ) ); - bbox->yMax = FT_RoundFix( cff_parse_fixed( data ) ); + bbox->xMin = FT_RoundFix( cff_parse_fixed( parser, data++ ) ); + bbox->yMin = FT_RoundFix( cff_parse_fixed( parser, data++ ) ); + bbox->xMax = FT_RoundFix( cff_parse_fixed( parser, data++ ) ); + bbox->yMax = FT_RoundFix( cff_parse_fixed( parser, data ) ); error = FT_Err_Ok; FT_TRACE4(( " [%d %d %d %d]\n", @@ -620,7 +736,7 @@ FT_Long tmp; - tmp = cff_parse_num( data++ ); + tmp = cff_parse_num( parser, data++ ); if ( tmp < 0 ) { FT_ERROR(( "cff_parse_private_dict: Invalid dictionary size\n" )); @@ -629,7 +745,7 @@ } dict->private_size = (FT_ULong)tmp; - tmp = cff_parse_num( data ); + tmp = cff_parse_num( parser, data ); if ( tmp < 0 ) { FT_ERROR(( "cff_parse_private_dict: Invalid dictionary offset\n" )); @@ -649,6 +765,56 @@ } + /* The `MultipleMaster' operator comes before any */ + /* top DICT operators that contain T2 charstrings. */ + + static FT_Error + cff_parse_multiple_master( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Error error; + + +#ifdef FT_DEBUG_LEVEL_TRACE + /* beautify tracing message */ + if ( ft_trace_levels[FT_COMPONENT] < 4 ) + FT_TRACE1(( "Multiple Master CFFs not supported yet," + " handling first master design only\n" )); + else + FT_TRACE1(( " (not supported yet," + " handling first master design only)\n" )); +#endif + + error = FT_ERR( Stack_Underflow ); + + /* currently, we handle only the first argument */ + if ( parser->top >= parser->stack + 5 ) + { + FT_Long num_designs = cff_parse_num( parser, parser->stack ); + + + if ( num_designs > 16 || num_designs < 2 ) + { + FT_ERROR(( "cff_parse_multiple_master:" + " Invalid number of designs\n" )); + error = FT_THROW( Invalid_File_Format ); + } + else + { + dict->num_designs = (FT_UShort)num_designs; + dict->num_axes = (FT_UShort)( parser->top - parser->stack - 4 ); + + parser->num_designs = dict->num_designs; + parser->num_axes = dict->num_axes; + + error = FT_Err_Ok; + } + } + + return error; + } + + static FT_Error cff_parse_cid_ros( CFF_Parser parser ) { @@ -661,11 +827,11 @@ if ( parser->top >= parser->stack + 3 ) { - dict->cid_registry = (FT_UInt)cff_parse_num( data++ ); - dict->cid_ordering = (FT_UInt)cff_parse_num( data++ ); + dict->cid_registry = (FT_UInt)cff_parse_num( parser, data++ ); + dict->cid_ordering = (FT_UInt)cff_parse_num( parser, data++ ); if ( **data == 30 ) FT_TRACE1(( "cff_parse_cid_ros: real supplement is rounded\n" )); - dict->cid_supplement = cff_parse_num( data ); + dict->cid_supplement = cff_parse_num( parser, data ); if ( dict->cid_supplement < 0 ) FT_TRACE1(( "cff_parse_cid_ros: negative supplement %d is found\n", dict->cid_supplement )); @@ -681,6 +847,125 @@ } + static FT_Error + cff_parse_vsindex( CFF_Parser parser ) + { + /* vsindex operator can only be used in a Private DICT */ + CFF_Private priv = (CFF_Private)parser->object; + FT_Byte** data = parser->stack; + CFF_Blend blend; + FT_Error error; + + + if ( !priv || !priv->subfont ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + blend = &priv->subfont->blend; + + if ( blend->usedBV ) + { + FT_ERROR(( " cff_parse_vsindex: vsindex not allowed after blend\n" )); + error = FT_THROW( Syntax_Error ); + goto Exit; + } + + priv->vsindex = (FT_UInt)cff_parse_num( parser, data++ ); + + FT_TRACE4(( " %d\n", priv->vsindex )); + + error = FT_Err_Ok; + + Exit: + return error; + } + + + static FT_Error + cff_parse_blend( CFF_Parser parser ) + { + /* blend operator can only be used in a Private DICT */ + CFF_Private priv = (CFF_Private)parser->object; + CFF_SubFont subFont; + CFF_Blend blend; + FT_UInt numBlends; + FT_Error error; + + + error = FT_ERR( Stack_Underflow ); + + if ( !priv || !priv->subfont ) + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + subFont = priv->subfont; + blend = &subFont->blend; + + if ( cff_blend_check_vector( blend, + priv->vsindex, + subFont->lenNDV, + subFont->NDV ) ) + { + error = cff_blend_build_vector( blend, + priv->vsindex, + subFont->lenNDV, + subFont->NDV ); + if ( error ) + goto Exit; + } + + numBlends = (FT_UInt)cff_parse_num( parser, parser->top - 1 ); + if ( numBlends > parser->stackSize ) + { + FT_ERROR(( "cff_parse_blend: Invalid number of blends\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + FT_TRACE4(( " %d values blended\n", numBlends )); + + error = cff_blend_doBlend( subFont, parser, numBlends ); + + blend->usedBV = TRUE; + + Exit: + return error; + } + + + /* 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 ) \ @@ -692,9 +977,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 @@ -715,6 +997,15 @@ 0, 0 \ }, +#define CFF_FIELD_BLEND( code, id ) \ + { \ + cff_kind_blend, \ + code | CFFCODE, \ + 0, 0, \ + cff_parse_blend, \ + 0, 0 \ + }, + #define CFF_FIELD( code, name, id, kind ) \ { \ kind, \ @@ -758,6 +1049,16 @@ id \ }, +#define CFF_FIELD_BLEND( code, id ) \ + { \ + cff_kind_blend, \ + code | CFFCODE, \ + 0, 0, \ + cff_parse_blend, \ + 0, 0, \ + id \ + }, + #define CFF_FIELD( code, name, id, kind ) \ { \ kind, \ @@ -965,14 +1266,16 @@ { FT_UInt v = *p; - - if ( v >= 27 && v != 31 ) + /* Opcode 31 is legacy MM T2 operator, not a number. */ + /* Opcode 255 is reserved and should not appear in fonts; */ + /* it is used internally for CFF2 blends. */ + if ( v >= 27 && v != 31 && v != 255 ) { /* it's a number; we will push its position on the stack */ - if ( parser->top - parser->stack >= CFF_MAX_STACK_DEPTH ) + if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize ) goto Stack_Overflow; - *parser->top ++ = p; + *parser->top++ = p; /* now, skip it */ if ( v == 30 ) @@ -1001,19 +1304,153 @@ else if ( v > 246 ) p += 1; } +#ifdef CFF_CONFIG_OPTION_OLD_ENGINE + else if ( v == 31 ) + { + /* a Type 2 charstring */ + + CFF_Decoder decoder; + CFF_FontRec cff_rec; + FT_Byte* charstring_base; + FT_ULong charstring_len; + + FT_Fixed* stack; + FT_Byte* q; + + + charstring_base = ++p; + + /* search `endchar' operator */ + for (;;) + { + if ( p >= limit ) + goto Exit; + if ( *p == 14 ) + break; + p++; + } + + charstring_len = (FT_ULong)( p - charstring_base ) + 1; + + /* construct CFF_Decoder object */ + FT_ZERO( &decoder ); + FT_ZERO( &cff_rec ); + + cff_rec.top_font.font_dict.num_designs = parser->num_designs; + cff_rec.top_font.font_dict.num_axes = parser->num_axes; + decoder.cff = &cff_rec; + + error = cff_decoder_parse_charstrings( &decoder, + charstring_base, + charstring_len, + 1 ); + + /* Now copy the stack data in the temporary decoder object, */ + /* converting it back to charstring number representations */ + /* (this is ugly, I know). */ + /* */ + /* We overwrite the original top DICT charstring under the */ + /* assumption that the charstring representation of the result */ + /* of `cff_decoder_parse_charstrings' is shorter, which should */ + /* be always true. */ + + q = charstring_base - 1; + stack = decoder.stack; + + while ( stack < decoder.top ) + { + FT_ULong num; + FT_Bool neg; + + + if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize ) + goto Stack_Overflow; + + *parser->top++ = q; + + if ( *stack < 0 ) + { + num = (FT_ULong)-*stack; + neg = 1; + } + else + { + num = (FT_ULong)*stack; + neg = 0; + } + + if ( num & 0xFFFFU ) + { + if ( neg ) + num = (FT_ULong)-num; + + *q++ = 255; + *q++ = ( num & 0xFF000000U ) >> 24; + *q++ = ( num & 0x00FF0000U ) >> 16; + *q++ = ( num & 0x0000FF00U ) >> 8; + *q++ = num & 0x000000FFU; + } + else + { + num >>= 16; + + if ( neg ) + { + if ( num <= 107 ) + *q++ = (FT_Byte)( 139 - num ); + else if ( num <= 1131 ) + { + *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 251 ); + *q++ = (FT_Byte)( ( num - 108 ) & 0xFF ); + } + else + { + num = (FT_ULong)-num; + + *q++ = 28; + *q++ = (FT_Byte)( num >> 8 ); + *q++ = (FT_Byte)( num & 0xFF ); + } + } + else + { + if ( num <= 107 ) + *q++ = (FT_Byte)( num + 139 ); + else if ( num <= 1131 ) + { + *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 247 ); + *q++ = (FT_Byte)( ( num - 108 ) & 0xFF ); + } + else + { + *q++ = 28; + *q++ = (FT_Byte)( num >> 8 ); + *q++ = (FT_Byte)( num & 0xFF ); + } + } + } + + stack++; + } + } +#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */ else { /* This is not a number, hence it's an operator. Compute its code */ /* and look for it in our current list. */ FT_UInt code; - FT_UInt num_args = (FT_UInt) - ( parser->top - parser->stack ); + FT_UInt num_args; const CFF_Field_Handler* field; + if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize ) + goto Stack_Overflow; + + num_args = (FT_UInt)( parser->top - parser->stack ); *parser->top = p; - code = v; + code = v; + if ( v == 12 ) { /* two byte operator */ @@ -1048,15 +1485,15 @@ case cff_kind_bool: case cff_kind_string: case cff_kind_num: - val = cff_parse_num( parser->stack ); + val = cff_parse_num( parser, parser->stack ); goto Store_Number; case cff_kind_fixed: - val = cff_parse_fixed( parser->stack ); + val = cff_parse_fixed( parser, parser->stack ); goto Store_Number; case cff_kind_fixed_thousand: - val = cff_parse_fixed_scaled( parser->stack, 3 ); + val = cff_parse_fixed_scaled( parser, parser->stack, 3 ); Store_Number: switch ( field->size ) @@ -1125,7 +1562,7 @@ val = 0; while ( num_args > 0 ) { - val += cff_parse_num( data++ ); + val += cff_parse_num( parser, data++ ); switch ( field->size ) { case (8 / FT_CHAR_BIT): @@ -1154,7 +1591,7 @@ } break; - default: /* callback */ + default: /* callback or blend */ error = field->reader( parser ); if ( error ) goto Exit; @@ -1168,7 +1605,10 @@ Found: /* clear stack */ - parser->top = parser->stack; + /* TODO: could clear blend stack here, */ + /* but we don't have access to subFont */ + if ( field->kind != cff_kind_blend ) + parser->top = parser->stack; } p++; } diff --git a/third_party/freetype/src/cff/cffparse.h b/third_party/freetype/src/cff/cffparse.h index 8ad02ea1e2..9976d42b18 100644 --- a/third_party/freetype/src/cff/cffparse.h +++ b/third_party/freetype/src/cff/cffparse.h @@ -4,7 +4,7 @@ /* */ /* CFF token stream parser (specification) */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2017 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,8 +16,8 @@ /***************************************************************************/ -#ifndef __CFF_PARSE_H__ -#define __CFF_PARSE_H__ +#ifndef CFFPARSE_H_ +#define CFFPARSE_H_ #include <ft2build.h> @@ -28,33 +28,54 @@ 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_ { - FT_Library library; - FT_Byte* start; - FT_Byte* limit; - FT_Byte* cursor; + FT_Library library; + FT_Byte* start; + FT_Byte* limit; + FT_Byte* cursor; - FT_Byte* stack[CFF_MAX_STACK_DEPTH + 1]; - FT_Byte** top; + FT_Byte** stack; + FT_Byte** top; + FT_UInt stackSize; /* allocated size */ - FT_UInt object_code; - void* object; + FT_UInt object_code; + void* object; + + FT_UShort num_designs; /* a copy of `CFF_FontRecDict->num_designs' */ + FT_UShort num_axes; /* a copy of `CFF_FontRecDict->num_axes' */ } CFF_ParserRec, *CFF_Parser; - FT_LOCAL( void ) + FT_LOCAL( FT_Long ) + cff_parse_num( CFF_Parser parser, + FT_Byte** d ); + + FT_LOCAL( FT_Error ) cff_parser_init( CFF_Parser parser, FT_UInt code, void* object, - FT_Library library); + FT_Library library, + FT_UInt stackSize, + FT_UShort num_designs, + FT_UShort num_axes ); + + FT_LOCAL( void ) + cff_parser_done( CFF_Parser parser ); FT_LOCAL( FT_Error ) cff_parser_run( CFF_Parser parser, @@ -72,6 +93,7 @@ FT_BEGIN_HEADER cff_kind_bool, cff_kind_delta, cff_kind_callback, + cff_kind_blend, cff_kind_max /* do not remove */ }; @@ -100,7 +122,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __CFF_PARSE_H__ */ +#endif /* CFFPARSE_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cffpic.c b/third_party/freetype/src/cff/cffpic.c index d40dec50e9..4e9ba12b3f 100644 --- a/third_party/freetype/src/cff/cffpic.c +++ b/third_party/freetype/src/cff/cffpic.c @@ -4,7 +4,7 @@ /* */ /* The FreeType position independent code services for cff module. */ /* */ -/* Copyright 2009-2015 by */ +/* Copyright 2009-2017 by */ /* Oran Agra and Mickey Gabel. */ /* */ /* This file is part of the FreeType project, and may only be used, */ diff --git a/third_party/freetype/src/cff/cffpic.h b/third_party/freetype/src/cff/cffpic.h index 9a221a7b7e..0b89fcb5e5 100644 --- a/third_party/freetype/src/cff/cffpic.h +++ b/third_party/freetype/src/cff/cffpic.h @@ -4,7 +4,7 @@ /* */ /* The FreeType position independent code services for cff module. */ /* */ -/* Copyright 2009-2015 by */ +/* Copyright 2009-2017 by */ /* Oran Agra and Mickey Gabel. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,8 +16,8 @@ /***************************************************************************/ -#ifndef __CFFPIC_H__ -#define __CFFPIC_H__ +#ifndef CFFPIC_H_ +#define CFFPIC_H_ #include FT_INTERNAL_PIC_H @@ -32,6 +32,7 @@ #define CFF_SERVICE_CID_INFO_GET cff_service_cid_info #define CFF_SERVICE_PROPERTIES_GET cff_service_properties #define CFF_SERVICES_GET cff_services +#define CFF_SERVICE_MULTI_MASTERS_GET cff_service_multi_masters #define CFF_CMAP_ENCODING_CLASS_REC_GET cff_cmap_encoding_class_rec #define CFF_CMAP_UNICODE_CLASS_REC_GET cff_cmap_unicode_class_rec #define CFF_FIELD_HANDLERS_GET cff_field_handlers @@ -102,7 +103,7 @@ FT_END_HEADER /* */ -#endif /* __CFFPIC_H__ */ +#endif /* CFFPIC_H_ */ /* END */ diff --git a/third_party/freetype/src/cff/cfftoken.h b/third_party/freetype/src/cff/cfftoken.h index 5b32076ab8..3222e933f1 100644 --- a/third_party/freetype/src/cff/cfftoken.h +++ b/third_party/freetype/src/cff/cfftoken.h @@ -4,7 +4,7 @@ /* */ /* CFF token definitions (specification only). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2017 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -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" ) @@ -38,6 +38,9 @@ CFF_FIELD_NUM ( 13, unique_id, "UniqueID" ) CFF_FIELD_CALLBACK( 5, font_bbox, "FontBBox" ) CFF_FIELD_NUM ( 0x108, stroke_width, "StrokeWidth" ) +#if 0 + CFF_FIELD_DELTA ( 14, xuid, 16, "XUID" ) +#endif CFF_FIELD_NUM ( 15, charset_offset, "charset" ) CFF_FIELD_NUM ( 16, encoding_offset, "Encoding" ) CFF_FIELD_NUM ( 17, charstrings_offset, "CharStrings" ) @@ -48,8 +51,13 @@ #if 0 CFF_FIELD_STRING ( 0x116, base_font_name, "BaseFontName" ) CFF_FIELD_DELTA ( 0x117, base_font_blend, 16, "BaseFontBlend" ) +#endif + + /* the next two operators were removed from the Type2 specification */ + /* in version 16-March-2000 */ CFF_FIELD_CALLBACK( 0x118, multiple_master, "MultipleMaster" ) - CFF_FIELD_CALLBACK( 0x119, blend_axis_types, "BlendAxisTypes" ) +#if 0 + CFF_FIELD_CALLBACK( 0x11A, blend_axis_types, "BlendAxisTypes" ) #endif CFF_FIELD_CALLBACK( 0x11E, cid_ros, "ROS" ) @@ -70,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" ) @@ -94,4 +102,49 @@ 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_NUM ( 24, vstore_offset, "vstore" ) + 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_CALLBACK ( 22, vsindex, "vsindex" ) + CFF_FIELD_BLEND ( 23, "blend" ) + CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" ) + + /* END */ diff --git a/third_party/freetype/src/cff/cfftypes.h b/third_party/freetype/src/cff/cfftypes.h index de8a5ee9b4..412712c86c 100644 --- a/third_party/freetype/src/cff/cfftypes.h +++ b/third_party/freetype/src/cff/cfftypes.h @@ -5,7 +5,7 @@ /* Basic OpenType/CFF type definitions and interface (specification */ /* only). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2017 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -17,8 +17,8 @@ /***************************************************************************/ -#ifndef __CFFTYPES_H__ -#define __CFFTYPES_H__ +#ifndef CFFTYPES_H_ +#define CFFTYPES_H_ #include <ft2build.h> @@ -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; @@ -102,6 +103,79 @@ FT_BEGIN_HEADER } CFF_CharsetRec, *CFF_Charset; + /* cf. similar fields in file `ttgxvar.h' from the `truetype' module */ + + typedef struct CFF_VarData_ + { +#if 0 + FT_UInt itemCount; /* not used; always zero */ + FT_UInt shortDeltaCount; /* not used; always zero */ +#endif + + FT_UInt regionIdxCount; /* number of regions in this var data */ + FT_UInt* regionIndices; /* array of `regionCount' indices; */ + /* these index `varRegionList' */ + } CFF_VarData; + + + /* contribution of one axis to a region */ + typedef struct CFF_AxisCoords_ + { + FT_Fixed startCoord; + FT_Fixed peakCoord; /* zero peak means no effect (factor = 1) */ + FT_Fixed endCoord; + + } CFF_AxisCoords; + + + typedef struct CFF_VarRegion_ + { + CFF_AxisCoords* axisList; /* array of axisCount records */ + + } CFF_VarRegion; + + + typedef struct CFF_VStoreRec_ + { + FT_UInt dataCount; + CFF_VarData* varData; /* array of dataCount records */ + /* vsindex indexes this array */ + FT_UShort axisCount; + FT_UInt regionCount; /* total number of regions defined */ + CFF_VarRegion* varRegionList; + + } CFF_VStoreRec, *CFF_VStore; + + + /* forward reference */ + typedef struct CFF_FontRec_* CFF_Font; + + + /* This object manages one cached blend vector. */ + /* */ + /* There is a BlendRec for Private DICT parsing in each subfont */ + /* and a BlendRec for charstrings in CF2_Font instance data. */ + /* A cached BV may be used across DICTs or Charstrings if inputs */ + /* have not changed. */ + /* */ + /* `usedBV' is reset at the start of each parse or charstring. */ + /* vsindex cannot be changed after a BV is used. */ + /* */ + /* Note: NDV is long (32/64 bit), while BV is 16.16 (FT_Int32). */ + typedef struct CFF_BlendRec_ + { + FT_Bool builtBV; /* blendV has been built */ + FT_Bool usedBV; /* blendV has been used */ + CFF_Font font; /* top level font struct */ + FT_UInt lastVsindex; /* last vsindex used */ + FT_UInt lenNDV; /* normDV length (aka numAxes) */ + FT_Fixed* lastNDV; /* last NDV used */ + FT_UInt lenBV; /* BlendV length (aka numMasters) */ + FT_Int32* BV; /* current blendV (per DICT/glyph) */ + + } CFF_BlendRec, *CFF_Blend; + + typedef struct CFF_FontRecDictRec_ { FT_UInt version; @@ -145,9 +219,23 @@ FT_BEGIN_HEADER FT_ULong cid_fd_select_offset; FT_UInt cid_font_name; + /* the next fields come from the data of the deprecated */ + /* `MultipleMaster' operator; they are needed to parse the (also */ + /* deprecated) `blend' operator in Type 2 charstrings */ + FT_UShort num_designs; + FT_UShort num_axes; + + /* fields for CFF2 */ + FT_ULong vstore_offset; + FT_UInt maxstack; + } CFF_FontRecDictRec, *CFF_FontRecDict; + /* forward reference */ + typedef struct CFF_SubFontRec_* CFF_SubFont; + + typedef struct CFF_PrivateRec_ { FT_Byte num_blue_values; @@ -180,6 +268,10 @@ FT_BEGIN_HEADER FT_Pos default_width; FT_Pos nominal_width; + /* fields for CFF2 */ + FT_UInt vsindex; + CFF_SubFont subfont; + } CFF_PrivateRec, *CFF_Private; @@ -207,10 +299,29 @@ 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 */ + /* fields for CFF2 */ + CFF_BlendRec blend; /* current blend vector */ + FT_UInt lenNDV; /* current length NDV or zero */ + FT_Fixed* NDV; /* ptr to current NDV or NULL */ + + /* `blend_stack' is a writable buffer to hold blend results. */ + /* This buffer is to the side of the normal cff parser stack; */ + /* `cff_parse_blend' and `cff_blend_doBlend' push blend results here. */ + /* The normal stack then points to these values instead of the DICT */ + /* because all other operators in Private DICT clear the stack. */ + /* `blend_stack' could be cleared at each operator other than blend. */ + /* Blended values are stored as 5-byte fixed point values. */ + + FT_Byte* blend_stack; /* base of stack allocation */ + FT_Byte* blend_top; /* first empty slot */ + FT_UInt blend_used; /* number of bytes in use */ + FT_UInt blend_alloc; /* number of bytes allocated */ - } CFF_SubFontRec, *CFF_SubFont; + CFF_IndexRec local_subrs_index; + FT_Byte** local_subrs; /* array of pointers */ + /* into Local Subrs INDEX data */ + + } CFF_SubFontRec; #define CFF_MAX_CID_FONTS 256 @@ -218,16 +329,20 @@ FT_BEGIN_HEADER typedef struct CFF_FontRec_ { + 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; 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; @@ -250,6 +365,7 @@ FT_BEGIN_HEADER FT_UInt num_strings; FT_Byte** strings; FT_Byte* string_pool; + FT_ULong string_pool_size; CFF_SubFontRec top_font; FT_UInt num_subfonts; @@ -273,12 +389,14 @@ FT_BEGIN_HEADER /* since version 2.4.12 */ FT_Generic cf2_instance; - } CFF_FontRec, *CFF_Font; + CFF_VStoreRec vstore; /* parsed vstore structure */ + + } CFF_FontRec; FT_END_HEADER -#endif /* __CFFTYPES_H__ */ +#endif /* CFFTYPES_H_ */ /* END */ |