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

Side by Side Diff: base/gfx/vector_device.cc

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

Powered by Google App Engine
This is Rietveld 408576698