From 6d0ae3ae94e4d77d5fb89fe92628300b347c7b64 Mon Sep 17 00:00:00 2001 From: Alexei Podtelezhnikov Date: Sun, 26 Apr 2026 08:26:52 -0400 Subject: [PATCH 1/3] [truetype] Fix SHZ according to specifications. SHZ must shift the zone specified by its arguments. Previously, it was shifting zp2 instead. * src/truetype/ttinterp.c (Ins_SHZ): Rewrite to specifications. --- src/truetype/ttinterp.c | 59 ++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c index 44400fbe2..f2bdac13b 100644 --- a/src/truetype/ttinterp.c +++ b/src/truetype/ttinterp.c @@ -5111,16 +5111,28 @@ Ins_SHZ( TT_ExecContext exc, FT_Long* args ) { + FT_Vector* cur; TT_GlyphZoneRec zp; - FT_UShort refp; + FT_UShort refp, i, limit; FT_F26Dot6 dx, dy; - FT_UShort limit, i; - - if ( BOUNDS( args[0], 2 ) ) + /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points, */ + /* which must be subtracted. */ + switch ( (FT_Int)args[0] ) { + case 0: + cur = exc->twilight.cur; + limit = exc->twilight.n_points; + break; + + case 1: + cur = exc->pts.cur; + limit = exc->pts.n_points > 4U ? exc->pts.n_points - 4U : 0; + break; + + default: if ( exc->pedantic_hinting ) exc->error = FT_THROW( Invalid_Reference ); return; @@ -5129,22 +5141,31 @@ if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) ) return; - /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */ - /* Twilight zone has no real contours, so use `n_points'. */ - /* Normal zone's `n_points' includes phantoms, so must */ - /* subtract them. */ - if ( exc->GS.gep2 == 0 ) - limit = exc->zp2.n_points; - else if ( exc->zp2.n_points > 4U ) - limit = exc->zp2.n_points - 4U; - else - return; - - /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */ - for ( i = 0; i < limit; i++ ) + /* XXX: UNDOCUMENTED! SHZ doesn't touch the points. */ + if ( dx ) { - if ( zp.cur != exc->zp2.cur || refp != i ) - Move_Zp2_Point( exc, i, dx, dy, FALSE ); +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( !exc->backward_compatibility ) +#endif + for ( i = 0; i < limit; i++ ) + { + if ( zp.cur != cur || refp != i ) + cur[i].x = ADD_LONG( cur[i].x, dx ); + } + } + + if ( dy ) + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( exc->backward_compatibility != 0x7 ) +#endif + for ( i = 0; i < limit; i++ ) + { + if ( zp.cur != cur || refp != i ) + cur[i].y = ADD_LONG( cur[i].y, dy ); + } } } From 85c20f4e78e3443704ac00f2f957ef873b068bdd Mon Sep 17 00:00:00 2001 From: Alexei Podtelezhnikov Date: Sun, 26 Apr 2026 08:32:13 -0400 Subject: [PATCH 2/3] * src/truetype/ttinterp.c (Move_Zp2_Point): Remove 'touch'. Update all callers. --- src/truetype/ttinterp.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c index f2bdac13b..ff98ccf7b 100644 --- a/src/truetype/ttinterp.c +++ b/src/truetype/ttinterp.c @@ -4967,8 +4967,7 @@ Move_Zp2_Point( TT_ExecContext exc, FT_UShort point, FT_F26Dot6 dx, - FT_F26Dot6 dy, - FT_Bool touch ) + FT_F26Dot6 dy ) { if ( exc->GS.freeVector.x != 0 ) { @@ -4978,8 +4977,7 @@ #endif exc->zp2.cur[point].x = ADD_LONG( exc->zp2.cur[point].x, dx ); - if ( touch ) - exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X; + exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X; } if ( exc->GS.freeVector.y != 0 ) @@ -4990,8 +4988,7 @@ #endif exc->zp2.cur[point].y = ADD_LONG( exc->zp2.cur[point].y, dy ); - if ( touch ) - exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y; + exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y; } } @@ -5039,7 +5036,7 @@ } } else - Move_Zp2_Point( exc, point, dx, dy, TRUE ); + Move_Zp2_Point( exc, point, dx, dy ); } Fail: @@ -5096,7 +5093,7 @@ for ( i = start; i < limit; i++ ) { if ( zp.cur != exc->zp2.cur || refp != i ) - Move_Zp2_Point( exc, i, dx, dy, TRUE ); + Move_Zp2_Point( exc, i, dx, dy ); } } @@ -5227,11 +5224,11 @@ ( exc->backward_compatibility != 0x7 && ( ( 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 ); + Move_Zp2_Point( exc, point, 0, dy ); } else #endif - Move_Zp2_Point( exc, point, dx, dy, TRUE ); + Move_Zp2_Point( exc, point, dx, dy ); } Fail: From c8c8b4b8a0d98bee005700d7c7698adb78e96f4f Mon Sep 17 00:00:00 2001 From: Alexei Podtelezhnikov Date: Sun, 26 Apr 2026 08:36:25 -0400 Subject: [PATCH 3/3] [truetype] Simplify shift conditions. * src/truetype/ttinterp.c (Compute_Point_Displacement, Ins_SHP, Ins_SHPIX): Use 'FT_UInt" as point references. (Ins_SHC, Ins_SHZ): Ditto and simplify repeated condition. --- src/truetype/ttinterp.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c index ff98ccf7b..2ea09db1e 100644 --- a/src/truetype/ttinterp.c +++ b/src/truetype/ttinterp.c @@ -4924,7 +4924,7 @@ FT_F26Dot6* x, FT_F26Dot6* y, TT_GlyphZone zone, - FT_UShort* refp ) + FT_UInt* refp ) { TT_GlyphZoneRec zp; FT_UShort p; @@ -4965,7 +4965,7 @@ /* See `ttinterp.h' for details on backward compatibility mode. */ static void Move_Zp2_Point( TT_ExecContext exc, - FT_UShort point, + FT_UInt point, FT_F26Dot6 dx, FT_F26Dot6 dy ) { @@ -5005,10 +5005,10 @@ { FT_Long loop = exc->GS.loop; TT_GlyphZoneRec zp; - FT_UShort refp; + FT_UInt refp; FT_F26Dot6 dx, dy; - FT_UShort point; + FT_UInt point; if ( exc->new_top < loop ) @@ -5025,7 +5025,7 @@ while ( loop-- ) { - point = (FT_UShort)*(--args); + point = (FT_UInt)*(--args); if ( BOUNDS( point, exc->zp2.n_points ) ) { @@ -5059,11 +5059,10 @@ FT_Long* args ) { TT_GlyphZoneRec zp; - FT_UShort refp; + FT_UInt refp, start, limit, i; FT_F26Dot6 dx, dy; FT_UShort contour, bounds; - FT_UShort start, limit, i; contour = (FT_UShort)args[0]; @@ -5079,6 +5078,9 @@ if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) ) return; + if ( zp.cur != exc->zp2.cur ) + refp = ~0U; /* nan */ + if ( contour == 0 ) start = 0; else @@ -5092,7 +5094,7 @@ for ( i = start; i < limit; i++ ) { - if ( zp.cur != exc->zp2.cur || refp != i ) + if ( refp != i ) Move_Zp2_Point( exc, i, dx, dy ); } } @@ -5110,9 +5112,8 @@ { FT_Vector* cur; TT_GlyphZoneRec zp; - FT_UShort refp, i, limit; - FT_F26Dot6 dx, - dy; + FT_UInt refp, i, limit; + FT_F26Dot6 dx, dy; /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points, */ @@ -5138,6 +5139,9 @@ if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) ) return; + if ( zp.cur != cur ) + refp = ~0U; /* nan */ + /* XXX: UNDOCUMENTED! SHZ doesn't touch the points. */ if ( dx ) { @@ -5147,7 +5151,7 @@ #endif for ( i = 0; i < limit; i++ ) { - if ( zp.cur != cur || refp != i ) + if ( refp != i ) cur[i].x = ADD_LONG( cur[i].x, dx ); } } @@ -5160,7 +5164,7 @@ #endif for ( i = 0; i < limit; i++ ) { - if ( zp.cur != cur || refp != i ) + if ( refp != i ) cur[i].y = ADD_LONG( cur[i].y, dy ); } } @@ -5179,7 +5183,7 @@ { FT_Long loop = exc->GS.loop; FT_F26Dot6 dx, dy; - FT_UShort point; + FT_UInt point; #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL FT_Bool in_twilight = FT_BOOL( exc->GS.gep0 == 0 || exc->GS.gep1 == 0 || @@ -5201,7 +5205,7 @@ while ( loop-- ) { - point = (FT_UShort)*(--args); + point = (FT_UInt)*(--args); if ( BOUNDS( point, exc->zp2.n_points ) ) {