diff options
Diffstat (limited to 'src/freetype2/cff/cffparse.c')
-rw-r--r-- | src/freetype2/cff/cffparse.c | 459 |
1 files changed, 344 insertions, 115 deletions
diff --git a/src/freetype2/cff/cffparse.c b/src/freetype2/cff/cffparse.c index 41af6a3..947ec9d 100644 --- a/src/freetype2/cff/cffparse.c +++ b/src/freetype2/cff/cffparse.c @@ -4,7 +4,7 @@ /* */ /* CFF token stream parser (body) */ /* */ -/* Copyright 1996-2001, 2002, 2003, 2004, 2007 by */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2007, 2008, 2009 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -19,8 +19,10 @@ #include <ft2build.h> #include "cffparse.h" #include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_DEBUG_H #include "cfferrs.h" +#include "cffpic.h" /*************************************************************************/ @@ -33,47 +35,20 @@ #define FT_COMPONENT trace_cffparse - enum - { - cff_kind_none = 0, - cff_kind_num, - cff_kind_fixed, - cff_kind_fixed_thousand, - cff_kind_string, - cff_kind_bool, - cff_kind_delta, - cff_kind_callback, - - cff_kind_max /* do not remove */ - }; - - - /* now generate handlers for the most simple fields */ - typedef FT_Error (*CFF_Field_Reader)( CFF_Parser parser ); - - typedef struct CFF_Field_Handler_ - { - int kind; - int code; - FT_UInt offset; - FT_Byte size; - CFF_Field_Reader reader; - FT_UInt array_max; - FT_UInt count_offset; - - } CFF_Field_Handler; FT_LOCAL_DEF( void ) cff_parser_init( CFF_Parser parser, FT_UInt code, - void* object ) + void* object, + FT_Library library) { FT_MEM_ZERO( parser, sizeof ( *parser ) ); parser->top = parser->stack; parser->object_code = code; parser->object = object; + parser->library = library; } @@ -136,24 +111,53 @@ } + static const FT_Long power_tens[] = + { + 1L, + 10L, + 100L, + 1000L, + 10000L, + 100000L, + 1000000L, + 10000000L, + 100000000L, + 1000000000L + }; + + /* read a real */ static FT_Fixed cff_parse_real( FT_Byte* start, FT_Byte* limit, - FT_Int power_ten ) + FT_Long power_ten, + FT_Long* scaling ) { - FT_Byte* p = start; - FT_Long num, divider, result, exponent; - FT_Int sign = 0, exponent_sign = 0; + FT_Byte* p = start; FT_UInt nib; FT_UInt phase; + FT_Long result, number, rest, exponent; + FT_Int sign = 0, exponent_sign = 0; + FT_Long exponent_add, integer_length, fraction_length; + + + if ( scaling ) + *scaling = 0; + + result = 0; + + number = 0; + rest = 0; + exponent = 0; - result = 0; - num = 0; - divider = 1; + exponent_add = 0; + integer_length = 0; + fraction_length = 0; - /* first of all, read the integer part */ + FT_UNUSED( rest ); + + /* First of all, read the integer part. */ phase = 4; for (;;) @@ -166,7 +170,7 @@ /* Make sure we don't read past the end. */ if ( p >= limit ) - goto Bad; + goto Exit; } /* Get the nibble. */ @@ -178,10 +182,20 @@ else if ( nib > 9 ) break; else - result = result * 10 + nib; + { + /* Increase exponent if we can't add the digit. */ + if ( number >= 0xCCCCCCCL ) + exponent_add++; + /* Skip leading zeros. */ + else if ( nib || number ) + { + integer_length++; + number = number * 10 + nib; + } + } } - /* read decimal part, if any */ + /* Read fraction part, if any. */ if ( nib == 0xa ) for (;;) { @@ -193,7 +207,7 @@ /* Make sure we don't read past the end. */ if ( p >= limit ) - goto Bad; + goto Exit; } /* Get the nibble. */ @@ -202,14 +216,18 @@ if ( nib >= 10 ) break; - if ( divider < 10000000L ) + /* Skip leading zeros if possible. */ + if ( !nib && !number ) + exponent_add--; + /* Only add digit if we don't overflow. */ + else if ( number < 0xCCCCCCCL && fraction_length < 9 ) { - num = num * 10 + nib; - divider *= 10; + fraction_length++; + number = number * 10 + nib; } } - /* read exponent, if any */ + /* Read exponent, if any. */ if ( nib == 12 ) { exponent_sign = 1; @@ -218,19 +236,17 @@ if ( nib == 11 ) { - exponent = 0; - for (;;) { - /* If we entered this iteration with phase == 4, we need */ - /* to read a new byte. */ + /* If we entered this iteration with phase == 4, */ + /* we need to read a new byte. */ if ( phase ) { p++; /* Make sure we don't read past the end. */ if ( p >= limit ) - goto Bad; + goto Exit; } /* Get the nibble. */ @@ -240,47 +256,111 @@ break; exponent = exponent * 10 + nib; + + /* Arbitrarily limit exponent. */ + if ( exponent > 1000 ) + goto Exit; } if ( exponent_sign ) exponent = -exponent; - - power_ten += (FT_Int)exponent; } - /* raise to power of ten if needed */ - while ( power_ten > 0 ) + /* We don't check `power_ten' and `exponent_add'. */ + exponent += power_ten + exponent_add; + + if ( scaling ) { - result = result * 10; - num = num * 10; + /* Only use `fraction_length'. */ + fraction_length += integer_length; + exponent += integer_length; - power_ten--; - } + if ( fraction_length <= 5 ) + { + if ( number > 0x7FFFL ) + { + result = FT_DivFix( number, 10 ); + *scaling = exponent - fraction_length + 1; + } + else + { + if ( exponent > 0 ) + { + FT_Long new_fraction_length, shift; - while ( power_ten < 0 ) - { - result = result / 10; - divider = divider * 10; - power_ten++; + /* Make `scaling' as small as possible. */ + new_fraction_length = FT_MIN( exponent, 5 ); + exponent -= new_fraction_length; + shift = new_fraction_length - fraction_length; + + number *= power_tens[shift]; + if ( number > 0x7FFFL ) + { + number /= 10; + exponent += 1; + } + } + else + exponent -= fraction_length; + + result = number << 16; + *scaling = exponent; + } + } + else + { + if ( ( number / power_tens[fraction_length - 5] ) > 0x7FFFL ) + { + result = FT_DivFix( number, power_tens[fraction_length - 4] ); + *scaling = exponent - 4; + } + else + { + result = FT_DivFix( number, power_tens[fraction_length - 5] ); + *scaling = exponent - 5; + } + } } + else + { + integer_length += exponent; + fraction_length -= exponent; + + /* Check for overflow and underflow. */ + if ( FT_ABS( integer_length ) > 5 ) + goto Exit; + + /* Remove non-significant digits. */ + if ( integer_length < 0 ) { + number /= power_tens[-integer_length]; + fraction_length += integer_length; + } + + /* Convert into 16.16 format. */ + if ( fraction_length > 0 ) + { + if ( ( number / power_tens[fraction_length] ) > 0x7FFFL ) + goto Exit; + + result = FT_DivFix( number, power_tens[fraction_length] ); + } + else + { + number *= power_tens[-fraction_length]; - /* Move the integer part into the high 16 bits. */ - result <<= 16; + if ( number > 0x7FFFL ) + goto Exit; - /* Place the decimal part into the low 16 bits. */ - if ( num ) - result |= FT_DivFix( num, divider ); + result = number << 16; + } + } if ( sign ) result = -result; Exit: return result; - - Bad: - result = 0; - goto Exit; } @@ -288,8 +368,8 @@ static FT_Long cff_parse_num( FT_Byte** d ) { - return ( **d == 30 ? ( cff_parse_real ( d[0], d[1], 0 ) >> 16 ) - : cff_parse_integer( d[0], d[1] ) ); + return **d == 30 ? ( cff_parse_real( d[0], d[1], 0, NULL ) >> 16 ) + : cff_parse_integer( d[0], d[1] ); } @@ -297,64 +377,120 @@ static FT_Fixed cff_parse_fixed( FT_Byte** d ) { - return ( **d == 30 ? cff_parse_real ( d[0], d[1], 0 ) - : cff_parse_integer( d[0], d[1] ) << 16 ); + return **d == 30 ? cff_parse_real( d[0], d[1], 0, NULL ) + : cff_parse_integer( d[0], d[1] ) << 16; } + /* read a floating point number, either integer or real, */ - /* but return 1000 times the number read in. */ + /* but return `10^scaling' times the number read in */ + static FT_Fixed + cff_parse_fixed_scaled( FT_Byte** d, + FT_Long scaling ) + { + return **d == 30 ? cff_parse_real( d[0], d[1], scaling, NULL ) + : ( cff_parse_integer( d[0], d[1] ) * + power_tens[scaling] ) << 16; + } + + + /* read a floating point number, either integer or real, */ + /* and return it as precise as possible -- `scaling' returns */ + /* the scaling factor (as a power of 10) */ static FT_Fixed - cff_parse_fixed_thousand( FT_Byte** d ) + cff_parse_fixed_dynamic( FT_Byte** d, + FT_Long* scaling ) { - return **d == - 30 ? cff_parse_real ( d[0], d[1], 3 ) - : (FT_Fixed)FT_MulFix( cff_parse_integer( d[0], d[1] ) << 16, 1000 ); + FT_ASSERT( scaling ); + + if ( **d == 30 ) + return cff_parse_real( d[0], d[1], 0, scaling ); + else + { + FT_Long number; + FT_Int integer_length; + + + number = cff_parse_integer( d[0], d[1] ); + + if ( number > 0x7FFFL ) + { + for ( integer_length = 5; integer_length < 10; integer_length++ ) + if ( number < power_tens[integer_length] ) + break; + + if ( ( number / power_tens[integer_length - 5] ) > 0x7FFFL ) + { + *scaling = integer_length - 4; + return FT_DivFix( number, power_tens[integer_length - 4] ); + } + else + { + *scaling = integer_length - 5; + return FT_DivFix( number, power_tens[integer_length - 5] ); + } + } + else + { + *scaling = 0; + return number << 16; + } + } } + static FT_Error cff_parse_font_matrix( CFF_Parser parser ) { CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; FT_Matrix* matrix = &dict->font_matrix; FT_Vector* offset = &dict->font_offset; - FT_UShort* upm = &dict->units_per_em; + FT_ULong* upm = &dict->units_per_em; FT_Byte** data = parser->stack; - FT_Error error; - FT_Fixed temp; + FT_Error error = CFF_Err_Stack_Underflow; - error = CFF_Err_Stack_Underflow; - if ( parser->top >= parser->stack + 6 ) { - matrix->xx = cff_parse_fixed_thousand( data++ ); - matrix->yx = cff_parse_fixed_thousand( data++ ); - matrix->xy = cff_parse_fixed_thousand( data++ ); - matrix->yy = cff_parse_fixed_thousand( data++ ); - offset->x = cff_parse_fixed_thousand( data++ ); - offset->y = cff_parse_fixed_thousand( data ); + FT_Long scaling; - temp = FT_ABS( matrix->yy ); - *upm = (FT_UShort)FT_DivFix( 0x10000L, FT_DivFix( temp, 1000 ) ); + error = CFF_Err_Ok; + + /* 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. */ - if ( temp != 0x10000L ) + matrix->xx = cff_parse_fixed_dynamic( data++, &scaling ); + + scaling = -scaling; + + if ( scaling < 0 || scaling > 9 ) { - matrix->xx = FT_DivFix( matrix->xx, temp ); - matrix->yx = FT_DivFix( matrix->yx, temp ); - matrix->xy = FT_DivFix( matrix->xy, temp ); - matrix->yy = FT_DivFix( matrix->yy, temp ); - offset->x = FT_DivFix( offset->x, temp ); - offset->y = FT_DivFix( offset->y, temp ); + /* Return default matrix in case of unlikely values. */ + matrix->xx = 0x10000L; + matrix->yx = 0; + matrix->yx = 0; + matrix->yy = 0x10000L; + offset->x = 0; + offset->y = 0; + *upm = 1; + + goto Exit; } - /* note that the offsets must be expressed in integer font units */ - offset->x >>= 16; - offset->y >>= 16; + 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 ); - error = CFF_Err_Ok; + *upm = power_tens[scaling]; } + Exit: return error; } @@ -418,7 +554,12 @@ { dict->cid_registry = (FT_UInt)cff_parse_num ( data++ ); dict->cid_ordering = (FT_UInt)cff_parse_num ( data++ ); - dict->cid_supplement = (FT_ULong)cff_parse_num( data ); + if ( **data == 30 ) + FT_TRACE1(( "cff_parse_cid_ros: real supplement is rounded\n" )); + dict->cid_supplement = cff_parse_num( data ); + if ( dict->cid_supplement < 0 ) + FT_TRACE1(( "cff_parse_cid_ros: negative supplement %d is found\n", + dict->cid_supplement )); error = CFF_Err_Ok; } @@ -439,6 +580,11 @@ #define CFF_FIELD_DELTA( code, name, max ) \ CFF_FIELD( code, name, cff_kind_delta ) +#define CFFCODE_TOPDICT 0x1000 +#define CFFCODE_PRIVATE 0x2000 + +#ifndef FT_CONFIG_OPTION_PIC + #define CFF_FIELD_CALLBACK( code, name ) \ { \ cff_kind_callback, \ @@ -470,9 +616,6 @@ FT_FIELD_OFFSET( num_ ## name ) \ }, -#define CFFCODE_TOPDICT 0x1000 -#define CFFCODE_PRIVATE 0x2000 - static const CFF_Field_Handler cff_field_handlers[] = { @@ -482,13 +625,99 @@ }; +#else /* FT_CONFIG_OPTION_PIC */ + + void FT_Destroy_Class_cff_field_handlers(FT_Library library, CFF_Field_Handler* clazz) + { + FT_Memory memory = library->memory; + if ( clazz ) + FT_FREE( clazz ); + } + + FT_Error FT_Create_Class_cff_field_handlers(FT_Library library, CFF_Field_Handler** output_class) + { + CFF_Field_Handler* clazz; + FT_Error error; + FT_Memory memory = library->memory; + int i=0; + +#undef CFF_FIELD +#undef CFF_FIELD_DELTA +#undef CFF_FIELD_CALLBACK +#define CFF_FIELD_CALLBACK( code, name ) i++; +#define CFF_FIELD( code, name, kind ) i++; +#define CFF_FIELD_DELTA( code, name, max ) i++; + +#include "cfftoken.h" + i++;/*{ 0, 0, 0, 0, 0, 0, 0 }*/ + + if ( FT_ALLOC( clazz, sizeof(CFF_Field_Handler)*i ) ) + return error; + + i=0; +#undef CFF_FIELD +#undef CFF_FIELD_DELTA +#undef CFF_FIELD_CALLBACK + +#define CFF_FIELD_CALLBACK( code_, name_ ) \ + clazz[i].kind = cff_kind_callback; \ + clazz[i].code = code_ | CFFCODE; \ + clazz[i].offset = 0; \ + clazz[i].size = 0; \ + clazz[i].reader = cff_parse_ ## name_; \ + clazz[i].array_max = 0; \ + clazz[i].count_offset = 0; \ + i++; + +#undef CFF_FIELD +#define CFF_FIELD( code_, name_, kind_ ) \ + clazz[i].kind = kind_; \ + clazz[i].code = code_ | CFFCODE; \ + clazz[i].offset = FT_FIELD_OFFSET( name_ ); \ + clazz[i].size = FT_FIELD_SIZE( name_ ); \ + clazz[i].reader = 0; \ + clazz[i].array_max = 0; \ + clazz[i].count_offset = 0; \ + i++; \ + +#undef CFF_FIELD_DELTA +#define CFF_FIELD_DELTA( code_, name_, max_ ) \ + clazz[i].kind = cff_kind_delta; \ + clazz[i].code = code_ | CFFCODE; \ + clazz[i].offset = FT_FIELD_OFFSET( name_ ); \ + clazz[i].size = FT_FIELD_SIZE_DELTA( name_ ); \ + clazz[i].reader = 0; \ + clazz[i].array_max = max_; \ + clazz[i].count_offset = FT_FIELD_OFFSET( num_ ## name_ ); \ + i++; + +#include "cfftoken.h" + + clazz[i].kind = 0; + clazz[i].code = 0; + clazz[i].offset = 0; + clazz[i].size = 0; + clazz[i].reader = 0; + clazz[i].array_max = 0; + clazz[i].count_offset = 0; + + *output_class = clazz; + return FT_Err_Ok; + } + + +#endif /* FT_CONFIG_OPTION_PIC */ + + FT_LOCAL_DEF( FT_Error ) cff_parser_run( CFF_Parser parser, FT_Byte* start, FT_Byte* limit ) { - FT_Byte* p = start; - FT_Error error = CFF_Err_Ok; + FT_Byte* p = start; + FT_Error error = CFF_Err_Ok; + FT_Library library = parser->library; + FT_UNUSED(library); parser->top = parser->stack; @@ -558,7 +787,7 @@ } code = code | parser->object_code; - for ( field = cff_field_handlers; field->kind; field++ ) + for ( field = FT_CFF_FIELD_HANDLERS_GET; field->kind; field++ ) { if ( field->code == (FT_Int)code ) { @@ -585,7 +814,7 @@ goto Store_Number; case cff_kind_fixed_thousand: - val = cff_parse_fixed_thousand( parser->stack ); + val = cff_parse_fixed_scaled( parser->stack, 3 ); Store_Number: switch ( field->size ) |