[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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
diff --git a/ChangeLog b/ChangeLog
index 2a9b753..bf88625 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2012-10-17 Werner Lemberg <wl@gnu.org>
+
+ [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 <g.esp@free.fr>
Remove useless `rm' detection.
diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c
index a996d17..41f77cd 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 );