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