Index: skia/ext/vector_platform_device_emf_win.cc |
diff --git a/skia/ext/vector_platform_device_emf_win.cc b/skia/ext/vector_platform_device_emf_win.cc |
deleted file mode 100644 |
index 90e4a201234e02a4d5625e2e9f8d51ec04fb2c37..0000000000000000000000000000000000000000 |
--- a/skia/ext/vector_platform_device_emf_win.cc |
+++ /dev/null |
@@ -1,982 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "skia/ext/vector_platform_device_emf_win.h" |
- |
-#include <windows.h> |
- |
-#include "base/logging.h" |
-#include "base/strings/string16.h" |
-#include "skia/ext/bitmap_platform_device.h" |
-#include "skia/ext/skia_utils_win.h" |
-#include "third_party/skia/include/core/SkPathEffect.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 { |
- |
-#define CHECK_FOR_NODRAW_ANNOTATION(paint) \ |
- do { if (paint.isNoDrawAnnotation()) { return; } } while (0) |
- |
-// static |
-SkBaseDevice* VectorPlatformDeviceEmf::CreateDevice( |
- int width, int height, bool is_opaque, HANDLE shared_section) { |
- if (!is_opaque) { |
- // TODO(maruel): http://crbug.com/18382 When restoring a semi-transparent |
- // layer, i.e. merging it, we need to rasterize it because GDI doesn't |
- // support transparency except for AlphaBlend(). Right now, a |
- // BitmapPlatformDevice is created when VectorCanvas think a saveLayers() |
- // call is being done. The way to save a layer would be to create an |
- // EMF-based VectorDevice and have this device registers the drawing. When |
- // playing back the device into a bitmap, do it at the printer's dpi instead |
- // of the layout's dpi (which is much lower). |
- return BitmapPlatformDevice::Create(width, height, is_opaque, |
- shared_section); |
- } |
- |
- // TODO(maruel): http://crbug.com/18383 Look if it would be worth to |
- // increase the resolution by ~10x (any worthy factor) to increase the |
- // rendering precision (think about printing) while using a relatively |
- // low dpi. This happens because we receive float as input but the GDI |
- // functions works with integers. The idea is to premultiply the matrix |
- // with this factor and multiply each SkScalar that are passed to |
- // SkScalarRound(value) as SkScalarRound(value * 10). Safari is already |
- // doing the same for text rendering. |
- SkASSERT(shared_section); |
- SkBaseDevice* device = VectorPlatformDeviceEmf::create( |
- reinterpret_cast<HDC>(shared_section), width, height); |
- return device; |
-} |
- |
-static void FillBitmapInfoHeader(int width, int height, BITMAPINFOHEADER* hdr) { |
- hdr->biSize = sizeof(BITMAPINFOHEADER); |
- hdr->biWidth = width; |
- hdr->biHeight = -height; // Minus means top-down bitmap. |
- hdr->biPlanes = 1; |
- hdr->biBitCount = 32; |
- hdr->biCompression = BI_RGB; // no compression |
- hdr->biSizeImage = 0; |
- hdr->biXPelsPerMeter = 1; |
- hdr->biYPelsPerMeter = 1; |
- hdr->biClrUsed = 0; |
- hdr->biClrImportant = 0; |
-} |
- |
-SkBaseDevice* VectorPlatformDeviceEmf::create(HDC dc, int width, int height) { |
- InitializeDC(dc); |
- |
- // Link the SkBitmap to the current selected bitmap in the device context. |
- SkBitmap bitmap; |
- HGDIOBJ selected_bitmap = GetCurrentObject(dc, OBJ_BITMAP); |
- bool succeeded = false; |
- if (selected_bitmap != NULL) { |
- BITMAP bitmap_data = {0}; |
- if (GetObject(selected_bitmap, sizeof(BITMAP), &bitmap_data) == |
- sizeof(BITMAP)) { |
- // The context has a bitmap attached. Attach our SkBitmap to it. |
- // Warning: If the bitmap gets unselected from the HDC, |
- // VectorPlatformDeviceEmf has no way to detect this, so the HBITMAP |
- // could be released while SkBitmap still has a reference to it. Be |
- // cautious. |
- if (width == bitmap_data.bmWidth && height == bitmap_data.bmHeight) { |
- SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); |
- succeeded = bitmap.installPixels(info, bitmap_data.bmBits, |
- bitmap_data.bmWidthBytes); |
- } |
- } |
- } |
- |
- if (!succeeded) |
- bitmap.setInfo(SkImageInfo::MakeUnknown(width, height)); |
- |
- return new VectorPlatformDeviceEmf(dc, bitmap); |
-} |
- |
-VectorPlatformDeviceEmf::VectorPlatformDeviceEmf(HDC dc, const SkBitmap& bitmap) |
- : SkBitmapDevice(bitmap), |
- hdc_(dc), |
- previous_brush_(NULL), |
- previous_pen_(NULL) { |
- transform_.reset(); |
- SetPlatformDevice(this, this); |
-} |
- |
-VectorPlatformDeviceEmf::~VectorPlatformDeviceEmf() { |
- SkASSERT(previous_brush_ == NULL); |
- SkASSERT(previous_pen_ == NULL); |
-} |
- |
-HDC VectorPlatformDeviceEmf::BeginPlatformPaint() { |
- return hdc_; |
-} |
- |
-void VectorPlatformDeviceEmf::drawPaint(const SkDraw& draw, |
- const SkPaint& paint) { |
- // TODO(maruel): Bypass the current transformation matrix. |
- SkRect rect; |
- rect.fLeft = 0; |
- rect.fTop = 0; |
- rect.fRight = SkIntToScalar(width() + 1); |
- rect.fBottom = SkIntToScalar(height() + 1); |
- drawRect(draw, rect, paint); |
-} |
- |
-void VectorPlatformDeviceEmf::drawPoints(const SkDraw& draw, |
- SkCanvas::PointMode mode, |
- size_t count, |
- const SkPoint pts[], |
- const SkPaint& paint) { |
- if (!count) |
- return; |
- |
- if (mode == SkCanvas::kPoints_PointMode) { |
- SkASSERT(false); |
- return; |
- } |
- |
- SkPaint tmp_paint(paint); |
- tmp_paint.setStyle(SkPaint::kStroke_Style); |
- |
- // Draw a path instead. |
- SkPath path; |
- switch (mode) { |
- case SkCanvas::kLines_PointMode: |
- if (count % 2) { |
- SkASSERT(false); |
- return; |
- } |
- for (size_t i = 0; i < count / 2; ++i) { |
- path.moveTo(pts[2 * i]); |
- path.lineTo(pts[2 * i + 1]); |
- } |
- break; |
- case SkCanvas::kPolygon_PointMode: |
- path.moveTo(pts[0]); |
- for (size_t i = 1; i < count; ++i) { |
- path.lineTo(pts[i]); |
- } |
- break; |
- default: |
- SkASSERT(false); |
- return; |
- } |
- // Draw the calculated path. |
- drawPath(draw, path, tmp_paint); |
-} |
- |
-void VectorPlatformDeviceEmf::drawRect(const SkDraw& draw, |
- const SkRect& rect, |
- const SkPaint& paint) { |
- CHECK_FOR_NODRAW_ANNOTATION(paint); |
- if (paint.getPathEffect()) { |
- // Draw a path instead. |
- SkPath path_orginal; |
- path_orginal.addRect(rect); |
- |
- // Apply the path effect to the rect. |
- SkPath path_modified; |
- paint.getFillPath(path_orginal, &path_modified); |
- |
- // Removes the path effect from the temporary SkPaint object. |
- SkPaint paint_no_effet(paint); |
- paint_no_effet.setPathEffect(NULL); |
- |
- // Draw the calculated path. |
- drawPath(draw, path_modified, paint_no_effet); |
- return; |
- } |
- |
- if (!ApplyPaint(paint)) { |
- return; |
- } |
- HDC dc = BeginPlatformPaint(); |
- if (!Rectangle(dc, SkScalarRoundToInt(rect.fLeft), |
- SkScalarRoundToInt(rect.fTop), |
- SkScalarRoundToInt(rect.fRight), |
- SkScalarRoundToInt(rect.fBottom))) { |
- SkASSERT(false); |
- } |
- EndPlatformPaint(); |
- Cleanup(); |
-} |
- |
-void VectorPlatformDeviceEmf::drawRRect(const SkDraw& draw, const SkRRect& rr, |
- const SkPaint& paint) { |
- SkPath path; |
- path.addRRect(rr); |
- this->drawPath(draw, path, paint, NULL, true); |
-} |
- |
-void VectorPlatformDeviceEmf::drawPath(const SkDraw& draw, |
- const SkPath& path, |
- const SkPaint& paint, |
- const SkMatrix* prePathMatrix, |
- bool pathIsMutable) { |
- CHECK_FOR_NODRAW_ANNOTATION(paint); |
- if (paint.getPathEffect()) { |
- // Apply the path effect forehand. |
- SkPath path_modified; |
- paint.getFillPath(path, &path_modified); |
- |
- // Removes the path effect from the temporary SkPaint object. |
- SkPaint paint_no_effet(paint); |
- paint_no_effet.setPathEffect(NULL); |
- |
- // Draw the calculated path. |
- drawPath(draw, path_modified, paint_no_effet); |
- return; |
- } |
- |
- if (!ApplyPaint(paint)) { |
- return; |
- } |
- HDC dc = BeginPlatformPaint(); |
- 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; |
- } |
- } |
- EndPlatformPaint(); |
- Cleanup(); |
-} |
- |
-void VectorPlatformDeviceEmf::drawBitmapRect(const SkDraw& draw, |
- const SkBitmap& bitmap, |
- const SkRect* src, |
- const SkRect& dst, |
- const SkPaint& paint, |
- SkCanvas::DrawBitmapRectFlags flags) { |
- SkMatrix matrix; |
- SkRect bitmapBounds, tmpSrc, tmpDst; |
- SkBitmap tmpBitmap; |
- |
- bitmapBounds.isetWH(bitmap.width(), bitmap.height()); |
- |
- // Compute matrix from the two rectangles |
- if (src) { |
- tmpSrc = *src; |
- } else { |
- tmpSrc = bitmapBounds; |
- } |
- matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); |
- |
- const SkBitmap* bitmapPtr = &bitmap; |
- |
- // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if |
- // needed (if the src was clipped). No check needed if src==null. |
- if (src) { |
- if (!bitmapBounds.contains(*src)) { |
- if (!tmpSrc.intersect(bitmapBounds)) { |
- return; // nothing to draw |
- } |
- // recompute dst, based on the smaller tmpSrc |
- matrix.mapRect(&tmpDst, tmpSrc); |
- } |
- |
- // since we may need to clamp to the borders of the src rect within |
- // the bitmap, we extract a subset. |
- // TODO: make sure this is handled in drawrect and remove it from here. |
- SkIRect srcIR; |
- tmpSrc.roundOut(&srcIR); |
- if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { |
- return; |
- } |
- bitmapPtr = &tmpBitmap; |
- |
- // Since we did an extract, we need to adjust the matrix accordingly |
- SkScalar dx = 0, dy = 0; |
- if (srcIR.fLeft > 0) { |
- dx = SkIntToScalar(srcIR.fLeft); |
- } |
- if (srcIR.fTop > 0) { |
- dy = SkIntToScalar(srcIR.fTop); |
- } |
- if (dx || dy) { |
- matrix.preTranslate(dx, dy); |
- } |
- } |
- this->drawBitmap(draw, *bitmapPtr, matrix, paint); |
-} |
- |
-void VectorPlatformDeviceEmf::drawBitmap(const SkDraw& draw, |
- const SkBitmap& bitmap, |
- const SkMatrix& matrix, |
- const SkPaint& paint) { |
- // Load the temporary matrix. This is what will translate, rotate and resize |
- // the bitmap. |
- SkMatrix actual_transform(transform_); |
- actual_transform.preConcat(matrix); |
- LoadTransformToDC(hdc_, actual_transform); |
- |
- InternalDrawBitmap(bitmap, 0, 0, paint); |
- |
- // Restore the original matrix. |
- LoadTransformToDC(hdc_, transform_); |
-} |
- |
-void VectorPlatformDeviceEmf::drawSprite(const SkDraw& draw, |
- const SkBitmap& bitmap, |
- int x, int y, |
- const SkPaint& paint) { |
- SkMatrix identity; |
- identity.reset(); |
- LoadTransformToDC(hdc_, identity); |
- |
- InternalDrawBitmap(bitmap, x, y, paint); |
- |
- // Restore the original matrix. |
- 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() : |
- fHDC(NULL), |
- fNewFont(NULL), |
- fSavedFont(NULL), |
- fSavedTextColor(0), |
- 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 = {0}; |
- SkLOGFONTFromTypeface(paint.getTypeface(), &lf); |
- lf.lfHeight = -SkScalarRoundToInt(paint.getTextSize()); |
- fNewFont = CreateFontIndirect(&lf); |
- fSavedFont = (HFONT)::SelectObject(hdc, fNewFont); |
- fHDC = hdc; |
- } |
- 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; |
- } |
-} |
- |
-static SkiaEnsureTypefaceCharactersAccessible |
- g_skia_ensure_typeface_characters_accessible = NULL; |
- |
-SK_API void SetSkiaEnsureTypefaceCharactersAccessible( |
- SkiaEnsureTypefaceCharactersAccessible func) { |
- // This function is supposed to be called once in process life time. |
- SkASSERT(g_skia_ensure_typeface_characters_accessible == NULL); |
- g_skia_ensure_typeface_characters_accessible = func; |
-} |
- |
-void EnsureTypefaceCharactersAccessible( |
- const SkTypeface& typeface, const wchar_t* text, unsigned int text_length) { |
- LOGFONT lf = {0}; |
- SkLOGFONTFromTypeface(&typeface, &lf); |
- g_skia_ensure_typeface_characters_accessible(lf, text, text_length); |
-} |
- |
-bool EnsureExtTextOut(HDC hdc, int x, int y, UINT options, const RECT * lprect, |
- LPCWSTR text, unsigned int characters, const int * lpDx, |
- SkTypeface* const typeface) { |
- bool success = ExtTextOut(hdc, x, y, options, lprect, text, characters, lpDx); |
- if (!success) { |
- if (typeface) { |
- EnsureTypefaceCharactersAccessible(*typeface, |
- text, |
- characters); |
- success = ExtTextOut(hdc, x, y, options, lprect, text, characters, lpDx); |
- if (!success) { |
- LOGFONT lf = {0}; |
- SkLOGFONTFromTypeface(typeface, &lf); |
- VLOG(1) << "SkFontHost::EnsureTypefaceCharactersAccessible FAILED for " |
- << " FaceName = " << lf.lfFaceName |
- << " and characters: " << base::string16(text, characters); |
- } |
- } else { |
- VLOG(1) << "ExtTextOut FAILED for default FaceName " |
- << " and characters: " << base::string16(text, characters); |
- } |
- } |
- return success; |
-} |
- |
-void VectorPlatformDeviceEmf::drawText(const SkDraw& draw, |
- const void* text, |
- size_t byteLength, |
- SkScalar x, |
- SkScalar y, |
- const SkPaint& paint) { |
- SkGDIFontSetup setup; |
- bool useDrawPath = true; |
- |
- if (SkPaint::kUTF8_TextEncoding != paint.getTextEncoding() |
- && setup.useGDI(hdc_, paint)) { |
- UINT options = getTextOutOptions(paint); |
- UINT count = byteLength >> 1; |
- useDrawPath = !EnsureExtTextOut(hdc_, SkScalarRoundToInt(x), |
- SkScalarRoundToInt(y + getAscent(paint)), options, 0, |
- reinterpret_cast<const wchar_t*>(text), count, NULL, |
- paint.getTypeface()); |
- } |
- |
- if (useDrawPath) { |
- 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, |
- const void* text, |
- size_t len, |
- const SkScalar pos[], |
- int scalarsPerPos, |
- const SkPoint& offset, |
- const SkPaint& paint) { |
- SkGDIFontSetup setup; |
- bool useDrawText = true; |
- |
- if (scalarsPerPos == 2 && len >= 2 && |
- SkPaint::kUTF8_TextEncoding != paint.getTextEncoding() && |
- setup.useGDI(hdc_, paint)) { |
- int startX = SkScalarRoundToInt(pos[0] + offset.x()); |
- int startY = SkScalarRoundToInt(pos[1] + offset.y() + 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] = SkScalarRoundToInt(pos[2] - pos[0]); |
- pos += 2; |
- } |
- advances[count - 1] = 0; |
- useDrawText = !EnsureExtTextOut(hdc_, startX, startY, |
- getTextOutOptions(paint), 0, reinterpret_cast<const wchar_t*>(text), |
- count, advances, paint.getTypeface()); |
- } |
- |
- if (useDrawText) { |
- 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 x = offset.x() + pos[0]; |
- SkScalar y = offset.y() + (2 == scalarsPerPos ? pos[1] : 0); |
- |
- size_t bytes = bytesPerCodePoint(curr); |
- drawText(draw, curr, bytes, x, y, paint); |
- curr += bytes; |
- pos += scalarsPerPos; |
- } |
- } |
-} |
- |
-void VectorPlatformDeviceEmf::drawTextOnPath(const SkDraw& draw, |
- const void* text, |
- size_t len, |
- const SkPath& path, |
- const SkMatrix* matrix, |
- const SkPaint& paint) { |
- // This function isn't used in the code. Verify this assumption. |
- SkASSERT(false); |
-} |
- |
-void VectorPlatformDeviceEmf::drawVertices(const SkDraw& draw, |
- SkCanvas::VertexMode vmode, |
- int vertexCount, |
- const SkPoint vertices[], |
- const SkPoint texs[], |
- const SkColor colors[], |
- SkXfermode* xmode, |
- const uint16_t indices[], |
- int indexCount, |
- const SkPaint& paint) { |
- // This function isn't used in the code. Verify this assumption. |
- SkASSERT(false); |
-} |
- |
-void VectorPlatformDeviceEmf::drawDevice(const SkDraw& draw, |
- SkBaseDevice* device, |
- int x, |
- int y, |
- const SkPaint& paint) { |
- // TODO(maruel): http://b/1183870 Playback the EMF buffer at printer's dpi if |
- // it is a vectorial device. |
- drawSprite(draw, device->accessBitmap(false), x, y, paint); |
-} |
- |
-bool VectorPlatformDeviceEmf::ApplyPaint(const SkPaint& paint) { |
- // Note: The goal here is to transfert the SkPaint's state to the HDC's state. |
- // This function does not execute the SkPaint drawing commands. These should |
- // be executed in drawPaint(). |
- |
- SkPaint::Style style = paint.getStyle(); |
- if (!paint.getAlpha()) |
- style = (SkPaint::Style) SkPaint::kStyleCount; |
- |
- switch (style) { |
- case SkPaint::kFill_Style: |
- if (!CreateBrush(true, paint) || |
- !CreatePen(false, paint)) |
- return false; |
- break; |
- case SkPaint::kStroke_Style: |
- if (!CreateBrush(false, paint) || |
- !CreatePen(true, paint)) |
- return false; |
- break; |
- case SkPaint::kStrokeAndFill_Style: |
- if (!CreateBrush(true, paint) || |
- !CreatePen(true, paint)) |
- return false; |
- break; |
- default: |
- if (!CreateBrush(false, paint) || |
- !CreatePen(false, paint)) |
- return false; |
- break; |
- } |
- |
- /* |
- getFlags(); |
- isAntiAlias(); |
- isDither() |
- isLinearText() |
- isSubpixelText() |
- isUnderlineText() |
- isStrikeThruText() |
- isFakeBoldText() |
- isDevKernText() |
- isFilterBitmap() |
- |
- // Skia's text is not used. This should be fixed. |
- getTextAlign() |
- getTextScaleX() |
- getTextSkewX() |
- getTextEncoding() |
- getFontMetrics() |
- getFontSpacing() |
- */ |
- |
- // BUG 1094907: Implement shaders. Shaders currently in use: |
- // SkShader::CreateBitmapShader |
- // SkGradientShader::CreateRadial |
- // SkGradientShader::CreateLinear |
- // SkASSERT(!paint.getShader()); |
- |
- // http://b/1106647 Implement loopers and mask filter. Looper currently in |
- // use: |
- // SkBlurDrawLooper is used for shadows. |
- // SkASSERT(!paint.getLooper()); |
- // SkASSERT(!paint.getMaskFilter()); |
- |
- // http://b/1165900 Implement xfermode. |
- // SkASSERT(!paint.getXfermode()); |
- |
- // The path effect should be processed before arriving here. |
- SkASSERT(!paint.getPathEffect()); |
- |
- // This isn't used in the code. Verify this assumption. |
- SkASSERT(!paint.getRasterizer()); |
- // Reuse code to load Win32 Fonts. |
- return true; |
-} |
- |
-void VectorPlatformDeviceEmf::setMatrixClip(const SkMatrix& transform, |
- const SkRegion& region, |
- const SkClipStack&) { |
- transform_ = transform; |
- LoadTransformToDC(hdc_, transform_); |
- clip_region_ = region; |
- if (!clip_region_.isEmpty()) |
- LoadClipRegion(); |
-} |
- |
-void VectorPlatformDeviceEmf::LoadClipRegion() { |
- SkMatrix t; |
- t.reset(); |
- LoadClippingRegionToDC(hdc_, clip_region_, t); |
-} |
- |
-SkBaseDevice* VectorPlatformDeviceEmf::onCreateCompatibleDevice( |
- const CreateInfo& info) { |
- SkASSERT(info.fInfo.colorType() == kN32_SkColorType); |
- return VectorPlatformDeviceEmf::CreateDevice( |
- info.fInfo.width(), info.fInfo.height(), info.fInfo.isOpaque(), NULL); |
-} |
- |
-bool VectorPlatformDeviceEmf::CreateBrush(bool use_brush, COLORREF color) { |
- SkASSERT(previous_brush_ == NULL); |
- // We can't use SetDCBrushColor() or DC_BRUSH when drawing to a EMF buffer. |
- // SetDCBrushColor() calls are not recorded at all and DC_BRUSH will use |
- // WHITE_BRUSH instead. |
- |
- if (!use_brush) { |
- // Set the transparency. |
- if (0 == SetBkMode(hdc_, TRANSPARENT)) { |
- SkASSERT(false); |
- return false; |
- } |
- |
- // Select the NULL brush. |
- previous_brush_ = SelectObject(GetStockObject(NULL_BRUSH)); |
- return previous_brush_ != NULL; |
- } |
- |
- // Set the opacity. |
- if (0 == SetBkMode(hdc_, OPAQUE)) { |
- SkASSERT(false); |
- return false; |
- } |
- |
- // Create and select the brush. |
- previous_brush_ = SelectObject(CreateSolidBrush(color)); |
- return previous_brush_ != NULL; |
-} |
- |
-bool VectorPlatformDeviceEmf::CreatePen(bool use_pen, |
- COLORREF color, |
- int stroke_width, |
- float stroke_miter, |
- DWORD pen_style) { |
- SkASSERT(previous_pen_ == NULL); |
- // We can't use SetDCPenColor() or DC_PEN when drawing to a EMF buffer. |
- // SetDCPenColor() calls are not recorded at all and DC_PEN will use BLACK_PEN |
- // instead. |
- |
- // No pen case |
- if (!use_pen) { |
- previous_pen_ = SelectObject(GetStockObject(NULL_PEN)); |
- return previous_pen_ != NULL; |
- } |
- |
- // Use the stock pen if the stroke width is 0. |
- if (stroke_width == 0) { |
- // Create a pen with the right color. |
- previous_pen_ = SelectObject(::CreatePen(PS_SOLID, 0, color)); |
- return previous_pen_ != NULL; |
- } |
- |
- // Load a custom pen. |
- LOGBRUSH brush = {0}; |
- brush.lbStyle = BS_SOLID; |
- brush.lbColor = color; |
- brush.lbHatch = 0; |
- HPEN pen = ExtCreatePen(pen_style, stroke_width, &brush, 0, NULL); |
- SkASSERT(pen != NULL); |
- previous_pen_ = SelectObject(pen); |
- if (previous_pen_ == NULL) |
- return false; |
- |
- if (!SetMiterLimit(hdc_, stroke_miter, NULL)) { |
- SkASSERT(false); |
- return false; |
- } |
- return true; |
-} |
- |
-void VectorPlatformDeviceEmf::Cleanup() { |
- if (previous_brush_) { |
- HGDIOBJ result = SelectObject(previous_brush_); |
- previous_brush_ = NULL; |
- if (result) { |
- BOOL res = DeleteObject(result); |
- SkASSERT(res != 0); |
- } |
- } |
- if (previous_pen_) { |
- HGDIOBJ result = SelectObject(previous_pen_); |
- previous_pen_ = NULL; |
- if (result) { |
- BOOL res = DeleteObject(result); |
- SkASSERT(res != 0); |
- } |
- } |
- // Remove any loaded path from the context. |
- AbortPath(hdc_); |
-} |
- |
-HGDIOBJ VectorPlatformDeviceEmf::SelectObject(HGDIOBJ object) { |
- HGDIOBJ result = ::SelectObject(hdc_, object); |
- SkASSERT(result != HGDI_ERROR); |
- if (result == HGDI_ERROR) |
- return NULL; |
- return result; |
-} |
- |
-bool VectorPlatformDeviceEmf::CreateBrush(bool use_brush, |
- const SkPaint& paint) { |
- // Make sure that for transparent color, no brush is used. |
- if (paint.getAlpha() == 0) { |
- use_brush = false; |
- } |
- |
- return CreateBrush(use_brush, SkColorToCOLORREF(paint.getColor())); |
-} |
- |
-bool VectorPlatformDeviceEmf::CreatePen(bool use_pen, const SkPaint& paint) { |
- // Make sure that for transparent color, no pen is used. |
- if (paint.getAlpha() == 0) { |
- use_pen = false; |
- } |
- |
- DWORD pen_style = PS_GEOMETRIC | PS_SOLID; |
- switch (paint.getStrokeJoin()) { |
- case SkPaint::kMiter_Join: |
- // Connects path segments with a sharp join. |
- pen_style |= PS_JOIN_MITER; |
- break; |
- case SkPaint::kRound_Join: |
- // Connects path segments with a round join. |
- pen_style |= PS_JOIN_ROUND; |
- break; |
- case SkPaint::kBevel_Join: |
- // Connects path segments with a flat bevel join. |
- pen_style |= PS_JOIN_BEVEL; |
- break; |
- default: |
- SkASSERT(false); |
- break; |
- } |
- switch (paint.getStrokeCap()) { |
- case SkPaint::kButt_Cap: |
- // Begin/end contours with no extension. |
- pen_style |= PS_ENDCAP_FLAT; |
- break; |
- case SkPaint::kRound_Cap: |
- // Begin/end contours with a semi-circle extension. |
- pen_style |= PS_ENDCAP_ROUND; |
- break; |
- case SkPaint::kSquare_Cap: |
- // Begin/end contours with a half square extension. |
- pen_style |= PS_ENDCAP_SQUARE; |
- break; |
- default: |
- SkASSERT(false); |
- break; |
- } |
- |
- return CreatePen(use_pen, |
- SkColorToCOLORREF(paint.getColor()), |
- SkScalarRoundToInt(paint.getStrokeWidth()), |
- paint.getStrokeMiter(), |
- pen_style); |
-} |
- |
-void VectorPlatformDeviceEmf::InternalDrawBitmap(const SkBitmap& bitmap, |
- int x, int y, |
- const SkPaint& paint) { |
- unsigned char alpha = paint.getAlpha(); |
- if (alpha == 0) |
- return; |
- |
- bool is_translucent; |
- if (alpha != 255) { |
- // ApplyPaint expect an opaque color. |
- SkPaint tmp_paint(paint); |
- tmp_paint.setAlpha(255); |
- if (!ApplyPaint(tmp_paint)) |
- return; |
- is_translucent = true; |
- } else { |
- if (!ApplyPaint(paint)) |
- return; |
- is_translucent = false; |
- } |
- int src_size_x = bitmap.width(); |
- int src_size_y = bitmap.height(); |
- if (!src_size_x || !src_size_y) |
- return; |
- |
- // Create a BMP v4 header that we can serialize. We use the shared "V3" |
- // fillter to fill the stardard items, then add in the "V4" stuff we want. |
- BITMAPV4HEADER bitmap_header = {0}; |
- FillBitmapInfoHeader(src_size_x, src_size_y, |
- reinterpret_cast<BITMAPINFOHEADER*>(&bitmap_header)); |
- bitmap_header.bV4Size = sizeof(BITMAPV4HEADER); |
- bitmap_header.bV4RedMask = 0x00ff0000; |
- bitmap_header.bV4GreenMask = 0x0000ff00; |
- bitmap_header.bV4BlueMask = 0x000000ff; |
- bitmap_header.bV4AlphaMask = 0xff000000; |
- |
- SkAutoLockPixels lock(bitmap); |
- SkASSERT(bitmap.colorType() == kN32_SkColorType); |
- const uint32_t* pixels = static_cast<const uint32_t*>(bitmap.getPixels()); |
- if (pixels == NULL) { |
- SkASSERT(false); |
- return; |
- } |
- |
- if (!is_translucent) { |
- int row_length = bitmap.rowBytesAsPixels(); |
- // There is no quick way to determine if an image is opaque. |
- for (int y2 = 0; y2 < src_size_y; ++y2) { |
- for (int x2 = 0; x2 < src_size_x; ++x2) { |
- if (SkColorGetA(pixels[(y2 * row_length) + x2]) != 255) { |
- is_translucent = true; |
- y2 = src_size_y; |
- break; |
- } |
- } |
- } |
- } |
- |
- HDC dc = BeginPlatformPaint(); |
- BITMAPINFOHEADER hdr = {0}; |
- FillBitmapInfoHeader(src_size_x, src_size_y, &hdr); |
- if (is_translucent) { |
- // The image must be loaded as a bitmap inside a device context. |
- HDC bitmap_dc = ::CreateCompatibleDC(dc); |
- void* bits = NULL; |
- HBITMAP hbitmap = ::CreateDIBSection( |
- bitmap_dc, reinterpret_cast<const BITMAPINFO*>(&hdr), |
- DIB_RGB_COLORS, &bits, NULL, 0); |
- |
- // static cast to a char so we can do byte ptr arithmatic to |
- // get the offset. |
- unsigned char* dest_buffer = static_cast<unsigned char *>(bits); |
- |
- // We will copy row by row to avoid having to worry about |
- // the row strides being different. |
- const int dest_row_size = hdr.biBitCount / 8 * hdr.biWidth; |
- for (int row = 0; row < bitmap.height(); ++row) { |
- int dest_offset = row * dest_row_size; |
- // pixels_offset in terms of pixel count. |
- int src_offset = row * bitmap.rowBytesAsPixels(); |
- memcpy(dest_buffer + dest_offset, pixels + src_offset, dest_row_size); |
- } |
- SkASSERT(hbitmap); |
- HGDIOBJ old_bitmap = ::SelectObject(bitmap_dc, hbitmap); |
- |
- // After some analysis of IE7's behavior, this is the thing to do. I was |
- // sure IE7 was doing so kind of bitmasking due to the way translucent image |
- // where renderered but after some windbg tracing, it is being done by the |
- // printer driver after all (mostly HP printers). IE7 always use AlphaBlend |
- // for bitmasked images. The trick seems to switch the stretching mode in |
- // what the driver expects. |
- DWORD previous_mode = GetStretchBltMode(dc); |
- BOOL result = SetStretchBltMode(dc, COLORONCOLOR); |
- SkASSERT(result); |
- // Note that this function expect premultiplied colors (!) |
- BLENDFUNCTION blend_function = {AC_SRC_OVER, 0, alpha, AC_SRC_ALPHA}; |
- result = GdiAlphaBlend(dc, |
- x, y, // Destination origin. |
- src_size_x, src_size_y, // Destination size. |
- bitmap_dc, |
- 0, 0, // Source origin. |
- src_size_x, src_size_y, // Source size. |
- blend_function); |
- SkASSERT(result); |
- result = SetStretchBltMode(dc, previous_mode); |
- SkASSERT(result); |
- |
- ::SelectObject(bitmap_dc, static_cast<HBITMAP>(old_bitmap)); |
- DeleteObject(hbitmap); |
- DeleteDC(bitmap_dc); |
- } else { |
- int nCopied = StretchDIBits(dc, |
- x, y, // Destination origin. |
- src_size_x, src_size_y, |
- 0, 0, // Source origin. |
- src_size_x, src_size_y, // Source size. |
- pixels, |
- reinterpret_cast<const BITMAPINFO*>(&hdr), |
- DIB_RGB_COLORS, |
- SRCCOPY); |
- } |
- EndPlatformPaint(); |
- Cleanup(); |
-} |
- |
-} // namespace skia |