Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=46512 -- 'ClearType compatible advance width'[1] is introduced by Microsoft to ensure that it is compatible with previous GRAY and B/W antialias metric. This can be specified as CLEARTYPE_QUALITY. Unfortunately, Freetype does not have 'ClearType compatible advance widths'[2].
So, we need to use FT_LOAD_TARGET_MONO to get the right advance value. Please note that this flag is a hinting flag, not a rendering flag.
FT_LOAD_TARGET_LCD can be used for CLEARTYPE_NATURAL_QUALITY [3].
[1] http://rastertragedy.com/RTRCh4.htm#Sec2
[2] Freetype interpreter V38(A.K.A. Infinality patch) is trying to implement it, but there are many bugs and no further improvements. This is not included in the default build option, and is documented as being deprecated in the future.
[3] With CLEARTYPE_NATURAL_QUALITY(ClearType natural advance widths), some legacy fonts are not ( integer ) linear with the advance width. To avoid the subpixel color blending problem between the small side-bearing characters, Microsoft seems to have modified the right-side-bearing. Also, there are issues that pointed out in [1].
This may be a text layout issue, but FT_LOAD_TARGET_LCD is still valid. To solve this, Wine need an additional advance correction patch, but it's not yet an interesting issue compared to other issues.
Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- dlls/gdi32/freetype.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index c38108eece..85cff28c22 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -6897,31 +6897,28 @@ static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int b return needed; }
-static FT_Int get_load_flags( UINT format ) +static FT_Int get_load_flags( UINT format, GdiFont *font ) { + BOOL natural_width; FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
if (format & GGO_UNHINTED) return load_flags | FT_LOAD_NO_HINTING;
+ natural_width = font->font_desc.lf.lfQuality == CLEARTYPE_NATURAL_QUALITY; + switch (format & ~GGO_GLYPH_INDEX) { - case GGO_BITMAP: - load_flags |= FT_LOAD_TARGET_MONO; - break; - case GGO_GRAY2_BITMAP: - case GGO_GRAY4_BITMAP: - case GGO_GRAY8_BITMAP: - case WINE_GGO_GRAY16_BITMAP: - load_flags |= FT_LOAD_TARGET_NORMAL; - break; case WINE_GGO_HRGB_BITMAP: case WINE_GGO_HBGR_BITMAP: - load_flags |= FT_LOAD_TARGET_LCD; + load_flags |= natural_width ? FT_LOAD_TARGET_LCD : FT_LOAD_TARGET_MONO; break; case WINE_GGO_VRGB_BITMAP: case WINE_GGO_VBGR_BITMAP: - load_flags |= FT_LOAD_TARGET_LCD_V; + load_flags |= natural_width ? FT_LOAD_TARGET_LCD_V : FT_LOAD_TARGET_MONO; + break; + default: + load_flags |= FT_LOAD_TARGET_MONO; break; }
@@ -6947,7 +6944,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, FT_Vector adv; INT origin_x = 0, origin_y = 0; FT_Angle angle = 0; - FT_Int load_flags = get_load_flags(format); + FT_Int load_flags = get_load_flags(format, incoming_font); double widthRatio = 1.0; FT_Matrix transMat = identityMat; FT_Matrix transMatUnrotated;
Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=41639 -- Freetype<2.8.1 V40 has the wrong advance width issue, the wrong rendering issue. This workaround is required for the Linux distribution that contains the old version of Freetype.
These two patches help Wine resolve issues caused by fragmentation of Freetype version and build option.
I didn't mean to, but this patch also solves the wine-bug#41639. This is the patch on the init_freetype(). It's not relevant to my old patch using the gasp table.
Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- dlls/gdi32/freetype.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 85cff28c22..3786b5dbdf 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -169,6 +169,7 @@ static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library); #ifdef FT_LCD_FILTER_H static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter); #endif +static FT_Error (*pFT_Property_Set)(FT_Library, const FT_String *, const FT_String *, const void *);
#ifdef SONAME_LIBFONTCONFIG #include <fontconfig/fontconfig.h> @@ -4161,6 +4162,7 @@ static BOOL init_freetype(void) #ifdef FT_LCD_FILTER_H pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0); #endif + pFT_Property_Set = wine_dlsym(ft_handle, "FT_Property_Set", NULL, 0);
if(pFT_Init_FreeType(&library) != 0) { ERR("Can't init FreeType library\n"); @@ -4175,6 +4177,13 @@ static BOOL init_freetype(void) ((FT_Version.minor << 8) & 0x00ff00) | ((FT_Version.patch ) & 0x0000ff);
+ /* Freetype(<2.8.1) V40's FT_LOAD_TARGET_MONO is not compatible with advance width. */ + if (pFT_Property_Set && FT_SimpleVersion < ((2 << 16) | (8 << 8) | (1 << 0))) + { + FT_UInt interpreter_version = 35; + pFT_Property_Set( library, "truetype", "interpreter-version", &interpreter_version ); + } + font_driver = &freetype_funcs; return TRUE;
Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net --- dlls/gdi32/freetype.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 3786b5dbdf..999b921b9d 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -130,6 +130,7 @@ typedef struct } FT_Version_t; static FT_Version_t FT_Version; static DWORD FT_SimpleVersion; +#define FT_VERSION_VALUE(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch))
static void *ft_handle = NULL;
@@ -1004,7 +1005,7 @@ static BOOL is_subpixel_rendering_enabled( void ) if (enabled == -1) { /* FreeType >= 2.8.1 offers LCD-optimezed rendering without lcd filters. */ - if (FT_SimpleVersion >= ((2 << 16) | (8 << 8) | (1 << 0))) + if (FT_SimpleVersion >= FT_VERSION_VALUE(2, 8, 1)) enabled = TRUE; #ifdef FT_LCD_FILTER_H else if (pFT_Library_SetLcdFilter && @@ -2189,7 +2190,7 @@ static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_da }
/* There are too many bugs in FreeType < 2.1.9 for bitmap font support */ - if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) + if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < FT_VERSION_VALUE(2, 1, 9)) { WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr); goto fail; @@ -4178,7 +4179,7 @@ static BOOL init_freetype(void) ((FT_Version.patch ) & 0x0000ff);
/* Freetype(<2.8.1) V40's FT_LOAD_TARGET_MONO is not compatible with advance width. */ - if (pFT_Property_Set && FT_SimpleVersion < ((2 << 16) | (8 << 8) | (1 << 0))) + if (pFT_Property_Set && FT_SimpleVersion < FT_VERSION_VALUE(2, 8, 1)) { FT_UInt interpreter_version = 35; pFT_Property_Set( library, "truetype", "interpreter-version", &interpreter_version ); @@ -7125,7 +7126,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face)); /* there is a freetype bug where vertical metrics are only properly scaled and correct in 2.4.0 or greater */ - if ((vertical_metrics) && (FT_Version.major < 2 || (FT_Version.major == 2 && FT_Version.minor < 4))) + if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4 ,0)) vertical_metrics = FALSE;
if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
https://bugs.winehq.org/show_bug.cgi?id=46512#c7
Following these patches, I uploaded additional patches.
Byeongsik Jeon wrote:
Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=46512
'ClearType compatible advance width'[1] is introduced by Microsoft to ensure that it is compatible with previous GRAY and B/W antialias metric. This can be specified as CLEARTYPE_QUALITY. Unfortunately, Freetype does not have 'ClearType compatible advance widths'[2].
So, we need to use FT_LOAD_TARGET_MONO to get the right advance value. Please note that this flag is a hinting flag, not a rendering flag.
FT_LOAD_TARGET_LCD can be used for CLEARTYPE_NATURAL_QUALITY [3].
[1] http://rastertragedy.com/RTRCh4.htm#Sec2
[2] Freetype interpreter V38(A.K.A. Infinality patch) is trying to implement it, but there are many bugs and no further improvements. This is not included in the default build option, and is documented as being deprecated in the future.
[3] With CLEARTYPE_NATURAL_QUALITY(ClearType natural advance widths), some legacy fonts are not ( integer ) linear with the advance width. To avoid the subpixel color blending problem between the small side-bearing characters, Microsoft seems to have modified the right-side-bearing. Also, there are issues that pointed out in [1].
This may be a text layout issue, but FT_LOAD_TARGET_LCD is still valid. To solve this, Wine need an additional advance correction patch, but it's not yet an interesting issue compared to other issues.
Signed-off-by: Byeongsik Jeon bsjeon@hanmail.net
dlls/gdi32/freetype.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index c38108eece..85cff28c22 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -6897,31 +6897,28 @@ static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int b return needed; }
-static FT_Int get_load_flags( UINT format ) +static FT_Int get_load_flags( UINT format, GdiFont *font ) {
BOOL natural_width; FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
if (format & GGO_UNHINTED) return load_flags | FT_LOAD_NO_HINTING;
natural_width = font->font_desc.lf.lfQuality == CLEARTYPE_NATURAL_QUALITY;
switch (format & ~GGO_GLYPH_INDEX) {
- case GGO_BITMAP:
load_flags |= FT_LOAD_TARGET_MONO;
break;
- case GGO_GRAY2_BITMAP:
- case GGO_GRAY4_BITMAP:
- case GGO_GRAY8_BITMAP:
- case WINE_GGO_GRAY16_BITMAP:
load_flags |= FT_LOAD_TARGET_NORMAL;
case WINE_GGO_HRGB_BITMAP: case WINE_GGO_HBGR_BITMAP:break;
load_flags |= FT_LOAD_TARGET_LCD;
case WINE_GGO_VRGB_BITMAP: case WINE_GGO_VBGR_BITMAP:load_flags |= natural_width ? FT_LOAD_TARGET_LCD : FT_LOAD_TARGET_MONO; break;
load_flags |= FT_LOAD_TARGET_LCD_V;
load_flags |= natural_width ? FT_LOAD_TARGET_LCD_V : FT_LOAD_TARGET_MONO;
break;
- default:
}load_flags |= FT_LOAD_TARGET_MONO; break;
@@ -6947,7 +6944,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format, FT_Vector adv; INT origin_x = 0, origin_y = 0; FT_Angle angle = 0;
- FT_Int load_flags = get_load_flags(format);
- FT_Int load_flags = get_load_flags(format, incoming_font); double widthRatio = 1.0; FT_Matrix transMat = identityMat; FT_Matrix transMatUnrotated;