>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