Hi Werner,
Here is likely the final form of mod to freetype that I am putting in as part
of the next release of font validator. Mostly it is just two new APIs : to set
and unset an external diagnostics messaging routine, and a macro which wrap
around it to call it in a nicer way: DIAGNOSTICS("message", where).
The rest is just a lot of scattered:
"DIAGNOSTICS('message", where)",
or
"if (simple_condition) DIAGNOSTICS('message", where)".
If you re-define the macro to nothing, it causes no functionality change to
freetype at all.
The end result is simplier than I thought, as mostly freetype already detects
and silently works around the errors; so it is mostly about finding out or
deciding *where* to put the DIANOSTICS().
Sorry that the "message" part is a string - it turns out to be more convenient
for me to have it as a string on the freetype side, instead of having it as a
enum. The set of such strings - I only use 6, but eventually there will be 70+
of them - are a subset of the ~800 enums
(those that starts with "_rast_") in
https://github.com/HinTak/Font-Validator/blob/master/OTFontFileVal/atoms.cs
Trimming (i.e. removing the "_rast_" part) or name-space prepending
("FontVal_rast_") don't add any trouble to me. So if that's more preferable?
Hin-Takdiff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c
index ccbb1d7..7575fe1 100644
--- a/src/truetype/ttinterp.c
+++ b/src/truetype/ttinterp.c
@@ -79,12 +79,31 @@
#define BOUNDSL( x, n ) ( (FT_ULong)(x) >= (FT_ULong)(n) )
+typedef int (*diagnostics_Function)(char *message, char *opcode, int is_composite, int IP, int callTop, int opc, int start);
+
+static diagnostics_Function diagnostics = NULL;
+
#undef SUCCESS
#define SUCCESS 0
#undef FAILURE
#define FAILURE 1
+ FT_EXPORT_DEF( void )
+ TT_diagnostics_unset( void )
+ {
+ diagnostics = NULL;
+ }
+
+ FT_EXPORT_DEF( void )
+ TT_diagnostics_set( diagnostics_Function funcptr )
+ {
+ diagnostics = funcptr;
+ }
+
+#define DIAGNOSTICS(message, context) if (diagnostics) (*diagnostics)(message, opcode_name[(context)->opcode] + 2, (context)->is_composite , (context)->IP, (context)->callTop, ((context)->callTop ? ((context)->callStack + (context)->callTop - 1)->Def->opc : 0), ((context)->callTop ? ((context)->callStack + (context)->callTop - 1)->Def->start : 0))
+
+
/*************************************************************************/
/* */
@@ -1649,6 +1668,7 @@
FT_F26Dot6 distance )
{
FT_F26Dot6 v;
+ FT_Long F_dot_P = 0, moved_x = 0, moved_y = 0;
v = exc->GS.freeVector.x;
@@ -1660,7 +1680,8 @@
( !exc->ignore_x_mode ||
( exc->sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) ) )
#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
- zone->cur[point].x += FT_MulDiv( distance, v, exc->F_dot_P );
+ moved_x = FT_MulDiv( distance, v, exc->F_dot_P );
+ zone->cur[point].x += moved_x;
zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
}
@@ -1669,10 +1690,21 @@
if ( v != 0 )
{
- zone->cur[point].y += FT_MulDiv( distance, v, exc->F_dot_P );
+ moved_y = FT_MulDiv( distance, v, exc->F_dot_P );
+ zone->cur[point].y += moved_y;
zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
}
+
+ F_dot_P =
+ ( (FT_Long)exc->GS.projVector.x * exc->GS.freeVector.x +
+ (FT_Long)exc->GS.projVector.y * exc->GS.freeVector.y ) >> 14;
+
+ if ( FT_ABS( F_dot_P ) < 0x400L )
+ {
+ if ( (moved_x == 0 || moved_y == 0) && distance != 0 )
+ DIAGNOSTICS("_rast_W_PF_VECTORS_AT_OR_NEAR_PERP", exc);
+ }
}
@@ -3951,6 +3983,10 @@
}
exc->numIDefs++;
}
+ else
+ {
+ DIAGNOSTICS("_rast_E_INSTR_DEFD_BY_FS", exc);
+ }
/* opcode must be unsigned 8-bit integer */
if ( 0 > args[0] || args[0] > 0x00FF )
@@ -4130,6 +4166,7 @@
if ( BOUNDS( aIdx1, exc->zp2.n_points ) ||
BOUNDS( aIdx2, exc->zp1.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
return FAILURE;
@@ -4276,7 +4313,7 @@
{
FT_Short S;
FT_Long X, Y;
-
+ FT_Long P_dot_P;
/* Only use low 16bits, then sign extend */
S = (FT_Short)args[1];
@@ -4284,6 +4321,11 @@
S = (FT_Short)args[0];
X = (FT_Long)S;
+ P_dot_P = ( X * X + Y * Y ) >> 14;
+
+ if ( P_dot_P < 0x3C00 ) /* arbitrary - expect 0x4000 */
+ DIAGNOSTICS("_rast_E_VECTOR_XY_INVALID", exc );
+
Normalize( X, Y, &exc->GS.projVector );
exc->GS.dualVector = exc->GS.projVector;
@@ -4303,7 +4345,7 @@
{
FT_Short S;
FT_Long X, Y;
-
+ FT_Long F_dot_F;
/* Only use low 16bits, then sign extend */
S = (FT_Short)args[1];
@@ -4311,6 +4353,11 @@
S = (FT_Short)args[0];
X = S;
+ F_dot_F = ( X * X + Y * Y ) >> 14;
+
+ if ( F_dot_F < 0x3C00 ) /* arbitrary - expect 0x4000 */
+ DIAGNOSTICS("_rast_E_VECTOR_XY_INVALID", exc );
+
Normalize( X, Y, &exc->GS.freeVector );
Compute_Funcs( exc );
}
@@ -4652,6 +4699,7 @@
if ( BOUNDSL( L, exc->zp2.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
R = 0;
@@ -4690,6 +4738,7 @@
if ( BOUNDS( L, exc->zp2.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
return;
@@ -4735,6 +4784,7 @@
if ( BOUNDS( L, exc->zp0.n_points ) ||
BOUNDS( K, exc->zp1.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
D = 0;
@@ -4815,6 +4865,7 @@
if ( BOUNDS( p2, exc->zp1.n_points ) ||
BOUNDS( p1, exc->zp2.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
return;
@@ -5043,6 +5094,9 @@
exc->GS.instruct_control &= ~(FT_Byte)Kf;
exc->GS.instruct_control |= (FT_Byte)L;
+ if ( exc->curRange != tt_coderange_font )
+ DIAGNOSTICS("_rast_E_NOT_CALLED_FROM_PREPROGRAM", exc);
+
#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
/* INSTCTRL modifying flag 3 also has an effect */
/* outside of the CVT program */
@@ -5148,6 +5202,7 @@
if ( BOUNDS( point, exc->pts.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
{
exc->error = FT_THROW( Invalid_Reference );
@@ -5185,6 +5240,7 @@
if ( BOUNDS( K, exc->pts.n_points ) ||
BOUNDS( L, exc->pts.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
return;
@@ -5214,6 +5270,7 @@
if ( BOUNDS( K, exc->pts.n_points ) ||
BOUNDS( L, exc->pts.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
return;
@@ -5249,6 +5306,7 @@
if ( BOUNDS( p, zp.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
*refp = 0;
@@ -5323,6 +5381,7 @@
if ( BOUNDS( point, exc->zp2.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
{
exc->error = FT_THROW( Invalid_Reference );
@@ -5487,6 +5546,7 @@
if ( BOUNDS( point, exc->zp2.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
{
exc->error = FT_THROW( Invalid_Reference );
@@ -5621,6 +5681,7 @@
if ( BOUNDS( point, exc->zp1.n_points ) ||
BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
return;
@@ -5675,6 +5736,7 @@
if ( BOUNDS( point, exc->zp0.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
return;
@@ -5741,6 +5803,8 @@
if ( BOUNDS( point, exc->zp0.n_points ) ||
BOUNDSL( cvtEntry, exc->cvtSize ) )
{
+ if ( BOUNDS( point, exc->zp0.n_points ) )
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
goto Fail;
@@ -5850,6 +5914,7 @@
if ( BOUNDS( point, exc->zp1.n_points ) ||
BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
goto Fail;
@@ -6004,6 +6069,9 @@
BOUNDSL( cvtEntry, exc->cvtSize + 1 ) ||
BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
{
+ if ( BOUNDS( point, exc->zp1.n_points ) ||
+ BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
goto Fail;
@@ -6214,6 +6282,8 @@
if ( exc->top < exc->GS.loop ||
BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
{
+ if ( BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
goto Fail;
@@ -6227,6 +6297,7 @@
if ( BOUNDS( point, exc->zp1.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
{
exc->error = FT_THROW( Invalid_Reference );
@@ -6288,6 +6359,7 @@
BOUNDS( a1, exc->zp1.n_points ) ||
BOUNDS( point, exc->zp2.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
return;
@@ -6365,6 +6437,7 @@
if ( BOUNDS( p1, exc->zp1.n_points ) ||
BOUNDS( p2, exc->zp0.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
return;
@@ -6411,6 +6484,7 @@
if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
goto Fail;
@@ -6430,6 +6504,7 @@
if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) ||
BOUNDS( exc->GS.rp2, exc->zp1.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
old_range = 0;
cur_range = 0;
}
@@ -6464,6 +6539,7 @@
/* check point bounds */
if ( BOUNDS( point, exc->zp2.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
{
exc->error = FT_THROW( Invalid_Reference );
@@ -6512,13 +6588,18 @@
/* new_dist - cur_dist = delta , */
/* new_dist - cur_dist = org_dist - cur_dist , */
/* new_dist = org_dist . */
-
new_dist = org_dist;
+ DIAGNOSTICS("_rast_E_RP1_RP2_SAME_POS_ON_PROJ", exc);
}
}
else
new_dist = 0;
+ /*
+ if ( (new_dist - cur_dist) != 0 && (new_dist - org_dist) == 0)
+ DIAGNOSTICS("_rast_E_RP1_RP2_SAME_POS_ON_PROJ", exc);
+ */
+
exc->func_move( exc,
&exc->zp2,
(FT_UShort)point,
@@ -6549,6 +6630,7 @@
if ( BOUNDS( point, exc->zp0.n_points ) )
{
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
return;
@@ -6757,8 +6839,10 @@
end_point = exc->pts.contours[contour] - exc->pts.first_point;
first_point = point;
- if ( BOUNDS( end_point, exc->pts.n_points ) )
+ if ( BOUNDS( end_point, exc->pts.n_points ) ) {
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
end_point = exc->pts.n_points - 1;
+ }
while ( point <= end_point && ( exc->pts.tags[point] & mask ) == 0 )
point++;
@@ -6950,8 +7034,11 @@
}
}
else
+ {
+ DIAGNOSTICS("_rast_E_POINT_OUT_OF_RANGE", exc );
if ( exc->pedantic_hinting )
exc->error = FT_THROW( Invalid_Reference );
+ }
}
Fail:
_______________________________________________
Freetype-devel mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/freetype-devel