Index: src/truetype/ttinterp.c |
diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c |
index 6c4eed684688d1cf9821ba435b36bf991fd740a5..3acb24a2f6f6dc513a2eb4963f77ca36ec5fc79f 100644 |
--- a/src/truetype/ttinterp.c |
+++ b/src/truetype/ttinterp.c |
@@ -4,7 +4,7 @@ |
/* */ |
/* TrueType bytecode interpreter (body). */ |
/* */ |
-/* Copyright 1996-2011 */ |
+/* Copyright 1996-2012 */ |
/* by David Turner, Robert Wilhelm, and Werner Lemberg. */ |
/* */ |
/* This file is part of the FreeType project, and may only be used, */ |
@@ -715,7 +715,7 @@ |
FT_Error error; |
- if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) ) |
+ if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) ) |
!= TT_Err_Ok ) |
return error; |
@@ -1800,7 +1800,7 @@ |
/* NOTE: Because the last instruction of a program may be a CALL */ |
/* which will return to the first byte *after* the code */ |
- /* range, we test for AIP <= Size, instead of AIP < Size. */ |
+ /* range, we test for aIP <= Size, instead of aIP < Size. */ |
if ( aIP > range->size ) |
{ |
@@ -2757,7 +2757,7 @@ |
W = Vx * Vx + Vy * Vy; |
/* Now, we want that Sqrt( W ) = 0x4000 */ |
- /* Or 0x10000000 <= W < 0x10004000 */ |
+ /* Or 0x10000000 <= W < 0x10004000 */ |
if ( Vx < 0 ) |
{ |
@@ -3199,36 +3199,42 @@ |
} |
-#define DO_JROT \ |
- if ( args[1] != 0 ) \ |
- { \ |
- if ( args[0] == 0 && CUR.args == 0 ) \ |
- CUR.error = TT_Err_Bad_Argument; \ |
- CUR.IP += args[0]; \ |
- if ( CUR.IP < 0 ) \ |
- CUR.error = TT_Err_Bad_Argument; \ |
- CUR.step_ins = FALSE; \ |
+#define DO_JROT \ |
+ if ( args[1] != 0 ) \ |
+ { \ |
+ if ( args[0] == 0 && CUR.args == 0 ) \ |
+ CUR.error = TT_Err_Bad_Argument; \ |
+ CUR.IP += args[0]; \ |
+ if ( CUR.IP < 0 || \ |
+ ( CUR.callTop > 0 && \ |
+ CUR.IP > CUR.callStack[CUR.callTop - 1].Cur_End ) ) \ |
+ CUR.error = TT_Err_Bad_Argument; \ |
+ CUR.step_ins = FALSE; \ |
} |
-#define DO_JMPR \ |
- if ( args[0] == 0 && CUR.args == 0 ) \ |
- CUR.error = TT_Err_Bad_Argument; \ |
- CUR.IP += args[0]; \ |
- if ( CUR.IP < 0 ) \ |
- CUR.error = TT_Err_Bad_Argument; \ |
+#define DO_JMPR \ |
+ if ( args[0] == 0 && CUR.args == 0 ) \ |
+ CUR.error = TT_Err_Bad_Argument; \ |
+ CUR.IP += args[0]; \ |
+ if ( CUR.IP < 0 || \ |
+ ( CUR.callTop > 0 && \ |
+ CUR.IP > CUR.callStack[CUR.callTop - 1].Cur_End ) ) \ |
+ CUR.error = TT_Err_Bad_Argument; \ |
CUR.step_ins = FALSE; |
-#define DO_JROF \ |
- if ( args[1] == 0 ) \ |
- { \ |
- if ( args[0] == 0 && CUR.args == 0 ) \ |
- CUR.error = TT_Err_Bad_Argument; \ |
- CUR.IP += args[0]; \ |
- if ( CUR.IP < 0 ) \ |
- CUR.error = TT_Err_Bad_Argument; \ |
- CUR.step_ins = FALSE; \ |
+#define DO_JROF \ |
+ if ( args[1] == 0 ) \ |
+ { \ |
+ if ( args[0] == 0 && CUR.args == 0 ) \ |
+ CUR.error = TT_Err_Bad_Argument; \ |
+ CUR.IP += args[0]; \ |
+ if ( CUR.IP < 0 || \ |
+ ( CUR.callTop > 0 && \ |
+ CUR.IP > CUR.callStack[CUR.callTop - 1].Cur_End ) ) \ |
+ CUR.error = TT_Err_Bad_Argument; \ |
+ CUR.step_ins = FALSE; \ |
} |
@@ -4471,7 +4477,7 @@ |
CUR.length = opcode_length[CUR.opcode]; |
if ( CUR.length < 0 ) |
{ |
- if ( CUR.IP + 1 > CUR.codeSize ) |
+ if ( CUR.IP + 1 >= CUR.codeSize ) |
goto Fail_Overflow; |
CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1]; |
} |
@@ -4640,6 +4646,7 @@ |
return; |
case 0x2D: /* ENDF */ |
+ rec->end = CUR.IP; |
return; |
} |
} |
@@ -4757,6 +4764,7 @@ |
pCrec->Caller_IP = CUR.IP + 1; |
pCrec->Cur_Count = 1; |
pCrec->Cur_Restart = def->start; |
+ pCrec->Cur_End = def->end; |
CUR.callTop++; |
@@ -4835,6 +4843,7 @@ |
pCrec->Caller_IP = CUR.IP + 1; |
pCrec->Cur_Count = (FT_Int)args[0]; |
pCrec->Cur_Restart = def->start; |
+ pCrec->Cur_End = def->end; |
CUR.callTop++; |
@@ -5050,8 +5059,8 @@ |
/* Opcode range: 0x46-0x47 */ |
/* Stack: uint32 --> f26.6 */ |
/* */ |
- /* BULLSHIT: Measures from the original glyph must be taken along the */ |
- /* dual projection vector! */ |
+ /* XXX: UNDOCUMENTED: Measures from the original glyph must be taken */ |
+ /* along the dual projection vector! */ |
/* */ |
static void |
Ins_GC( INS_ARG ) |
@@ -5123,14 +5132,14 @@ |
/* Opcode range: 0x49-0x4A */ |
/* Stack: uint32 uint32 --> f26.6 */ |
/* */ |
- /* BULLSHIT: Measure taken in the original glyph must be along the dual */ |
- /* projection vector. */ |
+ /* XXX: UNDOCUMENTED: Measure taken in the original glyph must be along */ |
+ /* the dual projection vector. */ |
/* */ |
- /* Second BULLSHIT: Flag attributes are inverted! */ |
- /* 0 => measure distance in original outline */ |
- /* 1 => measure distance in grid-fitted outline */ |
+ /* XXX: UNDOCUMENTED: Flag attributes are inverted! */ |
+ /* 0 => measure distance in original outline */ |
+ /* 1 => measure distance in grid-fitted outline */ |
/* */ |
- /* Third one: `zp0 - zp1', and not `zp2 - zp1! */ |
+ /* XXX: UNDOCUMENTED: `zp0 - zp1', and not `zp2 - zp1! */ |
/* */ |
static void |
Ins_MD( INS_ARG ) |
@@ -5155,25 +5164,38 @@ |
D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K ); |
else |
{ |
- FT_Vector* vec1 = CUR.zp0.orus + L; |
- FT_Vector* vec2 = CUR.zp1.orus + K; |
+ /* XXX: UNDOCUMENTED: twilight zone special case */ |
- |
- if ( CUR.metrics.x_scale == CUR.metrics.y_scale ) |
+ if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 ) |
{ |
- /* this should be faster */ |
+ FT_Vector* vec1 = CUR.zp0.org + L; |
+ FT_Vector* vec2 = CUR.zp1.org + K; |
+ |
+ |
D = CUR_Func_dualproj( vec1, vec2 ); |
- D = TT_MULFIX( D, CUR.metrics.x_scale ); |
} |
else |
{ |
- FT_Vector vec; |
+ FT_Vector* vec1 = CUR.zp0.orus + L; |
+ FT_Vector* vec2 = CUR.zp1.orus + K; |
+ |
+ |
+ if ( CUR.metrics.x_scale == CUR.metrics.y_scale ) |
+ { |
+ /* this should be faster */ |
+ D = CUR_Func_dualproj( vec1, vec2 ); |
+ D = TT_MULFIX( D, CUR.metrics.x_scale ); |
+ } |
+ else |
+ { |
+ FT_Vector vec; |
- vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale ); |
- vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale ); |
+ vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale ); |
+ vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale ); |
- D = CUR_fast_dualproj( &vec ); |
+ D = CUR_fast_dualproj( &vec ); |
+ } |
} |
} |
} |
@@ -5748,21 +5770,25 @@ |
/* Opcode range: 0x34-35 */ |
/* Stack: uint32 --> */ |
/* */ |
+ /* UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual) */ |
+ /* contour in the twilight zone, namely contour number */ |
+ /* zero. */ |
+ /* */ |
static void |
Ins_SHC( INS_ARG ) |
{ |
- TT_GlyphZoneRec zp; |
- FT_UShort refp; |
- FT_F26Dot6 dx, |
- dy; |
+ TT_GlyphZoneRec zp; |
+ FT_UShort refp; |
+ FT_F26Dot6 dx, dy; |
- FT_Short contour; |
- FT_UShort first_point, last_point, i; |
+ FT_Short contour, bounds; |
+ FT_UShort start, limit, i; |
contour = (FT_UShort)args[0]; |
+ bounds = ( CUR.GS.gep2 == 0 ) ? 1 : CUR.zp2.n_contours; |
- if ( BOUNDS( contour, CUR.pts.n_contours ) ) |
+ if ( BOUNDS( contour, bounds ) ) |
{ |
if ( CUR.pedantic_hinting ) |
CUR.error = TT_Err_Invalid_Reference; |
@@ -5773,25 +5799,19 @@ |
return; |
if ( contour == 0 ) |
- first_point = 0; |
+ start = 0; |
else |
- first_point = (FT_UShort)( CUR.pts.contours[contour - 1] + 1 - |
- CUR.pts.first_point ); |
- |
- last_point = (FT_UShort)( CUR.pts.contours[contour] - |
- CUR.pts.first_point ); |
+ start = (FT_UShort)( CUR.zp2.contours[contour - 1] + 1 - |
+ CUR.zp2.first_point ); |
- /* XXX: this is probably wrong... at least it prevents memory */ |
- /* corruption when zp2 is the twilight zone */ |
- if ( BOUNDS( last_point, CUR.zp2.n_points ) ) |
- { |
- if ( CUR.zp2.n_points > 0 ) |
- last_point = (FT_UShort)(CUR.zp2.n_points - 1); |
- else |
- last_point = 0; |
- } |
+ /* we use the number of points if in the twilight zone */ |
+ if ( CUR.GS.gep2 == 0 ) |
+ limit = CUR.zp2.n_points; |
+ else |
+ limit = (FT_UShort)( CUR.zp2.contours[contour] - |
+ CUR.zp2.first_point + 1 ); |
- for ( i = first_point; i <= last_point; i++ ) |
+ for ( i = start; i < limit; i++ ) |
{ |
if ( zp.cur != CUR.zp2.cur || refp != i ) |
MOVE_Zp2_Point( i, dx, dy, TRUE ); |
@@ -5813,7 +5833,7 @@ |
FT_F26Dot6 dx, |
dy; |
- FT_UShort last_point, i; |
+ FT_UShort limit, i; |
if ( BOUNDS( args[0], 2 ) ) |
@@ -5826,28 +5846,19 @@ |
if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) |
return; |
- /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */ |
- /* Twilight zone has no contours, so use `n_points'. */ |
- /* Normal zone's `n_points' includes phantoms, so must */ |
- /* use end of last contour. */ |
- if ( CUR.GS.gep2 == 0 && CUR.zp2.n_points > 0 ) |
- last_point = (FT_UShort)( CUR.zp2.n_points - 1 ); |
+ /* 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 */ |
+ /* use end of last contour. */ |
+ if ( CUR.GS.gep2 == 0 ) |
+ limit = (FT_UShort)CUR.zp2.n_points; |
else if ( CUR.GS.gep2 == 1 && CUR.zp2.n_contours > 0 ) |
- { |
- last_point = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] ); |
- |
- if ( BOUNDS( last_point, CUR.zp2.n_points ) ) |
- { |
- if ( CUR.pedantic_hinting ) |
- CUR.error = TT_Err_Invalid_Reference; |
- return; |
- } |
- } |
+ limit = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] + 1 ); |
else |
- last_point = 0; |
+ limit = 0; |
/* XXX: UNDOCUMENTED! SHZ doesn't touch the points */ |
- for ( i = 0; i <= last_point; i++ ) |
+ for ( i = 0; i < limit; i++ ) |
{ |
if ( zp.cur != CUR.zp2.cur || refp != i ) |
MOVE_Zp2_Point( i, dx, dy, FALSE ); |
@@ -6253,7 +6264,7 @@ |
CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y + |
TT_MulFix14( (FT_UInt32)cvt_dist, |
CUR.GS.freeVector.y ); |
- CUR.zp1.cur[point] = CUR.zp0.cur[point]; |
+ CUR.zp1.cur[point] = CUR.zp1.org[point]; |
} |
org_dist = CUR_Func_dualproj( &CUR.zp1.org[point], |
@@ -6562,9 +6573,21 @@ |
if ( twilight ) |
old_range = CUR_Func_dualproj( &CUR.zp1.org[CUR.GS.rp2], |
orus_base ); |
- else |
+ else if ( CUR.metrics.x_scale == CUR.metrics.y_scale ) |
old_range = CUR_Func_dualproj( &CUR.zp1.orus[CUR.GS.rp2], |
orus_base ); |
+ else |
+ { |
+ FT_Vector vec; |
+ |
+ |
+ vec.x = TT_MULFIX( CUR.zp1.orus[CUR.GS.rp2].x - orus_base->x, |
+ CUR.metrics.x_scale ); |
+ vec.y = TT_MULFIX( CUR.zp1.orus[CUR.GS.rp2].y - orus_base->y, |
+ CUR.metrics.y_scale ); |
+ |
+ old_range = CUR_fast_dualproj( &vec ); |
+ } |
cur_range = CUR_Func_project ( &CUR.zp1.cur[CUR.GS.rp2], cur_base ); |
} |
@@ -6588,8 +6611,20 @@ |
if ( twilight ) |
org_dist = CUR_Func_dualproj( &CUR.zp2.org[point], orus_base ); |
- else |
+ else if ( CUR.metrics.x_scale == CUR.metrics.y_scale ) |
org_dist = CUR_Func_dualproj( &CUR.zp2.orus[point], orus_base ); |
+ else |
+ { |
+ FT_Vector vec; |
+ |
+ |
+ vec.x = TT_MULFIX( CUR.zp2.orus[point].x - orus_base->x, |
+ CUR.metrics.x_scale ); |
+ vec.y = TT_MULFIX( CUR.zp2.orus[point].y - orus_base->y, |
+ CUR.metrics.y_scale ); |
+ |
+ org_dist = CUR_fast_dualproj( &vec ); |
+ } |
cur_dist = CUR_Func_project ( &CUR.zp2.cur[point], cur_base ); |
@@ -7136,6 +7171,7 @@ |
call->Caller_IP = CUR.IP + 1; |
call->Cur_Count = 1; |
call->Cur_Restart = def->start; |
+ call->Cur_End = def->end; |
INS_Goto_CodeRange( def->range, def->start ); |
@@ -7508,7 +7544,7 @@ |
if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 ) |
{ |
- if ( CUR.IP + 1 > CUR.codeSize ) |
+ if ( CUR.IP + 1 >= CUR.codeSize ) |
goto LErrorCodeOverflow_; |
CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1]; |
@@ -8144,6 +8180,7 @@ |
callrec->Caller_IP = CUR.IP + 1; |
callrec->Cur_Count = 1; |
callrec->Cur_Restart = def->start; |
+ callrec->Cur_End = def->end; |
if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE ) |
goto LErrorLabel_; |
@@ -8217,7 +8254,7 @@ |
if ( CUR.error && !CUR.instruction_trap ) |
{ |
FT_TRACE1(( " The interpreter returned error 0x%x\n", CUR.error )); |
- exc->size->cvt_ready = FALSE; |
+ exc->size->cvt_ready = FALSE; |
} |
return CUR.error; |