From 33f5f24957397d37ff44f27098937f6e1aceed32 Mon Sep 17 00:00:00 2001 From: David Turner Date: Wed, 16 Aug 2006 16:50:55 +0000 Subject: [PATCH] * 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 --- ChangeLog | 8 + include/freetype/internal/ftgloadr.h | 1 + include/freetype/internal/tttypes.h | 1 + src/base/ftgloadr.c | 36 +++- src/base/ftobjs.c | 1 + src/truetype/ttgload.c | 15 +- src/truetype/ttinterp.c | 272 ++++++++++++++++++--------- src/truetype/ttobjs.c | 2 + 8 files changed, 236 insertions(+), 100 deletions(-) diff --git a/ChangeLog b/ChangeLog index af494fdd..d0903825 100644 --- 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 * modules.cfg (BASE_EXTENSIONS): Compile in ftgxval.c by default to diff --git a/include/freetype/internal/ftgloadr.h b/include/freetype/internal/ftgloadr.h index b2e35fee..9f47c0b8 100644 --- a/include/freetype/internal/ftgloadr.h +++ b/include/freetype/internal/ftgloadr.h @@ -69,6 +69,7 @@ FT_BEGIN_HEADER { 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 */ diff --git a/include/freetype/internal/tttypes.h b/include/freetype/internal/tttypes.h index 1cd78935..7c0dc617 100644 --- a/include/freetype/internal/tttypes.h +++ b/include/freetype/internal/tttypes.h @@ -1470,6 +1470,7 @@ FT_BEGIN_HEADER 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 */ diff --git a/src/base/ftgloadr.c b/src/base/ftgloadr.c index 81ecd8e3..5dbb6b50 100644 --- 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,9 +222,17 @@ 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; diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c index 6ab71445..9488cd45 100644 --- 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; } diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c index 50d3c7f8..0d47bf7c 100644 --- 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 ); diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c index c9471449..6c518808 100644 --- 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 #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,109 +6258,112 @@ /* 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) { - for ( i = p1; i <= p2; i++ ) - { - x = LINK->orgs[i].x; + FT_F26Dot6 tmp_o; + FT_UInt tmp_r; - if ( x <= x1 ) - x += d1; - else - x += d2; - - LINK->curs[i].x = x; - } - return; + tmp_o = orus1; orus1 = orus2; orus2 = tmp_o; + tmp_r = ref1; ref1 = ref2; ref2 = tmp_r; } - if ( x1 < x2 ) + 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 <= org1 ) + x += delta1; + else + x += delta2; + + worker->curs[i].x = x; + } + } + else + { + FT_Fixed scale = 0; + FT_Bool scale_valid = 0; + + /* interpolation */ + for ( i = p1; i <= p2; i++ ) + { + FT_F26Dot6 x = worker->orgs[i].x; + + if ( x <= org1 ) + x += delta1; + + else if ( x >= org2 ) + x += delta2; - if ( x <= x1 ) - x += d1; 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,12 +6397,14 @@ mask = FT_CURVE_TAG_TOUCH_X; V.orgs = CUR.pts.org; V.curs = CUR.pts.cur; + V.orus = CUR.pts.orus; } else { 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++; diff --git a/src/truetype/ttobjs.c b/src/truetype/ttobjs.c index 89ef75d9..3f78137a 100644 --- 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 ) ) {