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