From a5fe359596df306666b7f5abc13f1b605359d22c Mon Sep 17 00:00:00 2001 From: Infinality Date: Sat, 26 Jan 2013 12:29:52 -0600 Subject: [PATCH] [truetype] Align more to ClearType whitepaper for sph. --- ChangeLog | 53 +++++ include/freetype/internal/tttypes.h | 6 + src/truetype/ttgload.c | 2 + src/truetype/ttinterp.c | 318 ++++++++++++++++++++-------- src/truetype/ttinterp.h | 12 +- src/truetype/ttobjs.h | 2 +- src/truetype/ttsubpix.c | 84 +++----- src/truetype/ttsubpix.h | 15 ++ 8 files changed, 352 insertions(+), 140 deletions(-) diff --git a/ChangeLog b/ChangeLog index a3da50573..fab11e8aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,56 @@ +2013-01-26 Infinality + + [truetype] Align more to ClearType whitepaper for sph. + + * include/freetype/internal/tttypes.h (TT_FaceRec): Add flags + for detected fdefs and compatibility mode. + + * src/truetype/ttgload.c (tt_loader_init): Complete conditional. + + * src/truetype/ttinterp.c: Updated. Remove SPH_DEBUG and replace + with FT_TRACE7. + (DO_RS): More conditions. + (Ins_FDEF): Add more opcode detection patterns. More specific + conditions when flagging a fdef. Make compatibility mode only turn + on when delta fdefs are found. + (Ins_CALL, Ins_LOOPCALL): Set flags for currently executing fdef. + (Ins_SHPIX): Remove logic to handle ttfautohinted fonts. Simplify + conditionals where possible. Use & instead of % operator for dumb + compilers. + (Ins_MIAP): Adjust twilight zone conditional. Ensure ingore_x_mode + is on when testing sph conditionals. + (Ins_MIRP): Ensure ingore_x_mode is on when testing sph conditionals. + Do cvt cutin always when in ignore_x_mode. Remove test for + ttfautohinted fonts. + (Ins_DELTAP): Ensure ingore_x_mode is on when testing sph conditionals. + Do cvt cutin always when in ignore_x_mode. Remove test for + ttfautohinted fonts. Use & instead of % operator for dumb + compilers. + (Ins_GETINFO): Remove SPH_DEBUG and replace with FT_TRACE7. + + * src/truetype/ttinterp.h: Updated. + (TT_ExecContextRec): Remove compatibility_mode variable. Add variable + to indicate when executing in special fdefs for sph. + + * src/truetype/ttobjs.h: Updated. + (TT_DefRecord): Add flags to identify special fdefs for sph. + (TT_SizeRec): Remove unnecessary ttfautohinted variable. + + * src/truetype/ttsubpix.c: Updated. + (COMPATIBILITY_MODE_Rules): Remove all. Auto-detected now. + (PIXEL_HINTING_Rules): Remove all. Unnecessary after fixes. + (SKIP_NONPIXEL_Y_MOVES_Rules): Remove Ubuntu. + (SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions): Add Arial Bold `N'. + (SKIP_OFFPIXEL_Y_MOVES_Rules): Remove all. Happens automatically now. + (ROUND_NONPIXEL_Y_MOVES_Rules): Remove Ubuntu. + (ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions): Remove all. + (NORMAL_ROUND_Rules): Remove Verdana. + (NO_DELTAP_AFTER_IUP_Rules): Remove all. + (sph_set_tweaks): Performance fix. Don't run prep always. Adjust + conditional for sph_compatibility_mode. + + * src/truetype/ttsubpix.h: Add new fdef flags for sph. + 2013-01-23 Alexei Podtelezhnikov [base] Fix broken emboldening at small sizes. diff --git a/include/freetype/internal/tttypes.h b/include/freetype/internal/tttypes.h index 5eee3cd6c..a29fd1446 100644 --- a/include/freetype/internal/tttypes.h +++ b/include/freetype/internal/tttypes.h @@ -1428,6 +1428,12 @@ FT_BEGIN_HEADER FT_ULong horz_metrics_offset; FT_ULong vert_metrics_offset; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + FT_ULong sph_found_func_flags; /* special funcs identified */ + /* for this face */ + FT_Bool sph_compatibility_mode; +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + } TT_FaceRec; diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c index 08718db0e..ba5e533a8 100644 --- a/src/truetype/ttgload.c +++ b/src/truetype/ttgload.c @@ -1949,6 +1949,8 @@ grayscale = grayscale_hinting = TRUE; subpixel_hinting = FALSE; } + else + grayscale = grayscale_hinting = FALSE; if ( FT_IS_TRICKY( glyph->face ) ) subpixel_hinting = grayscale_hinting = FALSE; diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c index f71a7ec93..03c81c280 100644 --- a/src/truetype/ttinterp.c +++ b/src/truetype/ttinterp.c @@ -34,10 +34,6 @@ #ifdef TT_USE_BYTECODE_INTERPRETER -#define xxxSPH_DEBUG -#define xxxSPH_DEBUG_MORE_VERBOSE - - /*************************************************************************/ /* */ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ @@ -3169,14 +3165,23 @@ /* subpixel hinting - avoid Typeman Dstroke and */ \ /* IStroke and Vacuform rounds */ \ \ - if ( CUR.compatibility_mode && \ - ( I == 24 || I == 22 || I == 8 ) ) \ + if ( CUR.ignore_x_mode && \ + ( ( I == 24 && \ + ( CUR.face->sph_found_func_flags & \ + ( SPH_FDEF_SPACING_1 | \ + SPH_FDEF_SPACING_2 ) ) ) || \ + ( I == 22 && \ + ( CUR.sph_in_func_flags & \ + SPH_FDEF_TYPEMAN_STROKES ) ) || \ + ( I == 8 && \ + ( CUR.face->sph_found_func_flags & \ + SPH_FDEF_VACUFORM_ROUND_1 ) && \ + CUR.iup_called ) ) ) \ args[0] = 0; \ else \ args[0] = CUR.storage[I]; \ } \ } - #else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ #define DO_RS \ @@ -4458,8 +4463,57 @@ #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING /* arguments to opcodes are skipped by `SKIP_Code' */ - FT_Byte opcode_pattern[1][12] = { - /* #0 TTFautohint bytecode (old) */ + FT_Byte opcode_pattern[7][12] = { + /* #0 inline delta function 1 */ + { + 0x4B, /* PPEM */ + 0x53, /* GTEQ */ + 0x23, /* SWAP */ + 0x4B, /* PPEM */ + 0x51, /* LTEQ */ + 0x5A, /* AND */ + 0x58, /* IF */ + 0x38, /* SHPIX */ + 0x1B, /* ELSE */ + 0x21, /* POP */ + 0x21, /* POP */ + 0x59 /* EIF */ + }, + /* #1 inline delta function 2 */ + { + 0x4B, /* PPEM */ + 0x54, /* EQ */ + 0x58, /* IF */ + 0x38, /* SHPIX */ + 0x1B, /* ELSE */ + 0x21, /* POP */ + 0x21, /* POP */ + 0x59 /* EIF */ + }, + /* #2 diagonal stroke function */ + { + 0x20, /* DUP */ + 0x20, /* DUP */ + 0xB0, /* PUSHB_1 */ + /* 1 */ + 0x60, /* ADD */ + 0x46, /* GC_cur */ + 0xB0, /* PUSHB_1 */ + /* 64 */ + 0x23, /* SWAP */ + 0x42 /* WS */ + }, + /* #3 VacuFormRound function */ + { + 0x45, /* RCVT */ + 0x23, /* SWAP */ + 0x46, /* GC_cur */ + 0x60, /* ADD */ + 0x20, /* DUP */ + 0xB0 /* PUSHB_1 */ + /* 38 */ + }, + /* #4 TTFautohint bytecode (old) */ { 0x20, /* DUP */ 0x64, /* ABS */ @@ -4470,10 +4524,27 @@ 0x23, /* SWAP */ 0xB0 /* PUSHB_1 */ }, + /* #5 spacing function 1 */ + { + 0x01, /* SVTCA_x */ + 0xB0, /* PUSHB_1 */ + /* 24 */ + 0x43, /* RS */ + 0x58 /* IF */ + }, + /* #6 spacing function 2 */ + { + 0x01, /* SVTCA_x */ + 0x18, /* RTG */ + 0xB0, /* PUSHB_1 */ + /* 24 */ + 0x43, /* RS */ + 0x58 /* IF */ + }, }; - FT_UShort opcode_patterns = 1; - FT_UShort opcode_pointer[1] = { 0, }; - FT_UShort opcode_size[1] = { 7, }; + FT_UShort opcode_patterns = 7; + FT_UShort opcode_pointer[7] = { 0, 0, 0, 0, 0, 0, 0 }; + FT_UShort opcode_size[7] = { 12, 8, 8, 6, 7, 4, 5 }; FT_UShort i; #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ @@ -4515,10 +4586,18 @@ rec->start = CUR.IP + 1; rec->active = TRUE; rec->inline_delta = FALSE; + rec->sph_fdef_flags = 0x0000; if ( n > CUR.maxFunc ) CUR.maxFunc = (FT_UInt16)n; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + /* We don't know for sure these are typeman functions, */ + /* however they are only active when RS 22 is called */ + if ( n >= 64 && n <= 66 ) + rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_STROKES; +#endif + /* Now skip the whole function definition. */ /* We don't allow nested IDEFS & FDEFs. */ @@ -4526,33 +4605,85 @@ { #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING -#ifdef SPH_DEBUG_MORE_VERBOSE - printf ( "Opcode: %d ", CUR.opcode ); -#endif - for ( i = 0; i < opcode_patterns; i++ ) { if ( opcode_pointer[i] < opcode_size[i] && CUR.opcode == opcode_pattern[i][opcode_pointer[i]] ) { -#ifdef SPH_DEBUG_MORE_VERBOSE - printf( "function %d, opcode ptrn: %d" - " op# %d: %d FOUND \n", - n, i, opcode_pointer[i], CUR.opcode ); -#endif opcode_pointer[i] += 1; if ( opcode_pointer[i] == opcode_size[i] ) { -#ifdef SPH_DEBUG - printf( "Function signature %d detected in FDEF %d\n", i, n); -#endif + + FT_TRACE7(( "sph: Function %d, opcode ptrn: %d, %s %s\n", i, n, + CUR.face->root.family_name, + CUR.face->root.style_name )); switch ( i ) { case 0: - CUR.size->ttfautohinted = TRUE; + rec->sph_fdef_flags |= SPH_FDEF_INLINE_DELTA_1; + CUR.face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_1; break; + + case 1: + rec->sph_fdef_flags |= SPH_FDEF_INLINE_DELTA_2; + CUR.face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_2; + break; + + case 2: + switch ( n ) + { + /* needs to be implemented still */ + case 58: + rec->sph_fdef_flags |= SPH_FDEF_DIAGONAL_STROKE; + CUR.face->sph_found_func_flags |= SPH_FDEF_DIAGONAL_STROKE; + } + break; + + case 3: + switch ( n ) + { + case 0: + rec->sph_fdef_flags |= SPH_FDEF_VACUFORM_ROUND_1; + CUR.face->sph_found_func_flags |= SPH_FDEF_VACUFORM_ROUND_1; + } + break; + + case 4: + /* probably not necessary to detect anymore */ + rec->sph_fdef_flags |= SPH_FDEF_TTFAUTOHINT_1; + CUR.face->sph_found_func_flags |= SPH_FDEF_TTFAUTOHINT_1; + break; + + case 5: + switch ( n ) + { + case 0: + case 1: + case 2: + case 4: + case 7: + case 8: + rec->sph_fdef_flags |= SPH_FDEF_SPACING_1; + CUR.face->sph_found_func_flags |= SPH_FDEF_SPACING_1; + } + break; + + case 6: + switch ( n ) + { + case 0: + case 1: + case 2: + case 4: + case 7: + case 8: + rec->sph_fdef_flags |= SPH_FDEF_SPACING_2; + CUR.face->sph_found_func_flags |= SPH_FDEF_SPACING_2; + } + break; + } opcode_pointer[i] = 0; } @@ -4562,6 +4693,12 @@ opcode_pointer[i] = 0; } + /* Set sph_compatibility_mode only when deltas are detected */ + CUR.face->sph_compatibility_mode = ( ( CUR.face->sph_found_func_flags & + SPH_FDEF_INLINE_DELTA_1 ) | + ( CUR.face->sph_found_func_flags & + SPH_FDEF_INLINE_DELTA_2 ) ); + #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ switch ( CUR.opcode ) @@ -4607,15 +4744,6 @@ CUR.step_ins = FALSE; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - /* - * CUR.ignore_x_mode may be turned off prior to function calls. This - * ensures it is turned back on. - */ - CUR.ignore_x_mode = ( CUR.subpixel_hinting || CUR.grayscale_hinting ) && - !( CUR.sph_tweak_flags & SPH_TWEAK_PIXEL_HINTING ); -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - if ( pRec->Cur_Count > 0 ) { CUR.callTop++; @@ -4686,6 +4814,9 @@ if ( !def->active ) goto Fail; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + CUR.sph_in_func_flags &= def->sph_fdef_flags; +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ /* check the call stack */ if ( CUR.callTop >= CUR.callSize ) @@ -4708,6 +4839,11 @@ def->start ); CUR.step_ins = FALSE; + +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + CUR.sph_in_func_flags &= !def->sph_fdef_flags; +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + return; Fail: @@ -4764,6 +4900,10 @@ if ( !def->active ) goto Fail; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + CUR.sph_in_func_flags &= def->sph_fdef_flags; +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + /* check stack */ if ( CUR.callTop >= CUR.callSize ) { @@ -4788,6 +4928,10 @@ CUR.step_ins = FALSE; } +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + CUR.sph_in_func_flags &= !def->sph_fdef_flags; +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + return; Fail: @@ -5874,7 +6018,7 @@ /* If not using ignore_x_mode rendering, allow ZP2 move. */ /* If inline deltas aren't allowed, skip ZP2 move. */ /* If using ignore_x_mode rendering, allow ZP2 point move if: */ - /* - freedom vector is y and compatibility_mode is off */ + /* - freedom vector is y and sph_compatibility_mode is off */ /* - the glyph is composite and the move is in the Y direction */ /* - the glyph is specifically set to allow SHPIX moves */ /* - the move is on a previously Y-touched point */ @@ -5891,14 +6035,12 @@ ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_INLINE_DELTAS ) ) goto Skip; - if ( CUR.ignore_x_mode && - !CUR.compatibility_mode && CUR.GS.freeVector.y != 0 ) + if ( !CUR.face->sph_compatibility_mode && CUR.GS.freeVector.y != 0 ) MOVE_Zp2_Point( point, dx, dy, TRUE ); - else if ( CUR.ignore_x_mode && CUR.compatibility_mode ) + else if ( CUR.face->sph_compatibility_mode ) { - if ( CUR.ignore_x_mode && - ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) ) + if ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) { dx = FT_PIX_ROUND( B1 + dx ) - B1; dy = FT_PIX_ROUND( B1 + dy ) - B1; @@ -5920,21 +6062,15 @@ /* reverse any disallowed moves */ if ( ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) && CUR.GS.freeVector.y != 0 && - B1 % 64 != 0 && - B2 % 64 != 0 && + ( B1 & 63 ) != 0 && + ( B2 & 63 ) != 0 && B1 != B2 ) || - ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES ) && + ( CUR.face->sph_compatibility_mode && CUR.GS.freeVector.y != 0 && - B1 % 64 == 0 && - B2 % 64 != 0 && - B1 != B2 && - !CUR.size->ttfautohinted ) ) - { -#ifdef SPH_DEBUG - printf( "Reversing ZP2 move\n" ); -#endif + ( B1 & 63 ) == 0 && + ( B2 & 63 ) != 0 && + B1 != B2 ) ) MOVE_Zp2_Point( point, -dx, -dy, TRUE ); - } } else MOVE_Zp2_Point( point, dx, dy, TRUE ); @@ -6124,8 +6260,9 @@ if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */ { #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - /* only adjust legacy fonts x otherwise breaks Calibri italic */ - if ( CUR.compatibility_mode ) + /* Only adjust when not in sph_compatibility_mode or ignore_x_mode */ + /* Determined via experimentation and may be incorrect */ + if ( !CUR.ignore_x_mode || !CUR.face->sph_compatibility_mode ) #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ CUR.zp0.org[point].x = TT_MulFix14( (FT_UInt32)distance, CUR.GS.freeVector.x ); @@ -6134,7 +6271,8 @@ CUR.zp0.cur[point] = CUR.zp0.org[point]; } #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( ( CUR.sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) && + if ( CUR.ignore_x_mode && + ( CUR.sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) && distance > 0 && CUR.GS.freeVector.y != 0 ) distance = 0; @@ -6352,7 +6490,8 @@ else cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 ); #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( CUR.sph_tweak_flags & SPH_TWEAK_MIRP_CVT_ZERO ) + if ( CUR.ignore_x_mode && + ( CUR.sph_tweak_flags & SPH_TWEAK_MIRP_CVT_ZERO ) ) cvt_dist = 0; #endif @@ -6393,7 +6532,8 @@ cvt_dist = -cvt_dist; } #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( CUR.GS.freeVector.y != 0 && + if ( CUR.ignore_x_mode && + CUR.GS.freeVector.y != 0 && ( CUR.sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) ) { if ( cur_dist < -64 ) @@ -6432,9 +6572,23 @@ CUR.tt_metrics.compensations[CUR.opcode & 3] ); } else +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + { + /* do cvt cut-in always in MIRP for sph */ + if ( CUR.ignore_x_mode && CUR.GS.gep0 == CUR.GS.gep1 ) + { + if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin ) + cvt_dist = org_dist; + } distance = ROUND_None( cvt_dist, CUR.tt_metrics.compensations[CUR.opcode & 3] ); + } +#else + distance = ROUND_None( + cvt_dist, + CUR.tt_metrics.compensations[CUR.opcode & 3] ); +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ /* minimum distance test */ @@ -6461,7 +6615,8 @@ ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) ) distance = FT_PIX_ROUND( B1 + distance - cur_dist ) - B1 + cur_dist; - if ( CUR.GS.freeVector.y != 0 && + if ( CUR.ignore_x_mode && + CUR.GS.freeVector.y != 0 && ( CUR.opcode & 16 ) == 0 && ( CUR.opcode & 8 ) == 0 && ( CUR.sph_tweak_flags & SPH_TWEAK_COURIER_NEW_2_HACK ) ) @@ -6476,17 +6631,16 @@ /* Reverse move if necessary */ if ( CUR.ignore_x_mode ) { - if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES ) && + if ( CUR.face->sph_compatibility_mode && CUR.GS.freeVector.y != 0 && - B1 % 64 == 0 && - B2 % 64 != 0 && - !CUR.size->ttfautohinted ) + ( B1 & 63 ) == 0 && + ( B2 & 63 ) != 0 ) reverse_move = TRUE; if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) && CUR.GS.freeVector.y != 0 && - B2 % 64 != 0 && - B1 % 64 != 0 ) + ( B2 & 63 ) != 0 && + ( B1 & 63 ) != 0 ) reverse_move = TRUE; if ( ( CUR.sph_tweak_flags & @@ -7216,15 +7370,18 @@ B1 = CUR.zp0.cur[A].y; else B1 = CUR.zp0.cur[A].x; - - /* Standard Subpixel Hinting: Allow y move */ - if ( !CUR.compatibility_mode && CUR.GS.freeVector.y != 0 ) +#if 0 + /* Standard Subpixel Hinting: Allow y move */ + /* This messes up dejavu and may not be needed */ + if ( !CUR.face->sph_compatibility_mode && + CUR.GS.freeVector.y != 0 ) CUR_Func_move( &CUR.zp0, A, B ); - + else +#endif /* Compatibility Mode: Allow x or y move if point touched in Y direction */ - else if ( CUR.compatibility_mode && - !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) ) + if ( CUR.face->sph_compatibility_mode && + !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) ) { /* save the y value of the point now; compare after move */ B1 = CUR.zp0.cur[A].y; @@ -7233,7 +7390,7 @@ B = FT_PIX_ROUND( B1 + B ) - B1; /* - * Allow delta move if using compatibility_mode, IUP has not + * Allow delta move if using sph_compatibility_mode, IUP has not * been called, and point is touched on Y. */ if ( !CUR.iup_called && @@ -7245,15 +7402,13 @@ /* Reverse this move if it results in a disallowed move */ if ( CUR.GS.freeVector.y != 0 && - ( ( ( CUR.sph_tweak_flags & - SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES ) && - B1 % 64 == 0 && - B2 % 64 != 0 && - !CUR.size->ttfautohinted ) || + ( ( CUR.face->sph_compatibility_mode && + ( B1 & 63 ) == 0 && + ( B2 & 63 ) != 0 ) || ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) && - B1 % 64 != 0 && - B2 % 64 != 0 ) ) ) + ( B1 & 63 ) != 0 && + ( B2 & 63 ) != 0 ) ) ) CUR_Func_move( &CUR.zp0, A, -B ); } #else @@ -7397,9 +7552,7 @@ if ( ( args[0] & 1 ) != 0 && CUR.ignore_x_mode ) { K = CUR.rasterizer_version; -#ifdef SPH_DEBUG_MORE_VERBOSE - printf(" SETTING AS %d\n", CUR.rasterizer_version ); -#endif + FT_TRACE7(( "Setting rasterizer version %d\n", CUR.rasterizer_version )); } else #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ @@ -7871,8 +8024,7 @@ #endif #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( CUR.ignore_x_mode ) - CUR.iup_called = FALSE; + CUR.iup_called = FALSE; #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ /* set CVT functions */ diff --git a/src/truetype/ttinterp.h b/src/truetype/ttinterp.h index 6c65df4b6..84602105a 100644 --- a/src/truetype/ttinterp.h +++ b/src/truetype/ttinterp.h @@ -269,10 +269,6 @@ FT_BEGIN_HEADER FT_Bool ignore_x_mode; /* Standard rendering mode for */ /* subpixel hinting. On if gray */ /* or subpixel hinting is on ) */ - FT_Bool compatibility_mode;/* Additional exceptions to */ - /* native TT rules for legacy */ - /* fonts. Implies */ - /* ignore_x_mode. */ /* The following 4 aren't fully implemented but here for MS rasterizer */ /* compatibility. */ @@ -286,8 +282,12 @@ FT_BEGIN_HEADER FT_Bool iup_called; /* IUP called for glyph? */ - FT_ULong sph_tweak_flags; /* flags to control */ - /* hint tweaks */ + FT_ULong sph_tweak_flags; /* flags to control */ + /* hint tweaks */ + + FT_ULong sph_in_func_flags; /* flags to indicate if in */ + /* special functions */ + #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ } TT_ExecContextRec; diff --git a/src/truetype/ttobjs.h b/src/truetype/ttobjs.h index 5c3cb067e..98a69aa70 100644 --- a/src/truetype/ttobjs.h +++ b/src/truetype/ttobjs.h @@ -179,6 +179,7 @@ FT_BEGIN_HEADER FT_UInt opc; /* function #, or instruction code */ FT_Bool active; /* is it active? */ FT_Bool inline_delta; /* is function that defines inline delta? */ + FT_ULong sph_fdef_flags; /* flags to identify special functions */ } TT_DefRecord, *TT_DefArray; @@ -334,7 +335,6 @@ FT_BEGIN_HEADER FT_Bool bytecode_ready; FT_Bool cvt_ready; - FT_Bool ttfautohinted; #endif /* TT_USE_BYTECODE_INTERPRETER */ diff --git a/src/truetype/ttsubpix.c b/src/truetype/ttsubpix.c index cfd99863e..29eda9258 100644 --- a/src/truetype/ttsubpix.c +++ b/src/truetype/ttsubpix.c @@ -275,32 +275,24 @@ }; - /* Special fixes for known legacy fonts; */ - /* this is the primary workhorse rule for legacy fonts */ -#define COMPATIBILITY_MODE_RULES_SIZE 4 + /* Force special legacy fixes for fonts; */ +#define COMPATIBILITY_MODE_RULES_SIZE 1 const SPH_TweakRule COMPATIBILITY_MODE_Rules [COMPATIBILITY_MODE_RULES_SIZE] = { - { "MS Legacy Fonts", 0, "", 0 }, - { "Apple Legacy Fonts", 0, "", 0 }, - { "Misc Legacy Fonts", 0, "", 0 }, - { "Verdana Clones", 0, "", 0 }, + { "-", 0, "", 0 }, }; /* Don't do subpixel (ignore_x_mode) hinting; do normal hinting. */ -#define PIXEL_HINTING_RULES_SIZE 4 +#define PIXEL_HINTING_RULES_SIZE 1 const SPH_TweakRule PIXEL_HINTING_Rules [PIXEL_HINTING_RULES_SIZE] = { /* these characters are almost always safe */ - { "", 0, "", '<' }, - { "", 0, "", '>' }, - /* fixes the vanishing stem */ - { "Times New Roman", 0, "Bold", 'A' }, - { "Times New Roman", 0, "Bold", 'V' }, + { "-", 0, "", 0 }, }; @@ -328,7 +320,7 @@ /* Skip Y moves that start with a point that is not on a Y pixel */ /* boundary and don't move that point to a Y pixel boundary. */ -#define SKIP_NONPIXEL_Y_MOVES_RULES_SIZE 10 +#define SKIP_NONPIXEL_Y_MOVES_RULES_SIZE 9 const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules [SKIP_NONPIXEL_Y_MOVES_RULES_SIZE] = @@ -344,7 +336,6 @@ /* Cyrillic small letter I */ { "Legacy Sans Fonts", 0, "", 0x438 }, { "Verdana Clones", 0, "",'N' }, - { "Ubuntu", 0, "Regular Class", 'N' }, /* Fix misshapen x */ { "Verdana", 0, "Bold", 'x' }, /* Fix misshapen s */ @@ -352,7 +343,7 @@ }; -#define SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 6 +#define SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 7 const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions [SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] = @@ -363,22 +354,18 @@ { "Verdana", 11, "Bold", 'x' }, /* Cyrillic small letter I */ { "Arial", 0, "", 0x438 }, + { "Arial", 11, "Bold", 'N' }, { "Trebuchet MS", 0, "Bold", 0 }, }; /* Skip Y moves that move a point off a Y pixel boundary. */ - /* This fixes Tahoma, Trebuchet oddities and some issues with `$'. */ -#define SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE 5 +#define SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE 1 const SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules [SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE] = { - { "MS Legacy Fonts", 0, "", 0 }, - { "Apple Legacy Fonts", 0, "", 0 }, - { "Misc Legacy Fonts", 0, "", 0 }, - { "Ubuntu", 0, "Regular Class", 0 }, - { "Verdana Clones", 0, "", 0 }, + { "-", 0, "", 0 }, }; @@ -392,7 +379,7 @@ /* Round moves that don't move a point to a Y pixel boundary. */ -#define ROUND_NONPIXEL_Y_MOVES_RULES_SIZE 3 +#define ROUND_NONPIXEL_Y_MOVES_RULES_SIZE 2 const SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules [ROUND_NONPIXEL_Y_MOVES_RULES_SIZE] = @@ -400,18 +387,15 @@ /* Droid font instructions don't snap Y to pixels */ { "Droid Sans", 0, "Regular/Italic Class", 0 }, { "Droid Sans Mono", 0, "", 0 }, - { "Ubuntu", 0, "", 0 }, }; -#define ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 3 +#define ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1 const SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions [ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] = { - { "Droid Sans", 12, "Bold", 0 }, - { "Droid Sans", 13, "Bold", 0 }, - { "Droid Sans", 16, "Bold", 0 }, + { "-", 0, "", 0 }, }; @@ -466,14 +450,13 @@ /* Don't round to the subpixel grid. Round to pixel grid. */ -#define NORMAL_ROUND_RULES_SIZE 2 +#define NORMAL_ROUND_RULES_SIZE 1 const SPH_TweakRule NORMAL_ROUND_Rules [NORMAL_ROUND_RULES_SIZE] = { - /* Fix point "explosions" */ + /* Fix serif thickness */ { "Courier New", 0, "", 0 }, - { "Verdana", 10, "Regular", '4' }, }; @@ -563,8 +546,7 @@ static const SPH_TweakRule DELTAP_SKIP_EXAGGERATED_VALUES_Rules [DELTAP_SKIP_EXAGGERATED_VALUES_RULES_SIZE] = { - /* Fix vanishing stems */ - { "Ubuntu", 0, "Regular", 'M' }, + { "-", 0, "", 0 }, }; @@ -583,13 +565,12 @@ /* Don't allow DELTAP after IUP. */ -#define NO_DELTAP_AFTER_IUP_RULES_SIZE 2 +#define NO_DELTAP_AFTER_IUP_RULES_SIZE 1 static const SPH_TweakRule NO_DELTAP_AFTER_IUP_Rules [NO_DELTAP_AFTER_IUP_RULES_SIZE] = { - { "Arial", 0, "Bold", 'N' }, - { "Verdana", 0, "Regular", '4' }, + { "-", 0, "", 0 }, }; @@ -1046,15 +1027,22 @@ TWEAK_RULES( ROUND_NONPIXEL_Y_MOVES ); TWEAK_RULES_EXCEPTIONS( ROUND_NONPIXEL_Y_MOVES ); - if ( loader->exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 ) + if ( loader->exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 && + loader->exec->rasterizer_version != 35 ) + { loader->exec->rasterizer_version = 35; - else + loader->exec->size->cvt_ready = FALSE; + tt_size_ready_bytecode( loader->exec->size, + FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) ); + } + else if ( loader->exec->rasterizer_version != + SPH_OPTION_SET_RASTERIZER_VERSION ) + { loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION; - - /* re-execute fpgm always to avoid problems */ - loader->exec->size->cvt_ready = FALSE; - tt_size_ready_bytecode( loader->exec->size, - FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) ); + loader->exec->size->cvt_ready = FALSE; + tt_size_ready_bytecode( loader->exec->size, + FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) ); + } if ( IS_HINTED( loader->load_flags ) ) { @@ -1064,12 +1052,8 @@ if ( sph_test_tweak( face, family, ppem, style, glyph_index, COMPATIBILITY_MODE_Rules, COMPATIBILITY_MODE_RULES_SIZE ) ) - { - loader->exec->compatibility_mode |= TRUE; - loader->exec->ignore_x_mode |= TRUE; - } - else - loader->exec->compatibility_mode &= FALSE; + loader->exec->face->sph_compatibility_mode = TRUE; + if ( IS_HINTED( loader->load_flags ) ) { diff --git a/src/truetype/ttsubpix.h b/src/truetype/ttsubpix.h index 6ae441373..ba39916a2 100644 --- a/src/truetype/ttsubpix.h +++ b/src/truetype/ttsubpix.h @@ -29,6 +29,21 @@ FT_BEGIN_HEADER #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + /*************************************************************************/ + /* */ + /* ID flags to identify special functions at FDEF and runtime. */ + /* */ + /* */ +#define SPH_FDEF_INLINE_DELTA_1 0x0000001 +#define SPH_FDEF_INLINE_DELTA_2 0x0000002 +#define SPH_FDEF_DIAGONAL_STROKE 0x0000004 +#define SPH_FDEF_VACUFORM_ROUND_1 0x0000008 +#define SPH_FDEF_TTFAUTOHINT_1 0x0000010 +#define SPH_FDEF_SPACING_1 0x0000020 +#define SPH_FDEF_SPACING_2 0x0000040 +#define SPH_FDEF_TYPEMAN_STROKES 0x0000080 + + /*************************************************************************/ /* */ /* Tweak flags that are set for each glyph by the below rules. */