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