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 |