From 2df16761c93bd0d49c0b7e3c6df9e05a3b8a763e Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Wed, 17 Oct 2012 11:34:22 +0200 Subject: [PATCH] [truetype] Fix Savannah bug #37572. * src/truetype/ttinterp.c (Ins_ISECT): Use angle between vectors to avoid grazing intersections. The previous threshold was too coarse, incorrectly rejecting short but valid vectors. --- ChangeLog | 8 ++++++++ src/truetype/ttinterp.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 2a9b7530..bf886258 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2012-10-17 Werner Lemberg + + [truetype] Fix Savannah bug #37572. + + * src/truetype/ttinterp.c (Ins_ISECT): Use angle between vectors to + avoid grazing intersections. The previous threshold was too coarse, + incorrectly rejecting short but valid vectors. + 2012-09-30 Gilles Espinasse Remove useless `rm' detection. diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c index a996d176..41f77cd0 100644 --- a/src/truetype/ttinterp.c +++ b/src/truetype/ttinterp.c @@ -6841,6 +6841,9 @@ dax, day, dbx, dby; + FT_F26Dot6 len_a, len_b; + FT_Long sine; + FT_F26Dot6 val; FT_Vector R; @@ -6864,6 +6867,8 @@ return; } + /* Cramer's rule */ + dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x; dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y; @@ -6878,7 +6883,33 @@ discriminant = TT_MULDIV( dax, -dby, 0x40 ) + TT_MULDIV( day, dbx, 0x40 ); - if ( FT_ABS( discriminant ) >= 0x40 ) + /* Let */ + /* */ + /* a = vector(a0, a1) */ + /* b = vector(b0, b1) . */ + /* */ + /* Then */ + /* */ + /* dot_product(normal_vector(a), b) */ + /* = discriminant */ + /* = |a| * |b| * sin(alpha) . */ + + len_a = TT_VecLen( dax, day ); + len_b = TT_VecLen( dbx, dby ); + + if ( len_a && len_b ) + { + /* precision: (F.6 * F.16) / F.6 = F.16 */ + sine = FT_DivFix( discriminant, len_a ); + /* precision: (F.16 * F.16) / F.6 = F.26 */ + sine = FT_DivFix( sine, len_b ); + } + else + sine = 0; + + /* We reject grazing intersections; heuristic value 2342066 */ + /* corresponds to arcsin(2342066/2^26), this is approx 2 degrees. */ + if ( FT_ABS( sine ) >= 2342066 ) { val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 );