From 028617b90ba586bdb30723c700eea888c159ada7 Mon Sep 17 00:00:00 2001 From: ByeongSik Jeon Date: Wed, 10 Dec 2008 23:50:44 +0900 Subject: [PATCH] gdi32, winex11: Add support for subpixel font rendering. --- configure | 1 + configure.ac | 1 + dlls/gdi32/freetype.c | 149 ++++++++++++++++++++++++++++++++++++++++++++- dlls/winex11.drv/xrender.c | 76 ++++++++++++++++++----- include/config.h.in | 3 + include/wingdi.h | 7 ++- 6 files changed, 219 insertions(+), 18 deletions(-) diff --git a/configure b/configure index b31a842ba5f..8574025f5d6 100755 --- a/configure +++ b/configure @@ -14591,6 +14591,7 @@ for ac_header in ft2build.h \ freetype/ftoutln.h \ freetype/ftwinfnt.h \ freetype/ftmodapi.h \ + freetype/ftlcdfil.h \ freetype/internal/sfnt.h do as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` diff --git a/configure.ac b/configure.ac index 137aea5e1cf..ce90fcaccca 100644 --- a/configure.ac +++ b/configure.ac @@ -1040,6 +1040,7 @@ then freetype/ftoutln.h \ freetype/ftwinfnt.h \ freetype/ftmodapi.h \ + freetype/ftlcdfil.h \ freetype/internal/sfnt.h,,, [#ifdef HAVE_FT2BUILD_H # include diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index aac5fde3f96..e3c7da2046c 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -132,6 +132,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(font); #ifdef HAVE_FREETYPE_FTMODAPI_H #include #endif +#ifdef HAVE_FREETYPE_FTLCDFIL_H +#include +#endif #ifndef HAVE_FT_TRUETYPEENGINETYPE typedef enum @@ -179,7 +182,9 @@ MAKE_FUNCPTR(FT_Select_Charmap); MAKE_FUNCPTR(FT_Set_Charmap); MAKE_FUNCPTR(FT_Set_Pixel_Sizes); MAKE_FUNCPTR(FT_Vector_Transform); +MAKE_FUNCPTR(FT_Render_Glyph); static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*); +static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter); static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*); static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*); static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*); @@ -2481,10 +2486,12 @@ static BOOL init_freetype(void) LOAD_FUNCPTR(FT_Set_Charmap) LOAD_FUNCPTR(FT_Set_Pixel_Sizes) LOAD_FUNCPTR(FT_Vector_Transform) + LOAD_FUNCPTR(FT_Render_Glyph) #undef LOAD_FUNCPTR /* Don't warn if these ones are missing */ pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0); + pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0); pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0); pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0); pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0); @@ -4491,8 +4498,12 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format, needsTransform = TRUE; } - if (needsTransform || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP)) + if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER || + format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP || + format == GGO_GRAY8_BITMAP)) + { load_flags |= FT_LOAD_NO_BITMAP; + } err = pFT_Load_Glyph(ft_face, glyph_index, load_flags); @@ -4563,7 +4574,9 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format, wine_dbgstr_point(&lpgm->gmptGlyphOrigin), lpgm->gmCellIncX, lpgm->gmCellIncY); - if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) && + if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP || + format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP || + format == WINE_GGO_VRGB_BITMAP || format == WINE_GGO_VBGR_BITMAP ) && (!lpmat || is_identity_MAT2(lpmat))) /* don't cache custom transforms */ { FONT_GM(font,original_index)->gm = *lpgm; @@ -4579,7 +4592,11 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format, return 1; /* FIXME */ } - if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) { + if(ft_face->glyph->format != ft_glyph_format_outline && + (needsTransform || format == GGO_NATIVE || format == GGO_BEZIER || + format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP || + format == GGO_GRAY8_BITMAP)) + { TRACE("loaded a bitmap\n"); LeaveCriticalSection( &freetype_cs ); return GDI_ERROR; @@ -4714,6 +4731,112 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format, break; } + case WINE_GGO_HRGB_BITMAP: + case WINE_GGO_HBGR_BITMAP: + case WINE_GGO_VRGB_BITMAP: + case WINE_GGO_VBGR_BITMAP: + { + width = lpgm->gmBlackBoxX; + height = lpgm->gmBlackBoxY; + pitch = width * 4; + needed = pitch * height; + + if (!buf || !buflen) break; + + memset(buf, 0, buflen); + + switch (ft_face->glyph->format) + { + case FT_GLYPH_FORMAT_BITMAP: + { + BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf; + INT src_pitch = ft_face->glyph->bitmap.pitch; + INT x; + + while ( height-- ) + { + for (x = 0; x < width; x++) + { + if ( src[x / 8] & (1 << ( (7 - (x % 8)))) ) + ((unsigned int *)dst)[x] = ~0u; + } + src += src_pitch; + dst += pitch; + } + + break; + } + + case FT_GLYPH_FORMAT_OUTLINE: + { + unsigned int *dst = (unsigned int *) buf; + BYTE *src; + INT x, src_pitch, rgb_interval, hmul, vmul; + BOOL rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP); + FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT; + FT_Render_Mode render_mode = + (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)? + FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V; + + if ( needsTransform ) + pFT_Outline_Transform (&ft_face->glyph->outline, &transMat); + pFT_Outline_Translate (&ft_face->glyph->outline, -left, -bottom ); + if ( pFT_Library_SetLcdFilter ) + pFT_Library_SetLcdFilter( library, lcdfilter ); + pFT_Render_Glyph (ft_face->glyph, render_mode); + + src = ft_face->glyph->bitmap.buffer; + src_pitch = ft_face->glyph->bitmap.pitch; + if ( render_mode == FT_RENDER_MODE_LCD) + { + rgb_interval = 1; + hmul = 3; + vmul = 1; + } + else + { + rgb_interval = src_pitch; + hmul = 1; + vmul = 3; + } + + if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT ) + src += rgb_interval * 3; + while ( height-- ) + { + for ( x = 0; x < width; x++ ) + { + if ( rgb ) + { + dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) | + ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) | + ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) | + ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ; + } + else + { + dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) | + ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) | + ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) | + ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ; + } + } + src += src_pitch * vmul; + dst += pitch / 4; + } + + break; + } + + default: + FIXME ("loaded glyph format %x\n", ft_face->glyph->format); + LeaveCriticalSection ( &freetype_cs ); + return GDI_ERROR; + } + + break; + } + case GGO_NATIVE: { int contour, point = 0, first_pt; @@ -5792,12 +5915,24 @@ static BOOL is_hinting_enabled(void) return FALSE; } +static BOOL is_subpixel_rendering_enabled( void ) +{ + if ( !pFT_Library_SetLcdFilter ) + return FALSE; + + if ( pFT_Library_SetLcdFilter ( NULL, 0 ) == FT_Err_Unimplemented_Feature ) + return FALSE; + + return TRUE; +} + /************************************************************************* * GetRasterizerCaps (GDI32.@) */ BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes) { static int hinting = -1; + static int subpixel = -1; if(hinting == -1) { @@ -5805,8 +5940,16 @@ BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes) TRACE("hinting is %senabled\n", hinting ? "" : "NOT "); } + if ( subpixel == -1 ) + { + subpixel = is_subpixel_rendering_enabled(); + TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT "); + } + lprs->nSize = sizeof(RASTERIZER_STATUS); lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0); + if ( subpixel ) + lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED; lprs->nLanguageID = 0; return TRUE; } diff --git a/dlls/winex11.drv/xrender.c b/dlls/winex11.drv/xrender.c index 3bad0a3bc99..b343962e9b7 100644 --- a/dlls/winex11.drv/xrender.c +++ b/dlls/winex11.drv/xrender.c @@ -142,8 +142,10 @@ static CRITICAL_SECTION xrender_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; #ifdef WORDS_BIGENDIAN #define get_be_word(x) (x) +#define NATIVE_BYTE_ORDER MSBFirst #else #define get_be_word(x) RtlUshortByteSwap(x) +#define NATIVE_BYTE_ORDER LSBFirst #endif /*********************************************************************** @@ -456,6 +458,7 @@ static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz) gsCacheEntry *entry; WORD flags; static int hinter = -1; + static int subpixel = -1; if((ret = LookupEntry(plfsz)) != -1) return ret; @@ -468,13 +471,24 @@ static int GetCacheEntry(X11DRV_PDEVICE *physDev, LFANDSIZE *plfsz) if(antialias && plfsz->lf.lfQuality != NONANTIALIASED_QUALITY) { - if(hinter == -1) + if(hinter == -1 || subpixel == -1) { RASTERIZER_STATUS status; GetRasterizerCaps(&status, sizeof(status)); hinter = status.wFlags & WINE_TT_HINTER_ENABLED; + subpixel = status.wFlags & WINE_TT_SUBPIXEL_RENDERING_ENABLED; } - if(!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY) + + /* FIXME: Use the following registry information + [HKEY_CURRENT_USER\Control Panel\Desktop] + "FontSmoothing"="2" ; 0=>Off, 2=>On + "FontSmoothingType"=dword:00000002 ; 1=>Standard, 2=>Cleartype + "FontSmoothingOrientation"=dword:00000001 ; 0=>BGR, 1=>RGB + "FontSmoothingGamma"=dword:00000578 + */ + if ( subpixel && X11DRV_XRender_Installed) + entry->aa_default = AA_RGB; + else if(!hinter || !get_gasp_flags(physDev, &flags) || flags & GASP_DOGRAY) entry->aa_default = AA_Grey; else entry->aa_default = AA_None; @@ -610,12 +624,25 @@ static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format) gsCacheEntryFormat *formatEntry; UINT ggo_format = GGO_GLYPH_INDEX; XRenderPictFormat pf; + unsigned long pf_mask; static const char zero[4]; switch(format) { case AA_Grey: ggo_format |= WINE_GGO_GRAY16_BITMAP; break; + case AA_RGB: + ggo_format |= WINE_GGO_HRGB_BITMAP; + break; + case AA_BGR: + ggo_format |= WINE_GGO_HBGR_BITMAP; + break; + case AA_VRGB: + ggo_format |= WINE_GGO_VRGB_BITMAP; + break; + case AA_VBGR: + ggo_format |= WINE_GGO_VBGR_BITMAP; + break; default: ERR("aa = %d - not implemented\n", format); @@ -630,8 +657,7 @@ static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format) if(format != AA_None) { format = AA_None; entry->aa_default = AA_None; - ggo_format &= ~WINE_GGO_GRAY16_BITMAP; - ggo_format |= GGO_BITMAP; + ggo_format = GGO_GLYPH_INDEX | GGO_BITMAP; buflen = GetGlyphOutlineW(physDev->hdc, glyph, ggo_format, &gm, 0, NULL, NULL); } @@ -689,29 +715,45 @@ static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format) if(formatEntry->glyphset == 0 && X11DRV_XRender_Installed) { switch(format) { case AA_Grey: + pf_mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask, + pf.type = PictTypeDirect; pf.depth = 8; + pf.direct.alpha = 0; pf.direct.alphaMask = 0xff; break; + case AA_RGB: + case AA_BGR: + case AA_VRGB: + case AA_VBGR: + pf_mask = PictFormatType | PictFormatDepth | PictFormatRed | PictFormatRedMask | + PictFormatGreen | PictFormatGreenMask | PictFormatBlue | + PictFormatBlueMask | PictFormatAlpha | PictFormatAlphaMask; + pf.type = PictTypeDirect; + pf.depth = 32; + pf.direct.red = 16; + pf.direct.redMask = 0xff; + pf.direct.green = 8; + pf.direct.greenMask = 0xff; + pf.direct.blue = 0; + pf.direct.blueMask = 0xff; + pf.direct.alpha = 24; + pf.direct.alphaMask = 0xff; + break; + default: ERR("aa = %d - not implemented\n", format); case AA_None: + pf_mask = PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask, + pf.type = PictTypeDirect; pf.depth = 1; + pf.direct.alpha = 0; pf.direct.alphaMask = 1; break; } - pf.type = PictTypeDirect; - pf.direct.alpha = 0; - wine_tsx11_lock(); - formatEntry->font_format = pXRenderFindFormat(gdi_display, - PictFormatType | - PictFormatDepth | - PictFormatAlpha | - PictFormatAlphaMask, - &pf, 0); - + formatEntry->font_format = pXRenderFindFormat(gdi_display, pf_mask, &pf, 0); formatEntry->glyphset = pXRenderCreateGlyphSet(gdi_display, formatEntry->font_format); wine_tsx11_unlock(); } @@ -783,6 +825,12 @@ static BOOL UploadGlyph(X11DRV_PDEVICE *physDev, int glyph, AA_Type format) *byte++ = c; } } + else if ( format != AA_Grey && + ImageByteOrder (gdi_display) != NATIVE_BYTE_ORDER) + { + unsigned int i, *data = (unsigned int *)buf; + for (i = buflen / sizeof(int); i; i--, data++) *data = RtlUlongByteSwap(*data); + } gid = glyph; /* diff --git a/include/config.h.in b/include/config.h.in index cee19973555..790c6ba673f 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -117,6 +117,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_FREETYPE_FTGLYPH_H +/* Define to 1 if you have the header file. */ +#undef HAVE_FREETYPE_FTLCDFIL_H + /* Define to 1 if you have the header file. */ #undef HAVE_FREETYPE_FTMODAPI_H diff --git a/include/wingdi.h b/include/wingdi.h index ac4ba2bff86..58411034dee 100644 --- a/include/wingdi.h +++ b/include/wingdi.h @@ -1297,7 +1297,11 @@ typedef struct #define GGO_UNHINTED 0x100 #ifdef __WINESRC__ -#define WINE_GGO_GRAY16_BITMAP 0x7f +#define WINE_GGO_GRAY16_BITMAP 0x10 +#define WINE_GGO_HRGB_BITMAP 0x11 +#define WINE_GGO_HBGR_BITMAP 0x12 +#define WINE_GGO_VRGB_BITMAP 0x13 +#define WINE_GGO_VBGR_BITMAP 0x14 #endif typedef struct @@ -1424,6 +1428,7 @@ typedef struct #define TT_ENABLED 0x0002 #ifdef __WINESRC__ +#define WINE_TT_SUBPIXEL_RENDERING_ENABLED 0x4000 #define WINE_TT_HINTER_ENABLED 0x8000 #endif -- 2.11.4.GIT