>From eb85288d5f50a51eabbec94096160ff19516b301 Mon Sep 17 00:00:00 2001 From: Nikolaus Waxweiler Date: Thu, 17 Mar 2016 21:49:06 +0100 Subject: [PATCH 2/2] Implement v38 bytecode interpreter. --- src/truetype/ttinterp.c | 230 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 214 insertions(+), 16 deletions(-) diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c index ccbb1d7..7932d62 100644 --- a/src/truetype/ttinterp.c +++ b/src/truetype/ttinterp.c @@ -1642,6 +1642,10 @@ /* */ /* zone :: The affected glyph zone. */ /* */ + /* */ + /* See ttinterp.h for details on backwards compatibility mode. Will */ + /* `touch' the point. */ + /* */ static void Direct_Move( TT_ExecContext exc, TT_GlyphZone zone, @@ -1660,6 +1664,10 @@ ( !exc->ignore_x_mode || ( exc->sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) ) ) #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + /* Exception to the post-IUP curfew: Allow the x-component of diagonal + * moves, but only post-IUP. DejaVu tries to adjust diagonal stems like + * on 'Z' and 'z' post-IUP. */ + if ( !exc->backwards_compatibility ) zone->cur[point].x += FT_MulDiv( distance, v, exc->F_dot_P ); zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; @@ -1669,7 +1677,9 @@ if ( v != 0 ) { - zone->cur[point].y += FT_MulDiv( distance, v, exc->F_dot_P ); + if ( !( exc->backwards_compatibility && + exc->iupx_called && exc->iupy_called ) ) + zone->cur[point].y += FT_MulDiv( distance, v, exc->F_dot_P ); zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; } @@ -1720,6 +1730,7 @@ /* */ /* The following versions are used whenever both vectors are both */ /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */ + /* See ttinterp.h for details on backwards compatibility mode. */ /* */ /*************************************************************************/ @@ -1736,6 +1747,7 @@ if ( !SUBPIXEL_HINTING || !exc->ignore_x_mode ) #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + if ( ! exc->backwards_compatibility ) zone->cur[point].x += distance; zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; @@ -1750,7 +1762,9 @@ { FT_UNUSED( exc ); - zone->cur[point].y += distance; + if ( !( exc->backwards_compatibility && + exc->iupx_called && exc->iupy_called ) ) + zone->cur[point].y += distance; zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; } @@ -1853,6 +1867,9 @@ /* */ /* Rounded distance. */ /* */ + /* */ + /* See ttinterp.h for details on backwards compatibility mode. */ + /* */ static FT_F26Dot6 Round_To_Grid( TT_ExecContext exc, FT_F26Dot6 distance, @@ -1860,8 +1877,9 @@ { FT_F26Dot6 val; - FT_UNUSED( exc ); + if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0 ) + return Round_None( exc, distance, compensation ); if ( distance >= 0 ) { @@ -1896,6 +1914,9 @@ /* */ /* Rounded distance. */ /* */ + /* */ + /* See ttinterp.h for details on backwards compatibility mode. */ + /* */ static FT_F26Dot6 Round_To_Half_Grid( TT_ExecContext exc, FT_F26Dot6 distance, @@ -1903,8 +1924,9 @@ { FT_F26Dot6 val; - FT_UNUSED( exc ); + if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0 ) + return Round_None( exc, distance, compensation ); if ( distance >= 0 ) { @@ -1939,6 +1961,9 @@ /* */ /* Rounded distance. */ /* */ + /* */ + /* See ttinterp.h for details on backwards compatibility mode. */ + /* */ static FT_F26Dot6 Round_Down_To_Grid( TT_ExecContext exc, FT_F26Dot6 distance, @@ -1946,8 +1971,9 @@ { FT_F26Dot6 val; - FT_UNUSED( exc ); + if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0 ) + return Round_None( exc, distance, compensation ); if ( distance >= 0 ) { @@ -1982,6 +2008,9 @@ /* */ /* Rounded distance. */ /* */ + /* */ + /* See ttinterp.h for details on backwards compatibility mode. */ + /* */ static FT_F26Dot6 Round_Up_To_Grid( TT_ExecContext exc, FT_F26Dot6 distance, @@ -1989,8 +2018,9 @@ { FT_F26Dot6 val; - FT_UNUSED( exc ); + if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0 ) + return Round_None( exc, distance, compensation ); if ( distance >= 0 ) { @@ -2025,6 +2055,9 @@ /* */ /* Rounded distance. */ /* */ + /* */ + /* See ttinterp.h for details on backwards compatibility mode. */ + /* */ static FT_F26Dot6 Round_To_Double_Grid( TT_ExecContext exc, FT_F26Dot6 distance, @@ -2032,8 +2065,9 @@ { FT_F26Dot6 val; - FT_UNUSED( exc ); + if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0 ) + return Round_None( exc, distance, compensation ); if ( distance >= 0 ) { @@ -2074,6 +2108,8 @@ /* the description of super round that we should add the compensation */ /* before rounding. */ /* */ + /* See ttinterp.h for details on backwards compatibility mode. */ + /* */ static FT_F26Dot6 Round_Super( TT_ExecContext exc, FT_F26Dot6 distance, @@ -2082,6 +2118,9 @@ FT_F26Dot6 val; + if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0 ) + return Round_None( exc, distance, compensation ); + if ( distance >= 0 ) { val = ( distance - exc->phase + exc->threshold + compensation ) & @@ -2123,6 +2162,8 @@ /* There is a separate function for Round_Super_45() as we may need */ /* greater precision. */ /* */ + /* See ttinterp.h for details on backwards compatibility mode. */ + /* */ static FT_F26Dot6 Round_Super_45( TT_ExecContext exc, FT_F26Dot6 distance, @@ -2131,6 +2172,9 @@ FT_F26Dot6 val; + if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0 ) + return Round_None( exc, distance, compensation ); + if ( distance >= 0 ) { val = ( ( distance - exc->phase + exc->threshold + compensation ) / @@ -5049,6 +5093,11 @@ if ( K == 3 ) exc->ignore_x_mode = FT_BOOL( L == 4 ); #endif + /* Native ClearType fonts sign a waiver that turns off all backwards + * compatibility hacks and lets them program points to the grid like it's + * 1996. They might sign a waiver for just one glyph though. */ + if ( K == 3 ) + exc->backwards_compatibility = ! FT_BOOL( L == 4 ); } @@ -5133,6 +5182,10 @@ FT_UShort point; + /* See ttinterp.h for details on backwards compatibility mode. */ + if ( exc->backwards_compatibility && exc->iupx_called && exc->iupy_called ) + goto Fail; + if ( exc->top < exc->GS.loop ) { if ( exc->pedantic_hinting ) @@ -5179,6 +5232,10 @@ FT_UShort I, K, L; + /* See ttinterp.h for details on backwards compatibility mode. */ + if ( exc->backwards_compatibility && exc->iupx_called && exc->iupy_called ) + return; + K = (FT_UShort)args[1]; L = (FT_UShort)args[0]; @@ -5208,6 +5265,10 @@ FT_UShort I, K, L; + /* See ttinterp.h for details on backwards compatibility mode. */ + if ( exc->backwards_compatibility && exc->iupx_called && exc->iupy_called ) + return; + K = (FT_UShort)args[1]; L = (FT_UShort)args[0]; @@ -5267,6 +5328,7 @@ } + /* See ttinterp.h for details on backwards compatibility mode. */ static void Move_Zp2_Point( TT_ExecContext exc, FT_UShort point, @@ -5276,14 +5338,18 @@ { if ( exc->GS.freeVector.x != 0 ) { - exc->zp2.cur[point].x += dx; + if ( !( exc->backwards_compatibility && + exc->iupx_called && exc->iupy_called ) ) + exc->zp2.cur[point].x += dx; if ( touch ) exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X; } if ( exc->GS.freeVector.y != 0 ) { - exc->zp2.cur[point].y += dy; + if ( !( exc->backwards_compatibility && + exc->iupx_called && exc->iupy_called ) ) + exc->zp2.cur[point].y += dy; if ( touch ) exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y; } @@ -5337,7 +5403,10 @@ Move_Zp2_Point( exc, point, 0, dy, TRUE ); else #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - Move_Zp2_Point( exc, point, dx, dy, TRUE ); + if ( exc->backwards_compatibility ) + Move_Zp2_Point( exc, point, 0, dy, TRUE ); + else + Move_Zp2_Point( exc, point, dx, dy, TRUE ); exc->GS.loop--; } @@ -5468,7 +5537,6 @@ FT_Int B1, B2; #endif - if ( exc->top < exc->GS.loop + 1 ) { if ( exc->pedantic_hinting ) @@ -5574,7 +5642,17 @@ #else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - Move_Zp2_Point( exc, point, dx, dy, TRUE ); + if ( exc->backwards_compatibility ) + { + /* XXX: breaks Rokkitt < v1.2 (glyphs explode vertically on ALIGNRP). + */ + if ( !( exc->iupx_called && exc->iupy_called ) && + ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) || + ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ) ) + Move_Zp2_Point( exc, point, 0, dy, TRUE ); + } + else + Move_Zp2_Point( exc, point, dx, dy, TRUE ); #endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ @@ -5616,6 +5694,12 @@ #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + FT_F26Dot6 control_value_cutin = exc->GS.control_value_cutin; + + /* See ttinterp.h for details on backwards compatibility mode. */ + if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0 ) + control_value_cutin = 0; + point = (FT_UShort)args[0]; if ( BOUNDS( point, exc->zp1.n_points ) || @@ -5646,6 +5730,10 @@ distance = args[1]; #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + if ( exc->backwards_compatibility && + FT_ABS( distance - args[1] ) >= control_value_cutin ) + distance = args[1]; + exc->func_move( exc, &exc->zp1, point, args[1] - distance ); exc->GS.rp1 = exc->GS.rp0; @@ -5738,6 +5826,10 @@ control_value_cutin = 0; #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + /* See ttinterp.h for details on backwards compatibility mode. */ + if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0 ) + control_value_cutin = 0; + if ( BOUNDS( point, exc->zp0.n_points ) || BOUNDSL( cvtEntry, exc->cvtSize ) ) { @@ -5845,6 +5937,10 @@ minimum_distance = 0; #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + /* See ttinterp.h for details on backwards compatibility mode. */ + if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0x0 ) + minimum_distance = 0; + point = (FT_UShort)args[0]; if ( BOUNDS( point, exc->zp1.n_points ) || @@ -5998,6 +6094,10 @@ control_value_cutin = minimum_distance = 0; #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + /* See ttinterp.h for details on backwards compatibility mode. */ + if ( exc->backwards_compatibility && exc->GS.freeVector.y == 0x0 ) + control_value_cutin = minimum_distance = 0; + /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */ if ( BOUNDS( point, exc->zp1.n_points ) || @@ -6106,6 +6206,13 @@ } #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + if ( exc->backwards_compatibility && + exc->GS.gep0 == exc->GS.gep1 ) + { + if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin ) + cvt_dist = org_dist; + } + distance = Round_None( exc, cvt_dist, @@ -6324,6 +6431,7 @@ R.x = FT_MulDiv( val, dax, discriminant ); R.y = FT_MulDiv( val, day, discriminant ); + /* XXX: Block in backwards_compatibility and/or post-IUP? */ exc->zp2.cur[point].x = exc->zp1.cur[a0].x + R.x; exc->zp2.cur[point].y = exc->zp1.cur[a0].y + R.y; } @@ -6331,6 +6439,7 @@ { /* else, take the middle of the middles of A and B */ + /* XXX: Block in backwards_compatibility and/or post-IUP? */ exc->zp2.cur[point].x = ( exc->zp1.cur[a0].x + exc->zp1.cur[a1].x + exc->zp0.cur[b0].x + @@ -6719,6 +6828,20 @@ FT_Short contour; /* current contour */ + /* See ttinterp.h for details on backwards compatibility mode. Allow IUP + * until it has been called on both axes, immediately return on subsequent + * ones. */ + if ( exc->backwards_compatibility ) + { + if ( exc->iupx_called && exc->iupy_called ) + return; + + if ( exc->opcode & 1 ) + exc->iupx_called = TRUE; + else + exc->iupy_called = TRUE; + } + /* ignore empty outlines */ if ( exc->pts.n_contours == 0 ) return; @@ -6945,8 +7068,15 @@ } else #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - - exc->func_move( exc, &exc->zp0, A, B ); + /* See ttinterp.h for details on backwards compatibility mode. */ + if ( exc->backwards_compatibility ) + { + if ( !( exc->iupx_called && exc->iupy_called ) && + ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) || + ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) ) ) + exc->func_move( exc, &exc->zp0, A, B ); + } else + exc->func_move( exc, &exc->zp0, A, B ); } } else @@ -7063,9 +7193,11 @@ FT_Long* args ) { FT_Long K; + TT_Driver driver; K = 0; + driver = (TT_Driver)FT_FACE_DRIVER( exc->face ); #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING /********************************/ @@ -7091,7 +7223,7 @@ else #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ if ( ( args[0] & 1 ) != 0 ) - K = TT_INTERPRETER_VERSION_35; + K = driver->interpreter_version; /********************************/ /* GLYPH ROTATED */ @@ -7110,13 +7242,65 @@ K |= 1 << 8; /********************************/ - /* HINTING FOR GRAYSCALE */ + /* BI-LEVEL HINTING AND */ + /* GRAYSCALE RENDERING */ /* Selector Bit: 5 */ /* Return Bit(s): 12 */ /* */ if ( ( args[0] & 32 ) != 0 && exc->grayscale ) K |= 1 << 12; + + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) + { + /********************************/ + /* HINTING FOR SUBPIXEL */ + /* Selector Bit: 6 */ + /* Return Bit(s): 13 */ + /* */ + /* v38 will do subpixel hinting by default. */ + if ( ( args[0] & 64 ) != 0 ) + K |= 1 << 13; + + /********************************/ + /* VERTICAL LCD SUBPIXELS? */ + /* Selector Bit: 8 */ + /* Return Bit(s): 15 */ + /* */ + if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd ) + K |= 1 << 15; + + /********************************/ + /* SUBPIXEL POSITIONED? */ + /* Selector Bit: 10 */ + /* Return Bit(s): 17 */ + /* */ + /* XXX: FreeType supports it, dependant on what client does? */ + if ( ( args[0] & 1024 ) != 0 ) + K |= 1 << 17; + + /********************************/ + /* SYMMETRICAL SMOOTHING */ + /* Selector Bit: 11 */ + /* Return Bit(s): 18 */ + /* */ + /* The only smoothing method FreeType supports unless someone set + * FT_LOAD_TARGET_MONO. */ + if ( ( args[0] & 2048 ) != 0 ) + K |= 1 << 18; + + /********************************/ + /* CLEARTYPE HINTING AND */ + /* GRAYSCALE RENDERING */ + /* Selector Bit: 12 */ + /* Return Bit(s): 19 */ + /* */ + /* Grayscale rendering is what FreeType does anyway unless someone set + * FT_LOAD_TARGET_MONO or FT_LOAD_TARGET_LCD(_V) */ + if ( ( args[0] & 4096 ) != 0 && exc->grayscale_cleartype ) + K |= 1 << 19; + } + #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING if ( SUBPIXEL_HINTING && @@ -7274,6 +7458,8 @@ FT_Long ins_counter = 0; /* executed instructions counter */ FT_UShort i; + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( exc->face ); + #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING FT_Byte opcode_pattern[1][2] = { /* #8 TypeMan Talk Align */ @@ -7291,6 +7477,18 @@ #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING exc->iup_called = FALSE; #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + /* Toggle backwards compatibility according to what font says, except when + * it's a 'tricky' font that heavily relies on the interpreter to render + * glyphs correctly, e.g. DFKai-SB. Backwards compatibility hacks may break + * it. */ + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 && + !FT_IS_TRICKY( (&exc->face->root) ) ) + exc->backwards_compatibility = ! (exc->GS.instruct_control & 4); + else + exc->backwards_compatibility = FALSE; + + exc->iupx_called = FALSE; + exc->iupy_called = FALSE; /* set PPEM and CVT functions */ exc->tt_metrics.ratio = 0; -- 2.5.0