>From b5828d7889e4965f262c5cfbe084ae2b1b20310d Mon Sep 17 00:00:00 2001 From: Nikolaus Waxweiler Date: Thu, 28 Apr 2016 23:46:12 +0200 Subject: [PATCH 1/2] Prepare landing of new lean TrueType bytcode interpreter Modern TrueType fonts are usually rendered through Microsoft's collection of rendering techniques called ClearType (e.g., subpixel rendering and subpixel hinting). When ClearType was introduced, most fonts were not ready. Microsoft decided to implement a backwards compatibility mode that employed several simple to complicated assumptions and tricks that modified the interpretation of the bytecode contained in these fonts to make them look ClearType-y somehow. Most (web)fonts that were released since then have come to rely on these hacks to render correctly, even some of Microsoft's flagship ClearType fonts (Calibri, Cambria, Segoe UI). FreeType's new lean bytecode interpreter, derived from the Infinality code and vastly simplified, employs a small list of font-agnostic hacks to bludgeon non-native-ClearType fonts (except tricky ones[1]) into submission. It will not try to toggle hacks for specific fonts for performance and complexity reasons. The focus is on modern (web)fonts rather than legacy fonts that were made for black-and-white rendering. 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 backwards 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 v38 interpreter assumes backwards 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[] The new interpreter can coexist with the older Infinality code and the interpreter without subpixel hinting support. The different versions can be selected at runtime. [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 (v38 with backwards 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. --- devel/ftoption.h | 61 +++++++++++++----- include/freetype/config/ftoption.h | 55 ++++++++++++---- include/freetype/ftcffdrv.h | 8 +-- include/freetype/ftttdrv.h | 48 +++++++++----- src/truetype/ttdriver.c | 11 +++- src/truetype/ttgload.c | 119 ++++++++++++++++++++++++++++------ src/truetype/ttinterp.h | 128 ++++++++++++++++++++++++++++++++++++- src/truetype/ttobjs.c | 6 +- 8 files changed, 361 insertions(+), 75 deletions(-) diff --git a/devel/ftoption.h b/devel/ftoption.h index b354efd..77835dc 100644 --- a/devel/ftoption.h +++ b/devel/ftoption.h @@ -585,24 +585,53 @@ FT_BEGIN_HEADER /*************************************************************************/ /* */ - /* Define TT_CONFIG_OPTION_SUBPIXEL_HINTING if you want to compile */ - /* EXPERIMENTAL subpixel hinting support into the TrueType driver. This */ - /* replaces the native TrueType hinting mechanism when anything but */ - /* FT_RENDER_MODE_MONO is requested. */ - /* */ - /* Enabling this causes the TrueType driver to ignore instructions under */ - /* certain conditions. This is done in accordance with the guide here, */ - /* with some minor differences: */ - /* */ - /* http://www.microsoft.com/typography/cleartype/truetypecleartype.aspx */ - /* */ - /* By undefining this, you only compile the code necessary to hint */ - /* TrueType glyphs with native TT hinting. */ - /* */ - /* This option requires TT_CONFIG_OPTION_BYTECODE_INTERPRETER to be */ - /* defined. */ + /* Define TT_CONFIG_OPTION_SUBPIXEL_HINTING or */ + /* TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN if you want to compile */ + /* subpixel hinting support into the TrueType driver. This modifies the */ + /* TrueType hinting mechanism when anything but FT_RENDER_MODE_MONO is */ + /* requested. */ + /* */ + /* In particular, it modifies the bytecode interpreter to interpret (or */ + /* not) instructions in a certain way so that all TrueType fonts look */ + /* like they do in a Windows ClearType (DirectWrite) environment. See */ + /* [1] for a technical overview on what this means. See `ttinterp.h' */ + /* for more details on the LEAN option. */ + /* */ + /* There are two options. */ + /* */ + /* - TT_CONFIG_OPTION_SUBPIXEL_HINTING (TT_INTERPRETER_VERSION_38): This is associated with the */ + /* `Infinality' moniker. Contributed by an individual nicknamed */ + /* Infinality with the goal of making TrueType fonts render better */ + /* than on Windows. A high amount of configurability and flexibility, */ + /* down to rules for single glyphs in fonts, but also very slow. Its */ + /* experimental and slow nature and the original developer losing */ + /* interest meant that this option was never enabled in default */ + /* builds. */ + /* */ + /* - TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN (TT_INTERPRETER_VERSION_40): The new default mode for */ + /* the TrueType driver. The Infinality code base was stripped to the */ + /* bare minimum and all configurability removed in the name of speed */ + /* and simplicity. The configurability was mainly aimed at legacy */ + /* fonts like Arial, Times New Roman, or Courier. Legacy fonts are */ + /* fonts that modify vertical stems to achieve clean black-and-white */ + /* bitmaps. The new mode focuses on applying a minimal set of rules */ + /* to all fonts indiscriminately so that modern and web fonts render */ + /* well while legacy fonts render okay. */ + /* */ + /* By undefining these, you get rendering behavior like on Windows */ + /* without ClearType, i.e., Windows XP without ClearType enabled and */ + /* Win9x (interpreter version v35). Or not, depending on how much */ + /* hinting blood and testing tears the font designer put into a given */ + /* font. If you define one or both, you can switch between between v35 */ + /* and the ones you define. */ + /* */ + /* This option requires TT_CONFIG_OPTION_BYTECODE_INTERPRETER to be */ + /* defined. */ + /* */ + /* [1] http://www.microsoft.com/typography/cleartype/truetypecleartype.aspx */ /* */ #define TT_CONFIG_OPTION_SUBPIXEL_HINTING +#define TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN /*************************************************************************/ diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h index a8097fe..fe037e5 100644 --- a/include/freetype/config/ftoption.h +++ b/include/freetype/config/ftoption.h @@ -92,7 +92,7 @@ FT_BEGIN_HEADER /* This is done to allow FreeType clients to run unmodified, forcing */ /* them to display normal gray-level anti-aliased glyphs. */ /* */ -/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ +#define FT_CONFIG_OPTION_SUBPIXEL_RENDERING /*************************************************************************/ @@ -585,24 +585,53 @@ FT_BEGIN_HEADER /*************************************************************************/ /* */ - /* Define TT_CONFIG_OPTION_SUBPIXEL_HINTING if you want to compile */ - /* EXPERIMENTAL subpixel hinting support into the TrueType driver. This */ - /* replaces the native TrueType hinting mechanism when anything but */ - /* FT_RENDER_MODE_MONO is requested. */ + /* Define TT_CONFIG_OPTION_SUBPIXEL_HINTING or */ + /* TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN if you want to compile */ + /* subpixel hinting support into the TrueType driver. This modifies the */ + /* TrueType hinting mechanism when anything but FT_RENDER_MODE_MONO is */ + /* requested. */ /* */ - /* Enabling this causes the TrueType driver to ignore instructions under */ - /* certain conditions. This is done in accordance with the guide here, */ - /* with some minor differences: */ + /* In particular, it modifies the bytecode interpreter to interpret (or */ + /* not) instructions in a certain way so that all TrueType fonts look */ + /* like they do in a Windows ClearType (DirectWrite) environment. See */ + /* [1] for a technical overview on what this means. See `ttinterp.h' */ + /* for more details on the LEAN option. */ /* */ - /* http://www.microsoft.com/typography/cleartype/truetypecleartype.aspx */ + /* There are two options. */ /* */ - /* By undefining this, you only compile the code necessary to hint */ - /* TrueType glyphs with native TT hinting. */ + /* - TT_CONFIG_OPTION_SUBPIXEL_HINTING (TT_INTERPRETER_VERSION_38): This is associated with the */ + /* `Infinality' moniker. Contributed by an individual nicknamed */ + /* Infinality with the goal of making TrueType fonts render better */ + /* than on Windows. A high amount of configurability and flexibility, */ + /* down to rules for single glyphs in fonts, but also very slow. Its */ + /* experimental and slow nature and the original developer losing */ + /* interest meant that this option was never enabled in default */ + /* builds. */ /* */ - /* This option requires TT_CONFIG_OPTION_BYTECODE_INTERPRETER to be */ - /* defined. */ + /* - TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN (TT_INTERPRETER_VERSION_40): The new default mode for */ + /* the TrueType driver. The Infinality code base was stripped to the */ + /* bare minimum and all configurability removed in the name of speed */ + /* and simplicity. The configurability was mainly aimed at legacy */ + /* fonts like Arial, Times New Roman, or Courier. Legacy fonts are */ + /* fonts that modify vertical stems to achieve clean black-and-white */ + /* bitmaps. The new mode focuses on applying a minimal set of rules */ + /* to all fonts indiscriminately so that modern and web fonts render */ + /* well while legacy fonts render okay. */ + /* */ + /* By undefining these, you get rendering behavior like on Windows */ + /* without ClearType, i.e., Windows XP without ClearType enabled and */ + /* Win9x (interpreter version v35). Or not, depending on how much */ + /* hinting blood and testing tears the font designer put into a given */ + /* font. If you define one or both, you can switch between between v35 */ + /* and the ones you define. */ + /* */ + /* This option requires TT_CONFIG_OPTION_BYTECODE_INTERPRETER to be */ + /* defined. */ + /* */ + /* [1] http://www.microsoft.com/typography/cleartype/truetypecleartype.aspx */ /* */ /* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#define TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN /*************************************************************************/ diff --git a/include/freetype/ftcffdrv.h b/include/freetype/ftcffdrv.h index b0b4299..ad34541 100644 --- a/include/freetype/ftcffdrv.h +++ b/include/freetype/ftcffdrv.h @@ -110,7 +110,7 @@ FT_BEGIN_HEADER * to minimize distortion. * * @order: - * hinting-engine + * hinting-engine[cff] * no-stem-darkening[cff] * darkening-parameters[cff] * @@ -120,7 +120,7 @@ FT_BEGIN_HEADER /************************************************************************** * * @property: - * hinting-engine + * hinting-engine[cff] * * @description: * Thanks to Adobe, which contributed a new hinting (and parsing) @@ -157,8 +157,8 @@ FT_BEGIN_HEADER * FT_CFF_HINTING_XXX * * @description: - * A list of constants used for the @hinting-engine property to select - * the hinting engine for CFF fonts. + * A list of constants used for the @hinting-engine[cff] property to + * select the hinting engine for CFF fonts. * * @values: * FT_CFF_HINTING_FREETYPE :: diff --git a/include/freetype/ftttdrv.h b/include/freetype/ftttdrv.h index 6c02e65..467bf30 100644 --- a/include/freetype/ftttdrv.h +++ b/include/freetype/ftttdrv.h @@ -138,31 +138,37 @@ FT_BEGIN_HEADER * interpreter-version * * @description: - * Currently, two versions are available, representing the bytecode - * interpreter with and without subpixel hinting support, + * Currently, three versions are available, two representing the bytecode + * interpreter with subpixel hinting support (old Infinality code and new + * stripped-down and higher performance lean code) and one without, * respectively. The default is subpixel support if - * TT_CONFIG_OPTION_SUBPIXEL_HINTING is defined, and no subpixel + * TT_CONFIG_OPTION_SUBPIXEL_HINTING or + * TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN is defined, and no subpixel * support otherwise (since it isn't available then). * * If subpixel hinting is on, many TrueType bytecode instructions behave * differently compared to B/W or grayscale rendering (except if `native - * ClearType' is selected by the font). The main idea is to render at a - * much increased horizontal resolution, then sampling down the created - * output to subpixel precision. However, many older fonts are not + * ClearType' is selected by the font). Microsoft's main idea is to render + * at a much increased horizontal resolution, then sampling down the + * created output to subpixel precision. However, many older fonts are not * suited to this and must be specially taken care of by applying - * (hardcoded) font-specific tweaks. + * (hardcoded) tweaks in Microsoft's interpreter. * * Details on subpixel hinting and some of the necessary tweaks can be * found in Greg Hitchcock's whitepaper at * `http://www.microsoft.com/typography/cleartype/truetypecleartype.aspx'. + * Note that FreeType currently doesn't really "subpixel hint" (6x1, 6x2 or + * 6x5) like discussed in the paper. Depending in the chosen interpreter, + * it simply ignores instructions on vertical stems to arrive at very + * similar results. * - * The following example code demonstrates how to activate subpixel + * The following example code demonstrates how to deactivate subpixel * hinting (omitting the error handling). * * { * FT_Library library; * FT_Face face; - * FT_UInt interpreter_version = TT_INTERPRETER_VERSION_38; + * FT_UInt interpreter_version = TT_INTERPRETER_VERSION_35; * * * FT_Init_FreeType( &library ); @@ -199,7 +205,15 @@ FT_BEGIN_HEADER * Version~38 corresponds to MS rasterizer v.1.9; it is roughly * equivalent to the hinting provided by DirectWrite ClearType (as * can be found, for example, in the Internet Explorer~9 running on - * Windows~7). + * Windows~7). It is used in FreeType to select the Infinality subpixel + * hinting code. The code may be removed in a future version. + * + * TT_INTERPRETER_VERSION_40 :: + * Version~40 corresponds to MS rasterizer v.2.1; it is roughly + * equivalent to the hinting provided by DirectWrite ClearType (as can be + * found, for example, in Microsoft's Edge Browser on Windows~10). It is + * used in FreeType to select the lean subpixel hinting code, a + * stripped-down and higher performance version of the Infinality code. * * @note: * This property controls the behaviour of the bytecode interpreter @@ -207,9 +221,10 @@ FT_BEGIN_HEADER * get rasterized! In particular, it does not control subpixel color * filtering. * - * If FreeType has not been compiled with configuration option - * FT_CONFIG_OPTION_SUBPIXEL_HINTING, selecting version~38 causes an - * `FT_Err_Unimplemented_Feature' error. + * If FreeType has not been compiled with the configuration options + * FT_CONFIG_OPTION_SUBPIXEL_HINTING and/or + * FT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN, selecting version~38 or 40 + * causes an `FT_Err_Unimplemented_Feature' error, respectively. * * Depending on the graphics framework, Microsoft uses different * bytecode and rendering engines. As a consequence, the version @@ -290,13 +305,14 @@ FT_BEGIN_HEADER * the version~1 gasp table exclusively (like Color ClearType), while * v1.6 only respects the values of version~0 (bits 0 and~1). * - * FreeType doesn't provide all capabilities of the most recent - * ClearType incarnation, thus we identify our subpixel support as - * version~38. + * Keep in mind that the features of above interpreter versions might not + * map exactly to FreeType features or behavior because it is a + * fundamentally different library with different internals. * */ #define TT_INTERPRETER_VERSION_35 35 #define TT_INTERPRETER_VERSION_38 38 +#define TT_INTERPRETER_VERSION_40 40 /* */ diff --git a/src/truetype/ttdriver.c b/src/truetype/ttdriver.c index bbebabd..7128240 100644 --- a/src/truetype/ttdriver.c +++ b/src/truetype/ttdriver.c @@ -72,11 +72,16 @@ FT_UInt* interpreter_version = (FT_UInt*)value; -#ifndef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( *interpreter_version != TT_INTERPRETER_VERSION_35 ) + if ( *interpreter_version != TT_INTERPRETER_VERSION_35 +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + && *interpreter_version != TT_INTERPRETER_VERSION_38 +#endif +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN + && *interpreter_version != TT_INTERPRETER_VERSION_40 +#endif + ) error = FT_ERR( Unimplemented_Feature ); else -#endif driver->interpreter_version = *interpreter_version; return error; diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c index c4038ee..bad9f3c 100644 --- a/src/truetype/ttgload.c +++ b/src/truetype/ttgload.c @@ -733,7 +733,8 @@ TT_Hint_Glyph( TT_Loader loader, FT_Bool is_composite ) { -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#if defined TT_CONFIG_OPTION_SUBPIXEL_HINTING || \ + defined TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN TT_Face face = loader->face; TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); #endif @@ -816,11 +817,21 @@ #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_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN + /* Save possibly modified glyph phantom points unless in v38 backwards */ + /* 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->backwards_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_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN + } +#endif #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) @@ -1078,7 +1089,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; @@ -1324,6 +1335,7 @@ * (3) for everything else. * */ + /* XXX merge infinality + lean datafields? */ #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING #define TT_LOADER_SET_PP( loader ) \ @@ -1946,7 +1958,8 @@ FT_UInt glyph_index ) { TT_Face face = loader->face; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#if defined TT_CONFIG_OPTION_SUBPIXEL_HINTING || \ + defined TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); #endif @@ -1973,11 +1986,18 @@ 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 backwards compatibility */ + /* mode of the v38 interpreter is active. See `ttinterp.h' for */ + /* details on backwards compatibility mode. */ + if ( +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN + !( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && + ( loader->exec && loader->exec->backwards_compatibility ) ) && +#endif + !face->postscript.isFixedPitch && + IS_HINTED( loader->load_flags ) && + !( loader->load_flags & FT_LOAD_COMPUTE_METRICS ) ) { FT_Byte* widthp; @@ -2193,6 +2213,10 @@ #ifdef TT_USE_BYTECODE_INTERPRETER FT_Bool pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); #endif +#if defined TT_CONFIG_OPTION_SUBPIXEL_HINTING || \ + defined TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( (TT_Face)glyph->face ); +#endif face = (TT_Face)glyph->face; @@ -2206,11 +2230,13 @@ if ( IS_HINTED( load_flags ) && !glyf_table_only ) { TT_ExecContext exec; - FT_Bool grayscale; + FT_Bool grayscale = TRUE; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN + FT_Bool subpixel_hinting_lean; + FT_Bool grayscale_cleartype; +#endif #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); - FT_Bool subpixel_hinting = FALSE; #if 0 @@ -2243,6 +2269,25 @@ if ( !exec ) return FT_THROW( Could_Not_Find_Context ); +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 ) + { + subpixel_hinting_lean = TRUE; + grayscale_cleartype = !FT_BOOL( load_flags & + FT_LOAD_TARGET_LCD || + load_flags & + FT_LOAD_TARGET_LCD_V ); + exec->vertical_lcd_lean = FT_BOOL( load_flags & + FT_LOAD_TARGET_LCD_V ); + } + else + { + subpixel_hinting_lean = FALSE; + grayscale_cleartype = FALSE; + exec->vertical_lcd_lean = FALSE; + } +#endif + #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) @@ -2302,10 +2347,15 @@ #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - { +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN + 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 ) @@ -2342,6 +2392,34 @@ #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ { + +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN + 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 ) @@ -2377,7 +2455,8 @@ #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING /* 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 diff --git a/src/truetype/ttinterp.h b/src/truetype/ttinterp.h index e5a02b9..a34044a 100644 --- a/src/truetype/ttinterp.h +++ b/src/truetype/ttinterp.h @@ -247,7 +247,133 @@ 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? */ + FT_Bool grayscale; /* bi-level hinting and */ + /* grayscale rendering */ + +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN + /* + * Modern TrueType fonts are usually rendered through Microsoft's + * collection of rendering techniques called ClearType (e.g., subpixel + * rendering and subpixel hinting). When ClearType was introduced, + * most fonts were not ready. Microsoft decided to implement a + * backwards compatibility mode that employed several simple to + * complicated assumptions and tricks that modified the interpretation + * of the bytecode contained in these fonts to make them look + * ClearType-y somehow. Most (web)fonts that were released since then + * have come to rely on these hacks to render correctly, even some of + * Microsoft's flagship ClearType fonts (Calibri, Cambria, Segoe UI). + * + * FreeType employs a small list of font-agnostic hacks to bludgeon + * non-native-ClearType fonts (except tricky ones[1]) into submission. + * FreeType will not try to toggle hacks for specific fonts for + * performance and complexity reasons. The focus is on modern + * (web)fonts rather than legacy fonts that were made for + * black-and-white rendering. + * + * 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 backwards 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 v38 + * interpreter assumes backwards 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 (v38 with + * backwards 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 v38 implies subpixel hinting. Used to detect interpreter */ + /* version switches. `_lean' to differentiate from the Infinality */ + /* `subpixel_hinting' that 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' that is */ + /* managed differently. */ + FT_Bool vertical_lcd_lean; + + /* Default to backwards compatibility mode in v38 interpreter. If */ + /* this is false, it implies the interpreter is in v35 or in native */ + /* ClearType mode. */ + FT_Bool backwards_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_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN */ #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING TT_Round_Func func_round_sphn; /* subpixel rounding function */ diff --git a/src/truetype/ttobjs.c b/src/truetype/ttobjs.c index a05f216..4ea0b39 100644 --- a/src/truetype/ttobjs.c +++ b/src/truetype/ttobjs.c @@ -1287,10 +1287,12 @@ TT_Driver driver = (TT_Driver)ttdriver; + driver->interpreter_version = TT_INTERPRETER_VERSION_35; #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING driver->interpreter_version = TT_INTERPRETER_VERSION_38; -#else - driver->interpreter_version = TT_INTERPRETER_VERSION_35; +#endif +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING_LEAN + driver->interpreter_version = TT_INTERPRETER_VERSION_40; #endif #else /* !TT_USE_BYTECODE_INTERPRETER */ -- 2.5.5