From fd668cfffe3fdcfbf6e0b858343a62818d337590 Mon Sep 17 00:00:00 2001 From: "bungeman@google.com" Date: Fri, 24 Aug 2012 17:46:11 +0000 Subject: [PATCH] Fix greenish text rendering on Linux. https://codereview.appspot.com/6484048/ git-svn-id: http://skia.googlecode.com/svn/trunk@5280 2bbb7eff-a529-9590-31e7-b0007b416f81 --- gyp/core.gyp | 1 - gyp/ports.gyp | 17 +++++++++++++ src/core/SkMaskGamma.cpp | 9 ++++--- src/core/SkPaint.cpp | 7 ++++-- src/core/SkScalerContext.h | 5 ++-- src/ports/SkFontHost_FreeType.cpp | 51 +++++++++++++++++++++++++++++++-------- 6 files changed, 72 insertions(+), 18 deletions(-) diff --git a/gyp/core.gyp b/gyp/core.gyp index 47a46ac..806626a 100644 --- a/gyp/core.gyp +++ b/gyp/core.gyp @@ -27,7 +27,6 @@ ], 'link_settings': { 'libraries': [ - '-lfreetype', '-lpthread', ], }, diff --git a/gyp/ports.gyp b/gyp/ports.gyp index 34c0540..f070ac6 100644 --- a/gyp/ports.gyp +++ b/gyp/ports.gyp @@ -37,12 +37,23 @@ ], 'conditions': [ [ 'skia_os in ["linux", "freebsd", "openbsd", "solaris"]', { + 'defines': [ + #The font host requires at least FreeType 2.3.0 at runtime. + 'SK_FONTHOST_FREETYPE_RUNTIME_VERSION=0x020300', + 'SK_CAN_USE_DLOPEN=1', + ], 'sources': [ '../src/ports/SkThread_pthread.cpp', '../src/ports/SkFontHost_FreeType.cpp', '../src/ports/SkFontHost_FreeType_common.cpp', '../src/ports/SkFontHost_linux.cpp', ], + 'link_settings': { + 'libraries': [ + '-lfreetype', + '-ldl', + ], + }, }], [ 'skia_os == "mac"', { 'include_dirs': [ @@ -100,6 +111,12 @@ ], }], [ 'skia_os == "android"', { + 'defines': [ + #Android provides at least FreeType 2.4.0 at runtime. + 'SK_FONTHOST_FREETYPE_RUNTIME_VERSION=0x020400', + #Skia should not use dlopen on Android. + 'SK_CAN_USE_DLOPEN=0', + ], 'sources!': [ '../src/ports/SkDebug_stdio.cpp', ], diff --git a/src/core/SkMaskGamma.cpp b/src/core/SkMaskGamma.cpp index 47903fb..449a78d 100644 --- a/src/core/SkMaskGamma.cpp +++ b/src/core/SkMaskGamma.cpp @@ -53,9 +53,12 @@ void SkTMaskGamma_build_correcting_lut(uint8_t table[256], U8CPU srcI, SkScalar const SkColorSpaceLuminance& dstConvert) { const float src = (float)srcI / 255.0f; const float linSrc = srcConvert.toLuma(src); - //Guess at the dst. - const float linDst = 1.0f - linSrc; - const float dst = dstConvert.fromLuma(linDst); + //Guess at the dst. The perceptual inverse provides smaller visual + //discontinuities when slight changes to desaturated colors cause a channel + //to map to a different correcting lut with neighboring srcI. + //See https://code.google.com/p/chromium/issues/detail?id=141425#c59 . + const float dst = 1.0f - src; + const float linDst = dstConvert.toLuma(dst); //Contrast value tapers off to 0 as the src luminance becomes white const float adjustedContrast = SkScalarToFloat(contrast) * linDst; diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 9c810be..6ea03b4 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -1706,8 +1706,11 @@ void SkScalerContext::PostMakeRec(const SkPaint& paint, SkScalerContext::Rec* re SkColor color = rec->getLuminanceColor(); SkAutoMutexAcquire ama(gMaskGammaCacheMutex); U8CPU lum = cachedPaintLuminance(rec->getPaintGamma())->computeLuminance(color); - // HACK: Prevents green from being pre-blended as white. - lum -= ((255 - lum) * lum) / 255; + //If we are asked to look like LCD, look like LCD. + if (!(rec->fFlags & SkScalerContext::kGenA8FromLCD_Flag)) { + // HACK: Prevents green from being pre-blended as white. + lum -= ((255 - lum) * lum) / 255; + } // reduce to our finite number of bits SkMaskGamma* maskGamma = cachedMaskGamma(rec->getContrast(), diff --git a/src/core/SkScalerContext.h b/src/core/SkScalerContext.h index 085e31d..2443aaf 100644 --- a/src/core/SkScalerContext.h +++ b/src/core/SkScalerContext.h @@ -108,8 +108,9 @@ struct SkScalerContextRec { //The following typedef hides from the rest of the implementation the number of //most significant bits to consider when creating mask gamma tables. Two bits //per channel was chosen as a balance between fidelity (more bits) and cache -//sizes (fewer bits). -typedef SkTMaskGamma<2, 2, 2> SkMaskGamma; +//sizes (fewer bits). Three bits per channel was chosen when #303942; (used by +//the Chrome UI) turned out too green. +typedef SkTMaskGamma<3, 3, 3> SkMaskGamma; class SkScalerContext { public: diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp index 45ae7ec..3d6b574 100644 --- a/src/ports/SkFontHost_FreeType.cpp +++ b/src/ports/SkFontHost_FreeType.cpp @@ -24,6 +24,9 @@ #include "SkTemplates.h" #include "SkThread.h" +#if defined(SK_CAN_USE_DLOPEN) +#include +#endif #include #include FT_FREETYPE_H #include FT_OUTLINE_H @@ -83,23 +86,51 @@ static bool gLCDSupportValid; // true iff |gLCDSupport| has been set. static bool gLCDSupport; // true iff LCD is supported by the runtime. static int gLCDExtra; // number of extra pixels for filtering. +// FT_Library_SetLcdFilterWeights was introduced in FreeType 2.4.0. +// The following platforms provide FreeType of at least 2.4.0. +// Ubuntu >= 11.04 (previous deprecated April 2013) +// Debian >= 6.0 (good) +// OpenSuse >= 11.4 (previous deprecated January 2012 / Nov 2013 for Evergreen 11.2) +// Fedora >= 14 (good) +// Android >= Gingerbread (good) +typedef FT_Error (*FT_Library_SetLcdFilterWeightsProc)(FT_Library, unsigned char*); + ///////////////////////////////////////////////////////////////////////// -static bool -InitFreetype() { +static bool InitFreetype() { FT_Error err = FT_Init_FreeType(&gFTLibrary); if (err) { return false; } - // Setup LCD filtering. This reduces colour fringes for LCD rendered - // glyphs. + // Setup LCD filtering. This reduces color fringes for LCD smoothed glyphs. #ifdef FT_LCD_FILTER_H - err = FT_Library_SetLcdFilter(gFTLibrary, FT_LCD_FILTER_DEFAULT); -// err = FT_Library_SetLcdFilter(gFTLibrary, FT_LCD_FILTER_LIGHT); - gLCDSupport = err == 0; - if (gLCDSupport) { - gLCDExtra = 2; //DEFAULT and LIGHT add one pixel to each side. + //Use light as default, as FT_LCD_FILTER_DEFAULT adds up to 0x110. + err = FT_Library_SetLcdFilter(gFTLibrary, FT_LCD_FILTER_LIGHT); + if (0 == err) { + gLCDSupport = true; + gLCDExtra = 2; //Using a filter adds one full pixel to each side. + + static unsigned char gaussianLikeWeights[] = { 0x17, 0x40, 0x52, 0x40, 0x17 }; + //static unsigned char triangleLikeWeights[] = { 0x1C, 0x39, 0x56, 0x39, 0x1C }; + +#if defined(SK_FONTHOST_FREETYPE_RUNTIME_VERSION) && \ + SK_FONTHOST_FREETYPE_RUNTIME_VERSION > 0x020400 + err = FT_Library_SetLcdFilterWeights(gFTLibrary, gaussianLikeWeights); +#elif defined(SK_CAN_USE_DLOPEN) && SK_CAN_USE_DLOPEN == 1 + //The FreeType library is already loaded, so symbols are available in process. + void* self = dlopen(NULL, RTLD_LAZY); + if (NULL != self) { + FT_Library_SetLcdFilterWeightsProc setLcdFilterWeights; + //The following cast is non-standard, but safe for POSIX. + *reinterpret_cast(&setLcdFilterWeights) = dlsym(self, "FT_Library_SetLcdFilterWeights"); + dlclose(self); + + if (NULL != setLcdFilterWeights) { + err = setLcdFilterWeights(gFTLibrary, gaussianLikeWeights); + } + } +#endif } #else gLCDSupport = false; @@ -610,7 +641,7 @@ void SkFontHost::FilterRec(SkScalerContext::Rec* rec) { if (rec->fTextSize > SkIntToScalar(1 << 14)) { rec->fTextSize = SkIntToScalar(1 << 14); } - + if (!gLCDSupportValid) { InitFreetype(); FT_Done_FreeType(gFTLibrary); -- 2.7.4