diff options
author | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-07-26 19:33:08 +0000 |
---|---|---|
committer | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-07-26 19:33:08 +0000 |
commit | 82a34d83f646d069ef2d1d7b649d0a0b1829d62f (patch) | |
tree | 25731a9300a75b393ba7e685f131b90b7731bc12 | |
parent | cee661af926cc977addc6e039b7022975a448ace (diff) |
GetGlyphOutline can return clipped results :( so we now draw offscreen
instead, as we always did for BW and lcd. This means sometimes we get
BG results when we requested AA, since GDI can decide (based on user-settings)
that we're too small for AA :(
git-svn-id: http://skia.googlecode.com/svn/trunk@1960 2bbb7eff-a529-9590-31e7-b0007b416f81
-rwxr-xr-x | src/ports/SkFontHost_win.cpp | 231 |
1 files changed, 112 insertions, 119 deletions
diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp index 01d2421443..c8acdbdf0e 100755 --- a/src/ports/SkFontHost_win.cpp +++ b/src/ports/SkFontHost_win.cpp @@ -33,6 +33,11 @@ // client3d has to undefine this for now #define CAN_USE_LOGFONT_NAME +static bool isLCD(const SkScalerContext::Rec& rec) { + return SkMask::kLCD16_Format == rec.fMaskFormat || + SkMask::kLCD32_Format == rec.fMaskFormat; +} + using namespace skia_advanced_typeface_metrics_utils; static const uint16_t BUFFERSIZE = (16384 - 32); @@ -53,6 +58,7 @@ static void make_canonical(LOGFONT* lf) { lf->lfHeight = -gCanonicalTextSize; lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY; lf->lfCharSet = DEFAULT_CHARSET; +// lf->lfClipPrecision = 64; } static SkTypeface::Style getStyle(const LOGFONT& lf) { @@ -290,6 +296,18 @@ static bool needHiResMetrics(const SkScalar mat[2][2]) { return mat[1][0] || mat[0][1]; } +static BYTE compute_quality(const SkScalerContext::Rec& rec) { + switch (rec.fMaskFormat) { + case SkMask::kBW_Format: + return NONANTIALIASED_QUALITY; + case SkMask::kLCD16_Format: + case SkMask::kLCD32_Format: + return CLEARTYPE_QUALITY; + default: + return ANTIALIASED_QUALITY; + } +} + SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc) : SkScalerContext(desc), fDDC(0), fFont(0), fSavefont(0), fSC(0) , fGlyphCount(-1) { @@ -318,6 +336,7 @@ SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc) LOGFONT lf; GetLogFontByID(fRec.fFontID, &lf); lf.lfHeight = -gCanonicalTextSize; + lf.lfQuality = compute_quality(fRec); fFont = CreateFontIndirect(&lf); // if we're rotated, or want fractional widths, create a hires font @@ -415,16 +434,14 @@ void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) { glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX); glyph->fAdvanceY = -SkIntToFixed(gm.gmCellIncY); - // we outset by 1 in all dimensions, since the lcd image may bleed outside + // we outset by 1 in all dimensions, since the image may bleed outside // of the computed bounds returned by GetGlyphOutline. // This was deduced by trial and error for small text (e.g. 8pt), so there // maybe a more precise way to make this adjustment... - if (SkMask::kLCD16_Format == fRec.fMaskFormat) { - glyph->fWidth += 2; - glyph->fHeight += 2; - glyph->fTop -= 1; - glyph->fLeft -= 1; - } + glyph->fWidth += 2; + glyph->fHeight += 2; + glyph->fTop -= 1; + glyph->fLeft -= 1; if (fHiResFont) { SelectObject(fDDC, fHiResFont); @@ -479,6 +496,14 @@ void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPa #include "SkColorPriv.h" +static inline uint8_t rgb_to_a8(uint32_t rgb) { + // can pick any component, since we're grayscale + int r = (rgb >> 16) & 0xFF; + // invert, since we draw black-on-white, but we want the original + // src mask values. + return 255 - r; +} + static inline uint16_t rgb_to_lcd16(uint32_t rgb) { int r = (rgb >> 16) & 0xFF; int g = (rgb >> 8) & 0xFF; @@ -507,121 +532,94 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { SkASSERT(fDDC); const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; - if ((SkMask::kLCD16_Format == fRec.fMaskFormat) || isBW) { - HDC dc = CreateCompatibleDC(0); - void* bits = 0; - int biWidth = isBW ? alignTo32(glyph.fWidth) : glyph.fWidth; - MyBitmapInfo info; - sk_bzero(&info, sizeof(info)); - if (isBW) { - RGBQUAD blackQuad = { 0, 0, 0, 0 }; - RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 }; - info.bmiColors[0] = blackQuad; - info.bmiColors[1] = whiteQuad; - } - info.bmiHeader.biSize = sizeof(info.bmiHeader); - info.bmiHeader.biWidth = biWidth; - info.bmiHeader.biHeight = glyph.fHeight; - info.bmiHeader.biPlanes = 1; - info.bmiHeader.biBitCount = isBW ? 1 : 32; - info.bmiHeader.biCompression = BI_RGB; - if (isBW) { - info.bmiHeader.biClrUsed = 2; - } - HBITMAP bm = CreateDIBSection(dc, &info, DIB_RGB_COLORS, &bits, 0, 0); - SelectObject(dc, bm); - - // erase to white - size_t srcRB = isBW ? (biWidth >> 3) : (glyph.fWidth << 2); - size_t size = glyph.fHeight * srcRB; - memset(bits, isBW ? 0 : 0xFF, size); - - SetGraphicsMode(dc, GM_ADVANCED); - SetBkMode(dc, TRANSPARENT); - SetTextAlign(dc, TA_LEFT | TA_BASELINE); - - XFORM xform = fXform; - xform.eDx = (float)-glyph.fLeft; - xform.eDy = (float)-glyph.fTop; - SetWorldTransform(dc, &xform); - - HGDIOBJ prevFont = SelectObject(dc, fFont); - COLORREF color = SetTextColor(dc, isBW ? 0xFFFFFF : 0); - SkASSERT(color != CLR_INVALID); - uint16_t glyphID = glyph.getGlyphID(); + const bool isAA = !isLCD(fRec); + HDC dc = CreateCompatibleDC(0); + void* bits = 0; + int biWidth = isBW ? alignTo32(glyph.fWidth) : glyph.fWidth; + + MyBitmapInfo info; + sk_bzero(&info, sizeof(info)); + if (isBW) { + RGBQUAD blackQuad = { 0, 0, 0, 0 }; + RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 }; + info.bmiColors[0] = blackQuad; + info.bmiColors[1] = whiteQuad; + } + info.bmiHeader.biSize = sizeof(info.bmiHeader); + info.bmiHeader.biWidth = biWidth; + info.bmiHeader.biHeight = glyph.fHeight; + info.bmiHeader.biPlanes = 1; + info.bmiHeader.biBitCount = isBW ? 1 : 32; + info.bmiHeader.biCompression = BI_RGB; + if (isBW) { + info.bmiHeader.biClrUsed = 2; + } + HBITMAP bm = CreateDIBSection(dc, &info, DIB_RGB_COLORS, &bits, 0, 0); + SelectObject(dc, bm); + + // erase to white + size_t srcRB = isBW ? (biWidth >> 3) : (glyph.fWidth << 2); + size_t size = glyph.fHeight * srcRB; + memset(bits, isBW ? 0 : 0xFF, size); + + SetGraphicsMode(dc, GM_ADVANCED); + SetBkMode(dc, TRANSPARENT); + SetTextAlign(dc, TA_LEFT | TA_BASELINE); + + XFORM xform = fXform; + xform.eDx = (float)-glyph.fLeft; + xform.eDy = (float)-glyph.fTop; + SetWorldTransform(dc, &xform); + + HGDIOBJ prevFont = SelectObject(dc, fFont); + COLORREF color = SetTextColor(dc, isBW ? 0xFFFFFF : 0); + SkASSERT(color != CLR_INVALID); + uint16_t glyphID = glyph.getGlyphID(); #if defined(UNICODE) - ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCWSTR)&glyphID, 1, NULL); + ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCWSTR)&glyphID, 1, NULL); #else - ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&glyphID, 1, NULL); + ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&glyphID, 1, NULL); #endif - GdiFlush(); - - // downsample from rgba to rgb565 - int width = glyph.fWidth; - size_t dstRB = glyph.rowBytes(); - if (isBW) { - const uint8_t* src = (const uint8_t*)bits; - // gdi's bitmap is upside-down, so we reverse dst walking in Y - uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); - for (int y = 0; y < glyph.fHeight; y++) { - memcpy(dst, src, dstRB); - src += srcRB; - dst -= dstRB; - } - } else { // LCD16 - const uint32_t* src = (const uint32_t*)bits; - // gdi's bitmap is upside-down, so we reverse dst walking in Y - uint16_t* 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]); - } - src = (const uint32_t*)((const char*)src + srcRB); - dst = (uint16_t*)((char*)dst - dstRB); - } + GdiFlush(); + + // downsample from rgba to rgb565 + int width = glyph.fWidth; + size_t dstRB = glyph.rowBytes(); + if (isBW) { + const uint8_t* src = (const uint8_t*)bits; + // gdi's bitmap is upside-down, so we reverse dst walking in Y + uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); + for (int y = 0; y < glyph.fHeight; y++) { + memcpy(dst, src, dstRB); + src += srcRB; + dst -= dstRB; } - - DeleteDC(dc); - DeleteObject(bm); - return; - } - - GLYPHMETRICS gm; - memset(&gm, 0, sizeof(gm)); - uint32_t bytecount = 0; - uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); - if (GDI_ERROR != total_size && total_size > 0) { - SkAutoSMalloc<1024> storage(total_size); - uint8_t *pBuff = (uint8_t*)storage.get(); - total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, total_size, pBuff, &fMat22); - SkASSERT(total_size != GDI_ERROR); - SkASSERT(glyph.fWidth == gm.gmBlackBoxX); - SkASSERT(glyph.fHeight == gm.gmBlackBoxY); - - uint8_t* dst = (uint8_t*)glyph.fImage; - uint32_t pitch = (gm.gmBlackBoxX + 3) & ~0x3; - if (pitch != glyph.rowBytes()) { - SkASSERT(false); // glyph.fImage has different rowsize!? + } else if (isAA) { + const uint32_t* src = (const uint32_t*)bits; + // gdi's bitmap is upside-down, so we reverse dst walking in Y + uint8_t* 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]); + } + src = (const uint32_t*)((const char*)src + srcRB); + dst -= dstRB; } - - for (int32_t y = gm.gmBlackBoxY - 1; y >= 0; y--) { - const uint8_t* src = pBuff + pitch * y; - - for (uint32_t x = 0; x < gm.gmBlackBoxX; x++) { - if (*src > 63) { - *dst = 0xFF; - } else { - *dst = *src << 2; // scale to 0-255 - } - dst++; - src++; - bytecount++; + } else { // LCD16 + const uint32_t* src = (const uint32_t*)bits; + // gdi's bitmap is upside-down, so we reverse dst walking in Y + uint16_t* 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]); } - memset(dst, 0, glyph.rowBytes() - glyph.fWidth); - dst += glyph.rowBytes() - glyph.fWidth; + src = (const uint32_t*)((const char*)src + srcRB); + dst = (uint16_t*)((char*)dst - dstRB); } } - SkASSERT(GDI_ERROR != total_size && total_size >= 0); + + DeleteDC(dc); + DeleteObject(bm); } void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) { @@ -950,11 +948,6 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { return NULL; } -static bool isLCD(const SkScalerContext::Rec& rec) { - return SkMask::kLCD16_Format == rec.fMaskFormat || - SkMask::kLCD32_Format == rec.fMaskFormat; -} - static bool bothZero(SkScalar a, SkScalar b) { return 0 == a && 0 == b; } |