diff options
author | reed@google.com <reed@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-21 14:53:37 +0000 |
---|---|---|
committer | reed@google.com <reed@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-21 14:53:37 +0000 |
commit | 86cd4854c06e31d6c581d5d439ab97241d7d2fc5 (patch) | |
tree | b83ea1c703e02a50a76d9ea7f92e67328c83009e /skia | |
parent | b1e544f36255f965ba719ee40dde4c9880fd81ce (diff) | |
download | chromium_src-86cd4854c06e31d6c581d5d439ab97241d7d2fc5.zip chromium_src-86cd4854c06e31d6c581d5d439ab97241d7d2fc5.tar.gz chromium_src-86cd4854c06e31d6c581d5d439ab97241d7d2fc5.tar.bz2 |
support text drawing instead of asserting
add bool return for LoadPathToDC() since it can fail and the caller needs to know.
Review URL: http://codereview.chromium.org/7443006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@93395 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia')
-rw-r--r-- | skia/ext/platform_device_win.cc | 9 | ||||
-rw-r--r-- | skia/ext/platform_device_win.h | 4 | ||||
-rw-r--r-- | skia/ext/vector_platform_device_emf_win.cc | 188 |
3 files changed, 168 insertions, 33 deletions
diff --git a/skia/ext/platform_device_win.cc b/skia/ext/platform_device_win.cc index 17e04b2..ea72165 100644 --- a/skia/ext/platform_device_win.cc +++ b/skia/ext/platform_device_win.cc @@ -62,7 +62,7 @@ void PlatformDevice::EndPlatformPaint() { } // static -void PlatformDevice::LoadPathToDC(HDC context, const SkPath& path) { +bool PlatformDevice::LoadPathToDC(HDC context, const SkPath& path) { switch (path.getFillType()) { case SkPath::kWinding_FillType: { int res = SetPolyFillMode(context, WINDING); @@ -80,11 +80,13 @@ void PlatformDevice::LoadPathToDC(HDC context, const SkPath& path) { } } BOOL res = BeginPath(context); - SkASSERT(res != 0); + if (!res) { + return false; + } CubicPaths paths; if (!SkPathToCubicPaths(&paths, path)) - return; + return false; std::vector<POINT> points; for (CubicPaths::const_iterator path(paths.begin()); path != paths.end(); @@ -119,6 +121,7 @@ void PlatformDevice::LoadPathToDC(HDC context, const SkPath& path) { res = EndPath(context); SkASSERT(res != 0); } + return true; } // static diff --git a/skia/ext/platform_device_win.h b/skia/ext/platform_device_win.h index a5445aa..57afa89 100644 --- a/skia/ext/platform_device_win.h +++ b/skia/ext/platform_device_win.h @@ -53,8 +53,8 @@ class SK_API PlatformDevice : public SkDevice { virtual bool IsNativeFontRenderingAllowed() { return true; } // Loads a SkPath into the GDI context. The path can there after be used for - // clipping or as a stroke. - static void LoadPathToDC(HDC context, const SkPath& path); + // clipping or as a stroke. Returns false if the path failed to be loaded. + static bool LoadPathToDC(HDC context, const SkPath& path); // Loads a SkRegion into the GDI context. static void LoadClippingRegionToDC(HDC context, const SkRegion& region, diff --git a/skia/ext/vector_platform_device_emf_win.cc b/skia/ext/vector_platform_device_emf_win.cc index 0789197..eac7977 100644 --- a/skia/ext/vector_platform_device_emf_win.cc +++ b/skia/ext/vector_platform_device_emf_win.cc @@ -8,7 +8,9 @@ #include "skia/ext/bitmap_platform_device.h" #include "skia/ext/skia_utils_win.h" +#include "third_party/skia/include/core/SkTemplates.h" #include "third_party/skia/include/core/SkUtils.h" +#include "third_party/skia/include/ports/SkTypeface_win.h" namespace skia { @@ -227,26 +229,27 @@ void VectorPlatformDeviceEmf::drawPath(const SkDraw& draw, return; } HDC dc = BeginPlatformPaint(); - PlatformDevice::LoadPathToDC(dc, path); - switch (paint.getStyle()) { - case SkPaint::kFill_Style: { - BOOL res = StrokeAndFillPath(dc); - SkASSERT(res != 0); - break; - } - case SkPaint::kStroke_Style: { - BOOL res = StrokePath(dc); - SkASSERT(res != 0); - break; - } - case SkPaint::kStrokeAndFill_Style: { - BOOL res = StrokeAndFillPath(dc); - SkASSERT(res != 0); - break; + if (PlatformDevice::LoadPathToDC(dc, path)) { + switch (paint.getStyle()) { + case SkPaint::kFill_Style: { + BOOL res = StrokeAndFillPath(dc); + SkASSERT(res != 0); + break; + } + case SkPaint::kStroke_Style: { + BOOL res = StrokePath(dc); + SkASSERT(res != 0); + break; + } + case SkPaint::kStrokeAndFill_Style: { + BOOL res = StrokeAndFillPath(dc); + SkASSERT(res != 0); + break; + } + default: + SkASSERT(false); + break; } - default: - SkASSERT(false); - break; } EndPlatformPaint(); Cleanup(); @@ -283,14 +286,108 @@ void VectorPlatformDeviceEmf::drawSprite(const SkDraw& draw, LoadTransformToDC(hdc_, transform_); } +///////////////////////////////////////////////////////////////////////// + +static bool gdiCanHandleText(const SkPaint& paint) { + return !paint.getShader() && + !paint.getPathEffect() && + (SkPaint::kFill_Style == paint.getStyle()) && + (255 == paint.getAlpha()); +} + +class SkGDIFontSetup { +public: + SkGDIFontSetup() : fUseGDI(false) { + SkDEBUGCODE(fUseGDIHasBeenCalled = false;) + } + ~SkGDIFontSetup(); + + // can only be called once + bool useGDI(HDC hdc, const SkPaint&); + +private: + HDC fHDC; + HFONT fNewFont; + HFONT fSavedFont; + COLORREF fSavedTextColor; + bool fUseGDI; + SkDEBUGCODE(bool fUseGDIHasBeenCalled;) +}; + +bool SkGDIFontSetup::useGDI(HDC hdc, const SkPaint& paint) { + SkASSERT(!fUseGDIHasBeenCalled); + SkDEBUGCODE(fUseGDIHasBeenCalled = true;) + + fUseGDI = gdiCanHandleText(paint); + if (fUseGDI) { + fSavedTextColor = GetTextColor(hdc); + SetTextColor(hdc, skia::SkColorToCOLORREF(paint.getColor())); + + LOGFONT lf; + SkLOGFONTFromTypeface(paint.getTypeface(), &lf); + lf.lfHeight = -SkScalarRound(paint.getTextSize()); + fNewFont = CreateFontIndirect(&lf); + fSavedFont = (HFONT)::SelectObject(hdc, fNewFont); + } + return fUseGDI; +} + +SkGDIFontSetup::~SkGDIFontSetup() { + if (fUseGDI) { + ::SelectObject(fHDC, fSavedFont); + ::DeleteObject(fNewFont); + SetTextColor(fHDC, fSavedTextColor); + } +} + +static SkScalar getAscent(const SkPaint& paint) { + SkPaint::FontMetrics fm; + paint.getFontMetrics(&fm); + return fm.fAscent; +} + +// return the options int for ExtTextOut. Only valid if the paint's text encoding +// is not UTF8 (in which case ExtTextOut can't be used). +static UINT getTextOutOptions(const SkPaint& paint) { + if (SkPaint::kGlyphID_TextEncoding == paint.getTextEncoding()) { + return ETO_GLYPH_INDEX; + } else { + SkASSERT(SkPaint::kUTF16_TextEncoding == paint.getTextEncoding()); + return 0; + } +} + void VectorPlatformDeviceEmf::drawText(const SkDraw& draw, const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { - // This function isn't used in the code. Verify this assumption. - SkASSERT(false); + SkGDIFontSetup setup; + if (SkPaint::kUTF8_TextEncoding != paint.getTextEncoding() + && setup.useGDI(hdc_, paint)) { + UINT options = getTextOutOptions(paint); + UINT count = byteLength >> 1; + ExtTextOut(hdc_, SkScalarRound(x), SkScalarRound(y + getAscent(paint)), + options, 0, reinterpret_cast<const wchar_t*>(text), count, NULL); + } else { + SkPath path; + paint.getTextPath(text, byteLength, x, y, &path); + drawPath(draw, path, paint); + } +} + +static size_t size_utf8(const char* text) { + return SkUTF8_CountUTF8Bytes(text); +} + +static size_t size_utf16(const char* text) { + uint16_t c = *reinterpret_cast<const uint16_t*>(text); + return SkUTF16_IsHighSurrogate(c) ? 4 : 2; +} + +static size_t size_glyphid(const char* text) { + return 2; } void VectorPlatformDeviceEmf::drawPosText(const SkDraw& draw, @@ -300,8 +397,46 @@ void VectorPlatformDeviceEmf::drawPosText(const SkDraw& draw, SkScalar constY, int scalarsPerPos, const SkPaint& paint) { - // This function isn't used in the code. Verify this assumption. - SkASSERT(false); + SkGDIFontSetup setup; + if (2 == scalarsPerPos + && SkPaint::kUTF8_TextEncoding != paint.getTextEncoding() + && setup.useGDI(hdc_, paint)) { + int startX = SkScalarRound(pos[0]); + int startY = SkScalarRound(pos[1] + getAscent(paint)); + const int count = len >> 1; + SkAutoSTMalloc<64, INT> storage(count); + INT* advances = storage.get(); + for (int i = 0; i < count - 1; ++i) { + advances[i] = SkScalarRound(pos[2] - pos[0]); + pos += 2; + } + ExtTextOut(hdc_, startX, startY, getTextOutOptions(paint), 0, + reinterpret_cast<const wchar_t*>(text), count, advances); + } else { + size_t (*bytesPerCodePoint)(const char*); + switch (paint.getTextEncoding()) { + case SkPaint::kUTF8_TextEncoding: + bytesPerCodePoint = size_utf8; + break; + case SkPaint::kUTF16_TextEncoding: + bytesPerCodePoint = size_utf16; + break; + default: + SkASSERT(SkPaint::kGlyphID_TextEncoding == paint.getTextEncoding()); + bytesPerCodePoint = size_glyphid; + break; + } + + const char* curr = reinterpret_cast<const char*>(text); + const char* stop = curr + len; + while (curr < stop) { + SkScalar y = (1 == scalarsPerPos) ? constY : pos[1]; + size_t bytes = bytesPerCodePoint(curr); + drawText(draw, curr, bytes, pos[0], y, paint); + curr += bytes; + pos += scalarsPerPos; + } + } } void VectorPlatformDeviceEmf::drawTextOnPath(const SkDraw& draw, @@ -409,11 +544,9 @@ bool VectorPlatformDeviceEmf::ApplyPaint(const SkPaint& paint) { // The path effect should be processed before arriving here. SkASSERT(!paint.getPathEffect()); - // These aren't used in the code. Verify this assumption. - SkASSERT(!paint.getColorFilter()); + // This isn't used in the code. Verify this assumption. SkASSERT(!paint.getRasterizer()); // Reuse code to load Win32 Fonts. - SkASSERT(!paint.getTypeface()); return true; } @@ -717,7 +850,7 @@ void VectorPlatformDeviceEmf::InternalDrawBitmap(const SkBitmap& bitmap, DeleteObject(hbitmap); DeleteDC(bitmap_dc); } else { - BOOL result = StretchDIBits(dc, + int nCopied = StretchDIBits(dc, x, y, // Destination origin. src_size_x, src_size_y, 0, 0, // Source origin. @@ -726,7 +859,6 @@ void VectorPlatformDeviceEmf::InternalDrawBitmap(const SkBitmap& bitmap, reinterpret_cast<const BITMAPINFO*>(&hdr), DIB_RGB_COLORS, SRCCOPY); - SkASSERT(result); } EndPlatformPaint(); Cleanup(); |