diff options
Diffstat (limited to 'src/truetype/ttgload.c')
-rw-r--r-- | src/truetype/ttgload.c | 367 |
1 files changed, 292 insertions, 75 deletions
diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c index ce8c888..f640a6c 100644 --- a/src/truetype/ttgload.c +++ b/src/truetype/ttgload.c @@ -4,7 +4,7 @@ /* */ /* TrueType Glyph Loader (body). */ /* */ -/* Copyright 1996-2012 */ +/* Copyright 1996-2013 */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -23,6 +23,7 @@ #include FT_INTERNAL_SFNT_H #include FT_TRUETYPE_TAGS_H #include FT_OUTLINE_H +#include FT_TRUETYPE_DRIVER_H #include "ttgload.h" #include "ttpload.h" @@ -32,6 +33,7 @@ #endif #include "tterrors.h" +#include "ttsubpix.h" /*************************************************************************/ @@ -131,7 +133,10 @@ tt_get_metrics( TT_Loader loader, FT_UInt glyph_index ) { - TT_Face face = (TT_Face)loader->face; + TT_Face face = (TT_Face)loader->face; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); +#endif FT_Short left_bearing = 0, top_bearing = 0; FT_UShort advance_width = 0, advance_height = 0; @@ -149,6 +154,18 @@ loader->top_bearing = top_bearing; loader->vadvance = advance_height; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) + { + if ( loader->exec ) + loader->exec->sph_tweak_flags = 0; + + /* this may not be the right place for this, but it works */ + if ( loader->exec && loader->exec->ignore_x_mode ) + sph_set_tweaks( loader, glyph_index ); + } +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + if ( !loader->linear_def ) { loader->linear_def = 1; @@ -252,10 +269,6 @@ } -#undef IS_HINTED -#define IS_HINTED( flags ) ( ( flags & FT_LOAD_NO_HINTING ) == 0 ) - - /*************************************************************************/ /* */ /* The following functions are used by default with TrueType fonts. */ @@ -286,7 +299,7 @@ loader->cursor = stream->cursor; loader->limit = stream->limit; - return TT_Err_Ok; + return FT_Err_Ok; } @@ -308,7 +321,7 @@ if ( p + 10 > limit ) - return TT_Err_Invalid_Outline; + return FT_THROW( Invalid_Outline ); loader->n_contours = FT_NEXT_SHORT( p ); @@ -324,7 +337,7 @@ loader->bbox.yMax )); loader->cursor = p; - return TT_Err_Ok; + return FT_Err_Ok; } @@ -409,14 +422,14 @@ { FT_TRACE0(( "TT_Load_Simple_Glyph: too many instructions (%d)\n", n_ins )); - error = TT_Err_Too_Many_Hints; + error = FT_THROW( Too_Many_Hints ); goto Fail; } if ( ( limit - p ) < n_ins ) { FT_TRACE0(( "TT_Load_Simple_Glyph: instruction count mismatch\n" )); - error = TT_Err_Too_Many_Hints; + error = FT_THROW( Too_Many_Hints ); goto Fail; } @@ -546,7 +559,7 @@ return error; Invalid_Outline: - error = TT_Err_Invalid_Outline; + error = FT_THROW( Invalid_Outline ); goto Fail; } @@ -667,7 +680,7 @@ return error; Invalid_Composite: - error = TT_Err_Invalid_Composite; + error = FT_THROW( Invalid_Composite ); goto Fail; } @@ -714,6 +727,11 @@ TT_Hint_Glyph( TT_Loader loader, FT_Bool is_composite ) { +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + TT_Face face = (TT_Face)loader->face; + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); +#endif + TT_GlyphZone zone = &loader->zone; FT_Pos origin; @@ -813,7 +831,18 @@ loader->pp4 = zone->cur[zone->n_points - 1]; } - return TT_Err_Ok; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) + { + if ( loader->exec->sph_tweak_flags & SPH_TWEAK_DEEMBOLDEN ) + FT_Outline_EmboldenXY( &loader->gloader->current.outline, -24, 0 ); + + else if ( loader->exec->sph_tweak_flags & SPH_TWEAK_EMBOLDEN ) + FT_Outline_EmboldenXY( &loader->gloader->current.outline, 24, 0 ); + } +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + return FT_Err_Ok; } @@ -831,7 +860,7 @@ TT_Process_Simple_Glyph( TT_Loader loader ) { FT_GlyphLoader gloader = loader->gloader; - FT_Error error = TT_Err_Ok; + FT_Error error = FT_Err_Ok; FT_Outline* outline; FT_Int n_points; @@ -889,25 +918,83 @@ loader->zone.n_points + 4 ); } - /* scale the glyph */ - if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) { - FT_Vector* vec = outline->points; - FT_Vector* limit = outline->points + n_points; - FT_Fixed x_scale = ((TT_Size)loader->size)->metrics.x_scale; - FT_Fixed y_scale = ((TT_Size)loader->size)->metrics.y_scale; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + TT_Face face = (TT_Face)loader->face; + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); + + FT_String* family = face->root.family_name; + FT_Int ppem = loader->size->metrics.x_ppem; + FT_String* style = face->root.style_name; + FT_Int x_scale_factor = 1000; +#endif + + FT_Vector* vec = outline->points; + FT_Vector* limit = outline->points + n_points; + + FT_Fixed x_scale = 0; /* pacify compiler */ + FT_Fixed y_scale = 0; + + FT_Bool do_scale = FALSE; - for ( ; vec < limit; vec++ ) +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) { - vec->x = FT_MulFix( vec->x, x_scale ); - vec->y = FT_MulFix( vec->y, y_scale ); + /* scale, but only if enabled and only if TT hinting is being used */ + if ( IS_HINTED( loader->load_flags ) ) + x_scale_factor = sph_test_tweak_x_scaling( face, + family, + ppem, + style, + loader->glyph_index ); + /* scale the glyph */ + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 || + x_scale_factor != 1000 ) + { + x_scale = FT_MulDiv( ((TT_Size)loader->size)->metrics.x_scale, + x_scale_factor, 1000 ); + y_scale = ((TT_Size)loader->size)->metrics.y_scale; + + /* compensate for any scaling by de/emboldening; */ + /* the amount was determined via experimentation */ + if ( x_scale_factor != 1000 && ppem > 11 ) + FT_Outline_EmboldenXY( outline, + FT_MulFix( 1280 * ppem, + 1000 - x_scale_factor ), + 0 ); + do_scale = TRUE; + } } + else + +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - loader->pp1 = outline->points[n_points - 4]; - loader->pp2 = outline->points[n_points - 3]; - loader->pp3 = outline->points[n_points - 2]; - loader->pp4 = outline->points[n_points - 1]; + { + /* scale the glyph */ + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + x_scale = ((TT_Size)loader->size)->metrics.x_scale; + y_scale = ((TT_Size)loader->size)->metrics.y_scale; + + do_scale = TRUE; + } + } + + if ( do_scale ) + { + for ( ; vec < limit; vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + + loader->pp1 = outline->points[n_points - 4]; + loader->pp2 = outline->points[n_points - 3]; + loader->pp3 = outline->points[n_points - 2]; + loader->pp4 = outline->points[n_points - 1]; + } } if ( IS_HINTED( loader->load_flags ) ) @@ -974,7 +1061,7 @@ l += num_base_points; if ( k >= num_base_points || l >= num_points ) - return TT_Err_Invalid_Composite; + return FT_THROW( Invalid_Composite ); p1 = gloader->base.outline.points + k; p2 = gloader->base.outline.points + l; @@ -988,7 +1075,7 @@ y = subglyph->arg2; if ( !x && !y ) - return TT_Err_Ok; + return FT_Err_Ok; /* Use a default value dependent on */ /* TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED. This is useful for old TT */ @@ -1033,16 +1120,10 @@ /* */ /* This algorithm is a guess and works much better than the above. */ /* */ - FT_Fixed mac_xscale = FT_SqrtFixed( - (FT_Int32)FT_MulFix( subglyph->transform.xx, - subglyph->transform.xx ) + - (FT_Int32)FT_MulFix( subglyph->transform.xy, - subglyph->transform.xy ) ); - FT_Fixed mac_yscale = FT_SqrtFixed( - (FT_Int32)FT_MulFix( subglyph->transform.yy, - subglyph->transform.yy ) + - (FT_Int32)FT_MulFix( subglyph->transform.yx, - subglyph->transform.yx ) ); + FT_Fixed mac_xscale = FT_Hypot( subglyph->transform.xx, + subglyph->transform.xy ); + FT_Fixed mac_yscale = FT_Hypot( subglyph->transform.yy, + subglyph->transform.yx ); x = FT_MulFix( x, mac_xscale ); @@ -1074,7 +1155,7 @@ base_vec + num_base_points, x, y ); - return TT_Err_Ok; + return FT_Err_Ok; } @@ -1143,7 +1224,7 @@ FT_TRACE1(( "TT_Process_Composite_Glyph: " "too many instructions (%d) for glyph with length %d\n", n_ins, loader->byte_len )); - return TT_Err_Too_Many_Hints; + return FT_THROW( Too_Many_Hints ); } tmp = loader->exec->glyphSize; @@ -1157,7 +1238,7 @@ return error; } else if ( n_ins == 0 ) - return TT_Err_Ok; + return FT_Err_Ok; if ( FT_STREAM_READ( loader->exec->glyphIns, n_ins ) ) return error; @@ -1213,7 +1294,7 @@ FT_UInt recurse_count, FT_Bool header_only ) { - FT_Error error = TT_Err_Ok; + FT_Error error = FT_Err_Ok; FT_Fixed x_scale, y_scale; FT_ULong offset; TT_Face face = (TT_Face)loader->face; @@ -1236,14 +1317,14 @@ if ( recurse_count > 1 && recurse_count > face->max_profile.maxComponentDepth ) { - error = TT_Err_Invalid_Composite; + error = FT_THROW( Invalid_Composite ); goto Exit; } /* check glyph index */ if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) { - error = TT_Err_Invalid_Glyph_Index; + error = FT_THROW( Invalid_Glyph_Index ); goto Exit; } @@ -1307,7 +1388,7 @@ #endif /* FT_CONFIG_OPTION_INCREMENTAL */ { FT_TRACE2(( "no `glyf' table but non-zero `loca' entry\n" )); - error = TT_Err_Invalid_Table; + error = FT_THROW( Invalid_Table ); goto Exit; } @@ -1374,7 +1455,7 @@ loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale ); } - error = TT_Err_Ok; + error = FT_Err_Ok; goto Exit; } @@ -1588,7 +1669,7 @@ else { /* invalid composite count (negative but not -1) */ - error = TT_Err_Invalid_Outline; + error = FT_THROW( Invalid_Outline ); goto Exit; } @@ -1618,11 +1699,15 @@ compute_glyph_metrics( TT_Loader loader, FT_UInt glyph_index ) { + TT_Face face = (TT_Face)loader->face; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); +#endif + FT_BBox bbox; - TT_Face face = (TT_Face)loader->face; FT_Fixed y_scale; TT_GlyphSlot glyph = loader->glyph; - TT_Size size = (TT_Size)loader->size; + TT_Size size = (TT_Size)loader->size; y_scale = 0x10000L; @@ -1653,8 +1738,30 @@ size->root.metrics.x_ppem, glyph_index ); - if ( widthp ) - glyph->metrics.horiAdvance = *widthp << 6; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) + { + FT_Bool ignore_x_mode; + + + ignore_x_mode = FT_BOOL( FT_LOAD_TARGET_MODE( loader->load_flags ) != + FT_RENDER_MODE_MONO ); + + if ( widthp && + ( ( ignore_x_mode && loader->exec->compatible_widths ) || + !ignore_x_mode || + SPH_OPTION_BITMAP_WIDTHS ) ) + glyph->metrics.horiAdvance = *widthp << 6; + } + else + +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + { + if ( widthp ) + glyph->metrics.horiAdvance = *widthp << 6; + } } /* set glyph dimensions */ @@ -1833,7 +1940,9 @@ { TT_Face face; FT_Stream stream; +#ifdef TT_USE_BYTECODE_INTERPRETER FT_Bool pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); +#endif face = (TT_Face)glyph->face; @@ -1849,6 +1958,23 @@ TT_ExecContext exec; FT_Bool grayscale; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); + + FT_Bool subpixel_hinting = FALSE; + FT_Bool grayscale_hinting = TRUE; + +#if 0 + /* not used yet */ + FT_Bool compatible_widths; + FT_Bool symmetrical_smoothing; + FT_Bool bgr; + FT_Bool subpixel_positioned; +#endif +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + FT_Bool reexecute = FALSE; + if ( !size->cvt_ready ) { @@ -1863,24 +1989,113 @@ exec = size->debug ? size->context : ( (TT_Driver)FT_FACE_DRIVER( face ) )->context; if ( !exec ) - return TT_Err_Could_Not_Find_Context; + return FT_THROW( Could_Not_Find_Context ); + +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) + { + subpixel_hinting = FT_BOOL( ( FT_LOAD_TARGET_MODE( load_flags ) + != FT_RENDER_MODE_MONO ) && + SPH_OPTION_SET_SUBPIXEL ); + + if ( subpixel_hinting ) + grayscale = grayscale_hinting = FALSE; + else if ( SPH_OPTION_SET_GRAYSCALE ) + { + grayscale = grayscale_hinting = TRUE; + subpixel_hinting = FALSE; + } + else + grayscale = grayscale_hinting = FALSE; + + if ( FT_IS_TRICKY( glyph->face ) ) + subpixel_hinting = grayscale_hinting = FALSE; + + exec->ignore_x_mode = subpixel_hinting || grayscale_hinting; + exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION; + if ( exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 ) + exec->rasterizer_version = TT_INTERPRETER_VERSION_35; + +#if 1 + exec->compatible_widths = SPH_OPTION_SET_COMPATIBLE_WIDTHS; + exec->symmetrical_smoothing = FALSE; + exec->bgr = FALSE; + exec->subpixel_positioned = TRUE; +#else /* 0 */ + exec->compatible_widths = + FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != + TT_LOAD_COMPATIBLE_WIDTHS ); + exec->symmetrical_smoothing = + FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != + TT_LOAD_SYMMETRICAL_SMOOTHING ); + exec->bgr = + FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != + TT_LOAD_BGR ); + exec->subpixel_positioned = + FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != + TT_LOAD_SUBPIXEL_POSITIONED ); +#endif /* 0 */ + + } + else + +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - grayscale = - FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != FT_RENDER_MODE_MONO ); + { + grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != + FT_RENDER_MODE_MONO ); + } TT_Load_Context( exec, face, size ); - /* a change from mono to grayscale rendering (and vice versa) */ - /* requires a re-execution of the CVT program */ - if ( grayscale != exec->grayscale ) +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) { - FT_UInt i; + /* a change from mono to subpixel rendering (and vice versa) */ + /* requires a re-execution of the CVT program */ + if ( subpixel_hinting != exec->subpixel_hinting ) + { + FT_TRACE4(( "tt_loader_init: subpixel hinting change," + " re-executing `prep' table\n" )); + + exec->subpixel_hinting = subpixel_hinting; + reexecute = TRUE; + } + + /* a change from mono to grayscale rendering (and vice versa) */ + /* requires a re-execution of the CVT program */ + if ( grayscale != exec->grayscale_hinting ) + { + FT_TRACE4(( "tt_loader_init: grayscale hinting change," + " re-executing `prep' table\n" )); + + exec->grayscale_hinting = grayscale_hinting; + reexecute = TRUE; + } + } + else +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - FT_TRACE4(( "tt_loader_init: grayscale change," - " re-executing `prep' table\n" )); + { + /* a change from mono to grayscale rendering (and vice versa) */ + /* requires a re-execution of the CVT program */ + if ( grayscale != exec->grayscale ) + { + FT_TRACE4(( "tt_loader_init: grayscale change," + " re-executing `prep' table\n" )); + + exec->grayscale = grayscale; + reexecute = TRUE; + } + } + + if ( reexecute ) + { + FT_UInt i; - exec->grayscale = grayscale; for ( i = 0; i < size->cvt_size; i++ ) size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale ); @@ -1918,7 +2133,7 @@ FT_Error error = face->goto_table( face, TTAG_glyf, stream, 0 ); - if ( error == TT_Err_Table_Missing ) + if ( FT_ERR_EQ( error, Table_Missing ) ) loader->glyf_offset = 0; else if ( error ) { @@ -1946,7 +2161,7 @@ loader->glyph = (FT_GlyphSlot)glyph; loader->stream = stream; - return TT_Err_Ok; + return FT_Err_Ok; } @@ -1983,13 +2198,11 @@ FT_UInt glyph_index, FT_Int32 load_flags ) { - TT_Face face; FT_Error error; TT_LoaderRec loader; - face = (TT_Face)glyph->face; - error = TT_Err_Ok; + error = FT_Err_Ok; #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS @@ -2003,10 +2216,7 @@ error = load_sbit_image( size, glyph, glyph_index, load_flags ); if ( !error ) { - FT_Face root = &face->root; - - - if ( FT_IS_SCALABLE( root ) ) + if ( FT_IS_SCALABLE( glyph->face ) ) { /* for the bbox we need the header only */ (void)tt_loader_init( &loader, size, glyph, load_flags, TRUE ); @@ -2014,9 +2224,16 @@ glyph->linearHoriAdvance = loader.linear; glyph->linearVertAdvance = loader.top_bearing + loader.bbox.yMax - loader.vadvance; + + /* sanity check: if `horiAdvance' in the sbit metric */ + /* structure isn't set, use `linearHoriAdvance' */ + if ( !glyph->metrics.horiAdvance && glyph->linearHoriAdvance ) + glyph->metrics.horiAdvance = + FT_MulFix( glyph->linearHoriAdvance, + size->root.metrics.x_scale ); } - return TT_Err_Ok; + return FT_Err_Ok; } } @@ -2024,10 +2241,10 @@ /* if FT_LOAD_NO_SCALE is not set, `ttmetrics' must be valid */ if ( !( load_flags & FT_LOAD_NO_SCALE ) && !size->ttmetrics.valid ) - return TT_Err_Invalid_Size_Handle; + return FT_THROW( Invalid_Size_Handle ); if ( load_flags & FT_LOAD_SBITS_ONLY ) - return TT_Err_Invalid_Argument; + return FT_THROW( Invalid_Argument ); error = tt_loader_init( &loader, size, glyph, load_flags, FALSE ); if ( error ) |