diff options
Diffstat (limited to 'src/truetype')
-rw-r--r-- | src/truetype/ttdriver.c | 12 | ||||
-rw-r--r-- | src/truetype/ttgload.c | 56 | ||||
-rw-r--r-- | src/truetype/ttgload.h | 4 | ||||
-rw-r--r-- | src/truetype/ttgxvar.c | 12 | ||||
-rw-r--r-- | src/truetype/ttinterp.c | 248 | ||||
-rw-r--r-- | src/truetype/ttobjs.c | 372 | ||||
-rw-r--r-- | src/truetype/ttobjs.h | 11 | ||||
-rw-r--r-- | src/truetype/ttpload.c | 41 |
8 files changed, 577 insertions, 179 deletions
diff --git a/src/truetype/ttdriver.c b/src/truetype/ttdriver.c index d723b57..e70a611 100644 --- a/src/truetype/ttdriver.c +++ b/src/truetype/ttdriver.c @@ -4,8 +4,7 @@ /* */ /* TrueType font driver implementation (body). */ /* */ -/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 */ -/* 2010 by */ +/* Copyright 1996-2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -135,8 +134,6 @@ { FT_UInt nn; TT_Face face = (TT_Face) ttface; - FT_Bool check = FT_BOOL( - !( flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ) ); /* XXX: TODO: check for sbits */ @@ -149,7 +146,7 @@ FT_UShort ah; - TT_Get_VMetrics( face, start + nn, check, &tsb, &ah ); + TT_Get_VMetrics( face, start + nn, &tsb, &ah ); advances[nn] = ah; } } @@ -161,7 +158,7 @@ FT_UShort aw; - TT_Get_HMetrics( face, start + nn, check, &lsb, &aw ); + TT_Get_HMetrics( face, start + nn, &lsb, &aw ); advances[nn] = aw; } } @@ -249,7 +246,10 @@ FT_Request_Metrics( size->face, req ); if ( FT_IS_SCALABLE( size->face ) ) + { error = tt_size_reset( ttsize ); + ttsize->root.metrics = ttsize->metrics; + } return error; } diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c index 1b496c0..f35521e 100644 --- a/src/truetype/ttgload.c +++ b/src/truetype/ttgload.c @@ -4,8 +4,7 @@ /* */ /* TrueType Glyph Loader (body). */ /* */ -/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */ -/* 2010 by */ +/* Copyright 1996-2011 */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -47,7 +46,7 @@ /*************************************************************************/ /* */ - /* Composite font flags. */ + /* Composite glyph flags. */ /* */ #define ARGS_ARE_WORDS 0x0001 #define ARGS_ARE_XY_VALUES 0x0002 @@ -66,22 +65,16 @@ /*************************************************************************/ /* */ - /* Returns the horizontal metrics in font units for a given glyph. If */ - /* `check' is true, take care of monospaced fonts by returning the */ - /* advance width maximum. */ + /* Return the horizontal metrics in font units for a given glyph. */ /* */ FT_LOCAL_DEF( void ) TT_Get_HMetrics( TT_Face face, FT_UInt idx, - FT_Bool check, FT_Short* lsb, FT_UShort* aw ) { ( (SFNT_Service)face->sfnt )->get_metrics( face, 0, idx, lsb, aw ); - if ( check && face->postscript.isFixedPitch ) - *aw = face->horizontal.advance_Width_Max; - FT_TRACE5(( " advance width (font units): %d\n", *aw )); FT_TRACE5(( " left side bearing (font units): %d\n", *lsb )); } @@ -89,7 +82,7 @@ /*************************************************************************/ /* */ - /* Returns the vertical metrics in font units for a given glyph. */ + /* Return the vertical metrics in font units for a given glyph. */ /* Greg Hitchcock from Microsoft told us that if there were no `vmtx' */ /* table, typoAscender/Descender from the `OS/2' table would be used */ /* instead, and if there were no `OS/2' table, use ascender/descender */ @@ -97,18 +90,12 @@ /* apparently does: It uses the ppem value as the advance height, and */ /* sets the top side bearing to be zero. */ /* */ - /* The monospace `check' is probably not meaningful here, but we leave */ - /* it in for a consistent interface. */ - /* */ FT_LOCAL_DEF( void ) TT_Get_VMetrics( TT_Face face, FT_UInt idx, - FT_Bool check, FT_Short* tsb, FT_UShort* ah ) { - FT_UNUSED( check ); - if ( face->vertical_info ) ( (SFNT_Service)face->sfnt )->get_metrics( face, 1, idx, tsb, ah ); @@ -151,13 +138,9 @@ TT_Get_HMetrics( face, glyph_index, - (FT_Bool)!( loader->load_flags & - FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ), &left_bearing, &advance_width ); TT_Get_VMetrics( face, glyph_index, - (FT_Bool)!( loader->load_flags & - FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ), &top_bearing, &advance_height ); @@ -1656,23 +1639,7 @@ /* get the device-independent horizontal advance; it is scaled later */ /* by the base layer. */ - { - FT_Pos advance = loader->linear; - - - /* the flag FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH was introduced to */ - /* correctly support DynaLab fonts, which have an incorrect */ - /* `advance_Width_Max' field! It is used, to my knowledge, */ - /* exclusively in the X-TrueType font server. */ - /* */ - if ( face->postscript.isFixedPitch && - ( loader->load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ) == 0 ) - advance = face->horizontal.advance_Width_Max; - - /* we need to return the advance in font units in linearHoriAdvance, */ - /* it will be scaled later by the base layer. */ - glyph->linearHoriAdvance = advance; - } + glyph->linearHoriAdvance = loader->linear; glyph->metrics.horiBearingX = bbox.xMin; glyph->metrics.horiBearingY = bbox.yMax; @@ -1869,6 +1836,7 @@ { TT_Face face; FT_Stream stream; + FT_Bool pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); face = (TT_Face)glyph->face; @@ -1887,7 +1855,9 @@ if ( !size->cvt_ready ) { - FT_Error error = tt_size_ready_bytecode( size ); + FT_Error error = tt_size_ready_bytecode( size, pedantic ); + + if ( error ) return error; } @@ -1910,11 +1880,14 @@ FT_UInt i; + FT_TRACE4(( "tt_loader_init: grayscale change," + " re-executing `prep' table\n" )); + exec->grayscale = grayscale; for ( i = 0; i < size->cvt_size; i++ ) size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale ); - tt_size_run_prep( size ); + tt_size_run_prep( size, pedantic ); } /* see whether the cvt program has disabled hinting */ @@ -2044,9 +2017,6 @@ glyph->linearHoriAdvance = loader.linear; glyph->linearVertAdvance = loader.top_bearing + loader.bbox.yMax - loader.vadvance; - if ( face->postscript.isFixedPitch && - ( load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ) == 0 ) - glyph->linearHoriAdvance = face->horizontal.advance_Width_Max; } return TT_Err_Ok; diff --git a/src/truetype/ttgload.h b/src/truetype/ttgload.h index 958d67d..05f7588 100644 --- a/src/truetype/ttgload.h +++ b/src/truetype/ttgload.h @@ -4,7 +4,7 @@ /* */ /* TrueType Glyph Loader (specification). */ /* */ -/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2008 by */ +/* Copyright 1996-2006, 2008, 2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -37,14 +37,12 @@ FT_BEGIN_HEADER FT_LOCAL( void ) TT_Get_HMetrics( TT_Face face, FT_UInt idx, - FT_Bool check, FT_Short* lsb, FT_UShort* aw ); FT_LOCAL( void ) TT_Get_VMetrics( TT_Face face, FT_UInt idx, - FT_Bool check, FT_Short* tsb, FT_UShort* ah ); diff --git a/src/truetype/ttgxvar.c b/src/truetype/ttgxvar.c index 653d9d5..37bbe6d 100644 --- a/src/truetype/ttgxvar.c +++ b/src/truetype/ttgxvar.c @@ -123,14 +123,14 @@ ft_var_readpackedpoints( FT_Stream stream, FT_UInt *point_cnt ) { - FT_UShort *points; + FT_UShort *points = NULL; FT_Int n; FT_Int runcnt; FT_Int i; FT_Int j; FT_Int first; FT_Memory memory = stream->memory; - FT_Error error = TT_Err_Ok; + FT_Error error = TT_Err_Ok; FT_UNUSED( error ); @@ -154,7 +154,7 @@ runcnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK; first = points[i++] = FT_GET_USHORT(); - if ( runcnt < 1 ) + if ( runcnt < 1 || i + runcnt >= n ) goto Exit; /* first point not included in runcount */ @@ -165,7 +165,7 @@ { first = points[i++] = FT_GET_BYTE(); - if ( runcnt < 1 ) + if ( runcnt < 1 || i + runcnt >= n ) goto Exit; for ( j = 0; j < runcnt; ++j ) @@ -622,7 +622,7 @@ FT_Error error = TT_Err_Ok; FT_ULong fvar_start; FT_Int i, j; - FT_MM_Var* mmvar; + FT_MM_Var* mmvar = NULL; FT_Fixed* next_coords; FT_String* next_name; FT_Var_Axis* a; @@ -1325,7 +1325,7 @@ FT_Stream stream = face->root.stream; FT_Memory memory = stream->memory; GX_Blend blend = face->blend; - FT_Vector* delta_xy; + FT_Vector* delta_xy = NULL; FT_Error error; FT_ULong glyph_start; diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c index d22e94f..d568926 100644 --- a/src/truetype/ttinterp.c +++ b/src/truetype/ttinterp.c @@ -4,8 +4,7 @@ /* */ /* TrueType bytecode interpreter (body). */ /* */ -/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */ -/* 2010 */ +/* Copyright 1996-2011 */ /* by David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -478,8 +477,7 @@ return TT_Err_Ok; Fail_Memory: - FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n", - (FT_Long)exec )); + FT_ERROR(( "Init_Context: not enough memory for %p\n", exec )); TT_Done_Context( exec ); return error; @@ -596,6 +594,12 @@ exec->storage = size->storage; exec->twilight = size->twilight; + + /* In case of multi-threading it can happen that the old size object */ + /* no longer exists, thus we must clear all glyph zone references. */ + ft_memset( &exec->zp0, 0, sizeof ( exec->zp0 ) ); + exec->zp1 = exec->zp0; + exec->zp2 = exec->zp0; } /* XXX: We reserve a little more elements on the stack to deal safely */ @@ -981,8 +985,8 @@ /* INS_$83 */ PACK( 0, 0 ), /* INS_$84 */ PACK( 0, 0 ), /* ScanCTRL */ PACK( 1, 0 ), - /* SDVPTL[0] */ PACK( 2, 0 ), - /* SDVPTL[1] */ PACK( 2, 0 ), + /* SDPVTL[0] */ PACK( 2, 0 ), + /* SDPVTL[1] */ PACK( 2, 0 ), /* GetINFO */ PACK( 1, 1 ), /* IDEF */ PACK( 1, 0 ), /* ROLL */ PACK( 3, 3 ), @@ -3162,44 +3166,54 @@ args[0] = CUR.top; -#define DO_CINDEX \ - { \ - FT_Long L; \ - \ - \ - L = args[0]; \ - \ - if ( L <= 0 || L > CUR.args ) \ - CUR.error = TT_Err_Invalid_Reference; \ - else \ - args[0] = CUR.stack[CUR.args - L]; \ - } - - -#define DO_JROT \ - if ( args[1] != 0 ) \ - { \ - CUR.IP += args[0]; \ - if ( CUR.IP < 0 ) \ - CUR.error = TT_Err_Bad_Argument; \ - CUR.step_ins = FALSE; \ - } - - -#define DO_JMPR \ - CUR.IP += args[0]; \ - if ( CUR.IP < 0 ) \ - CUR.error = TT_Err_Bad_Argument; \ +#define DO_CINDEX \ + { \ + FT_Long L; \ + \ + \ + L = args[0]; \ + \ + if ( L <= 0 || L > CUR.args ) \ + { \ + if ( CUR.pedantic_hinting ) \ + CUR.error = TT_Err_Invalid_Reference; \ + args[0] = 0; \ + } \ + else \ + args[0] = CUR.stack[CUR.args - L]; \ + } + + +#define DO_JROT \ + if ( args[1] != 0 ) \ + { \ + if ( args[0] == 0 && CUR.args == 0 ) \ + CUR.error = TT_Err_Bad_Argument; \ + CUR.IP += args[0]; \ + if ( CUR.IP < 0 ) \ + CUR.error = TT_Err_Bad_Argument; \ + CUR.step_ins = FALSE; \ + } + + +#define DO_JMPR \ + if ( args[0] == 0 && CUR.args == 0 ) \ + CUR.error = TT_Err_Bad_Argument; \ + CUR.IP += args[0]; \ + if ( CUR.IP < 0 ) \ + CUR.error = TT_Err_Bad_Argument; \ CUR.step_ins = FALSE; -#define DO_JROF \ - if ( args[1] == 0 ) \ - { \ - CUR.IP += args[0]; \ - if ( CUR.IP < 0 ) \ - CUR.error = TT_Err_Bad_Argument; \ - CUR.step_ins = FALSE; \ +#define DO_JROF \ + if ( args[1] == 0 ) \ + { \ + if ( args[0] == 0 && CUR.args == 0 ) \ + CUR.error = TT_Err_Bad_Argument; \ + CUR.IP += args[0]; \ + if ( CUR.IP < 0 ) \ + CUR.error = TT_Err_Bad_Argument; \ + CUR.step_ins = FALSE; \ } @@ -4381,17 +4395,19 @@ if ( L <= 0 || L > CUR.args ) { - CUR.error = TT_Err_Invalid_Reference; - return; + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; } + else + { + K = CUR.stack[CUR.args - L]; - K = CUR.stack[CUR.args - L]; - - FT_ARRAY_MOVE( &CUR.stack[CUR.args - L ], - &CUR.stack[CUR.args - L + 1], - ( L - 1 ) ); + FT_ARRAY_MOVE( &CUR.stack[CUR.args - L ], + &CUR.stack[CUR.args - L + 1], + ( L - 1 ) ); - CUR.stack[CUR.args - 1] = K; + CUR.stack[CUR.args - 1] = K; + } } @@ -5034,12 +5050,8 @@ if ( BOUNDSL( L, CUR.zp2.n_points ) ) { if ( CUR.pedantic_hinting ) - { CUR.error = TT_Err_Invalid_Reference; - return; - } - else - R = 0; + R = 0; } else { @@ -5119,10 +5131,7 @@ BOUNDS( K, CUR.zp1.n_points ) ) { if ( CUR.pedantic_hinting ) - { CUR.error = TT_Err_Invalid_Reference; - return; - } D = 0; } else @@ -5460,8 +5469,9 @@ if ( CUR.top < CUR.GS.loop ) { - CUR.error = TT_Err_Too_Few_Arguments; - return; + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Too_Few_Arguments; + goto Fail; } while ( CUR.GS.loop > 0 ) @@ -5484,6 +5494,7 @@ CUR.GS.loop--; } + Fail: CUR.GS.loop = 1; CUR.new_top = CUR.args; } @@ -5671,8 +5682,9 @@ if ( CUR.top < CUR.GS.loop ) { - CUR.error = TT_Err_Invalid_Reference; - return; + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + goto Fail; } if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) @@ -5698,6 +5710,7 @@ CUR.GS.loop--; } + Fail: CUR.GS.loop = 1; CUR.new_top = CUR.args; } @@ -5795,7 +5808,16 @@ if ( CUR.GS.gep2 == 0 && CUR.zp2.n_points > 0 ) last_point = (FT_UShort)( CUR.zp2.n_points - 1 ); else if ( CUR.GS.gep2 == 1 && CUR.zp2.n_contours > 0 ) + { last_point = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] ); + + if ( BOUNDS( last_point, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + } else last_point = 0; @@ -5823,8 +5845,9 @@ if ( CUR.top < CUR.GS.loop + 1 ) { - CUR.error = TT_Err_Invalid_Reference; - return; + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + goto Fail; } #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING @@ -5868,6 +5891,7 @@ CUR.GS.loop--; } + Fail: CUR.GS.loop = 1; CUR.new_top = CUR.args; } @@ -5982,7 +6006,7 @@ { if ( CUR.pedantic_hinting ) CUR.error = TT_Err_Invalid_Reference; - return; + goto Fail; } /* XXX: UNDOCUMENTED! */ @@ -6028,6 +6052,7 @@ CUR_Func_move( &CUR.zp0, point, distance - org_dist ); + Fail: CUR.GS.rp0 = point; CUR.GS.rp1 = point; } @@ -6053,7 +6078,7 @@ { if ( CUR.pedantic_hinting ) CUR.error = TT_Err_Invalid_Reference; - return; + goto Fail; } /* XXX: Is there some undocumented feature while in the */ @@ -6138,6 +6163,7 @@ CUR_Func_move( &CUR.zp1, point, distance - org_dist ); + Fail: CUR.GS.rp1 = CUR.GS.rp0; CUR.GS.rp2 = point; @@ -6175,7 +6201,7 @@ { if ( CUR.pedantic_hinting ) CUR.error = TT_Err_Invalid_Reference; - return; + goto Fail; } if ( !cvtEntry ) @@ -6230,8 +6256,22 @@ /* refer to the same zone. */ if ( CUR.GS.gep0 == CUR.GS.gep1 ) - if ( FT_ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin ) + { + /* XXX: According to Greg Hitchcock, the following wording is */ + /* the right one: */ + /* */ + /* When the absolute difference between the value in */ + /* the table [CVT] and the measurement directly from */ + /* the outline is _greater_ than the cut_in value, the */ + /* outline measurement is used. */ + /* */ + /* This is from `instgly.doc'. The description in */ + /* `ttinst2.doc', version 1.66, is thus incorrect since */ + /* it implies `>=' instead of `>'. */ + + if ( FT_ABS( cvt_dist - org_dist ) > CUR.GS.control_value_cutin ) cvt_dist = org_dist; + } distance = CUR_Func_round( cvt_dist, @@ -6260,6 +6300,7 @@ CUR_Func_move( &CUR.zp1, point, distance - cur_dist ); + Fail: CUR.GS.rp1 = CUR.GS.rp0; if ( ( CUR.opcode & 16 ) != 0 ) @@ -6290,7 +6331,7 @@ { if ( CUR.pedantic_hinting ) CUR.error = TT_Err_Invalid_Reference; - return; + goto Fail; } while ( CUR.GS.loop > 0 ) @@ -6318,6 +6359,7 @@ CUR.GS.loop--; } + Fail: CUR.GS.loop = 1; CUR.new_top = CUR.args; } @@ -6459,8 +6501,9 @@ if ( CUR.top < CUR.GS.loop ) { - CUR.error = TT_Err_Invalid_Reference; - return; + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + goto Fail; } /* @@ -6474,7 +6517,7 @@ { if ( CUR.pedantic_hinting ) CUR.error = TT_Err_Invalid_Reference; - return; + goto Fail; } if ( twilight ) @@ -6539,6 +6582,8 @@ CUR_Func_move( &CUR.zp2, (FT_UShort)point, new_dist - cur_dist ); } + + Fail: CUR.GS.loop = 1; CUR.new_top = CUR.args; } @@ -6773,12 +6818,11 @@ { if ( ( CUR.pts.tags[point] & mask ) != 0 ) { - if ( point > 0 ) - _iup_worker_interpolate( &V, - cur_touched + 1, - point - 1, - cur_touched, - point ); + _iup_worker_interpolate( &V, + cur_touched + 1, + point - 1, + cur_touched, + point ); cur_touched = point; } @@ -6832,8 +6876,9 @@ if ( CUR.args < n ) { - CUR.error = TT_Err_Too_Few_Arguments; - return; + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Too_Few_Arguments; + n = CUR.args; } CUR.args -= n; @@ -6849,8 +6894,10 @@ { if ( CUR.args < 2 ) { - CUR.error = TT_Err_Too_Few_Arguments; - return; + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Too_Few_Arguments; + CUR.args = 0; + goto Fail; } CUR.args -= 2; @@ -6899,6 +6946,7 @@ CUR.error = TT_Err_Invalid_Reference; } + Fail: CUR.new_top = CUR.args; } @@ -6926,8 +6974,9 @@ if ( CUR.args < n ) { - CUR.error = TT_Err_Too_Few_Arguments; - return; + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Too_Few_Arguments; + n = CUR.args; } CUR.args -= n; @@ -6942,8 +6991,10 @@ { if ( CUR.args < 2 ) { - CUR.error = TT_Err_Too_Few_Arguments; - return; + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Too_Few_Arguments; + CUR.args = 0; + goto Fail; } CUR.args -= 2; @@ -6991,6 +7042,7 @@ } } + Fail: CUR.new_top = CUR.args; } @@ -7452,8 +7504,19 @@ /* One can also interpret it as the index of the last argument. */ if ( CUR.args < 0 ) { - CUR.error = TT_Err_Too_Few_Arguments; - goto LErrorLabel_; + FT_UShort i; + + + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Too_Few_Arguments; + goto LErrorLabel_; + } + + /* push zeroes onto the stack */ + for ( i = 0; i < Pop_Push_Count[CUR.opcode] >> 4; i++ ) + CUR.stack[i] = 0; + CUR.args = 0; } CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 ); @@ -7490,7 +7553,7 @@ case 0x04: /* SFvTCA y */ case 0x05: /* SFvTCA x */ { - FT_Short AA, BB; + FT_Short AA, BB; AA = (FT_Short)( ( opcode & 1 ) << 14 ); @@ -8128,6 +8191,15 @@ *exc = cur; #endif + /* If any errors have occurred, function tables may be broken. */ + /* Force a re-execution of `prep' and `fpgm' tables if no */ + /* bytecode debugger is run. */ + if ( CUR.error && !CUR.instruction_trap ) + { + FT_TRACE1(( " The interpreter returned error 0x%x\n", CUR.error )); + exc->size->cvt_ready = FALSE; + } + return CUR.error; } diff --git a/src/truetype/ttobjs.c b/src/truetype/ttobjs.c index 11d662d..d77c3c4 100644 --- a/src/truetype/ttobjs.c +++ b/src/truetype/ttobjs.c @@ -4,7 +4,7 @@ /* */ /* Objects manager (body). */ /* */ -/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */ +/* Copyright 1996-2011 */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -146,28 +146,28 @@ /* This list shall be expanded as we find more of them. */ static FT_Bool - tt_check_trickyness( FT_String* name ) + tt_check_trickyness_family( FT_String* name ) { + #define TRICK_NAMES_MAX_CHARACTERS 16 -#define TRICK_NAMES_COUNT 7 - static const char trick_names[TRICK_NAMES_COUNT][TRICK_NAMES_MAX_CHARACTERS+1] = +#define TRICK_NAMES_COUNT 8 + + static const char trick_names[TRICK_NAMES_COUNT] + [TRICK_NAMES_MAX_CHARACTERS + 1] = { "DFKaiSho-SB", /* dfkaisb.ttf */ "DFKaiShu", "DFKai-SB", /* kaiu.ttf */ + "HuaTianKaiTi?", /* htkt2.ttf */ "HuaTianSongTi?", /* htst3.ttf */ "MingLiU", /* mingliu.ttf & mingliu.ttc */ "PMingLiU", /* mingliu.ttc */ "MingLi43", /* mingli.ttf */ }; + int nn; - if ( !name ) - return FALSE; - - /* Note that we only check the face name at the moment; it might */ - /* be worth to do more checks for a few special cases. */ for ( nn = 0; nn < TRICK_NAMES_COUNT; nn++ ) if ( ft_strstr( name, trick_names[nn] ) ) return TRUE; @@ -176,6 +176,287 @@ } + /* XXX: This function should be in the `sfnt' module. */ + + /* Some PDF generators clear the checksums in the TrueType header table. */ + /* For example, Quartz ContextPDF clears all entries, or Bullzip PDF */ + /* Printer clears the entries for subsetted subtables. We thus have to */ + /* recalculate the checksums where necessary. */ + + static FT_UInt32 + tt_synth_sfnt_checksum( FT_Stream stream, + FT_ULong length ) + { + FT_Error error; + FT_UInt32 checksum = 0; + int i; + + + if ( FT_FRAME_ENTER( length ) ) + return 0; + + for ( ; length > 3; length -= 4 ) + checksum += (FT_UInt32)FT_GET_ULONG(); + + for ( i = 3; length > 0; length --, i-- ) + checksum += (FT_UInt32)( FT_GET_BYTE() << ( i * 8 ) ); + + FT_FRAME_EXIT(); + + return checksum; + } + + + /* XXX: This function should be in the `sfnt' module. */ + + static FT_ULong + tt_get_sfnt_checksum( TT_Face face, + FT_UShort i ) + { +#if 0 /* if we believe the written value, use following part. */ + if ( face->dir_tables[i].CheckSum ) + return face->dir_tables[i].CheckSum; +#endif + + if ( !face->goto_table ) + return 0; + + if ( face->goto_table( face, + face->dir_tables[i].Tag, + face->root.stream, + NULL ) ) + return 0; + + return (FT_ULong)tt_synth_sfnt_checksum( face->root.stream, + face->dir_tables[i].Length ); + } + + + typedef struct tt_sfnt_id_rec_ + { + FT_ULong CheckSum; + FT_ULong Length; + + } tt_sfnt_id_rec; + + + static FT_Bool + tt_check_trickyness_sfnt_ids( TT_Face face ) + { +#define TRICK_SFNT_IDS_PER_FACE 3 +#define TRICK_SFNT_IDS_NUM_FACES 13 + + static const tt_sfnt_id_rec sfnt_id[TRICK_SFNT_IDS_NUM_FACES] + [TRICK_SFNT_IDS_PER_FACE] = { + +#define TRICK_SFNT_ID_cvt 0 +#define TRICK_SFNT_ID_fpgm 1 +#define TRICK_SFNT_ID_prep 2 + + { /* MingLiU 1995 */ + { 0x05bcf058, 0x000002e4 }, /* cvt */ + { 0x28233bf1, 0x000087c4 }, /* fpgm */ + { 0xa344a1ea, 0x000001e1 } /* prep */ + }, + { /* MingLiU 1996- */ + { 0x05bcf058, 0x000002e4 }, /* cvt */ + { 0x28233bf1, 0x000087c4 }, /* fpgm */ + { 0xa344a1eb, 0x000001e1 } /* prep */ + }, + { /* DFKaiShu */ + { 0x11e5ead4, 0x00000350 }, /* cvt */ + { 0x5a30ca3b, 0x00009063 }, /* fpgm */ + { 0x13a42602, 0x0000007e } /* prep */ + }, + { /* HuaTianKaiTi */ + { 0xfffbfffc, 0x00000008 }, /* cvt */ + { 0x9c9e48b8, 0x0000bea2 }, /* fpgm */ + { 0x70020112, 0x00000008 } /* prep */ + }, + { /* HuaTianSongTi */ + { 0xfffbfffc, 0x00000008 }, /* cvt */ + { 0x0a5a0483, 0x00017c39 }, /* fpgm */ + { 0x70020112, 0x00000008 } /* prep */ + }, + { /* NEC fadpop7.ttf */ + { 0x00000000, 0x00000000 }, /* cvt */ + { 0x40c92555, 0x000000e5 }, /* fpgm */ + { 0xa39b58e3, 0x0000117c } /* prep */ + }, + { /* NEC fadrei5.ttf */ + { 0x00000000, 0x00000000 }, /* cvt */ + { 0x33c41652, 0x000000e5 }, /* fpgm */ + { 0x26d6c52a, 0x00000f6a } /* prep */ + }, + { /* NEC fangot7.ttf */ + { 0x00000000, 0x00000000 }, /* cvt */ + { 0x6db1651d, 0x0000019d }, /* fpgm */ + { 0x6c6e4b03, 0x00002492 } /* prep */ + }, + { /* NEC fangyo5.ttf */ + { 0x00000000, 0x00000000 }, /* cvt */ + { 0x40c92555, 0x000000e5 }, /* fpgm */ + { 0xde51fad0, 0x0000117c } /* prep */ + }, + { /* NEC fankyo5.ttf */ + { 0x00000000, 0x00000000 }, /* cvt */ + { 0x85e47664, 0x000000e5 }, /* fpgm */ + { 0xa6c62831, 0x00001caa } /* prep */ + }, + { /* NEC fanrgo5.ttf */ + { 0x00000000, 0x00000000 }, /* cvt */ + { 0x2d891cfd, 0x0000019d }, /* fpgm */ + { 0xa0604633, 0x00001de8 } /* prep */ + }, + { /* NEC fangot5.ttc */ + { 0x00000000, 0x00000000 }, /* cvt */ + { 0x40aa774c, 0x000001cb }, /* fpgm */ + { 0x9b5caa96, 0x00001f9a } /* prep */ + }, + { /* NEC fanmin3.ttc */ + { 0x00000000, 0x00000000 }, /* cvt */ + { 0x0d3de9cb, 0x00000141 }, /* fpgm */ + { 0xd4127766, 0x00002280 } /* prep */ + } + }; + + FT_ULong checksum; + int num_matched_ids[TRICK_SFNT_IDS_NUM_FACES]; + FT_Bool has_cvt, has_fpgm, has_prep; + FT_UShort i; + int j, k; + + + FT_MEM_SET( num_matched_ids, 0, + sizeof( int ) * TRICK_SFNT_IDS_NUM_FACES ); + has_cvt = FALSE; + has_fpgm = FALSE; + has_prep = FALSE; + + for ( i = 0; i < face->num_tables; i++ ) + { + checksum = 0; + + switch( face->dir_tables[i].Tag ) + { + case TTAG_cvt: + k = TRICK_SFNT_ID_cvt; + has_cvt = TRUE; + break; + + case TTAG_fpgm: + k = TRICK_SFNT_ID_fpgm; + has_fpgm = TRUE; + break; + + case TTAG_prep: + k = TRICK_SFNT_ID_prep; + has_prep = TRUE; + break; + + default: + continue; + } + + for ( j = 0; j < TRICK_SFNT_IDS_NUM_FACES; j++ ) + if ( face->dir_tables[i].Length == sfnt_id[j][k].Length ) + { + if ( !checksum ) + checksum = tt_get_sfnt_checksum( face, i ); + + if ( sfnt_id[j][k].CheckSum == checksum ) + num_matched_ids[j]++; + + if ( num_matched_ids[j] == TRICK_SFNT_IDS_PER_FACE ) + return TRUE; + } + } + + for ( j = 0; j < TRICK_SFNT_IDS_NUM_FACES; j++ ) + { + if ( !has_cvt && !sfnt_id[j][TRICK_SFNT_ID_cvt].Length ) + num_matched_ids[j] ++; + if ( !has_fpgm && !sfnt_id[j][TRICK_SFNT_ID_fpgm].Length ) + num_matched_ids[j] ++; + if ( !has_prep && !sfnt_id[j][TRICK_SFNT_ID_prep].Length ) + num_matched_ids[j] ++; + if ( num_matched_ids[j] == TRICK_SFNT_IDS_PER_FACE ) + return TRUE; + } + + return FALSE; + } + + + static FT_Bool + tt_check_trickyness( FT_Face face ) + { + if ( !face ) + return FALSE; + + /* For first, check the face name for quick check. */ + if ( face->family_name && + tt_check_trickyness_family( face->family_name ) ) + return TRUE; + + /* Type42 fonts may lack `name' tables, we thus try to identify */ + /* tricky fonts by checking the checksums of Type42-persistent */ + /* sfnt tables (`cvt', `fpgm', and `prep'). */ + if ( tt_check_trickyness_sfnt_ids( (TT_Face)face ) ) + return TRUE; + + return FALSE; + } + + + /* Check whether `.notdef' is the only glyph in the `loca' table. */ + static FT_Bool + tt_check_single_notdef( FT_Face ttface ) + { + FT_Bool result = FALSE; + + TT_Face face = (TT_Face)ttface; + FT_UInt asize; + FT_ULong i; + FT_ULong glyph_index = 0; + FT_UInt count = 0; + + + for( i = 0; i < face->num_locations; i++ ) + { + tt_face_get_location( face, i, &asize ); + if ( asize > 0 ) + { + count += 1; + if ( count > 1 ) + break; + glyph_index = i; + } + } + + /* Only have a single outline. */ + if ( count == 1 ) + { + if ( glyph_index == 0 ) + result = TRUE; + else + { + /* FIXME: Need to test glyphname == .notdef ? */ + FT_Error error; + char buf[8]; + + + error = FT_Get_Glyph_Name( ttface, glyph_index, buf, 8 ); + if ( !error && + buf[0] == '.' && !ft_strncmp( buf, ".notdef", 8 ) ) + result = TRUE; + } + } + + return result; + } + + /*************************************************************************/ /* */ /* <Function> */ @@ -250,7 +531,7 @@ if ( error ) goto Exit; - if ( tt_check_trickyness( ttface->family_name ) ) + if ( tt_check_trickyness( ttface ) ) ttface->face_flags |= FT_FACE_FLAG_TRICKY; error = tt_face_load_hdmx( face, stream ); @@ -271,6 +552,20 @@ if ( !error ) error = tt_face_load_prep( face, stream ); + /* Check the scalable flag based on `loca'. */ + if ( !ttface->internal->incremental_interface && + ttface->num_fixed_sizes && + face->glyph_locations && + tt_check_single_notdef( ttface ) ) + { + FT_TRACE5(( "tt_face_init:" + " Only the `.notdef' glyph has an outline.\n" + " " + " Resetting scalable flag to FALSE.\n" )); + + ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE; + } + #else if ( !error ) @@ -282,6 +577,19 @@ if ( !error ) error = tt_face_load_prep( face, stream ); + /* Check the scalable flag based on `loca'. */ + if ( ttface->num_fixed_sizes && + face->glyph_locations && + tt_check_single_notdef( ttface ) ) + { + FT_TRACE5(( "tt_face_init:" + " Only the `.notdef' glyph has an outline.\n" + " " + " Resetting scalable flag to FALSE.\n" )); + + ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE; + } + #endif } @@ -394,13 +702,16 @@ /* Run the font program. */ /* */ /* <Input> */ - /* size :: A handle to the size object. */ + /* size :: A handle to the size object. */ + /* */ + /* pedantic :: Set if bytecode execution should be pedantic. */ /* */ /* <Return> */ /* FreeType error code. 0 means success. */ /* */ FT_LOCAL_DEF( FT_Error ) - tt_size_run_fpgm( TT_Size size ) + tt_size_run_fpgm( TT_Size size, + FT_Bool pedantic ) { TT_Face face = (TT_Face)size->root.face; TT_ExecContext exec; @@ -418,15 +729,17 @@ TT_Load_Context( exec, face, size ); - exec->callTop = 0; - exec->top = 0; + exec->callTop = 0; + exec->top = 0; exec->period = 64; exec->phase = 0; exec->threshold = 0; exec->instruction_trap = FALSE; - exec->F_dot_P = 0x10000L; + exec->F_dot_P = 0x10000L; + + exec->pedantic_hinting = pedantic; { FT_Size_Metrics* metrics = &exec->metrics; @@ -458,7 +771,11 @@ error = TT_Goto_CodeRange( exec, tt_coderange_font, 0 ); if ( !error ) + { + FT_TRACE4(( "Executing `fpgm' table.\n" )); + error = face->interpreter( exec ); + } } else error = TT_Err_Ok; @@ -479,13 +796,16 @@ /* Run the control value program. */ /* */ /* <Input> */ - /* size :: A handle to the size object. */ + /* size :: A handle to the size object. */ + /* */ + /* pedantic :: Set if bytecode execution should be pedantic. */ /* */ /* <Return> */ /* FreeType error code. 0 means success. */ /* */ FT_LOCAL_DEF( FT_Error ) - tt_size_run_prep( TT_Size size ) + tt_size_run_prep( TT_Size size, + FT_Bool pedantic ) { TT_Face face = (TT_Face)size->root.face; TT_ExecContext exec; @@ -508,6 +828,8 @@ exec->instruction_trap = FALSE; + exec->pedantic_hinting = pedantic; + TT_Set_CodeRange( exec, tt_coderange_cvt, face->cvt_program, @@ -520,7 +842,11 @@ error = TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 ); if ( !error && !size->debug ) + { + FT_TRACE4(( "Executing `prep' table.\n" )); + error = face->interpreter( exec ); + } } else error = TT_Err_Ok; @@ -582,7 +908,8 @@ /* Initialize bytecode-related fields in the size object. */ /* We do this only if bytecode interpretation is really needed. */ static FT_Error - tt_size_init_bytecode( FT_Size ftsize ) + tt_size_init_bytecode( FT_Size ftsize, + FT_Bool pedantic ) { FT_Error error; TT_Size size = (TT_Size)ftsize; @@ -655,7 +982,7 @@ } /* Fine, now run the font program! */ - error = tt_size_run_fpgm( size ); + error = tt_size_run_fpgm( size, pedantic ); Exit: if ( error ) @@ -666,14 +993,15 @@ FT_LOCAL_DEF( FT_Error ) - tt_size_ready_bytecode( TT_Size size ) + tt_size_ready_bytecode( TT_Size size, + FT_Bool pedantic ) { FT_Error error = TT_Err_Ok; if ( !size->bytecode_ready ) { - error = tt_size_init_bytecode( (FT_Size)size ); + error = tt_size_init_bytecode( (FT_Size)size, pedantic ); if ( error ) goto Exit; } @@ -705,7 +1033,7 @@ size->GS = tt_default_graphics_state; - error = tt_size_run_prep( size ); + error = tt_size_run_prep( size, pedantic ); if ( !error ) size->cvt_ready = 1; } diff --git a/src/truetype/ttobjs.h b/src/truetype/ttobjs.h index 30c8669..087b3c2 100644 --- a/src/truetype/ttobjs.h +++ b/src/truetype/ttobjs.h @@ -4,7 +4,7 @@ /* */ /* Objects manager (specification). */ /* */ -/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */ +/* Copyright 1996-2009, 2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -390,13 +390,16 @@ FT_BEGIN_HEADER #ifdef TT_USE_BYTECODE_INTERPRETER FT_LOCAL( FT_Error ) - tt_size_run_fpgm( TT_Size size ); + tt_size_run_fpgm( TT_Size size, + FT_Bool pedantic ); FT_LOCAL( FT_Error ) - tt_size_run_prep( TT_Size size ); + tt_size_run_prep( TT_Size size, + FT_Bool pedantic ); FT_LOCAL( FT_Error ) - tt_size_ready_bytecode( TT_Size size ); + tt_size_ready_bytecode( TT_Size size, + FT_Bool pedantic ); #endif /* TT_USE_BYTECODE_INTERPRETER */ diff --git a/src/truetype/ttpload.c b/src/truetype/ttpload.c index a311b03..818b29d 100644 --- a/src/truetype/ttpload.c +++ b/src/truetype/ttpload.c @@ -4,7 +4,7 @@ /* */ /* TrueType-specific tables loader (body). */ /* */ -/* Copyright 1996-2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009 by */ +/* Copyright 1996-2002, 2004-2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -110,15 +110,16 @@ face->num_locations = table_len >> shift; } - if ( face->num_locations != (FT_ULong)face->root.num_glyphs ) + if ( face->num_locations != (FT_ULong)face->root.num_glyphs + 1 ) { FT_TRACE2(( "glyph count mismatch! loca: %d, maxp: %d\n", - face->num_locations, face->root.num_glyphs )); + face->num_locations - 1, face->root.num_glyphs )); /* we only handle the case where `maxp' gives a larger value */ - if ( face->num_locations < (FT_ULong)face->root.num_glyphs ) + if ( face->num_locations <= (FT_ULong)face->root.num_glyphs ) { - FT_Long new_loca_len = (FT_Long)face->root.num_glyphs << shift; + FT_Long new_loca_len = + ( (FT_Long)( face->root.num_glyphs ) + 1 ) << shift; TT_Table entry = face->dir_tables; TT_Table limit = entry + face->num_tables; @@ -137,9 +138,15 @@ dist = diff; } + if ( entry == limit ) + { + /* `loca' is the last table */ + dist = stream->size - pos; + } + if ( new_loca_len <= dist ) { - face->num_locations = face->root.num_glyphs; + face->num_locations = face->root.num_glyphs + 1; table_len = new_loca_len; FT_TRACE2(( "adjusting num_locations to %d\n", @@ -203,6 +210,26 @@ } } + /* Check broken location data */ + if ( pos1 >= face->glyf_len ) + { + FT_TRACE1(( "tt_face_get_location:" + " too large offset=0x%08lx found for gid=0x%04lx," + " exceeding the end of glyf table (0x%08lx)\n", + pos1, gindex, face->glyf_len )); + *asize = 0; + return 0; + } + + if ( pos2 >= face->glyf_len ) + { + FT_TRACE1(( "tt_face_get_location:" + " too large offset=0x%08lx found for gid=0x%04lx," + " truncate at the end of glyf table (0x%08lx)\n", + pos2, gindex + 1, face->glyf_len )); + pos2 = face->glyf_len; + } + /* The `loca' table must be ordered; it refers to the length of */ /* an entry as the difference between the current and the next */ /* position. However, there do exist (malformed) fonts which */ @@ -287,7 +314,7 @@ FT_Short* limit = cur + face->cvt_size; - for ( ; cur < limit; cur++ ) + for ( ; cur < limit; cur++ ) *cur = FT_GET_SHORT(); } |