diff options
author | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-09-26 13:21:39 +0000 |
---|---|---|
committer | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-09-26 13:21:39 +0000 |
commit | 754e4ebd10d7353ce55be7dfe0a417e502ef4047 (patch) | |
tree | f1558c4545984b5d61382f9bbc30db6868de3117 | |
parent | 0e736c23cdee1dc5521e7cc69f6ef27b93a5bb95 (diff) |
set gamma flag for white, since GDI gives us different (better) values
for white-on-black text.
git-svn-id: http://skia.googlecode.com/svn/trunk@2325 2bbb7eff-a529-9590-31e7-b0007b416f81
-rwxr-xr-x | src/ports/SkFontHost_win.cpp | 161 |
1 files changed, 116 insertions, 45 deletions
diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp index 276e180f0c..2c18e42b18 100755 --- a/src/ports/SkFontHost_win.cpp +++ b/src/ports/SkFontHost_win.cpp @@ -288,6 +288,7 @@ public: fBits = NULL; fWidth = fHeight = 0; fIsBW = false; + fColor = kInvalid_Color; } ~HDCOffscreen() { @@ -304,7 +305,8 @@ public: fXform = xform; } - const void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr); + const void* draw(const SkGlyph&, bool isBW, bool whiteFG, + size_t* srcRBPtr); private: HDC fDC; @@ -312,12 +314,20 @@ private: HFONT fFont; XFORM fXform; void* fBits; // points into fBM + COLORREF fColor; int fWidth; int fHeight; bool fIsBW; + + enum { + // will always trigger us to reset the color, since we + // should only store 0 or 0xFFFFFF + kInvalid_Color = 12345 + }; }; -const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW, size_t* srcRBPtr) { +const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW, + bool whiteFG, size_t* srcRBPtr) { if (0 == fDC) { fDC = CreateCompatibleDC(0); if (0 == fDC) { @@ -327,20 +337,25 @@ const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW, size_t* srcRBPtr SetBkMode(fDC, TRANSPARENT); SetTextAlign(fDC, TA_LEFT | TA_BASELINE); SelectObject(fDC, fFont); - COLORREF color = SetTextColor(fDC, fIsBW ? 0xFFFFFF : 0); - SkASSERT(color != CLR_INVALID); + fColor = kInvalid_Color; } if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) { DeleteObject(fBM); fBM = 0; } + fIsBW = isBW; - if (fIsBW != isBW) { - fIsBW = isBW; - COLORREF color = SetTextColor(fDC, fIsBW ? 0xFFFFFF : 0); - SkASSERT(color != CLR_INVALID); + COLORREF color = 0; + if (fIsBW || whiteFG) { + color = 0xFFFFFF; + } + if (fColor != color) { + fColor = color; + COLORREF prev = SetTextColor(fDC, color); + SkASSERT(prev != CLR_INVALID); } + fWidth = SkMax32(fWidth, glyph.fWidth); fHeight = SkMax32(fHeight, glyph.fHeight); @@ -374,7 +389,7 @@ const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW, size_t* srcRBPtr // erase size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2); size_t size = fHeight * srcRB; - memset(fBits, isBW ? 0 : 0xFF, size); + memset(fBits, ~color & 0xFF, size); XFORM xform = fXform; xform.eDx = (float)-glyph.fLeft; @@ -668,18 +683,24 @@ typedef uint32_t SkGdiRGB; static inline uint8_t rgb_to_a8(SkGdiRGB rgb) { // can pick any component (low 3 bytes), since we're grayscale - // but must invert since we draw black-on-white - return ~rgb & 0xFF; + return rgb & 0xFF; } static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb) { - rgb = ~rgb; // 255 - each component int r = (rgb >> 16) & 0xFF; int g = (rgb >> 8) & 0xFF; int b = (rgb >> 0) & 0xFF; return SkPackRGB16(SkR32ToR16(r), SkG32ToG16(g), SkB32ToB16(b)); } +static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb) { + int r = (rgb >> 16) & 0xFF; + int g = (rgb >> 8) & 0xFF; + int b = (rgb >> 0) & 0xFF; + int a = SkMax32(r, SkMax32(g, b)); + return SkPackARGB32(a, r, g, b); +} + // Is this GDI color neither black nor white? If so, we have to keep this // image as is, rather than smashing it down to a BW mask. // @@ -705,7 +726,7 @@ static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, int src } static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, - const SkGlyph& glyph) { + const SkGlyph& glyph, int32_t xorMask) { const int width = glyph.fWidth; const size_t dstRB = (width + 7) >> 3; uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); @@ -721,14 +742,14 @@ static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, if (byteCount > 0) { unsigned byte = 0; for (int i = 0; i < byteCount; ++i) { - byte |= src[0] & (1 << 7); - byte |= src[1] & (1 << 6); - byte |= src[2] & (1 << 5); - byte |= src[3] & (1 << 4); - byte |= src[4] & (1 << 3); - byte |= src[5] & (1 << 2); - byte |= src[6] & (1 << 1); - byte |= src[7] & (1 << 0); + byte |= (src[0] ^ xorMask) & (1 << 7); + byte |= (src[1] ^ xorMask) & (1 << 6); + byte |= (src[2] ^ xorMask) & (1 << 5); + byte |= (src[3] ^ xorMask) & (1 << 4); + byte |= (src[4] ^ xorMask) & (1 << 3); + byte |= (src[5] ^ xorMask) & (1 << 2); + byte |= (src[6] ^ xorMask) & (1 << 1); + byte |= (src[7] ^ xorMask) & (1 << 0); dst[i] = ~byte; src += 8; } @@ -737,7 +758,7 @@ static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, unsigned byte = 0; unsigned mask = 0x80; for (int i = 0; i < bitCount; i++) { - byte |= ~src[i] & mask; + byte |= ~(src[i] ^ xorMask) & mask; mask >>= 1; } dst[byteCount] = byte; @@ -748,14 +769,14 @@ static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, } static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, - const SkGlyph& glyph) { + const SkGlyph& glyph, int32_t xorMask) { const size_t dstRB = glyph.rowBytes(); const int width = glyph.fWidth; uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); for (int y = 0; y < glyph.fHeight; y++) { for (int i = 0; i < width; i++) { - dst[i] = rgb_to_a8(src[i]); + dst[i] = rgb_to_a8(src[i] ^ xorMask); } src = (const SkGdiRGB*)((const char*)src + srcRB); dst -= dstRB; @@ -763,20 +784,35 @@ static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, } static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, - const SkGlyph& glyph) { + const SkGlyph& glyph, int32_t xorMask) { const size_t dstRB = glyph.rowBytes(); const int width = glyph.fWidth; uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); for (int y = 0; y < glyph.fHeight; y++) { for (int i = 0; i < width; i++) { - dst[i] = rgb_to_lcd16(src[i]); + dst[i] = rgb_to_lcd16(src[i] ^ xorMask); } src = (const SkGdiRGB*)((const char*)src + srcRB); dst = (uint16_t*)((char*)dst - dstRB); } } +static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, + const SkGlyph& glyph, int32_t xorMask) { + const size_t dstRB = glyph.rowBytes(); + const int width = glyph.fWidth; + SkPMColor* SK_RESTRICT dst = (SkPMColor*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); + + for (int y = 0; y < glyph.fHeight; y++) { + for (int i = 0; i < width; i++) { + dst[i] = rgb_to_lcd32(src[i] ^ xorMask); + } + src = (const SkGdiRGB*)((const char*)src + srcRB); + dst = (SkPMColor*)((char*)dst - dstRB); + } +} + void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { SkAutoMutexAcquire ac(gFTMutex); @@ -785,9 +821,11 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; const bool isAA = !isLCD(fRec); + const bool isWhite = SkToBool(fRec.fFlags & SkScalerContext::kGammaForWhite_Flag); + const uint32_t rgbXOR = isWhite ? 0 : ~0; size_t srcRB; - const void* bits = fOffscreen.draw(glyph, isBW, &srcRB); + const void* bits = fOffscreen.draw(glyph, isBW, isWhite, &srcRB); if (!bits) { sk_bzero(glyph.fImage, glyph.computeImageSize()); return; @@ -812,15 +850,20 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { } else #endif { - rgb_to_a8(src, srcRB, glyph); + rgb_to_a8(src, srcRB, glyph, rgbXOR); } } else { // LCD16 const SkGdiRGB* src = (const SkGdiRGB*)bits; if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) { - rgb_to_bw(src, srcRB, glyph); + rgb_to_bw(src, srcRB, glyph, rgbXOR); ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format; } else { - rgb_to_lcd16(src, srcRB, glyph); + if (SkMask::kLCD16_Format == glyph.fMaskFormat) { + rgb_to_lcd16(src, srcRB, glyph, rgbXOR); + } else { + SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat); + rgb_to_lcd32(src, srcRB, glyph, rgbXOR); + } } } } @@ -935,18 +978,12 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics( OUTLINETEXTMETRIC otm; if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm) || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) { - DWORD error_code = GetLastError(); - SkASSERT(error_code == 0); // GDI error, possibly caused by sandboxing. - SkASSERT(false); // GDI corruption. goto Error; } lf.lfHeight = -SkToS32(otm.otmEMSquare); designFont = CreateFontIndirect(&lf); SelectObject(hdc, designFont); if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) { - DWORD error_code = GetLastError(); - SkASSERT(error_code == 0); // GDI error, possibly caused by sandboxing. - SkASSERT(false); // GDI corruption. goto Error; } const unsigned glyphCount = calculateGlyphCount(hdc); @@ -1156,15 +1193,6 @@ size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) { return 0; // nothing to do } -int SkFontHost::ComputeGammaFlag(const SkPaint& paint) { - return 0; -} - -void SkFontHost::GetGammaTables(const uint8_t* tables[2]) { - tables[0] = NULL; // black gamma (e.g. exp=1.4) - tables[1] = NULL; // white gamma (e.g. exp= 1/1.4) -} - SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { printf("SkFontHost::CreateTypefaceFromFile unimplemented"); return NULL; @@ -1208,6 +1236,49 @@ void SkFontHost::FilterRec(SkScalerContext::Rec* rec) { rec->fMaskFormat = SkMask::kA8_Format; } #endif + +#if 0 + if (SkMask::kLCD16_Format == rec->fMaskFormat) { + rec->fMaskFormat = SkMask::kLCD32_Format; + } +#endif + if (!isLCD(*rec)) { + rec->fFlags &= ~(SkScalerContext::kGammaForBlack_Flag | + SkScalerContext::kGammaForWhite_Flag); + } +} + +////////////////////////////////////////////////////////////////////////// + +void SkFontHost::GetGammaTables(const uint8_t* tables[2]) { + tables[0] = NULL; + tables[1] = NULL; +} + +// If the luminance is <= this value, then apply the black gamma table +#define BLACK_GAMMA_THRESHOLD 0x40 + +// If the luminance is >= this value, then apply the white gamma table +#define WHITE_GAMMA_THRESHOLD 0xA0 + +int SkFontHost::ComputeGammaFlag(const SkPaint& paint) { + if (paint.getShader() == NULL && paint.getColorFilter() == NULL) { + SkColor c = paint.getColor(); + int r = SkColorGetR(c); + int g = SkColorGetG(c); + int b = SkColorGetB(c); + int luminance = (r * 2 + g * 5 + b) >> 3; + +#if 0 // we basically default to black, so don't need to return it + if (luminance <= BLACK_GAMMA_THRESHOLD) { + return SkScalerContext::kGammaForBlack_Flag; + } +#endif + if (luminance >= WHITE_GAMMA_THRESHOLD) { + return SkScalerContext::kGammaForWhite_Flag; + } + } + return 0; } #endif // WIN32 |