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