ref: 33f5f24957397d37ff44f27098937f6e1aceed32
parent: 2b21a932f18d4887e5753a41a3303153afdbd418
author: David Turner <[email protected]>
date: Wed Aug 16 12:50:55 EDT 2006
* include/freetype/internal/ftgloadr.h, include/freetype/internal/tttypes.h, src/base/ftgloadr.c, src/base/ftobjs.c, src/truetype/ttgload.c, src/truetype/ttinterp.c, src/truetype/ttobjs.c: improvements to native TrueType hinting, this is a first try, controlled by the FIX_BYTECODE macro in src/truetype/ttinterp.c
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,14 @@
* src/base/ftobjs.c (ft_validator_run): disabling function, it is
buggy by design, so it will always return -1
+ * include/freetype/internal/ftgloadr.h,
+ include/freetype/internal/tttypes.h, src/base/ftgloadr.c,
+ src/base/ftobjs.c, src/truetype/ttgload.c, src/truetype/ttinterp.c,
+ src/truetype/ttobjs.c: improvements to native TrueType hinting,
+ this is a first try, controlled by the FIX_BYTECODE macro in
+ src/truetype/ttinterp.c
+
+
2006-08-15 suzuki toshiya <[email protected]>
* modules.cfg (BASE_EXTENSIONS): Compile in ftgxval.c by default to
--- a/include/freetype/internal/ftgloadr.h
+++ b/include/freetype/internal/ftgloadr.h
@@ -69,6 +69,7 @@
{
FT_Outline outline; /* outline */
FT_Vector* extra_points; /* extra points table */
+ FT_Vector* extra_points2; /* second extra points table */
FT_UInt num_subglyphs; /* number of subglyphs */
FT_SubGlyph subglyphs; /* subglyphs */
--- a/include/freetype/internal/tttypes.h
+++ b/include/freetype/internal/tttypes.h
@@ -1470,6 +1470,7 @@
FT_Vector* org; /* original point coordinates */
FT_Vector* cur; /* current point coordinates */
+ FT_Vector* orus; /* original (unscaled) point coordinates */
FT_Byte* tags; /* current touch flags */
FT_UShort* contours; /* contour end points */
--- a/src/base/ftgloadr.c
+++ b/src/base/ftgloadr.c
@@ -112,6 +112,8 @@
FT_FREE( loader->base.extra_points );
FT_FREE( loader->base.subglyphs );
+ loader->base.extra_points2 = NULL;
+
loader->max_points = 0;
loader->max_contours = 0;
loader->max_subglyphs = 0;
@@ -149,8 +151,13 @@
/* handle extra points table - if any */
if ( loader->use_extra )
- loader->current.extra_points =
- loader->base.extra_points + base->n_points;
+ {
+ loader->current.extra_points = loader->base.extra_points +
+ base->n_points;
+
+ loader->current.extra_points2 = loader->base.extra_points2 +
+ base->n_points;
+ }
}
@@ -161,9 +168,12 @@
FT_Memory memory = loader->memory;
- if ( !FT_NEW_ARRAY( loader->base.extra_points, loader->max_points ) )
+ if ( !FT_NEW_ARRAY( loader->base.extra_points, 2*loader->max_points ) )
{
- loader->use_extra = 1;
+ loader->use_extra = 1;
+ loader->base.extra_points2 = loader->base.extra_points +
+ loader->max_points;
+
FT_GlyphLoader_Adjust_Points( loader );
}
return error;
@@ -212,10 +222,18 @@
FT_RENEW_ARRAY( base->tags, old_max, new_max ) )
goto Exit;
- if ( loader->use_extra &&
- FT_RENEW_ARRAY( loader->base.extra_points, old_max, new_max ) )
- goto Exit;
+ if ( loader->use_extra )
+ {
+ if ( FT_RENEW_ARRAY( loader->base.extra_points, old_max*2, new_max*2 ) )
+ goto Exit;
+ FT_ARRAY_MOVE( loader->base.extra_points + new_max,
+ loader->base.extra_points + old_max,
+ old_max );
+
+ loader->base.extra_points2 = loader->base.extra_points + new_max;
+ }
+
adjust = 1;
loader->max_points = new_max;
}
@@ -355,8 +373,12 @@
/* do we need to copy the extra points? */
if ( target->use_extra && source->use_extra )
+ {
FT_ARRAY_COPY( target->base.extra_points, source->base.extra_points,
num_points );
+ FT_ARRAY_COPY( target->base.extra_points2, source->base.extra_points2,
+ num_points );
+ }
out->n_points = (short)num_points;
out->n_contours = (short)num_contours;
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -79,6 +79,7 @@
ft_validator_run( FT_Validator valid )
{
/* this function is so buggy, none should be calling it */
+ FT_UNUSED(valid);
return -1;
}
--- a/src/truetype/ttgload.c
+++ b/src/truetype/ttgload.c
@@ -576,6 +576,7 @@
zone->n_contours = (FT_Short) ( load->outline.n_contours - start_contour );
zone->org = load->extra_points + start_point;
zone->cur = load->outline.points + start_point;
+ zone->orus = load->extra_points2 + start_point;
zone->tags = (FT_Byte*)load->outline.tags + start_point;
zone->contours = (FT_UShort*)load->outline.contours + start_contour;
zone->first_point = (FT_UShort)start_point;
@@ -591,9 +592,6 @@
/* Hint the glyph using the zone prepared by the caller. Note that */
/* the zone is supposed to include four phantom points. */
/* */
-#define cur_to_org( n, zone ) \
- FT_ARRAY_COPY( (zone)->org, (zone)->cur, (n) )
-
static FT_Error
TT_Hint_Glyph( TT_Loader loader,
FT_Bool is_composite )
@@ -620,7 +618,7 @@
#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
/* save original point positioin in org */
if ( n_ins > 0 )
- cur_to_org( zone->n_points, zone );
+ FT_ARRAY_COPY( zone->org, zone->cur, zone->n_points );
#endif
/* round pp2 and pp4 */
@@ -732,6 +730,14 @@
#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
+ if ( IS_HINTED( loader->load_flags ) )
+ {
+ tt_prepare_zone( &loader->zone, &gloader->current, 0, 0 );
+
+ FT_ARRAY_COPY( loader->zone.orus, loader->zone.cur,
+ loader->zone.n_points + 4 );
+ }
+
/* scale the glyph */
if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
{
@@ -755,7 +761,6 @@
if ( IS_HINTED( loader->load_flags ) )
{
- tt_prepare_zone( &loader->zone, &gloader->current, 0, 0 );
loader->zone.n_points += 4;
error = TT_Hint_Glyph( loader, 0 );
--- a/src/truetype/ttinterp.c
+++ b/src/truetype/ttinterp.c
@@ -16,6 +16,11 @@
/***************************************************************************/
+/* define FIX_BYTECODE to implement the bytecode interpreter fixes needed
+ * to match Windows behaviour more accurately
+ */
+#define FIX_BYTECODE
+
#include <ft2build.h>
#include FT_INTERNAL_DEBUG_H
#include FT_INTERNAL_CALC_H
@@ -4781,7 +4786,31 @@
if ( CUR.opcode & 1 )
D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
else
+ {
+#ifdef FIX_BYTECODE
+ FT_Vector vec1, vec2;
+
+ if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
+ {
+ FT_ARRAY_COPY( CUR.twilight.orus,
+ CUR.twilight.org,
+ CUR.twilight.n_points );
+ }
+
+ /* get scaled orus coordinates */
+ vec1 = CUR.zp0.orus[L];
+ vec2 = CUR.zp1.orus[K];
+
+ vec1.x = TT_MULFIX( vec1.x, CUR.metrics.x_scale );
+ vec1.y = TT_MULFIX( vec1.y, CUR.metrics.y_scale );
+ vec2.x = TT_MULFIX( vec2.x, CUR.metrics.x_scale );
+ vec2.y = TT_MULFIX( vec2.y, CUR.metrics.y_scale );
+
+ D = CUR_Func_dualproj( &vec1, &vec2 );
+#else
D = CUR_Func_dualproj( CUR.zp0.org + L, CUR.zp1.org + K );
+#endif
+ }
}
args[0] = D;
@@ -5695,8 +5724,30 @@
/* XXX: Is there some undocumented feature while in the */
/* twilight zone? */
+#ifdef FIX_BYTECODE
+ {
+ FT_Vector vec1, vec2;
+
+ if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
+ FT_ARRAY_COPY( CUR.twilight.orus,
+ CUR.twilight.org,
+ CUR.twilight.n_points );
+
+ vec1 = CUR.zp1.orus[point];
+ vec2 = CUR.zp0.orus[CUR.GS.rp0];
+
+ vec1.x = TT_MULFIX( vec1.x, CUR.metrics.x_scale );
+ vec1.y = TT_MULFIX( vec1.y, CUR.metrics.y_scale );
+
+ vec2.x = TT_MULFIX( vec2.x, CUR.metrics.x_scale );
+ vec2.y = TT_MULFIX( vec2.y, CUR.metrics.y_scale );
+
+ org_dist = CUR_Func_dualproj( &vec1, &vec2 );
+ }
+#else
org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
CUR.zp0.org + CUR.GS.rp0 );
+#endif
/* single width cutin test */
@@ -6053,7 +6104,7 @@
{
FT_F26Dot6 org_a, org_b, org_x,
cur_a, cur_b, cur_x,
- distance;
+ distance = 0;
FT_UShort point;
FT_UNUSED_ARG;
@@ -6065,6 +6116,22 @@
return;
}
+#ifdef FIX_BYTECODE
+ /* we need to deal in a special way with the twilight zone
+ * the easiest is simply to copy the coordinates from 'org' to 'orus'
+ * whenever someone tries to perform intersections based on some
+ * of its points.
+ *
+ * otherwise, by definition value of CUR.twilight[n] is (0,0), whatever 'n'
+ */
+ if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 || CUR.GS.gep2 == 0 )
+ {
+ FT_ARRAY_COPY( CUR.twilight.orus,
+ CUR.twilight.org,
+ CUR.twilight.n_points );
+ }
+#endif /* FIX_BYTECODE */
+
/* XXX: There are some glyphs in some braindead but popular */
/* fonts out there (e.g. [aeu]grave in monotype.ttf) */
/* calling IP[] with bad values of rp[12]. */
@@ -6078,8 +6145,22 @@
}
else
{
+#ifdef FIX_BYTECODE
+ FT_Vector vec1, vec2;
+
+ vec1 = CUR.zp0.orus[CUR.GS.rp1];
+ vec2 = CUR.zp1.orus[CUR.GS.rp2];
+ vec1.x = TT_MULFIX( vec1.x, CUR.metrics.x_scale );
+ vec1.y = TT_MULFIX( vec1.y, CUR.metrics.y_scale );
+ vec2.x = TT_MULFIX( vec2.x, CUR.metrics.x_scale );
+ vec2.y = TT_MULFIX( vec2.y, CUR.metrics.y_scale );
+
+ org_a = CUR_Func_dualproj( &vec1, NULL_Vector );
+ org_b = CUR_Func_dualproj( &vec2, NULL_Vector );
+#else
org_a = CUR_Func_dualproj( CUR.zp0.org + CUR.GS.rp1, NULL_Vector );
org_b = CUR_Func_dualproj( CUR.zp1.org + CUR.GS.rp2, NULL_Vector );
+#endif
cur_a = CUR_Func_project( CUR.zp0.cur + CUR.GS.rp1, NULL_Vector );
cur_b = CUR_Func_project( CUR.zp1.cur + CUR.GS.rp2, NULL_Vector );
@@ -6100,7 +6181,17 @@
}
else
{
+#ifdef FIX_BYTECODE
+ FT_Vector vec;
+
+ vec = CUR.zp2.orus[point];
+ vec.x = TT_MULFIX( vec.x, CUR.metrics.x_scale );
+ vec.y = TT_MULFIX( vec.y, CUR.metrics.y_scale );
+
+ org_x = CUR_Func_dualproj( &vec, NULL_Vector );
+#else
org_x = CUR_Func_dualproj( CUR.zp2.org + point, NULL_Vector );
+#endif
cur_x = CUR_Func_project ( CUR.zp2.cur + point, NULL_Vector );
if ( ( org_a <= org_b && org_x <= org_a ) ||
@@ -6113,7 +6204,7 @@
distance = ( cur_b - org_b ) + ( org_x - cur_x );
- else
+ else if ( org_b != org_a )
/* note: it seems that rounding this value isn't a good */
/* idea (cf. width of capital `S' in Times) */
@@ -6167,110 +6258,113 @@
/* Local variables for Ins_IUP: */
- struct LOC_Ins_IUP
+ typedef struct
{
FT_Vector* orgs; /* original and current coordinate */
FT_Vector* curs; /* arrays */
- };
+ FT_Vector* orus;
+ } IUP_WorkerRec, *IUP_Worker;
+
static void
- Shift( FT_UInt p1,
- FT_UInt p2,
- FT_UInt p,
- struct LOC_Ins_IUP* LINK )
+ _iup_worker_shift( IUP_Worker worker,
+ FT_UInt p1,
+ FT_UInt p2,
+ FT_UInt p )
{
FT_UInt i;
- FT_F26Dot6 x;
+ FT_F26Dot6 dx;
- x = LINK->curs[p].x - LINK->orgs[p].x;
+ dx = worker->curs[p].x - worker->orgs[p].x;
+ if ( dx != 0 )
+ {
+ for ( i = p1; i < p; i++ )
+ worker->curs[i].x += dx;
- for ( i = p1; i < p; i++ )
- LINK->curs[i].x += x;
-
- for ( i = p + 1; i <= p2; i++ )
- LINK->curs[i].x += x;
+ for ( i = p + 1; i <= p2; i++ )
+ worker->curs[i].x += dx;
+ }
}
static void
- Interp( FT_UInt p1,
- FT_UInt p2,
- FT_UInt ref1,
- FT_UInt ref2,
- struct LOC_Ins_IUP* LINK )
+ _iup_worker_interpolate( IUP_Worker worker,
+ FT_UInt p1,
+ FT_UInt p2,
+ FT_UInt ref1,
+ FT_UInt ref2 )
{
FT_UInt i;
- FT_F26Dot6 x, x1, x2, d1, d2;
+ FT_F26Dot6 orus1, orus2, org1, org2, delta1, delta2;
if ( p1 > p2 )
return;
- x1 = LINK->orgs[ref1].x;
- d1 = LINK->curs[ref1].x - LINK->orgs[ref1].x;
- x2 = LINK->orgs[ref2].x;
- d2 = LINK->curs[ref2].x - LINK->orgs[ref2].x;
+ orus1 = worker->orus[ref1].x;
+ orus2 = worker->orus[ref2].x;
- if ( x1 == x2 )
+ if (orus1 > orus2)
{
+ FT_F26Dot6 tmp_o;
+ FT_UInt tmp_r;
+
+ tmp_o = orus1; orus1 = orus2; orus2 = tmp_o;
+ tmp_r = ref1; ref1 = ref2; ref2 = tmp_r;
+ }
+
+ org1 = worker->orgs[ref1].x;
+ org2 = worker->orgs[ref2].x;
+ delta1 = worker->curs[ref1].x - org1;
+ delta2 = worker->curs[ref2].x - org2;
+
+ if ( orus1 == orus2 )
+ {
+ /* simple shift of untouched points */
for ( i = p1; i <= p2; i++ )
{
- x = LINK->orgs[i].x;
+ FT_F26Dot6 x = worker->orgs[i].x;
- if ( x <= x1 )
- x += d1;
+ if ( x <= org1 )
+ x += delta1;
else
- x += d2;
+ x += delta2;
- LINK->curs[i].x = x;
+ worker->curs[i].x = x;
}
- return;
}
-
- if ( x1 < x2 )
+ else
{
+ FT_Fixed scale = 0;
+ FT_Bool scale_valid = 0;
+
+ /* interpolation */
for ( i = p1; i <= p2; i++ )
{
- x = LINK->orgs[i].x;
+ FT_F26Dot6 x = worker->orgs[i].x;
- if ( x <= x1 )
- x += d1;
+ if ( x <= org1 )
+ x += delta1;
+
+ else if ( x >= org2 )
+ x += delta2;
+
else
{
- if ( x >= x2 )
- x += d2;
- else
- x = LINK->curs[ref1].x +
- TT_MULDIV( x - x1,
- LINK->curs[ref2].x - LINK->curs[ref1].x,
- x2 - x1 );
+ if ( !scale_valid )
+ {
+ scale_valid = 1;
+ scale = TT_MULDIV( org2+delta2 - (org1+delta1), 0x10000,
+ orus2 - orus1 );
+ }
+
+ x = (org1 + delta1) + TT_MULFIX( worker->orus[i].x - orus1, scale );
}
- LINK->curs[i].x = x;
+ worker->curs[i].x = x;
}
- return;
}
-
- /* x2 < x1 */
-
- for ( i = p1; i <= p2; i++ )
- {
- x = LINK->orgs[i].x;
- if ( x <= x2 )
- x += d2;
- else
- {
- if ( x >= x1 )
- x += d1;
- else
- x = LINK->curs[ref1].x +
- TT_MULDIV( x - x1,
- LINK->curs[ref2].x - LINK->curs[ref1].x,
- x2 - x1 );
- }
- LINK->curs[i].x = x;
- }
}
@@ -6283,8 +6377,8 @@
static void
Ins_IUP( INS_ARG )
{
- struct LOC_Ins_IUP V;
- FT_Byte mask;
+ IUP_WorkerRec V;
+ FT_Byte mask;
FT_UInt first_point; /* first point of contour */
FT_UInt end_point; /* end point (last+1) of contour */
@@ -6303,6 +6397,7 @@
mask = FT_CURVE_TAG_TOUCH_X;
V.orgs = CUR.pts.org;
V.curs = CUR.pts.cur;
+ V.orus = CUR.pts.orus;
}
else
{
@@ -6309,6 +6404,7 @@
mask = FT_CURVE_TAG_TOUCH_Y;
V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
+ V.orus = (FT_Vector*)( (FT_Pos*)CUR.pts.orus + 1 );
}
contour = 0;
@@ -6334,11 +6430,11 @@
if ( ( CUR.pts.tags[point] & mask ) != 0 )
{
if ( point > 0 )
- Interp( cur_touched + 1,
- point - 1,
- cur_touched,
- point,
- &V );
+ _iup_worker_interpolate( &V,
+ cur_touched + 1,
+ point - 1,
+ cur_touched,
+ point );
cur_touched = point;
}
@@ -6346,21 +6442,21 @@
}
if ( cur_touched == first_touched )
- Shift( first_point, end_point, cur_touched, &V );
+ _iup_worker_shift( &V, first_point, end_point, cur_touched );
else
{
- Interp( (FT_UShort)( cur_touched + 1 ),
- end_point,
- cur_touched,
- first_touched,
- &V );
+ _iup_worker_interpolate( &V,
+ (FT_UShort)( cur_touched + 1 ),
+ end_point,
+ cur_touched,
+ first_touched );
if ( first_touched > 0 )
- Interp( first_point,
- first_touched - 1,
- cur_touched,
- first_touched,
- &V );
+ _iup_worker_interpolate( &V,
+ first_point,
+ first_touched - 1,
+ cur_touched,
+ first_touched );
}
}
contour++;
--- a/src/truetype/ttobjs.c
+++ b/src/truetype/ttobjs.c
@@ -83,6 +83,7 @@
FT_FREE( zone->tags );
FT_FREE( zone->cur );
FT_FREE( zone->org );
+ FT_FREE( zone->orus );
zone->max_points = zone->n_points = 0;
zone->max_contours = zone->n_contours = 0;
@@ -126,6 +127,7 @@
if ( FT_NEW_ARRAY( zone->org, maxPoints ) ||
FT_NEW_ARRAY( zone->cur, maxPoints ) ||
+ FT_NEW_ARRAY( zone->orus, maxPoints ) ||
FT_NEW_ARRAY( zone->tags, maxPoints ) ||
FT_NEW_ARRAY( zone->contours, maxContours ) )
{