diff options
Diffstat (limited to 'base/gfx/vector_device.cc')
-rw-r--r-- | base/gfx/vector_device.cc | 612 |
1 files changed, 0 insertions, 612 deletions
diff --git a/base/gfx/vector_device.cc b/base/gfx/vector_device.cc deleted file mode 100644 index 26da338..0000000 --- a/base/gfx/vector_device.cc +++ /dev/null @@ -1,612 +0,0 @@ -// Copyright (c) 2006-2008 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 "base/gfx/vector_device.h" - -#include "base/gfx/gdi_util.h" -#include "base/gfx/skia_utils.h" -#include "base/logging.h" -#include "base/scoped_handle.h" - -#include "SkUtils.h" - -namespace gfx { - -VectorDevice* VectorDevice::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; - 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, VectorDevice 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) { - bitmap.setConfig(SkBitmap::kARGB_8888_Config, - bitmap_data.bmWidth, - bitmap_data.bmHeight, - bitmap_data.bmWidthBytes); - bitmap.setPixels(bitmap_data.bmBits); - succeeded = true; - } - } - } - - if (!succeeded) - bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); - - return new VectorDevice(dc, bitmap); -} - -VectorDevice::VectorDevice(HDC dc, const SkBitmap& bitmap) - : PlatformDeviceWin(bitmap), - hdc_(dc), - previous_brush_(NULL), - previous_pen_(NULL) { - transform_.reset(); -} - -VectorDevice::~VectorDevice() { - DCHECK(previous_brush_ == NULL); - DCHECK(previous_pen_ == NULL); -} - - -void VectorDevice::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 VectorDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, - size_t count, const SkPoint pts[], - const SkPaint& paint) { - if (!count) - return; - - if (mode == SkCanvas::kPoints_PointMode) { - NOTREACHED(); - 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) { - NOTREACHED(); - 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: - NOTREACHED(); - return; - } - // Draw the calculated path. - drawPath(draw, path, tmp_paint); -} - -void VectorDevice::drawRect(const SkDraw& draw, const SkRect& rect, - const SkPaint& 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)->safeUnref(); - - // Draw the calculated path. - drawPath(draw, path_modified, paint_no_effet); - return; - } - - if (!ApplyPaint(paint)) { - return; - } - HDC dc = getBitmapDC(); - if (!Rectangle(dc, SkScalarRound(rect.fLeft), - SkScalarRound(rect.fTop), - SkScalarRound(rect.fRight), - SkScalarRound(rect.fBottom))) { - NOTREACHED(); - } - Cleanup(); -} - -void VectorDevice::drawPath(const SkDraw& draw, const SkPath& path, - const SkPaint& 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)->safeUnref(); - - // Draw the calculated path. - drawPath(draw, path_modified, paint_no_effet); - return; - } - - if (!ApplyPaint(paint)) { - return; - } - HDC dc = getBitmapDC(); - PlatformDeviceWin::LoadPathToDC(dc, path); - switch (paint.getStyle()) { - case SkPaint::kFill_Style: { - BOOL res = StrokeAndFillPath(dc); - DCHECK(res != 0); - break; - } - case SkPaint::kStroke_Style: { - BOOL res = StrokePath(dc); - DCHECK(res != 0); - break; - } - case SkPaint::kStrokeAndFill_Style: { - BOOL res = StrokeAndFillPath(dc); - DCHECK(res != 0); - break; - } - default: - NOTREACHED(); - break; - } - Cleanup(); -} - -void VectorDevice::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 VectorDevice::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_); -} - -void VectorDevice::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. - NOTREACHED(); -} - -void VectorDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, - const SkScalar pos[], SkScalar constY, - int scalarsPerPos, const SkPaint& paint) { - // This function isn't used in the code. Verify this assumption. - NOTREACHED(); -} - -void VectorDevice::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. - NOTREACHED(); -} - -void VectorDevice::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. - NOTREACHED(); -} - -void VectorDevice::drawDevice(const SkDraw& draw, SkDevice* 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 VectorDevice::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::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 - // DCHECK(!paint.getShader()); - - // http://b/1106647 Implement loopers and mask filter. Looper currently in - // use: - // SkBlurDrawLooper is used for shadows. - // DCHECK(!paint.getLooper()); - // DCHECK(!paint.getMaskFilter()); - - // http://b/1165900 Implement xfermode. - // DCHECK(!paint.getXfermode()); - - // The path effect should be processed before arriving here. - DCHECK(!paint.getPathEffect()); - - // These aren't used in the code. Verify this assumption. - DCHECK(!paint.getColorFilter()); - DCHECK(!paint.getRasterizer()); - // Reuse code to load Win32 Fonts. - DCHECK(!paint.getTypeface()); - return true; -} - -void VectorDevice::setMatrixClip(const SkMatrix& transform, - const SkRegion& region) { - transform_ = transform; - LoadTransformToDC(hdc_, transform_); - clip_region_ = region; - if (!clip_region_.isEmpty()) - LoadClipRegion(); -} - -void VectorDevice::drawToHDC(HDC dc, int x, int y, const RECT* src_rect) { - NOTREACHED(); -} - -void VectorDevice::LoadClipRegion() { - SkMatrix t; - t.reset(); - LoadClippingRegionToDC(hdc_, clip_region_, t); -} - -bool VectorDevice::CreateBrush(bool use_brush, COLORREF color) { - DCHECK(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)) { - NOTREACHED(); - return false; - } - - // Select the NULL brush. - previous_brush_ = SelectObject(GetStockObject(NULL_BRUSH)); - return previous_brush_ != NULL; - } - - // Set the opacity. - if (0 == SetBkMode(hdc_, OPAQUE)) { - NOTREACHED(); - return false; - } - - // Create and select the brush. - previous_brush_ = SelectObject(CreateSolidBrush(color)); - return previous_brush_ != NULL; -} - -bool VectorDevice::CreatePen(bool use_pen, COLORREF color, int stroke_width, - float stroke_miter, DWORD pen_style) { - DCHECK(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; - brush.lbStyle = BS_SOLID; - brush.lbColor = color; - brush.lbHatch = 0; - HPEN pen = ExtCreatePen(pen_style, stroke_width, &brush, 0, NULL); - DCHECK(pen != NULL); - previous_pen_ = SelectObject(pen); - if (previous_pen_ == NULL) - return false; - - if (!SetMiterLimit(hdc_, stroke_miter, NULL)) { - NOTREACHED(); - return false; - } - return true; -} - -void VectorDevice::Cleanup() { - if (previous_brush_) { - HGDIOBJ result = SelectObject(previous_brush_); - previous_brush_ = NULL; - if (result) { - BOOL res = DeleteObject(result); - DCHECK(res != 0); - } - } - if (previous_pen_) { - HGDIOBJ result = SelectObject(previous_pen_); - previous_pen_ = NULL; - if (result) { - BOOL res = DeleteObject(result); - DCHECK(res != 0); - } - } - // Remove any loaded path from the context. - AbortPath(hdc_); -} - -HGDIOBJ VectorDevice::SelectObject(HGDIOBJ object) { - HGDIOBJ result = ::SelectObject(hdc_, object); - DCHECK(result != HGDI_ERROR); - if (result == HGDI_ERROR) - return NULL; - return result; -} - -bool VectorDevice::CreateBrush(bool use_brush, const SkPaint& paint) { - // Make sure that for transparent color, no brush is used. - if (paint.getAlpha() == 0) { - // Test if it ever happen. - NOTREACHED(); - use_brush = false; - } - - return CreateBrush(use_brush, SkColorToCOLORREF(paint.getColor())); -} - -bool VectorDevice::CreatePen(bool use_pen, const SkPaint& paint) { - // Make sure that for transparent color, no pen is used. - if (paint.getAlpha() == 0) { - // Test if it ever happen. - NOTREACHED(); - 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: - NOTREACHED(); - 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: - NOTREACHED(); - break; - } - - return CreatePen(use_pen, - SkColorToCOLORREF(paint.getColor()), - SkScalarRound(paint.getStrokeWidth()), - paint.getStrokeMiter(), - pen_style); -} - -void VectorDevice::InternalDrawBitmap(const SkBitmap& bitmap, int x, int y, - const SkPaint& paint) { - uint8 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. - BITMAPV4HEADER bitmap_header; - gfx::CreateBitmapV4Header(src_size_x, src_size_y, &bitmap_header); - HDC dc = getBitmapDC(); - SkAutoLockPixels lock(bitmap); - DCHECK_EQ(bitmap.getConfig(), SkBitmap::kARGB_8888_Config); - const uint32_t* pixels = static_cast<const uint32_t*>(bitmap.getPixels()); - if (pixels == NULL) { - NOTREACHED(); - 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; - } - } - } - } - - BITMAPINFOHEADER hdr; - gfx::CreateBitmapHeader(src_size_x, src_size_y, &hdr); - if (is_translucent) { - // The image must be loaded as a bitmap inside a device context. - ScopedHDC bitmap_dc(::CreateCompatibleDC(dc)); - void* bits = NULL; - ScopedBitmap hbitmap(::CreateDIBSection( - bitmap_dc, reinterpret_cast<const BITMAPINFO*>(&hdr), - DIB_RGB_COLORS, &bits, NULL, 0)); - memcpy(bits, pixels, bitmap.getSize()); - DCHECK(hbitmap); - HGDIOBJ old_bitmap = ::SelectObject(bitmap_dc, hbitmap); - DeleteObject(old_bitmap); - - // 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); - DCHECK(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); - DCHECK(result); - result = SetStretchBltMode(dc, previous_mode); - DCHECK(result); - } else { - BOOL result = 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); - DCHECK(result); - } - Cleanup(); -} - -} // namespace gfx - |