- add sources.
[platform/framework/web/crosswalk.git] / src / skia / ext / vector_platform_device_emf_win.cc
1 // Copyright (c) 2012 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 "skia/ext/vector_platform_device_emf_win.h"
6
7 #include <windows.h>
8
9 #include "base/logging.h"
10 #include "base/strings/string16.h"
11 #include "skia/ext/bitmap_platform_device.h"
12 #include "skia/ext/skia_utils_win.h"
13 #include "third_party/skia/include/core/SkFontHost.h"
14 #include "third_party/skia/include/core/SkPathEffect.h"
15 #include "third_party/skia/include/core/SkTemplates.h"
16 #include "third_party/skia/include/core/SkUtils.h"
17 #include "third_party/skia/include/ports/SkTypeface_win.h"
18
19 namespace skia {
20
21 #define CHECK_FOR_NODRAW_ANNOTATION(paint) \
22     do { if (paint.isNoDrawAnnotation()) { return; } } while (0)
23
24 // static
25 SkBaseDevice* VectorPlatformDeviceEmf::CreateDevice(
26     int width, int height, bool is_opaque, HANDLE shared_section) {
27   if (!is_opaque) {
28     // TODO(maruel):  http://crbug.com/18382 When restoring a semi-transparent
29     // layer, i.e. merging it, we need to rasterize it because GDI doesn't
30     // support transparency except for AlphaBlend(). Right now, a
31     // BitmapPlatformDevice is created when VectorCanvas think a saveLayers()
32     // call is being done. The way to save a layer would be to create an
33     // EMF-based VectorDevice and have this device registers the drawing. When
34     // playing back the device into a bitmap, do it at the printer's dpi instead
35     // of the layout's dpi (which is much lower).
36     return BitmapPlatformDevice::Create(width, height, is_opaque,
37                                         shared_section);
38   }
39
40   // TODO(maruel):  http://crbug.com/18383 Look if it would be worth to
41   // increase the resolution by ~10x (any worthy factor) to increase the
42   // rendering precision (think about printing) while using a relatively
43   // low dpi. This happens because we receive float as input but the GDI
44   // functions works with integers. The idea is to premultiply the matrix
45   // with this factor and multiply each SkScalar that are passed to
46   // SkScalarRound(value) as SkScalarRound(value * 10). Safari is already
47   // doing the same for text rendering.
48   SkASSERT(shared_section);
49   SkBaseDevice* device = VectorPlatformDeviceEmf::create(
50       reinterpret_cast<HDC>(shared_section), width, height);
51   return device;
52 }
53
54 static void FillBitmapInfoHeader(int width, int height, BITMAPINFOHEADER* hdr) {
55   hdr->biSize = sizeof(BITMAPINFOHEADER);
56   hdr->biWidth = width;
57   hdr->biHeight = -height;  // Minus means top-down bitmap.
58   hdr->biPlanes = 1;
59   hdr->biBitCount = 32;
60   hdr->biCompression = BI_RGB;  // no compression
61   hdr->biSizeImage = 0;
62   hdr->biXPelsPerMeter = 1;
63   hdr->biYPelsPerMeter = 1;
64   hdr->biClrUsed = 0;
65   hdr->biClrImportant = 0;
66 }
67
68 SkBaseDevice* VectorPlatformDeviceEmf::create(HDC dc, int width, int height) {
69   InitializeDC(dc);
70
71   // Link the SkBitmap to the current selected bitmap in the device context.
72   SkBitmap bitmap;
73   HGDIOBJ selected_bitmap = GetCurrentObject(dc, OBJ_BITMAP);
74   bool succeeded = false;
75   if (selected_bitmap != NULL) {
76     BITMAP bitmap_data;
77     if (GetObject(selected_bitmap, sizeof(BITMAP), &bitmap_data) ==
78         sizeof(BITMAP)) {
79       // The context has a bitmap attached. Attach our SkBitmap to it.
80       // Warning: If the bitmap gets unselected from the HDC,
81       // VectorPlatformDeviceEmf has no way to detect this, so the HBITMAP
82       // could be released while SkBitmap still has a reference to it. Be
83       // cautious.
84       if (width == bitmap_data.bmWidth &&
85           height == bitmap_data.bmHeight) {
86         bitmap.setConfig(SkBitmap::kARGB_8888_Config,
87                          bitmap_data.bmWidth,
88                          bitmap_data.bmHeight,
89                          bitmap_data.bmWidthBytes);
90         bitmap.setPixels(bitmap_data.bmBits);
91         succeeded = true;
92       }
93     }
94   }
95
96   if (!succeeded)
97     bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
98
99   return new VectorPlatformDeviceEmf(dc, bitmap);
100 }
101
102 VectorPlatformDeviceEmf::VectorPlatformDeviceEmf(HDC dc, const SkBitmap& bitmap)
103     : SkBitmapDevice(bitmap),
104       hdc_(dc),
105       previous_brush_(NULL),
106       previous_pen_(NULL) {
107   transform_.reset();
108   SetPlatformDevice(this, this);
109 }
110
111 VectorPlatformDeviceEmf::~VectorPlatformDeviceEmf() {
112   SkASSERT(previous_brush_ == NULL);
113   SkASSERT(previous_pen_ == NULL);
114 }
115
116 HDC VectorPlatformDeviceEmf::BeginPlatformPaint() {
117   return hdc_;
118 }
119
120 uint32_t VectorPlatformDeviceEmf::getDeviceCapabilities() {
121   return SkBitmapDevice::getDeviceCapabilities() | kVector_Capability;
122 }
123
124 void VectorPlatformDeviceEmf::drawPaint(const SkDraw& draw,
125                                         const SkPaint& paint) {
126   // TODO(maruel):  Bypass the current transformation matrix.
127   SkRect rect;
128   rect.fLeft = 0;
129   rect.fTop = 0;
130   rect.fRight = SkIntToScalar(width() + 1);
131   rect.fBottom = SkIntToScalar(height() + 1);
132   drawRect(draw, rect, paint);
133 }
134
135 void VectorPlatformDeviceEmf::drawPoints(const SkDraw& draw,
136                                          SkCanvas::PointMode mode,
137                                          size_t count,
138                                          const SkPoint pts[],
139                                          const SkPaint& paint) {
140   if (!count)
141     return;
142
143   if (mode == SkCanvas::kPoints_PointMode) {
144     SkASSERT(false);
145     return;
146   }
147
148   SkPaint tmp_paint(paint);
149   tmp_paint.setStyle(SkPaint::kStroke_Style);
150
151   // Draw a path instead.
152   SkPath path;
153   switch (mode) {
154     case SkCanvas::kLines_PointMode:
155       if (count % 2) {
156         SkASSERT(false);
157         return;
158       }
159       for (size_t i = 0; i < count / 2; ++i) {
160         path.moveTo(pts[2 * i]);
161         path.lineTo(pts[2 * i + 1]);
162       }
163       break;
164     case SkCanvas::kPolygon_PointMode:
165       path.moveTo(pts[0]);
166       for (size_t i = 1; i < count; ++i) {
167         path.lineTo(pts[i]);
168       }
169       break;
170     default:
171       SkASSERT(false);
172       return;
173   }
174   // Draw the calculated path.
175   drawPath(draw, path, tmp_paint);
176 }
177
178 void VectorPlatformDeviceEmf::drawRect(const SkDraw& draw,
179                                        const SkRect& rect,
180                                        const SkPaint& paint) {
181   CHECK_FOR_NODRAW_ANNOTATION(paint);
182   if (paint.getPathEffect()) {
183     // Draw a path instead.
184     SkPath path_orginal;
185     path_orginal.addRect(rect);
186
187     // Apply the path effect to the rect.
188     SkPath path_modified;
189     paint.getFillPath(path_orginal, &path_modified);
190
191     // Removes the path effect from the temporary SkPaint object.
192     SkPaint paint_no_effet(paint);
193     paint_no_effet.setPathEffect(NULL);
194
195     // Draw the calculated path.
196     drawPath(draw, path_modified, paint_no_effet);
197     return;
198   }
199
200   if (!ApplyPaint(paint)) {
201     return;
202   }
203   HDC dc = BeginPlatformPaint();
204   if (!Rectangle(dc, SkScalarRound(rect.fLeft),
205                  SkScalarRound(rect.fTop),
206                  SkScalarRound(rect.fRight),
207                  SkScalarRound(rect.fBottom))) {
208     SkASSERT(false);
209   }
210   EndPlatformPaint();
211   Cleanup();
212 }
213
214 void VectorPlatformDeviceEmf::drawPath(const SkDraw& draw,
215                                        const SkPath& path,
216                                        const SkPaint& paint,
217                                        const SkMatrix* prePathMatrix,
218                                        bool pathIsMutable) {
219   CHECK_FOR_NODRAW_ANNOTATION(paint);
220   if (paint.getPathEffect()) {
221     // Apply the path effect forehand.
222     SkPath path_modified;
223     paint.getFillPath(path, &path_modified);
224
225     // Removes the path effect from the temporary SkPaint object.
226     SkPaint paint_no_effet(paint);
227     paint_no_effet.setPathEffect(NULL);
228
229     // Draw the calculated path.
230     drawPath(draw, path_modified, paint_no_effet);
231     return;
232   }
233
234   if (!ApplyPaint(paint)) {
235     return;
236   }
237   HDC dc = BeginPlatformPaint();
238   if (PlatformDevice::LoadPathToDC(dc, path)) {
239     switch (paint.getStyle()) {
240       case SkPaint::kFill_Style: {
241         BOOL res = StrokeAndFillPath(dc);
242         SkASSERT(res != 0);
243         break;
244       }
245       case SkPaint::kStroke_Style: {
246         BOOL res = StrokePath(dc);
247         SkASSERT(res != 0);
248         break;
249       }
250       case SkPaint::kStrokeAndFill_Style: {
251         BOOL res = StrokeAndFillPath(dc);
252         SkASSERT(res != 0);
253         break;
254       }
255       default:
256         SkASSERT(false);
257         break;
258     }
259   }
260   EndPlatformPaint();
261   Cleanup();
262 }
263
264 void VectorPlatformDeviceEmf::drawBitmapRect(const SkDraw& draw,
265                                              const SkBitmap& bitmap,
266                                              const SkRect* src,
267                                              const SkRect& dst,
268                                              const SkPaint& paint,
269                                              SkCanvas::DrawBitmapRectFlags flags) {
270     SkMatrix    matrix;
271     SkRect      bitmapBounds, tmpSrc, tmpDst;
272     SkBitmap    tmpBitmap;
273
274     bitmapBounds.isetWH(bitmap.width(), bitmap.height());
275
276     // Compute matrix from the two rectangles
277     if (src) {
278         tmpSrc = *src;
279     } else {
280         tmpSrc = bitmapBounds;
281     }
282     matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
283
284     const SkBitmap* bitmapPtr = &bitmap;
285
286     // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
287     // needed (if the src was clipped). No check needed if src==null.
288     if (src) {
289         if (!bitmapBounds.contains(*src)) {
290             if (!tmpSrc.intersect(bitmapBounds)) {
291                 return; // nothing to draw
292             }
293             // recompute dst, based on the smaller tmpSrc
294             matrix.mapRect(&tmpDst, tmpSrc);
295         }
296
297         // since we may need to clamp to the borders of the src rect within
298         // the bitmap, we extract a subset.
299         // TODO: make sure this is handled in drawrect and remove it from here.
300         SkIRect srcIR;
301         tmpSrc.roundOut(&srcIR);
302         if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
303             return;
304         }
305         bitmapPtr = &tmpBitmap;
306
307         // Since we did an extract, we need to adjust the matrix accordingly
308         SkScalar dx = 0, dy = 0;
309         if (srcIR.fLeft > 0) {
310             dx = SkIntToScalar(srcIR.fLeft);
311         }
312         if (srcIR.fTop > 0) {
313             dy = SkIntToScalar(srcIR.fTop);
314         }
315         if (dx || dy) {
316             matrix.preTranslate(dx, dy);
317         }
318     }
319     this->drawBitmap(draw, *bitmapPtr, matrix, paint);
320 }
321
322 void VectorPlatformDeviceEmf::drawBitmap(const SkDraw& draw,
323                                          const SkBitmap& bitmap,
324                                          const SkMatrix& matrix,
325                                          const SkPaint& paint) {
326   // Load the temporary matrix. This is what will translate, rotate and resize
327   // the bitmap.
328   SkMatrix actual_transform(transform_);
329   actual_transform.preConcat(matrix);
330   LoadTransformToDC(hdc_, actual_transform);
331
332   InternalDrawBitmap(bitmap, 0, 0, paint);
333
334   // Restore the original matrix.
335   LoadTransformToDC(hdc_, transform_);
336 }
337
338 void VectorPlatformDeviceEmf::drawSprite(const SkDraw& draw,
339                                          const SkBitmap& bitmap,
340                                          int x, int y,
341                                          const SkPaint& paint) {
342   SkMatrix identity;
343   identity.reset();
344   LoadTransformToDC(hdc_, identity);
345
346   InternalDrawBitmap(bitmap, x, y, paint);
347
348   // Restore the original matrix.
349   LoadTransformToDC(hdc_, transform_);
350 }
351
352 /////////////////////////////////////////////////////////////////////////
353
354 static bool gdiCanHandleText(const SkPaint& paint) {
355   return !paint.getShader() &&
356          !paint.getPathEffect() &&
357          (SkPaint::kFill_Style == paint.getStyle()) &&
358          (255 == paint.getAlpha());
359 }
360
361 class SkGDIFontSetup {
362  public:
363   SkGDIFontSetup() :
364       fHDC(NULL),
365       fNewFont(NULL),
366       fSavedFont(NULL),
367       fSavedTextColor(0),
368       fUseGDI(false) {
369     SkDEBUGCODE(fUseGDIHasBeenCalled = false;)
370   }
371   ~SkGDIFontSetup();
372
373   // can only be called once
374   bool useGDI(HDC hdc, const SkPaint&);
375
376  private:
377   HDC      fHDC;
378   HFONT    fNewFont;
379   HFONT    fSavedFont;
380   COLORREF fSavedTextColor;
381   bool     fUseGDI;
382   SkDEBUGCODE(bool fUseGDIHasBeenCalled;)
383 };
384
385 bool SkGDIFontSetup::useGDI(HDC hdc, const SkPaint& paint) {
386   SkASSERT(!fUseGDIHasBeenCalled);
387   SkDEBUGCODE(fUseGDIHasBeenCalled = true;)
388
389   fUseGDI = gdiCanHandleText(paint);
390   if (fUseGDI) {
391     fSavedTextColor = GetTextColor(hdc);
392     SetTextColor(hdc, skia::SkColorToCOLORREF(paint.getColor()));
393
394     LOGFONT lf;
395     SkLOGFONTFromTypeface(paint.getTypeface(), &lf);
396     lf.lfHeight = -SkScalarRound(paint.getTextSize());
397     fNewFont = CreateFontIndirect(&lf);
398     fSavedFont = (HFONT)::SelectObject(hdc, fNewFont);
399     fHDC = hdc;
400   }
401   return fUseGDI;
402 }
403
404 SkGDIFontSetup::~SkGDIFontSetup() {
405   if (fUseGDI) {
406     ::SelectObject(fHDC, fSavedFont);
407     ::DeleteObject(fNewFont);
408     SetTextColor(fHDC, fSavedTextColor);
409   }
410 }
411
412 static SkScalar getAscent(const SkPaint& paint) {
413   SkPaint::FontMetrics fm;
414   paint.getFontMetrics(&fm);
415   return fm.fAscent;
416 }
417
418 // return the options int for ExtTextOut. Only valid if the paint's text
419 // encoding is not UTF8 (in which case ExtTextOut can't be used).
420 static UINT getTextOutOptions(const SkPaint& paint) {
421   if (SkPaint::kGlyphID_TextEncoding == paint.getTextEncoding()) {
422     return ETO_GLYPH_INDEX;
423   } else {
424     SkASSERT(SkPaint::kUTF16_TextEncoding == paint.getTextEncoding());
425     return 0;
426   }
427 }
428
429 static SkiaEnsureTypefaceCharactersAccessible
430     g_skia_ensure_typeface_characters_accessible = NULL;
431
432 SK_API void SetSkiaEnsureTypefaceCharactersAccessible(
433     SkiaEnsureTypefaceCharactersAccessible func) {
434   // This function is supposed to be called once in process life time.
435   SkASSERT(g_skia_ensure_typeface_characters_accessible == NULL);
436   g_skia_ensure_typeface_characters_accessible = func;
437 }
438
439 void EnsureTypefaceCharactersAccessible(
440     const SkTypeface& typeface, const wchar_t* text, unsigned int text_length) {
441   LOGFONT lf;
442   SkLOGFONTFromTypeface(&typeface, &lf);
443   g_skia_ensure_typeface_characters_accessible(lf, text, text_length);
444 }
445
446 bool EnsureExtTextOut(HDC hdc, int x, int y, UINT options, const RECT * lprect,
447                       LPCWSTR text, unsigned int characters, const int * lpDx,
448                       SkTypeface* const typeface) {
449   bool success = ExtTextOut(hdc, x, y, options, lprect, text, characters, lpDx);
450   if (!success) {
451     if (typeface) {
452       EnsureTypefaceCharactersAccessible(*typeface,
453                                          text,
454                                          characters);
455       success = ExtTextOut(hdc, x, y, options, lprect, text, characters, lpDx);
456       if (!success) {
457         LOGFONT lf;
458         SkLOGFONTFromTypeface(typeface, &lf);
459         VLOG(1) << "SkFontHost::EnsureTypefaceCharactersAccessible FAILED for "
460                 << " FaceName = " << lf.lfFaceName
461                 << " and characters: " << string16(text, characters);
462       }
463     } else {
464       VLOG(1) << "ExtTextOut FAILED for default FaceName "
465               << " and characters: " << string16(text, characters);
466     }
467   }
468   return success;
469 }
470
471 void VectorPlatformDeviceEmf::drawText(const SkDraw& draw,
472                                        const void* text,
473                                        size_t byteLength,
474                                        SkScalar x,
475                                        SkScalar y,
476                                        const SkPaint& paint) {
477   SkGDIFontSetup setup;
478   bool useDrawPath = true;
479
480   if (SkPaint::kUTF8_TextEncoding != paint.getTextEncoding()
481       && setup.useGDI(hdc_, paint)) {
482     UINT options = getTextOutOptions(paint);
483     UINT count = byteLength >> 1;
484     useDrawPath = !EnsureExtTextOut(hdc_, SkScalarRound(x),
485         SkScalarRound(y + getAscent(paint)), options, 0,
486         reinterpret_cast<const wchar_t*>(text), count, NULL,
487         paint.getTypeface());
488   }
489
490   if (useDrawPath) {
491     SkPath path;
492     paint.getTextPath(text, byteLength, x, y, &path);
493     drawPath(draw, path, paint);
494   }
495 }
496
497 static size_t size_utf8(const char* text) {
498   return SkUTF8_CountUTF8Bytes(text);
499 }
500
501 static size_t size_utf16(const char* text) {
502   uint16_t c = *reinterpret_cast<const uint16_t*>(text);
503   return SkUTF16_IsHighSurrogate(c) ? 4 : 2;
504 }
505
506 static size_t size_glyphid(const char* text) {
507   return 2;
508 }
509
510 void VectorPlatformDeviceEmf::drawPosText(const SkDraw& draw,
511                                           const void* text,
512                                           size_t len,
513                                           const SkScalar pos[],
514                                           SkScalar constY,
515                                           int scalarsPerPos,
516                                           const SkPaint& paint) {
517   SkGDIFontSetup setup;
518   bool useDrawText = true;
519
520   if (2 == scalarsPerPos
521       && SkPaint::kUTF8_TextEncoding != paint.getTextEncoding()
522       && setup.useGDI(hdc_, paint)) {
523     int startX = SkScalarRound(pos[0]);
524     int startY = SkScalarRound(pos[1] + getAscent(paint));
525     const int count = len >> 1;
526     SkAutoSTMalloc<64, INT> storage(count);
527     INT* advances = storage.get();
528     for (int i = 0; i < count - 1; ++i) {
529       advances[i] = SkScalarRound(pos[2] - pos[0]);
530       pos += 2;
531     }
532     useDrawText = !EnsureExtTextOut(hdc_, startX, startY,
533         getTextOutOptions(paint), 0, reinterpret_cast<const wchar_t*>(text),
534         count, advances, paint.getTypeface());
535   }
536
537   if (useDrawText) {
538     size_t (*bytesPerCodePoint)(const char*);
539     switch (paint.getTextEncoding()) {
540     case SkPaint::kUTF8_TextEncoding:
541       bytesPerCodePoint = size_utf8;
542       break;
543     case SkPaint::kUTF16_TextEncoding:
544       bytesPerCodePoint = size_utf16;
545       break;
546     default:
547       SkASSERT(SkPaint::kGlyphID_TextEncoding == paint.getTextEncoding());
548       bytesPerCodePoint = size_glyphid;
549       break;
550     }
551
552     const char* curr = reinterpret_cast<const char*>(text);
553     const char* stop = curr + len;
554     while (curr < stop) {
555       SkScalar y = (1 == scalarsPerPos) ? constY : pos[1];
556       size_t bytes = bytesPerCodePoint(curr);
557       drawText(draw, curr, bytes, pos[0], y, paint);
558       curr += bytes;
559       pos += scalarsPerPos;
560     }
561   }
562 }
563
564 void VectorPlatformDeviceEmf::drawTextOnPath(const SkDraw& draw,
565                                              const void* text,
566                                              size_t len,
567                                              const SkPath& path,
568                                              const SkMatrix* matrix,
569                                              const SkPaint& paint) {
570   // This function isn't used in the code. Verify this assumption.
571   SkASSERT(false);
572 }
573
574 void VectorPlatformDeviceEmf::drawVertices(const SkDraw& draw,
575                                            SkCanvas::VertexMode vmode,
576                                            int vertexCount,
577                                            const SkPoint vertices[],
578                                            const SkPoint texs[],
579                                            const SkColor colors[],
580                                            SkXfermode* xmode,
581                                            const uint16_t indices[],
582                                            int indexCount,
583                                            const SkPaint& paint) {
584   // This function isn't used in the code. Verify this assumption.
585   SkASSERT(false);
586 }
587
588 void VectorPlatformDeviceEmf::drawDevice(const SkDraw& draw,
589                                          SkBaseDevice* device,
590                                          int x,
591                                          int y,
592                                          const SkPaint& paint) {
593   // TODO(maruel):  http://b/1183870 Playback the EMF buffer at printer's dpi if
594   // it is a vectorial device.
595   drawSprite(draw, device->accessBitmap(false), x, y, paint);
596 }
597
598 bool VectorPlatformDeviceEmf::ApplyPaint(const SkPaint& paint) {
599   // Note: The goal here is to transfert the SkPaint's state to the HDC's state.
600   // This function does not execute the SkPaint drawing commands. These should
601   // be executed in drawPaint().
602
603   SkPaint::Style style = paint.getStyle();
604   if (!paint.getAlpha())
605       style = (SkPaint::Style) SkPaint::kStyleCount;
606
607   switch (style) {
608     case SkPaint::kFill_Style:
609       if (!CreateBrush(true, paint) ||
610           !CreatePen(false, paint))
611         return false;
612       break;
613     case SkPaint::kStroke_Style:
614       if (!CreateBrush(false, paint) ||
615           !CreatePen(true, paint))
616         return false;
617       break;
618     case SkPaint::kStrokeAndFill_Style:
619       if (!CreateBrush(true, paint) ||
620           !CreatePen(true, paint))
621         return false;
622       break;
623     default:
624       if (!CreateBrush(false, paint) ||
625           !CreatePen(false, paint))
626         return false;
627       break;
628   }
629
630   /*
631   getFlags();
632     isAntiAlias();
633     isDither()
634     isLinearText()
635     isSubpixelText()
636     isUnderlineText()
637     isStrikeThruText()
638     isFakeBoldText()
639     isDevKernText()
640     isFilterBitmap()
641
642   // Skia's text is not used. This should be fixed.
643   getTextAlign()
644   getTextScaleX()
645   getTextSkewX()
646   getTextEncoding()
647   getFontMetrics()
648   getFontSpacing()
649   */
650
651   // BUG 1094907: Implement shaders. Shaders currently in use:
652   //  SkShader::CreateBitmapShader
653   //  SkGradientShader::CreateRadial
654   //  SkGradientShader::CreateLinear
655   // SkASSERT(!paint.getShader());
656
657   // http://b/1106647 Implement loopers and mask filter. Looper currently in
658   // use:
659   //   SkBlurDrawLooper is used for shadows.
660   // SkASSERT(!paint.getLooper());
661   // SkASSERT(!paint.getMaskFilter());
662
663   // http://b/1165900 Implement xfermode.
664   // SkASSERT(!paint.getXfermode());
665
666   // The path effect should be processed before arriving here.
667   SkASSERT(!paint.getPathEffect());
668
669   // This isn't used in the code. Verify this assumption.
670   SkASSERT(!paint.getRasterizer());
671   // Reuse code to load Win32 Fonts.
672   return true;
673 }
674
675 void VectorPlatformDeviceEmf::setMatrixClip(const SkMatrix& transform,
676                                             const SkRegion& region,
677                                             const SkClipStack&) {
678   transform_ = transform;
679   LoadTransformToDC(hdc_, transform_);
680   clip_region_ = region;
681   if (!clip_region_.isEmpty())
682     LoadClipRegion();
683 }
684
685 void VectorPlatformDeviceEmf::DrawToNativeContext(HDC dc, int x, int y,
686                                                   const RECT* src_rect) {
687   SkASSERT(false);
688 }
689
690 void VectorPlatformDeviceEmf::LoadClipRegion() {
691   SkMatrix t;
692   t.reset();
693   LoadClippingRegionToDC(hdc_, clip_region_, t);
694 }
695
696 SkBaseDevice* VectorPlatformDeviceEmf::onCreateCompatibleDevice(
697     SkBitmap::Config config, int width, int height, bool isOpaque,
698     Usage /*usage*/) {
699   SkASSERT(config == SkBitmap::kARGB_8888_Config);
700   return VectorPlatformDeviceEmf::CreateDevice(width, height, isOpaque, NULL);
701 }
702
703 bool VectorPlatformDeviceEmf::CreateBrush(bool use_brush, COLORREF color) {
704   SkASSERT(previous_brush_ == NULL);
705   // We can't use SetDCBrushColor() or DC_BRUSH when drawing to a EMF buffer.
706   // SetDCBrushColor() calls are not recorded at all and DC_BRUSH will use
707   // WHITE_BRUSH instead.
708
709   if (!use_brush) {
710     // Set the transparency.
711     if (0 == SetBkMode(hdc_, TRANSPARENT)) {
712       SkASSERT(false);
713       return false;
714     }
715
716     // Select the NULL brush.
717     previous_brush_ = SelectObject(GetStockObject(NULL_BRUSH));
718     return previous_brush_ != NULL;
719   }
720
721   // Set the opacity.
722   if (0 == SetBkMode(hdc_, OPAQUE)) {
723     SkASSERT(false);
724     return false;
725   }
726
727   // Create and select the brush.
728   previous_brush_ = SelectObject(CreateSolidBrush(color));
729   return previous_brush_ != NULL;
730 }
731
732 bool VectorPlatformDeviceEmf::CreatePen(bool use_pen,
733                                         COLORREF color,
734                                         int stroke_width,
735                                         float stroke_miter,
736                                         DWORD pen_style) {
737   SkASSERT(previous_pen_ == NULL);
738   // We can't use SetDCPenColor() or DC_PEN when drawing to a EMF buffer.
739   // SetDCPenColor() calls are not recorded at all and DC_PEN will use BLACK_PEN
740   // instead.
741
742   // No pen case
743   if (!use_pen) {
744     previous_pen_ = SelectObject(GetStockObject(NULL_PEN));
745     return previous_pen_ != NULL;
746   }
747
748   // Use the stock pen if the stroke width is 0.
749   if (stroke_width == 0) {
750     // Create a pen with the right color.
751     previous_pen_ = SelectObject(::CreatePen(PS_SOLID, 0, color));
752     return previous_pen_ != NULL;
753   }
754
755   // Load a custom pen.
756   LOGBRUSH brush;
757   brush.lbStyle = BS_SOLID;
758   brush.lbColor = color;
759   brush.lbHatch = 0;
760   HPEN pen = ExtCreatePen(pen_style, stroke_width, &brush, 0, NULL);
761   SkASSERT(pen != NULL);
762   previous_pen_ = SelectObject(pen);
763   if (previous_pen_ == NULL)
764     return false;
765
766   if (!SetMiterLimit(hdc_, stroke_miter, NULL)) {
767     SkASSERT(false);
768     return false;
769   }
770   return true;
771 }
772
773 void VectorPlatformDeviceEmf::Cleanup() {
774   if (previous_brush_) {
775     HGDIOBJ result = SelectObject(previous_brush_);
776     previous_brush_ = NULL;
777     if (result) {
778       BOOL res = DeleteObject(result);
779       SkASSERT(res != 0);
780     }
781   }
782   if (previous_pen_) {
783     HGDIOBJ result = SelectObject(previous_pen_);
784     previous_pen_ = NULL;
785     if (result) {
786       BOOL res = DeleteObject(result);
787       SkASSERT(res != 0);
788     }
789   }
790   // Remove any loaded path from the context.
791   AbortPath(hdc_);
792 }
793
794 HGDIOBJ VectorPlatformDeviceEmf::SelectObject(HGDIOBJ object) {
795   HGDIOBJ result = ::SelectObject(hdc_, object);
796   SkASSERT(result != HGDI_ERROR);
797   if (result == HGDI_ERROR)
798     return NULL;
799   return result;
800 }
801
802 bool VectorPlatformDeviceEmf::CreateBrush(bool use_brush,
803                                           const SkPaint& paint) {
804   // Make sure that for transparent color, no brush is used.
805   if (paint.getAlpha() == 0) {
806     use_brush = false;
807   }
808
809   return CreateBrush(use_brush, SkColorToCOLORREF(paint.getColor()));
810 }
811
812 bool VectorPlatformDeviceEmf::CreatePen(bool use_pen, const SkPaint& paint) {
813   // Make sure that for transparent color, no pen is used.
814   if (paint.getAlpha() == 0) {
815     use_pen = false;
816   }
817
818   DWORD pen_style = PS_GEOMETRIC | PS_SOLID;
819   switch (paint.getStrokeJoin()) {
820     case SkPaint::kMiter_Join:
821       // Connects path segments with a sharp join.
822       pen_style |= PS_JOIN_MITER;
823       break;
824     case SkPaint::kRound_Join:
825       // Connects path segments with a round join.
826       pen_style |= PS_JOIN_ROUND;
827       break;
828     case SkPaint::kBevel_Join:
829       // Connects path segments with a flat bevel join.
830       pen_style |= PS_JOIN_BEVEL;
831       break;
832     default:
833       SkASSERT(false);
834       break;
835   }
836   switch (paint.getStrokeCap()) {
837     case SkPaint::kButt_Cap:
838       // Begin/end contours with no extension.
839       pen_style |= PS_ENDCAP_FLAT;
840       break;
841     case SkPaint::kRound_Cap:
842       // Begin/end contours with a semi-circle extension.
843       pen_style |= PS_ENDCAP_ROUND;
844       break;
845     case SkPaint::kSquare_Cap:
846       // Begin/end contours with a half square extension.
847       pen_style |= PS_ENDCAP_SQUARE;
848       break;
849     default:
850       SkASSERT(false);
851       break;
852   }
853
854   return CreatePen(use_pen,
855                    SkColorToCOLORREF(paint.getColor()),
856                    SkScalarRound(paint.getStrokeWidth()),
857                    paint.getStrokeMiter(),
858                    pen_style);
859 }
860
861 void VectorPlatformDeviceEmf::InternalDrawBitmap(const SkBitmap& bitmap,
862                                                  int x, int y,
863                                                  const SkPaint& paint) {
864   unsigned char alpha = paint.getAlpha();
865   if (alpha == 0)
866     return;
867
868   bool is_translucent;
869   if (alpha != 255) {
870     // ApplyPaint expect an opaque color.
871     SkPaint tmp_paint(paint);
872     tmp_paint.setAlpha(255);
873     if (!ApplyPaint(tmp_paint))
874       return;
875     is_translucent = true;
876   } else {
877     if (!ApplyPaint(paint))
878       return;
879     is_translucent = false;
880   }
881   int src_size_x = bitmap.width();
882   int src_size_y = bitmap.height();
883   if (!src_size_x || !src_size_y)
884     return;
885
886   // Create a BMP v4 header that we can serialize. We use the shared "V3"
887   // fillter to fill the stardard items, then add in the "V4" stuff we want.
888   BITMAPV4HEADER bitmap_header;
889   memset(&bitmap_header, 0, sizeof(BITMAPV4HEADER));
890   FillBitmapInfoHeader(src_size_x, src_size_y,
891                        reinterpret_cast<BITMAPINFOHEADER*>(&bitmap_header));
892   bitmap_header.bV4Size = sizeof(BITMAPV4HEADER);
893   bitmap_header.bV4RedMask   = 0x00ff0000;
894   bitmap_header.bV4GreenMask = 0x0000ff00;
895   bitmap_header.bV4BlueMask  = 0x000000ff;
896   bitmap_header.bV4AlphaMask = 0xff000000;
897
898   SkAutoLockPixels lock(bitmap);
899   SkASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config);
900   const uint32_t* pixels = static_cast<const uint32_t*>(bitmap.getPixels());
901   if (pixels == NULL) {
902     SkASSERT(false);
903     return;
904   }
905
906   if (!is_translucent) {
907     int row_length = bitmap.rowBytesAsPixels();
908     // There is no quick way to determine if an image is opaque.
909     for (int y2 = 0; y2 < src_size_y; ++y2) {
910       for (int x2 = 0; x2 < src_size_x; ++x2) {
911         if (SkColorGetA(pixels[(y2 * row_length) + x2]) != 255) {
912           is_translucent = true;
913           y2 = src_size_y;
914           break;
915         }
916       }
917     }
918   }
919
920   HDC dc = BeginPlatformPaint();
921   BITMAPINFOHEADER hdr;
922   FillBitmapInfoHeader(src_size_x, src_size_y, &hdr);
923   if (is_translucent) {
924     // The image must be loaded as a bitmap inside a device context.
925     HDC bitmap_dc = ::CreateCompatibleDC(dc);
926     void* bits = NULL;
927     HBITMAP hbitmap = ::CreateDIBSection(
928         bitmap_dc, reinterpret_cast<const BITMAPINFO*>(&hdr),
929         DIB_RGB_COLORS, &bits, NULL, 0);
930
931     // static cast to a char so we can do byte ptr arithmatic to
932     // get the offset.
933     unsigned char* dest_buffer = static_cast<unsigned char *>(bits);
934
935     // We will copy row by row to avoid having to worry about
936     // the row strides being different.
937     const int dest_row_size = hdr.biBitCount / 8 * hdr.biWidth;
938     for (int row = 0; row < bitmap.height(); ++row) {
939       int dest_offset = row * dest_row_size;
940       // pixels_offset in terms of pixel count.
941       int src_offset = row * bitmap.rowBytesAsPixels();
942       memcpy(dest_buffer + dest_offset, pixels + src_offset, dest_row_size);
943     }
944     SkASSERT(hbitmap);
945     HGDIOBJ old_bitmap = ::SelectObject(bitmap_dc, hbitmap);
946
947     // After some analysis of IE7's behavior, this is the thing to do. I was
948     // sure IE7 was doing so kind of bitmasking due to the way translucent image
949     // where renderered but after some windbg tracing, it is being done by the
950     // printer driver after all (mostly HP printers). IE7 always use AlphaBlend
951     // for bitmasked images. The trick seems to switch the stretching mode in
952     // what the driver expects.
953     DWORD previous_mode = GetStretchBltMode(dc);
954     BOOL result = SetStretchBltMode(dc, COLORONCOLOR);
955     SkASSERT(result);
956     // Note that this function expect premultiplied colors (!)
957     BLENDFUNCTION blend_function = {AC_SRC_OVER, 0, alpha, AC_SRC_ALPHA};
958     result = GdiAlphaBlend(dc,
959                            x, y,  // Destination origin.
960                            src_size_x, src_size_y,  // Destination size.
961                            bitmap_dc,
962                            0, 0,  // Source origin.
963                            src_size_x, src_size_y,  // Source size.
964                            blend_function);
965     SkASSERT(result);
966     result = SetStretchBltMode(dc, previous_mode);
967     SkASSERT(result);
968
969     ::SelectObject(bitmap_dc, static_cast<HBITMAP>(old_bitmap));
970     DeleteObject(hbitmap);
971     DeleteDC(bitmap_dc);
972   } else {
973     int nCopied = StretchDIBits(dc,
974                                 x, y,  // Destination origin.
975                                 src_size_x, src_size_y,
976                                 0, 0,  // Source origin.
977                                 src_size_x, src_size_y,  // Source size.
978                                 pixels,
979                                 reinterpret_cast<const BITMAPINFO*>(&hdr),
980                                 DIB_RGB_COLORS,
981                                 SRCCOPY);
982   }
983   EndPlatformPaint();
984   Cleanup();
985 }
986
987 }  // namespace skia