From 99edd43813b7f1a8f02146cbd8c783d3c82be4ab Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Fri, 9 Sep 2011 14:59:59 +0000 Subject: cache offscreen HDC git-svn-id: http://skia.googlecode.com/svn/trunk@2245 2bbb7eff-a529-9590-31e7-b0007b416f81 --- src/ports/SkFontHost_win.cpp | 202 +++++++++++++++++++++++++++++-------------- 1 file changed, 136 insertions(+), 66 deletions(-) diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp index c5a9e08c59..8cf85351b1 100755 --- a/src/ports/SkFontHost_win.cpp +++ b/src/ports/SkFontHost_win.cpp @@ -269,7 +269,132 @@ static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount, } } -////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////// + +static int alignTo32(int n) { + return (n + 31) & ~31; +} + +struct MyBitmapInfo : public BITMAPINFO { + RGBQUAD fMoreSpaceForColors[1]; +}; + +class HDCOffscreen { +public: + HDCOffscreen() { + fFont = 0; + fDC = 0; + fBM = 0; + fBits = NULL; + fWidth = fHeight = 0; + fIsBW = false; + } + + ~HDCOffscreen() { + if (fDC) { + DeleteDC(fDC); + } + if (fBM) { + DeleteObject(fBM); + } + } + + void init(HFONT font, const XFORM& xform) { + fFont = font; + fXform = xform; + } + + const void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr); + +private: + HDC fDC; + HBITMAP fBM; + HFONT fFont; + XFORM fXform; + void* fBits; // points into fBM + int fWidth; + int fHeight; + bool fIsBW; +}; + +const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW, size_t* srcRBPtr) { + if (0 == fDC) { + fDC = CreateCompatibleDC(0); + if (0 == fDC) { + return NULL; + } + SetGraphicsMode(fDC, GM_ADVANCED); + SetBkMode(fDC, TRANSPARENT); + SetTextAlign(fDC, TA_LEFT | TA_BASELINE); + SelectObject(fDC, fFont); + COLORREF color = SetTextColor(fDC, fIsBW ? 0xFFFFFF : 0); + SkASSERT(color != CLR_INVALID); + } + + if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) { + DeleteObject(fBM); + fBM = 0; + } + + if (fIsBW != isBW) { + fIsBW = isBW; + COLORREF color = SetTextColor(fDC, fIsBW ? 0xFFFFFF : 0); + SkASSERT(color != CLR_INVALID); + } + fWidth = SkMax32(fWidth, glyph.fWidth); + fHeight = SkMax32(fHeight, glyph.fHeight); + + int biWidth = isBW ? alignTo32(fWidth) : fWidth; + + if (0 == fBM) { + 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 = fHeight; + info.bmiHeader.biPlanes = 1; + info.bmiHeader.biBitCount = isBW ? 1 : 32; + info.bmiHeader.biCompression = BI_RGB; + if (isBW) { + info.bmiHeader.biClrUsed = 2; + } + fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0); + if (0 == fBM) { + return NULL; + } + SelectObject(fDC, fBM); + } + + // erase + size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2); + size_t size = fHeight * srcRB; + memset(fBits, isBW ? 0 : 0xFF, size); + + XFORM xform = fXform; + xform.eDx = (float)-glyph.fLeft; + xform.eDy = (float)-glyph.fTop; + SetWorldTransform(fDC, &xform); + + uint16_t glyphID = glyph.getGlyphID(); +#if defined(UNICODE) + ExtTextOut(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCWSTR)&glyphID, 1, NULL); +#else + ExtTextOut(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&glyphID, 1, NULL); +#endif + GdiFlush(); + + *srcRBPtr = srcRB; + // offset to the start of the image + return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB; +} + +////////////////////////////////////////////////////////////////////////////////////// class SkScalerContext_Windows : public SkScalerContext { public: @@ -284,8 +409,9 @@ protected: virtual void generateImage(const SkGlyph& glyph); virtual void generatePath(const SkGlyph& glyph, SkPath* path); virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY); - //virtual SkDeviceContext getDC() {return ddc;} + private: + HDCOffscreen fOffscreen; SkScalar fScale; // to get from canonical size to real size MAT2 fMat22; XFORM fXform; @@ -382,6 +508,8 @@ SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc) if (needToRenderWithSkia(fRec)) { this->forceGenerateImageFromPath(); } + + fOffscreen.init(fFont, fXform); } SkScalerContext_Windows::~SkScalerContext_Windows() { @@ -539,26 +667,13 @@ static inline uint8_t rgb_to_a8(uint32_t rgb) { } static inline uint16_t rgb_to_lcd16(uint32_t rgb) { + rgb = ~rgb; // 255 - each component int r = (rgb >> 16) & 0xFF; int g = (rgb >> 8) & 0xFF; int b = (rgb >> 0) & 0xFF; - - // invert, since we draw black-on-white, but we want the original - // src mask values. - r = 255 - r; - g = 255 - g; - b = 255 - b; return SkPackRGB16(SkR32ToR16(r), SkG32ToG16(g), SkB32ToB16(b)); } -static int alignTo32(int n) { - return (n + 31) & ~31; -} - -struct MyBitmapInfo : public BITMAPINFO { - RGBQUAD fMoreSpaceForColors[1]; -}; - void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { SkAutoMutexAcquire ac(gFTMutex); @@ -567,56 +682,14 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; 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; + size_t srcRB; + const void* bits = fOffscreen.draw(glyph, isBW, &srcRB); + if (!bits) { + sk_bzero(glyph.fImage, glyph.computeImageSize()); + return; } - 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); -#else - 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) { @@ -651,9 +724,6 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { dst = (uint16_t*)((char*)dst - dstRB); } } - - DeleteDC(dc); - DeleteObject(bm); } void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) { -- cgit v1.2.3