| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "skia/ext/vector_device.h" | 5 #include "skia/ext/vector_device.h" |
| 6 | 6 |
| 7 #include "base/gfx/gdi_util.h" | 7 #include "base/gfx/gdi_util.h" |
| 8 #include "base/logging.h" | |
| 9 #include "base/scoped_handle.h" | |
| 10 #include "skia/ext/skia_utils_win.h" | 8 #include "skia/ext/skia_utils_win.h" |
| 11 | 9 |
| 12 #include "SkUtils.h" | 10 #include "SkUtils.h" |
| 13 | 11 |
| 14 namespace skia { | 12 namespace skia { |
| 15 | 13 |
| 16 VectorDevice* VectorDevice::create(HDC dc, int width, int height) { | 14 VectorDevice* VectorDevice::create(HDC dc, int width, int height) { |
| 17 InitializeDC(dc); | 15 InitializeDC(dc); |
| 18 | 16 |
| 19 // Link the SkBitmap to the current selected bitmap in the device context. | 17 // Link the SkBitmap to the current selected bitmap in the device context. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 48 | 46 |
| 49 VectorDevice::VectorDevice(HDC dc, const SkBitmap& bitmap) | 47 VectorDevice::VectorDevice(HDC dc, const SkBitmap& bitmap) |
| 50 : PlatformDeviceWin(bitmap), | 48 : PlatformDeviceWin(bitmap), |
| 51 hdc_(dc), | 49 hdc_(dc), |
| 52 previous_brush_(NULL), | 50 previous_brush_(NULL), |
| 53 previous_pen_(NULL) { | 51 previous_pen_(NULL) { |
| 54 transform_.reset(); | 52 transform_.reset(); |
| 55 } | 53 } |
| 56 | 54 |
| 57 VectorDevice::~VectorDevice() { | 55 VectorDevice::~VectorDevice() { |
| 58 DCHECK(previous_brush_ == NULL); | 56 SkASSERT(previous_brush_ == NULL); |
| 59 DCHECK(previous_pen_ == NULL); | 57 SkASSERT(previous_pen_ == NULL); |
| 60 } | 58 } |
| 61 | 59 |
| 62 | 60 |
| 63 void VectorDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { | 61 void VectorDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { |
| 64 // TODO(maruel): Bypass the current transformation matrix. | 62 // TODO(maruel): Bypass the current transformation matrix. |
| 65 SkRect rect; | 63 SkRect rect; |
| 66 rect.fLeft = 0; | 64 rect.fLeft = 0; |
| 67 rect.fTop = 0; | 65 rect.fTop = 0; |
| 68 rect.fRight = SkIntToScalar(width() + 1); | 66 rect.fRight = SkIntToScalar(width() + 1); |
| 69 rect.fBottom = SkIntToScalar(height() + 1); | 67 rect.fBottom = SkIntToScalar(height() + 1); |
| 70 drawRect(draw, rect, paint); | 68 drawRect(draw, rect, paint); |
| 71 } | 69 } |
| 72 | 70 |
| 73 void VectorDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, | 71 void VectorDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, |
| 74 size_t count, const SkPoint pts[], | 72 size_t count, const SkPoint pts[], |
| 75 const SkPaint& paint) { | 73 const SkPaint& paint) { |
| 76 if (!count) | 74 if (!count) |
| 77 return; | 75 return; |
| 78 | 76 |
| 79 if (mode == SkCanvas::kPoints_PointMode) { | 77 if (mode == SkCanvas::kPoints_PointMode) { |
| 80 NOTREACHED(); | 78 SkASSERT(false); |
| 81 return; | 79 return; |
| 82 } | 80 } |
| 83 | 81 |
| 84 SkPaint tmp_paint(paint); | 82 SkPaint tmp_paint(paint); |
| 85 tmp_paint.setStyle(SkPaint::kStroke_Style); | 83 tmp_paint.setStyle(SkPaint::kStroke_Style); |
| 86 | 84 |
| 87 // Draw a path instead. | 85 // Draw a path instead. |
| 88 SkPath path; | 86 SkPath path; |
| 89 switch (mode) { | 87 switch (mode) { |
| 90 case SkCanvas::kLines_PointMode: | 88 case SkCanvas::kLines_PointMode: |
| 91 if (count % 2) { | 89 if (count % 2) { |
| 92 NOTREACHED(); | 90 SkASSERT(false); |
| 93 return; | 91 return; |
| 94 } | 92 } |
| 95 for (size_t i = 0; i < count / 2; ++i) { | 93 for (size_t i = 0; i < count / 2; ++i) { |
| 96 path.moveTo(pts[2 * i]); | 94 path.moveTo(pts[2 * i]); |
| 97 path.lineTo(pts[2 * i + 1]); | 95 path.lineTo(pts[2 * i + 1]); |
| 98 } | 96 } |
| 99 break; | 97 break; |
| 100 case SkCanvas::kPolygon_PointMode: | 98 case SkCanvas::kPolygon_PointMode: |
| 101 path.moveTo(pts[0]); | 99 path.moveTo(pts[0]); |
| 102 for (size_t i = 1; i < count; ++i) { | 100 for (size_t i = 1; i < count; ++i) { |
| 103 path.lineTo(pts[i]); | 101 path.lineTo(pts[i]); |
| 104 } | 102 } |
| 105 break; | 103 break; |
| 106 default: | 104 default: |
| 107 NOTREACHED(); | 105 SkASSERT(false); |
| 108 return; | 106 return; |
| 109 } | 107 } |
| 110 // Draw the calculated path. | 108 // Draw the calculated path. |
| 111 drawPath(draw, path, tmp_paint); | 109 drawPath(draw, path, tmp_paint); |
| 112 } | 110 } |
| 113 | 111 |
| 114 void VectorDevice::drawRect(const SkDraw& draw, const SkRect& rect, | 112 void VectorDevice::drawRect(const SkDraw& draw, const SkRect& rect, |
| 115 const SkPaint& paint) { | 113 const SkPaint& paint) { |
| 116 if (paint.getPathEffect()) { | 114 if (paint.getPathEffect()) { |
| 117 // Draw a path instead. | 115 // Draw a path instead. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 132 } | 130 } |
| 133 | 131 |
| 134 if (!ApplyPaint(paint)) { | 132 if (!ApplyPaint(paint)) { |
| 135 return; | 133 return; |
| 136 } | 134 } |
| 137 HDC dc = getBitmapDC(); | 135 HDC dc = getBitmapDC(); |
| 138 if (!Rectangle(dc, SkScalarRound(rect.fLeft), | 136 if (!Rectangle(dc, SkScalarRound(rect.fLeft), |
| 139 SkScalarRound(rect.fTop), | 137 SkScalarRound(rect.fTop), |
| 140 SkScalarRound(rect.fRight), | 138 SkScalarRound(rect.fRight), |
| 141 SkScalarRound(rect.fBottom))) { | 139 SkScalarRound(rect.fBottom))) { |
| 142 NOTREACHED(); | 140 SkASSERT(false); |
| 143 } | 141 } |
| 144 Cleanup(); | 142 Cleanup(); |
| 145 } | 143 } |
| 146 | 144 |
| 147 void VectorDevice::drawPath(const SkDraw& draw, const SkPath& path, | 145 void VectorDevice::drawPath(const SkDraw& draw, const SkPath& path, |
| 148 const SkPaint& paint) { | 146 const SkPaint& paint) { |
| 149 if (paint.getPathEffect()) { | 147 if (paint.getPathEffect()) { |
| 150 // Apply the path effect forehand. | 148 // Apply the path effect forehand. |
| 151 SkPath path_modified; | 149 SkPath path_modified; |
| 152 paint.getFillPath(path, &path_modified); | 150 paint.getFillPath(path, &path_modified); |
| 153 | 151 |
| 154 // Removes the path effect from the temporary SkPaint object. | 152 // Removes the path effect from the temporary SkPaint object. |
| 155 SkPaint paint_no_effet(paint); | 153 SkPaint paint_no_effet(paint); |
| 156 paint_no_effet.setPathEffect(NULL)->safeUnref(); | 154 paint_no_effet.setPathEffect(NULL)->safeUnref(); |
| 157 | 155 |
| 158 // Draw the calculated path. | 156 // Draw the calculated path. |
| 159 drawPath(draw, path_modified, paint_no_effet); | 157 drawPath(draw, path_modified, paint_no_effet); |
| 160 return; | 158 return; |
| 161 } | 159 } |
| 162 | 160 |
| 163 if (!ApplyPaint(paint)) { | 161 if (!ApplyPaint(paint)) { |
| 164 return; | 162 return; |
| 165 } | 163 } |
| 166 HDC dc = getBitmapDC(); | 164 HDC dc = getBitmapDC(); |
| 167 PlatformDeviceWin::LoadPathToDC(dc, path); | 165 PlatformDeviceWin::LoadPathToDC(dc, path); |
| 168 switch (paint.getStyle()) { | 166 switch (paint.getStyle()) { |
| 169 case SkPaint::kFill_Style: { | 167 case SkPaint::kFill_Style: { |
| 170 BOOL res = StrokeAndFillPath(dc); | 168 BOOL res = StrokeAndFillPath(dc); |
| 171 DCHECK(res != 0); | 169 SkASSERT(res != 0); |
| 172 break; | 170 break; |
| 173 } | 171 } |
| 174 case SkPaint::kStroke_Style: { | 172 case SkPaint::kStroke_Style: { |
| 175 BOOL res = StrokePath(dc); | 173 BOOL res = StrokePath(dc); |
| 176 DCHECK(res != 0); | 174 SkASSERT(res != 0); |
| 177 break; | 175 break; |
| 178 } | 176 } |
| 179 case SkPaint::kStrokeAndFill_Style: { | 177 case SkPaint::kStrokeAndFill_Style: { |
| 180 BOOL res = StrokeAndFillPath(dc); | 178 BOOL res = StrokeAndFillPath(dc); |
| 181 DCHECK(res != 0); | 179 SkASSERT(res != 0); |
| 182 break; | 180 break; |
| 183 } | 181 } |
| 184 default: | 182 default: |
| 185 NOTREACHED(); | 183 SkASSERT(false); |
| 186 break; | 184 break; |
| 187 } | 185 } |
| 188 Cleanup(); | 186 Cleanup(); |
| 189 } | 187 } |
| 190 | 188 |
| 191 void VectorDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, | 189 void VectorDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, |
| 192 const SkMatrix& matrix, const SkPaint& paint) { | 190 const SkMatrix& matrix, const SkPaint& paint) { |
| 193 // Load the temporary matrix. This is what will translate, rotate and resize | 191 // Load the temporary matrix. This is what will translate, rotate and resize |
| 194 // the bitmap. | 192 // the bitmap. |
| 195 SkMatrix actual_transform(transform_); | 193 SkMatrix actual_transform(transform_); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 210 | 208 |
| 211 InternalDrawBitmap(bitmap, x, y, paint); | 209 InternalDrawBitmap(bitmap, x, y, paint); |
| 212 | 210 |
| 213 // Restore the original matrix. | 211 // Restore the original matrix. |
| 214 LoadTransformToDC(hdc_, transform_); | 212 LoadTransformToDC(hdc_, transform_); |
| 215 } | 213 } |
| 216 | 214 |
| 217 void VectorDevice::drawText(const SkDraw& draw, const void* text, size_t byteLen
gth, | 215 void VectorDevice::drawText(const SkDraw& draw, const void* text, size_t byteLen
gth, |
| 218 SkScalar x, SkScalar y, const SkPaint& paint) { | 216 SkScalar x, SkScalar y, const SkPaint& paint) { |
| 219 // This function isn't used in the code. Verify this assumption. | 217 // This function isn't used in the code. Verify this assumption. |
| 220 NOTREACHED(); | 218 SkASSERT(false); |
| 221 } | 219 } |
| 222 | 220 |
| 223 void VectorDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, | 221 void VectorDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, |
| 224 const SkScalar pos[], SkScalar constY, | 222 const SkScalar pos[], SkScalar constY, |
| 225 int scalarsPerPos, const SkPaint& paint) { | 223 int scalarsPerPos, const SkPaint& paint) { |
| 226 // This function isn't used in the code. Verify this assumption. | 224 // This function isn't used in the code. Verify this assumption. |
| 227 NOTREACHED(); | 225 SkASSERT(false); |
| 228 } | 226 } |
| 229 | 227 |
| 230 void VectorDevice::drawTextOnPath(const SkDraw& draw, const void* text, | 228 void VectorDevice::drawTextOnPath(const SkDraw& draw, const void* text, |
| 231 size_t len, | 229 size_t len, |
| 232 const SkPath& path, const SkMatrix* matrix, | 230 const SkPath& path, const SkMatrix* matrix, |
| 233 const SkPaint& paint) { | 231 const SkPaint& paint) { |
| 234 // This function isn't used in the code. Verify this assumption. | 232 // This function isn't used in the code. Verify this assumption. |
| 235 NOTREACHED(); | 233 SkASSERT(false); |
| 236 } | 234 } |
| 237 | 235 |
| 238 void VectorDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, | 236 void VectorDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, |
| 239 int vertexCount, | 237 int vertexCount, |
| 240 const SkPoint vertices[], const SkPoint texs[], | 238 const SkPoint vertices[], const SkPoint texs[], |
| 241 const SkColor colors[], SkXfermode* xmode, | 239 const SkColor colors[], SkXfermode* xmode, |
| 242 const uint16_t indices[], int indexCount, | 240 const uint16_t indices[], int indexCount, |
| 243 const SkPaint& paint) { | 241 const SkPaint& paint) { |
| 244 // This function isn't used in the code. Verify this assumption. | 242 // This function isn't used in the code. Verify this assumption. |
| 245 NOTREACHED(); | 243 SkASSERT(false); |
| 246 } | 244 } |
| 247 | 245 |
| 248 void VectorDevice::drawDevice(const SkDraw& draw, SkDevice* device, int x, | 246 void VectorDevice::drawDevice(const SkDraw& draw, SkDevice* device, int x, |
| 249 int y, const SkPaint& paint) { | 247 int y, const SkPaint& paint) { |
| 250 // TODO(maruel): http://b/1183870 Playback the EMF buffer at printer's dpi if | 248 // TODO(maruel): http://b/1183870 Playback the EMF buffer at printer's dpi if |
| 251 // it is a vectorial device. | 249 // it is a vectorial device. |
| 252 drawSprite(draw, device->accessBitmap(false), x, y, paint); | 250 drawSprite(draw, device->accessBitmap(false), x, y, paint); |
| 253 } | 251 } |
| 254 | 252 |
| 255 bool VectorDevice::ApplyPaint(const SkPaint& paint) { | 253 bool VectorDevice::ApplyPaint(const SkPaint& paint) { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 302 getTextSkewX() | 300 getTextSkewX() |
| 303 getTextEncoding() | 301 getTextEncoding() |
| 304 getFontMetrics() | 302 getFontMetrics() |
| 305 getFontSpacing() | 303 getFontSpacing() |
| 306 */ | 304 */ |
| 307 | 305 |
| 308 // BUG 1094907: Implement shaders. Shaders currently in use: | 306 // BUG 1094907: Implement shaders. Shaders currently in use: |
| 309 // SkShader::CreateBitmapShader | 307 // SkShader::CreateBitmapShader |
| 310 // SkGradientShader::CreateRadial | 308 // SkGradientShader::CreateRadial |
| 311 // SkGradientShader::CreateLinear | 309 // SkGradientShader::CreateLinear |
| 312 // DCHECK(!paint.getShader()); | 310 // SkASSERT(!paint.getShader()); |
| 313 | 311 |
| 314 // http://b/1106647 Implement loopers and mask filter. Looper currently in | 312 // http://b/1106647 Implement loopers and mask filter. Looper currently in |
| 315 // use: | 313 // use: |
| 316 // SkBlurDrawLooper is used for shadows. | 314 // SkBlurDrawLooper is used for shadows. |
| 317 // DCHECK(!paint.getLooper()); | 315 // SkASSERT(!paint.getLooper()); |
| 318 // DCHECK(!paint.getMaskFilter()); | 316 // SkASSERT(!paint.getMaskFilter()); |
| 319 | 317 |
| 320 // http://b/1165900 Implement xfermode. | 318 // http://b/1165900 Implement xfermode. |
| 321 // DCHECK(!paint.getXfermode()); | 319 // SkASSERT(!paint.getXfermode()); |
| 322 | 320 |
| 323 // The path effect should be processed before arriving here. | 321 // The path effect should be processed before arriving here. |
| 324 DCHECK(!paint.getPathEffect()); | 322 SkASSERT(!paint.getPathEffect()); |
| 325 | 323 |
| 326 // These aren't used in the code. Verify this assumption. | 324 // These aren't used in the code. Verify this assumption. |
| 327 DCHECK(!paint.getColorFilter()); | 325 SkASSERT(!paint.getColorFilter()); |
| 328 DCHECK(!paint.getRasterizer()); | 326 SkASSERT(!paint.getRasterizer()); |
| 329 // Reuse code to load Win32 Fonts. | 327 // Reuse code to load Win32 Fonts. |
| 330 DCHECK(!paint.getTypeface()); | 328 SkASSERT(!paint.getTypeface()); |
| 331 return true; | 329 return true; |
| 332 } | 330 } |
| 333 | 331 |
| 334 void VectorDevice::setMatrixClip(const SkMatrix& transform, | 332 void VectorDevice::setMatrixClip(const SkMatrix& transform, |
| 335 const SkRegion& region) { | 333 const SkRegion& region) { |
| 336 transform_ = transform; | 334 transform_ = transform; |
| 337 LoadTransformToDC(hdc_, transform_); | 335 LoadTransformToDC(hdc_, transform_); |
| 338 clip_region_ = region; | 336 clip_region_ = region; |
| 339 if (!clip_region_.isEmpty()) | 337 if (!clip_region_.isEmpty()) |
| 340 LoadClipRegion(); | 338 LoadClipRegion(); |
| 341 } | 339 } |
| 342 | 340 |
| 343 void VectorDevice::drawToHDC(HDC dc, int x, int y, const RECT* src_rect) { | 341 void VectorDevice::drawToHDC(HDC dc, int x, int y, const RECT* src_rect) { |
| 344 NOTREACHED(); | 342 SkASSERT(false); |
| 345 } | 343 } |
| 346 | 344 |
| 347 void VectorDevice::LoadClipRegion() { | 345 void VectorDevice::LoadClipRegion() { |
| 348 SkMatrix t; | 346 SkMatrix t; |
| 349 t.reset(); | 347 t.reset(); |
| 350 LoadClippingRegionToDC(hdc_, clip_region_, t); | 348 LoadClippingRegionToDC(hdc_, clip_region_, t); |
| 351 } | 349 } |
| 352 | 350 |
| 353 bool VectorDevice::CreateBrush(bool use_brush, COLORREF color) { | 351 bool VectorDevice::CreateBrush(bool use_brush, COLORREF color) { |
| 354 DCHECK(previous_brush_ == NULL); | 352 SkASSERT(previous_brush_ == NULL); |
| 355 // We can't use SetDCBrushColor() or DC_BRUSH when drawing to a EMF buffer. | 353 // We can't use SetDCBrushColor() or DC_BRUSH when drawing to a EMF buffer. |
| 356 // SetDCBrushColor() calls are not recorded at all and DC_BRUSH will use | 354 // SetDCBrushColor() calls are not recorded at all and DC_BRUSH will use |
| 357 // WHITE_BRUSH instead. | 355 // WHITE_BRUSH instead. |
| 358 | 356 |
| 359 if (!use_brush) { | 357 if (!use_brush) { |
| 360 // Set the transparency. | 358 // Set the transparency. |
| 361 if (0 == SetBkMode(hdc_, TRANSPARENT)) { | 359 if (0 == SetBkMode(hdc_, TRANSPARENT)) { |
| 362 NOTREACHED(); | 360 SkASSERT(false); |
| 363 return false; | 361 return false; |
| 364 } | 362 } |
| 365 | 363 |
| 366 // Select the NULL brush. | 364 // Select the NULL brush. |
| 367 previous_brush_ = SelectObject(GetStockObject(NULL_BRUSH)); | 365 previous_brush_ = SelectObject(GetStockObject(NULL_BRUSH)); |
| 368 return previous_brush_ != NULL; | 366 return previous_brush_ != NULL; |
| 369 } | 367 } |
| 370 | 368 |
| 371 // Set the opacity. | 369 // Set the opacity. |
| 372 if (0 == SetBkMode(hdc_, OPAQUE)) { | 370 if (0 == SetBkMode(hdc_, OPAQUE)) { |
| 373 NOTREACHED(); | 371 SkASSERT(false); |
| 374 return false; | 372 return false; |
| 375 } | 373 } |
| 376 | 374 |
| 377 // Create and select the brush. | 375 // Create and select the brush. |
| 378 previous_brush_ = SelectObject(CreateSolidBrush(color)); | 376 previous_brush_ = SelectObject(CreateSolidBrush(color)); |
| 379 return previous_brush_ != NULL; | 377 return previous_brush_ != NULL; |
| 380 } | 378 } |
| 381 | 379 |
| 382 bool VectorDevice::CreatePen(bool use_pen, COLORREF color, int stroke_width, | 380 bool VectorDevice::CreatePen(bool use_pen, COLORREF color, int stroke_width, |
| 383 float stroke_miter, DWORD pen_style) { | 381 float stroke_miter, DWORD pen_style) { |
| 384 DCHECK(previous_pen_ == NULL); | 382 SkASSERT(previous_pen_ == NULL); |
| 385 // We can't use SetDCPenColor() or DC_PEN when drawing to a EMF buffer. | 383 // We can't use SetDCPenColor() or DC_PEN when drawing to a EMF buffer. |
| 386 // SetDCPenColor() calls are not recorded at all and DC_PEN will use BLACK_PEN | 384 // SetDCPenColor() calls are not recorded at all and DC_PEN will use BLACK_PEN |
| 387 // instead. | 385 // instead. |
| 388 | 386 |
| 389 // No pen case | 387 // No pen case |
| 390 if (!use_pen) { | 388 if (!use_pen) { |
| 391 previous_pen_ = SelectObject(GetStockObject(NULL_PEN)); | 389 previous_pen_ = SelectObject(GetStockObject(NULL_PEN)); |
| 392 return previous_pen_ != NULL; | 390 return previous_pen_ != NULL; |
| 393 } | 391 } |
| 394 | 392 |
| 395 // Use the stock pen if the stroke width is 0. | 393 // Use the stock pen if the stroke width is 0. |
| 396 if (stroke_width == 0) { | 394 if (stroke_width == 0) { |
| 397 // Create a pen with the right color. | 395 // Create a pen with the right color. |
| 398 previous_pen_ = SelectObject(::CreatePen(PS_SOLID, 0, color)); | 396 previous_pen_ = SelectObject(::CreatePen(PS_SOLID, 0, color)); |
| 399 return previous_pen_ != NULL; | 397 return previous_pen_ != NULL; |
| 400 } | 398 } |
| 401 | 399 |
| 402 // Load a custom pen. | 400 // Load a custom pen. |
| 403 LOGBRUSH brush; | 401 LOGBRUSH brush; |
| 404 brush.lbStyle = BS_SOLID; | 402 brush.lbStyle = BS_SOLID; |
| 405 brush.lbColor = color; | 403 brush.lbColor = color; |
| 406 brush.lbHatch = 0; | 404 brush.lbHatch = 0; |
| 407 HPEN pen = ExtCreatePen(pen_style, stroke_width, &brush, 0, NULL); | 405 HPEN pen = ExtCreatePen(pen_style, stroke_width, &brush, 0, NULL); |
| 408 DCHECK(pen != NULL); | 406 SkASSERT(pen != NULL); |
| 409 previous_pen_ = SelectObject(pen); | 407 previous_pen_ = SelectObject(pen); |
| 410 if (previous_pen_ == NULL) | 408 if (previous_pen_ == NULL) |
| 411 return false; | 409 return false; |
| 412 | 410 |
| 413 if (!SetMiterLimit(hdc_, stroke_miter, NULL)) { | 411 if (!SetMiterLimit(hdc_, stroke_miter, NULL)) { |
| 414 NOTREACHED(); | 412 SkASSERT(false); |
| 415 return false; | 413 return false; |
| 416 } | 414 } |
| 417 return true; | 415 return true; |
| 418 } | 416 } |
| 419 | 417 |
| 420 void VectorDevice::Cleanup() { | 418 void VectorDevice::Cleanup() { |
| 421 if (previous_brush_) { | 419 if (previous_brush_) { |
| 422 HGDIOBJ result = SelectObject(previous_brush_); | 420 HGDIOBJ result = SelectObject(previous_brush_); |
| 423 previous_brush_ = NULL; | 421 previous_brush_ = NULL; |
| 424 if (result) { | 422 if (result) { |
| 425 BOOL res = DeleteObject(result); | 423 BOOL res = DeleteObject(result); |
| 426 DCHECK(res != 0); | 424 SkASSERT(res != 0); |
| 427 } | 425 } |
| 428 } | 426 } |
| 429 if (previous_pen_) { | 427 if (previous_pen_) { |
| 430 HGDIOBJ result = SelectObject(previous_pen_); | 428 HGDIOBJ result = SelectObject(previous_pen_); |
| 431 previous_pen_ = NULL; | 429 previous_pen_ = NULL; |
| 432 if (result) { | 430 if (result) { |
| 433 BOOL res = DeleteObject(result); | 431 BOOL res = DeleteObject(result); |
| 434 DCHECK(res != 0); | 432 SkASSERT(res != 0); |
| 435 } | 433 } |
| 436 } | 434 } |
| 437 // Remove any loaded path from the context. | 435 // Remove any loaded path from the context. |
| 438 AbortPath(hdc_); | 436 AbortPath(hdc_); |
| 439 } | 437 } |
| 440 | 438 |
| 441 HGDIOBJ VectorDevice::SelectObject(HGDIOBJ object) { | 439 HGDIOBJ VectorDevice::SelectObject(HGDIOBJ object) { |
| 442 HGDIOBJ result = ::SelectObject(hdc_, object); | 440 HGDIOBJ result = ::SelectObject(hdc_, object); |
| 443 DCHECK(result != HGDI_ERROR); | 441 SkASSERT(result != HGDI_ERROR); |
| 444 if (result == HGDI_ERROR) | 442 if (result == HGDI_ERROR) |
| 445 return NULL; | 443 return NULL; |
| 446 return result; | 444 return result; |
| 447 } | 445 } |
| 448 | 446 |
| 449 bool VectorDevice::CreateBrush(bool use_brush, const SkPaint& paint) { | 447 bool VectorDevice::CreateBrush(bool use_brush, const SkPaint& paint) { |
| 450 // Make sure that for transparent color, no brush is used. | 448 // Make sure that for transparent color, no brush is used. |
| 451 if (paint.getAlpha() == 0) { | 449 if (paint.getAlpha() == 0) { |
| 452 // Test if it ever happen. | 450 // Test if it ever happen. |
| 453 NOTREACHED(); | 451 SkASSERT(false); |
| 454 use_brush = false; | 452 use_brush = false; |
| 455 } | 453 } |
| 456 | 454 |
| 457 return CreateBrush(use_brush, SkColorToCOLORREF(paint.getColor())); | 455 return CreateBrush(use_brush, SkColorToCOLORREF(paint.getColor())); |
| 458 } | 456 } |
| 459 | 457 |
| 460 bool VectorDevice::CreatePen(bool use_pen, const SkPaint& paint) { | 458 bool VectorDevice::CreatePen(bool use_pen, const SkPaint& paint) { |
| 461 // Make sure that for transparent color, no pen is used. | 459 // Make sure that for transparent color, no pen is used. |
| 462 if (paint.getAlpha() == 0) { | 460 if (paint.getAlpha() == 0) { |
| 463 // Test if it ever happen. | 461 // Test if it ever happen. |
| 464 NOTREACHED(); | 462 SkASSERT(false); |
| 465 use_pen = false; | 463 use_pen = false; |
| 466 } | 464 } |
| 467 | 465 |
| 468 DWORD pen_style = PS_GEOMETRIC | PS_SOLID; | 466 DWORD pen_style = PS_GEOMETRIC | PS_SOLID; |
| 469 switch (paint.getStrokeJoin()) { | 467 switch (paint.getStrokeJoin()) { |
| 470 case SkPaint::kMiter_Join: | 468 case SkPaint::kMiter_Join: |
| 471 // Connects path segments with a sharp join. | 469 // Connects path segments with a sharp join. |
| 472 pen_style |= PS_JOIN_MITER; | 470 pen_style |= PS_JOIN_MITER; |
| 473 break; | 471 break; |
| 474 case SkPaint::kRound_Join: | 472 case SkPaint::kRound_Join: |
| 475 // Connects path segments with a round join. | 473 // Connects path segments with a round join. |
| 476 pen_style |= PS_JOIN_ROUND; | 474 pen_style |= PS_JOIN_ROUND; |
| 477 break; | 475 break; |
| 478 case SkPaint::kBevel_Join: | 476 case SkPaint::kBevel_Join: |
| 479 // Connects path segments with a flat bevel join. | 477 // Connects path segments with a flat bevel join. |
| 480 pen_style |= PS_JOIN_BEVEL; | 478 pen_style |= PS_JOIN_BEVEL; |
| 481 break; | 479 break; |
| 482 default: | 480 default: |
| 483 NOTREACHED(); | 481 SkASSERT(false); |
| 484 break; | 482 break; |
| 485 } | 483 } |
| 486 switch (paint.getStrokeCap()) { | 484 switch (paint.getStrokeCap()) { |
| 487 case SkPaint::kButt_Cap: | 485 case SkPaint::kButt_Cap: |
| 488 // Begin/end contours with no extension. | 486 // Begin/end contours with no extension. |
| 489 pen_style |= PS_ENDCAP_FLAT; | 487 pen_style |= PS_ENDCAP_FLAT; |
| 490 break; | 488 break; |
| 491 case SkPaint::kRound_Cap: | 489 case SkPaint::kRound_Cap: |
| 492 // Begin/end contours with a semi-circle extension. | 490 // Begin/end contours with a semi-circle extension. |
| 493 pen_style |= PS_ENDCAP_ROUND; | 491 pen_style |= PS_ENDCAP_ROUND; |
| 494 break; | 492 break; |
| 495 case SkPaint::kSquare_Cap: | 493 case SkPaint::kSquare_Cap: |
| 496 // Begin/end contours with a half square extension. | 494 // Begin/end contours with a half square extension. |
| 497 pen_style |= PS_ENDCAP_SQUARE; | 495 pen_style |= PS_ENDCAP_SQUARE; |
| 498 break; | 496 break; |
| 499 default: | 497 default: |
| 500 NOTREACHED(); | 498 SkASSERT(false); |
| 501 break; | 499 break; |
| 502 } | 500 } |
| 503 | 501 |
| 504 return CreatePen(use_pen, | 502 return CreatePen(use_pen, |
| 505 SkColorToCOLORREF(paint.getColor()), | 503 SkColorToCOLORREF(paint.getColor()), |
| 506 SkScalarRound(paint.getStrokeWidth()), | 504 SkScalarRound(paint.getStrokeWidth()), |
| 507 paint.getStrokeMiter(), | 505 paint.getStrokeMiter(), |
| 508 pen_style); | 506 pen_style); |
| 509 } | 507 } |
| 510 | 508 |
| 511 void VectorDevice::InternalDrawBitmap(const SkBitmap& bitmap, int x, int y, | 509 void VectorDevice::InternalDrawBitmap(const SkBitmap& bitmap, int x, int y, |
| 512 const SkPaint& paint) { | 510 const SkPaint& paint) { |
| 513 uint8 alpha = paint.getAlpha(); | 511 unsigned char alpha = paint.getAlpha(); |
| 514 if (alpha == 0) | 512 if (alpha == 0) |
| 515 return; | 513 return; |
| 516 | 514 |
| 517 bool is_translucent; | 515 bool is_translucent; |
| 518 if (alpha != 255) { | 516 if (alpha != 255) { |
| 519 // ApplyPaint expect an opaque color. | 517 // ApplyPaint expect an opaque color. |
| 520 SkPaint tmp_paint(paint); | 518 SkPaint tmp_paint(paint); |
| 521 tmp_paint.setAlpha(255); | 519 tmp_paint.setAlpha(255); |
| 522 if (!ApplyPaint(tmp_paint)) | 520 if (!ApplyPaint(tmp_paint)) |
| 523 return; | 521 return; |
| 524 is_translucent = true; | 522 is_translucent = true; |
| 525 } else { | 523 } else { |
| 526 if (!ApplyPaint(paint)) | 524 if (!ApplyPaint(paint)) |
| 527 return; | 525 return; |
| 528 is_translucent = false; | 526 is_translucent = false; |
| 529 } | 527 } |
| 530 int src_size_x = bitmap.width(); | 528 int src_size_x = bitmap.width(); |
| 531 int src_size_y = bitmap.height(); | 529 int src_size_y = bitmap.height(); |
| 532 if (!src_size_x || !src_size_y) | 530 if (!src_size_x || !src_size_y) |
| 533 return; | 531 return; |
| 534 | 532 |
| 535 // Create a BMP v4 header that we can serialize. | 533 // Create a BMP v4 header that we can serialize. |
| 536 BITMAPV4HEADER bitmap_header; | 534 BITMAPV4HEADER bitmap_header; |
| 537 gfx::CreateBitmapV4Header(src_size_x, src_size_y, &bitmap_header); | 535 gfx::CreateBitmapV4Header(src_size_x, src_size_y, &bitmap_header); |
| 538 HDC dc = getBitmapDC(); | 536 HDC dc = getBitmapDC(); |
| 539 SkAutoLockPixels lock(bitmap); | 537 SkAutoLockPixels lock(bitmap); |
| 540 DCHECK_EQ(bitmap.getConfig(), SkBitmap::kARGB_8888_Config); | 538 SkASSERT(bitmap.getConfig() == SkBitmap::kARGB_8888_Config); |
| 541 const uint32_t* pixels = static_cast<const uint32_t*>(bitmap.getPixels()); | 539 const uint32_t* pixels = static_cast<const uint32_t*>(bitmap.getPixels()); |
| 542 if (pixels == NULL) { | 540 if (pixels == NULL) { |
| 543 NOTREACHED(); | 541 SkASSERT(false); |
| 544 return; | 542 return; |
| 545 } | 543 } |
| 546 | 544 |
| 547 if (!is_translucent) { | 545 if (!is_translucent) { |
| 548 int row_length = bitmap.rowBytesAsPixels(); | 546 int row_length = bitmap.rowBytesAsPixels(); |
| 549 // There is no quick way to determine if an image is opaque. | 547 // There is no quick way to determine if an image is opaque. |
| 550 for (int y2 = 0; y2 < src_size_y; ++y2) { | 548 for (int y2 = 0; y2 < src_size_y; ++y2) { |
| 551 for (int x2 = 0; x2 < src_size_x; ++x2) { | 549 for (int x2 = 0; x2 < src_size_x; ++x2) { |
| 552 if (SkColorGetA(pixels[(y2 * row_length) + x2]) != 255) { | 550 if (SkColorGetA(pixels[(y2 * row_length) + x2]) != 255) { |
| 553 is_translucent = true; | 551 is_translucent = true; |
| 554 y2 = src_size_y; | 552 y2 = src_size_y; |
| 555 break; | 553 break; |
| 556 } | 554 } |
| 557 } | 555 } |
| 558 } | 556 } |
| 559 } | 557 } |
| 560 | 558 |
| 561 BITMAPINFOHEADER hdr; | 559 BITMAPINFOHEADER hdr; |
| 562 gfx::CreateBitmapHeader(src_size_x, src_size_y, &hdr); | 560 gfx::CreateBitmapHeader(src_size_x, src_size_y, &hdr); |
| 563 if (is_translucent) { | 561 if (is_translucent) { |
| 564 // The image must be loaded as a bitmap inside a device context. | 562 // The image must be loaded as a bitmap inside a device context. |
| 565 ScopedHDC bitmap_dc(::CreateCompatibleDC(dc)); | 563 HDC bitmap_dc = ::CreateCompatibleDC(dc); |
| 566 void* bits = NULL; | 564 void* bits = NULL; |
| 567 ScopedBitmap hbitmap(::CreateDIBSection( | 565 HBITMAP hbitmap = ::CreateDIBSection( |
| 568 bitmap_dc, reinterpret_cast<const BITMAPINFO*>(&hdr), | 566 bitmap_dc, reinterpret_cast<const BITMAPINFO*>(&hdr), |
| 569 DIB_RGB_COLORS, &bits, NULL, 0)); | 567 DIB_RGB_COLORS, &bits, NULL, 0); |
| 570 memcpy(bits, pixels, bitmap.getSize()); | 568 memcpy(bits, pixels, bitmap.getSize()); |
| 571 DCHECK(hbitmap); | 569 SkASSERT(hbitmap); |
| 572 HGDIOBJ old_bitmap = ::SelectObject(bitmap_dc, hbitmap); | 570 HGDIOBJ old_bitmap = ::SelectObject(bitmap_dc, hbitmap); |
| 573 DeleteObject(old_bitmap); | |
| 574 | 571 |
| 575 // After some analysis of IE7's behavior, this is the thing to do. I was | 572 // After some analysis of IE7's behavior, this is the thing to do. I was |
| 576 // sure IE7 was doing so kind of bitmasking due to the way translucent image | 573 // sure IE7 was doing so kind of bitmasking due to the way translucent image |
| 577 // where renderered but after some windbg tracing, it is being done by the | 574 // where renderered but after some windbg tracing, it is being done by the |
| 578 // printer driver after all (mostly HP printers). IE7 always use AlphaBlend | 575 // printer driver after all (mostly HP printers). IE7 always use AlphaBlend |
| 579 // for bitmasked images. The trick seems to switch the stretching mode in | 576 // for bitmasked images. The trick seems to switch the stretching mode in |
| 580 // what the driver expects. | 577 // what the driver expects. |
| 581 DWORD previous_mode = GetStretchBltMode(dc); | 578 DWORD previous_mode = GetStretchBltMode(dc); |
| 582 BOOL result = SetStretchBltMode(dc, COLORONCOLOR); | 579 BOOL result = SetStretchBltMode(dc, COLORONCOLOR); |
| 583 DCHECK(result); | 580 SkASSERT(result); |
| 584 // Note that this function expect premultiplied colors (!) | 581 // Note that this function expect premultiplied colors (!) |
| 585 BLENDFUNCTION blend_function = {AC_SRC_OVER, 0, alpha, AC_SRC_ALPHA}; | 582 BLENDFUNCTION blend_function = {AC_SRC_OVER, 0, alpha, AC_SRC_ALPHA}; |
| 586 result = GdiAlphaBlend(dc, | 583 result = GdiAlphaBlend(dc, |
| 587 x, y, // Destination origin. | 584 x, y, // Destination origin. |
| 588 src_size_x, src_size_y, // Destination size. | 585 src_size_x, src_size_y, // Destination size. |
| 589 bitmap_dc, | 586 bitmap_dc, |
| 590 0, 0, // Source origin. | 587 0, 0, // Source origin. |
| 591 src_size_x, src_size_y, // Source size. | 588 src_size_x, src_size_y, // Source size. |
| 592 blend_function); | 589 blend_function); |
| 593 DCHECK(result); | 590 SkASSERT(result); |
| 594 result = SetStretchBltMode(dc, previous_mode); | 591 result = SetStretchBltMode(dc, previous_mode); |
| 595 DCHECK(result); | 592 SkASSERT(result); |
| 593 |
| 594 ::SelectObject(bitmap_dc, static_cast<HBITMAP>(old_bitmap)); |
| 595 DeleteObject(hbitmap); |
| 596 DeleteDC(bitmap_dc); |
| 596 } else { | 597 } else { |
| 597 BOOL result = StretchDIBits(dc, | 598 BOOL result = StretchDIBits(dc, |
| 598 x, y, // Destination origin. | 599 x, y, // Destination origin. |
| 599 src_size_x, src_size_y, | 600 src_size_x, src_size_y, |
| 600 0, 0, // Source origin. | 601 0, 0, // Source origin. |
| 601 src_size_x, src_size_y, // Source size. | 602 src_size_x, src_size_y, // Source size. |
| 602 pixels, | 603 pixels, |
| 603 reinterpret_cast<const BITMAPINFO*>(&hdr), | 604 reinterpret_cast<const BITMAPINFO*>(&hdr), |
| 604 DIB_RGB_COLORS, | 605 DIB_RGB_COLORS, |
| 605 SRCCOPY); | 606 SRCCOPY); |
| 606 DCHECK(result); | 607 SkASSERT(result); |
| 607 } | 608 } |
| 608 Cleanup(); | 609 Cleanup(); |
| 609 } | 610 } |
| 610 | 611 |
| 611 } // namespace skia | 612 } // namespace skia |
| 612 | 613 |
| OLD | NEW |