diff options
Diffstat (limited to 'src/3rdparty/freetype/src/truetype/ttgload.c')
-rw-r--r-- | src/3rdparty/freetype/src/truetype/ttgload.c | 890 |
1 files changed, 643 insertions, 247 deletions
diff --git a/src/3rdparty/freetype/src/truetype/ttgload.c b/src/3rdparty/freetype/src/truetype/ttgload.c index 57ea0baa77..c5841c301d 100644 --- a/src/3rdparty/freetype/src/truetype/ttgload.c +++ b/src/3rdparty/freetype/src/truetype/ttgload.c @@ -4,8 +4,7 @@ /* */ /* TrueType Glyph Loader (body). */ /* */ -/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */ -/* 2010 by */ +/* Copyright 1996-2014 */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -24,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" @@ -33,6 +33,7 @@ #endif #include "tterrors.h" +#include "ttsubpix.h" /*************************************************************************/ @@ -47,7 +48,7 @@ /*************************************************************************/ /* */ - /* Composite font flags. */ + /* Composite glyph flags. */ /* */ #define ARGS_ARE_WORDS 0x0001 #define ARGS_ARE_XY_VALUES 0x0002 @@ -66,22 +67,16 @@ /*************************************************************************/ /* */ - /* Returns the horizontal metrics in font units for a given glyph. If */ - /* `check' is true, take care of monospaced fonts by returning the */ - /* advance width maximum. */ + /* Return the horizontal metrics in font units for a given glyph. */ /* */ FT_LOCAL_DEF( void ) TT_Get_HMetrics( TT_Face face, FT_UInt idx, - FT_Bool check, FT_Short* lsb, FT_UShort* aw ) { ( (SFNT_Service)face->sfnt )->get_metrics( face, 0, idx, lsb, aw ); - if ( check && face->postscript.isFixedPitch ) - *aw = face->horizontal.advance_Width_Max; - FT_TRACE5(( " advance width (font units): %d\n", *aw )); FT_TRACE5(( " left side bearing (font units): %d\n", *lsb )); } @@ -89,80 +84,106 @@ /*************************************************************************/ /* */ - /* Returns the vertical metrics in font units for a given glyph. */ - /* Greg Hitchcock from Microsoft told us that if there were no `vmtx' */ - /* table, typoAscender/Descender from the `OS/2' table would be used */ - /* instead, and if there were no `OS/2' table, use ascender/descender */ - /* from the `hhea' table. But that is not what Microsoft's rasterizer */ - /* apparently does: It uses the ppem value as the advance height, and */ - /* sets the top side bearing to be zero. */ - /* */ - /* The monospace `check' is probably not meaningful here, but we leave */ - /* it in for a consistent interface. */ + /* Return the vertical metrics in font units for a given glyph. */ + /* See macro `TT_LOADER_SET_PP' below for explanations. */ /* */ FT_LOCAL_DEF( void ) TT_Get_VMetrics( TT_Face face, FT_UInt idx, - FT_Bool check, + FT_Pos yMax, FT_Short* tsb, FT_UShort* ah ) { - FT_UNUSED( check ); - if ( face->vertical_info ) ( (SFNT_Service)face->sfnt )->get_metrics( face, 1, idx, tsb, ah ); -#if 1 /* Empirically determined, at variance with what MS said */ - - else - { - *tsb = 0; - *ah = face->root.units_per_EM; - } - -#else /* This is what MS said to do. It isn't what they do, however. */ - else if ( face->os2.version != 0xFFFFU ) { - *tsb = face->os2.sTypoAscender; + *tsb = (FT_Short)( face->os2.sTypoAscender - yMax ); *ah = face->os2.sTypoAscender - face->os2.sTypoDescender; } + else { - *tsb = face->horizontal.Ascender; + *tsb = (FT_Short)( face->horizontal.Ascender - yMax ); *ah = face->horizontal.Ascender - face->horizontal.Descender; } -#endif - FT_TRACE5(( " advance height (font units): %d\n", *ah )); FT_TRACE5(( " top side bearing (font units): %d\n", *tsb )); } - static void + static FT_Error 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_Error error; + FT_Stream stream = loader->stream; FT_Short left_bearing = 0, top_bearing = 0; FT_UShort advance_width = 0, advance_height = 0; + /* we must preserve the stream position */ + /* (which gets altered by the metrics functions) */ + FT_ULong pos = FT_STREAM_POS(); + TT_Get_HMetrics( face, glyph_index, - (FT_Bool)!( loader->load_flags & - FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ), &left_bearing, &advance_width ); TT_Get_VMetrics( face, glyph_index, - (FT_Bool)!( loader->load_flags & - FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ), + loader->bbox.yMax, &top_bearing, &advance_height ); + if ( FT_STREAM_SEEK( pos ) ) + return error; + + loader->left_bearing = left_bearing; + loader->advance = advance_width; + 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; + loader->linear = advance_width; + } + + return FT_Err_Ok; + } + + #ifdef FT_CONFIG_OPTION_INCREMENTAL + static void + tt_get_metrics_incr_overrides( TT_Loader loader, + FT_UInt glyph_index ) + { + TT_Face face = (TT_Face)loader->face; + + FT_Short left_bearing = 0, top_bearing = 0; + FT_UShort advance_width = 0, advance_height = 0; + + /* If this is an incrementally loaded font check whether there are */ /* overriding metrics for this glyph. */ if ( face->root.internal->incremental_interface && @@ -172,9 +193,9 @@ FT_Error error; - metrics.bearing_x = left_bearing; + metrics.bearing_x = loader->left_bearing; metrics.bearing_y = 0; - metrics.advance = advance_width; + metrics.advance = loader->advance; metrics.advance_v = 0; error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( @@ -190,8 +211,8 @@ /* GWW: Do I do the same for vertical metrics? */ metrics.bearing_x = 0; - metrics.bearing_y = top_bearing; - metrics.advance = advance_height; + metrics.bearing_y = loader->top_bearing; + metrics.advance = loader->vadvance; error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( face->root.internal->incremental_interface->object, @@ -204,24 +225,24 @@ #endif /* 0 */ + loader->left_bearing = left_bearing; + loader->advance = advance_width; + loader->top_bearing = top_bearing; + loader->vadvance = advance_height; + + if ( !loader->linear_def ) + { + loader->linear_def = 1; + loader->linear = advance_width; + } } Exit: + return; + } #endif /* FT_CONFIG_OPTION_INCREMENTAL */ - loader->left_bearing = left_bearing; - loader->advance = advance_width; - loader->top_bearing = top_bearing; - loader->vadvance = advance_height; - - if ( !loader->linear_def ) - { - loader->linear_def = 1; - loader->linear = advance_width; - } - } - /*************************************************************************/ /* */ @@ -246,10 +267,6 @@ } -#undef IS_HINTED -#define IS_HINTED( flags ) ( ( flags & FT_LOAD_NO_HINTING ) == 0 ) - - /*************************************************************************/ /* */ /* The following functions are used by default with TrueType fonts. */ @@ -271,7 +288,7 @@ FT_UNUSED( glyph_index ); - FT_TRACE5(( "Glyph %ld\n", glyph_index )); + FT_TRACE4(( "Glyph %ld\n", glyph_index )); /* the following line sets the `error' variable through macros! */ if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( byte_count ) ) @@ -280,7 +297,7 @@ loader->cursor = stream->cursor; loader->limit = stream->limit; - return TT_Err_Ok; + return FT_Err_Ok; } @@ -302,7 +319,7 @@ if ( p + 10 > limit ) - return TT_Err_Invalid_Outline; + return FT_THROW( Invalid_Outline ); loader->n_contours = FT_NEXT_SHORT( p ); @@ -318,7 +335,7 @@ loader->bbox.yMax )); loader->cursor = p; - return TT_Err_Ok; + return FT_Err_Ok; } @@ -331,9 +348,9 @@ FT_GlyphLoader gloader = load->gloader; FT_Int n_contours = load->n_contours; FT_Outline* outline; - TT_Face face = (TT_Face)load->face; FT_UShort n_ins; FT_Int n_points; + FT_ULong tmp; FT_Byte *flag, *flag_limit; FT_Byte c, count; @@ -356,19 +373,21 @@ if ( n_contours >= 0xFFF || p + ( n_contours + 1 ) * 2 > limit ) goto Invalid_Outline; - prev_cont = FT_NEXT_USHORT( p ); + prev_cont = FT_NEXT_SHORT( p ); if ( n_contours > 0 ) cont[0] = prev_cont; + if ( prev_cont < 0 ) + goto Invalid_Outline; + for ( cont++; cont < cont_limit; cont++ ) { - cont[0] = FT_NEXT_USHORT( p ); + cont[0] = FT_NEXT_SHORT( p ); if ( cont[0] <= prev_cont ) { /* unordered contours: this is invalid */ - error = FT_Err_Invalid_Table; - goto Fail; + goto Invalid_Outline; } prev_cont = cont[0]; } @@ -386,13 +405,6 @@ if ( error ) goto Fail; - /* we'd better check the contours table right now */ - outline = &gloader->current.outline; - - for ( cont = outline->contours + 1; cont < cont_limit; cont++ ) - if ( cont[-1] >= cont[0] ) - goto Invalid_Outline; - /* reading the bytecode instructions */ load->glyph->control_len = 0; load->glyph->control_data = 0; @@ -404,18 +416,11 @@ FT_TRACE5(( " Instructions size: %u\n", n_ins )); - if ( n_ins > face->max_profile.maxSizeOfInstructions ) - { - FT_TRACE0(( "TT_Load_Simple_Glyph: too many instructions (%d)\n", - n_ins )); - error = TT_Err_Too_Many_Hints; - goto Fail; - } - + /* check it */ 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; } @@ -423,6 +428,20 @@ if ( IS_HINTED( load->load_flags ) ) { + /* we don't trust `maxSizeOfInstructions' in the `maxp' table */ + /* and thus update the bytecode array size by ourselves */ + + tmp = load->exec->glyphSize; + error = Update_Max( load->exec->memory, + &tmp, + sizeof ( FT_Byte ), + (void*)&load->exec->glyphIns, + n_ins ); + + load->exec->glyphSize = (FT_UShort)tmp; + if ( error ) + return error; + load->glyph->control_len = n_ins; load->glyph->control_data = load->exec->glyphIns; @@ -433,6 +452,8 @@ p += n_ins; + outline = &gloader->current.outline; + /* reading the point tags */ flag = (FT_Byte*)outline->tags; flag_limit = flag + n_points; @@ -543,7 +564,7 @@ return error; Invalid_Outline: - error = TT_Err_Invalid_Outline; + error = FT_THROW( Invalid_Outline ); goto Fail; } @@ -664,7 +685,7 @@ return error; Invalid_Composite: - error = TT_Err_Invalid_Composite; + error = FT_THROW( Invalid_Composite ); goto Fail; } @@ -711,8 +732,12 @@ 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; #ifdef TT_USE_BYTECODE_INTERPRETER FT_UInt n_ins; @@ -724,19 +749,12 @@ #ifdef TT_USE_BYTECODE_INTERPRETER if ( loader->glyph->control_len > 0xFFFFL ) { - FT_TRACE1(( "TT_Hint_Glyph: too long instructions " )); - FT_TRACE1(( "(0x%lx byte) is truncated\n", + FT_TRACE1(( "TT_Hint_Glyph: too long instructions" )); + FT_TRACE1(( " (0x%lx byte) is truncated\n", loader->glyph->control_len )); } n_ins = (FT_UInt)( loader->glyph->control_len ); -#endif - origin = zone->cur[zone->n_points - 4].x; - origin = FT_PIX_ROUND( origin ) - origin; - if ( origin ) - translate_array( zone->n_points, zone->cur, origin, 0 ); - -#ifdef TT_USE_BYTECODE_INTERPRETER /* save original point position in org */ if ( n_ins > 0 ) FT_ARRAY_COPY( zone->org, zone->cur, zone->n_points ); @@ -762,9 +780,13 @@ } #endif - /* round pp2 and pp4 */ + /* round phantom points */ + zone->cur[zone->n_points - 4].x = + FT_PIX_ROUND( zone->cur[zone->n_points - 4].x ); zone->cur[zone->n_points - 3].x = FT_PIX_ROUND( zone->cur[zone->n_points - 3].x ); + zone->cur[zone->n_points - 2].y = + FT_PIX_ROUND( zone->cur[zone->n_points - 2].y ); zone->cur[zone->n_points - 1].y = FT_PIX_ROUND( zone->cur[zone->n_points - 1].y ); @@ -779,10 +801,8 @@ FT_Outline current_outline = gloader->current.outline; - error = TT_Set_CodeRange( loader->exec, tt_coderange_glyph, - loader->exec->glyphIns, n_ins ); - if ( error ) - return error; + TT_Set_CodeRange( loader->exec, tt_coderange_glyph, + loader->exec->glyphIns, n_ins ); loader->exec->is_composite = is_composite; loader->exec->pts = *zone; @@ -802,15 +822,23 @@ #endif /* save glyph phantom points */ - if ( !loader->preserve_pps ) + loader->pp1 = zone->cur[zone->n_points - 4]; + loader->pp2 = zone->cur[zone->n_points - 3]; + loader->pp3 = zone->cur[zone->n_points - 2]; + loader->pp4 = zone->cur[zone->n_points - 1]; + +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) { - loader->pp1 = zone->cur[zone->n_points - 4]; - loader->pp2 = zone->cur[zone->n_points - 3]; - loader->pp3 = zone->cur[zone->n_points - 2]; - loader->pp4 = zone->cur[zone->n_points - 1]; + 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 TT_Err_Ok; + return FT_Err_Ok; } @@ -828,7 +856,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; @@ -886,25 +914,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; - for ( ; vec < limit; vec++ ) + FT_Bool do_scale = FALSE; + + +#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 */ + + { + /* 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; + } } - 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 ( 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 ) ) @@ -971,7 +1057,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; @@ -985,11 +1071,11 @@ 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 */ - /* fonts which don't set the xxx_COMPONENT_OFFSET bit. */ + /* Use a default value dependent on */ + /* TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED. This is useful for old */ + /* TT fonts which don't set the xxx_COMPONENT_OFFSET bit. */ if ( have_scale && #ifdef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED @@ -1001,10 +1087,10 @@ #if 0 - /*************************************************************************/ - /* */ - /* This algorithm is what Apple documents. But it doesn't work. */ - /* */ + /*******************************************************************/ + /* */ + /* This algorithm is what Apple documents. But it doesn't work. */ + /* */ int a = subglyph->transform.xx > 0 ? subglyph->transform.xx : -subglyph->transform.xx; int b = subglyph->transform.yx > 0 ? subglyph->transform.yx @@ -1024,28 +1110,22 @@ x = FT_MulFix( x, m ); y = FT_MulFix( y, n ); -#else /* 0 */ +#else /* 1 */ - /*************************************************************************/ - /* */ - /* 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 ) ); + /*******************************************************************/ + /* */ + /* This algorithm is a guess and works much better than the above. */ + /* */ + 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 ); y = FT_MulFix( y, mac_yscale ); -#endif /* 0 */ +#endif /* 1 */ } @@ -1071,7 +1151,7 @@ base_vec + num_base_points, x, y ); - return TT_Err_Ok; + return FT_Err_Ok; } @@ -1118,7 +1198,8 @@ { FT_Stream stream = loader->stream; - FT_UShort n_ins; + FT_UShort n_ins, max_ins; + FT_ULong tmp; /* TT_Load_Composite_Glyph only gives us the offset of instructions */ @@ -1130,15 +1211,32 @@ FT_TRACE5(( " Instructions size = %d\n", n_ins )); /* check it */ - if ( n_ins > ((TT_Face)loader->face)->max_profile.maxSizeOfInstructions ) + max_ins = ((TT_Face)loader->face)->max_profile.maxSizeOfInstructions; + if ( n_ins > max_ins ) { - FT_TRACE0(( "TT_Process_Composite_Glyph: too many instructions (%d)\n", - n_ins )); + /* don't trust `maxSizeOfInstructions'; */ + /* only do a rough safety check */ + if ( (FT_Int)n_ins > loader->byte_len ) + { + FT_TRACE1(( "TT_Process_Composite_Glyph:" + " too many instructions (%d) for glyph with length %d\n", + n_ins, loader->byte_len )); + return FT_THROW( Too_Many_Hints ); + } - return TT_Err_Too_Many_Hints; + tmp = loader->exec->glyphSize; + error = Update_Max( loader->exec->memory, + &tmp, + sizeof ( FT_Byte ), + (void*)&loader->exec->glyphIns, + n_ins ); + + loader->exec->glyphSize = (FT_UShort)tmp; + if ( error ) + 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; @@ -1154,7 +1252,7 @@ /* Some points are likely touched during execution of */ /* instructions on components. So let's untouch them. */ - for ( i = start_point; i < loader->zone.n_points; i++ ) + for ( i = 0; i < loader->zone.n_points; i++ ) loader->zone.tags[i] &= ~FT_CURVE_TAG_TOUCH_BOTH; loader->zone.n_points += 4; @@ -1163,21 +1261,131 @@ } - /* Calculate the four phantom points. */ - /* The first two stand for horizontal origin and advance. */ - /* The last two stand for vertical origin and advance. */ + /* + * Calculate the phantom points + * + * Defining the right side bearing (rsb) as + * + * rsb = aw - (lsb + xmax - xmin) + * + * (with `aw' the advance width, `lsb' the left side bearing, and `xmin' + * and `xmax' the glyph's minimum and maximum x value), the OpenType + * specification defines the initial position of horizontal phantom points + * as + * + * pp1 = (round(xmin - lsb), 0) , + * pp2 = (round(pp1 + aw), 0) . + * + * Note that the rounding to the grid (in the device space) is not + * documented currently in the specification. + * + * However, the specification lacks the precise definition of vertical + * phantom points. Greg Hitchcock provided the following explanation. + * + * - a `vmtx' table is present + * + * For any glyph, the minimum and maximum y values (`ymin' and `ymax') + * are given in the `glyf' table, the top side bearing (tsb) and advance + * height (ah) are given in the `vmtx' table. The bottom side bearing + * (bsb) is then calculated as + * + * bsb = ah - (tsb + ymax - ymin) , + * + * and the initial position of vertical phantom points is + * + * pp3 = (x, round(ymax + tsb)) , + * pp4 = (x, round(pp3 - ah)) . + * + * See below for value `x'. + * + * - no `vmtx' table in the font + * + * If there is an `OS/2' table, we set + * + * DefaultAscender = sTypoAscender , + * DefaultDescender = sTypoDescender , + * + * otherwise we use data from the `hhea' table: + * + * DefaultAscender = Ascender , + * DefaultDescender = Descender . + * + * With these two variables we can now set + * + * ah = DefaultAscender - sDefaultDescender , + * tsb = DefaultAscender - yMax , + * + * and proceed as if a `vmtx' table was present. + * + * Usually we have + * + * x = aw / 2 , (1) + * + * but there is one compatibility case where it can be set to + * + * x = -DefaultDescender - + * ((DefaultAscender - DefaultDescender - aw) / 2) . (2) + * + * and another one with + * + * x = 0 . (3) + * + * In Windows, the history of those values is quite complicated, + * depending on the hinting engine (that is, the graphics framework). + * + * framework from to formula + * ---------------------------------------------------------- + * GDI Windows 98 current (1) + * (Windows 2000 for NT) + * GDI+ Windows XP Windows 7 (2) + * GDI+ Windows 8 current (3) + * DWrite Windows 7 current (3) + * + * For simplicity, FreeType uses (1) for grayscale subpixel hinting and + * (3) for everything else. + * + */ +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + +#define TT_LOADER_SET_PP( loader ) \ + do \ + { \ + FT_Bool subpixel_ = loader->exec ? loader->exec->subpixel \ + : 0; \ + FT_Bool grayscale_ = loader->exec ? loader->exec->grayscale \ + : 0; \ + FT_Bool use_aw_2_ = (FT_Bool)( subpixel_ && grayscale_ ); \ + \ + \ + (loader)->pp1.x = (loader)->bbox.xMin - (loader)->left_bearing; \ + (loader)->pp1.y = 0; \ + (loader)->pp2.x = (loader)->pp1.x + (loader)->advance; \ + (loader)->pp2.y = 0; \ + \ + (loader)->pp3.x = use_aw_2_ ? (loader)->advance / 2 : 0; \ + (loader)->pp3.y = (loader)->bbox.yMax + (loader)->top_bearing; \ + (loader)->pp4.x = use_aw_2_ ? (loader)->advance / 2 : 0; \ + (loader)->pp4.y = (loader)->pp3.y - (loader)->vadvance; \ + } while ( 0 ) + +#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + #define TT_LOADER_SET_PP( loader ) \ - do { \ + do \ + { \ (loader)->pp1.x = (loader)->bbox.xMin - (loader)->left_bearing; \ (loader)->pp1.y = 0; \ (loader)->pp2.x = (loader)->pp1.x + (loader)->advance; \ (loader)->pp2.y = 0; \ + \ (loader)->pp3.x = 0; \ - (loader)->pp3.y = (loader)->top_bearing + (loader)->bbox.yMax; \ + (loader)->pp3.y = (loader)->bbox.yMax + (loader)->top_bearing; \ (loader)->pp4.x = 0; \ (loader)->pp4.y = (loader)->pp3.y - (loader)->vadvance; \ } while ( 0 ) +#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + /*************************************************************************/ /* */ @@ -1194,7 +1402,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; @@ -1217,14 +1425,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; } @@ -1241,8 +1449,6 @@ y_scale = 0x10000L; } - tt_get_metrics( loader, glyph_index ); - /* Set `offset' to the start of the glyph relative to the start of */ /* the `glyf' table, and `byte_len' to the length of the glyph in */ /* bytes. */ @@ -1288,7 +1494,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; } @@ -1302,7 +1508,17 @@ /* read glyph header first */ error = face->read_glyph_header( loader ); - if ( error || header_only ) + if ( error ) + goto Exit; + + /* the metrics must be computed after loading the glyph header */ + /* since we need the glyph's `yMax' value in case the vertical */ + /* metrics must be emulated */ + error = tt_get_metrics( loader, glyph_index ); + if ( error ) + goto Exit; + + if ( header_only ) goto Exit; } @@ -1313,11 +1529,21 @@ loader->bbox.yMin = 0; loader->bbox.yMax = 0; + error = tt_get_metrics( loader, glyph_index ); + if ( error ) + goto Exit; + if ( header_only ) goto Exit; + /* must initialize points before (possibly) overriding */ + /* glyph metrics from the incremental interface */ TT_LOADER_SET_PP( loader ); +#ifdef FT_CONFIG_OPTION_INCREMENTAL + tt_get_metrics_incr_overrides( loader, glyph_index ); +#endif + #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT if ( ((TT_Face)(loader->face))->doblend ) @@ -1331,30 +1557,47 @@ if ( error ) goto Exit; - loader->pp1.x += deltas[0].x; loader->pp1.y += deltas[0].y; - loader->pp2.x += deltas[1].x; loader->pp2.y += deltas[1].y; - loader->pp3.x += deltas[2].x; loader->pp3.y += deltas[2].y; - loader->pp4.x += deltas[3].x; loader->pp4.y += deltas[3].y; + loader->pp1.x += deltas[0].x; + loader->pp1.y += deltas[0].y; + loader->pp2.x += deltas[1].x; + loader->pp2.y += deltas[1].y; + + loader->pp3.x += deltas[2].x; + loader->pp3.y += deltas[2].y; + loader->pp4.x += deltas[3].x; + loader->pp4.y += deltas[3].y; FT_FREE( deltas ); } -#endif +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + /* scale phantom points, if necessary; */ + /* they get rounded in `TT_Hint_Glyph' */ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) { loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + /* pp1.y and pp2.y are always zero */ + + loader->pp3.x = FT_MulFix( loader->pp3.x, x_scale ); loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale ); + loader->pp4.x = FT_MulFix( loader->pp4.x, x_scale ); loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale ); } - error = TT_Err_Ok; + error = FT_Err_Ok; goto Exit; } + /* must initialize phantom points before (possibly) overriding */ + /* glyph metrics from the incremental interface */ TT_LOADER_SET_PP( loader ); +#ifdef FT_CONFIG_OPTION_INCREMENTAL + tt_get_metrics_incr_overrides( loader, glyph_index ); +#endif + /***********************************************************************/ /***********************************************************************/ /***********************************************************************/ @@ -1421,7 +1664,7 @@ face, glyph_index, &deltas, - gloader->current.num_subglyphs + 4 )) != 0 ) + gloader->current.num_subglyphs + 4 ) ) != 0 ) goto Exit; subglyph = gloader->current.subglyphs + gloader->base.num_subglyphs; @@ -1439,21 +1682,32 @@ } } - loader->pp1.x += deltas[i + 0].x; loader->pp1.y += deltas[i + 0].y; - loader->pp2.x += deltas[i + 1].x; loader->pp2.y += deltas[i + 1].y; - loader->pp3.x += deltas[i + 2].x; loader->pp3.y += deltas[i + 2].y; - loader->pp4.x += deltas[i + 3].x; loader->pp4.y += deltas[i + 3].y; + loader->pp1.x += deltas[i + 0].x; + loader->pp1.y += deltas[i + 0].y; + loader->pp2.x += deltas[i + 1].x; + loader->pp2.y += deltas[i + 1].y; + + loader->pp3.x += deltas[i + 2].x; + loader->pp3.y += deltas[i + 2].y; + loader->pp4.x += deltas[i + 3].x; + loader->pp4.y += deltas[i + 3].y; FT_FREE( deltas ); } #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + /* scale phantom points, if necessary; */ + /* they get rounded in `TT_Hint_Glyph' */ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) { loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + /* pp1.y and pp2.y are always zero */ + + loader->pp3.x = FT_MulFix( loader->pp3.x, x_scale ); loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale ); + loader->pp4.x = FT_MulFix( loader->pp4.x, x_scale ); loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale ); } @@ -1481,6 +1735,7 @@ FT_UInt num_base_subgs = gloader->base.num_subglyphs; FT_Stream old_stream = loader->stream; + FT_Int old_byte_len = loader->byte_len; FT_GlyphLoader_Add( gloader ); @@ -1512,6 +1767,7 @@ /* restore subglyph pointer */ subglyph = gloader->base.subglyphs + num_base_subgs + n; + /* restore phantom points if necessary */ if ( !( subglyph->flags & USE_MY_METRICS ) ) { loader->pp1 = pp[0]; @@ -1531,31 +1787,37 @@ /* (1): exists from the beginning */ /* (2): components that have been loaded so far */ /* (3): the newly loaded component */ - TT_Process_Composite_Component( loader, subglyph, start_point, - num_base_points ); + error = TT_Process_Composite_Component( loader, + subglyph, + start_point, + num_base_points ); + if ( error ) + goto Exit; } - loader->stream = old_stream; + loader->stream = old_stream; + loader->byte_len = old_byte_len; /* process the glyph */ loader->ins_pos = ins_pos; if ( IS_HINTED( loader->load_flags ) && - #ifdef TT_USE_BYTECODE_INTERPRETER - subglyph->flags & WE_HAVE_INSTR && - #endif - num_points > start_point ) - TT_Process_Composite_Glyph( loader, start_point, start_contour ); - + { + error = TT_Process_Composite_Glyph( loader, + start_point, + start_contour ); + if ( error ) + goto Exit; + } } } else { /* invalid composite count (negative but not -1) */ - error = TT_Err_Invalid_Outline; + error = FT_THROW( Invalid_Outline ); goto Exit; } @@ -1585,11 +1847,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; @@ -1603,23 +1869,7 @@ /* get the device-independent horizontal advance; it is scaled later */ /* by the base layer. */ - { - FT_Pos advance = loader->linear; - - - /* the flag FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH was introduced to */ - /* correctly support DynaLab fonts, which have an incorrect */ - /* `advance_Width_Max' field! It is used, to my knowledge, */ - /* exclusively in the X-TrueType font server. */ - /* */ - if ( face->postscript.isFixedPitch && - ( loader->load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ) == 0 ) - advance = face->horizontal.advance_Width_Max; - - /* we need to return the advance in font units in linearHoriAdvance, */ - /* it will be scaled later by the base layer. */ - glyph->linearHoriAdvance = advance; - } + glyph->linearHoriAdvance = loader->linear; glyph->metrics.horiBearingX = bbox.xMin; glyph->metrics.horiBearingY = bbox.yMax; @@ -1636,8 +1886,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 */ @@ -1814,8 +2086,13 @@ FT_Int32 load_flags, FT_Bool glyf_table_only ) { + FT_Error error; + 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; @@ -1831,37 +2108,153 @@ TT_ExecContext exec; FT_Bool grayscale; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); + + FT_Bool subpixel = FALSE; + +#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 ) + + if ( size->bytecode_ready < 0 || size->cvt_ready < 0 ) { - FT_Error error = tt_size_ready_bytecode( size ); + error = tt_size_ready_bytecode( size, pedantic ); if ( error ) return error; } + else if ( size->bytecode_ready ) + return size->bytecode_ready; + else if ( size->cvt_ready ) + return size->cvt_ready; /* query new execution context */ 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 ); - grayscale = - FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != FT_RENDER_MODE_MONO ); +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - TT_Load_Context( exec, face, size ); + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) + { + subpixel = FT_BOOL( ( FT_LOAD_TARGET_MODE( load_flags ) != + FT_RENDER_MODE_MONO ) && + SPH_OPTION_SET_SUBPIXEL ); + + if ( subpixel ) + grayscale = FALSE; + else if ( SPH_OPTION_SET_GRAYSCALE ) + { + grayscale = TRUE; + subpixel = FALSE; + } + else + grayscale = FALSE; + + if ( FT_IS_TRICKY( glyph->face ) ) + subpixel = FALSE; + + exec->ignore_x_mode = subpixel || grayscale; + 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 */ - /* a change from mono to grayscale rendering (and vice versa) */ - /* requires a re-execution of the CVT program */ - if ( grayscale != exec->grayscale ) { - FT_UInt i; + grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != + FT_RENDER_MODE_MONO ); + } + error = TT_Load_Context( exec, face, size ); + if ( error ) + return error; + +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) + { + /* a change from mono to subpixel rendering (and vice versa) */ + /* requires a re-execution of the CVT program */ + if ( subpixel != exec->subpixel ) + { + FT_TRACE4(( "tt_loader_init: subpixel hinting change," + " re-executing `prep' table\n" )); + + exec->subpixel = subpixel; + reexecute = TRUE; + } + + /* 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 hinting change," + " re-executing `prep' table\n" )); + + exec->grayscale = grayscale; + reexecute = TRUE; + } + } + else + +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + { + /* 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 ); - tt_size_run_prep( size ); + error = tt_size_run_prep( size, pedantic ); + if ( error ) + return error; } /* see whether the cvt program has disabled hinting */ @@ -1892,10 +2285,9 @@ #endif { - FT_Error error = face->goto_table( face, TTAG_glyf, stream, 0 ); - + 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 ) { @@ -1923,7 +2315,7 @@ loader->glyph = (FT_GlyphSlot)glyph; loader->stream = stream; - return TT_Err_Ok; + return FT_Err_Ok; } @@ -1960,13 +2352,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; + FT_TRACE1(( "TT_Load_Glyph: glyph index %d\n", glyph_index )); #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS @@ -1980,23 +2370,27 @@ 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 ); (void)load_truetype_glyph( &loader, glyph_index, 0, TRUE ); glyph->linearHoriAdvance = loader.linear; - glyph->linearVertAdvance = loader.top_bearing + loader.bbox.yMax - - loader.vadvance; - if ( face->postscript.isFixedPitch && - ( load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ) == 0 ) - glyph->linearHoriAdvance = face->horizontal.advance_Width_Max; + glyph->linearVertAdvance = loader.vadvance; + + /* sanity checks: if `xxxAdvance' in the sbit metric */ + /* structure isn't set, use `linearXXXAdvance' */ + if ( !glyph->metrics.horiAdvance && glyph->linearHoriAdvance ) + glyph->metrics.horiAdvance = + FT_MulFix( glyph->linearHoriAdvance, + size->root.metrics.x_scale ); + if ( !glyph->metrics.vertAdvance && glyph->linearVertAdvance ) + glyph->metrics.vertAdvance = + FT_MulFix( glyph->linearVertAdvance, + size->root.metrics.y_scale ); } - return TT_Err_Ok; + return FT_Err_Ok; } } @@ -2004,10 +2398,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 ) @@ -2031,9 +2425,11 @@ glyph->outline = loader.gloader->base.outline; glyph->outline.flags &= ~FT_OUTLINE_SINGLE_PASS; - /* In case bit 1 of the `flags' field in the `head' table isn't */ - /* set, translate array so that (0,0) is the glyph's origin. */ - if ( ( face->header.Flags & 2 ) == 0 && loader.pp1.x ) + /* Translate array so that (0,0) is the glyph's origin. Note */ + /* that this behaviour is independent on the value of bit 1 of */ + /* the `flags' field in the `head' table -- at least major */ + /* applications like Acroread indicate that. */ + if ( loader.pp1.x ) FT_Outline_Translate( &glyph->outline, -loader.pp1.x, 0 ); } @@ -2071,7 +2467,7 @@ #endif /* TT_USE_BYTECODE_INTERPRETER */ - compute_glyph_metrics( &loader, glyph_index ); + error = compute_glyph_metrics( &loader, glyph_index ); } /* Set the `high precision' bit flag. */ |