Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(139)

Side by Side Diff: skia/ext/vector_platform_device_win.cc

Issue 125109: Refactor the PlatformContext layer to have only one class. (Closed)
Patch Set: Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « skia/ext/vector_platform_device_win.h ('k') | skia/skia.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <windows.h>
6
7 #include "skia/ext/vector_platform_device_win.h"
8
9 #include "base/gfx/gdi_util.h"
10 #include "skia/ext/skia_utils_win.h"
11 #include "third_party/skia/include/core/SkUtils.h"
12
13 namespace skia {
14
15 VectorPlatformDevice* VectorPlatformDevice::create(HDC dc,
16 int width, int height) {
17 InitializeDC(dc);
18
19 // Link the SkBitmap to the current selected bitmap in the device context.
20 SkBitmap bitmap;
21 HGDIOBJ selected_bitmap = GetCurrentObject(dc, OBJ_BITMAP);
22 bool succeeded = false;
23 if (selected_bitmap != NULL) {
24 BITMAP bitmap_data;
25 if (GetObject(selected_bitmap, sizeof(BITMAP), &bitmap_data) ==
26 sizeof(BITMAP)) {
27 // The context has a bitmap attached. Attach our SkBitmap to it.
28 // Warning: If the bitmap gets unselected from the HDC,
29 // VectorPlatformDevice has no way to detect this, so the HBITMAP could be
30 // released while SkBitmap still has a reference to it. Be cautious.
31 if (width == bitmap_data.bmWidth &&
32 height == bitmap_data.bmHeight) {
33 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
34 bitmap_data.bmWidth,
35 bitmap_data.bmHeight,
36 bitmap_data.bmWidthBytes);
37 bitmap.setPixels(bitmap_data.bmBits);
38 succeeded = true;
39 }
40 }
41 }
42
43 if (!succeeded)
44 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
45
46 return new VectorPlatformDevice(dc, bitmap);
47 }
48
49 VectorPlatformDevice::VectorPlatformDevice(HDC dc, const SkBitmap& bitmap)
50 : PlatformDevice(bitmap),
51 hdc_(dc),
52 previous_brush_(NULL),
53 previous_pen_(NULL) {
54 transform_.reset();
55 }
56
57 VectorPlatformDevice::~VectorPlatformDevice() {
58 SkASSERT(previous_brush_ == NULL);
59 SkASSERT(previous_pen_ == NULL);
60 }
61
62
63 void VectorPlatformDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
64 // TODO(maruel): Bypass the current transformation matrix.
65 SkRect rect;
66 rect.fLeft = 0;
67 rect.fTop = 0;
68 rect.fRight = SkIntToScalar(width() + 1);
69 rect.fBottom = SkIntToScalar(height() + 1);
70 drawRect(draw, rect, paint);
71 }
72
73 void VectorPlatformDevice::drawPoints(const SkDraw& draw,
74 SkCanvas::PointMode mode,
75 size_t count,
76 const SkPoint pts[],
77 const SkPaint& paint) {
78 if (!count)
79 return;
80
81 if (mode == SkCanvas::kPoints_PointMode) {
82 SkASSERT(false);
83 return;
84 }
85
86 SkPaint tmp_paint(paint);
87 tmp_paint.setStyle(SkPaint::kStroke_Style);
88
89 // Draw a path instead.
90 SkPath path;
91 switch (mode) {
92 case SkCanvas::kLines_PointMode:
93 if (count % 2) {
94 SkASSERT(false);
95 return;
96 }
97 for (size_t i = 0; i < count / 2; ++i) {
98 path.moveTo(pts[2 * i]);
99 path.lineTo(pts[2 * i + 1]);
100 }
101 break;
102 case SkCanvas::kPolygon_PointMode:
103 path.moveTo(pts[0]);
104 for (size_t i = 1; i < count; ++i) {
105 path.lineTo(pts[i]);
106 }
107 break;
108 default:
109 SkASSERT(false);
110 return;
111 }
112 // Draw the calculated path.
113 drawPath(draw, path, tmp_paint);
114 }
115
116 void VectorPlatformDevice::drawRect(const SkDraw& draw,
117 const SkRect& rect,
118 const SkPaint& paint) {
119 if (paint.getPathEffect()) {
120 // Draw a path instead.
121 SkPath path_orginal;
122 path_orginal.addRect(rect);
123
124 // Apply the path effect to the rect.
125 SkPath path_modified;
126 paint.getFillPath(path_orginal, &path_modified);
127
128 // Removes the path effect from the temporary SkPaint object.
129 SkPaint paint_no_effet(paint);
130 paint_no_effet.setPathEffect(NULL)->safeUnref();
131
132 // Draw the calculated path.
133 drawPath(draw, path_modified, paint_no_effet);
134 return;
135 }
136
137 if (!ApplyPaint(paint)) {
138 return;
139 }
140 HDC dc = getBitmapDC();
141 if (!Rectangle(dc, SkScalarRound(rect.fLeft),
142 SkScalarRound(rect.fTop),
143 SkScalarRound(rect.fRight),
144 SkScalarRound(rect.fBottom))) {
145 SkASSERT(false);
146 }
147 Cleanup();
148 }
149
150 void VectorPlatformDevice::drawPath(const SkDraw& draw,
151 const SkPath& path,
152 const SkPaint& paint) {
153 if (paint.getPathEffect()) {
154 // Apply the path effect forehand.
155 SkPath path_modified;
156 paint.getFillPath(path, &path_modified);
157
158 // Removes the path effect from the temporary SkPaint object.
159 SkPaint paint_no_effet(paint);
160 paint_no_effet.setPathEffect(NULL)->safeUnref();
161
162 // Draw the calculated path.
163 drawPath(draw, path_modified, paint_no_effet);
164 return;
165 }
166
167 if (!ApplyPaint(paint)) {
168 return;
169 }
170 HDC dc = getBitmapDC();
171 PlatformDevice::LoadPathToDC(dc, path);
172 switch (paint.getStyle()) {
173 case SkPaint::kFill_Style: {
174 BOOL res = StrokeAndFillPath(dc);
175 SkASSERT(res != 0);
176 break;
177 }
178 case SkPaint::kStroke_Style: {
179 BOOL res = StrokePath(dc);
180 SkASSERT(res != 0);
181 break;
182 }
183 case SkPaint::kStrokeAndFill_Style: {
184 BOOL res = StrokeAndFillPath(dc);
185 SkASSERT(res != 0);
186 break;
187 }
188 default:
189 SkASSERT(false);
190 break;
191 }
192 Cleanup();
193 }
194
195 void VectorPlatformDevice::drawBitmap(const SkDraw& draw,
196 const SkBitmap& bitmap,
197 const SkMatrix& matrix,
198 const SkPaint& paint) {
199 // Load the temporary matrix. This is what will translate, rotate and resize
200 // the bitmap.
201 SkMatrix actual_transform(transform_);
202 actual_transform.preConcat(matrix);
203 LoadTransformToDC(hdc_, actual_transform);
204
205 InternalDrawBitmap(bitmap, 0, 0, paint);
206
207 // Restore the original matrix.
208 LoadTransformToDC(hdc_, transform_);
209 }
210
211 void VectorPlatformDevice::drawSprite(const SkDraw& draw,
212 const SkBitmap& bitmap,
213 int x, int y,
214 const SkPaint& paint) {
215 SkMatrix identity;
216 identity.reset();
217 LoadTransformToDC(hdc_, identity);
218
219 InternalDrawBitmap(bitmap, x, y, paint);
220
221 // Restore the original matrix.
222 LoadTransformToDC(hdc_, transform_);
223 }
224
225 void VectorPlatformDevice::drawText(const SkDraw& draw,
226 const void* text,
227 size_t byteLength,
228 SkScalar x,
229 SkScalar y,
230 const SkPaint& paint) {
231 // This function isn't used in the code. Verify this assumption.
232 SkASSERT(false);
233 }
234
235 void VectorPlatformDevice::drawPosText(const SkDraw& draw,
236 const void* text,
237 size_t len,
238 const SkScalar pos[],
239 SkScalar constY,
240 int scalarsPerPos,
241 const SkPaint& paint) {
242 // This function isn't used in the code. Verify this assumption.
243 SkASSERT(false);
244 }
245
246 void VectorPlatformDevice::drawTextOnPath(const SkDraw& draw,
247 const void* text,
248 size_t len,
249 const SkPath& path,
250 const SkMatrix* matrix,
251 const SkPaint& paint) {
252 // This function isn't used in the code. Verify this assumption.
253 SkASSERT(false);
254 }
255
256 void VectorPlatformDevice::drawVertices(const SkDraw& draw,
257 SkCanvas::VertexMode vmode,
258 int vertexCount,
259 const SkPoint vertices[],
260 const SkPoint texs[],
261 const SkColor colors[],
262 SkXfermode* xmode,
263 const uint16_t indices[],
264 int indexCount,
265 const SkPaint& paint) {
266 // This function isn't used in the code. Verify this assumption.
267 SkASSERT(false);
268 }
269
270 void VectorPlatformDevice::drawDevice(const SkDraw& draw,
271 SkDevice* device,
272 int x,
273 int y,
274 const SkPaint& paint) {
275 // TODO(maruel): http://b/1183870 Playback the EMF buffer at printer's dpi if
276 // it is a vectorial device.
277 drawSprite(draw, device->accessBitmap(false), x, y, paint);
278 }
279
280 bool VectorPlatformDevice::ApplyPaint(const SkPaint& paint) {
281 // Note: The goal here is to transfert the SkPaint's state to the HDC's state.
282 // This function does not execute the SkPaint drawing commands. These should
283 // be executed in drawPaint().
284
285 SkPaint::Style style = paint.getStyle();
286 if (!paint.getAlpha())
287 style = SkPaint::kStyleCount;
288
289 switch (style) {
290 case SkPaint::kFill_Style:
291 if (!CreateBrush(true, paint) ||
292 !CreatePen(false, paint))
293 return false;
294 break;
295 case SkPaint::kStroke_Style:
296 if (!CreateBrush(false, paint) ||
297 !CreatePen(true, paint))
298 return false;
299 break;
300 case SkPaint::kStrokeAndFill_Style:
301 if (!CreateBrush(true, paint) ||
302 !CreatePen(true, paint))
303 return false;
304 break;
305 default:
306 if (!CreateBrush(false, paint) ||
307 !CreatePen(false, paint))
308 return false;
309 break;
310 }
311
312 /*
313 getFlags();
314 isAntiAlias();
315 isDither()
316 isLinearText()
317 isSubpixelText()
318 isUnderlineText()
319 isStrikeThruText()
320 isFakeBoldText()
321 isDevKernText()
322 isFilterBitmap()
323
324 // Skia's text is not used. This should be fixed.
325 getTextAlign()
326 getTextScaleX()
327 getTextSkewX()
328 getTextEncoding()
329 getFontMetrics()
330 getFontSpacing()
331 */
332
333 // BUG 1094907: Implement shaders. Shaders currently in use:
334 // SkShader::CreateBitmapShader
335 // SkGradientShader::CreateRadial
336 // SkGradientShader::CreateLinear
337 // SkASSERT(!paint.getShader());
338
339 // http://b/1106647 Implement loopers and mask filter. Looper currently in
340 // use:
341 // SkBlurDrawLooper is used for shadows.
342 // SkASSERT(!paint.getLooper());
343 // SkASSERT(!paint.getMaskFilter());
344
345 // http://b/1165900 Implement xfermode.
346 // SkASSERT(!paint.getXfermode());
347
348 // The path effect should be processed before arriving here.
349 SkASSERT(!paint.getPathEffect());
350
351 // These aren't used in the code. Verify this assumption.
352 SkASSERT(!paint.getColorFilter());
353 SkASSERT(!paint.getRasterizer());
354 // Reuse code to load Win32 Fonts.
355 SkASSERT(!paint.getTypeface());
356 return true;
357 }
358
359 void VectorPlatformDevice::setMatrixClip(const SkMatrix& transform,
360 const SkRegion& region) {
361 transform_ = transform;
362 LoadTransformToDC(hdc_, transform_);
363 clip_region_ = region;
364 if (!clip_region_.isEmpty())
365 LoadClipRegion();
366 }
367
368 void VectorPlatformDevice::drawToHDC(HDC dc, int x, int y,
369 const RECT* src_rect) {
370 SkASSERT(false);
371 }
372
373 void VectorPlatformDevice::LoadClipRegion() {
374 SkMatrix t;
375 t.reset();
376 LoadClippingRegionToDC(hdc_, clip_region_, t);
377 }
378
379 bool VectorPlatformDevice::CreateBrush(bool use_brush, COLORREF color) {
380 SkASSERT(previous_brush_ == NULL);
381 // We can't use SetDCBrushColor() or DC_BRUSH when drawing to a EMF buffer.
382 // SetDCBrushColor() calls are not recorded at all and DC_BRUSH will use
383 // WHITE_BRUSH instead.
384
385 if (!use_brush) {
386 // Set the transparency.
387 if (0 == SetBkMode(hdc_, TRANSPARENT)) {
388 SkASSERT(false);
389 return false;
390 }
391
392 // Select the NULL brush.
393 previous_brush_ = SelectObject(GetStockObject(NULL_BRUSH));
394 return previous_brush_ != NULL;
395 }
396
397 // Set the opacity.
398 if (0 == SetBkMode(hdc_, OPAQUE)) {
399 SkASSERT(false);
400 return false;
401 }
402
403 // Create and select the brush.
404 previous_brush_ = SelectObject(CreateSolidBrush(color));
405 return previous_brush_ != NULL;
406 }
407
408 bool VectorPlatformDevice::CreatePen(bool use_pen,
409 COLORREF color,
410 int stroke_width,
411 float stroke_miter,
412 DWORD pen_style) {
413 SkASSERT(previous_pen_ == NULL);
414 // We can't use SetDCPenColor() or DC_PEN when drawing to a EMF buffer.
415 // SetDCPenColor() calls are not recorded at all and DC_PEN will use BLACK_PEN
416 // instead.
417
418 // No pen case
419 if (!use_pen) {
420 previous_pen_ = SelectObject(GetStockObject(NULL_PEN));
421 return previous_pen_ != NULL;
422 }
423
424 // Use the stock pen if the stroke width is 0.
425 if (stroke_width == 0) {
426 // Create a pen with the right color.
427 previous_pen_ = SelectObject(::CreatePen(PS_SOLID, 0, color));
428 return previous_pen_ != NULL;
429 }
430
431 // Load a custom pen.
432 LOGBRUSH brush;
433 brush.lbStyle = BS_SOLID;
434 brush.lbColor = color;
435 brush.lbHatch = 0;
436 HPEN pen = ExtCreatePen(pen_style, stroke_width, &brush, 0, NULL);
437 SkASSERT(pen != NULL);
438 previous_pen_ = SelectObject(pen);
439 if (previous_pen_ == NULL)
440 return false;
441
442 if (!SetMiterLimit(hdc_, stroke_miter, NULL)) {
443 SkASSERT(false);
444 return false;
445 }
446 return true;
447 }
448
449 void VectorPlatformDevice::Cleanup() {
450 if (previous_brush_) {
451 HGDIOBJ result = SelectObject(previous_brush_);
452 previous_brush_ = NULL;
453 if (result) {
454 BOOL res = DeleteObject(result);
455 SkASSERT(res != 0);
456 }
457 }
458 if (previous_pen_) {
459 HGDIOBJ result = SelectObject(previous_pen_);
460 previous_pen_ = NULL;
461 if (result) {
462 BOOL res = DeleteObject(result);
463 SkASSERT(res != 0);
464 }
465 }
466 // Remove any loaded path from the context.
467 AbortPath(hdc_);
468 }
469
470 HGDIOBJ VectorPlatformDevice::SelectObject(HGDIOBJ object) {
471 HGDIOBJ result = ::SelectObject(hdc_, object);
472 SkASSERT(result != HGDI_ERROR);
473 if (result == HGDI_ERROR)
474 return NULL;
475 return result;
476 }
477
478 bool VectorPlatformDevice::CreateBrush(bool use_brush, const SkPaint& paint) {
479 // Make sure that for transparent color, no brush is used.
480 if (paint.getAlpha() == 0) {
481 // Test if it ever happen.
482 SkASSERT(false);
483 use_brush = false;
484 }
485
486 return CreateBrush(use_brush, SkColorToCOLORREF(paint.getColor()));
487 }
488
489 bool VectorPlatformDevice::CreatePen(bool use_pen, const SkPaint& paint) {
490 // Make sure that for transparent color, no pen is used.
491 if (paint.getAlpha() == 0) {
492 // Test if it ever happen.
493 SkASSERT(false);
494 use_pen = false;
495 }
496
497 DWORD pen_style = PS_GEOMETRIC | PS_SOLID;
498 switch (paint.getStrokeJoin()) {
499 case SkPaint::kMiter_Join:
500 // Connects path segments with a sharp join.
501 pen_style |= PS_JOIN_MITER;
502 break;
503 case SkPaint::kRound_Join:
504 // Connects path segments with a round join.
505 pen_style |= PS_JOIN_ROUND;
506 break;
507 case SkPaint::kBevel_Join:
508 // Connects path segments with a flat bevel join.
509 pen_style |= PS_JOIN_BEVEL;
510 break;
511 default:
512 SkASSERT(false);
513 break;
514 }
515 switch (paint.getStrokeCap()) {
516 case SkPaint::kButt_Cap:
517 // Begin/end contours with no extension.
518 pen_style |= PS_ENDCAP_FLAT;
519 break;
520 case SkPaint::kRound_Cap:
521 // Begin/end contours with a semi-circle extension.
522 pen_style |= PS_ENDCAP_ROUND;
523 break;
524 case SkPaint::kSquare_Cap:
525 // Begin/end contours with a half square extension.
526 pen_style |= PS_ENDCAP_SQUARE;
527 break;
528 default:
529 SkASSERT(false);
530 break;
531 }
532
533 return CreatePen(use_pen,
534 SkColorToCOLORREF(paint.getColor()),
535 SkScalarRound(paint.getStrokeWidth()),
536 paint.getStrokeMiter(),
537 pen_style);
538 }
539
540 void VectorPlatformDevice::InternalDrawBitmap(const SkBitmap& bitmap,
541 int x, int y,
542 const SkPaint& paint) {
543 unsigned char alpha = paint.getAlpha();
544 if (alpha == 0)
545 return;
546
547 bool is_translucent;
548 if (alpha != 255) {
549 // ApplyPaint expect an opaque color.
550 SkPaint tmp_paint(paint);
551 tmp_paint.setAlpha(255);
552 if (!ApplyPaint(tmp_paint))
553 return;
554 is_translucent = true;
555 } else {
556 if (!ApplyPaint(paint))
557 return;
558 is_translucent = false;
559 }
560 int src_size_x = bitmap.width();
561 int src_size_y = bitmap.height();
562 if (!src_size_x || !src_size_y)
563 return;
564
565 // Create a BMP v4 header that we can serialize.
566 BITMAPV4HEADER bitmap_header;
567 gfx::CreateBitmapV4Header(src_size_x, src_size_y, &bitmap_header);
568 HDC dc = getBitmapDC();
569 SkAutoLockPixels lock(bitmap);
570 SkASSERT(bitmap.getConfig() == SkBitmap::kARGB_8888_Config);
571 const uint32_t* pixels = static_cast<const uint32_t*>(bitmap.getPixels());
572 if (pixels == NULL) {
573 SkASSERT(false);
574 return;
575 }
576
577 if (!is_translucent) {
578 int row_length = bitmap.rowBytesAsPixels();
579 // There is no quick way to determine if an image is opaque.
580 for (int y2 = 0; y2 < src_size_y; ++y2) {
581 for (int x2 = 0; x2 < src_size_x; ++x2) {
582 if (SkColorGetA(pixels[(y2 * row_length) + x2]) != 255) {
583 is_translucent = true;
584 y2 = src_size_y;
585 break;
586 }
587 }
588 }
589 }
590
591 BITMAPINFOHEADER hdr;
592 gfx::CreateBitmapHeader(src_size_x, src_size_y, &hdr);
593 if (is_translucent) {
594 // The image must be loaded as a bitmap inside a device context.
595 HDC bitmap_dc = ::CreateCompatibleDC(dc);
596 void* bits = NULL;
597 HBITMAP hbitmap = ::CreateDIBSection(
598 bitmap_dc, reinterpret_cast<const BITMAPINFO*>(&hdr),
599 DIB_RGB_COLORS, &bits, NULL, 0);
600 memcpy(bits, pixels, bitmap.getSize());
601 SkASSERT(hbitmap);
602 HGDIOBJ old_bitmap = ::SelectObject(bitmap_dc, hbitmap);
603
604 // After some analysis of IE7's behavior, this is the thing to do. I was
605 // sure IE7 was doing so kind of bitmasking due to the way translucent image
606 // where renderered but after some windbg tracing, it is being done by the
607 // printer driver after all (mostly HP printers). IE7 always use AlphaBlend
608 // for bitmasked images. The trick seems to switch the stretching mode in
609 // what the driver expects.
610 DWORD previous_mode = GetStretchBltMode(dc);
611 BOOL result = SetStretchBltMode(dc, COLORONCOLOR);
612 SkASSERT(result);
613 // Note that this function expect premultiplied colors (!)
614 BLENDFUNCTION blend_function = {AC_SRC_OVER, 0, alpha, AC_SRC_ALPHA};
615 result = GdiAlphaBlend(dc,
616 x, y, // Destination origin.
617 src_size_x, src_size_y, // Destination size.
618 bitmap_dc,
619 0, 0, // Source origin.
620 src_size_x, src_size_y, // Source size.
621 blend_function);
622 SkASSERT(result);
623 result = SetStretchBltMode(dc, previous_mode);
624 SkASSERT(result);
625
626 ::SelectObject(bitmap_dc, static_cast<HBITMAP>(old_bitmap));
627 DeleteObject(hbitmap);
628 DeleteDC(bitmap_dc);
629 } else {
630 BOOL result = StretchDIBits(dc,
631 x, y, // Destination origin.
632 src_size_x, src_size_y,
633 0, 0, // Source origin.
634 src_size_x, src_size_y, // Source size.
635 pixels,
636 reinterpret_cast<const BITMAPINFO*>(&hdr),
637 DIB_RGB_COLORS,
638 SRCCOPY);
639 SkASSERT(result);
640 }
641 Cleanup();
642 }
643
644 } // namespace skia
645
OLDNEW
« no previous file with comments | « skia/ext/vector_platform_device_win.h ('k') | skia/skia.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698