diff options
Diffstat (limited to 'src/3rdparty/freetype/src/truetype')
21 files changed, 4774 insertions, 1514 deletions
diff --git a/src/3rdparty/freetype/src/truetype/Jamfile b/src/3rdparty/freetype/src/truetype/Jamfile index 88cc26f2b1..e321fba14a 100644 --- a/src/3rdparty/freetype/src/truetype/Jamfile +++ b/src/3rdparty/freetype/src/truetype/Jamfile @@ -1,6 +1,6 @@ # FreeType 2 src/truetype Jamfile # -# Copyright 2001-2015 by +# Copyright 2001-2018 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/src/3rdparty/freetype/src/truetype/module.mk b/src/3rdparty/freetype/src/truetype/module.mk index c6dc6fa6e7..16bc9c8b20 100644 --- a/src/3rdparty/freetype/src/truetype/module.mk +++ b/src/3rdparty/freetype/src/truetype/module.mk @@ -3,7 +3,7 @@ # -# Copyright 1996-2015 by +# Copyright 1996-2018 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/src/3rdparty/freetype/src/truetype/rules.mk b/src/3rdparty/freetype/src/truetype/rules.mk index 1db16ba35f..e16113f128 100644 --- a/src/3rdparty/freetype/src/truetype/rules.mk +++ b/src/3rdparty/freetype/src/truetype/rules.mk @@ -3,7 +3,7 @@ # -# Copyright 1996-2015 by +# Copyright 1996-2018 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/src/3rdparty/freetype/src/truetype/truetype.c b/src/3rdparty/freetype/src/truetype/truetype.c index f929437dc1..484370975c 100644 --- a/src/3rdparty/freetype/src/truetype/truetype.c +++ b/src/3rdparty/freetype/src/truetype/truetype.c @@ -4,7 +4,7 @@ /* */ /* FreeType TrueType driver component (body only). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2018 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -17,22 +17,16 @@ #define FT_MAKE_OPTION_SINGLE_OBJECT - #include <ft2build.h> -#include "ttpic.c" + #include "ttdriver.c" /* driver interface */ -#include "ttpload.c" /* tables loader */ #include "ttgload.c" /* glyph loader */ -#include "ttobjs.c" /* object manager */ - -#ifdef TT_USE_BYTECODE_INTERPRETER +#include "ttgxvar.c" /* gx distortable font */ #include "ttinterp.c" +#include "ttobjs.c" /* object manager */ +#include "ttpic.c" +#include "ttpload.c" /* tables loader */ #include "ttsubpix.c" -#endif - -#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT -#include "ttgxvar.c" /* gx distortable font */ -#endif /* END */ diff --git a/src/3rdparty/freetype/src/truetype/ttdriver.c b/src/3rdparty/freetype/src/truetype/ttdriver.c index 08b30c95ad..820cafbb8d 100644 --- a/src/3rdparty/freetype/src/truetype/ttdriver.c +++ b/src/3rdparty/freetype/src/truetype/ttdriver.c @@ -4,7 +4,7 @@ /* */ /* TrueType font driver implementation (body). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2018 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -25,12 +25,13 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT #include FT_MULTIPLE_MASTERS_H #include FT_SERVICE_MULTIPLE_MASTERS_H +#include FT_SERVICE_METRICS_VARIATIONS_H #endif #include FT_SERVICE_TRUETYPE_ENGINE_H #include FT_SERVICE_TRUETYPE_GLYF_H #include FT_SERVICE_PROPERTIES_H -#include FT_TRUETYPE_DRIVER_H +#include FT_DRIVER_H #include "ttdriver.h" #include "ttgload.h" @@ -61,23 +62,50 @@ static FT_Error tt_property_set( FT_Module module, /* TT_Driver */ const char* property_name, - const void* value ) + const void* value, + FT_Bool value_is_string ) { FT_Error error = FT_Err_Ok; TT_Driver driver = (TT_Driver)module; +#ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + FT_UNUSED( value_is_string ); +#endif + if ( !ft_strcmp( property_name, "interpreter-version" ) ) { - FT_UInt* interpreter_version = (FT_UInt*)value; + FT_UInt interpreter_version; -#ifndef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( *interpreter_version != TT_INTERPRETER_VERSION_35 ) - error = FT_ERR( Unimplemented_Feature ); +#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + if ( value_is_string ) + { + const char* s = (const char*)value; + + + interpreter_version = (FT_UInt)ft_strtol( s, NULL, 10 ); + } else #endif - driver->interpreter_version = *interpreter_version; + { + FT_UInt* iv = (FT_UInt*)value; + + + interpreter_version = *iv; + } + + if ( interpreter_version == TT_INTERPRETER_VERSION_35 +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + || interpreter_version == TT_INTERPRETER_VERSION_38 +#endif +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + || interpreter_version == TT_INTERPRETER_VERSION_40 +#endif + ) + driver->interpreter_version = interpreter_version; + else + error = FT_ERR( Unimplemented_Feature ); return error; } @@ -117,8 +145,10 @@ FT_DEFINE_SERVICE_PROPERTIESREC( tt_service_properties, - (FT_Properties_SetFunc)tt_property_set, - (FT_Properties_GetFunc)tt_property_get ) + + (FT_Properties_SetFunc)tt_property_set, /* set_property */ + (FT_Properties_GetFunc)tt_property_get /* get_property */ + ) /*************************************************************************/ @@ -194,13 +224,20 @@ FT_Fixed *advances ) { FT_UInt nn; - TT_Face face = (TT_Face) ttface; + TT_Face face = (TT_Face)ttface; /* XXX: TODO: check for sbits */ if ( flags & FT_LOAD_VERTICAL_LAYOUT ) { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* no fast retrieval for blended MM fonts without VVAR table */ + if ( ( FT_IS_NAMED_INSTANCE( ttface ) || FT_IS_VARIATION( ttface ) ) && + !( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) + return FT_THROW( Unimplemented_Feature ); +#endif + for ( nn = 0; nn < count; nn++ ) { FT_Short tsb; @@ -214,6 +251,13 @@ } else { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* no fast retrieval for blended MM fonts without HVAR table */ + if ( ( FT_IS_NAMED_INSTANCE( ttface ) || FT_IS_VARIATION( ttface ) ) && + !( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) + return FT_THROW( Unimplemented_Feature ); +#endif + for ( nn = 0; nn < count; nn++ ) { FT_Short lsb; @@ -228,6 +272,7 @@ return FT_Err_Ok; } + /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ @@ -259,15 +304,17 @@ /* use the scaled metrics, even when tt_size_reset fails */ FT_Select_Metrics( size->face, strike_index ); - tt_size_reset( ttsize ); /* ignore return value */ + tt_size_reset( ttsize, 0 ); /* ignore return value */ } else { - SFNT_Service sfnt = (SFNT_Service) ttface->sfnt; - FT_Size_Metrics* metrics = &size->metrics; + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; + FT_Size_Metrics* size_metrics = &size->metrics; - error = sfnt->load_strike_metrics( ttface, strike_index, metrics ); + error = sfnt->load_strike_metrics( ttface, + strike_index, + size_metrics ); if ( error ) ttsize->strike_index = 0xFFFFFFFFUL; } @@ -291,7 +338,7 @@ if ( FT_HAS_FIXED_SIZES( size->face ) ) { TT_Face ttface = (TT_Face)size->face; - SFNT_Service sfnt = (SFNT_Service) ttface->sfnt; + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; FT_ULong strike_index; @@ -309,8 +356,28 @@ if ( FT_IS_SCALABLE( size->face ) ) { - error = tt_size_reset( ttsize ); - ttsize->root.metrics = ttsize->metrics; + error = tt_size_reset( ttsize, 0 ); + +#ifdef TT_USE_BYTECODE_INTERPRETER + /* for the `MPS' bytecode instruction we need the point size */ + if ( !error ) + { + FT_UInt resolution = + ttsize->metrics->x_ppem > ttsize->metrics->y_ppem + ? req->horiResolution + : req->vertResolution; + + + /* if we don't have a resolution value, assume 72dpi */ + if ( req->type == FT_SIZE_REQUEST_TYPE_SCALES || + !resolution ) + resolution = 72; + + ttsize->point_size = FT_MulDiv( ttsize->ttmetrics.ppem, + 64 * 72, + resolution ); + } +#endif } return error; @@ -392,6 +459,11 @@ load_flags |= FT_LOAD_NO_HINTING; } + /* use hinted metrics only if we load a glyph with hinting */ + size->metrics = ( load_flags & FT_LOAD_NO_HINTING ) + ? &ttsize->metrics + : &size->hinted_metrics; + /* now load the glyph outline if necessary */ error = TT_Load_Glyph( size, slot, glyph_index, load_flags ); @@ -415,24 +487,46 @@ /*************************************************************************/ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_DEFINE_SERVICE_MULTIMASTERSREC( tt_service_gx_multi_masters, - (FT_Get_MM_Func) NULL, - (FT_Set_MM_Design_Func) NULL, - (FT_Set_MM_Blend_Func) TT_Set_MM_Blend, - (FT_Get_MM_Var_Func) TT_Get_MM_Var, - (FT_Set_Var_Design_Func)TT_Set_Var_Design ) -#endif + + (FT_Get_MM_Func) NULL, /* get_mm */ + (FT_Set_MM_Design_Func) NULL, /* set_mm_design */ + (FT_Set_MM_Blend_Func) TT_Set_MM_Blend, /* set_mm_blend */ + (FT_Get_MM_Blend_Func) TT_Get_MM_Blend, /* get_mm_blend */ + (FT_Get_MM_Var_Func) TT_Get_MM_Var, /* get_mm_var */ + (FT_Set_Var_Design_Func)TT_Set_Var_Design, /* set_var_design */ + (FT_Get_Var_Design_Func)TT_Get_Var_Design, /* get_var_design */ + (FT_Set_Instance_Func) TT_Set_Named_Instance, /* set_instance */ + + (FT_Get_Var_Blend_Func) tt_get_var_blend, /* get_var_blend */ + (FT_Done_Blend_Func) tt_done_blend /* done_blend */ + ) + + FT_DEFINE_SERVICE_METRICSVARIATIONSREC( + tt_service_metrics_variations, + + (FT_HAdvance_Adjust_Func)tt_hadvance_adjust, /* hadvance_adjust */ + (FT_LSB_Adjust_Func) NULL, /* lsb_adjust */ + (FT_RSB_Adjust_Func) NULL, /* rsb_adjust */ + + (FT_VAdvance_Adjust_Func)tt_vadvance_adjust, /* vadvance_adjust */ + (FT_TSB_Adjust_Func) NULL, /* tsb_adjust */ + (FT_BSB_Adjust_Func) NULL, /* bsb_adjust */ + (FT_VOrg_Adjust_Func) NULL, /* vorg_adjust */ + + (FT_Metrics_Adjust_Func) tt_apply_mvar /* metrics_adjust */ + ) + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + static const FT_Service_TrueTypeEngineRec tt_service_truetype_engine = { #ifdef TT_USE_BYTECODE_INTERPRETER -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - FT_TRUETYPE_ENGINE_TYPE_UNPATENTED -#else FT_TRUETYPE_ENGINE_TYPE_PATENTED -#endif #else /* !TT_USE_BYTECODE_INTERPRETER */ @@ -441,21 +535,28 @@ #endif /* TT_USE_BYTECODE_INTERPRETER */ }; + FT_DEFINE_SERVICE_TTGLYFREC( tt_service_truetype_glyf, - (TT_Glyf_GetLocationFunc)tt_face_get_location ) + + (TT_Glyf_GetLocationFunc)tt_face_get_location /* get_location */ + ) + #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - FT_DEFINE_SERVICEDESCREC5( + FT_DEFINE_SERVICEDESCREC6( tt_services, - FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_TRUETYPE, - FT_SERVICE_ID_MULTI_MASTERS, &TT_SERVICE_GX_MULTI_MASTERS_GET, - FT_SERVICE_ID_TRUETYPE_ENGINE, &tt_service_truetype_engine, - FT_SERVICE_ID_TT_GLYF, &TT_SERVICE_TRUETYPE_GLYF_GET, - FT_SERVICE_ID_PROPERTIES, &TT_SERVICE_PROPERTIES_GET ) + + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_TRUETYPE, + FT_SERVICE_ID_MULTI_MASTERS, &TT_SERVICE_GX_MULTI_MASTERS_GET, + FT_SERVICE_ID_METRICS_VARIATIONS, &TT_SERVICE_METRICS_VARIATIONS_GET, + FT_SERVICE_ID_TRUETYPE_ENGINE, &tt_service_truetype_engine, + FT_SERVICE_ID_TT_GLYF, &TT_SERVICE_TRUETYPE_GLYF_GET, + FT_SERVICE_ID_PROPERTIES, &TT_SERVICE_PROPERTIES_GET ) #else FT_DEFINE_SERVICEDESCREC4( tt_services, + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_TRUETYPE, FT_SERVICE_ID_TRUETYPE_ENGINE, &tt_service_truetype_engine, FT_SERVICE_ID_TT_GLYF, &TT_SERVICE_TRUETYPE_GLYF_GET, @@ -483,7 +584,7 @@ #endif result = ft_service_list_lookup( TT_SERVICES_GET, tt_interface ); - if ( result != NULL ) + if ( result ) return result; #ifndef FT_CONFIG_OPTION_PIC @@ -534,31 +635,31 @@ 0x10000L, /* driver version == 1.0 */ 0x20000L, /* driver requires FreeType 2.0 or above */ - (void*)0, /* driver specific interface */ + NULL, /* module-specific interface */ - tt_driver_init, - tt_driver_done, - tt_get_interface, + tt_driver_init, /* FT_Module_Constructor module_init */ + tt_driver_done, /* FT_Module_Destructor module_done */ + tt_get_interface, /* FT_Module_Requester get_interface */ sizeof ( TT_FaceRec ), sizeof ( TT_SizeRec ), sizeof ( FT_GlyphSlotRec ), - tt_face_init, - tt_face_done, - tt_size_init, - tt_size_done, - tt_slot_init, - 0, /* FT_Slot_DoneFunc */ + tt_face_init, /* FT_Face_InitFunc init_face */ + tt_face_done, /* FT_Face_DoneFunc done_face */ + tt_size_init, /* FT_Size_InitFunc init_size */ + tt_size_done, /* FT_Size_DoneFunc done_size */ + tt_slot_init, /* FT_Slot_InitFunc init_slot */ + NULL, /* FT_Slot_DoneFunc done_slot */ - tt_glyph_load, + tt_glyph_load, /* FT_Slot_LoadFunc load_glyph */ - tt_get_kerning, - 0, /* FT_Face_AttachFunc */ - tt_get_advances, + tt_get_kerning, /* FT_Face_GetKerningFunc get_kerning */ + NULL, /* FT_Face_AttachFunc attach_file */ + tt_get_advances, /* FT_Face_GetAdvancesFunc get_advances */ - tt_size_request, - TT_SIZE_SELECT + tt_size_request, /* FT_Size_RequestFunc request_size */ + TT_SIZE_SELECT /* FT_Size_SelectFunc select_size */ ) diff --git a/src/3rdparty/freetype/src/truetype/ttdriver.h b/src/3rdparty/freetype/src/truetype/ttdriver.h index 6cacd60966..707aa68edf 100644 --- a/src/3rdparty/freetype/src/truetype/ttdriver.h +++ b/src/3rdparty/freetype/src/truetype/ttdriver.h @@ -4,7 +4,7 @@ /* */ /* High-level TrueType driver interface (specification). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2018 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,8 +16,8 @@ /***************************************************************************/ -#ifndef __TTDRIVER_H__ -#define __TTDRIVER_H__ +#ifndef TTDRIVER_H_ +#define TTDRIVER_H_ #include <ft2build.h> @@ -32,7 +32,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __TTDRIVER_H__ */ +#endif /* TTDRIVER_H_ */ /* END */ diff --git a/src/3rdparty/freetype/src/truetype/tterrors.h b/src/3rdparty/freetype/src/truetype/tterrors.h index ba32cf744c..88bca3a04a 100644 --- a/src/3rdparty/freetype/src/truetype/tterrors.h +++ b/src/3rdparty/freetype/src/truetype/tterrors.h @@ -4,7 +4,7 @@ /* */ /* TrueType error codes (specification only). */ /* */ -/* Copyright 2001-2015 by */ +/* Copyright 2001-2018 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -23,12 +23,12 @@ /* */ /*************************************************************************/ -#ifndef __TTERRORS_H__ -#define __TTERRORS_H__ +#ifndef TTERRORS_H_ +#define TTERRORS_H_ #include FT_MODULE_ERRORS_H -#undef __FTERRORS_H__ +#undef FTERRORS_H_ #undef FT_ERR_PREFIX #define FT_ERR_PREFIX TT_Err_ @@ -36,6 +36,7 @@ #include FT_ERRORS_H -#endif /* __TTERRORS_H__ */ +#endif /* TTERRORS_H_ */ + /* END */ diff --git a/src/3rdparty/freetype/src/truetype/ttgload.c b/src/3rdparty/freetype/src/truetype/ttgload.c index a792ad44a0..39d9c3f736 100644 --- a/src/3rdparty/freetype/src/truetype/ttgload.c +++ b/src/3rdparty/freetype/src/truetype/ttgload.c @@ -4,7 +4,7 @@ /* */ /* TrueType Glyph Loader (body). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2018 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -18,12 +18,14 @@ #include <ft2build.h> #include FT_INTERNAL_DEBUG_H +#include FT_CONFIG_CONFIG_H #include FT_INTERNAL_CALC_H #include FT_INTERNAL_STREAM_H #include FT_INTERNAL_SFNT_H #include FT_TRUETYPE_TAGS_H #include FT_OUTLINE_H -#include FT_TRUETYPE_DRIVER_H +#include FT_DRIVER_H +#include FT_LIST_H #include "ttgload.h" #include "ttpload.h" @@ -85,7 +87,7 @@ /*************************************************************************/ /* */ /* Return the vertical metrics in font units for a given glyph. */ - /* See macro `TT_LOADER_SET_PP' below for explanations. */ + /* See function `tt_loader_set_pp' below for explanations. */ /* */ FT_LOCAL_DEF( void ) TT_Get_VMetrics( TT_Face face, @@ -121,7 +123,7 @@ FT_UInt glyph_index ) { TT_Face face = loader->face; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); #endif @@ -152,7 +154,7 @@ loader->top_bearing = top_bearing; loader->vadvance = advance_height; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 && loader->exec ) { @@ -161,10 +163,10 @@ /* This may not be the right place for this, but it works... */ /* Note that we have to unconditionally load the tweaks since */ /* it is possible that glyphs individually switch ClearType's */ - /* backwards compatibility mode on and off. */ + /* backward compatibility mode on and off. */ sph_set_tweaks( loader, glyph_index ); } -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ if ( !loader->linear_def ) { @@ -193,39 +195,39 @@ if ( face->root.internal->incremental_interface && face->root.internal->incremental_interface->funcs->get_glyph_metrics ) { - FT_Incremental_MetricsRec metrics; + FT_Incremental_MetricsRec incr_metrics; FT_Error error; - metrics.bearing_x = loader->left_bearing; - metrics.bearing_y = 0; - metrics.advance = loader->advance; - metrics.advance_v = 0; + incr_metrics.bearing_x = loader->left_bearing; + incr_metrics.bearing_y = 0; + incr_metrics.advance = loader->advance; + incr_metrics.advance_v = 0; error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( face->root.internal->incremental_interface->object, - glyph_index, FALSE, &metrics ); + glyph_index, FALSE, &incr_metrics ); if ( error ) goto Exit; - left_bearing = (FT_Short)metrics.bearing_x; - advance_width = (FT_UShort)metrics.advance; + left_bearing = (FT_Short)incr_metrics.bearing_x; + advance_width = (FT_UShort)incr_metrics.advance; #if 0 /* GWW: Do I do the same for vertical metrics? */ - metrics.bearing_x = 0; - metrics.bearing_y = loader->top_bearing; - metrics.advance = loader->vadvance; + incr_metrics.bearing_x = 0; + incr_metrics.bearing_y = loader->top_bearing; + incr_metrics.advance = loader->vadvance; error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( face->root.internal->incremental_interface->object, - glyph_index, TRUE, &metrics ); + glyph_index, TRUE, &incr_metrics ); if ( error ) goto Exit; - top_bearing = (FT_Short)metrics.bearing_y; - advance_height = (FT_UShort)metrics.advance; + top_bearing = (FT_Short)incr_metrics.bearing_y; + advance_height = (FT_UShort)incr_metrics.advance; #endif /* 0 */ @@ -331,7 +333,6 @@ FT_Outline* outline; FT_UShort n_ins; FT_Int n_points; - FT_ULong tmp; FT_Byte *flag, *flag_limit; FT_Byte c, count; @@ -397,18 +398,21 @@ FT_TRACE5(( " Instructions size: %u\n", n_ins )); - /* check it */ - if ( ( limit - p ) < n_ins ) - { - FT_TRACE0(( "TT_Load_Simple_Glyph: instruction count mismatch\n" )); - error = FT_THROW( Too_Many_Hints ); - goto Fail; - } - #ifdef TT_USE_BYTECODE_INTERPRETER if ( IS_HINTED( load->load_flags ) ) { + FT_ULong tmp; + + + /* check instructions size */ + if ( ( limit - p ) < n_ins ) + { + FT_TRACE1(( "TT_Load_Simple_Glyph: instruction count mismatch\n" )); + error = FT_THROW( Too_Many_Hints ); + goto Fail; + } + /* we don't trust `maxSizeOfInstructions' in the `maxp' table */ /* and thus update the bytecode array size by ourselves */ @@ -426,7 +430,8 @@ load->glyph->control_len = n_ins; load->glyph->control_data = load->exec->glyphIns; - FT_MEM_COPY( load->exec->glyphIns, p, (FT_Long)n_ins ); + if ( n_ins ) + FT_MEM_COPY( load->exec->glyphIns, p, (FT_Long)n_ins ); } #endif /* TT_USE_BYTECODE_INTERPRETER */ @@ -439,7 +444,7 @@ flag = (FT_Byte*)outline->tags; flag_limit = flag + n_points; - FT_ASSERT( flag != NULL ); + FT_ASSERT( flag ); while ( flag < flag_limit ) { @@ -659,6 +664,52 @@ } while ( subglyph->flags & MORE_COMPONENTS ); gloader->current.num_subglyphs = num_subglyphs; + FT_TRACE5(( " %d component%s\n", + num_subglyphs, + num_subglyphs > 1 ? "s" : "" )); + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_UInt i; + + + subglyph = gloader->current.subglyphs; + + for ( i = 0; i < num_subglyphs; i++ ) + { + if ( num_subglyphs > 1 ) + FT_TRACE7(( " subglyph %d:\n", i )); + + FT_TRACE7(( " glyph index: %d\n", subglyph->index )); + + if ( subglyph->flags & ARGS_ARE_XY_VALUES ) + FT_TRACE7(( " offset: x=%d, y=%d\n", + subglyph->arg1, + subglyph->arg2 )); + else + FT_TRACE7(( " matching points: base=%d, component=%d\n", + subglyph->arg1, + subglyph->arg2 )); + + if ( subglyph->flags & WE_HAVE_A_SCALE ) + FT_TRACE7(( " scaling: %f\n", + subglyph->transform.xx / 65536.0 )); + else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) + FT_TRACE7(( " scaling: x=%f, y=%f\n", + subglyph->transform.xx / 65536.0, + subglyph->transform.yy / 65536.0 )); + else if ( subglyph->flags & WE_HAVE_A_2X2 ) + FT_TRACE7(( " scaling: xx=%f, yx=%f\n" + " xy=%f, yy=%f\n", + subglyph->transform.xx / 65536.0, + subglyph->transform.yx / 65536.0, + subglyph->transform.xy / 65536.0, + subglyph->transform.yy / 65536.0 )); + + subglyph++; + } + } +#endif /* FT_DEBUG_LEVEL_TRACE */ #ifdef TT_USE_BYTECODE_INTERPRETER @@ -730,7 +781,8 @@ TT_Hint_Glyph( TT_Loader loader, FT_Bool is_composite ) { -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#if defined TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY || \ + defined TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL TT_Face face = loader->face; TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); #endif @@ -749,7 +801,7 @@ { FT_TRACE1(( "TT_Hint_Glyph: too long instructions" )); FT_TRACE1(( " (0x%lx byte) is truncated\n", - loader->glyph->control_len )); + loader->glyph->control_len )); } n_ins = loader->glyph->control_len; @@ -771,8 +823,8 @@ } else { - loader->exec->metrics.x_scale = loader->size->metrics.x_scale; - loader->exec->metrics.y_scale = loader->size->metrics.y_scale; + loader->exec->metrics.x_scale = loader->size->metrics->x_scale; + loader->exec->metrics.y_scale = loader->size->metrics->y_scale; } #endif @@ -813,13 +865,23 @@ #endif - /* save glyph phantom points */ - 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_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Save possibly modified glyph phantom points unless in v40 backward */ + /* compatibility mode, where no movement on the x axis means no reason */ + /* to change bearings or advance widths. */ + if ( !( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && + loader->exec->backward_compatibility ) ) + { +#endif + 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_SUPPORT_SUBPIXEL_HINTING_MINIMAL + } +#endif -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) { if ( loader->exec->sph_tweak_flags & SPH_TWEAK_DEEMBOLDEN ) @@ -828,7 +890,7 @@ 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 */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ return FT_Err_Ok; } @@ -872,13 +934,24 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - if ( loader->face->doblend ) + if ( FT_IS_NAMED_INSTANCE( FT_FACE( loader->face ) ) || + FT_IS_VARIATION( FT_FACE( loader->face ) ) ) { /* Deltas apply to the unscaled data. */ error = TT_Vary_Apply_Glyph_Deltas( loader->face, loader->glyph_index, outline, (FT_UInt)n_points ); + + /* recalculate linear horizontal and vertical advances */ + /* if we don't have HVAR and VVAR, respectively */ + if ( !( loader->face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) + loader->linear = outline->points[n_points - 3].x - + outline->points[n_points - 4].x; + if ( !( loader->face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) + loader->vadvance = outline->points[n_points - 1].x - + outline->points[n_points - 2].x; + if ( error ) return error; } @@ -894,12 +967,12 @@ } { -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY TT_Face face = loader->face; TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); FT_String* family = face->root.family_name; - FT_UInt ppem = loader->size->metrics.x_ppem; + FT_UInt ppem = loader->size->metrics->x_ppem; FT_String* style = face->root.style_name; FT_UInt x_scale_factor = 1000; #endif @@ -913,7 +986,7 @@ FT_Bool do_scale = FALSE; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) { @@ -928,9 +1001,9 @@ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 || x_scale_factor != 1000 ) { - x_scale = FT_MulDiv( loader->size->metrics.x_scale, + x_scale = FT_MulDiv( loader->size->metrics->x_scale, (FT_Long)x_scale_factor, 1000 ); - y_scale = loader->size->metrics.y_scale; + y_scale = loader->size->metrics->y_scale; /* compensate for any scaling by de/emboldening; */ /* the amount was determined via experimentation */ @@ -944,14 +1017,14 @@ } else -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ { /* scale the glyph */ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) { - x_scale = loader->size->metrics.x_scale; - y_scale = loader->size->metrics.y_scale; + x_scale = loader->size->metrics->x_scale; + y_scale = loader->size->metrics->y_scale; do_scale = TRUE; } @@ -964,9 +1037,24 @@ vec->x = FT_MulFix( vec->x, x_scale ); vec->y = FT_MulFix( vec->y, y_scale ); } + } +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* if we have a HVAR table, `pp1' and/or `pp2' are already adjusted */ + if ( !( loader->face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) || + !IS_HINTED( loader->load_flags ) ) +#endif + { loader->pp1 = outline->points[n_points - 4]; loader->pp2 = outline->points[n_points - 3]; + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* if we have a VVAR table, `pp3' and/or `pp4' are already adjusted */ + if ( !( loader->face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) || + !IS_HINTED( loader->load_flags ) ) +#endif + { loader->pp3 = outline->points[n_points - 2]; loader->pp4 = outline->points[n_points - 1]; } @@ -1075,7 +1163,7 @@ : -subglyph->transform.yx; int c = subglyph->transform.xy > 0 ? subglyph->transform.xy : -subglyph->transform.xy; - int d = subglyph->transform.yy > 0 ? subglyph->transform.yy + int d = subglyph->transform.yy > 0 ? subglyph->transform.yy : -subglyph->transform.yy; int m = a > b ? a : b; int n = c > d ? c : d; @@ -1109,8 +1197,8 @@ if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) { - FT_Fixed x_scale = loader->size->metrics.x_scale; - FT_Fixed y_scale = loader->size->metrics.y_scale; + FT_Fixed x_scale = loader->size->metrics->x_scale; + FT_Fixed y_scale = loader->size->metrics->y_scale; x = FT_MulFix( x, x_scale ); @@ -1118,8 +1206,28 @@ if ( subglyph->flags & ROUND_XY_TO_GRID ) { - x = FT_PIX_ROUND( x ); - y = FT_PIX_ROUND( y ); + TT_Face face = loader->face; + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); + + + if ( IS_HINTED( loader->load_flags ) ) + { + /* + * We round the horizontal offset only if there is hinting along + * the x axis; this corresponds to integer advance width values. + * + * Theoretically, a glyph's bytecode can toggle ClearType's + * `backward compatibility' mode, which would allow modification + * of the advance width. In reality, however, applications + * neither allow nor expect modified advance widths if subpixel + * rendering is active. + * + */ + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_35 ) + x = FT_PIX_ROUND( x ); + + y = FT_PIX_ROUND( y ); + } } } } @@ -1321,49 +1429,72 @@ * (3) for everything else. * */ + static void + tt_loader_set_pp( TT_Loader loader ) + { + FT_Bool subpixel_hinting = 0; + FT_Bool grayscale = 0; + FT_Bool use_aw_2 = 0; + #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( loader->face ); +#endif + + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) + { + subpixel_hinting = loader->exec ? loader->exec->subpixel_hinting + : 0; + grayscale = loader->exec ? loader->exec->grayscale + : 0; + } +#endif +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 ) + { + subpixel_hinting = loader->exec ? loader->exec->subpixel_hinting_lean + : 0; + grayscale = loader->exec ? loader->exec->grayscale_cleartype + : 0; + } +#endif + + use_aw_2 = (FT_Bool)( subpixel_hinting && 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; + } + + + /* a utility function to retrieve i-th node from given FT_List */ + static FT_ListNode + ft_list_get_node_at( FT_List list, + FT_UInt idx ) + { + FT_ListNode cur; + -#define TT_LOADER_SET_PP( loader ) \ - do \ - { \ - FT_Bool subpixel_hinting_ = loader->exec \ - ? loader->exec->subpixel_hinting \ - : 0; \ - FT_Bool grayscale_ = loader->exec \ - ? loader->exec->grayscale \ - : 0; \ - FT_Bool use_aw_2_ = (FT_Bool)( subpixel_hinting_ && \ - 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 \ - { \ - (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)->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 */ + if ( !list ) + return NULL; + + for ( cur = list->head; cur; cur = cur->next ) + { + if ( !idx ) + return cur; + + idx--; + } + + return NULL; + } /*************************************************************************/ @@ -1395,13 +1526,17 @@ #endif - /* some fonts have an incorrect value of `maxComponentDepth', */ - /* thus we allow depth 1 to catch the majority of them */ - if ( recurse_count > 1 && - recurse_count > face->max_profile.maxComponentDepth ) +#ifdef FT_DEBUG_LEVEL_TRACE + if ( recurse_count ) + FT_TRACE5(( " nesting level: %d\n", recurse_count )); +#endif + + /* some fonts have an incorrect value of `maxComponentDepth' */ + if ( recurse_count > face->max_profile.maxComponentDepth ) { - error = FT_THROW( Invalid_Composite ); - goto Exit; + FT_TRACE1(( "load_truetype_glyph: maxComponentDepth set to %d\n", + recurse_count )); + face->max_profile.maxComponentDepth = (FT_UShort)recurse_count; } #ifndef FT_CONFIG_OPTION_INCREMENTAL @@ -1417,8 +1552,8 @@ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) { - x_scale = loader->size->metrics.x_scale; - y_scale = loader->size->metrics.y_scale; + x_scale = loader->size->metrics->x_scale; + y_scale = loader->size->metrics->y_scale; } else { @@ -1447,7 +1582,7 @@ offset = 0; loader->byte_len = glyph_data.length; - FT_MEM_ZERO( &inc_stream, sizeof ( inc_stream ) ); + FT_ZERO( &inc_stream ); FT_Stream_OpenMemory( &inc_stream, glyph_data.pointer, (FT_ULong)glyph_data.length ); @@ -1465,10 +1600,10 @@ { #ifdef FT_CONFIG_OPTION_INCREMENTAL /* for the incremental interface, `glyf_offset' is always zero */ - if ( !loader->glyf_offset && + if ( !face->glyf_offset && !face->root.internal->incremental_interface ) #else - if ( !loader->glyf_offset ) + if ( !face->glyf_offset ) #endif /* FT_CONFIG_OPTION_INCREMENTAL */ { FT_TRACE2(( "no `glyf' table but non-zero `loca' entry\n" )); @@ -1477,7 +1612,7 @@ } error = face->access_glyph_frame( loader, glyph_index, - loader->glyf_offset + offset, + face->glyf_offset + offset, (FT_UInt)loader->byte_len ); if ( error ) goto Exit; @@ -1516,7 +1651,7 @@ /* must initialize points before (possibly) overriding */ /* glyph metrics from the incremental interface */ - TT_LOADER_SET_PP( loader ); + tt_loader_set_pp( loader ); #ifdef FT_CONFIG_OPTION_INCREMENTAL tt_get_metrics_incr_overrides( loader, glyph_index ); @@ -1524,7 +1659,8 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - if ( loader->face->doblend ) + if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) || + FT_IS_VARIATION( FT_FACE( face ) ) ) { /* a small outline structure with four elements for */ /* communication with `TT_Vary_Apply_Glyph_Deltas' */ @@ -1567,6 +1703,14 @@ loader->pp3.y = points[2].y; loader->pp4.x = points[3].x; loader->pp4.y = points[3].y; + + + /* recalculate linear horizontal and vertical advances */ + /* if we don't have HVAR and VVAR, respectively */ + if ( !( loader->face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) + loader->linear = loader->pp2.x - loader->pp1.x; + if ( !( loader->face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) + loader->vadvance = loader->pp4.x - loader->pp3.x; } #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ @@ -1591,7 +1735,7 @@ /* must initialize phantom points before (possibly) overriding */ /* glyph metrics from the incremental interface */ - TT_LOADER_SET_PP( loader ); + tt_loader_set_pp( loader ); #ifdef FT_CONFIG_OPTION_INCREMENTAL tt_get_metrics_incr_overrides( loader, glyph_index ); @@ -1625,12 +1769,53 @@ /***********************************************************************/ /* otherwise, load a composite! */ - else if ( loader->n_contours == -1 ) + else if ( loader->n_contours < 0 ) { + FT_Memory memory = face->root.memory; + FT_UInt start_point; FT_UInt start_contour; FT_ULong ins_pos; /* position of composite instructions, if any */ + FT_ListNode node, node2; + + + /* normalize the `n_contours' value */ + loader->n_contours = -1; + + /* + * We store the glyph index directly in the `node->data' pointer, + * following the glib solution (cf. macro `GUINT_TO_POINTER') with a + * double cast to make this portable. Note, however, that this needs + * pointers with a width of at least 32 bits. + */ + + + /* clear the nodes filled by sibling chains */ + node = ft_list_get_node_at( &loader->composites, recurse_count ); + for ( node2 = node; node2; node2 = node2->next ) + node2->data = (void*)FT_ULONG_MAX; + + /* check whether we already have a composite glyph with this index */ + if ( FT_List_Find( &loader->composites, + FT_UINT_TO_POINTER( glyph_index ) ) ) + { + FT_TRACE1(( "TT_Load_Composite_Glyph:" + " infinite recursion detected\n" )); + error = FT_THROW( Invalid_Composite ); + goto Exit; + } + + else if ( node ) + node->data = FT_UINT_TO_POINTER( glyph_index ); + + else + { + if ( FT_NEW( node ) ) + goto Exit; + node->data = FT_UINT_TO_POINTER( glyph_index ); + FT_List_Add( &loader->composites, node ); + } start_point = (FT_UInt)gloader->base.outline.n_points; start_contour = (FT_UInt)gloader->base.outline.n_contours; @@ -1649,7 +1834,8 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - if ( face->doblend ) + if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) || + FT_IS_VARIATION( FT_FACE( face ) ) ) { short i, limit; FT_SubGlyph subglyph; @@ -1659,8 +1845,6 @@ char* tags = NULL; short* contours = NULL; - FT_Memory memory = face->root.memory; - limit = (short)gloader->current.num_subglyphs; @@ -1669,6 +1853,10 @@ outline.n_points = (short)( gloader->current.num_subglyphs + 4 ); outline.n_contours = outline.n_points; + outline.points = NULL; + outline.tags = NULL; + outline.contours = NULL; + if ( FT_NEW_ARRAY( points, outline.n_points ) || FT_NEW_ARRAY( tags, outline.n_points ) || FT_NEW_ARRAY( contours, outline.n_points ) ) @@ -1716,22 +1904,22 @@ /* this call provides additional offsets */ /* for each component's translation */ - if ( ( error = TT_Vary_Apply_Glyph_Deltas( - face, - glyph_index, - &outline, - (FT_UInt)outline.n_points ) ) != 0 ) + if ( FT_SET_ERROR( TT_Vary_Apply_Glyph_Deltas( + face, + glyph_index, + &outline, + (FT_UInt)outline.n_points ) ) ) goto Exit1; subglyph = gloader->current.subglyphs; for ( i = 0; i < limit; i++, subglyph++ ) { - /* XXX: overflow check for subglyph->{arg1,arg2}. */ - /* Deltas must be within signed 16-bit, */ - /* but the restriction of summed deltas is not clear */ - subglyph->arg1 = (FT_Int16)points[i].x; - subglyph->arg2 = (FT_Int16)points[i].y; + if ( subglyph->flags & ARGS_ARE_XY_VALUES ) + { + subglyph->arg1 = (FT_Int16)points[i].x; + subglyph->arg2 = (FT_Int16)points[i].y; + } } loader->pp1.x = points[i + 0].x; @@ -1744,6 +1932,13 @@ loader->pp4.x = points[i + 3].x; loader->pp4.y = points[i + 3].y; + /* recalculate linear horizontal and vertical advances */ + /* if we don't have HVAR and VVAR, respectively */ + if ( !( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) + loader->linear = loader->pp2.x - loader->pp1.x; + if ( !( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) + loader->vadvance = loader->pp4.x - loader->pp3.x; + Exit1: FT_FREE( outline.points ); FT_FREE( outline.tags ); @@ -1803,6 +1998,9 @@ { FT_Vector pp[4]; + FT_Int linear_hadvance; + FT_Int linear_vadvance; + /* Each time we call load_truetype_glyph in this loop, the */ /* value of `gloader.base.subglyphs' can change due to table */ @@ -1815,6 +2013,9 @@ pp[2] = loader->pp3; pp[3] = loader->pp4; + linear_hadvance = loader->linear; + linear_vadvance = loader->vadvance; + num_base_points = (FT_UInt)gloader->base.outline.n_points; error = load_truetype_glyph( loader, @@ -1834,6 +2035,9 @@ loader->pp2 = pp[1]; loader->pp3 = pp[2]; loader->pp4 = pp[3]; + + loader->linear = linear_hadvance; + loader->vadvance = linear_vadvance; } num_points = (FT_UInt)gloader->base.outline.n_points; @@ -1874,12 +2078,6 @@ } } } - else - { - /* invalid composite count (negative but not -1) */ - error = FT_THROW( Invalid_Outline ); - goto Exit; - } /***********************************************************************/ /***********************************************************************/ @@ -1908,7 +2106,8 @@ FT_UInt glyph_index ) { TT_Face face = loader->face; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#if defined TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY || \ + defined TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); #endif @@ -1920,7 +2119,7 @@ y_scale = 0x10000L; if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) - y_scale = size->root.metrics.y_scale; + y_scale = size->metrics->y_scale; if ( glyph->format != FT_GLYPH_FORMAT_COMPOSITE ) FT_Outline_Get_CBox( &glyph->outline, &bbox ); @@ -1935,20 +2134,27 @@ glyph->metrics.horiBearingY = bbox.yMax; glyph->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; - /* adjust advance width to the value contained in the hdmx table */ - /* unless FT_LOAD_COMPUTE_METRICS is set */ - if ( !face->postscript.isFixedPitch && - IS_HINTED( loader->load_flags ) && - !( loader->load_flags & FT_LOAD_COMPUTE_METRICS ) ) + /* Adjust advance width to the value contained in the hdmx table */ + /* unless FT_LOAD_COMPUTE_METRICS is set or backward compatibility */ + /* mode of the v40 interpreter is active. See `ttinterp.h' for */ + /* details on backward compatibility mode. */ + if ( +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + !( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && + ( loader->exec && loader->exec->backward_compatibility ) ) && +#endif + !face->postscript.isFixedPitch && + IS_HINTED( loader->load_flags ) && + !( loader->load_flags & FT_LOAD_COMPUTE_METRICS ) ) { FT_Byte* widthp; widthp = tt_face_get_device_metrics( face, - size->root.metrics.x_ppem, + size->metrics->x_ppem, glyph_index ); -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) { @@ -1966,7 +2172,7 @@ } else -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ { if ( widthp ) @@ -1975,8 +2181,8 @@ } /* set glyph dimensions */ - glyph->metrics.width = bbox.xMax - bbox.xMin; - glyph->metrics.height = bbox.yMax - bbox.yMin; + glyph->metrics.width = SUB_LONG( bbox.xMax, bbox.xMin ); + glyph->metrics.height = SUB_LONG( bbox.yMax, bbox.yMin ); /* Now take care of vertical metrics. In the case where there is */ /* no vertical information within the font (relatively common), */ @@ -2012,7 +2218,8 @@ /* table in the font. Otherwise, we use the */ /* values defined in the horizontal header. */ - height = (FT_Short)FT_DivFix( bbox.yMax - bbox.yMin, + height = (FT_Short)FT_DivFix( SUB_LONG( bbox.yMax, + bbox.yMin ), y_scale ); if ( face->os2.version != 0xFFFFU ) advance = (FT_Pos)( face->os2.sTypoAscender - @@ -2027,7 +2234,7 @@ #ifdef FT_CONFIG_OPTION_INCREMENTAL { FT_Incremental_InterfaceRec* incr; - FT_Incremental_MetricsRec metrics; + FT_Incremental_MetricsRec incr_metrics; FT_Error error; @@ -2037,19 +2244,19 @@ /* overriding metrics for this glyph. */ if ( incr && incr->funcs->get_glyph_metrics ) { - metrics.bearing_x = 0; - metrics.bearing_y = top; - metrics.advance = advance; + incr_metrics.bearing_x = 0; + incr_metrics.bearing_y = top; + incr_metrics.advance = advance; error = incr->funcs->get_glyph_metrics( incr->object, glyph_index, TRUE, - &metrics ); + &incr_metrics ); if ( error ) return error; - top = metrics.bearing_y; - advance = metrics.advance; + top = incr_metrics.bearing_y; + advance = incr_metrics.advance; } } @@ -2091,7 +2298,7 @@ SFNT_Service sfnt; FT_Stream stream; FT_Error error; - TT_SBit_MetricsRec metrics; + TT_SBit_MetricsRec sbit_metrics; face = (TT_Face)glyph->face; @@ -2104,34 +2311,34 @@ (FT_UInt)load_flags, stream, &glyph->bitmap, - &metrics ); + &sbit_metrics ); if ( !error ) { glyph->outline.n_points = 0; glyph->outline.n_contours = 0; - glyph->metrics.width = (FT_Pos)metrics.width * 64; - glyph->metrics.height = (FT_Pos)metrics.height * 64; + glyph->metrics.width = (FT_Pos)sbit_metrics.width * 64; + glyph->metrics.height = (FT_Pos)sbit_metrics.height * 64; - glyph->metrics.horiBearingX = (FT_Pos)metrics.horiBearingX * 64; - glyph->metrics.horiBearingY = (FT_Pos)metrics.horiBearingY * 64; - glyph->metrics.horiAdvance = (FT_Pos)metrics.horiAdvance * 64; + glyph->metrics.horiBearingX = (FT_Pos)sbit_metrics.horiBearingX * 64; + glyph->metrics.horiBearingY = (FT_Pos)sbit_metrics.horiBearingY * 64; + glyph->metrics.horiAdvance = (FT_Pos)sbit_metrics.horiAdvance * 64; - glyph->metrics.vertBearingX = (FT_Pos)metrics.vertBearingX * 64; - glyph->metrics.vertBearingY = (FT_Pos)metrics.vertBearingY * 64; - glyph->metrics.vertAdvance = (FT_Pos)metrics.vertAdvance * 64; + glyph->metrics.vertBearingX = (FT_Pos)sbit_metrics.vertBearingX * 64; + glyph->metrics.vertBearingY = (FT_Pos)sbit_metrics.vertBearingY * 64; + glyph->metrics.vertAdvance = (FT_Pos)sbit_metrics.vertAdvance * 64; glyph->format = FT_GLYPH_FORMAT_BITMAP; if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) { - glyph->bitmap_left = metrics.vertBearingX; - glyph->bitmap_top = metrics.vertBearingY; + glyph->bitmap_left = sbit_metrics.vertBearingX; + glyph->bitmap_top = sbit_metrics.vertBearingY; } else { - glyph->bitmap_left = metrics.horiBearingX; - glyph->bitmap_top = metrics.horiBearingY; + glyph->bitmap_left = sbit_metrics.horiBearingX; + glyph->bitmap_top = sbit_metrics.horiBearingY; } } @@ -2148,19 +2355,23 @@ FT_Int32 load_flags, FT_Bool glyf_table_only ) { - FT_Error error; - TT_Face face; FT_Stream stream; + #ifdef TT_USE_BYTECODE_INTERPRETER + FT_Error error; FT_Bool pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); +#if defined TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY || \ + defined TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( (TT_Face)glyph->face ); +#endif #endif face = (TT_Face)glyph->face; stream = face->root.stream; - FT_MEM_ZERO( loader, sizeof ( TT_LoaderRec ) ); + FT_ZERO( loader ); #ifdef TT_USE_BYTECODE_INTERPRETER @@ -2168,11 +2379,13 @@ if ( IS_HINTED( load_flags ) && !glyf_table_only ) { TT_ExecContext exec; - FT_Bool grayscale; - -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); + FT_Bool grayscale = TRUE; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + FT_Bool subpixel_hinting_lean; + FT_Bool grayscale_cleartype; +#endif +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY FT_Bool subpixel_hinting = FALSE; #if 0 @@ -2184,7 +2397,7 @@ FT_Bool subpixel_positioned; FT_Bool gray_cleartype; #endif -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ FT_Bool reexecute = FALSE; @@ -2205,7 +2418,32 @@ if ( !exec ) return FT_THROW( Could_Not_Find_Context ); -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 ) + { + subpixel_hinting_lean = + FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != + FT_RENDER_MODE_MONO ); + grayscale_cleartype = + FT_BOOL( subpixel_hinting_lean && + !( ( load_flags & + FT_LOAD_TARGET_LCD ) || + ( load_flags & + FT_LOAD_TARGET_LCD_V ) ) ); + exec->vertical_lcd_lean = + FT_BOOL( subpixel_hinting_lean && + ( load_flags & + FT_LOAD_TARGET_LCD_V ) ); + } + else + { + subpixel_hinting_lean = FALSE; + grayscale_cleartype = FALSE; + exec->vertical_lcd_lean = FALSE; + } +#endif + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) { @@ -2262,18 +2500,23 @@ } else -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 ) + grayscale = FT_BOOL( !subpixel_hinting_lean && + FT_LOAD_TARGET_MODE( load_flags ) != + FT_RENDER_MODE_MONO ); + else +#endif grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != - FT_RENDER_MODE_MONO ); - } + FT_RENDER_MODE_MONO ); error = TT_Load_Context( exec, face, size ); if ( error ) return error; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) { @@ -2301,9 +2544,37 @@ } else -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ { + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 ) + { + /* a change from mono to subpixel rendering (and vice versa) */ + /* requires a re-execution of the CVT program */ + if ( subpixel_hinting_lean != exec->subpixel_hinting_lean ) + { + FT_TRACE4(( "tt_loader_init: subpixel hinting change," + " re-executing `prep' table\n" )); + + exec->subpixel_hinting_lean = subpixel_hinting_lean; + reexecute = TRUE; + } + + /* a change from colored to grayscale subpixel rendering (and */ + /* vice versa) requires a re-execution of the CVT program */ + if ( grayscale_cleartype != exec->grayscale_cleartype ) + { + FT_TRACE4(( "tt_loader_init: grayscale subpixel hinting change," + " re-executing `prep' table\n" )); + + exec->grayscale_cleartype = grayscale_cleartype; + reexecute = TRUE; + } + } +#endif + /* a change from mono to grayscale rendering (and vice versa) */ /* requires a re-execution of the CVT program */ if ( grayscale != exec->grayscale ) @@ -2336,10 +2607,11 @@ if ( exec->GS.instruct_control & 2 ) exec->GS = tt_default_graphics_state; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY /* check whether we have a font hinted for ClearType -- */ /* note that this flag can also be modified in a glyph's bytecode */ - if ( exec->GS.instruct_control & 4 ) + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 && + exec->GS.instruct_control & 4 ) exec->ignore_x_mode = 0; #endif @@ -2350,32 +2622,6 @@ #endif /* TT_USE_BYTECODE_INTERPRETER */ - /* seek to the beginning of the glyph table -- for Type 42 fonts */ - /* the table might be accessed from a Postscript stream or something */ - /* else... */ - -#ifdef FT_CONFIG_OPTION_INCREMENTAL - - if ( face->root.internal->incremental_interface ) - loader->glyf_offset = 0; - else - -#endif - - { - error = face->goto_table( face, TTAG_glyf, stream, 0 ); - - if ( FT_ERR_EQ( error, Table_Missing ) ) - loader->glyf_offset = 0; - else if ( error ) - { - FT_ERROR(( "tt_loader_init: could not access glyph table\n" )); - return error; - } - else - loader->glyf_offset = FT_STREAM_POS(); - } - /* get face's glyph loader */ if ( !glyf_table_only ) { @@ -2393,10 +2639,23 @@ loader->glyph = (FT_GlyphSlot)glyph; loader->stream = stream; + loader->composites.head = NULL; + loader->composites.tail = NULL; + return FT_Err_Ok; } + static void + tt_loader_done( TT_Loader loader ) + { + FT_List_Finalize( &loader->composites, + NULL, + loader->face->root.memory, + NULL ); + } + + /*************************************************************************/ /* */ /* <Function> */ @@ -2433,39 +2692,108 @@ FT_Error error; TT_LoaderRec loader; +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#define IS_DEFAULT_INSTANCE ( !( FT_IS_NAMED_INSTANCE( glyph->face ) || \ + FT_IS_VARIATION( glyph->face ) ) ) +#else +#define IS_DEFAULT_INSTANCE 1 +#endif + FT_TRACE1(( "TT_Load_Glyph: glyph index %d\n", glyph_index )); #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS - /* try to load embedded bitmap if any */ - /* */ - /* XXX: The convention should be emphasized in */ - /* the documents because it can be confusing. */ + /* try to load embedded bitmap (if any) */ if ( size->strike_index != 0xFFFFFFFFUL && - ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) + ( load_flags & FT_LOAD_NO_BITMAP ) == 0 && + IS_DEFAULT_INSTANCE ) { + FT_Fixed x_scale = size->root.metrics.x_scale; + FT_Fixed y_scale = size->root.metrics.y_scale; + + error = load_sbit_image( size, glyph, glyph_index, load_flags ); - if ( !error ) + if ( FT_ERR_EQ( error, Missing_Bitmap ) ) + { + /* the bitmap strike is incomplete and misses the requested glyph; */ + /* if we have a bitmap-only font, return an empty glyph */ + if ( !FT_IS_SCALABLE( glyph->face ) ) + { + TT_Face face = (TT_Face)glyph->face; + + FT_Short left_bearing = 0; + FT_Short top_bearing = 0; + + FT_UShort advance_width = 0; + FT_UShort advance_height = 0; + + + /* to return an empty glyph, however, we need metrics data */ + /* from the `hmtx' (or `vmtx') table; the assumption is that */ + /* empty glyphs are missing intentionally, representing */ + /* whitespace - not having at least horizontal metrics is */ + /* thus considered an error */ + if ( !face->horz_metrics_size ) + return error; + + /* we now construct an empty bitmap glyph */ + TT_Get_HMetrics( face, glyph_index, + &left_bearing, + &advance_width ); + TT_Get_VMetrics( face, glyph_index, + 0, + &top_bearing, + &advance_height ); + + glyph->outline.n_points = 0; + glyph->outline.n_contours = 0; + + glyph->metrics.width = 0; + glyph->metrics.height = 0; + + glyph->metrics.horiBearingX = FT_MulFix( left_bearing, x_scale ); + glyph->metrics.horiBearingY = 0; + glyph->metrics.horiAdvance = FT_MulFix( advance_width, x_scale ); + + glyph->metrics.vertBearingX = 0; + glyph->metrics.vertBearingY = FT_MulFix( top_bearing, y_scale ); + glyph->metrics.vertAdvance = FT_MulFix( advance_height, y_scale ); + + glyph->format = FT_GLYPH_FORMAT_BITMAP; + glyph->bitmap.pixel_mode = FT_PIXEL_MODE_MONO; + + glyph->bitmap_left = 0; + glyph->bitmap_top = 0; + + return FT_Err_Ok; + } + } + else if ( error ) + { + /* return error if font is not scalable */ + if ( !FT_IS_SCALABLE( glyph->face ) ) + return error; + } + else { 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 ); + tt_loader_done( &loader ); glyph->linearHoriAdvance = loader.linear; 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 ); + glyph->metrics.horiAdvance = FT_MulFix( glyph->linearHoriAdvance, + x_scale ); if ( !glyph->metrics.vertAdvance && glyph->linearVertAdvance ) - glyph->metrics.vertAdvance = - FT_MulFix( glyph->linearVertAdvance, - size->root.metrics.y_scale ); + glyph->metrics.vertAdvance = FT_MulFix( glyph->linearVertAdvance, + y_scale ); } return FT_Err_Ok; @@ -2476,14 +2804,20 @@ /* if FT_LOAD_NO_SCALE is not set, `ttmetrics' must be valid */ if ( !( load_flags & FT_LOAD_NO_SCALE ) && !size->ttmetrics.valid ) - return FT_THROW( Invalid_Size_Handle ); + { + error = FT_THROW( Invalid_Size_Handle ); + goto Exit; + } if ( load_flags & FT_LOAD_SBITS_ONLY ) - return FT_THROW( Invalid_Argument ); + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } error = tt_loader_init( &loader, size, glyph, load_flags, FALSE ); if ( error ) - return error; + goto Exit; glyph->format = FT_GLYPH_FORMAT_OUTLINE; glyph->num_subglyphs = 0; @@ -2548,14 +2882,23 @@ error = compute_glyph_metrics( &loader, glyph_index ); } + tt_loader_done( &loader ); + /* Set the `high precision' bit flag. */ /* This is _critical_ to get correct output for monochrome */ /* TrueType glyphs at all sizes using the bytecode interpreter. */ /* */ if ( !( load_flags & FT_LOAD_NO_SCALE ) && - size->root.metrics.y_ppem < 24 ) + size->metrics->y_ppem < 24 ) glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; + Exit: +#ifdef FT_DEBUG_LEVEL_TRACE + if ( error ) + FT_TRACE1(( " failed (error code 0x%x)\n", + error )); +#endif + return error; } diff --git a/src/3rdparty/freetype/src/truetype/ttgload.h b/src/3rdparty/freetype/src/truetype/ttgload.h index 8e3255e106..d237cfd284 100644 --- a/src/3rdparty/freetype/src/truetype/ttgload.h +++ b/src/3rdparty/freetype/src/truetype/ttgload.h @@ -4,7 +4,7 @@ /* */ /* TrueType Glyph Loader (specification). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2018 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,8 +16,8 @@ /***************************************************************************/ -#ifndef __TTGLOAD_H__ -#define __TTGLOAD_H__ +#ifndef TTGLOAD_H_ +#define TTGLOAD_H_ #include <ft2build.h> @@ -56,7 +56,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __TTGLOAD_H__ */ +#endif /* TTGLOAD_H_ */ /* END */ diff --git a/src/3rdparty/freetype/src/truetype/ttgxvar.c b/src/3rdparty/freetype/src/truetype/ttgxvar.c index dd9e250c94..29ab2a4efd 100644 --- a/src/3rdparty/freetype/src/truetype/ttgxvar.c +++ b/src/3rdparty/freetype/src/truetype/ttgxvar.c @@ -4,7 +4,7 @@ /* */ /* TrueType GX Font Variation loader */ /* */ -/* Copyright 2004-2015 by */ +/* Copyright 2004-2018 by */ /* David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -22,10 +22,6 @@ /* */ /* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6[fgca]var.html */ /* */ - /* The documentation for `fvar' is inconsistent. At one point it says */ - /* that `countSizePairs' should be 3, at another point 2. It should */ - /* be 2. */ - /* */ /* The documentation for `gvar' is not intelligible; `cvar' refers you */ /* to `gvar' and is thus also incomprehensible. */ /* */ @@ -49,7 +45,9 @@ #include FT_INTERNAL_STREAM_H #include FT_INTERNAL_SFNT_H #include FT_TRUETYPE_TAGS_H +#include FT_TRUETYPE_IDS_H #include FT_MULTIPLE_MASTERS_H +#include FT_LIST_H #include "ttpload.h" #include "ttgxvar.h" @@ -62,8 +60,11 @@ #define FT_Stream_FTell( stream ) \ (FT_ULong)( (stream)->cursor - (stream)->base ) -#define FT_Stream_SeekSet( stream, off ) \ - ( (stream)->cursor = (stream)->base + (off) ) +#define FT_Stream_SeekSet( stream, off ) \ + (stream)->cursor = \ + ( (off) < (FT_ULong)( (stream)->limit - (stream)->base ) ) \ + ? (stream)->base + (off) \ + : (stream)->limit /*************************************************************************/ @@ -112,6 +113,8 @@ /* <Input> */ /* stream :: The data stream. */ /* */ + /* size :: The size of the table holding the data. */ + /* */ /* <Output> */ /* point_cnt :: The number of points read. A zero value means that */ /* all points in the glyph will be affected, without */ @@ -123,6 +126,7 @@ /* */ static FT_UShort* ft_var_readpackedpoints( FT_Stream stream, + FT_ULong size, FT_UInt *point_cnt ) { FT_UShort *points = NULL; @@ -149,48 +153,55 @@ n |= FT_GET_BYTE(); } - if ( FT_NEW_ARRAY( points, n ) ) + if ( n > size ) + { + FT_TRACE1(( "ft_var_readpackedpoints: number of points too large\n" )); + return NULL; + } + + /* in the nested loops below we increase `i' twice; */ + /* it is faster to simply allocate one more slot */ + /* than to add another test within the loop */ + if ( FT_NEW_ARRAY( points, n + 1 ) ) return NULL; *point_cnt = n; - i = 0; + first = 0; + i = 0; while ( i < n ) { runcnt = FT_GET_BYTE(); if ( runcnt & GX_PT_POINTS_ARE_WORDS ) { runcnt &= GX_PT_POINT_RUN_COUNT_MASK; - first = FT_GET_USHORT(); + first += FT_GET_USHORT(); points[i++] = first; - if ( runcnt < 1 || i + runcnt > n ) - goto Exit; - /* first point not included in run count */ for ( j = 0; j < runcnt; j++ ) { first += FT_GET_USHORT(); points[i++] = first; + if ( i >= n ) + break; } } else { - first = FT_GET_BYTE(); + first += FT_GET_BYTE(); points[i++] = first; - if ( runcnt < 1 || i + runcnt > n ) - goto Exit; - for ( j = 0; j < runcnt; j++ ) { first += FT_GET_BYTE(); points[i++] = first; + if ( i >= n ) + break; } } } - Exit: return points; } @@ -212,6 +223,8 @@ /* <Input> */ /* stream :: The data stream. */ /* */ + /* size :: The size of the table holding the data. */ + /* */ /* delta_cnt :: The number of deltas to be read. */ /* */ /* <Return> */ @@ -222,6 +235,7 @@ /* */ static FT_Short* ft_var_readpackeddeltas( FT_Stream stream, + FT_ULong size, FT_UInt delta_cnt ) { FT_Short *deltas = NULL; @@ -233,6 +247,12 @@ FT_UNUSED( error ); + if ( delta_cnt > size ) + { + FT_TRACE1(( "ft_var_readpackeddeltas: number of points too large\n" )); + return NULL; + } + if ( FT_NEW_ARRAY( deltas, delta_cnt ) ) return NULL; @@ -303,7 +323,7 @@ FT_TRACE2(( "AVAR " )); - blend->avar_checked = TRUE; + blend->avar_loaded = TRUE; error = face->goto_table( face, TTAG_avar, stream, &table_len ); if ( error ) { @@ -327,7 +347,7 @@ if ( axisCount != (FT_Long)blend->mmvar->num_axis ) { - FT_TRACE2(( "ft_var_load_avar: number of axes in `avar' and `cvar'\n" + FT_TRACE2(( "ft_var_load_avar: number of axes in `avar' and `fvar'\n" " table are different\n" )); goto Exit; } @@ -341,7 +361,8 @@ FT_TRACE5(( " axis %d:\n", i )); segment->pairCount = FT_GET_USHORT(); - if ( FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) ) + if ( (FT_ULong)segment->pairCount * 4 > table_len || + FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) ) { /* Failure. Free everything we have done so far. We must do */ /* it right now since loading the `avar' table is optional. */ @@ -360,7 +381,7 @@ segment->correspondence[j].fromCoord = FT_GET_SHORT() * 4; segment->correspondence[j].toCoord = FT_GET_SHORT() * 4; - FT_TRACE5(( " mapping %.4f to %.4f\n", + FT_TRACE5(( " mapping %.5f to %.5f\n", segment->correspondence[j].fromCoord / 65536.0, segment->correspondence[j].toCoord / 65536.0 )); } @@ -373,6 +394,999 @@ } + /* some macros we need */ +#define FT_FIXED_ONE ( (FT_Fixed)0x10000 ) + +#define FT_fdot14ToFixed( x ) \ + ( (FT_Fixed)( (FT_ULong)(x) << 2 ) ) +#define FT_intToFixed( i ) \ + ( (FT_Fixed)( (FT_ULong)(i) << 16 ) ) +#define FT_fixedToInt( x ) \ + ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) ) + + + static FT_Error + ft_var_load_item_variation_store( TT_Face face, + FT_ULong offset, + GX_ItemVarStore itemStore ) + { + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + + FT_Error error; + FT_UShort format; + FT_ULong region_offset; + FT_UInt i, j, k; + FT_UInt shortDeltaCount; + + GX_Blend blend = face->blend; + GX_ItemVarData varData; + + FT_ULong* dataOffsetArray = NULL; + + + if ( FT_STREAM_SEEK( offset ) || + FT_READ_USHORT( format ) ) + goto Exit; + + if ( format != 1 ) + { + FT_TRACE2(( "ft_var_load_item_variation_store: bad store format %d\n", + format )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* read top level fields */ + if ( FT_READ_ULONG( region_offset ) || + FT_READ_USHORT( itemStore->dataCount ) ) + goto Exit; + + /* we need at least one entry in `itemStore->varData' */ + if ( !itemStore->dataCount ) + { + FT_TRACE2(( "ft_var_load_item_variation_store: missing varData\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* make temporary copy of item variation data offsets; */ + /* we will parse region list first, then come back */ + if ( FT_NEW_ARRAY( dataOffsetArray, itemStore->dataCount ) ) + goto Exit; + + for ( i = 0; i < itemStore->dataCount; i++ ) + { + if ( FT_READ_ULONG( dataOffsetArray[i] ) ) + goto Exit; + } + + /* parse array of region records (region list) */ + if ( FT_STREAM_SEEK( offset + region_offset ) ) + goto Exit; + + if ( FT_READ_USHORT( itemStore->axisCount ) || + FT_READ_USHORT( itemStore->regionCount ) ) + goto Exit; + + if ( itemStore->axisCount != (FT_Long)blend->mmvar->num_axis ) + { + FT_TRACE2(( "ft_var_load_item_variation_store:" + " number of axes in item variation store\n" + " " + " and `fvar' table are different\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( FT_NEW_ARRAY( itemStore->varRegionList, itemStore->regionCount ) ) + goto Exit; + + for ( i = 0; i < itemStore->regionCount; i++ ) + { + GX_AxisCoords axisCoords; + + + if ( FT_NEW_ARRAY( itemStore->varRegionList[i].axisList, + itemStore->axisCount ) ) + goto Exit; + + axisCoords = itemStore->varRegionList[i].axisList; + + for ( j = 0; j < itemStore->axisCount; j++ ) + { + FT_Short start, peak, end; + + + if ( FT_READ_SHORT( start ) || + FT_READ_SHORT( peak ) || + FT_READ_SHORT( end ) ) + goto Exit; + + axisCoords[j].startCoord = FT_fdot14ToFixed( start ); + axisCoords[j].peakCoord = FT_fdot14ToFixed( peak ); + axisCoords[j].endCoord = FT_fdot14ToFixed( end ); + } + } + + /* end of region list parse */ + + /* use dataOffsetArray now to parse varData items */ + if ( FT_NEW_ARRAY( itemStore->varData, itemStore->dataCount ) ) + goto Exit; + + for ( i = 0; i < itemStore->dataCount; i++ ) + { + varData = &itemStore->varData[i]; + + if ( FT_STREAM_SEEK( offset + dataOffsetArray[i] ) ) + goto Exit; + + if ( FT_READ_USHORT( varData->itemCount ) || + FT_READ_USHORT( shortDeltaCount ) || + FT_READ_USHORT( varData->regionIdxCount ) ) + goto Exit; + + /* check some data consistency */ + if ( shortDeltaCount > varData->regionIdxCount ) + { + FT_TRACE2(( "bad short count %d or region count %d\n", + shortDeltaCount, + varData->regionIdxCount )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( varData->regionIdxCount > itemStore->regionCount ) + { + FT_TRACE2(( "inconsistent regionCount %d in varData[%d]\n", + varData->regionIdxCount, + i )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* parse region indices */ + if ( FT_NEW_ARRAY( varData->regionIndices, + varData->regionIdxCount ) ) + goto Exit; + + for ( j = 0; j < varData->regionIdxCount; j++ ) + { + if ( FT_READ_USHORT( varData->regionIndices[j] ) ) + goto Exit; + + if ( varData->regionIndices[j] >= itemStore->regionCount ) + { + FT_TRACE2(( "bad region index %d\n", + varData->regionIndices[j] )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + + /* Parse delta set. */ + /* */ + /* On input, deltas are (shortDeltaCount + regionIdxCount) bytes */ + /* each; on output, deltas are expanded to `regionIdxCount' shorts */ + /* each. */ + if ( FT_NEW_ARRAY( varData->deltaSet, + varData->regionIdxCount * varData->itemCount ) ) + goto Exit; + + /* the delta set is stored as a 2-dimensional array of shorts; */ + /* sign-extend signed bytes to signed shorts */ + for ( j = 0; j < varData->itemCount * varData->regionIdxCount; ) + { + for ( k = 0; k < shortDeltaCount; k++, j++ ) + { + /* read the short deltas */ + FT_Short delta; + + + if ( FT_READ_SHORT( delta ) ) + goto Exit; + + varData->deltaSet[j] = delta; + } + + for ( ; k < varData->regionIdxCount; k++, j++ ) + { + /* read the (signed) byte deltas */ + FT_Char delta; + + + if ( FT_READ_CHAR( delta ) ) + goto Exit; + + varData->deltaSet[j] = delta; + } + } + } + + Exit: + FT_FREE( dataOffsetArray ); + + return error; + } + + + static FT_Error + ft_var_load_delta_set_index_mapping( TT_Face face, + FT_ULong offset, + GX_DeltaSetIdxMap map, + GX_ItemVarStore itemStore ) + { + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + + FT_Error error; + + FT_UShort format; + FT_UInt entrySize; + FT_UInt innerBitCount; + FT_UInt innerIndexMask; + FT_UInt i, j; + + + if ( FT_STREAM_SEEK( offset ) || + FT_READ_USHORT( format ) || + FT_READ_USHORT( map->mapCount ) ) + goto Exit; + + if ( format & 0xFFC0 ) + { + FT_TRACE2(( "bad map format %d\n", format )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* bytes per entry: 1, 2, 3, or 4 */ + entrySize = ( ( format & 0x0030 ) >> 4 ) + 1; + innerBitCount = ( format & 0x000F ) + 1; + innerIndexMask = ( 1 << innerBitCount ) - 1; + + if ( FT_NEW_ARRAY( map->innerIndex, map->mapCount ) ) + goto Exit; + + if ( FT_NEW_ARRAY( map->outerIndex, map->mapCount ) ) + goto Exit; + + for ( i = 0; i < map->mapCount; i++ ) + { + FT_UInt mapData = 0; + FT_UInt outerIndex, innerIndex; + + + /* read map data one unsigned byte at a time, big endian */ + for ( j = 0; j < entrySize; j++ ) + { + FT_Byte data; + + + if ( FT_READ_BYTE( data ) ) + goto Exit; + + mapData = ( mapData << 8 ) | data; + } + + outerIndex = mapData >> innerBitCount; + + if ( outerIndex >= itemStore->dataCount ) + { + FT_TRACE2(( "outerIndex[%d] == %d out of range\n", + i, + outerIndex )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + map->outerIndex[i] = outerIndex; + + innerIndex = mapData & innerIndexMask; + + if ( innerIndex >= itemStore->varData[outerIndex].itemCount ) + { + FT_TRACE2(( "innerIndex[%d] == %d out of range\n", + i, + innerIndex )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + map->innerIndex[i] = innerIndex; + } + + Exit: + return error; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* ft_var_load_hvvar */ + /* */ + /* <Description> */ + /* If `vertical' is zero, parse the `HVAR' table and set */ + /* `blend->hvar_loaded' to TRUE. On success, `blend->hvar_checked' */ + /* is set to TRUE. */ + /* */ + /* If `vertical' is not zero, parse the `VVAR' table and set */ + /* `blend->vvar_loaded' to TRUE. On success, `blend->vvar_checked' */ + /* is set to TRUE. */ + /* */ + /* Some memory may remain allocated on error; it is always freed in */ + /* `tt_done_blend', however. */ + /* */ + /* <InOut> */ + /* face :: The font face. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + static FT_Error + ft_var_load_hvvar( TT_Face face, + FT_Bool vertical ) + { + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + + GX_Blend blend = face->blend; + + GX_HVVarTable table; + + FT_Error error; + FT_UShort majorVersion; + FT_ULong table_len; + FT_ULong table_offset; + FT_ULong store_offset; + FT_ULong widthMap_offset; + + + if ( vertical ) + { + blend->vvar_loaded = TRUE; + + FT_TRACE2(( "VVAR " )); + + error = face->goto_table( face, TTAG_VVAR, stream, &table_len ); + } + else + { + blend->hvar_loaded = TRUE; + + FT_TRACE2(( "HVAR " )); + + error = face->goto_table( face, TTAG_HVAR, stream, &table_len ); + } + + if ( error ) + { + FT_TRACE2(( "is missing\n" )); + goto Exit; + } + + table_offset = FT_STREAM_POS(); + + /* skip minor version */ + if ( FT_READ_USHORT( majorVersion ) || + FT_STREAM_SKIP( 2 ) ) + goto Exit; + + if ( majorVersion != 1 ) + { + FT_TRACE2(( "bad table version %d\n", majorVersion )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( FT_READ_ULONG( store_offset ) || + FT_READ_ULONG( widthMap_offset ) ) + goto Exit; + + if ( vertical ) + { + if ( FT_NEW( blend->vvar_table ) ) + goto Exit; + table = blend->vvar_table; + } + else + { + if ( FT_NEW( blend->hvar_table ) ) + goto Exit; + table = blend->hvar_table; + } + + error = ft_var_load_item_variation_store( + face, + table_offset + store_offset, + &table->itemStore ); + if ( error ) + goto Exit; + + if ( widthMap_offset ) + { + error = ft_var_load_delta_set_index_mapping( + face, + table_offset + widthMap_offset, + &table->widthMap, + &table->itemStore ); + if ( error ) + goto Exit; + } + + FT_TRACE2(( "loaded\n" )); + error = FT_Err_Ok; + + Exit: + if ( !error ) + { + if ( vertical ) + { + blend->vvar_checked = TRUE; + + /* FreeType doesn't provide functions to quickly retrieve */ + /* TSB, BSB, or VORG values; we thus don't have to implement */ + /* support for those three item variation stores. */ + + face->variation_support |= TT_FACE_FLAG_VAR_VADVANCE; + } + else + { + blend->hvar_checked = TRUE; + + /* FreeType doesn't provide functions to quickly retrieve */ + /* LSB or RSB values; we thus don't have to implement */ + /* support for those two item variation stores. */ + + face->variation_support |= TT_FACE_FLAG_VAR_HADVANCE; + } + } + + return error; + } + + + static FT_Int + ft_var_get_item_delta( TT_Face face, + GX_ItemVarStore itemStore, + FT_UInt outerIndex, + FT_UInt innerIndex ) + { + GX_ItemVarData varData; + FT_Short* deltaSet; + + FT_UInt master, j; + FT_Fixed netAdjustment = 0; /* accumulated adjustment */ + FT_Fixed scaledDelta; + FT_Fixed delta; + + + /* See pseudo code from `Font Variations Overview' */ + /* in the OpenType specification. */ + + varData = &itemStore->varData[outerIndex]; + deltaSet = &varData->deltaSet[varData->regionIdxCount * innerIndex]; + + /* outer loop steps through master designs to be blended */ + for ( master = 0; master < varData->regionIdxCount; master++ ) + { + FT_Fixed scalar = FT_FIXED_ONE; + FT_UInt regionIndex = varData->regionIndices[master]; + + GX_AxisCoords axis = itemStore->varRegionList[regionIndex].axisList; + + + /* inner loop steps through axes in this region */ + for ( j = 0; j < itemStore->axisCount; j++, axis++ ) + { + FT_Fixed axisScalar; + + + /* compute the scalar contribution of this axis; */ + /* ignore invalid ranges */ + if ( axis->startCoord > axis->peakCoord || + axis->peakCoord > axis->endCoord ) + axisScalar = FT_FIXED_ONE; + + else if ( axis->startCoord < 0 && + axis->endCoord > 0 && + axis->peakCoord != 0 ) + axisScalar = FT_FIXED_ONE; + + /* peak of 0 means ignore this axis */ + else if ( axis->peakCoord == 0 ) + axisScalar = FT_FIXED_ONE; + + /* ignore this region if coords are out of range */ + else if ( face->blend->normalizedcoords[j] < axis->startCoord || + face->blend->normalizedcoords[j] > axis->endCoord ) + axisScalar = 0; + + /* calculate a proportional factor */ + else + { + if ( face->blend->normalizedcoords[j] == axis->peakCoord ) + axisScalar = FT_FIXED_ONE; + else if ( face->blend->normalizedcoords[j] < axis->peakCoord ) + axisScalar = + FT_DivFix( face->blend->normalizedcoords[j] - axis->startCoord, + axis->peakCoord - axis->startCoord ); + else + axisScalar = + FT_DivFix( axis->endCoord - face->blend->normalizedcoords[j], + axis->endCoord - axis->peakCoord ); + } + + /* take product of all the axis scalars */ + scalar = FT_MulFix( scalar, axisScalar ); + + } /* per-axis loop */ + + /* get the scaled delta for this region */ + delta = FT_intToFixed( deltaSet[master] ); + scaledDelta = FT_MulFix( scalar, delta ); + + /* accumulate the adjustments from each region */ + netAdjustment = netAdjustment + scaledDelta; + + } /* per-region loop */ + + return FT_fixedToInt( netAdjustment ); + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_hvadvance_adjust */ + /* */ + /* <Description> */ + /* Apply `HVAR' advance width or `VVAR' advance height adjustment of */ + /* a given glyph. */ + /* */ + /* <Input> */ + /* gindex :: The glyph index. */ + /* */ + /* vertical :: If set, handle `VVAR' table. */ + /* */ + /* <InOut> */ + /* face :: The font face. */ + /* */ + /* adelta :: Points to width or height value that gets modified. */ + /* */ + static FT_Error + tt_hvadvance_adjust( TT_Face face, + FT_UInt gindex, + FT_Int *avalue, + FT_Bool vertical ) + { + FT_Error error = FT_Err_Ok; + FT_UInt innerIndex, outerIndex; + FT_Int delta; + + GX_HVVarTable table; + + + if ( !face->doblend || !face->blend ) + goto Exit; + + if ( vertical ) + { + if ( !face->blend->vvar_loaded ) + { + /* initialize vvar table */ + face->blend->vvar_error = ft_var_load_hvvar( face, 1 ); + } + + if ( !face->blend->vvar_checked ) + { + error = face->blend->vvar_error; + goto Exit; + } + + table = face->blend->vvar_table; + } + else + { + if ( !face->blend->hvar_loaded ) + { + /* initialize hvar table */ + face->blend->hvar_error = ft_var_load_hvvar( face, 0 ); + } + + if ( !face->blend->hvar_checked ) + { + error = face->blend->hvar_error; + goto Exit; + } + + table = face->blend->hvar_table; + } + + /* advance width or height adjustments are always present in an */ + /* `HVAR' or `VVAR' table; no need to test for this capability */ + + if ( table->widthMap.innerIndex ) + { + FT_UInt idx = gindex; + + + if ( idx >= table->widthMap.mapCount ) + idx = table->widthMap.mapCount - 1; + + /* trust that HVAR parser has checked indices */ + outerIndex = table->widthMap.outerIndex[idx]; + innerIndex = table->widthMap.innerIndex[idx]; + } + else + { + GX_ItemVarData varData; + + + /* no widthMap data */ + outerIndex = 0; + innerIndex = gindex; + + varData = &table->itemStore.varData[outerIndex]; + if ( gindex >= varData->itemCount ) + { + FT_TRACE2(( "gindex %d out of range\n", gindex )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + } + + delta = ft_var_get_item_delta( face, + &table->itemStore, + outerIndex, + innerIndex ); + + FT_TRACE5(( "%s value %d adjusted by %d unit%s (%s)\n", + vertical ? "vertical height" : "horizontal width", + *avalue, + delta, + delta == 1 ? "" : "s", + vertical ? "VVAR" : "HVAR" )); + + *avalue += delta; + + Exit: + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_hadvance_adjust( TT_Face face, + FT_UInt gindex, + FT_Int *avalue ) + { + return tt_hvadvance_adjust( face, gindex, avalue, 0 ); + } + + + FT_LOCAL_DEF( FT_Error ) + tt_vadvance_adjust( TT_Face face, + FT_UInt gindex, + FT_Int *avalue ) + { + return tt_hvadvance_adjust( face, gindex, avalue, 1 ); + } + + +#define GX_VALUE_SIZE 8 + + /* all values are FT_Short or FT_UShort entities; */ + /* we treat them consistently as FT_Short */ +#define GX_VALUE_CASE( tag, dflt ) \ + case MVAR_TAG_ ## tag : \ + p = (FT_Short*)&face->dflt; \ + break + +#define GX_GASP_CASE( idx ) \ + case MVAR_TAG_GASP_ ## idx : \ + if ( idx < face->gasp.numRanges - 1 ) \ + p = (FT_Short*)&face->gasp.gaspRanges[idx].maxPPEM; \ + else \ + p = NULL; \ + break + + + static FT_Short* + ft_var_get_value_pointer( TT_Face face, + FT_ULong mvar_tag ) + { + FT_Short* p; + + + switch ( mvar_tag ) + { + GX_GASP_CASE( 0 ); + GX_GASP_CASE( 1 ); + GX_GASP_CASE( 2 ); + GX_GASP_CASE( 3 ); + GX_GASP_CASE( 4 ); + GX_GASP_CASE( 5 ); + GX_GASP_CASE( 6 ); + GX_GASP_CASE( 7 ); + GX_GASP_CASE( 8 ); + GX_GASP_CASE( 9 ); + + GX_VALUE_CASE( CPHT, os2.sCapHeight ); + GX_VALUE_CASE( HASC, os2.sTypoAscender ); + GX_VALUE_CASE( HCLA, os2.usWinAscent ); + GX_VALUE_CASE( HCLD, os2.usWinDescent ); + GX_VALUE_CASE( HCOF, horizontal.caret_Offset ); + GX_VALUE_CASE( HCRN, horizontal.caret_Slope_Run ); + GX_VALUE_CASE( HCRS, horizontal.caret_Slope_Rise ); + GX_VALUE_CASE( HDSC, os2.sTypoDescender ); + GX_VALUE_CASE( HLGP, os2.sTypoLineGap ); + GX_VALUE_CASE( SBXO, os2.ySubscriptXOffset); + GX_VALUE_CASE( SBXS, os2.ySubscriptXSize ); + GX_VALUE_CASE( SBYO, os2.ySubscriptYOffset ); + GX_VALUE_CASE( SBYS, os2.ySubscriptYSize ); + GX_VALUE_CASE( SPXO, os2.ySuperscriptXOffset ); + GX_VALUE_CASE( SPXS, os2.ySuperscriptXSize ); + GX_VALUE_CASE( SPYO, os2.ySuperscriptYOffset ); + GX_VALUE_CASE( SPYS, os2.ySuperscriptYSize ); + GX_VALUE_CASE( STRO, os2.yStrikeoutPosition ); + GX_VALUE_CASE( STRS, os2.yStrikeoutSize ); + GX_VALUE_CASE( UNDO, postscript.underlinePosition ); + GX_VALUE_CASE( UNDS, postscript.underlineThickness ); + GX_VALUE_CASE( VASC, vertical.Ascender ); + GX_VALUE_CASE( VCOF, vertical.caret_Offset ); + GX_VALUE_CASE( VCRN, vertical.caret_Slope_Run ); + GX_VALUE_CASE( VCRS, vertical.caret_Slope_Rise ); + GX_VALUE_CASE( VDSC, vertical.Descender ); + GX_VALUE_CASE( VLGP, vertical.Line_Gap ); + GX_VALUE_CASE( XHGT, os2.sxHeight ); + + default: + /* ignore unknown tag */ + p = NULL; + } + + return p; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* ft_var_load_mvar */ + /* */ + /* <Description> */ + /* Parse the `MVAR' table. */ + /* */ + /* Some memory may remain allocated on error; it is always freed in */ + /* `tt_done_blend', however. */ + /* */ + /* <InOut> */ + /* face :: The font face. */ + /* */ + static void + ft_var_load_mvar( TT_Face face ) + { + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + + GX_Blend blend = face->blend; + GX_ItemVarStore itemStore; + GX_Value value, limit; + + FT_Error error; + FT_UShort majorVersion; + FT_ULong table_len; + FT_ULong table_offset; + FT_UShort store_offset; + FT_ULong records_offset; + + + FT_TRACE2(( "MVAR " )); + + error = face->goto_table( face, TTAG_MVAR, stream, &table_len ); + if ( error ) + { + FT_TRACE2(( "is missing\n" )); + return; + } + + table_offset = FT_STREAM_POS(); + + /* skip minor version */ + if ( FT_READ_USHORT( majorVersion ) || + FT_STREAM_SKIP( 2 ) ) + return; + + if ( majorVersion != 1 ) + { + FT_TRACE2(( "bad table version %d\n", majorVersion )); + return; + } + + if ( FT_NEW( blend->mvar_table ) ) + return; + + /* skip reserved entry and value record size */ + if ( FT_STREAM_SKIP( 4 ) || + FT_READ_USHORT( blend->mvar_table->valueCount ) || + FT_READ_USHORT( store_offset ) ) + return; + + records_offset = FT_STREAM_POS(); + + error = ft_var_load_item_variation_store( + face, + table_offset + store_offset, + &blend->mvar_table->itemStore ); + if ( error ) + return; + + if ( FT_NEW_ARRAY( blend->mvar_table->values, + blend->mvar_table->valueCount ) ) + return; + + if ( FT_STREAM_SEEK( records_offset ) || + FT_FRAME_ENTER( blend->mvar_table->valueCount * GX_VALUE_SIZE ) ) + return; + + value = blend->mvar_table->values; + limit = value + blend->mvar_table->valueCount; + itemStore = &blend->mvar_table->itemStore; + + for ( ; value < limit; value++ ) + { + value->tag = FT_GET_ULONG(); + value->outerIndex = FT_GET_USHORT(); + value->innerIndex = FT_GET_USHORT(); + + if ( value->outerIndex >= itemStore->dataCount || + value->innerIndex >= itemStore->varData[value->outerIndex] + .itemCount ) + { + error = FT_THROW( Invalid_Table ); + break; + } + } + + FT_FRAME_EXIT(); + + if ( error ) + return; + + FT_TRACE2(( "loaded\n" )); + + value = blend->mvar_table->values; + limit = value + blend->mvar_table->valueCount; + + /* save original values of the data MVAR is going to modify */ + for ( ; value < limit; value++ ) + { + FT_Short* p = ft_var_get_value_pointer( face, value->tag ); + + + if ( p ) + value->unmodified = *p; +#ifdef FT_DEBUG_LEVEL_TRACE + else + FT_TRACE1(( "ft_var_load_mvar: Ignoring unknown tag `%c%c%c%c'\n", + (FT_Char)( value->tag >> 24 ), + (FT_Char)( value->tag >> 16 ), + (FT_Char)( value->tag >> 8 ), + (FT_Char)( value->tag ) )); +#endif + } + + face->variation_support |= TT_FACE_FLAG_VAR_MVAR; + } + + + static FT_Error + tt_size_reset_iterator( FT_ListNode node, + void* user ) + { + TT_Size size = (TT_Size)node->data; + + FT_UNUSED( user ); + + + tt_size_reset( size, 1 ); + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* tt_apply_mvar */ + /* */ + /* <Description> */ + /* Apply `MVAR' table adjustments. */ + /* */ + /* <InOut> */ + /* face :: The font face. */ + /* */ + FT_LOCAL_DEF( void ) + tt_apply_mvar( TT_Face face ) + { + GX_Blend blend = face->blend; + GX_Value value, limit; + + + if ( !( face->variation_support & TT_FACE_FLAG_VAR_MVAR ) ) + return; + + value = blend->mvar_table->values; + limit = value + blend->mvar_table->valueCount; + + for ( ; value < limit; value++ ) + { + FT_Short* p = ft_var_get_value_pointer( face, value->tag ); + FT_Int delta; + + + delta = ft_var_get_item_delta( face, + &blend->mvar_table->itemStore, + value->outerIndex, + value->innerIndex ); + + if ( p ) + { + FT_TRACE5(( "value %c%c%c%c (%d unit%s) adjusted by %d unit%s (MVAR)\n", + (FT_Char)( value->tag >> 24 ), + (FT_Char)( value->tag >> 16 ), + (FT_Char)( value->tag >> 8 ), + (FT_Char)( value->tag ), + value->unmodified, + value->unmodified == 1 ? "" : "s", + delta, + delta == 1 ? "" : "s" )); + + /* since we handle both signed and unsigned values as FT_Short, */ + /* ensure proper overflow arithmetic */ + *p = (FT_Short)( value->unmodified + (FT_Short)delta ); + } + } + + /* adjust all derived values */ + { + FT_Face root = &face->root; + + + if ( face->os2.version != 0xFFFFU ) + { + if ( face->os2.sTypoAscender || face->os2.sTypoDescender ) + { + root->ascender = face->os2.sTypoAscender; + root->descender = face->os2.sTypoDescender; + + root->height = root->ascender - root->descender + + face->os2.sTypoLineGap; + } + else + { + root->ascender = (FT_Short)face->os2.usWinAscent; + root->descender = -(FT_Short)face->os2.usWinDescent; + + root->height = root->ascender - root->descender; + } + } + + root->underline_position = face->postscript.underlinePosition - + face->postscript.underlineThickness / 2; + root->underline_thickness = face->postscript.underlineThickness; + + /* iterate over all FT_Size objects and call `tt_size_reset' */ + /* to propagate the metrics changes */ + FT_List_Iterate( &root->sizes_list, + tt_size_reset_iterator, + NULL ); + } + } + + typedef struct GX_GVar_Head_ { FT_Long version; @@ -434,10 +1448,10 @@ FT_TRACE2(( "GVAR " )); - if ( ( error = face->goto_table( face, - TTAG_gvar, - stream, - &table_len ) ) != 0 ) + if ( FT_SET_ERROR( face->goto_table( face, + TTAG_gvar, + stream, + &table_len ) ) ) { FT_TRACE2(( "is missing\n" )); goto Exit; @@ -447,10 +1461,6 @@ if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) ) goto Exit; - blend->tuplecount = gvar_head.globalCoordCount; - blend->gv_glyphcnt = gvar_head.glyphCount; - offsetToData = gvar_start + gvar_head.offsetToData; - if ( gvar_head.version != 0x00010000L ) { FT_TRACE1(( "bad table version\n" )); @@ -458,8 +1468,6 @@ goto Exit; } - FT_TRACE2(( "loaded\n" )); - if ( gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis ) { FT_TRACE1(( "ft_var_load_gvar: number of axes in `gvar' and `cvar'\n" @@ -468,8 +1476,36 @@ goto Exit; } - FT_TRACE5(( "gvar: there are %d shared coordinates:\n", - blend->tuplecount )); + /* rough sanity check, ignoring offsets */ + if ( (FT_ULong)gvar_head.globalCoordCount * gvar_head.axisCount > + table_len / 2 ) + { + FT_TRACE1(( "ft_var_load_gvar:" + " invalid number of global coordinates\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* rough sanity check: offsets can be either 2 or 4 bytes */ + if ( (FT_ULong)gvar_head.glyphCount * + ( ( gvar_head.flags & 1 ) ? 4 : 2 ) > table_len ) + { + FT_TRACE1(( "ft_var_load_gvar: invalid number of glyphs\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + FT_TRACE2(( "loaded\n" )); + + blend->gvar_size = table_len; + blend->tuplecount = gvar_head.globalCoordCount; + blend->gv_glyphcnt = gvar_head.glyphCount; + offsetToData = gvar_start + gvar_head.offsetToData; + + FT_TRACE5(( "gvar: there %s %d shared coordinate%s:\n", + blend->tuplecount == 1 ? "is" : "are", + blend->tuplecount, + blend->tuplecount == 1 ? "" : "s" )); if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) ) goto Exit; @@ -511,11 +1547,11 @@ for ( i = 0; i < blend->tuplecount; i++ ) { FT_TRACE5(( " [ " )); - for ( j = 0 ; j < (FT_UInt)gvar_head.axisCount; j++ ) + for ( j = 0; j < (FT_UInt)gvar_head.axisCount; j++ ) { blend->tuplecoords[i * gvar_head.axisCount + j] = FT_GET_SHORT() * 4; /* convert to FT_Fixed */ - FT_TRACE5(( "%.4f ", + FT_TRACE5(( "%.5f ", blend->tuplecoords[i * gvar_head.axisCount + j] / 65536.0 )); } FT_TRACE5(( "]\n" )); @@ -571,8 +1607,13 @@ for ( i = 0; i < blend->num_axis; i++ ) { - FT_TRACE6(( " axis coordinate %d (%.4f):\n", + FT_TRACE6(( " axis coordinate %d (%.5f):\n", i, blend->normalizedcoords[i] / 65536.0 )); + if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) + FT_TRACE6(( " intermediate coordinates %d (%.5f, %.5f):\n", + i, + im_start_coords[i] / 65536.0, + im_end_coords[i] / 65536.0 )); /* It's not clear why (for intermediate tuples) we don't need */ /* to check against start/end -- the documentation says we don't. */ @@ -585,68 +1626,254 @@ continue; } - else if ( blend->normalizedcoords[i] == 0 ) + if ( blend->normalizedcoords[i] == 0 ) { FT_TRACE6(( " axis coordinate is zero, stop\n" )); apply = 0; break; } - else if ( ( blend->normalizedcoords[i] < 0 && tuple_coords[i] > 0 ) || - ( blend->normalizedcoords[i] > 0 && tuple_coords[i] < 0 ) ) + if ( blend->normalizedcoords[i] == tuple_coords[i] ) { - FT_TRACE6(( " tuple coordinate value %.4f is exceeded, stop\n", + FT_TRACE6(( " tuple coordinate value %.5f fits perfectly\n", tuple_coords[i] / 65536.0 )); - apply = 0; - break; + /* `apply' does not change */ + continue; } - else if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) + if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) { - FT_TRACE6(( " tuple coordinate value %.4f fits\n", - tuple_coords[i] / 65536.0 )); /* not an intermediate tuple */ - apply = FT_MulFix( apply, - blend->normalizedcoords[i] > 0 - ? blend->normalizedcoords[i] - : -blend->normalizedcoords[i] ); - } - else if ( blend->normalizedcoords[i] < im_start_coords[i] || - blend->normalizedcoords[i] > im_end_coords[i] ) + if ( blend->normalizedcoords[i] < FT_MIN( 0, tuple_coords[i] ) || + blend->normalizedcoords[i] > FT_MAX( 0, tuple_coords[i] ) ) + { + FT_TRACE6(( " tuple coordinate value %.5f is exceeded, stop\n", + tuple_coords[i] / 65536.0 )); + apply = 0; + break; + } + + FT_TRACE6(( " tuple coordinate value %.5f fits\n", + tuple_coords[i] / 65536.0 )); + apply = FT_MulDiv( apply, + blend->normalizedcoords[i], + tuple_coords[i] ); + } + else { - FT_TRACE6(( " intermediate tuple range [%.4f;%.4f] is exceeded," - " stop\n", - im_start_coords[i] / 65536.0, - im_end_coords[i] / 65536.0 )); - apply = 0; - break; + /* intermediate tuple */ + + if ( blend->normalizedcoords[i] < im_start_coords[i] || + blend->normalizedcoords[i] > im_end_coords[i] ) + { + FT_TRACE6(( " intermediate tuple range [%.5f;%.5f] is exceeded," + " stop\n", + im_start_coords[i] / 65536.0, + im_end_coords[i] / 65536.0 )); + apply = 0; + break; + } + + else if ( blend->normalizedcoords[i] < tuple_coords[i] ) + { + FT_TRACE6(( " intermediate tuple range [%.5f;%.5f] fits\n", + im_start_coords[i] / 65536.0, + im_end_coords[i] / 65536.0 )); + apply = FT_MulDiv( apply, + blend->normalizedcoords[i] - im_start_coords[i], + tuple_coords[i] - im_start_coords[i] ); + } + + else + { + FT_TRACE6(( " intermediate tuple range [%.5f;%.5f] fits\n", + im_start_coords[i] / 65536.0, + im_end_coords[i] / 65536.0 )); + apply = FT_MulDiv( apply, + im_end_coords[i] - blend->normalizedcoords[i], + im_end_coords[i] - tuple_coords[i] ); + } } + } + + FT_TRACE6(( " apply factor is %.5f\n", apply / 65536.0 )); - else if ( blend->normalizedcoords[i] < tuple_coords[i] ) + return apply; + } + + + /* convert from design coordinates to normalized coordinates */ + + static void + ft_var_to_normalized( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords, + FT_Fixed* normalized ) + { + GX_Blend blend; + FT_MM_Var* mmvar; + FT_UInt i, j; + FT_Var_Axis* a; + GX_AVarSegment av; + + + blend = face->blend; + mmvar = blend->mmvar; + + if ( num_coords > mmvar->num_axis ) + { + FT_TRACE2(( "ft_var_to_normalized:" + " only using first %d of %d coordinates\n", + mmvar->num_axis, num_coords )); + num_coords = mmvar->num_axis; + } + + /* Axis normalization is a two-stage process. First we normalize */ + /* based on the [min,def,max] values for the axis to be [-1,0,1]. */ + /* Then, if there's an `avar' table, we renormalize this range. */ + + a = mmvar->axis; + for ( i = 0; i < num_coords; i++, a++ ) + { + FT_Fixed coord = coords[i]; + + + FT_TRACE5(( " %d: %.5f\n", i, coord / 65536.0 )); + if ( coord > a->maximum || coord < a->minimum ) { - FT_TRACE6(( " intermediate tuple range [%.4f;%.4f] fits\n", - im_start_coords[i] / 65536.0, - im_end_coords[i] / 65536.0 )); - apply = FT_MulDiv( apply, - blend->normalizedcoords[i] - im_start_coords[i], - tuple_coords[i] - im_start_coords[i] ); + FT_TRACE1(( + "ft_var_to_normalized: design coordinate %.5f\n" + " is out of range [%.5f;%.5f]; clamping\n", + coord / 65536.0, + a->minimum / 65536.0, + a->maximum / 65536.0 )); + + if ( coord > a->maximum ) + coord = a->maximum; + else + coord = a->minimum; } + if ( coord < a->def ) + normalized[i] = -FT_DivFix( coord - a->def, + a->minimum - a->def ); + else if ( coord > a->def ) + normalized[i] = FT_DivFix( coord - a->def, + a->maximum - a->def ); else + normalized[i] = 0; + } + + FT_TRACE5(( "\n" )); + + for ( ; i < mmvar->num_axis; i++ ) + normalized[i] = 0; + + if ( blend->avar_segment ) + { + FT_TRACE5(( "normalized design coordinates" + " before applying `avar' data:\n" )); + + av = blend->avar_segment; + for ( i = 0; i < mmvar->num_axis; i++, av++ ) { - FT_TRACE6(( " intermediate tuple range [%.4f;%.4f] fits\n", - im_start_coords[i] / 65536.0, - im_end_coords[i] / 65536.0 )); - apply = FT_MulDiv( apply, - im_end_coords[i] - blend->normalizedcoords[i], - im_end_coords[i] - tuple_coords[i] ); + for ( j = 1; j < (FT_UInt)av->pairCount; j++ ) + { + if ( normalized[i] < av->correspondence[j].fromCoord ) + { + FT_TRACE5(( " %.5f\n", normalized[i] / 65536.0 )); + + normalized[i] = + FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord, + av->correspondence[j].toCoord - + av->correspondence[j - 1].toCoord, + av->correspondence[j].fromCoord - + av->correspondence[j - 1].fromCoord ) + + av->correspondence[j - 1].toCoord; + break; + } + } } } + } - FT_TRACE6(( " apply factor is %.4f\n", apply / 65536.0 )); - return apply; + /* convert from normalized coordinates to design coordinates */ + + static void + ft_var_to_design( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords, + FT_Fixed* design ) + { + GX_Blend blend; + FT_MM_Var* mmvar; + FT_Var_Axis* a; + + FT_UInt i, j, nc; + + + blend = face->blend; + + nc = num_coords; + if ( num_coords > blend->num_axis ) + { + FT_TRACE2(( "ft_var_to_design:" + " only using first %d of %d coordinates\n", + blend->num_axis, num_coords )); + nc = blend->num_axis; + } + + for ( i = 0; i < nc; i++ ) + design[i] = coords[i]; + + for ( ; i < num_coords; i++ ) + design[i] = 0; + + if ( blend->avar_segment ) + { + GX_AVarSegment av = blend->avar_segment; + + + FT_TRACE5(( "design coordinates" + " after removing `avar' distortion:\n" )); + + for ( i = 0; i < nc; i++, av++ ) + { + for ( j = 1; j < (FT_UInt)av->pairCount; j++ ) + { + if ( design[i] < av->correspondence[j].toCoord ) + { + design[i] = + FT_MulDiv( design[i] - av->correspondence[j - 1].toCoord, + av->correspondence[j].fromCoord - + av->correspondence[j - 1].fromCoord, + av->correspondence[j].toCoord - + av->correspondence[j - 1].toCoord ) + + av->correspondence[j - 1].fromCoord; + + FT_TRACE5(( " %.5f\n", design[i] / 65536.0 )); + break; + } + } + } + } + + mmvar = blend->mmvar; + a = mmvar->axis; + + for ( i = 0; i < nc; i++, a++ ) + { + if ( design[i] < 0 ) + design[i] = a->def + FT_MulFix( design[i], + a->def - a->minimum ); + else if ( design[i] > 0 ) + design[i] = a->def + FT_MulFix( design[i], + a->maximum - a->def ); + else + design[i] = a->def; + } } @@ -663,7 +1890,6 @@ { FT_Long version; FT_UShort offsetToData; - FT_UShort countSizePairs; FT_UShort axisCount; FT_UShort axisSize; FT_UShort instanceCount; @@ -691,7 +1917,8 @@ /* */ /* <Description> */ /* Check that the font's `fvar' table is valid, parse it, and return */ - /* those data. */ + /* those data. It also loads (and parses) the `MVAR' table, if */ + /* possible. */ /* */ /* <InOut> */ /* face :: The font face. */ @@ -708,18 +1935,33 @@ TT_Get_MM_Var( TT_Face face, FT_MM_Var* *master ) { - FT_Stream stream = face->root.stream; - FT_Memory memory = face->root.memory; + FT_Stream stream = face->root.stream; + FT_Memory memory = face->root.memory; FT_ULong table_len; - FT_Error error = FT_Err_Ok; - FT_ULong fvar_start; - FT_Int i, j; + FT_Error error = FT_Err_Ok; + FT_ULong fvar_start = 0; + FT_UInt i, j; FT_MM_Var* mmvar = NULL; FT_Fixed* next_coords; + FT_Fixed* nsc; FT_String* next_name; FT_Var_Axis* a; + FT_Fixed* c; FT_Var_Named_Style* ns; GX_FVar_Head fvar_head; + FT_Bool usePsName = 0; + FT_UInt num_instances; + FT_UInt num_axes; + FT_UShort* axis_flags; + + FT_Offset mmvar_size; + FT_Offset axis_flags_size; + FT_Offset axis_size; + FT_Offset namedstyle_size; + FT_Offset next_coords_size; + FT_Offset next_name_size; + + FT_Bool need_init; static const FT_Frame_Field fvar_fields[] = { @@ -728,13 +1970,13 @@ #define FT_STRUCTURE GX_FVar_Head FT_FRAME_START( 16 ), - FT_FRAME_LONG ( version ), - FT_FRAME_USHORT( offsetToData ), - FT_FRAME_USHORT( countSizePairs ), - FT_FRAME_USHORT( axisCount ), - FT_FRAME_USHORT( axisSize ), - FT_FRAME_USHORT( instanceCount ), - FT_FRAME_USHORT( instanceSize ), + FT_FRAME_LONG ( version ), + FT_FRAME_USHORT ( offsetToData ), + FT_FRAME_SKIP_SHORT, + FT_FRAME_USHORT ( axisCount ), + FT_FRAME_USHORT ( axisSize ), + FT_FRAME_USHORT ( instanceCount ), + FT_FRAME_USHORT ( instanceSize ), FT_FRAME_END }; @@ -758,21 +2000,28 @@ /* read the font data and set up the internal representation */ /* if not already done */ - if ( face->blend == NULL ) + need_init = !face->blend; + + if ( need_init ) { FT_TRACE2(( "FVAR " )); /* both `fvar' and `gvar' must be present */ - if ( ( error = face->goto_table( face, TTAG_gvar, - stream, &table_len ) ) != 0 ) + if ( FT_SET_ERROR( face->goto_table( face, TTAG_gvar, + stream, &table_len ) ) ) { - FT_TRACE1(( "\n" - "TT_Get_MM_Var: `gvar' table is missing\n" )); - goto Exit; + /* CFF2 is an alternate to gvar here */ + if ( FT_SET_ERROR( face->goto_table( face, TTAG_CFF2, + stream, &table_len ) ) ) + { + FT_TRACE1(( "\n" + "TT_Get_MM_Var: `gvar' or `CFF2' table is missing\n" )); + goto Exit; + } } - if ( ( error = face->goto_table( face, TTAG_fvar, - stream, &table_len ) ) != 0 ) + if ( FT_SET_ERROR( face->goto_table( face, TTAG_fvar, + stream, &table_len ) ) ) { FT_TRACE1(( "is missing\n" )); goto Exit; @@ -780,45 +2029,67 @@ fvar_start = FT_STREAM_POS( ); + /* the validity of the `fvar' header data was already checked */ + /* in function `sfnt_init_face' */ if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) ) goto Exit; - if ( fvar_head.version != (FT_Long)0x00010000L || -#if 0 - /* fonts like `JamRegular.ttf' have an incorrect value for */ - /* `countSizePairs'; since value 2 is hard-coded in `fvar' */ - /* version 1.0, we simply ignore it */ - fvar_head.countSizePairs != 2 || -#endif - fvar_head.axisSize != 20 || - /* axisCount limit implied by 16-bit instanceSize */ - fvar_head.axisCount > 0x3FFE || - fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount || - /* instanceCount limit implied by limited range of name IDs */ - fvar_head.instanceCount > 0x7EFF || - fvar_head.offsetToData + fvar_head.axisCount * 20U + - fvar_head.instanceCount * fvar_head.instanceSize > table_len ) - { - FT_TRACE1(( "\n" - "TT_Get_MM_Var: invalid `fvar' header\n" )); - error = FT_THROW( Invalid_Table ); - goto Exit; - } + usePsName = FT_BOOL( fvar_head.instanceSize == + 6 + 4 * fvar_head.axisCount ); FT_TRACE2(( "loaded\n" )); - FT_TRACE5(( "number of GX style axes: %d\n", fvar_head.axisCount )); + FT_TRACE5(( "%d variation ax%s\n", + fvar_head.axisCount, + fvar_head.axisCount == 1 ? "is" : "es" )); if ( FT_NEW( face->blend ) ) goto Exit; - /* cannot overflow 32-bit arithmetic because of limits above */ - face->blend->mmvar_len = - sizeof ( FT_MM_Var ) + - fvar_head.axisCount * sizeof ( FT_Var_Axis ) + - fvar_head.instanceCount * sizeof ( FT_Var_Named_Style ) + - fvar_head.instanceCount * fvar_head.axisCount * sizeof ( FT_Fixed ) + - 5 * fvar_head.axisCount; + num_axes = fvar_head.axisCount; + face->blend->num_axis = num_axes; + } + else + num_axes = face->blend->num_axis; + + /* `num_instances' holds the number of all named instances, */ + /* including the default instance which might be missing */ + /* in fvar's table of named instances */ + num_instances = (FT_UInt)face->root.style_flags >> 16; + + /* prepare storage area for MM data; this cannot overflow */ + /* 32-bit arithmetic because of the size limits used in the */ + /* `fvar' table validity check in `sfnt_init_face' */ + + /* the various `*_size' variables, which we also use as */ + /* offsets into the `mmlen' array, must be multiples of the */ + /* pointer size (except the last one); without such an */ + /* alignment there might be runtime errors due to */ + /* misaligned addresses */ +#undef ALIGN_SIZE +#define ALIGN_SIZE( n ) \ + ( ( (n) + sizeof (void*) - 1 ) & ~( sizeof (void*) - 1 ) ) + + mmvar_size = ALIGN_SIZE( sizeof ( FT_MM_Var ) ); + axis_flags_size = ALIGN_SIZE( num_axes * + sizeof ( FT_UShort ) ); + axis_size = ALIGN_SIZE( num_axes * + sizeof ( FT_Var_Axis ) ); + namedstyle_size = ALIGN_SIZE( num_instances * + sizeof ( FT_Var_Named_Style ) ); + next_coords_size = ALIGN_SIZE( num_instances * + num_axes * + sizeof ( FT_Fixed ) ); + next_name_size = num_axes * 5; + + if ( need_init ) + { + face->blend->mmvar_len = mmvar_size + + axis_flags_size + + axis_size + + namedstyle_size + + next_coords_size + + next_name_size; if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) goto Exit; @@ -828,28 +2099,33 @@ /* the data gets filled in later on */ mmvar->num_axis = - fvar_head.axisCount; + num_axes; mmvar->num_designs = ~0U; /* meaningless in this context; each glyph */ /* may have a different number of designs */ /* (or tuples, as called by Apple) */ mmvar->num_namedstyles = - fvar_head.instanceCount; + num_instances; + + /* alas, no public field in `FT_Var_Axis' for axis flags */ + axis_flags = + (FT_UShort*)( (char*)mmvar + mmvar_size ); mmvar->axis = - (FT_Var_Axis*)&( mmvar[1] ); + (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size ); mmvar->namedstyle = - (FT_Var_Named_Style*)&( mmvar->axis[fvar_head.axisCount] ); + (FT_Var_Named_Style*)( (char*)mmvar->axis + axis_size ); - next_coords = - (FT_Fixed*)&( mmvar->namedstyle[fvar_head.instanceCount] ); - for ( i = 0; i < fvar_head.instanceCount; i++ ) + next_coords = (FT_Fixed*)( (char*)mmvar->namedstyle + + namedstyle_size ); + for ( i = 0; i < num_instances; i++ ) { mmvar->namedstyle[i].coords = next_coords; - next_coords += fvar_head.axisCount; + next_coords += num_axes; } - next_name = (FT_String*)next_coords; - for ( i = 0; i < fvar_head.axisCount; i++ ) + next_name = (FT_String*)( (char*)mmvar->namedstyle + + namedstyle_size + next_coords_size ); + for ( i = 0; i < num_axes; i++ ) { mmvar->axis[i].name = next_name; next_name += 5; @@ -861,10 +2137,14 @@ goto Exit; a = mmvar->axis; - for ( i = 0; i < fvar_head.axisCount; i++ ) + for ( i = 0; i < num_axes; i++ ) { GX_FVar_Axis axis_rec; +#ifdef FT_DEBUG_LEVEL_TRACE + int invalid = 0; +#endif + if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) ) goto Exit; @@ -880,36 +2160,194 @@ a->name[3] = (FT_String)( ( a->tag ) & 0xFF ); a->name[4] = '\0'; - FT_TRACE5(( " \"%s\": minimum=%.4f, default=%.4f, maximum=%.4f\n", + *axis_flags = axis_rec.flags; + + if ( a->minimum > a->def || + a->def > a->maximum ) + { + a->minimum = a->def; + a->maximum = a->def; + +#ifdef FT_DEBUG_LEVEL_TRACE + invalid = 1; +#endif + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( i == 0 ) + FT_TRACE5(( " idx tag " + /* " XXX `XXXX'" */ + " minimum default maximum flags\n" )); + /* " XXXX.XXXXX XXXX.XXXXX XXXX.XXXXX 0xXXXX" */ + + FT_TRACE5(( " %3d `%s'" + " %10.5f %10.5f %10.5f 0x%04X%s\n", + i, a->name, a->minimum / 65536.0, a->def / 65536.0, - a->maximum / 65536.0 )); + a->maximum / 65536.0, + *axis_flags, + invalid ? " (invalid, disabled)" : "" )); +#endif a++; + axis_flags++; } FT_TRACE5(( "\n" )); - ns = mmvar->namedstyle; + /* named instance coordinates are stored as design coordinates; */ + /* we have to convert them to normalized coordinates also */ + if ( FT_NEW_ARRAY( face->blend->normalized_stylecoords, + num_axes * num_instances ) ) + goto Exit; + + if ( fvar_head.instanceCount && !face->blend->avar_loaded ) + { + FT_ULong offset = FT_STREAM_POS(); + + + ft_var_load_avar( face ); + + if ( FT_STREAM_SEEK( offset ) ) + goto Exit; + } + + FT_TRACE5(( "%d instance%s\n", + fvar_head.instanceCount, + fvar_head.instanceCount == 1 ? "" : "s" )); + + ns = mmvar->namedstyle; + nsc = face->blend->normalized_stylecoords; for ( i = 0; i < fvar_head.instanceCount; i++, ns++ ) { - if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) ) + /* PostScript names add 2 bytes to the instance record size */ + if ( FT_FRAME_ENTER( ( usePsName ? 6L : 4L ) + + 4L * num_axes ) ) goto Exit; ns->strid = FT_GET_USHORT(); (void) /* flags = */ FT_GET_USHORT(); - for ( j = 0; j < fvar_head.axisCount; j++ ) - ns->coords[j] = FT_GET_LONG(); + c = ns->coords; + for ( j = 0; j < num_axes; j++, c++ ) + *c = FT_GET_LONG(); + + /* valid psid values are 6, [256;32767], and 0xFFFF */ + if ( usePsName ) + ns->psid = FT_GET_USHORT(); + else + ns->psid = 0xFFFF; + +#ifdef FT_DEBUG_LEVEL_TRACE + { + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + FT_String* strname = NULL; + FT_String* psname = NULL; + + FT_ULong pos; + + + pos = FT_STREAM_POS(); + + if ( ns->strid != 0xFFFF ) + { + (void)sfnt->get_name( face, + (FT_UShort)ns->strid, + &strname ); + if ( strname && !ft_strcmp( strname, ".notdef" ) ) + strname = NULL; + } + + if ( ns->psid != 0xFFFF ) + { + (void)sfnt->get_name( face, + (FT_UShort)ns->psid, + &psname ); + if ( psname && !ft_strcmp( psname, ".notdef" ) ) + psname = NULL; + } + + (void)FT_STREAM_SEEK( pos ); + + FT_TRACE5(( " instance %d (%s%s%s, %s%s%s)\n", + i, + strname ? "name: `" : "", + strname ? strname : "unnamed", + strname ? "'" : "", + psname ? "PS name: `" : "", + psname ? psname : "no PS name", + psname ? "'" : "" )); + + FT_FREE( strname ); + FT_FREE( psname ); + } +#endif /* FT_DEBUG_LEVEL_TRACE */ + + ft_var_to_normalized( face, num_axes, ns->coords, nsc ); + nsc += num_axes; FT_FRAME_EXIT(); } + + if ( num_instances != fvar_head.instanceCount ) + { + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + FT_Int found, dummy1, dummy2; + FT_UInt strid = ~0U; + + + /* the default instance is missing in array the */ + /* of named instances; try to synthesize an entry */ + found = sfnt->get_name_id( face, + TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY, + &dummy1, + &dummy2 ); + if ( found ) + strid = TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY; + else + { + found = sfnt->get_name_id( face, + TT_NAME_ID_FONT_SUBFAMILY, + &dummy1, + &dummy2 ); + if ( found ) + strid = TT_NAME_ID_FONT_SUBFAMILY; + } + + if ( found ) + { + found = sfnt->get_name_id( face, + TT_NAME_ID_PS_NAME, + &dummy1, + &dummy2 ); + if ( found ) + { + FT_TRACE5(( "TT_Get_MM_Var:" + " Adding default instance to named instances\n" )); + + ns = &mmvar->namedstyle[fvar_head.instanceCount]; + + ns->strid = strid; + ns->psid = TT_NAME_ID_PS_NAME; + + a = mmvar->axis; + c = ns->coords; + for ( j = 0; j < num_axes; j++, a++, c++ ) + *c = a->def; + } + } + } + + ft_var_load_mvar( face ); } /* fill the output array if requested */ - if ( master != NULL ) + if ( master ) { FT_UInt n; @@ -918,22 +2356,25 @@ goto Exit; FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len ); + axis_flags = + (FT_UShort*)( (char*)mmvar + mmvar_size ); mmvar->axis = - (FT_Var_Axis*)&( mmvar[1] ); + (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size ); mmvar->namedstyle = - (FT_Var_Named_Style*)&( mmvar->axis[mmvar->num_axis] ); - next_coords = - (FT_Fixed*)&( mmvar->namedstyle[mmvar->num_namedstyles] ); + (FT_Var_Named_Style*)( (char*)mmvar->axis+ axis_size ); + next_coords = (FT_Fixed*)( (char*)mmvar->namedstyle + + namedstyle_size ); for ( n = 0; n < mmvar->num_namedstyles; n++ ) { mmvar->namedstyle[n].coords = next_coords; - next_coords += mmvar->num_axis; + next_coords += num_axes; } a = mmvar->axis; - next_name = (FT_String*)next_coords; - for ( n = 0; n < mmvar->num_axis; n++ ) + next_name = (FT_String*)( (char*)mmvar->namedstyle + + namedstyle_size + next_coords_size ); + for ( n = 0; n < num_axes; n++ ) { a->name = next_name; @@ -959,40 +2400,19 @@ } - /*************************************************************************/ - /* */ - /* <Function> */ - /* TT_Set_MM_Blend */ - /* */ - /* <Description> */ - /* Set the blend (normalized) coordinates for this instance of the */ - /* font. Check that the `gvar' table is reasonable and does some */ - /* initial preparation. */ - /* */ - /* <InOut> */ - /* face :: The font. */ - /* Initialize the blend structure with `gvar' data. */ - /* */ - /* <Input> */ - /* num_coords :: The number of available coordinates. If it is */ - /* larger than the number of axes, ignore the excess */ - /* values. If it is smaller than the number of axes, */ - /* use the default value (0) for the remaining axes. */ - /* */ - /* coords :: An array of `num_coords', each between [-1,1]. */ - /* */ - /* <Return> */ - /* FreeType error code. 0 means success. */ - /* */ - FT_LOCAL_DEF( FT_Error ) - TT_Set_MM_Blend( TT_Face face, + static FT_Error + tt_set_mm_blend( TT_Face face, FT_UInt num_coords, - FT_Fixed* coords ) + FT_Fixed* coords, + FT_Bool set_design_coords ) { FT_Error error = FT_Err_Ok; GX_Blend blend; FT_MM_Var* mmvar; FT_UInt i; + + FT_Bool all_design_coords = FALSE; + FT_Memory memory = face->root.memory; enum @@ -1006,9 +2426,9 @@ face->doblend = FALSE; - if ( face->blend == NULL ) + if ( !face->blend ) { - if ( ( error = TT_Get_MM_Var( face, NULL ) ) != 0 ) + if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) goto Exit; } @@ -1017,19 +2437,21 @@ if ( num_coords > mmvar->num_axis ) { - FT_TRACE2(( "TT_Set_MM_Blend: only using first %d of %d coordinates\n", + FT_TRACE2(( "TT_Set_MM_Blend:" + " only using first %d of %d coordinates\n", mmvar->num_axis, num_coords )); num_coords = mmvar->num_axis; } - FT_TRACE5(( "normalized design coordinates:\n" )); + FT_TRACE5(( "TT_Set_MM_Blend:\n" + " normalized design coordinates:\n" )); for ( i = 0; i < num_coords; i++ ) { - FT_TRACE5(( " %.4f\n", coords[i] / 65536.0 )); + FT_TRACE5(( " %.5f\n", coords[i] / 65536.0 )); if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L ) { - FT_TRACE1(( "TT_Set_MM_Blend: normalized design coordinate %.4f\n" + FT_TRACE1(( "TT_Set_MM_Blend: normalized design coordinate %.5f\n" " is out of range [-1;1]\n", coords[i] / 65536.0 )); error = FT_THROW( Invalid_Argument ); @@ -1039,11 +2461,20 @@ FT_TRACE5(( "\n" )); - if ( blend->glyphoffsets == NULL ) - if ( ( error = ft_var_load_gvar( face ) ) != 0 ) + if ( !face->is_cff2 && !blend->glyphoffsets ) + if ( FT_SET_ERROR( ft_var_load_gvar( face ) ) ) goto Exit; - if ( blend->normalizedcoords == NULL ) + if ( !blend->coords ) + { + if ( FT_NEW_ARRAY( blend->coords, mmvar->num_axis ) ) + goto Exit; + + /* the first time we have to compute all design coordinates */ + all_design_coords = TRUE; + } + + if ( !blend->normalizedcoords ) { if ( FT_NEW_ARRAY( blend->normalizedcoords, mmvar->num_axis ) ) goto Exit; @@ -1056,6 +2487,12 @@ } else { + FT_Bool have_diff = 0; + FT_UInt j; + FT_Fixed* c; + FT_Fixed* n; + + manageCvt = mcvt_retain; for ( i = 0; i < num_coords; i++ ) @@ -1063,10 +2500,34 @@ if ( blend->normalizedcoords[i] != coords[i] ) { manageCvt = mcvt_load; + have_diff = 1; break; } } + if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ) + { + FT_UInt idx = (FT_UInt)face->root.face_index >> 16; + + + c = blend->normalizedcoords + i; + n = blend->normalized_stylecoords + idx * mmvar->num_axis + i; + for ( j = i; j < mmvar->num_axis; j++, n++, c++ ) + if ( *c != *n ) + have_diff = 1; + } + else + { + c = blend->normalizedcoords + i; + for ( j = i; j < mmvar->num_axis; j++, c++ ) + if ( *c != 0 ) + have_diff = 1; + } + + /* return value -1 indicates `no change' */ + if ( !have_diff ) + return -1; + for ( ; i < mmvar->num_axis; i++ ) { if ( blend->normalizedcoords[i] != 0 ) @@ -1087,9 +2548,15 @@ coords, num_coords * sizeof ( FT_Fixed ) ); + if ( set_design_coords ) + ft_var_to_design( face, + all_design_coords ? blend->num_axis : num_coords, + blend->normalizedcoords, + blend->coords ); + face->doblend = TRUE; - if ( face->cvt != NULL ) + if ( face->cvt ) { switch ( manageCvt ) { @@ -1114,6 +2581,10 @@ } } + /* enforce recomputation of the PostScript name; */ + FT_FREE( face->postscript_name ); + face->postscript_name = NULL; + Exit: return error; } @@ -1122,6 +2593,128 @@ /*************************************************************************/ /* */ /* <Function> */ + /* TT_Set_MM_Blend */ + /* */ + /* <Description> */ + /* Set the blend (normalized) coordinates for this instance of the */ + /* font. Check that the `gvar' table is reasonable and does some */ + /* initial preparation. */ + /* */ + /* <InOut> */ + /* face :: The font. */ + /* Initialize the blend structure with `gvar' data. */ + /* */ + /* <Input> */ + /* num_coords :: The number of available coordinates. If it is */ + /* larger than the number of axes, ignore the excess */ + /* values. If it is smaller than the number of axes, */ + /* use the default value (0) for the remaining axes. */ + /* */ + /* coords :: An array of `num_coords', each between [-1,1]. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + TT_Set_MM_Blend( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + + + error = tt_set_mm_blend( face, num_coords, coords, 1 ); + if ( error ) + return error; + + if ( num_coords ) + face->root.face_flags |= FT_FACE_FLAG_VARIATION; + else + face->root.face_flags &= ~FT_FACE_FLAG_VARIATION; + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Get_MM_Blend */ + /* */ + /* <Description> */ + /* Get the blend (normalized) coordinates for this instance of the */ + /* font. */ + /* */ + /* <InOut> */ + /* face :: The font. */ + /* Initialize the blend structure with `gvar' data. */ + /* */ + /* <Input> */ + /* num_coords :: The number of available coordinates. If it is */ + /* larger than the number of axes, set the excess */ + /* values to 0. */ + /* */ + /* coords :: An array of `num_coords', each between [-1,1]. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + TT_Get_MM_Blend( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error = FT_Err_Ok; + GX_Blend blend; + FT_UInt i, nc; + + + if ( !face->blend ) + { + if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) + return error; + } + + blend = face->blend; + + if ( !blend->coords ) + { + /* select default instance coordinates */ + /* if no instance is selected yet */ + if ( FT_SET_ERROR( tt_set_mm_blend( face, 0, NULL, 1 ) ) ) + return error; + } + + nc = num_coords; + if ( num_coords > blend->num_axis ) + { + FT_TRACE2(( "TT_Get_MM_Blend:" + " only using first %d of %d coordinates\n", + blend->num_axis, num_coords )); + nc = blend->num_axis; + } + + if ( face->doblend ) + { + for ( i = 0; i < nc; i++ ) + coords[i] = blend->normalizedcoords[i]; + } + else + { + for ( i = 0; i < nc; i++ ) + coords[i] = 0; + } + + for ( ; i < num_coords; i++ ) + coords[i] = 0; + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ /* TT_Set_Var_Design */ /* */ /* <Description> */ @@ -1149,19 +2742,22 @@ FT_UInt num_coords, FT_Fixed* coords ) { - FT_Error error = FT_Err_Ok; - FT_Fixed* normalized = NULL; - GX_Blend blend; - FT_MM_Var* mmvar; - FT_UInt i, j; - FT_Var_Axis* a; - GX_AVarSegment av; - FT_Memory memory = face->root.memory; + FT_Error error = FT_Err_Ok; + GX_Blend blend; + FT_MM_Var* mmvar; + FT_UInt i; + FT_Memory memory = face->root.memory; + + FT_Fixed* c; + FT_Fixed* n; + FT_Fixed* normalized = NULL; + + FT_Bool have_diff = 0; - if ( face->blend == NULL ) + if ( !face->blend ) { - if ( ( error = TT_Get_MM_Var( face, NULL ) ) != 0 ) + if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) goto Exit; } @@ -1176,75 +2772,81 @@ num_coords = mmvar->num_axis; } - /* Axis normalization is a two stage process. First we normalize */ - /* based on the [min,def,max] values for the axis to be [-1,0,1]. */ - /* Then, if there's an `avar' table, we renormalize this range. */ - - if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) ) - goto Exit; - - FT_TRACE5(( "design coordinates:\n" )); + if ( !blend->coords ) + { + if ( FT_NEW_ARRAY( blend->coords, mmvar->num_axis ) ) + goto Exit; + } - a = mmvar->axis; - for ( i = 0; i < num_coords; i++, a++ ) + c = blend->coords; + n = coords; + for ( i = 0; i < num_coords; i++, n++, c++ ) { - FT_TRACE5(( " %.4f\n", coords[i] / 65536.0 )); - if ( coords[i] > a->maximum || coords[i] < a->minimum ) + if ( *c != *n ) { - FT_TRACE1(( "TT_Set_Var_Design: normalized design coordinate %.4f\n" - " is out of range [%.4f;%.4f]\n", - coords[i] / 65536.0, - a->minimum / 65536.0, - a->maximum / 65536.0 )); - error = FT_THROW( Invalid_Argument ); - goto Exit; + *c = *n; + have_diff = 1; } - - if ( coords[i] < a->def ) - normalized[i] = -FT_DivFix( coords[i] - a->def, - a->minimum - a->def ); - else if ( a->maximum == a->def ) - normalized[i] = 0; - else - normalized[i] = FT_DivFix( coords[i] - a->def, - a->maximum - a->def ); } - FT_TRACE5(( "\n" )); + if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ) + { + FT_UInt instance_index; + FT_Var_Named_Style* named_style; - for ( ; i < mmvar->num_axis; i++ ) - normalized[i] = 0; - if ( !blend->avar_checked ) - ft_var_load_avar( face ); + instance_index = (FT_UInt)face->root.face_index >> 16; + named_style = mmvar->namedstyle + instance_index - 1; - if ( blend->avar_segment != NULL ) + n = named_style->coords + num_coords; + for ( ; i < mmvar->num_axis; i++, n++, c++ ) + { + if ( *c != *n ) + { + *c = *n; + have_diff = 1; + } + } + } + else { - FT_TRACE5(( "normalized design coordinates" - " before applying `avar' data:\n" )); + FT_Var_Axis* a; - av = blend->avar_segment; - for ( i = 0; i < mmvar->num_axis; i++, av++ ) + + a = mmvar->axis + num_coords; + for ( ; i < mmvar->num_axis; i++, a++, c++ ) { - for ( j = 1; j < (FT_UInt)av->pairCount; j++ ) + if ( *c != a->def ) { - FT_TRACE5(( " %.4f\n", normalized[i] / 65536.0 )); - if ( normalized[i] < av->correspondence[j].fromCoord ) - { - normalized[i] = - FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord, - av->correspondence[j].toCoord - - av->correspondence[j - 1].toCoord, - av->correspondence[j].fromCoord - - av->correspondence[j - 1].fromCoord ) + - av->correspondence[j - 1].toCoord; - break; - } + *c = a->def; + have_diff = 1; } } } - error = TT_Set_MM_Blend( face, mmvar->num_axis, normalized ); + /* return value -1 indicates `no change'; */ + /* we can exit early if `normalizedcoords' is already computed */ + if ( blend->normalizedcoords && !have_diff ) + return -1; + + if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) ) + goto Exit; + + if ( !face->blend->avar_loaded ) + ft_var_load_avar( face ); + + FT_TRACE5(( "TT_Set_Var_Design:\n" + " normalized design coordinates:\n" )); + ft_var_to_normalized( face, num_coords, blend->coords, normalized ); + + error = tt_set_mm_blend( face, mmvar->num_axis, normalized, 0 ); + if ( error ) + goto Exit; + + if ( num_coords ) + face->root.face_flags |= FT_FACE_FLAG_VARIATION; + else + face->root.face_flags &= ~FT_FACE_FLAG_VARIATION; Exit: FT_FREE( normalized ); @@ -1253,6 +2855,165 @@ /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Get_Var_Design */ + /* */ + /* <Description> */ + /* Get the design coordinates of the currently selected interpolated */ + /* font. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face. */ + /* */ + /* num_coords :: The number of design coordinates to retrieve. If it */ + /* is larger than the number of axes, set the excess */ + /* values to~0. */ + /* */ + /* <Output> */ + /* coords :: The design coordinates array. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + TT_Get_Var_Design( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error = FT_Err_Ok; + GX_Blend blend; + FT_UInt i, nc; + + + if ( !face->blend ) + { + if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) + return error; + } + + blend = face->blend; + + if ( !blend->coords ) + { + /* select default instance coordinates */ + /* if no instance is selected yet */ + if ( FT_SET_ERROR( tt_set_mm_blend( face, 0, NULL, 1 ) ) ) + return error; + } + + nc = num_coords; + if ( num_coords > blend->num_axis ) + { + FT_TRACE2(( "TT_Get_Var_Design:" + " only using first %d of %d coordinates\n", + blend->num_axis, num_coords )); + nc = blend->num_axis; + } + + if ( face->doblend ) + { + for ( i = 0; i < nc; i++ ) + coords[i] = blend->coords[i]; + } + else + { + for ( i = 0; i < nc; i++ ) + coords[i] = 0; + } + + for ( ; i < num_coords; i++ ) + coords[i] = 0; + + return FT_Err_Ok; + } + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* TT_Set_Named_Instance */ + /* */ + /* <Description> */ + /* Set the given named instance, also resetting any further */ + /* variation. */ + /* */ + /* <Input> */ + /* face :: A handle to the source face. */ + /* */ + /* instance_index :: The instance index, starting with value 1. */ + /* Value 0 indicates to not use an instance. */ + /* */ + /* <Return> */ + /* FreeType error code. 0~means success. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + TT_Set_Named_Instance( TT_Face face, + FT_UInt instance_index ) + { + FT_Error error = FT_ERR( Invalid_Argument ); + GX_Blend blend; + FT_MM_Var* mmvar; + + FT_UInt num_instances; + + + if ( !face->blend ) + { + if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) + goto Exit; + } + + blend = face->blend; + mmvar = blend->mmvar; + + num_instances = (FT_UInt)face->root.style_flags >> 16; + + /* `instance_index' starts with value 1, thus `>' */ + if ( instance_index > num_instances ) + goto Exit; + + if ( instance_index > 0 && mmvar->namedstyle ) + { + FT_Memory memory = face->root.memory; + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + FT_Var_Named_Style* named_style; + FT_String* style_name; + + + named_style = mmvar->namedstyle + instance_index - 1; + + error = sfnt->get_name( face, + (FT_UShort)named_style->strid, + &style_name ); + if ( error ) + goto Exit; + + /* set (or replace) style name */ + FT_FREE( face->root.style_name ); + face->root.style_name = style_name; + + /* finally, select the named instance */ + error = TT_Set_Var_Design( face, + mmvar->num_axis, + named_style->coords ); + if ( error ) + goto Exit; + } + else + error = TT_Set_Var_Design( face, 0, NULL ); + + face->root.face_index = ( instance_index << 16 ) | + ( face->root.face_index & 0xFFFFL ); + face->root.face_flags &= ~FT_FACE_FLAG_VARIATION; + + Exit: + return error; + } + + + /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** GX VAR PARSING ROUTINES *****/ @@ -1298,14 +3059,16 @@ FT_Fixed* im_start_coords = NULL; FT_Fixed* im_end_coords = NULL; GX_Blend blend = face->blend; - FT_UInt point_count; - FT_UShort* localpoints; + FT_UInt point_count, spoint_count = 0; + FT_UShort* sharedpoints = NULL; + FT_UShort* localpoints = NULL; + FT_UShort* points; FT_Short* deltas; FT_TRACE2(( "CVAR " )); - if ( blend == NULL ) + if ( !blend ) { FT_TRACE2(( "\n" "tt_face_vary_cvt: no blend specified\n" )); @@ -1313,7 +3076,7 @@ goto Exit; } - if ( face->cvt == NULL ) + if ( !face->cvt ) { FT_TRACE2(( "\n" "tt_face_vary_cvt: no `cvt ' table\n" )); @@ -1353,13 +3116,39 @@ goto FExit; tupleCount = FT_GET_USHORT(); - offsetToData = table_start + FT_GET_USHORT(); + offsetToData = FT_GET_USHORT(); + + /* rough sanity test */ + if ( offsetToData + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 > + table_len ) + { + FT_TRACE2(( "tt_face_vary_cvt:" + " invalid CVT variation array header\n" )); + + error = FT_THROW( Invalid_Table ); + goto FExit; + } - /* The documentation implies there are flags packed into the */ - /* tuplecount, but John Jenkins says that shared points don't apply */ - /* to `cvar', and no other flags are defined. */ + offsetToData += table_start; + + if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS ) + { + here = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, offsetToData ); + + sharedpoints = ft_var_readpackedpoints( stream, + table_len, + &spoint_count ); + offsetToData = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, here ); + } - FT_TRACE5(( "cvar: there are %d tuples:\n", tupleCount )); + FT_TRACE5(( "cvar: there %s %d tuple%s:\n", + ( tupleCount & 0xFFF ) == 1 ? "is" : "are", + tupleCount & 0xFFF, + ( tupleCount & 0xFFF ) == 1 ? "" : "s" )); for ( i = 0; i < ( tupleCount & 0xFFF ); i++ ) { @@ -1373,26 +3162,25 @@ tupleDataSize = FT_GET_USHORT(); tupleIndex = FT_GET_USHORT(); - /* There is no provision here for a global tuple coordinate section, */ - /* so John says. There are no tuple indices, just embedded tuples. */ - if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) { for ( j = 0; j < blend->num_axis; j++ ) tuple_coords[j] = FT_GET_SHORT() * 4; /* convert from */ /* short frac to fixed */ } - else + else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) { - /* skip this tuple; it makes no sense */ + FT_TRACE2(( "tt_face_vary_cvt:" + " invalid tuple index\n" )); - if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) - for ( j = 0; j < 2 * blend->num_axis; j++ ) - (void)FT_GET_SHORT(); - - offsetToData += tupleDataSize; - continue; + error = FT_THROW( Invalid_Table ); + goto Exit; } + else + FT_MEM_COPY( + tuple_coords, + &blend->tuplecoords[( tupleIndex & 0xFFF ) * blend->num_axis], + blend->num_axis * sizeof ( FT_Fixed ) ); if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) { @@ -1407,11 +3195,8 @@ tuple_coords, im_start_coords, im_end_coords ); - if ( /* tuple isn't active for our blend */ - apply == 0 || - /* global points not allowed, */ - /* if they aren't local, makes no sense */ - !( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) ) + + if ( apply == 0 ) /* tuple isn't active for our blend */ { offsetToData += tupleDataSize; continue; @@ -1421,11 +3206,27 @@ FT_Stream_SeekSet( stream, offsetToData ); - localpoints = ft_var_readpackedpoints( stream, &point_count ); - deltas = ft_var_readpackeddeltas( stream, - point_count == 0 ? face->cvt_size - : point_count ); - if ( localpoints == NULL || deltas == NULL ) + if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) + { + localpoints = ft_var_readpackedpoints( stream, + table_len, + &point_count ); + points = localpoints; + } + else + { + points = sharedpoints; + point_count = spoint_count; + } + + deltas = ft_var_readpackeddeltas( stream, + table_len, + point_count == 0 ? face->cvt_size + : point_count ); + + if ( !points || + !deltas || + ( localpoints == ALL_POINTS && point_count != face->cvt_size ) ) ; /* failure, ignore it */ else if ( localpoints == ALL_POINTS ) @@ -1473,10 +3274,15 @@ for ( j = 0; j < point_count; j++ ) { - int pindex = localpoints[j]; - FT_Long orig_cvt = face->cvt[pindex]; + int pindex; + FT_Long orig_cvt; + pindex = points[j]; + if ( (FT_ULong)pindex >= face->cvt_size ) + continue; + + orig_cvt = face->cvt[pindex]; face->cvt[pindex] = (FT_Short)( orig_cvt + FT_MulFix( deltas[j], apply ) ); @@ -1511,6 +3317,8 @@ FT_FRAME_EXIT(); Exit: + if ( sharedpoints != ALL_POINTS ) + FT_FREE( sharedpoints ); FT_FREE( tuple_coords ); FT_FREE( im_start_coords ); FT_FREE( im_end_coords ); @@ -1599,25 +3407,12 @@ d1 = out1 - in1; d2 = out2 - in2; - if ( out1 == out2 || in1 == in2 ) + /* If the reference points have the same coordinate but different */ + /* delta, inferred delta is zero. Otherwise interpolate. */ + if ( in1 != in2 || out1 == out2 ) { - for ( p = p1; p <= p2; p++ ) - { - out = in_points[p].x; - - if ( out <= in1 ) - out += d1; - else if ( out >= in2 ) - out += d2; - else - out = out1; - - out_points[p].x = out; - } - } - else - { - FT_Fixed scale = FT_DivFix( out2 - out1, in2 - in1 ); + FT_Fixed scale = in1 != in2 ? FT_DivFix( out2 - out1, in2 - in1 ) + : 0; for ( p = p1; p <= p2; p++ ) @@ -1644,12 +3439,11 @@ /* modeled after `Ins_IUP */ static void - tt_handle_deltas( FT_Outline* outline, - FT_Vector* in_points, - FT_Bool* has_delta ) + tt_interpolate_deltas( FT_Outline* outline, + FT_Vector* out_points, + FT_Vector* in_points, + FT_Bool* has_delta ) { - FT_Vector* out_points; - FT_Int first_point; FT_Int end_point; @@ -1664,8 +3458,6 @@ if ( !outline->n_contours ) return; - out_points = outline->points; - contour = 0; point = 0; @@ -1769,6 +3561,7 @@ GX_Blend blend = face->blend; FT_Vector* points_org = NULL; + FT_Vector* points_out = NULL; FT_Bool* has_delta = NULL; FT_Error error; @@ -1787,7 +3580,7 @@ FT_Short *deltas_x, *deltas_y; - if ( !face->doblend || blend == NULL ) + if ( !face->doblend || !blend ) return FT_THROW( Invalid_Argument ); if ( glyph_index >= blend->gv_glyphcnt || @@ -1800,6 +3593,7 @@ } if ( FT_NEW_ARRAY( points_org, n_points ) || + FT_NEW_ARRAY( points_out, n_points ) || FT_NEW_ARRAY( has_delta, n_points ) ) goto Fail1; @@ -1811,7 +3605,6 @@ glyph_start = FT_Stream_FTell( stream ); /* each set of glyph variation data is formatted similarly to `cvar' */ - /* (except we get shared points and global tuples) */ if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) || FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || @@ -1819,7 +3612,20 @@ goto Fail2; tupleCount = FT_GET_USHORT(); - offsetToData = glyph_start + FT_GET_USHORT(); + offsetToData = FT_GET_USHORT(); + + /* rough sanity test */ + if ( offsetToData + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 > + blend->gvar_size ) + { + FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" + " invalid glyph variation array header\n" )); + + error = FT_THROW( Invalid_Table ); + goto Fail2; + } + + offsetToData += glyph_start; if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS ) { @@ -1827,13 +3633,21 @@ FT_Stream_SeekSet( stream, offsetToData ); - sharedpoints = ft_var_readpackedpoints( stream, &spoint_count ); + sharedpoints = ft_var_readpackedpoints( stream, + blend->gvar_size, + &spoint_count ); offsetToData = FT_Stream_FTell( stream ); FT_Stream_SeekSet( stream, here ); } - FT_TRACE5(( "gvar: there are %d tuples:\n", tupleCount )); + FT_TRACE5(( "gvar: there %s %d tuple%s:\n", + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are", + tupleCount & GX_TC_TUPLE_COUNT_MASK, + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" )); + + for ( j = 0; j < n_points; j++ ) + points_org[j] = outline->points[j]; for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ ) { @@ -1855,6 +3669,9 @@ } else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) { + FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" + " invalid tuple index\n" )); + error = FT_THROW( Invalid_Table ); goto Fail2; } @@ -1886,11 +3703,13 @@ here = FT_Stream_FTell( stream ); + FT_Stream_SeekSet( stream, offsetToData ); + if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) { - FT_Stream_SeekSet( stream, offsetToData ); - - localpoints = ft_var_readpackedpoints( stream, &point_count ); + localpoints = ft_var_readpackedpoints( stream, + blend->gvar_size, + &point_count ); points = localpoints; } else @@ -1900,13 +3719,15 @@ } deltas_x = ft_var_readpackeddeltas( stream, + blend->gvar_size, point_count == 0 ? n_points : point_count ); deltas_y = ft_var_readpackeddeltas( stream, + blend->gvar_size, point_count == 0 ? n_points : point_count ); - if ( points == NULL || deltas_y == NULL || deltas_x == NULL ) + if ( !points || !deltas_y || !deltas_x ) ; /* failure, ignore it */ else if ( points == ALL_POINTS ) @@ -1921,22 +3742,48 @@ /* this means that there are deltas for every point in the glyph */ for ( j = 0; j < n_points; j++ ) { -#ifdef FT_DEBUG_LEVEL_TRACE - FT_Vector point_org = outline->points[j]; -#endif + FT_Pos delta_x = FT_MulFix( deltas_x[j], apply ); + FT_Pos delta_y = FT_MulFix( deltas_y[j], apply ); - outline->points[j].x += FT_MulFix( deltas_x[j], apply ); - outline->points[j].y += FT_MulFix( deltas_y[j], apply ); + if ( j < n_points - 4 ) + { + outline->points[j].x += delta_x; + outline->points[j].y += delta_y; + } + else + { + /* To avoid double adjustment of advance width or height, */ + /* adjust phantom points only if there is no HVAR or VVAR */ + /* support, respectively. */ + if ( j == ( n_points - 4 ) && + !( face->variation_support & + TT_FACE_FLAG_VAR_LSB ) ) + outline->points[j].x += delta_x; + + else if ( j == ( n_points - 3 ) && + !( face->variation_support & + TT_FACE_FLAG_VAR_HADVANCE ) ) + outline->points[j].x += delta_x; + + else if ( j == ( n_points - 2 ) && + !( face->variation_support & + TT_FACE_FLAG_VAR_TSB ) ) + outline->points[j].y += delta_y; + + else if ( j == ( n_points - 1 ) && + !( face->variation_support & + TT_FACE_FLAG_VAR_VADVANCE ) ) + outline->points[j].y += delta_y; + } #ifdef FT_DEBUG_LEVEL_TRACE - if ( ( point_org.x != outline->points[j].x ) || - ( point_org.y != outline->points[j].y ) ) + if ( delta_x || delta_y ) { FT_TRACE7(( " %d: (%d, %d) -> (%d, %d)\n", j, - point_org.x, - point_org.y, + outline->points[j].x - delta_x, + outline->points[j].y - delta_y, outline->points[j].x, outline->points[j].y )); count++; @@ -1961,13 +3808,13 @@ /* IUP bytecode instruction */ for ( j = 0; j < n_points; j++ ) { - points_org[j] = outline->points[j]; has_delta[j] = FALSE; + points_out[j] = points_org[j]; } for ( j = 0; j < point_count; j++ ) { - FT_UShort idx = localpoints[j]; + FT_UShort idx = points[j]; if ( idx >= n_points ) @@ -1975,34 +3822,71 @@ has_delta[idx] = TRUE; - outline->points[idx].x += FT_MulFix( deltas_x[j], apply ); - outline->points[idx].y += FT_MulFix( deltas_y[j], apply ); + points_out[idx].x += FT_MulFix( deltas_x[j], apply ); + points_out[idx].y += FT_MulFix( deltas_y[j], apply ); } /* no need to handle phantom points here, */ /* since solitary points can't be interpolated */ - tt_handle_deltas( outline, - points_org, - has_delta ); + tt_interpolate_deltas( outline, + points_out, + points_org, + has_delta ); -#ifdef FT_DEBUG_LEVEL_TRACE FT_TRACE7(( " point deltas:\n" )); - for ( j = 0; j < n_points; j++) + for ( j = 0; j < n_points; j++ ) { - if ( ( points_org[j].x != outline->points[j].x ) || - ( points_org[j].y != outline->points[j].y ) ) + FT_Pos delta_x = points_out[j].x - points_org[j].x; + FT_Pos delta_y = points_out[j].y - points_org[j].y; + + + if ( j < n_points - 4 ) + { + outline->points[j].x += delta_x; + outline->points[j].y += delta_y; + } + else + { + /* To avoid double adjustment of advance width or height, */ + /* adjust phantom points only if there is no HVAR or VVAR */ + /* support, respectively. */ + if ( j == ( n_points - 4 ) && + !( face->variation_support & + TT_FACE_FLAG_VAR_LSB ) ) + outline->points[j].x += delta_x; + + else if ( j == ( n_points - 3 ) && + !( face->variation_support & + TT_FACE_FLAG_VAR_HADVANCE ) ) + outline->points[j].x += delta_x; + + else if ( j == ( n_points - 2 ) && + !( face->variation_support & + TT_FACE_FLAG_VAR_TSB ) ) + outline->points[j].y += delta_y; + + else if ( j == ( n_points - 1 ) && + !( face->variation_support & + TT_FACE_FLAG_VAR_VADVANCE ) ) + outline->points[j].y += delta_y; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( delta_x || delta_y ) { FT_TRACE7(( " %d: (%d, %d) -> (%d, %d)\n", j, - points_org[j].x, - points_org[j].y, + outline->points[j].x - delta_x, + outline->points[j].y - delta_y, outline->points[j].x, outline->points[j].y )); count++; } +#endif } +#ifdef FT_DEBUG_LEVEL_TRACE if ( !count ) FT_TRACE7(( " none\n" )); #endif @@ -2021,6 +3905,8 @@ FT_TRACE5(( "\n" )); Fail2: + if ( sharedpoints != ALL_POINTS ) + FT_FREE( sharedpoints ); FT_FREE( tuple_coords ); FT_FREE( im_start_coords ); FT_FREE( im_end_coords ); @@ -2029,6 +3915,7 @@ Fail1: FT_FREE( points_org ); + FT_FREE( points_out ); FT_FREE( has_delta ); return error; @@ -2038,37 +3925,150 @@ /*************************************************************************/ /* */ /* <Function> */ + /* tt_get_var_blend */ + /* */ + /* <Description> */ + /* An extended internal version of `TT_Get_MM_Blend' that returns */ + /* pointers instead of copying data, without any initialization of */ + /* the MM machinery in case it isn't loaded yet. */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_get_var_blend( TT_Face face, + FT_UInt *num_coords, + FT_Fixed* *coords, + FT_Fixed* *normalizedcoords, + FT_MM_Var* *mm_var ) + { + if ( face->blend ) + { + if ( num_coords ) + *num_coords = face->blend->num_axis; + if ( coords ) + *coords = face->blend->coords; + if ( normalizedcoords ) + *normalizedcoords = face->blend->normalizedcoords; + if ( mm_var ) + *mm_var = face->blend->mmvar; + } + else + { + if ( num_coords ) + *num_coords = 0; + if ( coords ) + *coords = NULL; + if ( mm_var ) + *mm_var = NULL; + } + + return FT_Err_Ok; + } + + + static void + ft_var_done_item_variation_store( TT_Face face, + GX_ItemVarStore itemStore ) + { + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_UInt i; + + + if ( itemStore->varData ) + { + for ( i = 0; i < itemStore->dataCount; i++ ) + { + FT_FREE( itemStore->varData[i].regionIndices ); + FT_FREE( itemStore->varData[i].deltaSet ); + } + + FT_FREE( itemStore->varData ); + } + + if ( itemStore->varRegionList ) + { + for ( i = 0; i < itemStore->regionCount; i++ ) + FT_FREE( itemStore->varRegionList[i].axisList ); + + FT_FREE( itemStore->varRegionList ); + } + } + + + /*************************************************************************/ + /* */ + /* <Function> */ /* tt_done_blend */ /* */ /* <Description> */ /* Free the blend internal data structure. */ /* */ FT_LOCAL_DEF( void ) - tt_done_blend( FT_Memory memory, - GX_Blend blend ) + tt_done_blend( TT_Face face ) { - if ( blend != NULL ) + FT_Memory memory = FT_FACE_MEMORY( face ); + GX_Blend blend = face->blend; + + + if ( blend ) { - FT_UInt i; + FT_UInt i, num_axes; + /* blend->num_axis might not be set up yet */ + num_axes = blend->mmvar->num_axis; + + FT_FREE( blend->coords ); FT_FREE( blend->normalizedcoords ); + FT_FREE( blend->normalized_stylecoords ); FT_FREE( blend->mmvar ); - if ( blend->avar_segment != NULL ) + if ( blend->avar_segment ) { - for ( i = 0; i < blend->num_axis; i++ ) + for ( i = 0; i < num_axes; i++ ) FT_FREE( blend->avar_segment[i].correspondence ); FT_FREE( blend->avar_segment ); } + if ( blend->hvar_table ) + { + ft_var_done_item_variation_store( face, + &blend->hvar_table->itemStore ); + + FT_FREE( blend->hvar_table->widthMap.innerIndex ); + FT_FREE( blend->hvar_table->widthMap.outerIndex ); + FT_FREE( blend->hvar_table ); + } + + if ( blend->vvar_table ) + { + ft_var_done_item_variation_store( face, + &blend->vvar_table->itemStore ); + + FT_FREE( blend->vvar_table->widthMap.innerIndex ); + FT_FREE( blend->vvar_table->widthMap.outerIndex ); + FT_FREE( blend->vvar_table ); + } + + if ( blend->mvar_table ) + { + ft_var_done_item_variation_store( face, + &blend->mvar_table->itemStore ); + + FT_FREE( blend->mvar_table->values ); + FT_FREE( blend->mvar_table ); + } + FT_FREE( blend->tuplecoords ); FT_FREE( blend->glyphoffsets ); FT_FREE( blend ); } } -#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ +#else /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + /* ANSI C doesn't like empty source files */ + typedef int _tt_gxvar_dummy; + +#endif /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */ /* END */ diff --git a/src/3rdparty/freetype/src/truetype/ttgxvar.h b/src/3rdparty/freetype/src/truetype/ttgxvar.h index 060d4d60ea..a37bb90266 100644 --- a/src/3rdparty/freetype/src/truetype/ttgxvar.h +++ b/src/3rdparty/freetype/src/truetype/ttgxvar.h @@ -4,7 +4,7 @@ /* */ /* TrueType GX Font Variation loader (specification) */ /* */ -/* Copyright 2004-2015 by */ +/* Copyright 2004-2018 by */ /* David Turner, Robert Wilhelm, Werner Lemberg and George Williams. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,8 +16,8 @@ /***************************************************************************/ -#ifndef __TTGXVAR_H__ -#define __TTGXVAR_H__ +#ifndef TTGXVAR_H_ +#define TTGXVAR_H_ #include <ft2build.h> @@ -27,6 +27,8 @@ FT_BEGIN_HEADER +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /*************************************************************************/ /* */ /* <Struct> */ @@ -61,6 +63,152 @@ FT_BEGIN_HEADER } GX_AVarSegmentRec, *GX_AVarSegment; + typedef struct GX_ItemVarDataRec_ + { + FT_UInt itemCount; /* number of delta sets per item */ + FT_UInt regionIdxCount; /* number of region indices in this data */ + FT_UInt* regionIndices; /* array of `regionCount' indices; */ + /* these index `varRegionList' */ + FT_Short* deltaSet; /* array of `itemCount' deltas */ + /* use `innerIndex' for this array */ + + } GX_ItemVarDataRec, *GX_ItemVarData; + + + /* contribution of one axis to a region */ + typedef struct GX_AxisCoordsRec_ + { + FT_Fixed startCoord; + FT_Fixed peakCoord; /* zero means no effect (factor = 1) */ + FT_Fixed endCoord; + + } GX_AxisCoordsRec, *GX_AxisCoords; + + + typedef struct GX_VarRegionRec_ + { + GX_AxisCoords axisList; /* array of axisCount records */ + + } GX_VarRegionRec, *GX_VarRegion; + + + /* item variation store */ + typedef struct GX_ItemVarStoreRec_ + { + FT_UInt dataCount; + GX_ItemVarData varData; /* array of dataCount records; */ + /* use `outerIndex' for this array */ + FT_UShort axisCount; + FT_UInt regionCount; /* total number of regions defined */ + GX_VarRegion varRegionList; + + } GX_ItemVarStoreRec, *GX_ItemVarStore; + + + typedef struct GX_DeltaSetIdxMapRec_ + { + FT_UInt mapCount; + FT_UInt* outerIndex; /* indices to item var data */ + FT_UInt* innerIndex; /* indices to delta set */ + + } GX_DeltaSetIdxMapRec, *GX_DeltaSetIdxMap; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* GX_HVVarTableRec */ + /* */ + /* <Description> */ + /* Data from either the `HVAR' or `VVAR' table. */ + /* */ + typedef struct GX_HVVarTableRec_ + { + GX_ItemVarStoreRec itemStore; /* Item Variation Store */ + GX_DeltaSetIdxMapRec widthMap; /* Advance Width Mapping */ + +#if 0 + GX_DeltaSetIdxMapRec lsbMap; /* not implemented */ + GX_DeltaSetIdxMapRec rsbMap; /* not implemented */ + + GX_DeltaSetIdxMapRec tsbMap; /* not implemented */ + GX_DeltaSetIdxMapRec bsbMap; /* not implemented */ + GX_DeltaSetIdxMapRec vorgMap; /* not implemented */ +#endif + + } GX_HVVarTableRec, *GX_HVVarTable; + + +#define MVAR_TAG_GASP_0 FT_MAKE_TAG( 'g', 's', 'p', '0' ) +#define MVAR_TAG_GASP_1 FT_MAKE_TAG( 'g', 's', 'p', '1' ) +#define MVAR_TAG_GASP_2 FT_MAKE_TAG( 'g', 's', 'p', '2' ) +#define MVAR_TAG_GASP_3 FT_MAKE_TAG( 'g', 's', 'p', '3' ) +#define MVAR_TAG_GASP_4 FT_MAKE_TAG( 'g', 's', 'p', '4' ) +#define MVAR_TAG_GASP_5 FT_MAKE_TAG( 'g', 's', 'p', '5' ) +#define MVAR_TAG_GASP_6 FT_MAKE_TAG( 'g', 's', 'p', '6' ) +#define MVAR_TAG_GASP_7 FT_MAKE_TAG( 'g', 's', 'p', '7' ) +#define MVAR_TAG_GASP_8 FT_MAKE_TAG( 'g', 's', 'p', '8' ) +#define MVAR_TAG_GASP_9 FT_MAKE_TAG( 'g', 's', 'p', '9' ) + +#define MVAR_TAG_CPHT FT_MAKE_TAG( 'c', 'p', 'h', 't' ) +#define MVAR_TAG_HASC FT_MAKE_TAG( 'h', 'a', 's', 'c' ) +#define MVAR_TAG_HCLA FT_MAKE_TAG( 'h', 'c', 'l', 'a' ) +#define MVAR_TAG_HCLD FT_MAKE_TAG( 'h', 'c', 'l', 'd' ) +#define MVAR_TAG_HCOF FT_MAKE_TAG( 'h', 'c', 'o', 'f' ) +#define MVAR_TAG_HCRN FT_MAKE_TAG( 'h', 'c', 'r', 'n' ) +#define MVAR_TAG_HCRS FT_MAKE_TAG( 'h', 'c', 'r', 's' ) +#define MVAR_TAG_HDSC FT_MAKE_TAG( 'h', 'd', 's', 'c' ) +#define MVAR_TAG_HLGP FT_MAKE_TAG( 'h', 'l', 'g', 'p' ) +#define MVAR_TAG_SBXO FT_MAKE_TAG( 's', 'b', 'x', 'o' ) +#define MVAR_TAG_SBXS FT_MAKE_TAG( 's', 'b', 'x', 's' ) +#define MVAR_TAG_SBYO FT_MAKE_TAG( 's', 'b', 'y', 'o' ) +#define MVAR_TAG_SBYS FT_MAKE_TAG( 's', 'b', 'y', 's' ) +#define MVAR_TAG_SPXO FT_MAKE_TAG( 's', 'p', 'x', 'o' ) +#define MVAR_TAG_SPXS FT_MAKE_TAG( 's', 'p', 'x', 's' ) +#define MVAR_TAG_SPYO FT_MAKE_TAG( 's', 'p', 'y', 'o' ) +#define MVAR_TAG_SPYS FT_MAKE_TAG( 's', 'p', 'y', 's' ) +#define MVAR_TAG_STRO FT_MAKE_TAG( 's', 't', 'r', 'o' ) +#define MVAR_TAG_STRS FT_MAKE_TAG( 's', 't', 'r', 's' ) +#define MVAR_TAG_UNDO FT_MAKE_TAG( 'u', 'n', 'd', 'o' ) +#define MVAR_TAG_UNDS FT_MAKE_TAG( 'u', 'n', 'd', 's' ) +#define MVAR_TAG_VASC FT_MAKE_TAG( 'v', 'a', 's', 'c' ) +#define MVAR_TAG_VCOF FT_MAKE_TAG( 'v', 'c', 'o', 'f' ) +#define MVAR_TAG_VCRN FT_MAKE_TAG( 'v', 'c', 'r', 'n' ) +#define MVAR_TAG_VCRS FT_MAKE_TAG( 'v', 'c', 'r', 's' ) +#define MVAR_TAG_VDSC FT_MAKE_TAG( 'v', 'd', 's', 'c' ) +#define MVAR_TAG_VLGP FT_MAKE_TAG( 'v', 'l', 'g', 'p' ) +#define MVAR_TAG_XHGT FT_MAKE_TAG( 'x', 'h', 'g', 't' ) + + + typedef struct GX_ValueRec_ + { + FT_ULong tag; + FT_UShort outerIndex; + FT_UShort innerIndex; + + FT_Short unmodified; /* values are either FT_Short or FT_UShort */ + + } GX_ValueRec, *GX_Value; + + + /*************************************************************************/ + /* */ + /* <Struct> */ + /* GX_MVarTableRec */ + /* */ + /* <Description> */ + /* Data from the `MVAR' table. */ + /* */ + typedef struct GX_MVarTableRec_ + { + FT_UShort valueCount; + + GX_ItemVarStoreRec itemStore; /* Item Variation Store */ + GX_Value values; /* Value Records */ + + } GX_MVarTableRec, *GX_MVarTable; + + /*************************************************************************/ /* */ /* <Struct> */ @@ -68,32 +216,122 @@ FT_BEGIN_HEADER /* */ /* <Description> */ /* Data for interpolating a font from a distortable font specified */ - /* by the GX *var tables ([fgca]var). */ + /* by the GX *var tables ([fgcahvm]var). */ /* */ /* <Fields> */ - /* num_axis :: The number of axes along which interpolation */ - /* may happen */ + /* num_axis :: */ + /* The number of axes along which interpolation may happen. */ + /* */ + /* coords :: */ + /* An array of design coordinates (in user space) indicating the */ + /* contribution along each axis to the final interpolated font. */ + /* `normalizedcoords' holds the same values. */ + /* */ + /* normalizedcoords :: */ + /* An array of normalized values (between [-1,1]) indicating the */ + /* contribution along each axis to the final interpolated font. */ + /* `coords' holds the same values. */ + /* */ + /* mmvar :: */ + /* Data from the `fvar' table. */ + /* */ + /* mmvar_len :: */ + /* The length of the `mmvar' structure. */ + /* */ + /* normalized_stylecoords :: */ + /* A two-dimensional array that holds the named instance data from */ + /* `mmvar' as normalized values. */ + /* */ + /* avar_loaded :: */ + /* A Boolean; if set, FreeType tried to load (and parse) the `avar' */ + /* table. */ + /* */ + /* avar_segment :: */ + /* Data from the `avar' table. */ + /* */ + /* hvar_loaded :: */ + /* A Boolean; if set, FreeType tried to load (and parse) the `hvar' */ + /* table. */ + /* */ + /* hvar_checked :: */ + /* A Boolean; if set, FreeType successfully loaded and parsed the */ + /* `hvar' table. */ + /* */ + /* hvar_error :: */ + /* If loading and parsing of the `hvar' table failed, this field */ + /* holds the corresponding error code. */ /* */ - /* normalizedcoords :: A normalized value (between [-1,1]) indicating */ - /* the contribution along each axis to the final */ - /* interpolated font. */ + /* hvar_table :: */ + /* Data from the `hvar' table. */ + /* */ + /* vvar_loaded :: */ + /* A Boolean; if set, FreeType tried to load (and parse) the `vvar' */ + /* table. */ + /* */ + /* vvar_checked :: */ + /* A Boolean; if set, FreeType successfully loaded and parsed the */ + /* `vvar' table. */ + /* */ + /* vvar_error :: */ + /* If loading and parsing of the `vvar' table failed, this field */ + /* holds the corresponding error code. */ + /* */ + /* vvar_table :: */ + /* Data from the `vvar' table. */ + /* */ + /* mvar_table :: */ + /* Data from the `mvar' table. */ + /* */ + /* tuplecount :: */ + /* The number of shared tuples in the `gvar' table. */ + /* */ + /* tuplecoords :: */ + /* A two-dimensional array that holds the shared tuple coordinates */ + /* in the `gvar' table. */ + /* */ + /* gv_glyphcnt :: */ + /* The number of glyphs handled in the `gvar' table. */ + /* */ + /* glyphoffsets :: */ + /* Offsets into the glyph variation data array. */ + /* */ + /* gvar_size :: */ + /* The size of the `gvar' table. */ /* */ typedef struct GX_BlendRec_ { FT_UInt num_axis; + FT_Fixed* coords; FT_Fixed* normalizedcoords; FT_MM_Var* mmvar; FT_Offset mmvar_len; - FT_Bool avar_checked; - GX_AVarSegment avar_segment; + FT_Fixed* normalized_stylecoords; + /* normalized_stylecoords[num_namedstyles][num_axis] */ + + FT_Bool avar_loaded; + GX_AVarSegment avar_segment; /* avar_segment[num_axis] */ - FT_UInt tuplecount; /* shared tuples in `gvar' */ - FT_Fixed* tuplecoords; /* tuplecoords[tuplecount][num_axis] */ + FT_Bool hvar_loaded; + FT_Bool hvar_checked; + FT_Error hvar_error; + GX_HVVarTable hvar_table; + + FT_Bool vvar_loaded; + FT_Bool vvar_checked; + FT_Error vvar_error; + GX_HVVarTable vvar_table; + + GX_MVarTable mvar_table; + + FT_UInt tuplecount; + FT_Fixed* tuplecoords; /* tuplecoords[tuplecount][num_axis] */ FT_UInt gv_glyphcnt; - FT_ULong* glyphoffsets; + FT_ULong* glyphoffsets; /* glyphoffsets[gv_glyphcnt + 1] */ + + FT_ULong gvar_size; } GX_BlendRec; @@ -147,6 +385,11 @@ FT_BEGIN_HEADER FT_Fixed* coords ); FT_LOCAL( FT_Error ) + TT_Get_MM_Blend( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) TT_Set_Var_Design( TT_Face face, FT_UInt num_coords, FT_Fixed* coords ); @@ -155,6 +398,14 @@ FT_BEGIN_HEADER TT_Get_MM_Var( TT_Face face, FT_MM_Var* *master ); + FT_LOCAL( FT_Error ) + TT_Get_Var_Design( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + + FT_LOCAL( FT_Error ) + TT_Set_Named_Instance( TT_Face face, + FT_UInt instance_index ); FT_LOCAL( FT_Error ) tt_face_vary_cvt( TT_Face face, @@ -167,16 +418,36 @@ FT_BEGIN_HEADER FT_Outline* outline, FT_UInt n_points ); + FT_LOCAL( FT_Error ) + tt_hadvance_adjust( TT_Face face, + FT_UInt gindex, + FT_Int *adelta ); + + FT_LOCAL( FT_Error ) + tt_vadvance_adjust( TT_Face face, + FT_UInt gindex, + FT_Int *adelta ); + + FT_LOCAL( void ) + tt_apply_mvar( TT_Face face ); + + FT_LOCAL( FT_Error ) + tt_get_var_blend( TT_Face face, + FT_UInt *num_coords, + FT_Fixed* *coords, + FT_Fixed* *normalizedcoords, + FT_MM_Var* *mm_var ); FT_LOCAL( void ) - tt_done_blend( FT_Memory memory, - GX_Blend blend ); + tt_done_blend( TT_Face face ); + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ FT_END_HEADER -#endif /* __TTGXVAR_H__ */ +#endif /* TTGXVAR_H_ */ /* END */ diff --git a/src/3rdparty/freetype/src/truetype/ttinterp.c b/src/3rdparty/freetype/src/truetype/ttinterp.c index ae2a82adc5..da9b595aba 100644 --- a/src/3rdparty/freetype/src/truetype/ttinterp.c +++ b/src/3rdparty/freetype/src/truetype/ttinterp.c @@ -4,7 +4,7 @@ /* */ /* TrueType bytecode interpreter (body). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2018 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -25,11 +25,15 @@ #include FT_INTERNAL_CALC_H #include FT_TRIGONOMETRY_H #include FT_SYSTEM_H -#include FT_TRUETYPE_DRIVER_H +#include FT_DRIVER_H +#include FT_MULTIPLE_MASTERS_H #include "ttinterp.h" #include "tterrors.h" #include "ttsubpix.h" +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include "ttgxvar.h" +#endif #ifdef TT_USE_BYTECODE_INTERPRETER @@ -45,25 +49,31 @@ #define FT_COMPONENT trace_ttinterp - /*************************************************************************/ - /* */ - /* In order to detect infinite loops in the code, we set up a counter */ - /* within the run loop. A single stroke of interpretation is now */ - /* limited to a maximum number of opcodes defined below. */ - /* */ -#define MAX_RUNNABLE_OPCODES 1000000L - +#define NO_SUBPIXEL_HINTING \ + ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \ + TT_INTERPRETER_VERSION_35 ) -#define SUBPIXEL_HINTING \ +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY +#define SUBPIXEL_HINTING_INFINALITY \ ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \ TT_INTERPRETER_VERSION_38 ) +#endif +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL +#define SUBPIXEL_HINTING_MINIMAL \ + ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \ + TT_INTERPRETER_VERSION_40 ) +#endif -#define PROJECT( v1, v2 ) \ - exc->func_project( exc, (v1)->x - (v2)->x, (v1)->y - (v2)->y ) +#define PROJECT( v1, v2 ) \ + exc->func_project( exc, \ + SUB_LONG( (v1)->x, (v2)->x ), \ + SUB_LONG( (v1)->y, (v2)->y ) ) -#define DUALPROJ( v1, v2 ) \ - exc->func_dualproj( exc, (v1)->x - (v2)->x, (v1)->y - (v2)->y ) +#define DUALPROJ( v1, v2 ) \ + exc->func_dualproj( exc, \ + SUB_LONG( (v1)->x, (v2)->x ), \ + SUB_LONG( (v1)->y, (v2)->y ) ) #define FAST_PROJECT( v ) \ exc->func_project( exc, (v)->x, (v)->y ) @@ -74,14 +84,6 @@ /*************************************************************************/ /* */ - /* Instruction dispatch function, as used by the interpreter. */ - /* */ - typedef void (*TInstruction_Function)( TT_ExecContext exc, - FT_Long* args ); - - - /*************************************************************************/ - /* */ /* Two simple bounds-checking macros. */ /* */ #define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) ) @@ -94,20 +96,6 @@ #undef FAILURE #define FAILURE 1 -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING -#define GUESS_VECTOR( V ) \ - do \ - { \ - if ( exc->face->unpatented_hinting ) \ - { \ - exc->GS.V.x = (FT_F2Dot14)( exc->GS.both_x_axis ? 0x4000 : 0 ); \ - exc->GS.V.y = (FT_F2Dot14)( exc->GS.both_x_axis ? 0 : 0x4000 ); \ - } \ - } while (0) -#else -#define GUESS_VECTOR( V ) do { } while (0) -#endif - /*************************************************************************/ /* */ @@ -145,7 +133,7 @@ coderange = &exec->codeRangeTable[range - 1]; - FT_ASSERT( coderange->base != NULL ); + FT_ASSERT( coderange->base ); /* NOTE: Because the last instruction of a program may be a CALL */ /* which will return to the first byte *after* the code */ @@ -309,8 +297,8 @@ exec->stackSize = 0; exec->glyphSize = 0; - exec->stack = NULL; - exec->glyphIns = NULL; + exec->stack = NULL; + exec->glyphIns = NULL; exec->face = NULL; exec->size = NULL; @@ -416,8 +404,9 @@ exec->maxIDefs = size->max_instruction_defs; exec->FDefs = size->function_defs; exec->IDefs = size->instruction_defs; + exec->pointSize = size->point_size; exec->tt_metrics = size->ttmetrics; - exec->metrics = size->metrics; + exec->metrics = *size->metrics; exec->maxFunc = size->max_func; exec->maxIns = size->max_ins; @@ -438,7 +427,7 @@ /* In case of multi-threading it can happen that the old size object */ /* no longer exists, thus we must clear all glyph zone references. */ - ft_memset( &exec->zp0, 0, sizeof ( exec->zp0 ) ); + FT_ZERO( &exec->zp0 ); exec->zp1 = exec->zp0; exec->zp2 = exec->zp0; } @@ -556,10 +545,6 @@ exec->GS.freeVector = exec->GS.projVector; exec->GS.dualVector = exec->GS.projVector; -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - exec->GS.both_x_axis = TRUE; -#endif - exec->GS.round_state = 1; exec->GS.loop = 1; @@ -586,10 +571,6 @@ { 0x4000, 0 }, { 0x4000, 0 }, -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - TRUE, -#endif - 1, 64, 1, TRUE, 68, 0, 0, 9, 3, 0, FALSE, 0, 1, 1, 1 @@ -709,17 +690,17 @@ /* IUP[0] */ PACK( 0, 0 ), /* IUP[1] */ PACK( 0, 0 ), - /* SHP[0] */ PACK( 0, 0 ), - /* SHP[1] */ PACK( 0, 0 ), + /* SHP[0] */ PACK( 0, 0 ), /* loops */ + /* SHP[1] */ PACK( 0, 0 ), /* loops */ /* SHC[0] */ PACK( 1, 0 ), /* SHC[1] */ PACK( 1, 0 ), /* SHZ[0] */ PACK( 1, 0 ), /* SHZ[1] */ PACK( 1, 0 ), - /* SHPIX */ PACK( 1, 0 ), - /* IP */ PACK( 0, 0 ), + /* SHPIX */ PACK( 1, 0 ), /* loops */ + /* IP */ PACK( 0, 0 ), /* loops */ /* MSIRP[0] */ PACK( 2, 0 ), /* MSIRP[1] */ PACK( 2, 0 ), - /* AlignRP */ PACK( 0, 0 ), + /* AlignRP */ PACK( 0, 0 ), /* loops */ /* RTDG */ PACK( 0, 0 ), /* MIAP[0] */ PACK( 2, 0 ), /* MIAP[1] */ PACK( 2, 0 ), @@ -792,7 +773,7 @@ /* SANGW */ PACK( 1, 0 ), /* AA */ PACK( 1, 0 ), - /* FlipPT */ PACK( 0, 0 ), + /* FlipPT */ PACK( 0, 0 ), /* loops */ /* FlipRgON */ PACK( 2, 0 ), /* FlipRgOFF */ PACK( 2, 0 ), /* INS_$83 */ PACK( 0, 0 ), @@ -810,8 +791,8 @@ /* INS_$8F */ PACK( 0, 0 ), /* INS_$90 */ PACK( 0, 0 ), - /* INS_$91 */ PACK( 0, 0 ), - /* INS_$92 */ PACK( 0, 0 ), + /* GETVAR */ PACK( 0, 0 ), /* will be handled specially */ + /* GETDATA */ PACK( 0, 1 ), /* INS_$93 */ PACK( 0, 0 ), /* INS_$94 */ PACK( 0, 0 ), /* INS_$95 */ PACK( 0, 0 ), @@ -1093,8 +1074,13 @@ "7 INS_$8F", "7 INS_$90", +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + "6 GETVAR", + "7 GETDATA", +#else "7 INS_$91", "7 INS_$92", +#endif "7 INS_$93", "7 INS_$94", "7 INS_$95", @@ -1479,34 +1465,22 @@ { if ( !exc->tt_metrics.ratio ) { -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - if ( exc->face->unpatented_hinting ) - { - if ( exc->GS.both_x_axis ) - exc->tt_metrics.ratio = exc->tt_metrics.x_ratio; - else - exc->tt_metrics.ratio = exc->tt_metrics.y_ratio; - } - else -#endif - { - if ( exc->GS.projVector.y == 0 ) - exc->tt_metrics.ratio = exc->tt_metrics.x_ratio; + if ( exc->GS.projVector.y == 0 ) + exc->tt_metrics.ratio = exc->tt_metrics.x_ratio; - else if ( exc->GS.projVector.x == 0 ) - exc->tt_metrics.ratio = exc->tt_metrics.y_ratio; + else if ( exc->GS.projVector.x == 0 ) + exc->tt_metrics.ratio = exc->tt_metrics.y_ratio; - else - { - FT_F26Dot6 x, y; + else + { + FT_F26Dot6 x, y; - x = TT_MulFix14( exc->tt_metrics.x_ratio, - exc->GS.projVector.x ); - y = TT_MulFix14( exc->tt_metrics.y_ratio, - exc->GS.projVector.y ); - exc->tt_metrics.ratio = FT_Hypot( x, y ); - } + x = TT_MulFix14( exc->tt_metrics.x_ratio, + exc->GS.projVector.x ); + y = TT_MulFix14( exc->tt_metrics.y_ratio, + exc->GS.projVector.y ); + exc->tt_metrics.ratio = FT_Hypot( x, y ); } } return exc->tt_metrics.ratio; @@ -1604,7 +1578,7 @@ static FT_Short GetShortIns( TT_ExecContext exc ) { - /* Reading a byte stream so there is no endianess (DaveP) */ + /* Reading a byte stream so there is no endianness (DaveP) */ exc->IP += 2; return (FT_Short)( ( exc->code[exc->IP - 2] << 8 ) + exc->code[exc->IP - 1] ); @@ -1643,7 +1617,7 @@ range = &exc->codeRangeTable[aRange - 1]; - if ( range->base == NULL ) /* invalid coderange */ + if ( !range->base ) /* invalid coderange */ { exc->error = FT_THROW( Invalid_CodeRange ); return FAILURE; @@ -1685,6 +1659,10 @@ /* <InOut> */ /* zone :: The affected glyph zone. */ /* */ + /* <Note> */ + /* See `ttinterp.h' for details on backward compatibility mode. */ + /* `Touches' the point. */ + /* */ static void Direct_Move( TT_ExecContext exc, TT_GlyphZone zone, @@ -1694,20 +1672,38 @@ FT_F26Dot6 v; -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - FT_ASSERT( !exc->face->unpatented_hinting ); -#endif - v = exc->GS.freeVector.x; if ( v != 0 ) { -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( !SUBPIXEL_HINTING || +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY && ( !exc->ignore_x_mode || ( exc->sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) ) ) -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - zone->cur[point].x += FT_MulDiv( distance, v, exc->F_dot_P ); + zone->cur[point].x = ADD_LONG( zone->cur[point].x, + FT_MulDiv( distance, + v, + exc->F_dot_P ) ); + else +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Exception to the post-IUP curfew: Allow the x component of */ + /* diagonal moves, but only post-IUP. DejaVu tries to adjust */ + /* diagonal stems like on `Z' and `z' post-IUP. */ + if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility ) + zone->cur[point].x = ADD_LONG( zone->cur[point].x, + FT_MulDiv( distance, + v, + exc->F_dot_P ) ); + else +#endif + + if ( NO_SUBPIXEL_HINTING ) + zone->cur[point].x = ADD_LONG( zone->cur[point].x, + FT_MulDiv( distance, + v, + exc->F_dot_P ) ); zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; } @@ -1716,7 +1712,16 @@ if ( v != 0 ) { - zone->cur[point].y += FT_MulDiv( distance, v, exc->F_dot_P ); +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( !( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && + exc->iupy_called ) ) +#endif + zone->cur[point].y = ADD_LONG( zone->cur[point].y, + FT_MulDiv( distance, + v, + exc->F_dot_P ) ); zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; } @@ -1749,19 +1754,21 @@ FT_F26Dot6 v; -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - FT_ASSERT( !exc->face->unpatented_hinting ); -#endif - v = exc->GS.freeVector.x; if ( v != 0 ) - zone->org[point].x += FT_MulDiv( distance, v, exc->F_dot_P ); + zone->org[point].x = ADD_LONG( zone->org[point].x, + FT_MulDiv( distance, + v, + exc->F_dot_P ) ); v = exc->GS.freeVector.y; if ( v != 0 ) - zone->org[point].y += FT_MulDiv( distance, v, exc->F_dot_P ); + zone->org[point].y = ADD_LONG( zone->org[point].y, + FT_MulDiv( distance, + v, + exc->F_dot_P ) ); } @@ -1771,6 +1778,7 @@ /* */ /* The following versions are used whenever both vectors are both */ /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */ + /* See `ttinterp.h' for details on backward compatibility mode. */ /* */ /*************************************************************************/ @@ -1781,13 +1789,20 @@ FT_UShort point, FT_F26Dot6 distance ) { - FT_UNUSED( exc ); +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY && !exc->ignore_x_mode ) + zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance ); + else +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( !SUBPIXEL_HINTING || - !exc->ignore_x_mode ) -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - zone->cur[point].x += distance; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility ) + zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance ); + else +#endif + + if ( NO_SUBPIXEL_HINTING ) + zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance ); zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; } @@ -1801,8 +1816,14 @@ { FT_UNUSED( exc ); - zone->cur[point].y += distance; - zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( !( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && exc->iupy_called ) ) +#endif + zone->cur[point].y = ADD_LONG( zone->cur[point].y, distance ); + + zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; } @@ -1824,7 +1845,7 @@ { FT_UNUSED( exc ); - zone->org[point].x += distance; + zone->org[point].x = ADD_LONG( zone->org[point].x, distance ); } @@ -1836,7 +1857,7 @@ { FT_UNUSED( exc ); - zone->org[point].y += distance; + zone->org[point].y = ADD_LONG( zone->org[point].y, distance ); } @@ -1874,13 +1895,13 @@ if ( distance >= 0 ) { - val = distance + compensation; + val = ADD_LONG( distance, compensation ); if ( val < 0 ) val = 0; } else { - val = distance - compensation; + val = SUB_LONG( distance, compensation ); if ( val > 0 ) val = 0; } @@ -1916,13 +1937,14 @@ if ( distance >= 0 ) { - val = FT_PIX_ROUND( distance + compensation ); + val = FT_PIX_ROUND_LONG( ADD_LONG( distance, compensation ) ); if ( val < 0 ) val = 0; } else { - val = -FT_PIX_ROUND( compensation - distance ); + val = NEG_LONG( FT_PIX_ROUND_LONG( SUB_LONG( compensation, + distance ) ) ); if ( val > 0 ) val = 0; } @@ -1959,13 +1981,16 @@ if ( distance >= 0 ) { - val = FT_PIX_FLOOR( distance + compensation ) + 32; + val = ADD_LONG( FT_PIX_FLOOR( ADD_LONG( distance, compensation ) ), + 32 ); if ( val < 0 ) val = 32; } else { - val = -( FT_PIX_FLOOR( compensation - distance ) + 32 ); + val = NEG_LONG( ADD_LONG( FT_PIX_FLOOR( SUB_LONG( compensation, + distance ) ), + 32 ) ); if ( val > 0 ) val = -32; } @@ -2002,13 +2027,13 @@ if ( distance >= 0 ) { - val = FT_PIX_FLOOR( distance + compensation ); + val = FT_PIX_FLOOR( ADD_LONG( distance, compensation ) ); if ( val < 0 ) val = 0; } else { - val = -FT_PIX_FLOOR( compensation - distance ); + val = NEG_LONG( FT_PIX_FLOOR( SUB_LONG( compensation, distance ) ) ); if ( val > 0 ) val = 0; } @@ -2045,13 +2070,14 @@ if ( distance >= 0 ) { - val = FT_PIX_CEIL( distance + compensation ); + val = FT_PIX_CEIL_LONG( ADD_LONG( distance, compensation ) ); if ( val < 0 ) val = 0; } else { - val = -FT_PIX_CEIL( compensation - distance ); + val = NEG_LONG( FT_PIX_CEIL_LONG( SUB_LONG( compensation, + distance ) ) ); if ( val > 0 ) val = 0; } @@ -2081,20 +2107,21 @@ FT_F26Dot6 distance, FT_F26Dot6 compensation ) { - FT_F26Dot6 val; + FT_F26Dot6 val; FT_UNUSED( exc ); if ( distance >= 0 ) { - val = FT_PAD_ROUND( distance + compensation, 32 ); + val = FT_PAD_ROUND_LONG( ADD_LONG( distance, compensation ), 32 ); if ( val < 0 ) val = 0; } else { - val = -FT_PAD_ROUND( compensation - distance, 32 ); + val = NEG_LONG( FT_PAD_ROUND_LONG( SUB_LONG( compensation, distance ), + 32 ) ); if ( val > 0 ) val = 0; } @@ -2120,7 +2147,7 @@ /* Rounded distance. */ /* */ /* <Note> */ - /* The TrueType specification says very few about the relationship */ + /* The TrueType specification says very little about the relationship */ /* between rounding and engine compensation. However, it seems from */ /* the description of super round that we should add the compensation */ /* before rounding. */ @@ -2135,17 +2162,19 @@ if ( distance >= 0 ) { - val = ( distance - exc->phase + exc->threshold + compensation ) & + val = ADD_LONG( distance, + exc->threshold - exc->phase + compensation ) & -exc->period; - val += exc->phase; + val = ADD_LONG( val, exc->phase ); if ( val < 0 ) val = exc->phase; } else { - val = -( ( exc->threshold - exc->phase - distance + compensation ) & - -exc->period ); - val -= exc->phase; + val = NEG_LONG( SUB_LONG( exc->threshold - exc->phase + compensation, + distance ) & + -exc->period ); + val = SUB_LONG( val, exc->phase ); if ( val > 0 ) val = -exc->phase; } @@ -2184,17 +2213,19 @@ if ( distance >= 0 ) { - val = ( ( distance - exc->phase + exc->threshold + compensation ) / + val = ( ADD_LONG( distance, + exc->threshold - exc->phase + compensation ) / exc->period ) * exc->period; - val += exc->phase; + val = ADD_LONG( val, exc->phase ); if ( val < 0 ) val = exc->phase; } else { - val = -( ( ( exc->threshold - exc->phase - distance + compensation ) / - exc->period ) * exc->period ); - val -= exc->phase; + val = NEG_LONG( ( SUB_LONG( exc->threshold - exc->phase + compensation, + distance ) / + exc->period ) * exc->period ); + val = SUB_LONG( val, exc->phase ); if ( val > 0 ) val = -exc->phase; } @@ -2345,10 +2376,6 @@ FT_Pos dx, FT_Pos dy ) { -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - FT_ASSERT( !exc->face->unpatented_hinting ); -#endif - return TT_DotFix14( dx, dy, exc->GS.projVector.x, exc->GS.projVector.y ); @@ -2450,51 +2477,6 @@ static void Compute_Funcs( TT_ExecContext exc ) { -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - if ( exc->face->unpatented_hinting ) - { - /* If both vectors point rightwards along the x axis, set */ - /* `both-x-axis' true, otherwise set it false. The x values only */ - /* need be tested because the vector has been normalised to a unit */ - /* vector of length 0x4000 = unity. */ - exc->GS.both_x_axis = (FT_Bool)( exc->GS.projVector.x == 0x4000 && - exc->GS.freeVector.x == 0x4000 ); - - /* Throw away projection and freedom vector information */ - /* because the patents don't allow them to be stored. */ - /* The relevant US Patents are 5155805 and 5325479. */ - exc->GS.projVector.x = 0; - exc->GS.projVector.y = 0; - exc->GS.freeVector.x = 0; - exc->GS.freeVector.y = 0; - - if ( exc->GS.both_x_axis ) - { - exc->func_project = Project_x; - exc->func_move = Direct_Move_X; - exc->func_move_orig = Direct_Move_Orig_X; - } - else - { - exc->func_project = Project_y; - exc->func_move = Direct_Move_Y; - exc->func_move_orig = Direct_Move_Orig_Y; - } - - if ( exc->GS.dualVector.x == 0x4000 ) - exc->func_dualproj = Project_x; - else if ( exc->GS.dualVector.y == 0x4000 ) - exc->func_dualproj = Project_y; - else - exc->func_dualproj = Dual_Project; - - /* Force recalculation of cached aspect ratio */ - exc->tt_metrics.ratio = 0; - - return; - } -#endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING */ - if ( exc->GS.freeVector.x == 0x4000 ) exc->F_dot_P = exc->GS.projVector.x; else if ( exc->GS.freeVector.y == 0x4000 ) @@ -2634,13 +2616,20 @@ Ins_MPS( TT_ExecContext exc, FT_Long* args ) { - /* Note: The point size should be irrelevant in a given font program; */ - /* we thus decide to return only the PPEM value. */ -#if 0 - args[0] = exc->metrics.pointSize; -#else - args[0] = exc->func_cur_ppem( exc ); -#endif + if ( NO_SUBPIXEL_HINTING ) + { + /* Microsoft's GDI bytecode interpreter always returns value 12; */ + /* we return the current PPEM value instead. */ + args[0] = exc->func_cur_ppem( exc ); + } + else + { + /* A possible practical application of the MPS instruction is to */ + /* implement optical scaling and similar features, which should be */ + /* based on perceptual attributes, thus independent of the */ + /* resolution. */ + args[0] = exc->pointSize; + } } @@ -2869,7 +2858,7 @@ static void Ins_ADD( FT_Long* args ) { - args[0] += args[1]; + args[0] = ADD_LONG( args[0], args[1] ); } @@ -2882,7 +2871,7 @@ static void Ins_SUB( FT_Long* args ) { - args[0] -= args[1]; + args[0] = SUB_LONG( args[0], args[1] ); } @@ -2925,7 +2914,8 @@ static void Ins_ABS( FT_Long* args ) { - args[0] = FT_ABS( args[0] ); + if ( args[0] < 0 ) + args[0] = NEG_LONG( args[0] ); } @@ -2933,12 +2923,12 @@ /* */ /* NEG[]: NEGate */ /* Opcode range: 0x65 */ - /* Stack: f26.6 --> f26.6 */ + /* Stack: f26.6 --> f26.6 */ /* */ static void Ins_NEG( FT_Long* args ) { - args[0] = -args[0]; + args[0] = NEG_LONG( args[0] ); } @@ -2964,7 +2954,7 @@ static void Ins_CEILING( FT_Long* args ) { - args[0] = FT_PIX_CEIL( args[0] ); + args[0] = FT_PIX_CEIL_LONG( args[0] ); } @@ -2978,8 +2968,6 @@ Ins_RS( TT_ExecContext exc, FT_Long* args ) { -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - FT_ULong I = (FT_ULong)args[0]; @@ -2992,9 +2980,10 @@ } else { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY /* subpixel hinting - avoid Typeman Dstroke and */ /* IStroke and Vacuform rounds */ - if ( SUBPIXEL_HINTING && + if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode && ( ( I == 24 && ( exc->face->sph_found_func_flags & @@ -3009,25 +2998,9 @@ exc->iup_called ) ) ) args[0] = 0; else +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ args[0] = exc->storage[I]; } - -#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - - FT_ULong I = (FT_ULong)args[0]; - - - if ( BOUNDSL( I, exc->storeSize ) ) - { - if ( exc->pedantic_hinting ) - ARRAY_BOUND_ERROR; - else - args[0] = 0; - } - else - args[0] = exc->storage[I]; - -#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ } @@ -3190,7 +3163,7 @@ /*************************************************************************/ /* */ /* MAX[]: MAXimum */ - /* Opcode range: 0x68 */ + /* Opcode range: 0x8B */ /* Stack: int32? int32? --> int32 */ /* */ static void @@ -3204,7 +3177,7 @@ /*************************************************************************/ /* */ /* MIN[]: MINimum */ - /* Opcode range: 0x69 */ + /* Opcode range: 0x8C */ /* Stack: int32? int32? --> int32 */ /* */ static void @@ -3316,7 +3289,10 @@ if ( args[0] < 0 ) exc->error = FT_THROW( Bad_Argument ); else - exc->GS.loop = args[0]; + { + /* we heuristically limit the number of loops to 16 bits */ + exc->GS.loop = args[0] > 0xFFFFL ? 0xFFFFL : args[0]; + } } @@ -3448,13 +3424,27 @@ FT_Long* args ) { if ( args[0] == 0 && exc->args == 0 ) + { exc->error = FT_THROW( Bad_Argument ); + return; + } + exc->IP += args[0]; if ( exc->IP < 0 || ( exc->callTop > 0 && exc->IP > exc->callStack[exc->callTop - 1].Def->end ) ) + { exc->error = FT_THROW( Bad_Argument ); + return; + } + exc->step_ins = FALSE; + + if ( args[0] < 0 ) + { + if ( ++exc->neg_jump_counter > exc->neg_jump_counter_max ) + exc->error = FT_THROW( Execution_Too_Long ); + } } @@ -3509,7 +3499,7 @@ TT_DefRecord* rec; TT_DefRecord* limit; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY /* arguments to opcodes are skipped by `SKIP_Code' */ FT_Byte opcode_pattern[9][12] = { /* #0 inline delta function 1 */ @@ -3607,8 +3597,15 @@ FT_UShort opcode_pointer[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; FT_UShort opcode_size[9] = { 12, 8, 8, 6, 7, 4, 5, 4, 2 }; FT_UShort i; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ + + /* FDEF is only allowed in `prep' or `fpgm' */ + if ( exc->curRange == tt_coderange_glyph ) + { + exc->error = FT_THROW( DEF_In_Glyf_Bytecode ); + return; + } /* some font programs are broken enough to redefine functions! */ /* We will then parse the current table. */ @@ -3652,7 +3649,7 @@ if ( n > exc->maxFunc ) exc->maxFunc = (FT_UInt16)n; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY /* We don't know for sure these are typeman functions, */ /* however they are only active when RS 22 is called */ if ( n >= 64 && n <= 66 ) @@ -3665,9 +3662,9 @@ while ( SkipCode( exc ) == SUCCESS ) { -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING ) + if ( SUBPIXEL_HINTING_INFINALITY ) { for ( i = 0; i < opcode_patterns; i++ ) { @@ -3774,7 +3771,7 @@ ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_2 ) ); } -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ switch ( exc->opcode ) { @@ -3803,9 +3800,9 @@ TT_CallRec* pRec; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY exc->sph_in_func_flags = 0x0000; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ if ( exc->callTop <= 0 ) /* We encountered an ENDF without a call */ { @@ -3891,8 +3888,8 @@ if ( !def->active ) goto Fail; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( SUBPIXEL_HINTING && +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode && ( ( exc->iup_called && ( exc->sph_tweak_flags & SPH_TWEAK_NO_CALL_AFTER_IUP ) ) || @@ -3900,7 +3897,7 @@ goto Fail; else exc->sph_in_func_flags = def->sph_fdef_flags; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ /* check the call stack */ if ( exc->callTop >= exc->callSize ) @@ -3979,14 +3976,14 @@ if ( !def->active ) goto Fail; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( SUBPIXEL_HINTING && +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode && ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) ) goto Fail; else exc->sph_in_func_flags = def->sph_fdef_flags; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ /* check stack */ if ( exc->callTop >= exc->callSize ) @@ -4009,6 +4006,10 @@ Ins_Goto_CodeRange( exc, def->range, def->start ); exc->step_ins = FALSE; + + exc->loopcall_counter += (FT_ULong)args[0]; + if ( exc->loopcall_counter > exc->loopcall_counter_max ) + exc->error = FT_THROW( Execution_Too_Long ); } return; @@ -4032,6 +4033,13 @@ TT_DefRecord* limit; + /* we enable IDEF only in `prep' or `fpgm' */ + if ( exc->curRange == tt_coderange_glyph ) + { + exc->error = FT_THROW( DEF_In_Glyf_Bytecode ); + return; + } + /* First of all, look for the same function in our table */ def = exc->IDefs; @@ -4079,6 +4087,7 @@ exc->error = FT_THROW( Nested_DEFS ); return; case 0x2D: /* ENDF */ + def->end = exc->IP; return; } } @@ -4238,8 +4247,8 @@ p1 = exc->zp1.cur + aIdx2; p2 = exc->zp2.cur + aIdx1; - A = p1->x - p2->x; - B = p1->y - p2->y; + A = SUB_LONG( p1->x, p2->x ); + B = SUB_LONG( p1->y, p2->y ); /* If p1 == p2, SPvTL and SFvTL behave the same as */ /* SPvTCA[X] and SFvTCA[X], respectively. */ @@ -4254,9 +4263,9 @@ if ( ( opcode & 1 ) != 0 ) { - C = B; /* counter clockwise rotation */ - B = A; - A = -C; + C = B; /* counter clockwise rotation */ + B = A; + A = NEG_LONG( C ); } Normalize( A, B, Vec ); @@ -4298,16 +4307,12 @@ exc->GS.dualVector.x = AA; exc->GS.dualVector.y = BB; } - else - GUESS_VECTOR( projVector ); if ( ( opcode & 2 ) == 0 ) { exc->GS.freeVector.x = AA; exc->GS.freeVector.y = BB; } - else - GUESS_VECTOR( freeVector ); Compute_Funcs( exc ); } @@ -4329,7 +4334,6 @@ &exc->GS.projVector ) == SUCCESS ) { exc->GS.dualVector = exc->GS.projVector; - GUESS_VECTOR( freeVector ); Compute_Funcs( exc ); } } @@ -4350,7 +4354,6 @@ (FT_UShort)args[0], &exc->GS.freeVector ) == SUCCESS ) { - GUESS_VECTOR( projVector ); Compute_Funcs( exc ); } } @@ -4365,7 +4368,6 @@ static void Ins_SFVTPV( TT_ExecContext exc ) { - GUESS_VECTOR( projVector ); exc->GS.freeVector = exc->GS.projVector; Compute_Funcs( exc ); } @@ -4394,7 +4396,6 @@ Normalize( X, Y, &exc->GS.projVector ); exc->GS.dualVector = exc->GS.projVector; - GUESS_VECTOR( freeVector ); Compute_Funcs( exc ); } @@ -4420,7 +4421,6 @@ X = S; Normalize( X, Y, &exc->GS.freeVector ); - GUESS_VECTOR( projVector ); Compute_Funcs( exc ); } @@ -4435,21 +4435,8 @@ Ins_GPV( TT_ExecContext exc, FT_Long* args ) { -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - if ( exc->face->unpatented_hinting ) - { - args[0] = exc->GS.both_x_axis ? 0x4000 : 0; - args[1] = exc->GS.both_x_axis ? 0 : 0x4000; - } - else - { - args[0] = exc->GS.projVector.x; - args[1] = exc->GS.projVector.y; - } -#else args[0] = exc->GS.projVector.x; args[1] = exc->GS.projVector.y; -#endif } @@ -4463,21 +4450,8 @@ Ins_GFV( TT_ExecContext exc, FT_Long* args ) { -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - if ( exc->face->unpatented_hinting ) - { - args[0] = exc->GS.both_x_axis ? 0x4000 : 0; - args[1] = exc->GS.both_x_axis ? 0 : 0x4000; - } - else - { - args[0] = exc->GS.freeVector.x; - args[1] = exc->GS.freeVector.y; - } -#else args[0] = exc->GS.freeVector.x; args[1] = exc->GS.freeVector.y; -#endif } @@ -4597,7 +4571,7 @@ /* */ /* FLIPOFF[]: Set auto-FLIP to OFF */ /* Opcode range: 0x4E */ - /* Stack: --> */ + /* Stack: --> */ /* */ static void Ins_FLIPOFF( TT_ExecContext exc ) @@ -4832,7 +4806,7 @@ K = FAST_PROJECT( &exc->zp2.cur[L] ); - exc->func_move( exc, &exc->zp2, L, args[1] - K ); + exc->func_move( exc, &exc->zp2, L, SUB_LONG( args[1], K ) ); /* UNDOCUMENTED! The MS rasterizer does that with */ /* twilight points (confirmed by Greg Hitchcock) */ @@ -4916,13 +4890,13 @@ } } -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */ - if ( SUBPIXEL_HINTING && - exc->ignore_x_mode && - FT_ABS( D ) == 64 ) + if ( SUBPIXEL_HINTING_INFINALITY && + exc->ignore_x_mode && + FT_ABS( D ) == 64 ) D += 1; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ args[0] = D; } @@ -4956,12 +4930,12 @@ } { - FT_Vector* v1 = exc->zp1.org + p2; - FT_Vector* v2 = exc->zp2.org + p1; + FT_Vector* v1 = exc->zp1.org + p2; + FT_Vector* v2 = exc->zp2.org + p1; - A = v1->x - v2->x; - B = v1->y - v2->y; + A = SUB_LONG( v1->x, v2->x ); + B = SUB_LONG( v1->y, v2->y ); /* If v1 == v2, SDPvTL behaves the same as */ /* SVTCA[X], respectively. */ @@ -4977,9 +4951,9 @@ if ( ( opcode & 1 ) != 0 ) { - C = B; /* counter clockwise rotation */ - B = A; - A = -C; + C = B; /* counter clockwise rotation */ + B = A; + A = NEG_LONG( C ); } Normalize( A, B, &exc->GS.dualVector ); @@ -4989,8 +4963,8 @@ FT_Vector* v2 = exc->zp2.cur + p1; - A = v1->x - v2->x; - B = v1->y - v2->y; + A = SUB_LONG( v1->x, v2->x ); + B = SUB_LONG( v1->y, v2->y ); if ( A == 0 && B == 0 ) { @@ -5001,13 +4975,12 @@ if ( ( opcode & 1 ) != 0 ) { - C = B; /* counter clockwise rotation */ - B = A; - A = -C; + C = B; /* counter clockwise rotation */ + B = A; + A = NEG_LONG( C ); } Normalize( A, B, &exc->GS.projVector ); - GUESS_VECTOR( freeVector ); Compute_Funcs( exc ); } @@ -5179,12 +5152,23 @@ exc->GS.instruct_control &= ~(FT_Byte)Kf; exc->GS.instruct_control |= (FT_Byte)L; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - /* INSTCTRL modifying flag 3 also has an effect */ - /* outside of the CVT program */ if ( K == 3 ) - exc->ignore_x_mode = FT_BOOL( L == 4 ); + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + /* INSTCTRL modifying flag 3 also has an effect */ + /* outside of the CVT program */ + if ( SUBPIXEL_HINTING_INFINALITY ) + exc->ignore_x_mode = FT_BOOL( L == 4 ); #endif + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Native ClearType fonts sign a waiver that turns off all backward */ + /* compatibility hacks and lets them program points to the grid like */ + /* it's 1996. They might sign a waiver for just one glyph, though. */ + if ( SUBPIXEL_HINTING_MINIMAL ) + exc->backward_compatibility = !FT_BOOL( L == 4 ); +#endif + } } @@ -5239,14 +5223,14 @@ /* */ /* SCANTYPE[]: SCAN TYPE */ /* Opcode range: 0x8D */ - /* Stack: uint32? --> */ + /* Stack: uint16 --> */ /* */ static void Ins_SCANTYPE( TT_ExecContext exc, FT_Long* args ) { if ( args[0] >= 0 ) - exc->GS.scan_type = (FT_Int)args[0]; + exc->GS.scan_type = (FT_Int)args[0] & 0xFFFF; } @@ -5269,6 +5253,15 @@ FT_UShort point; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && + exc->iupy_called ) + goto Fail; +#endif + if ( exc->top < exc->GS.loop ) { if ( exc->pedantic_hinting ) @@ -5315,6 +5308,15 @@ FT_UShort I, K, L; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && + exc->iupy_called ) + return; +#endif + K = (FT_UShort)args[1]; L = (FT_UShort)args[0]; @@ -5344,6 +5346,15 @@ FT_UShort I, K, L; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && + exc->iupy_called ) + return; +#endif + K = (FT_UShort)args[1]; L = (FT_UShort)args[0]; @@ -5396,31 +5407,14 @@ d = PROJECT( zp.cur + p, zp.org + p ); -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - if ( exc->face->unpatented_hinting ) - { - if ( exc->GS.both_x_axis ) - { - *x = d; - *y = 0; - } - else - { - *x = 0; - *y = d; - } - } - else -#endif - { - *x = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.x, exc->F_dot_P ); - *y = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.y, exc->F_dot_P ); - } + *x = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.x, exc->F_dot_P ); + *y = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.y, exc->F_dot_P ); return SUCCESS; } + /* See `ttinterp.h' for details on backward compatibility mode. */ static void Move_Zp2_Point( TT_ExecContext exc, FT_UShort point, @@ -5428,35 +5422,28 @@ FT_F26Dot6 dy, FT_Bool touch ) { -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - if ( exc->face->unpatented_hinting ) + if ( exc->GS.freeVector.x != 0 ) { - if ( exc->GS.both_x_axis ) - { - exc->zp2.cur[point].x += dx; - if ( touch ) - exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X; - } - else - { - exc->zp2.cur[point].y += dy; - if ( touch ) - exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y; - } - return; - } +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( !( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility ) ) #endif + exc->zp2.cur[point].x = ADD_LONG( exc->zp2.cur[point].x, dx ); - if ( exc->GS.freeVector.x != 0 ) - { - exc->zp2.cur[point].x += dx; if ( touch ) exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X; } if ( exc->GS.freeVector.y != 0 ) { - exc->zp2.cur[point].y += dy; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( !( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility && + exc->iupx_called && + exc->iupy_called ) ) +#endif + exc->zp2.cur[point].y = ADD_LONG( exc->zp2.cur[point].y, dy ); + if ( touch ) exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y; } @@ -5503,13 +5490,12 @@ } } else -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY /* doesn't follow Cleartype spec but produces better result */ - if ( SUBPIXEL_HINTING && - exc->ignore_x_mode ) + if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode ) Move_Zp2_Point( exc, point, 0, dy, TRUE ); else -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ Move_Zp2_Point( exc, point, dx, dy, TRUE ); exc->GS.loop--; @@ -5637,9 +5623,15 @@ { FT_F26Dot6 dx, dy; FT_UShort point; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY FT_Int B1, B2; #endif +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + FT_Bool in_twilight = FT_BOOL( exc->GS.gep0 == 0 || + exc->GS.gep1 == 0 || + exc->GS.gep2 == 0 ); +#endif + if ( exc->top < exc->GS.loop + 1 ) @@ -5649,26 +5641,8 @@ goto Fail; } -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - if ( exc->face->unpatented_hinting ) - { - if ( exc->GS.both_x_axis ) - { - dx = (FT_UInt32)args[0]; - dy = 0; - } - else - { - dx = 0; - dy = (FT_UInt32)args[0]; - } - } - else -#endif - { - dx = TT_MulFix14( args[0], exc->GS.freeVector.x ); - dy = TT_MulFix14( args[0], exc->GS.freeVector.y ); - } + dx = TT_MulFix14( args[0], exc->GS.freeVector.x ); + dy = TT_MulFix14( args[0], exc->GS.freeVector.y ); while ( exc->GS.loop > 0 ) { @@ -5685,7 +5659,8 @@ } } else -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY ) { /* If not using ignore_x_mode rendering, allow ZP2 move. */ /* If inline deltas aren't allowed, skip ZP2 move. */ @@ -5695,8 +5670,7 @@ /* - the glyph is specifically set to allow SHPIX moves */ /* - the move is on a previously Y-touched point */ - if ( SUBPIXEL_HINTING && - exc->ignore_x_mode ) + if ( exc->ignore_x_mode ) { /* save point for later comparison */ if ( exc->GS.freeVector.y != 0 ) @@ -5719,7 +5693,11 @@ ( B1 & 63 ) != 0 && ( B2 & 63 ) != 0 && B1 != B2 ) - Move_Zp2_Point( exc, point, -dx, -dy, TRUE ); + Move_Zp2_Point( exc, + point, + NEG_LONG( dx ), + NEG_LONG( dy ), + TRUE ); } } else if ( exc->face->sph_compatibility_mode ) @@ -5751,7 +5729,7 @@ if ( ( B1 & 63 ) == 0 && ( B2 & 63 ) != 0 && B1 != B2 ) - Move_Zp2_Point( exc, point, 0, -dy, TRUE ); + Move_Zp2_Point( exc, point, 0, NEG_LONG( dy ), TRUE ); } } else if ( exc->sph_in_func_flags & SPH_FDEF_TYPEMAN_DIAGENDCTRL ) @@ -5760,15 +5738,30 @@ else Move_Zp2_Point( exc, point, dx, dy, TRUE ); } + else +#endif +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility ) + { + /* Special case: allow SHPIX to move points in the twilight zone. */ + /* Otherwise, treat SHPIX the same as DELTAP. Unbreaks various */ + /* fonts such as older versions of Rokkitt and DTL Argo T Light */ + /* that would glitch severely after calling ALIGNRP after a */ + /* blocked SHPIX. */ + if ( in_twilight || + ( !( exc->iupx_called && exc->iupy_called ) && + ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) || + ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ) ) ) + Move_Zp2_Point( exc, point, 0, dy, TRUE ); + } + else +#endif + Move_Zp2_Point( exc, point, dx, dy, TRUE ); +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY Skip: - -#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - - Move_Zp2_Point( exc, point, dx, dy, TRUE ); - -#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - +#endif exc->GS.loop--; } @@ -5788,14 +5781,14 @@ Ins_MSIRP( TT_ExecContext exc, FT_Long* args ) { - FT_UShort point; + FT_UShort point = 0; FT_F26Dot6 distance; - -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - FT_F26Dot6 control_value_cutin = 0; /* pacify compiler */ +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + FT_F26Dot6 control_value_cutin = 0; + FT_F26Dot6 delta; - if ( SUBPIXEL_HINTING ) + if ( SUBPIXEL_HINTING_INFINALITY ) { control_value_cutin = exc->GS.control_value_cutin; @@ -5804,8 +5797,7 @@ !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) ) control_value_cutin = 0; } - -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ point = (FT_UShort)args[0]; @@ -5828,16 +5820,23 @@ distance = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 ); -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + delta = SUB_LONG( distance, args[1] ); + if ( delta < 0 ) + delta = NEG_LONG( delta ); + /* subpixel hinting - make MSIRP respect CVT cut-in; */ - if ( SUBPIXEL_HINTING && - exc->ignore_x_mode && - exc->GS.freeVector.x != 0 && - FT_ABS( distance - args[1] ) >= control_value_cutin ) + if ( SUBPIXEL_HINTING_INFINALITY && + exc->ignore_x_mode && + exc->GS.freeVector.x != 0 && + delta >= control_value_cutin ) distance = args[1]; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - exc->func_move( exc, &exc->zp1, point, args[1] - distance ); + exc->func_move( exc, + &exc->zp1, + point, + SUB_LONG( args[1], distance ) ); exc->GS.rp1 = exc->GS.rp0; exc->GS.rp2 = point; @@ -5874,20 +5873,22 @@ if ( ( exc->opcode & 1 ) != 0 ) { cur_dist = FAST_PROJECT( &exc->zp0.cur[point] ); -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( SUBPIXEL_HINTING && - exc->ignore_x_mode && - exc->GS.freeVector.x != 0 ) - distance = Round_None( - exc, - cur_dist, - exc->tt_metrics.compensations[0] ) - cur_dist; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY && + exc->ignore_x_mode && + exc->GS.freeVector.x != 0 ) + distance = SUB_LONG( + Round_None( exc, + cur_dist, + exc->tt_metrics.compensations[0] ), + cur_dist ); else #endif - distance = exc->func_round( - exc, - cur_dist, - exc->tt_metrics.compensations[0] ) - cur_dist; + distance = SUB_LONG( + exc->func_round( exc, + cur_dist, + exc->tt_metrics.compensations[0] ), + cur_dist ); } else distance = 0; @@ -5920,14 +5921,14 @@ cvtEntry = (FT_ULong)args[1]; point = (FT_UShort)args[0]; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( SUBPIXEL_HINTING && +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode && exc->GS.freeVector.x != 0 && exc->GS.freeVector.y == 0 && !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) ) control_value_cutin = 0; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ if ( BOUNDS( point, exc->zp0.n_points ) || BOUNDSL( cvtEntry, exc->cvtSize ) ) @@ -5961,39 +5962,46 @@ if ( exc->GS.gep0 == 0 ) /* If in twilight zone */ { -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY /* Only adjust if not in sph_compatibility_mode or ignore_x_mode. */ /* Determined via experimentation and may be incorrect... */ - if ( !SUBPIXEL_HINTING || - ( !exc->ignore_x_mode || - !exc->face->sph_compatibility_mode ) ) -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + if ( !( SUBPIXEL_HINTING_INFINALITY && + ( exc->ignore_x_mode && + exc->face->sph_compatibility_mode ) ) ) +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ exc->zp0.org[point].x = TT_MulFix14( distance, exc->GS.freeVector.x ); exc->zp0.org[point].y = TT_MulFix14( distance, exc->GS.freeVector.y ), exc->zp0.cur[point] = exc->zp0.org[point]; } -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( SUBPIXEL_HINTING && +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode && ( exc->sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) && distance > 0 && exc->GS.freeVector.y != 0 ) distance = 0; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ org_dist = FAST_PROJECT( &exc->zp0.cur[point] ); if ( ( exc->opcode & 1 ) != 0 ) /* rounding and control cut-in flag */ { - if ( FT_ABS( distance - org_dist ) > control_value_cutin ) + FT_F26Dot6 delta; + + + delta = SUB_LONG( distance, org_dist ); + if ( delta < 0 ) + delta = NEG_LONG( delta ); + + if ( delta > control_value_cutin ) distance = org_dist; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( SUBPIXEL_HINTING && - exc->ignore_x_mode && - exc->GS.freeVector.x != 0 ) +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY && + exc->ignore_x_mode && + exc->GS.freeVector.x != 0 ) distance = Round_None( exc, distance, exc->tt_metrics.compensations[0] ); @@ -6004,7 +6012,7 @@ exc->tt_metrics.compensations[0] ); } - exc->func_move( exc, &exc->zp0, point, distance - org_dist ); + exc->func_move( exc, &exc->zp0, point, SUB_LONG( distance, org_dist ) ); Fail: exc->GS.rp0 = point; @@ -6022,19 +6030,19 @@ Ins_MDRP( TT_ExecContext exc, FT_Long* args ) { - FT_UShort point; + FT_UShort point = 0; FT_F26Dot6 org_dist, distance, minimum_distance; minimum_distance = exc->GS.minimum_distance; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( SUBPIXEL_HINTING && +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode && exc->GS.freeVector.x != 0 && !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) ) minimum_distance = 0; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ point = (FT_UShort)args[0]; @@ -6076,8 +6084,10 @@ FT_Vector vec; - vec.x = FT_MulFix( vec1->x - vec2->x, exc->metrics.x_scale ); - vec.y = FT_MulFix( vec1->y - vec2->y, exc->metrics.y_scale ); + vec.x = FT_MulFix( SUB_LONG( vec1->x, vec2->x ), + exc->metrics.x_scale ); + vec.y = FT_MulFix( SUB_LONG( vec1->y, vec2->y ), + exc->metrics.y_scale ); org_dist = FAST_DUALPROJ( &vec ); } @@ -6085,8 +6095,12 @@ /* single width cut-in test */ - if ( FT_ABS( org_dist - exc->GS.single_width_value ) < - exc->GS.single_width_cutin ) + /* |org_dist - single_width_value| < single_width_cutin */ + if ( exc->GS.single_width_cutin > 0 && + org_dist < exc->GS.single_width_value + + exc->GS.single_width_cutin && + org_dist > exc->GS.single_width_value - + exc->GS.single_width_cutin ) { if ( org_dist >= 0 ) org_dist = exc->GS.single_width_value; @@ -6098,10 +6112,10 @@ if ( ( exc->opcode & 4 ) != 0 ) { -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( SUBPIXEL_HINTING && - exc->ignore_x_mode && - exc->GS.freeVector.x != 0 ) +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY && + exc->ignore_x_mode && + exc->GS.freeVector.x != 0 ) distance = Round_None( exc, org_dist, @@ -6130,8 +6144,8 @@ } else { - if ( distance > -minimum_distance ) - distance = -minimum_distance; + if ( distance > NEG_LONG( minimum_distance ) ) + distance = NEG_LONG( minimum_distance ); } } @@ -6139,7 +6153,7 @@ org_dist = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 ); - exc->func_move( exc, &exc->zp1, point, distance - org_dist ); + exc->func_move( exc, &exc->zp1, point, SUB_LONG( distance, org_dist ) ); Fail: exc->GS.rp1 = exc->GS.rp0; @@ -6169,25 +6183,25 @@ org_dist, control_value_cutin, minimum_distance; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY FT_Int B1 = 0; /* pacify compiler */ FT_Int B2 = 0; FT_Bool reverse_move = FALSE; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ minimum_distance = exc->GS.minimum_distance; control_value_cutin = exc->GS.control_value_cutin; point = (FT_UShort)args[0]; - cvtEntry = (FT_ULong)( args[1] + 1 ); + cvtEntry = (FT_ULong)( ADD_LONG( args[1], 1 ) ); -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( SUBPIXEL_HINTING && +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode && exc->GS.freeVector.x != 0 && !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) ) control_value_cutin = minimum_distance = 0; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */ @@ -6240,8 +6254,8 @@ cvt_dist = -cvt_dist; } -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( SUBPIXEL_HINTING && +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode && exc->GS.freeVector.y != 0 && ( exc->sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) ) @@ -6251,7 +6265,7 @@ else if ( cur_dist > 64 && cur_dist < 84 ) cvt_dist += 32; } -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ /* control value cut-in and round */ @@ -6262,6 +6276,9 @@ if ( exc->GS.gep0 == exc->GS.gep1 ) { + FT_F26Dot6 delta; + + /* XXX: According to Greg Hitchcock, the following wording is */ /* the right one: */ /* */ @@ -6274,7 +6291,11 @@ /* `ttinst2.doc', version 1.66, is thus incorrect since */ /* it implies `>=' instead of `>'. */ - if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin ) + delta = SUB_LONG( cvt_dist, org_dist ); + if ( delta < 0 ) + delta = NEG_LONG( delta ); + + if ( delta > control_value_cutin ) cvt_dist = org_dist; } @@ -6286,16 +6307,23 @@ else { -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY /* do cvt cut-in always in MIRP for sph */ - if ( SUBPIXEL_HINTING && + if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode && exc->GS.gep0 == exc->GS.gep1 ) { - if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin ) + FT_F26Dot6 delta; + + + delta = SUB_LONG( cvt_dist, org_dist ); + if ( delta < 0 ) + delta = NEG_LONG( delta ); + + if ( delta > control_value_cutin ) cvt_dist = org_dist; } -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ distance = Round_None( exc, @@ -6314,13 +6342,13 @@ } else { - if ( distance > -minimum_distance ) - distance = -minimum_distance; + if ( distance > NEG_LONG( minimum_distance ) ) + distance = NEG_LONG( minimum_distance ); } } -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( SUBPIXEL_HINTING ) +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY ) { B1 = exc->zp1.cur[point].y; @@ -6337,12 +6365,15 @@ ( exc->sph_tweak_flags & SPH_TWEAK_COURIER_NEW_2_HACK ) ) distance += 64; } -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - exc->func_move( exc, &exc->zp1, point, distance - cur_dist ); + exc->func_move( exc, + &exc->zp1, + point, + SUB_LONG( distance, cur_dist ) ); -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( SUBPIXEL_HINTING ) +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY ) { B2 = exc->zp1.cur[point].y; @@ -6363,10 +6394,13 @@ } if ( reverse_move ) - exc->func_move( exc, &exc->zp1, point, -( distance - cur_dist ) ); + exc->func_move( exc, + &exc->zp1, + point, + SUB_LONG( cur_dist, distance ) ); } -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ Fail: exc->GS.rp1 = exc->GS.rp0; @@ -6391,8 +6425,8 @@ FT_F26Dot6 distance; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( SUBPIXEL_HINTING && +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode && exc->iup_called && ( exc->sph_tweak_flags & SPH_TWEAK_NO_ALIGNRP_AFTER_IUP ) ) @@ -6400,7 +6434,7 @@ exc->error = FT_THROW( Invalid_Reference ); goto Fail; } -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ if ( exc->top < exc->GS.loop || BOUNDS( exc->GS.rp0, exc->zp0.n_points ) ) @@ -6429,7 +6463,7 @@ distance = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 ); - exc->func_move( exc, &exc->zp1, point, -distance ); + exc->func_move( exc, &exc->zp1, point, NEG_LONG( distance ) ); } exc->GS.loop--; @@ -6486,19 +6520,19 @@ /* Cramer's rule */ - dbx = exc->zp0.cur[b1].x - exc->zp0.cur[b0].x; - dby = exc->zp0.cur[b1].y - exc->zp0.cur[b0].y; + dbx = SUB_LONG( exc->zp0.cur[b1].x, exc->zp0.cur[b0].x ); + dby = SUB_LONG( exc->zp0.cur[b1].y, exc->zp0.cur[b0].y ); - dax = exc->zp1.cur[a1].x - exc->zp1.cur[a0].x; - day = exc->zp1.cur[a1].y - exc->zp1.cur[a0].y; + dax = SUB_LONG( exc->zp1.cur[a1].x, exc->zp1.cur[a0].x ); + day = SUB_LONG( exc->zp1.cur[a1].y, exc->zp1.cur[a0].y ); - dx = exc->zp0.cur[b0].x - exc->zp1.cur[a0].x; - dy = exc->zp0.cur[b0].y - exc->zp1.cur[a0].y; + dx = SUB_LONG( exc->zp0.cur[b0].x, exc->zp1.cur[a0].x ); + dy = SUB_LONG( exc->zp0.cur[b0].y, exc->zp1.cur[a0].y ); - discriminant = FT_MulDiv( dax, -dby, 0x40 ) + - FT_MulDiv( day, dbx, 0x40 ); - dotproduct = FT_MulDiv( dax, dbx, 0x40 ) + - FT_MulDiv( day, dby, 0x40 ); + discriminant = ADD_LONG( FT_MulDiv( dax, NEG_LONG( dby ), 0x40 ), + FT_MulDiv( day, dbx, 0x40 ) ); + dotproduct = ADD_LONG( FT_MulDiv( dax, dbx, 0x40 ), + FT_MulDiv( day, dby, 0x40 ) ); /* The discriminant above is actually a cross product of vectors */ /* da and db. Together with the dot product, they can be used as */ @@ -6508,28 +6542,29 @@ /* discriminant = |da||db|sin(angle) . */ /* We use these equations to reject grazing intersections by */ /* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */ - if ( 19 * FT_ABS( discriminant ) > FT_ABS( dotproduct ) ) + if ( MUL_LONG( 19, FT_ABS( discriminant ) ) > FT_ABS( dotproduct ) ) { - val = FT_MulDiv( dx, -dby, 0x40 ) + FT_MulDiv( dy, dbx, 0x40 ); + val = ADD_LONG( FT_MulDiv( dx, NEG_LONG( dby ), 0x40 ), + FT_MulDiv( dy, dbx, 0x40 ) ); R.x = FT_MulDiv( val, dax, discriminant ); R.y = FT_MulDiv( val, day, discriminant ); - exc->zp2.cur[point].x = exc->zp1.cur[a0].x + R.x; - exc->zp2.cur[point].y = exc->zp1.cur[a0].y + R.y; + /* XXX: Block in backward_compatibility and/or post-IUP? */ + exc->zp2.cur[point].x = ADD_LONG( exc->zp1.cur[a0].x, R.x ); + exc->zp2.cur[point].y = ADD_LONG( exc->zp1.cur[a0].y, R.y ); } else { /* else, take the middle of the middles of A and B */ - exc->zp2.cur[point].x = ( exc->zp1.cur[a0].x + - exc->zp1.cur[a1].x + - exc->zp0.cur[b0].x + - exc->zp0.cur[b1].x ) / 4; - exc->zp2.cur[point].y = ( exc->zp1.cur[a0].y + - exc->zp1.cur[a1].y + - exc->zp0.cur[b0].y + - exc->zp0.cur[b1].y ) / 4; + /* XXX: Block in backward_compatibility and/or post-IUP? */ + exc->zp2.cur[point].x = + ADD_LONG( ADD_LONG( exc->zp1.cur[a0].x, exc->zp1.cur[a1].x ), + ADD_LONG( exc->zp0.cur[b0].x, exc->zp0.cur[b1].x ) ) / 4; + exc->zp2.cur[point].y = + ADD_LONG( ADD_LONG( exc->zp1.cur[a0].y, exc->zp1.cur[a1].y ), + ADD_LONG( exc->zp0.cur[b0].y, exc->zp0.cur[b1].y ) ) / 4; } exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH; @@ -6564,7 +6599,7 @@ distance = PROJECT( exc->zp0.cur + p2, exc->zp1.cur + p1 ) / 2; exc->func_move( exc, &exc->zp1, p1, distance ); - exc->func_move( exc, &exc->zp0, p2, -distance ); + exc->func_move( exc, &exc->zp0, p2, NEG_LONG( distance ) ); } @@ -6598,7 +6633,9 @@ * Otherwise, by definition, the value of exc->twilight.orus[n] is (0,0), * for every n. */ - twilight = exc->GS.gep0 == 0 || exc->GS.gep1 == 0 || exc->GS.gep2 == 0; + twilight = ( exc->GS.gep0 == 0 || + exc->GS.gep1 == 0 || + exc->GS.gep2 == 0 ); if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) ) { @@ -6635,9 +6672,11 @@ FT_Vector vec; - vec.x = FT_MulFix( exc->zp1.orus[exc->GS.rp2].x - orus_base->x, + vec.x = FT_MulFix( SUB_LONG( exc->zp1.orus[exc->GS.rp2].x, + orus_base->x ), exc->metrics.x_scale ); - vec.y = FT_MulFix( exc->zp1.orus[exc->GS.rp2].y - orus_base->y, + vec.y = FT_MulFix( SUB_LONG( exc->zp1.orus[exc->GS.rp2].y, + orus_base->y ), exc->metrics.y_scale ); old_range = FAST_DUALPROJ( &vec ); @@ -6646,7 +6685,7 @@ cur_range = PROJECT( &exc->zp1.cur[exc->GS.rp2], cur_base ); } - for ( ; exc->GS.loop > 0; --exc->GS.loop ) + for ( ; exc->GS.loop > 0; exc->GS.loop-- ) { FT_UInt point = (FT_UInt)exc->stack[--exc->args]; FT_F26Dot6 org_dist, cur_dist, new_dist; @@ -6672,9 +6711,11 @@ FT_Vector vec; - vec.x = FT_MulFix( exc->zp2.orus[point].x - orus_base->x, + vec.x = FT_MulFix( SUB_LONG( exc->zp2.orus[point].x, + orus_base->x ), exc->metrics.x_scale ); - vec.y = FT_MulFix( exc->zp2.orus[point].y - orus_base->y, + vec.y = FT_MulFix( SUB_LONG( exc->zp2.orus[point].y, + orus_base->y ), exc->metrics.y_scale ); org_dist = FAST_DUALPROJ( &vec ); @@ -6713,7 +6754,7 @@ exc->func_move( exc, &exc->zp2, (FT_UShort)point, - new_dist - cur_dist ); + SUB_LONG( new_dist, cur_dist ) ); } Fail: @@ -6778,14 +6819,14 @@ FT_F26Dot6 dx; - dx = worker->curs[p].x - worker->orgs[p].x; + dx = SUB_LONG( worker->curs[p].x, worker->orgs[p].x ); if ( dx != 0 ) { for ( i = p1; i < p; i++ ) - worker->curs[i].x += dx; + worker->curs[i].x = ADD_LONG( worker->curs[i].x, dx ); for ( i = p + 1; i <= p2; i++ ) - worker->curs[i].x += dx; + worker->curs[i].x = ADD_LONG( worker->curs[i].x, dx ); } } @@ -6830,8 +6871,8 @@ org2 = worker->orgs[ref2].x; cur1 = worker->curs[ref1].x; cur2 = worker->curs[ref2].x; - delta1 = cur1 - org1; - delta2 = cur2 - org2; + delta1 = SUB_LONG( cur1, org1 ); + delta2 = SUB_LONG( cur2, org2 ); if ( cur1 == cur2 || orus1 == orus2 ) { @@ -6843,10 +6884,10 @@ if ( x <= org1 ) - x += delta1; + x = ADD_LONG( x, delta1 ); else if ( x >= org2 ) - x += delta2; + x = ADD_LONG( x, delta2 ); else x = cur1; @@ -6867,20 +6908,23 @@ if ( x <= org1 ) - x += delta1; + x = ADD_LONG( x, delta1 ); else if ( x >= org2 ) - x += delta2; + x = ADD_LONG( x, delta2 ); else { if ( !scale_valid ) { scale_valid = 1; - scale = FT_DivFix( cur2 - cur1, orus2 - orus1 ); + scale = FT_DivFix( SUB_LONG( cur2, cur1 ), + SUB_LONG( orus2, orus1 ) ); } - x = cur1 + FT_MulFix( worker->orus[i].x - orus1, scale ); + x = ADD_LONG( cur1, + FT_MulFix( SUB_LONG( worker->orus[i].x, orus1 ), + scale ) ); } worker->curs[i].x = x; } @@ -6910,6 +6954,23 @@ FT_Short contour; /* current contour */ +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + /* Allow IUP until it has been called on both axes. Immediately */ + /* return on subsequent ones. */ + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility ) + { + if ( exc->iupx_called && exc->iupy_called ) + return; + + if ( exc->opcode & 1 ) + exc->iupx_called = TRUE; + else + exc->iupy_called = TRUE; + } +#endif + /* ignore empty outlines */ if ( exc->pts.n_contours == 0 ) return; @@ -6933,15 +6994,15 @@ contour = 0; point = 0; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( SUBPIXEL_HINTING && - exc->ignore_x_mode ) +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + if ( SUBPIXEL_HINTING_INFINALITY && + exc->ignore_x_mode ) { exc->iup_called = TRUE; if ( exc->sph_tweak_flags & SPH_TWEAK_SKIP_IUP ) return; } -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ do { @@ -7013,37 +7074,16 @@ FT_UShort A; FT_ULong C, P; FT_Long B; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY FT_UShort B1, B2; - if ( SUBPIXEL_HINTING && + if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode && exc->iup_called && ( exc->sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) ) goto Fail; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - - -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - /* Delta hinting is covered by US Patent 5159668. */ - if ( exc->face->unpatented_hinting ) - { - FT_Long n = args[0] * 2; - - - if ( exc->args < n ) - { - if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Too_Few_Arguments ); - n = exc->args; - } - - exc->args -= n; - exc->new_top = exc->args; - return; - } -#endif +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ P = (FT_ULong)exc->func_cur_ppem( exc ); nump = (FT_ULong)args[0]; /* some points theoretically may occur more @@ -7097,9 +7137,9 @@ B++; B *= 1L << ( 6 - exc->GS.delta_shift ); -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING ) + if ( SUBPIXEL_HINTING_INFINALITY ) { /* * Allow delta move if @@ -7152,13 +7192,29 @@ SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP ) && ( B1 & 63 ) != 0 && ( B2 & 63 ) != 0 ) ) ) - exc->func_move( exc, &exc->zp0, A, -B ); + exc->func_move( exc, &exc->zp0, A, NEG_LONG( B ) ); } } else -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - exc->func_move( exc, &exc->zp0, A, B ); + { + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility */ + /* mode. */ + if ( SUBPIXEL_HINTING_MINIMAL && + exc->backward_compatibility ) + { + if ( !( exc->iupx_called && exc->iupy_called ) && + ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) || + ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) ) ) + exc->func_move( exc, &exc->zp0, A, B ); + } + else +#endif + exc->func_move( exc, &exc->zp0, A, B ); + } } } else @@ -7186,26 +7242,6 @@ FT_Long B; -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - /* Delta hinting is covered by US Patent 5159668. */ - if ( exc->face->unpatented_hinting ) - { - FT_Long n = args[0] * 2; - - - if ( exc->args < n ) - { - if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Too_Few_Arguments ); - n = exc->args; - } - - exc->args -= n; - exc->new_top = exc->args; - return; - } -#endif - P = (FT_ULong)exc->func_cur_ppem( exc ); nump = (FT_ULong)args[0]; @@ -7294,24 +7330,25 @@ Ins_GETINFO( TT_ExecContext exc, FT_Long* args ) { - FT_Long K; + FT_Long K; + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( exc->face ); K = 0; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY /********************************/ /* RASTERIZER VERSION */ /* Selector Bit: 0 */ /* Return Bit(s): 0-7 */ /* */ - if ( SUBPIXEL_HINTING && - ( args[0] & 1 ) != 0 && - exc->subpixel_hinting ) + if ( SUBPIXEL_HINTING_INFINALITY && + ( args[0] & 1 ) != 0 && + exc->subpixel_hinting ) { if ( exc->ignore_x_mode ) { - /* if in ClearType backwards compatibility mode, */ + /* if in ClearType backward compatibility mode, */ /* we sometimes change the TrueType version dynamically */ K = exc->rasterizer_version; FT_TRACE6(( "Setting rasterizer version %d\n", @@ -7321,9 +7358,9 @@ K = TT_INTERPRETER_VERSION_38; } else -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ if ( ( args[0] & 1 ) != 0 ) - K = TT_INTERPRETER_VERSION_35; + K = driver->interpreter_version; /********************************/ /* GLYPH ROTATED */ @@ -7331,7 +7368,7 @@ /* Return Bit(s): 8 */ /* */ if ( ( args[0] & 2 ) != 0 && exc->tt_metrics.rotated ) - K |= 0x80; + K |= 1 << 8; /********************************/ /* GLYPH STRETCHED */ @@ -7339,19 +7376,87 @@ /* Return Bit(s): 9 */ /* */ if ( ( args[0] & 4 ) != 0 && exc->tt_metrics.stretched ) - K |= 1 << 8; + K |= 1 << 9; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /********************************/ + /* VARIATION GLYPH */ + /* Selector Bit: 3 */ + /* Return Bit(s): 10 */ + /* */ + /* XXX: UNDOCUMENTED! */ + if ( (args[0] & 8 ) != 0 && exc->face->blend ) + K |= 1 << 10; +#endif /********************************/ - /* HINTING FOR GRAYSCALE */ + /* BI-LEVEL HINTING AND */ + /* GRAYSCALE RENDERING */ /* Selector Bit: 5 */ /* Return Bit(s): 12 */ /* */ if ( ( args[0] & 32 ) != 0 && exc->grayscale ) K |= 1 << 12; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Toggle the following flags only outside of monochrome mode. */ + /* Otherwise, instructions may behave weirdly and rendering results */ + /* may differ between v35 and v40 mode, e.g., in `Times New Roman */ + /* Bold Italic'. */ + if ( SUBPIXEL_HINTING_MINIMAL && exc->subpixel_hinting_lean ) + { + /********************************/ + /* HINTING FOR SUBPIXEL */ + /* Selector Bit: 6 */ + /* Return Bit(s): 13 */ + /* */ + /* v40 does subpixel hinting by default. */ + if ( ( args[0] & 64 ) != 0 ) + K |= 1 << 13; + + /********************************/ + /* VERTICAL LCD SUBPIXELS? */ + /* Selector Bit: 8 */ + /* Return Bit(s): 15 */ + /* */ + if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd_lean ) + K |= 1 << 15; + + /********************************/ + /* SUBPIXEL POSITIONED? */ + /* Selector Bit: 10 */ + /* Return Bit(s): 17 */ + /* */ + /* XXX: FreeType supports it, dependent on what client does? */ + if ( ( args[0] & 1024 ) != 0 ) + K |= 1 << 17; + + /********************************/ + /* SYMMETRICAL SMOOTHING */ + /* Selector Bit: 11 */ + /* Return Bit(s): 18 */ + /* */ + /* The only smoothing method FreeType supports unless someone sets */ + /* FT_LOAD_TARGET_MONO. */ + if ( ( args[0] & 2048 ) != 0 && exc->subpixel_hinting_lean ) + K |= 1 << 18; + + /********************************/ + /* CLEARTYPE HINTING AND */ + /* GRAYSCALE RENDERING */ + /* Selector Bit: 12 */ + /* Return Bit(s): 19 */ + /* */ + /* Grayscale rendering is what FreeType does anyway unless someone */ + /* sets FT_LOAD_TARGET_MONO or FT_LOAD_TARGET_LCD(_V) */ + if ( ( args[0] & 4096 ) != 0 && exc->grayscale_cleartype ) + K |= 1 << 19; + } +#endif - if ( SUBPIXEL_HINTING && +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + + if ( SUBPIXEL_HINTING_INFINALITY && exc->rasterizer_version >= TT_INTERPRETER_VERSION_35 ) { @@ -7424,12 +7529,71 @@ } } -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ args[0] = K; } +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + /*************************************************************************/ + /* */ + /* GETVARIATION[]: get normalized variation (blend) coordinates */ + /* Opcode range: 0x91 */ + /* Stack: --> f2.14... */ + /* */ + /* XXX: UNDOCUMENTED! There is no official documentation from Apple for */ + /* this bytecode instruction. Active only if a font has GX */ + /* variation axes. */ + /* */ + static void + Ins_GETVARIATION( TT_ExecContext exc, + FT_Long* args ) + { + FT_UInt num_axes = exc->face->blend->num_axis; + FT_Fixed* coords = exc->face->blend->normalizedcoords; + + FT_UInt i; + + + if ( BOUNDS( num_axes, exc->stackSize + 1 - exc->top ) ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + + if ( coords ) + { + for ( i = 0; i < num_axes; i++ ) + args[i] = coords[i] >> 2; /* convert 16.16 to 2.14 format */ + } + else + { + for ( i = 0; i < num_axes; i++ ) + args[i] = 0; + } + } + + + /*************************************************************************/ + /* */ + /* GETDATA[]: no idea what this is good for */ + /* Opcode range: 0x92 */ + /* Stack: --> 17 */ + /* */ + /* XXX: UNDOCUMENTED! There is no documentation from Apple for this */ + /* very weird bytecode instruction. */ + /* */ + static void + Ins_GETDATA( FT_Long* args ) + { + args[0] = 17; + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + static void Ins_UNKNOWN( TT_ExecContext exc ) { @@ -7503,10 +7667,11 @@ FT_EXPORT_DEF( FT_Error ) TT_RunIns( TT_ExecContext exc ) { - FT_Long ins_counter = 0; /* executed instructions counter */ + FT_ULong ins_counter = 0; /* executed instructions counter */ + FT_ULong num_twilight_points; FT_UShort i; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY FT_Byte opcode_pattern[1][2] = { /* #8 TypeMan Talk Align */ { @@ -7517,12 +7682,88 @@ FT_UShort opcode_patterns = 1; FT_UShort opcode_pointer[1] = { 0 }; FT_UShort opcode_size[1] = { 1 }; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY exc->iup_called = FALSE; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* + * Toggle backward compatibility according to what font wants, except + * when + * + * 1) we have a `tricky' font that heavily relies on the interpreter to + * render glyphs correctly, for example DFKai-SB, or + * 2) FT_RENDER_MODE_MONO (i.e, monochome rendering) is requested. + * + * In those cases, backward compatibility needs to be turned off to get + * correct rendering. The rendering is then completely up to the + * font's programming. + * + */ + if ( SUBPIXEL_HINTING_MINIMAL && + exc->subpixel_hinting_lean && + !FT_IS_TRICKY( &exc->face->root ) ) + exc->backward_compatibility = !( exc->GS.instruct_control & 4 ); + else + exc->backward_compatibility = FALSE; + + exc->iupx_called = FALSE; + exc->iupy_called = FALSE; +#endif + + /* We restrict the number of twilight points to a reasonable, */ + /* heuristic value to avoid slow execution of malformed bytecode. */ + num_twilight_points = FT_MAX( 30, + 2 * ( exc->pts.n_points + exc->cvtSize ) ); + if ( exc->twilight.n_points > num_twilight_points ) + { + if ( num_twilight_points > 0xFFFFU ) + num_twilight_points = 0xFFFFU; + + FT_TRACE5(( "TT_RunIns: Resetting number of twilight points\n" + " from %d to the more reasonable value %d\n", + exc->twilight.n_points, + num_twilight_points )); + exc->twilight.n_points = (FT_UShort)num_twilight_points; + } + + /* Set up loop detectors. We restrict the number of LOOPCALL loops */ + /* and the number of JMPR, JROT, and JROF calls with a negative */ + /* argument to values that depend on various parameters like the */ + /* size of the CVT table or the number of points in the current */ + /* glyph (if applicable). */ + /* */ + /* The idea is that in real-world bytecode you either iterate over */ + /* all CVT entries (in the `prep' table), or over all points (or */ + /* contours, in the `glyf' table) of a glyph, and such iterations */ + /* don't happen very often. */ + exc->loopcall_counter = 0; + exc->neg_jump_counter = 0; + + /* The maximum values are heuristic. */ + if ( exc->pts.n_points ) + exc->loopcall_counter_max = FT_MAX( 50, + 10 * exc->pts.n_points ) + + FT_MAX( 50, + exc->cvtSize / 10 ); + else + exc->loopcall_counter_max = 300 + 8 * exc->cvtSize; + + /* as a protection against an unreasonable number of CVT entries */ + /* we assume at most 100 control values per glyph for the counter */ + if ( exc->loopcall_counter_max > + 100 * (FT_ULong)exc->face->root.num_glyphs ) + exc->loopcall_counter_max = 100 * (FT_ULong)exc->face->root.num_glyphs; + + FT_TRACE5(( "TT_RunIns: Limiting total number of loops in LOOPCALL" + " to %d\n", exc->loopcall_counter_max )); + + exc->neg_jump_counter_max = exc->loopcall_counter_max; + FT_TRACE5(( "TT_RunIns: Limiting total number of backward jumps" + " to %d\n", exc->neg_jump_counter_max )); /* set PPEM and CVT functions */ exc->tt_metrics.ratio = 0; @@ -7565,7 +7806,7 @@ ? 2 : 12 - ( *opcode_name[exc->opcode] - '0' ), "#" )); - for ( n = 0; n < cnt; n++ ) + for ( n = 1; n <= cnt; n++ ) FT_TRACE7(( " %d", exc->stack[exc->top - n] )); FT_TRACE6(( "\n" )); } @@ -7601,7 +7842,21 @@ exc->args = 0; } - exc->new_top = exc->args + ( Pop_Push_Count[exc->opcode] & 15 ); +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( exc->opcode == 0x91 ) + { + /* this is very special: GETVARIATION returns */ + /* a variable number of arguments */ + + /* it is the job of the application to `activate' GX handling, */ + /* this is, calling any of the GX API functions on the current */ + /* font to select a variation instance */ + if ( exc->face->blend ) + exc->new_top = exc->args + exc->face->blend->num_axis; + } + else +#endif + exc->new_top = exc->args + ( Pop_Push_Count[exc->opcode] & 15 ); /* `new_top' is the new top of the stack, after the instruction's */ /* execution. `top' will be set to `new_top' after the `switch' */ @@ -7615,9 +7870,9 @@ exc->step_ins = TRUE; exc->error = FT_Err_Ok; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING ) + if ( SUBPIXEL_HINTING_INFINALITY ) { for ( i = 0; i < opcode_patterns; i++ ) { @@ -7646,7 +7901,7 @@ } } -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ { FT_Long* args = exc->stack + exc->args; @@ -7794,7 +8049,7 @@ Ins_ALIGNPTS( exc, args ); break; - case 0x28: /* ???? */ + case 0x28: /* RAW */ Ins_UNKNOWN( exc ); break; @@ -8146,10 +8401,33 @@ Ins_INSTCTRL( exc, args ); break; - case 0x8F: + case 0x8F: /* ADJUST */ + case 0x90: /* ADJUST */ Ins_UNKNOWN( exc ); break; +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + case 0x91: + /* it is the job of the application to `activate' GX handling, */ + /* this is, calling any of the GX API functions on the current */ + /* font to select a variation instance */ + if ( exc->face->blend ) + Ins_GETVARIATION( exc, args ); + else + Ins_UNKNOWN( exc ); + break; + + case 0x92: + /* there is at least one MS font (LaoUI.ttf version 5.01) that */ + /* uses IDEFs for 0x91 and 0x92; for this reason we activate */ + /* GETDATA for GX fonts only, similar to GETVARIATION */ + if ( exc->face->blend ) + Ins_GETDATA( args ); + else + Ins_UNKNOWN( exc ); + break; +#endif + default: if ( opcode >= 0xE0 ) Ins_MIRP( exc, args ); @@ -8230,7 +8508,7 @@ /* increment instruction counter and check if we didn't */ /* run this program for too long (e.g. infinite loops). */ - if ( ++ins_counter > MAX_RUNNABLE_OPCODES ) + if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES ) return FT_THROW( Execution_Too_Long ); LSuiteLabel_: @@ -8247,29 +8525,27 @@ } while ( !exc->instruction_trap ); LNo_Error_: + FT_TRACE4(( " %d instruction%s executed\n", + ins_counter, + ins_counter == 1 ? "" : "s" )); return FT_Err_Ok; LErrorCodeOverflow_: exc->error = FT_THROW( Code_Overflow ); LErrorLabel_: - /* If any errors have occurred, function tables may be broken. */ - /* Force a re-execution of `prep' and `fpgm' tables if no */ - /* bytecode debugger is run. */ - if ( exc->error && - !exc->instruction_trap && - exc->curRange == tt_coderange_glyph ) - { + if ( exc->error && !exc->instruction_trap ) FT_TRACE1(( " The interpreter returned error 0x%x\n", exc->error )); - exc->size->bytecode_ready = -1; - exc->size->cvt_ready = -1; - } return exc->error; } +#else /* !TT_USE_BYTECODE_INTERPRETER */ + + /* ANSI C doesn't like empty source files */ + typedef int _tt_interp_dummy; -#endif /* TT_USE_BYTECODE_INTERPRETER */ +#endif /* !TT_USE_BYTECODE_INTERPRETER */ /* END */ diff --git a/src/3rdparty/freetype/src/truetype/ttinterp.h b/src/3rdparty/freetype/src/truetype/ttinterp.h index 32706d0760..2966439ea2 100644 --- a/src/3rdparty/freetype/src/truetype/ttinterp.h +++ b/src/3rdparty/freetype/src/truetype/ttinterp.h @@ -4,7 +4,7 @@ /* */ /* TrueType bytecode interpreter (specification). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2018 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,8 +16,8 @@ /***************************************************************************/ -#ifndef __TTINTERP_H__ -#define __TTINTERP_H__ +#ifndef TTINTERP_H_ +#define TTINTERP_H_ #include <ft2build.h> #include "ttobjs.h" @@ -99,7 +99,7 @@ FT_BEGIN_HEADER } TT_CallRec, *TT_CallStack; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY /*************************************************************************/ /* */ @@ -138,7 +138,7 @@ FT_BEGIN_HEADER } SPH_Font_Class; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ /*************************************************************************/ @@ -170,6 +170,7 @@ FT_BEGIN_HEADER pts, twilight; + FT_Long pointSize; /* in 26.6 format */ FT_Size_Metrics metrics; TT_Size_Metrics tt_metrics; /* size metrics */ @@ -247,9 +248,151 @@ FT_BEGIN_HEADER TT_Set_CVT_Func func_write_cvt; /* write a cvt entry (in pixels) */ TT_Set_CVT_Func func_move_cvt; /* incr a cvt entry (in pixels) */ - FT_Bool grayscale; /* are we hinting for grayscale? */ - -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + FT_Bool grayscale; /* bi-level hinting and */ + /* grayscale rendering */ + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* + * FreeType supports ClearType-like hinting of TrueType fonts through + * the version 40 interpreter. This is achieved through several hacks + * in the base (v35) interpreter, as detailed below. + * + * ClearType is an umbrella term for several rendering techniques + * employed by Microsoft's various GUI and rendering toolkit + * implementations, most importantly: subpixel rendering for using the + * RGB subpixels of LCDs to approximately triple the perceived + * resolution on the x-axis and subpixel hinting for positioning stems + * on subpixel borders. TrueType programming is explicit, i.e., fonts + * must be programmed to take advantage of ClearType's possibilities. + * + * When ClearType was introduced, it seemed unlikely that all fonts + * would be reprogrammed, so Microsoft decided to implement a backward + * compatibility mode. It employs several simple to complicated + * assumptions and tricks, many of them font-dependent, that modify the + * interpretation of the bytecode contained in these fonts to retrofit + * them into a ClearType-y look. The quality of the results varies. + * Most (web)fonts that were released since then have come to rely on + * these hacks to render correctly, even some of Microsoft's flagship + * fonts (e.g., Calibri, Cambria, Segoe UI). + * + * FreeType's minimal subpixel hinting code (interpreter version 40) + * employs a small list of font-agnostic hacks loosely based on the + * public information available on Microsoft's compatibility mode[2]. + * The focus is on modern (web)fonts rather than legacy fonts that were + * made for monochrome rendering. It will not match ClearType rendering + * exactly. Unlike the `Infinality' code (interpreter version 38) that + * came before, it will not try to toggle hacks for specific fonts for + * performance and complexity reasons. It will fall back to version 35 + * behavior for tricky fonts[1] or when monochrome rendering is + * requested. + * + * Major hacks + * + * - Any point movement on the x axis is ignored (cf. `Direct_Move' and + * `Direct_Move_X'). This has the smallest code footprint and single + * biggest effect. The ClearType way to increase resolution is + * supersampling the x axis, the FreeType way is ignoring instructions + * on the x axis, which gives the same result in the majority of + * cases. + * + * - Points are not moved post-IUP (neither on the x nor on the y axis), + * except the x component of diagonal moves post-IUP (cf. + * `Direct_Move', `Direct_Move_Y', `Move_Zp2_Point'). Post-IUP + * changes are commonly used to `fix' pixel patterns which has little + * use outside monochrome rendering. + * + * - SHPIX and DELTAP don't execute unless moving a composite on the + * y axis or moving a previously y touched point. SHPIX additionally + * denies movement on the x axis (cf. `Ins_SHPIX' and `Ins_DELTAP'). + * Both instructions are commonly used to `fix' pixel patterns for + * monochrome or Windows's GDI rendering but make little sense for + * FreeType rendering. Both can distort the outline. See [2] for + * details. + * + * - The hdmx table and modifications to phantom points are ignored. + * Bearings and advance widths remain unchanged (except rounding them + * outside the interpreter!), cf. `compute_glyph_metrics' and + * `TT_Hint_Glyph'. Letting non-native-ClearType fonts modify spacing + * might mess up spacing. + * + * Minor hacks + * + * - FLIPRGON, FLIPRGOFF, and FLIPPT don't execute post-IUP. This + * prevents dents in e.g. Arial-Regular's `D' and `G' glyphs at + * various sizes. + * + * (Post-IUP is the state after both IUP[x] and IUP[y] have been + * executed.) + * + * The best results are achieved for fonts that were from the outset + * designed with ClearType in mind, meaning they leave the x axis mostly + * alone and don't mess with the `final' outline to produce more + * pleasing pixel patterns. The harder the designer tried to produce + * very specific patterns (`superhinting') for pre-ClearType-displays, + * the worse the results. + * + * Microsoft defines a way to turn off backward compatibility and + * interpret instructions as before (called `native ClearType')[2][3]. + * The font designer then regains full control and is responsible for + * making the font work correctly with ClearType without any + * hand-holding by the interpreter or rasterizer[4]. The v40 + * interpreter assumes backward compatibility by default, which can be + * turned off the same way by executing the following in the control + * program (cf. `Ins_INSTCTRL'). + * + * #PUSH 4,3 + * INSTCTRL[] + * + * [1] Tricky fonts as FreeType defines them rely on the bytecode + * interpreter to display correctly. Hacks can interfere with them, + * so they get treated like native ClearType fonts (v40 with + * backward compatibility turned off). Cf. `TT_RunIns'. + * + * [2] Proposed by Microsoft's Greg Hitchcock in + * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx + * + * [3] Beat Stamm describes it in more detail: + * http://www.beatstamm.com/typography/RTRCh4.htm#Sec12 + * + * [4] The list of `native ClearType' fonts is small at the time of this + * writing; I found the following on a Windows 10 Update 1511 + * installation: Constantia, Corbel, Sitka, Malgun Gothic, Microsoft + * JhengHei (Bold and UI Bold), Microsoft YaHei (Bold and UI Bold), + * SimSun, NSimSun, and Yu Gothic. + * + */ + + /* Using v40 implies subpixel hinting, unless FT_RENDER_MODE_MONO has been + * requested. Used to detect interpreter */ + /* version switches. `_lean' to differentiate from the Infinality */ + /* `subpixel_hinting', which is managed differently. */ + FT_Bool subpixel_hinting_lean; + + /* Long side of a LCD subpixel is vertical (e.g., screen is rotated). */ + /* `_lean' to differentiate from the Infinality `vertical_lcd', which */ + /* is managed differently. */ + FT_Bool vertical_lcd_lean; + + /* Default to backward compatibility mode in v40 interpreter. If */ + /* this is false, it implies the interpreter is in v35 or in native */ + /* ClearType mode. */ + FT_Bool backward_compatibility; + + /* Useful for detecting and denying post-IUP trickery that is usually */ + /* used to fix pixel patterns (`superhinting'). */ + FT_Bool iupx_called; + FT_Bool iupy_called; + + /* ClearType hinting and grayscale rendering, as used by Universal */ + /* Windows Platform apps (Windows 8 and above). Like the standard */ + /* colorful ClearType mode, it utilizes a vastly increased virtual */ + /* resolution on the x axis. Different from bi-level hinting and */ + /* grayscale rendering, the old mode from Win9x days that roughly */ + /* adheres to the physical pixel grid on both axes. */ + FT_Bool grayscale_cleartype; +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */ + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY TT_Round_Func func_round_sphn; /* subpixel rounding function */ FT_Bool subpixel_hinting; /* Using subpixel hinting? */ @@ -279,7 +422,15 @@ FT_BEGIN_HEADER FT_ULong sph_in_func_flags; /* flags to indicate if in */ /* special functions */ -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ + + /* We maintain two counters (in addition to the instruction counter) */ + /* that act as loop detectors for LOOPCALL and jump opcodes with */ + /* negative arguments. */ + FT_ULong loopcall_counter; + FT_ULong loopcall_counter_max; + FT_ULong neg_jump_counter; + FT_ULong neg_jump_counter_max; } TT_ExecContextRec; @@ -382,7 +533,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __TTINTERP_H__ */ +#endif /* TTINTERP_H_ */ /* END */ diff --git a/src/3rdparty/freetype/src/truetype/ttobjs.c b/src/3rdparty/freetype/src/truetype/ttobjs.c index 6060d6f5d1..6685dc8196 100644 --- a/src/3rdparty/freetype/src/truetype/ttobjs.c +++ b/src/3rdparty/freetype/src/truetype/ttobjs.c @@ -4,7 +4,7 @@ /* */ /* Objects manager (body). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2018 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -21,7 +21,7 @@ #include FT_INTERNAL_STREAM_H #include FT_TRUETYPE_TAGS_H #include FT_INTERNAL_SFNT_H -#include FT_TRUETYPE_DRIVER_H +#include FT_DRIVER_H #include "ttgload.h" #include "ttpload.h" @@ -32,10 +32,6 @@ #include "ttinterp.h" #endif -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING -#include FT_TRUETYPE_UNPATENTED_H -#endif - #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT #include "ttgxvar.h" #endif @@ -121,7 +117,7 @@ FT_Error error; - FT_MEM_ZERO( zone, sizeof ( *zone ) ); + FT_ZERO( zone ); zone->memory = memory; if ( FT_NEW_ARRAY( zone->org, maxPoints ) || @@ -151,20 +147,51 @@ { #define TRICK_NAMES_MAX_CHARACTERS 19 -#define TRICK_NAMES_COUNT 9 +#define TRICK_NAMES_COUNT 26 static const char trick_names[TRICK_NAMES_COUNT] [TRICK_NAMES_MAX_CHARACTERS + 1] = { + /* + PostScript names are given in brackets if they differ from the + family name. The version numbers, together with the copyright or + release year data, are taken from fonts available to the + developers. + + Note that later versions of the fonts might be no longer tricky; + for example, `MingLiU' version 7.00 (file `mingliu.ttc' from + Windows 7) is an ordinary TTC with non-tricky subfonts. + */ + + "cpop", /* dftt-p7.ttf; version 1.00, 1992 [DLJGyShoMedium] */ + "DFGirl-W6-WIN-BF", /* dftt-h6.ttf; version 1.00, 1993 */ + "DFGothic-EB", /* DynaLab Inc. 1992-1995 */ + "DFGyoSho-Lt", /* DynaLab Inc. 1992-1995 */ + "DFHei-Md-HK-BF", /* maybe DynaLab Inc. */ + "DFHSGothic-W5", /* DynaLab Inc. 1992-1995 */ + "DFHSMincho-W3", /* DynaLab Inc. 1992-1995 */ + "DFHSMincho-W7", /* DynaLab Inc. 1992-1995 */ "DFKaiSho-SB", /* dfkaisb.ttf */ "DFKaiShu", - "DFKai-SB", /* kaiu.ttf */ + "DFKaiShu-Md-HK-BF", /* maybe DynaLab Inc. */ + "DFKai-SB", /* kaiu.ttf; version 3.00, 1998 [DFKaiShu-SB-Estd-BF] */ + "DFMing-Bd-HK-BF", /* maybe DynaLab Inc. */ + "DLC", /* dftt-m7.ttf; version 1.00, 1993 [DLCMingBold] */ + /* dftt-f5.ttf; version 1.00, 1993 [DLCFongSung] */ + "DLCHayMedium", /* dftt-b5.ttf; version 1.00, 1993 */ + "DLCHayBold", /* dftt-b7.ttf; version 1.00, 1993 */ + "DLCKaiMedium", /* dftt-k5.ttf; version 1.00, 1992 */ + "DLCLiShu", /* dftt-l5.ttf; version 1.00, 1992 */ + "DLCRoundBold", /* dftt-r7.ttf; version 1.00, 1993 */ "HuaTianKaiTi?", /* htkt2.ttf */ "HuaTianSongTi?", /* htst3.ttf */ - "Ming(for ISO10646)", /* hkscsiic.ttf & iicore.ttf */ - "MingLiU", /* mingliu.ttf & mingliu.ttc */ - "PMingLiU", /* mingliu.ttc */ - "MingLi43", /* mingli.ttf */ + "Ming(for ISO10646)", /* hkscsiic.ttf; version 0.12, 2007 [Ming] */ + /* iicore.ttf; version 0.07, 2007 [Ming] */ + "MingLiU", /* mingliu.ttf */ + /* mingliu.ttc; version 3.21, 2001 */ + "MingMedium", /* dftt-m5.ttf; version 1.00, 1993 [DLCMingMedium] */ + "PMingLiU", /* mingliu.ttc; version 3.21, 2001 */ + "MingLi43", /* mingli.ttf; version 1.00, 1992 */ }; int nn; @@ -246,7 +273,7 @@ tt_check_trickyness_sfnt_ids( TT_Face face ) { #define TRICK_SFNT_IDS_PER_FACE 3 -#define TRICK_SFNT_IDS_NUM_FACES 17 +#define TRICK_SFNT_IDS_NUM_FACES 29 static const tt_sfnt_id_rec sfnt_id[TRICK_SFNT_IDS_NUM_FACES] [TRICK_SFNT_IDS_PER_FACE] = { @@ -265,11 +292,66 @@ { 0x28233BF1UL, 0x000087C4UL }, /* fpgm */ { 0xA344A1EBUL, 0x000001E1UL } /* prep */ }, + { /* DFGothic-EB */ + { 0x12C3EBB2UL, 0x00000350UL }, /* cvt */ + { 0xB680EE64UL, 0x000087A7UL }, /* fpgm */ + { 0xCE939563UL, 0x00000758UL } /* prep */ + }, + { /* DFGyoSho-Lt */ + { 0x11E5EAD4UL, 0x00000350UL }, /* cvt */ + { 0xCE5956E9UL, 0x0000BC85UL }, /* fpgm */ + { 0x8272F416UL, 0x00000045UL } /* prep */ + }, + { /* DFHei-Md-HK-BF */ + { 0x1257EB46UL, 0x00000350UL }, /* cvt */ + { 0xF699D160UL, 0x0000715FUL }, /* fpgm */ + { 0xD222F568UL, 0x000003BCUL } /* prep */ + }, + { /* DFHSGothic-W5 */ + { 0x1262EB4EUL, 0x00000350UL }, /* cvt */ + { 0xE86A5D64UL, 0x00007940UL }, /* fpgm */ + { 0x7850F729UL, 0x000005FFUL } /* prep */ + }, + { /* DFHSMincho-W3 */ + { 0x122DEB0AUL, 0x00000350UL }, /* cvt */ + { 0x3D16328AUL, 0x0000859BUL }, /* fpgm */ + { 0xA93FC33BUL, 0x000002CBUL } /* prep */ + }, + { /* DFHSMincho-W7 */ + { 0x125FEB26UL, 0x00000350UL }, /* cvt */ + { 0xA5ACC982UL, 0x00007EE1UL }, /* fpgm */ + { 0x90999196UL, 0x0000041FUL } /* prep */ + }, { /* DFKaiShu */ { 0x11E5EAD4UL, 0x00000350UL }, /* cvt */ { 0x5A30CA3BUL, 0x00009063UL }, /* fpgm */ { 0x13A42602UL, 0x0000007EUL } /* prep */ }, + { /* DFKaiShu, variant */ + { 0x11E5EAD4UL, 0x00000350UL }, /* cvt */ + { 0xA6E78C01UL, 0x00008998UL }, /* fpgm */ + { 0x13A42602UL, 0x0000007EUL } /* prep */ + }, + { /* DFKaiShu-Md-HK-BF */ + { 0x11E5EAD4UL, 0x00000360UL }, /* cvt */ + { 0x9DB282B2UL, 0x0000C06EUL }, /* fpgm */ + { 0x53E6D7CAUL, 0x00000082UL } /* prep */ + }, + { /* DFMing-Bd-HK-BF */ + { 0x1243EB18UL, 0x00000350UL }, /* cvt */ + { 0xBA0A8C30UL, 0x000074ADUL }, /* fpgm */ + { 0xF3D83409UL, 0x0000037BUL } /* prep */ + }, + { /* DLCLiShu */ + { 0x07DCF546UL, 0x00000308UL }, /* cvt */ + { 0x40FE7C90UL, 0x00008E2AUL }, /* fpgm */ + { 0x608174B5UL, 0x0000007AUL } /* prep */ + }, + { /* DLCHayBold */ + { 0xEB891238UL, 0x00000308UL }, /* cvt */ + { 0xD2E4DCD4UL, 0x0000676FUL }, /* fpgm */ + { 0x8EA5F293UL, 0x000003B8UL } /* prep */ + }, { /* HuaTianKaiTi */ { 0xFFFBFFFCUL, 0x00000008UL }, /* cvt */ { 0x9C9E48B8UL, 0x0000BEA2UL }, /* fpgm */ @@ -339,6 +421,11 @@ { 0x00000000UL, 0x00000000UL }, /* cvt */ { 0xF055FC48UL, 0x000001C2UL }, /* fpgm */ { 0x3900DED3UL, 0x00001E18UL } /* prep */ + }, + { /* MINGLI.TTF, 1992 */ + { 0x00170003UL, 0x00000060UL }, /* cvt */ + { 0xDBB4306EUL, 0x000058AAUL }, /* fpgm */ + { 0xD643482AUL, 0x00000035UL } /* prep */ } }; @@ -397,11 +484,11 @@ for ( j = 0; j < TRICK_SFNT_IDS_NUM_FACES; j++ ) { if ( !has_cvt && !sfnt_id[j][TRICK_SFNT_ID_cvt].Length ) - num_matched_ids[j] ++; + num_matched_ids[j]++; if ( !has_fpgm && !sfnt_id[j][TRICK_SFNT_ID_fpgm].Length ) - num_matched_ids[j] ++; + num_matched_ids[j]++; if ( !has_prep && !sfnt_id[j][TRICK_SFNT_ID_prep].Length ) - num_matched_ids[j] ++; + num_matched_ids[j]++; if ( num_matched_ids[j] == TRICK_SFNT_IDS_PER_FACE ) return TRUE; } @@ -535,6 +622,7 @@ goto Exit; /* check that we have a valid TrueType file */ + FT_TRACE2(( " " )); error = sfnt->init_face( stream, face, face_index, num_params, params ); /* Stream may have changed. */ @@ -546,9 +634,11 @@ /* We must also be able to accept Mac/GX fonts, as well as OT ones. */ /* The 0x00020000 tag is completely undocumented; some fonts from */ /* Arphic made for Chinese Windows 3.1 have this. */ - if ( face->format_tag != 0x00010000L && /* MS fonts */ - face->format_tag != 0x00020000L && /* CJK fonts for Win 3.1 */ - face->format_tag != TTAG_true ) /* Mac fonts */ + if ( face->format_tag != 0x00010000L && /* MS fonts */ + face->format_tag != 0x00020000L && /* CJK fonts for Win 3.1 */ + face->format_tag != TTAG_true && /* Mac fonts */ + face->format_tag != TTAG_0xA5kbd && /* `Keyboard.dfont' (legacy Mac OS X) */ + face->format_tag != TTAG_0xA5lst ) /* `LastResort.dfont' (legacy Mac OS X) */ { FT_TRACE2(( " not a TTF font\n" )); goto Bad_Format; @@ -576,129 +666,71 @@ if ( FT_IS_SCALABLE( ttface ) ) { - #ifdef FT_CONFIG_OPTION_INCREMENTAL - if ( !ttface->internal->incremental_interface ) - error = tt_face_load_loca( face, stream ); - if ( !error ) - error = tt_face_load_cvt( face, stream ); - if ( !error ) - error = tt_face_load_fpgm( face, stream ); - if ( !error ) - error = tt_face_load_prep( face, stream ); - - /* Check the scalable flag based on `loca'. */ - if ( !ttface->internal->incremental_interface && - ttface->num_fixed_sizes && - face->glyph_locations && - tt_check_single_notdef( ttface ) ) +#endif { - FT_TRACE5(( "tt_face_init:" - " Only the `.notdef' glyph has an outline.\n" - " " - " Resetting scalable flag to FALSE.\n" )); + error = tt_face_load_loca( face, stream ); - ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE; + /* having a (non-zero) `glyf' table without */ + /* a `loca' table is not valid */ + if ( face->glyf_len && FT_ERR_EQ( error, Table_Missing ) ) + goto Exit; + if ( error ) + goto Exit; } -#else /* !FT_CONFIG_OPTION_INCREMENTAL */ + /* `fpgm', `cvt', and `prep' are optional */ + error = tt_face_load_cvt( face, stream ); + if ( error && FT_ERR_NEQ( error, Table_Missing ) ) + goto Exit; - if ( !error ) - error = tt_face_load_loca( face, stream ); - if ( !error ) - error = tt_face_load_cvt( face, stream ); - if ( !error ) - error = tt_face_load_fpgm( face, stream ); - if ( !error ) - error = tt_face_load_prep( face, stream ); + error = tt_face_load_fpgm( face, stream ); + if ( error && FT_ERR_NEQ( error, Table_Missing ) ) + goto Exit; + + error = tt_face_load_prep( face, stream ); + if ( error && FT_ERR_NEQ( error, Table_Missing ) ) + goto Exit; /* Check the scalable flag based on `loca'. */ - if ( ttface->num_fixed_sizes && - face->glyph_locations && - tt_check_single_notdef( ttface ) ) +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( !ttface->internal->incremental_interface ) +#endif { - FT_TRACE5(( "tt_face_init:" - " Only the `.notdef' glyph has an outline.\n" - " " - " Resetting scalable flag to FALSE.\n" )); + if ( ttface->num_fixed_sizes && + face->glyph_locations && + tt_check_single_notdef( ttface ) ) + { + FT_TRACE5(( "tt_face_init:" + " Only the `.notdef' glyph has an outline.\n" + " " + " Resetting scalable flag to FALSE.\n" )); - ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE; + ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE; + } } - -#endif /* !FT_CONFIG_OPTION_INCREMENTAL */ - } #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT { - FT_Int instance_index = face_index >> 16; + FT_UInt instance_index = (FT_UInt)face_index >> 16; if ( FT_HAS_MULTIPLE_MASTERS( ttface ) && instance_index > 0 ) { - error = TT_Get_MM_Var( face, NULL ); + error = TT_Set_Named_Instance( face, instance_index ); if ( error ) goto Exit; - if ( face->blend->mmvar->namedstyle ) - { - FT_Memory memory = ttface->memory; - - FT_Var_Named_Style* named_style; - FT_String* style_name; - - - /* in `face_index', the instance index starts with value 1 */ - named_style = face->blend->mmvar->namedstyle + instance_index - 1; - error = sfnt->get_name( face, - (FT_UShort)named_style->strid, - &style_name ); - if ( error ) - goto Exit; - - /* set style name; if already set, replace it */ - if ( face->root.style_name ) - FT_FREE( face->root.style_name ); - face->root.style_name = style_name; - - /* finally, select the named instance */ - error = TT_Set_Var_Design( face, - face->blend->mmvar->num_axis, - named_style->coords ); - if ( error ) - goto Exit; - } + tt_apply_mvar( face ); } } #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ -#if defined( TT_CONFIG_OPTION_UNPATENTED_HINTING ) && \ - !defined( TT_CONFIG_OPTION_BYTECODE_INTERPRETER ) - - { - FT_Bool unpatented_hinting; - int i; - - - /* Determine whether unpatented hinting is to be used for this face. */ - unpatented_hinting = FT_BOOL - ( library->debug_hooks[FT_DEBUG_HOOK_UNPATENTED_HINTING] != NULL ); - - for ( i = 0; i < num_params && !face->unpatented_hinting; i++ ) - if ( params[i].tag == FT_PARAM_TAG_UNPATENTED_HINTING ) - unpatented_hinting = TRUE; - - if ( !unpatented_hinting ) - ttface->internal->ignore_unpatented_hinter = TRUE; - } - -#endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING && - !TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ - /* initialize standard glyph loading routines */ TT_Init_Glyph_Loading( face ); @@ -761,7 +793,7 @@ face->cvt_program_size = 0; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - tt_done_blend( memory, face->blend ); + tt_done_blend( face ); face->blend = NULL; #endif } @@ -819,14 +851,14 @@ exec->pedantic_hinting = pedantic; { - FT_Size_Metrics* metrics = &exec->metrics; - TT_Size_Metrics* tt_metrics = &exec->tt_metrics; + FT_Size_Metrics* size_metrics = &exec->metrics; + TT_Size_Metrics* tt_metrics = &exec->tt_metrics; - metrics->x_ppem = 0; - metrics->y_ppem = 0; - metrics->x_scale = 0; - metrics->y_scale = 0; + size_metrics->x_ppem = 0; + size_metrics->y_ppem = 0; + size_metrics->x_scale = 0; + size_metrics->y_scale = 0; tt_metrics->ppem = 0; tt_metrics->scale = 0; @@ -849,6 +881,11 @@ FT_TRACE4(( "Executing `fpgm' table.\n" )); error = face->interpreter( exec ); +#ifdef FT_DEBUG_LEVEL_TRACE + if ( error ) + FT_TRACE4(( " interpretation failed with error code 0x%x\n", + error )); +#endif } else error = FT_Err_Ok; @@ -912,8 +949,12 @@ TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 ); FT_TRACE4(( "Executing `prep' table.\n" )); - error = face->interpreter( exec ); +#ifdef FT_DEBUG_LEVEL_TRACE + if ( error ) + FT_TRACE4(( " interpretation failed with error code 0x%x\n", + error )); +#endif } else error = FT_Err_Ok; @@ -1032,17 +1073,17 @@ /* Set default metrics */ { - TT_Size_Metrics* metrics = &size->ttmetrics; + TT_Size_Metrics* tt_metrics = &size->ttmetrics; - metrics->rotated = FALSE; - metrics->stretched = FALSE; + tt_metrics->rotated = FALSE; + tt_metrics->stretched = FALSE; /* set default engine compensation */ - metrics->compensations[0] = 0; /* gray */ - metrics->compensations[1] = 0; /* black */ - metrics->compensations[2] = 0; /* white */ - metrics->compensations[3] = 0; /* reserved */ + tt_metrics->compensations[0] = 0; /* gray */ + tt_metrics->compensations[1] = 0; /* black */ + tt_metrics->compensations[2] = 0; /* white */ + tt_metrics->compensations[3] = 0; /* reserved */ } /* allocate function defs, instruction defs, cvt, and storage area */ @@ -1078,7 +1119,15 @@ } /* Fine, now run the font program! */ + + /* In case of an error while executing `fpgm', we intentionally don't */ + /* clean up immediately – bugs in the `fpgm' are so fundamental that */ + /* all following hinting calls should fail. Additionally, `fpgm' is */ + /* to be executed just once; calling it again is completely useless */ + /* and might even lead to extremely slow behaviour if it is malformed */ + /* (containing an infinite loop, for example). */ error = tt_size_run_fpgm( size, pedantic ); + return error; Exit: if ( error ) @@ -1097,8 +1146,10 @@ if ( size->bytecode_ready < 0 ) error = tt_size_init_bytecode( (FT_Size)size, pedantic ); + else + error = size->bytecode_ready; - if ( error || size->bytecode_ready ) + if ( error ) goto Exit; /* rescale CVT when needed */ @@ -1130,6 +1181,8 @@ error = tt_size_run_prep( size, pedantic ); } + else + error = size->cvt_ready; Exit: return error; @@ -1206,26 +1259,34 @@ /* have been changed. */ /* */ /* <Input> */ - /* size :: A handle to the target size object. */ + /* size :: A handle to the target size object. */ + /* */ + /* only_height :: Only recompute ascender, descender, and height; */ + /* this flag is used for variation fonts where */ + /* `tt_size_reset' is used as an iterator function. */ /* */ FT_LOCAL_DEF( FT_Error ) - tt_size_reset( TT_Size size ) + tt_size_reset( TT_Size size, + FT_Bool only_height ) { TT_Face face; - FT_Error error = FT_Err_Ok; - FT_Size_Metrics* metrics; + FT_Size_Metrics* size_metrics; - size->ttmetrics.valid = FALSE; - face = (TT_Face)size->root.face; - metrics = &size->metrics; + /* nothing to do for CFF2 */ + if ( face->is_cff2 ) + return FT_Err_Ok; + + size->ttmetrics.valid = FALSE; + + size_metrics = &size->hinted_metrics; /* copy the result from base layer */ - *metrics = size->root.metrics; + *size_metrics = size->root.metrics; - if ( metrics->x_ppem < 1 || metrics->y_ppem < 1 ) + if ( size_metrics->x_ppem < 1 || size_metrics->y_ppem < 1 ) return FT_THROW( Invalid_PPem ); /* This bit flag, if set, indicates that the ppems must be */ @@ -1234,48 +1295,66 @@ /* */ if ( face->header.Flags & 8 ) { - metrics->x_scale = FT_DivFix( metrics->x_ppem << 6, - face->root.units_per_EM ); - metrics->y_scale = FT_DivFix( metrics->y_ppem << 6, - face->root.units_per_EM ); - - metrics->ascender = - FT_PIX_ROUND( FT_MulFix( face->root.ascender, metrics->y_scale ) ); - metrics->descender = - FT_PIX_ROUND( FT_MulFix( face->root.descender, metrics->y_scale ) ); - metrics->height = - FT_PIX_ROUND( FT_MulFix( face->root.height, metrics->y_scale ) ); - metrics->max_advance = - FT_PIX_ROUND( FT_MulFix( face->root.max_advance_width, - metrics->x_scale ) ); + /* the TT spec always asks for ROUND, not FLOOR or CEIL */ + size_metrics->ascender = FT_PIX_ROUND( + FT_MulFix( face->root.ascender, + size_metrics->y_scale ) ); + size_metrics->descender = FT_PIX_ROUND( + FT_MulFix( face->root.descender, + size_metrics->y_scale ) ); + size_metrics->height = FT_PIX_ROUND( + FT_MulFix( face->root.height, + size_metrics->y_scale ) ); + } + + size->ttmetrics.valid = TRUE; + + if ( only_height ) + { + /* we must not recompute the scaling values here since */ + /* `tt_size_reset' was already called (with only_height = 0) */ + return FT_Err_Ok; + } + + if ( face->header.Flags & 8 ) + { + /* base scaling values on integer ppem values, */ + /* as mandated by the TrueType specification */ + size_metrics->x_scale = FT_DivFix( size_metrics->x_ppem << 6, + face->root.units_per_EM ); + size_metrics->y_scale = FT_DivFix( size_metrics->y_ppem << 6, + face->root.units_per_EM ); + + size_metrics->max_advance = FT_PIX_ROUND( + FT_MulFix( face->root.max_advance_width, + size_metrics->x_scale ) ); } /* compute new transformation */ - if ( metrics->x_ppem >= metrics->y_ppem ) + if ( size_metrics->x_ppem >= size_metrics->y_ppem ) { - size->ttmetrics.scale = metrics->x_scale; - size->ttmetrics.ppem = metrics->x_ppem; + size->ttmetrics.scale = size_metrics->x_scale; + size->ttmetrics.ppem = size_metrics->x_ppem; size->ttmetrics.x_ratio = 0x10000L; - size->ttmetrics.y_ratio = FT_DivFix( metrics->y_ppem, - metrics->x_ppem ); + size->ttmetrics.y_ratio = FT_DivFix( size_metrics->y_ppem, + size_metrics->x_ppem ); } else { - size->ttmetrics.scale = metrics->y_scale; - size->ttmetrics.ppem = metrics->y_ppem; - size->ttmetrics.x_ratio = FT_DivFix( metrics->x_ppem, - metrics->y_ppem ); + size->ttmetrics.scale = size_metrics->y_scale; + size->ttmetrics.ppem = size_metrics->y_ppem; + size->ttmetrics.x_ratio = FT_DivFix( size_metrics->x_ppem, + size_metrics->y_ppem ); size->ttmetrics.y_ratio = 0x10000L; } + size->metrics = size_metrics; + #ifdef TT_USE_BYTECODE_INTERPRETER size->cvt_ready = -1; #endif /* TT_USE_BYTECODE_INTERPRETER */ - if ( !error ) - size->ttmetrics.valid = TRUE; - - return error; + return FT_Err_Ok; } @@ -1301,10 +1380,12 @@ TT_Driver driver = (TT_Driver)ttdriver; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - driver->interpreter_version = TT_INTERPRETER_VERSION_38; -#else driver->interpreter_version = TT_INTERPRETER_VERSION_35; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY + driver->interpreter_version = TT_INTERPRETER_VERSION_38; +#endif +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + driver->interpreter_version = TT_INTERPRETER_VERSION_40; #endif #else /* !TT_USE_BYTECODE_INTERPRETER */ diff --git a/src/3rdparty/freetype/src/truetype/ttobjs.h b/src/3rdparty/freetype/src/truetype/ttobjs.h index 9396089a99..38fa30e4e9 100644 --- a/src/3rdparty/freetype/src/truetype/ttobjs.h +++ b/src/3rdparty/freetype/src/truetype/ttobjs.h @@ -4,7 +4,7 @@ /* */ /* Objects manager (specification). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2018 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,8 +16,8 @@ /***************************************************************************/ -#ifndef __TTOBJS_H__ -#define __TTOBJS_H__ +#ifndef TTOBJS_H_ +#define TTOBJS_H_ #include <ft2build.h> @@ -72,10 +72,6 @@ FT_BEGIN_HEADER FT_UnitVector projVector; FT_UnitVector freeVector; -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - FT_Bool both_x_axis; -#endif - FT_Long loop; FT_F26Dot6 minimum_distance; FT_Int round_state; @@ -282,7 +278,8 @@ FT_BEGIN_HEADER /* we have our own copy of metrics so that we can modify */ /* it without affecting auto-hinting (when used) */ - FT_Size_Metrics metrics; + FT_Size_Metrics* metrics; /* for the current rendering mode */ + FT_Size_Metrics hinted_metrics; /* for the hinted rendering mode */ TT_Size_Metrics ttmetrics; @@ -290,6 +287,8 @@ FT_BEGIN_HEADER #ifdef TT_USE_BYTECODE_INTERPRETER + FT_Long point_size; /* for the `MPS' bytecode instruction */ + FT_UInt num_function_defs; /* number of function definitions */ FT_UInt max_function_defs; TT_DefArray function_defs; /* table of function definitions */ @@ -391,7 +390,8 @@ FT_BEGIN_HEADER #endif /* TT_USE_BYTECODE_INTERPRETER */ FT_LOCAL( FT_Error ) - tt_size_reset( TT_Size size ); + tt_size_reset( TT_Size size, + FT_Bool only_height ); /*************************************************************************/ @@ -419,7 +419,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __TTOBJS_H__ */ +#endif /* TTOBJS_H_ */ /* END */ diff --git a/src/3rdparty/freetype/src/truetype/ttpic.c b/src/3rdparty/freetype/src/truetype/ttpic.c index 242a6b76dd..cdbb80639e 100644 --- a/src/3rdparty/freetype/src/truetype/ttpic.c +++ b/src/3rdparty/freetype/src/truetype/ttpic.c @@ -4,7 +4,7 @@ /* */ /* The FreeType position independent code services for truetype module. */ /* */ -/* Copyright 2009-2015 by */ +/* Copyright 2009-2018 by */ /* Oran Agra and Mickey Gabel. */ /* */ /* This file is part of the FreeType project, and may only be used, */ diff --git a/src/3rdparty/freetype/src/truetype/ttpic.h b/src/3rdparty/freetype/src/truetype/ttpic.h index 076ae56efa..df878ae6f1 100644 --- a/src/3rdparty/freetype/src/truetype/ttpic.h +++ b/src/3rdparty/freetype/src/truetype/ttpic.h @@ -4,7 +4,7 @@ /* */ /* The FreeType position independent code services for truetype module. */ /* */ -/* Copyright 2009-2015 by */ +/* Copyright 2009-2018 by */ /* Oran Agra and Mickey Gabel. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,8 +16,8 @@ /***************************************************************************/ -#ifndef __TTPIC_H__ -#define __TTPIC_H__ +#ifndef TTPIC_H_ +#define TTPIC_H_ #include FT_INTERNAL_PIC_H @@ -25,15 +25,17 @@ #ifndef FT_CONFIG_OPTION_PIC -#define TT_SERVICES_GET tt_services -#define TT_SERVICE_GX_MULTI_MASTERS_GET tt_service_gx_multi_masters -#define TT_SERVICE_TRUETYPE_GLYF_GET tt_service_truetype_glyf -#define TT_SERVICE_PROPERTIES_GET tt_service_properties +#define TT_SERVICES_GET tt_services +#define TT_SERVICE_GX_MULTI_MASTERS_GET tt_service_gx_multi_masters +#define TT_SERVICE_METRICS_VARIATIONS_GET tt_service_metrics_variations +#define TT_SERVICE_TRUETYPE_GLYF_GET tt_service_truetype_glyf +#define TT_SERVICE_PROPERTIES_GET tt_service_properties #else /* FT_CONFIG_OPTION_PIC */ #include FT_MULTIPLE_MASTERS_H #include FT_SERVICE_MULTIPLE_MASTERS_H +#include FT_SERVICE_METRICS_VARIATIONS_H #include FT_SERVICE_TRUETYPE_GLYF_H #include FT_SERVICE_PROPERTIES_H @@ -42,12 +44,13 @@ FT_BEGIN_HEADER typedef struct TTModulePIC_ { - FT_ServiceDescRec* tt_services; + FT_ServiceDescRec* tt_services; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - FT_Service_MultiMastersRec tt_service_gx_multi_masters; + FT_Service_MultiMastersRec tt_service_gx_multi_masters; + FT_Service_MetricsVariationsRec tt_service_metrics_variations; #endif - FT_Service_TTGlyfRec tt_service_truetype_glyf; - FT_Service_PropertiesRec tt_service_properties; + FT_Service_TTGlyfRec tt_service_truetype_glyf; + FT_Service_PropertiesRec tt_service_properties; } TTModulePIC; @@ -56,6 +59,8 @@ FT_BEGIN_HEADER ( (TTModulePIC*)((lib)->pic_container.truetype) ) #define TT_SERVICES_GET \ ( GET_PIC( library )->tt_services ) +#define TT_SERVICE_METRICS_VARIATIONS_GET \ + ( GET_PIC( library )->tt_service_metrics_variations ) #define TT_SERVICE_GX_MULTI_MASTERS_GET \ ( GET_PIC( library )->tt_service_gx_multi_masters ) #define TT_SERVICE_TRUETYPE_GLYF_GET \ @@ -77,7 +82,7 @@ FT_END_HEADER /* */ -#endif /* __TTPIC_H__ */ +#endif /* TTPIC_H_ */ /* END */ diff --git a/src/3rdparty/freetype/src/truetype/ttpload.c b/src/3rdparty/freetype/src/truetype/ttpload.c index 4647c938ae..d9526ad082 100644 --- a/src/3rdparty/freetype/src/truetype/ttpload.c +++ b/src/3rdparty/freetype/src/truetype/ttpload.c @@ -4,7 +4,7 @@ /* */ /* TrueType-specific tables loader (body). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2018 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -73,9 +73,21 @@ /* it is possible that a font doesn't have a glyf table at all */ /* or its size is zero */ if ( FT_ERR_EQ( error, Table_Missing ) ) - face->glyf_len = 0; + { + face->glyf_len = 0; + face->glyf_offset = 0; + } else if ( error ) goto Exit; + else + { +#ifdef FT_CONFIG_OPTION_INCREMENTAL + if ( face->root.internal->incremental_interface ) + face->glyf_offset = 0; + else +#endif + face->glyf_offset = FT_STREAM_POS(); + } FT_TRACE2(( "Locations " )); error = face->goto_table( face, TTAG_loca, stream, &table_len ); @@ -92,8 +104,7 @@ if ( table_len >= 0x40000L ) { FT_TRACE2(( "table too large\n" )); - error = FT_THROW( Invalid_Table ); - goto Exit; + table_len = 0x3FFFFL; } face->num_locations = table_len >> shift; } @@ -104,8 +115,7 @@ if ( table_len >= 0x20000L ) { FT_TRACE2(( "table too large\n" )); - error = FT_THROW( Invalid_Table ); - goto Exit; + table_len = 0x1FFFFL; } face->num_locations = table_len >> shift; } @@ -124,8 +134,9 @@ TT_Table entry = face->dir_tables; TT_Table limit = entry + face->num_tables; - FT_Long pos = (FT_Long)FT_STREAM_POS(); - FT_Long dist = 0x7FFFFFFFL; + FT_Long pos = (FT_Long)FT_STREAM_POS(); + FT_Long dist = 0x7FFFFFFFL; + FT_Bool found = 0; /* compute the distance to next table in font file */ @@ -135,10 +146,13 @@ if ( diff > 0 && diff < dist ) - dist = diff; + { + dist = diff; + found = 1; + } } - if ( entry == limit ) + if ( !found ) { /* `loca' is the last table */ dist = (FT_Long)stream->size - pos; @@ -218,12 +232,13 @@ } } - /* Check broken location data */ + /* Check broken location data. */ if ( pos1 > face->glyf_len ) { FT_TRACE1(( "tt_face_get_location:" - " too large offset=0x%08lx found for gid=0x%04lx," - " exceeding the end of glyf table (0x%08lx)\n", + " too large offset (0x%08lx) found for glyph index %ld,\n" + " " + " exceeding the end of `glyf' table (0x%08lx)\n", pos1, gindex, face->glyf_len )); *asize = 0; return 0; @@ -231,11 +246,26 @@ if ( pos2 > face->glyf_len ) { - FT_TRACE1(( "tt_face_get_location:" - " too large offset=0x%08lx found for gid=0x%04lx," - " truncate at the end of glyf table (0x%08lx)\n", - pos2, gindex + 1, face->glyf_len )); - pos2 = face->glyf_len; + /* We try to sanitize the last `loca' entry. */ + if ( gindex == face->num_locations - 2 ) + { + FT_TRACE1(( "tt_face_get_location:" + " too large size (%ld bytes) found for glyph index %ld,\n" + " " + " truncating at the end of `glyf' table to %ld bytes\n", + pos2 - pos1, gindex, face->glyf_len - pos1 )); + pos2 = face->glyf_len; + } + else + { + FT_TRACE1(( "tt_face_get_location:" + " too large offset (0x%08lx) found for glyph index %ld,\n" + " " + " exceeding the end of `glyf' table (0x%08lx)\n", + pos2, gindex + 1, face->glyf_len )); + *asize = 0; + return 0; + } } /* The `loca' table must be ordered; it refers to the length of */ @@ -494,7 +524,7 @@ { FT_Error error; FT_Memory memory = stream->memory; - FT_UInt version, nn, num_records; + FT_UInt nn, num_records; FT_ULong table_size, record_size; FT_Byte* p; FT_Byte* limit; @@ -511,7 +541,10 @@ p = face->hdmx_table; limit = p + table_size; - version = FT_NEXT_USHORT( p ); + /* Given that `hdmx' tables are losing its importance (for example, */ + /* variation fonts introduced in OpenType 1.8 must not have this */ + /* table) we no longer test for a correct `version' field. */ + p += 2; num_records = FT_NEXT_USHORT( p ); record_size = FT_NEXT_ULONG( p ); @@ -530,10 +563,10 @@ record_size &= 0xFFFFU; /* The limit for `num_records' is a heuristic value. */ - if ( version != 0 || - num_records > 255 || - record_size > 0x10001L || - record_size < 4 ) + if ( num_records > 255 || + ( num_records > 0 && + ( record_size > 0x10001L || + record_size < 4 ) ) ) { error = FT_THROW( Invalid_File_Format ); goto Fail; diff --git a/src/3rdparty/freetype/src/truetype/ttpload.h b/src/3rdparty/freetype/src/truetype/ttpload.h index bc92369827..fa12527247 100644 --- a/src/3rdparty/freetype/src/truetype/ttpload.h +++ b/src/3rdparty/freetype/src/truetype/ttpload.h @@ -4,7 +4,7 @@ /* */ /* TrueType-specific tables loader (specification). */ /* */ -/* Copyright 1996-2015 by */ +/* Copyright 1996-2018 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,8 +16,8 @@ /***************************************************************************/ -#ifndef __TTPLOAD_H__ -#define __TTPLOAD_H__ +#ifndef TTPLOAD_H_ +#define TTPLOAD_H_ #include <ft2build.h> @@ -69,7 +69,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __TTPLOAD_H__ */ +#endif /* TTPLOAD_H_ */ /* END */ diff --git a/src/3rdparty/freetype/src/truetype/ttsubpix.c b/src/3rdparty/freetype/src/truetype/ttsubpix.c index 0d391e95a0..d94bcc8b50 100644 --- a/src/3rdparty/freetype/src/truetype/ttsubpix.c +++ b/src/3rdparty/freetype/src/truetype/ttsubpix.c @@ -4,7 +4,7 @@ /* */ /* TrueType Subpixel Hinting. */ /* */ -/* Copyright 2010-2015 by */ +/* Copyright 2010-2018 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -22,12 +22,13 @@ #include FT_INTERNAL_SFNT_H #include FT_TRUETYPE_TAGS_H #include FT_OUTLINE_H -#include FT_TRUETYPE_DRIVER_H +#include FT_DRIVER_H #include "ttsubpix.h" -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#if defined( TT_USE_BYTECODE_INTERPRETER ) && \ + defined( TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY ) /*************************************************************************/ /* */ @@ -752,24 +753,24 @@ /* Does font name match rule family? */ - if ( strcmp( detected_font_name, rule_font_name ) == 0 ) + if ( ft_strcmp( detected_font_name, rule_font_name ) == 0 ) return TRUE; /* Is font name a wildcard ""? */ - if ( strcmp( rule_font_name, "" ) == 0 ) + if ( ft_strcmp( rule_font_name, "" ) == 0 ) return TRUE; /* Is font name contained in a class list? */ for ( i = 0; i < FAMILY_CLASS_RULES_SIZE; i++ ) { - if ( strcmp( FAMILY_CLASS_Rules[i].name, rule_font_name ) == 0 ) + if ( ft_strcmp( FAMILY_CLASS_Rules[i].name, rule_font_name ) == 0 ) { for ( j = 0; j < SPH_MAX_CLASS_MEMBERS; j++ ) { - if ( strcmp( FAMILY_CLASS_Rules[i].member[j], "" ) == 0 ) + if ( ft_strcmp( FAMILY_CLASS_Rules[i].member[j], "" ) == 0 ) continue; - if ( strcmp( FAMILY_CLASS_Rules[i].member[j], - detected_font_name ) == 0 ) + if ( ft_strcmp( FAMILY_CLASS_Rules[i].member[j], + detected_font_name ) == 0 ) return TRUE; } } @@ -787,24 +788,24 @@ /* Does font style match rule style? */ - if ( strcmp( detected_font_style, rule_font_style ) == 0 ) + if ( ft_strcmp( detected_font_style, rule_font_style ) == 0 ) return TRUE; /* Is font style a wildcard ""? */ - if ( strcmp( rule_font_style, "" ) == 0 ) + if ( ft_strcmp( rule_font_style, "" ) == 0 ) return TRUE; /* Is font style contained in a class list? */ for ( i = 0; i < STYLE_CLASS_RULES_SIZE; i++ ) { - if ( strcmp( STYLE_CLASS_Rules[i].name, rule_font_style ) == 0 ) + if ( ft_strcmp( STYLE_CLASS_Rules[i].name, rule_font_style ) == 0 ) { for ( j = 0; j < SPH_MAX_CLASS_MEMBERS; j++ ) { - if ( strcmp( STYLE_CLASS_Rules[i].member[j], "" ) == 0 ) + if ( ft_strcmp( STYLE_CLASS_Rules[i].member[j], "" ) == 0 ) continue; - if ( strcmp( STYLE_CLASS_Rules[i].member[j], - detected_font_style ) == 0 ) + if ( ft_strcmp( STYLE_CLASS_Rules[i].member[j], + detected_font_style ) == 0 ) return TRUE; } } @@ -905,7 +906,7 @@ { TT_Face face = loader->face; FT_String* family = face->root.family_name; - FT_UInt ppem = loader->size->metrics.x_ppem; + FT_UInt ppem = loader->size->metrics->x_ppem; FT_String* style = face->root.style_name; @@ -1000,12 +1001,14 @@ } } -#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#else /* !(TT_USE_BYTECODE_INTERPRETER && */ + /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY) */ /* ANSI C doesn't like empty source files */ typedef int _tt_subpix_dummy; -#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* !(TT_USE_BYTECODE_INTERPRETER && */ + /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY) */ /* END */ diff --git a/src/3rdparty/freetype/src/truetype/ttsubpix.h b/src/3rdparty/freetype/src/truetype/ttsubpix.h index 9151aa3250..1070bb016f 100644 --- a/src/3rdparty/freetype/src/truetype/ttsubpix.h +++ b/src/3rdparty/freetype/src/truetype/ttsubpix.h @@ -4,7 +4,7 @@ /* */ /* TrueType Subpixel Hinting. */ /* */ -/* Copyright 2010-2015 by */ +/* Copyright 2010-2018 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,8 +16,8 @@ /***************************************************************************/ -#ifndef __TTSUBPIX_H__ -#define __TTSUBPIX_H__ +#ifndef TTSUBPIX_H_ +#define TTSUBPIX_H_ #include <ft2build.h> #include "ttobjs.h" @@ -27,7 +27,7 @@ FT_BEGIN_HEADER -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY /*************************************************************************/ /* */ @@ -100,11 +100,12 @@ FT_BEGIN_HEADER #define SPH_OPTION_SET_COMPATIBLE_WIDTHS FALSE #define SPH_OPTION_SET_RASTERIZER_VERSION 38 -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ FT_END_HEADER -#endif /* __TTSUBPIX_H__ */ +#endif /* TTSUBPIX_H_ */ + /* END */ |