Home | History | Annotate | Download | only in xps
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #ifndef UNICODE
      9 #define UNICODE
     10 #endif
     11 #ifndef _UNICODE
     12 #define _UNICODE
     13 #endif
     14 #include "SkTypes.h"
     15 #include <ObjBase.h>
     16 #include <XpsObjectModel.h>
     17 #include <T2EmbApi.h>
     18 #include <FontSub.h>
     19 
     20 #include "SkColor.h"
     21 #include "SkConstexprMath.h"
     22 #include "SkData.h"
     23 #include "SkDraw.h"
     24 #include "SkDrawProcs.h"
     25 #include "SkFontHost.h"
     26 #include "SkGlyphCache.h"
     27 #include "SkHRESULT.h"
     28 #include "SkImageEncoder.h"
     29 #include "SkIStream.h"
     30 #include "SkMaskFilter.h"
     31 #include "SkPaint.h"
     32 #include "SkPoint.h"
     33 #include "SkRasterizer.h"
     34 #include "SkShader.h"
     35 #include "SkSize.h"
     36 #include "SkStream.h"
     37 #include "SkTDArray.h"
     38 #include "SkTLazy.h"
     39 #include "SkTScopedComPtr.h"
     40 #include "SkUtils.h"
     41 #include "SkXPSDevice.h"
     42 
     43 //Windows defines a FLOAT type,
     44 //make it clear when converting a scalar that this is what is wanted.
     45 #define SkScalarToFLOAT(n) SkScalarToFloat(n)
     46 
     47 //Dummy representation of a GUID from create_id.
     48 #define L_GUID_ID L"XXXXXXXXsXXXXsXXXXsXXXXsXXXXXXXXXXXX"
     49 //Length of GUID representation from create_id, including NULL terminator.
     50 #define GUID_ID_LEN SK_ARRAY_COUNT(L_GUID_ID)
     51 
     52 /**
     53    Formats a GUID and places it into buffer.
     54    buffer should have space for at least GUID_ID_LEN wide characters.
     55    The string will always be wchar null terminated.
     56    XXXXXXXXsXXXXsXXXXsXXXXsXXXXXXXXXXXX0
     57    @return -1 if there was an error, > 0 if success.
     58  */
     59 static int format_guid(const GUID& guid,
     60                        wchar_t* buffer, size_t bufferSize,
     61                        wchar_t sep = '-') {
     62     SkASSERT(bufferSize >= GUID_ID_LEN);
     63     return swprintf_s(buffer,
     64                       bufferSize,
     65                       L"%08lX%c%04X%c%04X%c%02X%02X%c%02X%02X%02X%02X%02X%02X",
     66                       guid.Data1,
     67                       sep,
     68                       guid.Data2,
     69                       sep,
     70                       guid.Data3,
     71                       sep,
     72                       guid.Data4[0],
     73                       guid.Data4[1],
     74                       sep,
     75                       guid.Data4[2],
     76                       guid.Data4[3],
     77                       guid.Data4[4],
     78                       guid.Data4[5],
     79                       guid.Data4[6],
     80                       guid.Data4[7]);
     81 }
     82 /**
     83    Creates a GUID based id and places it into buffer.
     84    buffer should have space for at least GUID_ID_LEN wide characters.
     85    The string will always be wchar null terminated.
     86    XXXXXXXXsXXXXsXXXXsXXXXsXXXXXXXXXXXX0
     87    The string may begin with a digit,
     88    and so may not be suitable as a bare resource key.
     89  */
     90 static HRESULT create_id(wchar_t* buffer, size_t bufferSize,
     91                          wchar_t sep = '-') {
     92     GUID guid = {};
     93     HRM(CoCreateGuid(&guid), "Could not create GUID for id.");
     94 
     95     if (format_guid(guid, buffer, bufferSize, sep) == -1) {
     96         HRM(E_UNEXPECTED, "Could not format GUID into id.");
     97     }
     98 
     99     return S_OK;
    100 }
    101 
    102 static SkBitmap make_fake_bitmap(int width, int height) {
    103     SkBitmap bitmap;
    104     bitmap.setConfig(SkBitmap::kNo_Config, width, height);
    105     return bitmap;
    106 }
    107 
    108 SkXPSDevice::SkXPSDevice()
    109     : SkDevice(make_fake_bitmap(10000, 10000))
    110     , fCurrentPage(0) {
    111 }
    112 
    113 SkXPSDevice::~SkXPSDevice() {
    114 }
    115 
    116 SkXPSDevice::TypefaceUse::TypefaceUse()
    117     : typefaceId(0xffffffff)
    118     , fontData(NULL)
    119     , xpsFont(NULL)
    120     , glyphsUsed(NULL) {
    121 }
    122 
    123 SkXPSDevice::TypefaceUse::~TypefaceUse() {
    124     //xpsFont owns fontData ref
    125     this->xpsFont->Release();
    126     delete this->glyphsUsed;
    127 }
    128 
    129 bool SkXPSDevice::beginPortfolio(SkWStream* outputStream) {
    130     if (!this->fAutoCo.succeeded()) return false;
    131 
    132     //Create XPS Factory.
    133     HRBM(CoCreateInstance(
    134              CLSID_XpsOMObjectFactory,
    135              NULL,
    136              CLSCTX_INPROC_SERVER,
    137              IID_PPV_ARGS(&this->fXpsFactory)),
    138          "Could not create XPS factory.");
    139 
    140     HRBM(SkWIStream::CreateFromSkWStream(outputStream, &this->fOutputStream),
    141          "Could not convert SkStream to IStream.");
    142 
    143     return true;
    144 }
    145 
    146 bool SkXPSDevice::beginSheet(
    147         const SkVector& unitsPerMeter,
    148         const SkVector& pixelsPerMeter,
    149         const SkSize& trimSize,
    150         const SkRect* mediaBox,
    151         const SkRect* bleedBox,
    152         const SkRect* artBox,
    153         const SkRect* cropBox) {
    154     ++this->fCurrentPage;
    155 
    156     //For simplicity, just write everything out in geometry units,
    157     //then have a base canvas do the scale to physical units.
    158     this->fCurrentCanvasSize = trimSize;
    159     this->fCurrentUnitsPerMeter = unitsPerMeter;
    160     this->fCurrentPixelsPerMeter = pixelsPerMeter;
    161 
    162     this->fCurrentXpsCanvas.reset();
    163     HRBM(this->fXpsFactory->CreateCanvas(&this->fCurrentXpsCanvas),
    164          "Could not create base canvas.");
    165 
    166     return true;
    167 }
    168 
    169 HRESULT SkXPSDevice::createXpsThumbnail(IXpsOMPage* page,
    170                                         const unsigned int pageNum,
    171                                         IXpsOMImageResource** image) {
    172     SkTScopedComPtr<IXpsOMThumbnailGenerator> thumbnailGenerator;
    173     HRM(CoCreateInstance(
    174             CLSID_XpsOMThumbnailGenerator,
    175             NULL,
    176             CLSCTX_INPROC_SERVER,
    177             IID_PPV_ARGS(&thumbnailGenerator)),
    178         "Could not create thumbnail generator.");
    179 
    180     SkTScopedComPtr<IOpcPartUri> partUri;
    181     static const size_t size = SK_MAX(
    182         SK_ARRAY_COUNT(L"/Documents/1/Metadata/.png") + SK_DIGITS_IN(pageNum),
    183         SK_ARRAY_COUNT(L"/Metadata/" L_GUID_ID L".png")
    184     );
    185     wchar_t buffer[size];
    186     if (pageNum > 0) {
    187         swprintf_s(buffer, size, L"/Documents/1/Metadata/%u.png", pageNum);
    188     } else {
    189         wchar_t id[GUID_ID_LEN];
    190         HR(create_id(id, GUID_ID_LEN));
    191         swprintf_s(buffer, size, L"/Metadata/%s.png", id);
    192     }
    193     HRM(this->fXpsFactory->CreatePartUri(buffer, &partUri),
    194         "Could not create thumbnail part uri.");
    195 
    196     HRM(thumbnailGenerator->GenerateThumbnail(page,
    197                                               XPS_IMAGE_TYPE_PNG,
    198                                               XPS_THUMBNAIL_SIZE_LARGE,
    199                                               partUri.get(),
    200                                               image),
    201         "Could not generate thumbnail.");
    202 
    203     return S_OK;
    204 }
    205 
    206 HRESULT SkXPSDevice::createXpsPage(const XPS_SIZE& pageSize,
    207                                    IXpsOMPage** page) {
    208     static const size_t size = SK_ARRAY_COUNT(L"/Documents/1/Pages/.fpage")
    209                              + SK_DIGITS_IN(fCurrentPage);
    210     wchar_t buffer[size];
    211     swprintf_s(buffer, size, L"/Documents/1/Pages/%u.fpage",
    212                              this->fCurrentPage);
    213     SkTScopedComPtr<IOpcPartUri> partUri;
    214     HRM(this->fXpsFactory->CreatePartUri(buffer, &partUri),
    215         "Could not create page part uri.");
    216 
    217     //If the language is unknown, use "und" (XPS Spec 2.3.5.1).
    218     HRM(this->fXpsFactory->CreatePage(&pageSize,
    219                                       L"und",
    220                                       partUri.get(),
    221                                       page),
    222         "Could not create page.");
    223 
    224     return S_OK;
    225 }
    226 
    227 HRESULT SkXPSDevice::initXpsDocumentWriter(IXpsOMImageResource* image) {
    228     //Create package writer.
    229     {
    230         SkTScopedComPtr<IOpcPartUri> partUri;
    231         HRM(this->fXpsFactory->CreatePartUri(L"/FixedDocumentSequence.fdseq",
    232                                              &partUri),
    233             "Could not create document sequence part uri.");
    234         HRM(this->fXpsFactory->CreatePackageWriterOnStream(
    235                 this->fOutputStream.get(),
    236                 TRUE,
    237                 XPS_INTERLEAVING_OFF, //XPS_INTERLEAVING_ON,
    238                 partUri.get(),
    239                 NULL,
    240                 image,
    241                 NULL,
    242                 NULL,
    243                 &this->fPackageWriter),
    244             "Could not create package writer.");
    245     }
    246 
    247     //Begin the lone document.
    248     {
    249         SkTScopedComPtr<IOpcPartUri> partUri;
    250         HRM(this->fXpsFactory->CreatePartUri(
    251                 L"/Documents/1/FixedDocument.fdoc",
    252                 &partUri),
    253             "Could not create fixed document part uri.");
    254         HRM(this->fPackageWriter->StartNewDocument(partUri.get(),
    255                                                    NULL,
    256                                                    NULL,
    257                                                    NULL,
    258                                                    NULL),
    259             "Could not start document.");
    260     }
    261 
    262     return S_OK;
    263 }
    264 
    265 bool SkXPSDevice::endSheet() {
    266     //XPS is fixed at 96dpi (XPS Spec 11.1).
    267     static const float xpsDPI = 96.0f;
    268     static const float inchesPerMeter = 10000.0f / 254.0f;
    269     static const float targetUnitsPerMeter = xpsDPI * inchesPerMeter;
    270     const float scaleX = targetUnitsPerMeter
    271                        / SkScalarToFLOAT(this->fCurrentUnitsPerMeter.fX);
    272     const float scaleY = targetUnitsPerMeter
    273                        / SkScalarToFLOAT(this->fCurrentUnitsPerMeter.fY);
    274 
    275     //Create the scale canvas.
    276     SkTScopedComPtr<IXpsOMCanvas> scaleCanvas;
    277     HRBM(this->fXpsFactory->CreateCanvas(&scaleCanvas),
    278          "Could not create scale canvas.");
    279     SkTScopedComPtr<IXpsOMVisualCollection> scaleCanvasVisuals;
    280     HRBM(scaleCanvas->GetVisuals(&scaleCanvasVisuals),
    281          "Could not get scale canvas visuals.");
    282 
    283     SkTScopedComPtr<IXpsOMMatrixTransform> geomToPhys;
    284     XPS_MATRIX rawGeomToPhys = { scaleX, 0, 0, scaleY, 0, 0, };
    285     HRBM(this->fXpsFactory->CreateMatrixTransform(&rawGeomToPhys, &geomToPhys),
    286          "Could not create geometry to physical transform.");
    287     HRBM(scaleCanvas->SetTransformLocal(geomToPhys.get()),
    288          "Could not set transform on scale canvas.");
    289 
    290     //Add the content canvas to the scale canvas.
    291     HRBM(scaleCanvasVisuals->Append(this->fCurrentXpsCanvas.get()),
    292          "Could not add base canvas to scale canvas.");
    293 
    294     //Create the page.
    295     XPS_SIZE pageSize = {
    296         SkScalarToFLOAT(this->fCurrentCanvasSize.width()) * scaleX,
    297         SkScalarToFLOAT(this->fCurrentCanvasSize.height()) * scaleY,
    298     };
    299     SkTScopedComPtr<IXpsOMPage> page;
    300     HRB(this->createXpsPage(pageSize, &page));
    301 
    302     SkTScopedComPtr<IXpsOMVisualCollection> pageVisuals;
    303     HRBM(page->GetVisuals(&pageVisuals), "Could not get page visuals.");
    304 
    305     //Add the scale canvas to the page.
    306     HRBM(pageVisuals->Append(scaleCanvas.get()),
    307          "Could not add scale canvas to page.");
    308 
    309     //Create the package writer if it hasn't been created yet.
    310     if (NULL == this->fPackageWriter.get()) {
    311         SkTScopedComPtr<IXpsOMImageResource> image;
    312         //Ignore return, thumbnail is completely optional.
    313         this->createXpsThumbnail(page.get(), 0, &image);
    314 
    315         HRB(this->initXpsDocumentWriter(image.get()));
    316     }
    317 
    318     HRBM(this->fPackageWriter->AddPage(page.get(),
    319                                        &pageSize,
    320                                        NULL,
    321                                        NULL,
    322                                        NULL,
    323                                        NULL),
    324          "Could not write the page.");
    325     this->fCurrentXpsCanvas.reset();
    326 
    327     return true;
    328 }
    329 
    330 static HRESULT subset_typeface(SkXPSDevice::TypefaceUse* current) {
    331     //CreateFontPackage wants unsigned short.
    332     //Microsoft, Y U NO stdint.h?
    333     SkTDArray<unsigned short> keepList;
    334     current->glyphsUsed->exportTo(&keepList);
    335 
    336     //The following are declared with the types required by CreateFontPackage.
    337     unsigned char *puchFontPackageBuffer;
    338     unsigned long pulFontPackageBufferSize;
    339     unsigned long pulBytesWritten;
    340     unsigned long result = CreateFontPackage(
    341         (unsigned char *) current->fontData->getMemoryBase(),
    342         (unsigned long) current->fontData->getLength(),
    343         &puchFontPackageBuffer,
    344         &pulFontPackageBufferSize,
    345         &pulBytesWritten,
    346         TTFCFP_FLAGS_SUBSET | TTFCFP_FLAGS_GLYPHLIST,// | TTFCFP_FLAGS_TTC,
    347         0,//TTC index
    348         TTFCFP_SUBSET,
    349         0,
    350         0,
    351         0,
    352         keepList.begin(),
    353         keepList.count(),
    354         sk_malloc_throw,
    355         sk_realloc_throw,
    356         sk_free,
    357         NULL);
    358     if (result != NO_ERROR) {
    359         SkDEBUGF(("CreateFontPackage Error %lu", result));
    360         return E_UNEXPECTED;
    361     }
    362 
    363     SkMemoryStream* newStream = new SkMemoryStream;
    364     newStream->setMemoryOwned(puchFontPackageBuffer, pulBytesWritten);
    365     SkTScopedComPtr<IStream> newIStream;
    366     SkIStream::CreateFromSkStream(newStream, true, &newIStream);
    367 
    368     XPS_FONT_EMBEDDING embedding;
    369     HRM(current->xpsFont->GetEmbeddingOption(&embedding),
    370         "Could not get embedding option from font.");
    371 
    372     SkTScopedComPtr<IOpcPartUri> partUri;
    373     HRM(current->xpsFont->GetPartName(&partUri),
    374         "Could not get part uri from font.");
    375 
    376     HRM(current->xpsFont->SetContent(
    377             newIStream.get(),
    378             embedding,
    379             partUri.get()),
    380         "Could not set new stream for subsetted font.");
    381 
    382     return S_OK;
    383 }
    384 
    385 bool SkXPSDevice::endPortfolio() {
    386     //Subset fonts
    387     if (!this->fTypefaces.empty()) {
    388         SkXPSDevice::TypefaceUse* current = &this->fTypefaces.front();
    389         const TypefaceUse* last = &this->fTypefaces.back();
    390         for (; current <= last; ++current) {
    391             //Ignore return for now, if it didn't subset, let it be.
    392             subset_typeface(current);
    393         }
    394     }
    395 
    396     HRBM(this->fPackageWriter->Close(), "Could not close writer.");
    397 
    398     return true;
    399 }
    400 
    401 static XPS_COLOR xps_color(const SkColor skColor) {
    402     //XPS uses non-pre-multiplied alpha (XPS Spec 11.4).
    403     XPS_COLOR xpsColor;
    404     xpsColor.colorType = XPS_COLOR_TYPE_SRGB;
    405     xpsColor.value.sRGB.alpha = SkColorGetA(skColor);
    406     xpsColor.value.sRGB.red = SkColorGetR(skColor);
    407     xpsColor.value.sRGB.green = SkColorGetG(skColor);
    408     xpsColor.value.sRGB.blue = SkColorGetB(skColor);
    409 
    410     return xpsColor;
    411 }
    412 
    413 static XPS_POINT xps_point(const SkPoint& point) {
    414     XPS_POINT xpsPoint = {
    415         SkScalarToFLOAT(point.fX),
    416         SkScalarToFLOAT(point.fY),
    417     };
    418     return xpsPoint;
    419 }
    420 
    421 static XPS_POINT xps_point(const SkPoint& point, const SkMatrix& matrix) {
    422     SkPoint skTransformedPoint;
    423     matrix.mapXY(point.fX, point.fY, &skTransformedPoint);
    424     return xps_point(skTransformedPoint);
    425 }
    426 
    427 static XPS_SPREAD_METHOD xps_spread_method(SkShader::TileMode tileMode) {
    428     switch (tileMode) {
    429     case SkShader::kClamp_TileMode:
    430         return XPS_SPREAD_METHOD_PAD;
    431     case SkShader::kRepeat_TileMode:
    432         return XPS_SPREAD_METHOD_REPEAT;
    433     case SkShader::kMirror_TileMode:
    434         return XPS_SPREAD_METHOD_REFLECT;
    435     default:
    436         SkASSERT(!"Unknown tile mode.");
    437     }
    438     return XPS_SPREAD_METHOD_PAD;
    439 }
    440 
    441 static void transform_offsets(SkScalar* stopOffsets, const int numOffsets,
    442                               const SkPoint& start, const SkPoint& end,
    443                               const SkMatrix& transform) {
    444     SkPoint startTransformed;
    445     transform.mapXY(start.fX, start.fY, &startTransformed);
    446     SkPoint endTransformed;
    447     transform.mapXY(end.fX, end.fY, &endTransformed);
    448 
    449     //Manhattan distance between transformed start and end.
    450     SkScalar startToEnd = (endTransformed.fX - startTransformed.fX)
    451                         + (endTransformed.fY - startTransformed.fY);
    452     if (SkScalarNearlyZero(startToEnd)) {
    453         for (int i = 0; i < numOffsets; ++i) {
    454             stopOffsets[i] = 0;
    455         }
    456         return;
    457     }
    458 
    459     for (int i = 0; i < numOffsets; ++i) {
    460         SkPoint stop;
    461         stop.fX = SkScalarMul(end.fX - start.fX, stopOffsets[i]);
    462         stop.fY = SkScalarMul(end.fY - start.fY, stopOffsets[i]);
    463 
    464         SkPoint stopTransformed;
    465         transform.mapXY(stop.fX, stop.fY, &stopTransformed);
    466 
    467         //Manhattan distance between transformed start and stop.
    468         SkScalar startToStop = (stopTransformed.fX - startTransformed.fX)
    469                              + (stopTransformed.fY - startTransformed.fY);
    470         //Percentage along transformed line.
    471         stopOffsets[i] = SkScalarDiv(startToStop, startToEnd);
    472     }
    473 }
    474 
    475 HRESULT SkXPSDevice::createXpsTransform(const SkMatrix& matrix,
    476                                         IXpsOMMatrixTransform** xpsTransform) {
    477     SkScalar affine[6];
    478     if (!matrix.asAffine(affine)) {
    479         *xpsTransform = NULL;
    480         return S_FALSE;
    481     }
    482     XPS_MATRIX rawXpsMatrix = {
    483         SkScalarToFLOAT(affine[SkMatrix::kAScaleX]),
    484         SkScalarToFLOAT(affine[SkMatrix::kASkewY]),
    485         SkScalarToFLOAT(affine[SkMatrix::kASkewX]),
    486         SkScalarToFLOAT(affine[SkMatrix::kAScaleY]),
    487         SkScalarToFLOAT(affine[SkMatrix::kATransX]),
    488         SkScalarToFLOAT(affine[SkMatrix::kATransY]),
    489     };
    490     HRM(this->fXpsFactory->CreateMatrixTransform(&rawXpsMatrix, xpsTransform),
    491         "Could not create transform.");
    492 
    493     return S_OK;
    494 }
    495 
    496 HRESULT SkXPSDevice::createPath(IXpsOMGeometryFigure* figure,
    497                                 IXpsOMVisualCollection* visuals,
    498                                 IXpsOMPath** path) {
    499     SkTScopedComPtr<IXpsOMGeometry> geometry;
    500     HRM(this->fXpsFactory->CreateGeometry(&geometry),
    501         "Could not create geometry.");
    502 
    503     SkTScopedComPtr<IXpsOMGeometryFigureCollection> figureCollection;
    504     HRM(geometry->GetFigures(&figureCollection), "Could not get figures.");
    505     HRM(figureCollection->Append(figure), "Could not add figure.");
    506 
    507     HRM(this->fXpsFactory->CreatePath(path), "Could not create path.");
    508     HRM((*path)->SetGeometryLocal(geometry.get()), "Could not set geometry");
    509 
    510     HRM(visuals->Append(*path), "Could not add path to visuals.");
    511     return S_OK;
    512 }
    513 
    514 HRESULT SkXPSDevice::createXpsSolidColorBrush(const SkColor skColor,
    515                                               const SkAlpha alpha,
    516                                               IXpsOMBrush** xpsBrush) {
    517     XPS_COLOR xpsColor = xps_color(skColor);
    518     SkTScopedComPtr<IXpsOMSolidColorBrush> solidBrush;
    519     HRM(this->fXpsFactory->CreateSolidColorBrush(&xpsColor, NULL, &solidBrush),
    520         "Could not create solid color brush.");
    521     HRM(solidBrush->SetOpacity(alpha / 255.0f), "Could not set opacity.");
    522     HRM(solidBrush->QueryInterface<IXpsOMBrush>(xpsBrush), "QI Fail.");
    523     return S_OK;
    524 }
    525 
    526 HRESULT SkXPSDevice::sideOfClamp(const SkRect& areaToFill,
    527                                  const XPS_RECT& imageViewBox,
    528                                  IXpsOMImageResource* image,
    529                                  IXpsOMVisualCollection* visuals) {
    530     SkTScopedComPtr<IXpsOMGeometryFigure> areaToFillFigure;
    531     HR(this->createXpsRect(areaToFill, FALSE, TRUE, &areaToFillFigure));
    532 
    533     SkTScopedComPtr<IXpsOMPath> areaToFillPath;
    534     HR(this->createPath(areaToFillFigure.get(), visuals, &areaToFillPath));
    535 
    536     SkTScopedComPtr<IXpsOMImageBrush> areaToFillBrush;
    537     HRM(this->fXpsFactory->CreateImageBrush(image,
    538                                             &imageViewBox,
    539                                             &imageViewBox,
    540                                             &areaToFillBrush),
    541         "Could not create brush for side of clamp.");
    542     HRM(areaToFillBrush->SetTileMode(XPS_TILE_MODE_FLIPXY),
    543         "Could not set tile mode for side of clamp.");
    544     HRM(areaToFillPath->SetFillBrushLocal(areaToFillBrush.get()),
    545         "Could not set brush for side of clamp");
    546 
    547     return S_OK;
    548 }
    549 
    550 HRESULT SkXPSDevice::cornerOfClamp(const SkRect& areaToFill,
    551                                    const SkColor color,
    552                                    IXpsOMVisualCollection* visuals) {
    553     SkTScopedComPtr<IXpsOMGeometryFigure> areaToFillFigure;
    554     HR(this->createXpsRect(areaToFill, FALSE, TRUE, &areaToFillFigure));
    555 
    556     SkTScopedComPtr<IXpsOMPath> areaToFillPath;
    557     HR(this->createPath(areaToFillFigure.get(), visuals, &areaToFillPath));
    558 
    559     SkTScopedComPtr<IXpsOMBrush> areaToFillBrush;
    560     HR(this->createXpsSolidColorBrush(color, 0xFF, &areaToFillBrush));
    561     HRM(areaToFillPath->SetFillBrushLocal(areaToFillBrush.get()),
    562         "Could not set brush for corner of clamp.");
    563 
    564     return S_OK;
    565 }
    566 
    567 static const XPS_TILE_MODE XTM_N  = XPS_TILE_MODE_NONE;
    568 static const XPS_TILE_MODE XTM_T  = XPS_TILE_MODE_TILE;
    569 static const XPS_TILE_MODE XTM_X  = XPS_TILE_MODE_FLIPX;
    570 static const XPS_TILE_MODE XTM_Y  = XPS_TILE_MODE_FLIPY;
    571 static const XPS_TILE_MODE XTM_XY = XPS_TILE_MODE_FLIPXY;
    572 
    573 //TODO(bungeman): In the future, should skia add None,
    574 //handle None+Mirror and None+Repeat correctly.
    575 //None is currently an internal hack so masks don't repeat (None+None only).
    576 static XPS_TILE_MODE SkToXpsTileMode[SkShader::kTileModeCount+1]
    577                                     [SkShader::kTileModeCount+1] = {
    578            //Clamp //Repeat //Mirror //None
    579 /*Clamp */ XTM_N,  XTM_T,   XTM_Y,   XTM_N,
    580 /*Repeat*/ XTM_T,  XTM_T,   XTM_Y,   XTM_N,
    581 /*Mirror*/ XTM_X,  XTM_X,   XTM_XY,  XTM_X,
    582 /*None  */ XTM_N,  XTM_N,   XTM_Y,   XTM_N,
    583 };
    584 
    585 HRESULT SkXPSDevice::createXpsImageBrush(
    586         const SkBitmap& bitmap,
    587         const SkMatrix& localMatrix,
    588         const SkShader::TileMode (&xy)[2],
    589         const SkAlpha alpha,
    590         IXpsOMTileBrush** xpsBrush) {
    591     SkDynamicMemoryWStream write;
    592     if (!SkImageEncoder::EncodeStream(&write, bitmap,
    593                                       SkImageEncoder::kPNG_Type, 100)) {
    594         HRM(E_FAIL, "Unable to encode bitmap as png.");
    595     }
    596     SkMemoryStream* read = new SkMemoryStream;
    597     read->setData(write.copyToData())->unref();
    598     SkTScopedComPtr<IStream> readWrapper;
    599     HRM(SkIStream::CreateFromSkStream(read, true, &readWrapper),
    600         "Could not create stream from png data.");
    601 
    602     const size_t size =
    603         SK_ARRAY_COUNT(L"/Documents/1/Resources/Images/" L_GUID_ID L".png");
    604     wchar_t buffer[size];
    605     wchar_t id[GUID_ID_LEN];
    606     HR(create_id(id, GUID_ID_LEN));
    607     swprintf_s(buffer, size, L"/Documents/1/Resources/Images/%s.png", id);
    608 
    609     SkTScopedComPtr<IOpcPartUri> imagePartUri;
    610     HRM(this->fXpsFactory->CreatePartUri(buffer, &imagePartUri),
    611         "Could not create image part uri.");
    612 
    613     SkTScopedComPtr<IXpsOMImageResource> imageResource;
    614     HRM(this->fXpsFactory->CreateImageResource(
    615             readWrapper.get(),
    616             XPS_IMAGE_TYPE_PNG,
    617             imagePartUri.get(),
    618             &imageResource),
    619         "Could not create image resource.");
    620 
    621     XPS_RECT bitmapRect = {
    622         0.0, 0.0,
    623         static_cast<FLOAT>(bitmap.width()), static_cast<FLOAT>(bitmap.height())
    624     };
    625     SkTScopedComPtr<IXpsOMImageBrush> xpsImageBrush;
    626     HRM(this->fXpsFactory->CreateImageBrush(imageResource.get(),
    627                                             &bitmapRect, &bitmapRect,
    628                                             &xpsImageBrush),
    629         "Could not create image brush.");
    630 
    631     if (SkShader::kClamp_TileMode != xy[0] &&
    632         SkShader::kClamp_TileMode != xy[1]) {
    633 
    634         HRM(xpsImageBrush->SetTileMode(SkToXpsTileMode[xy[0]][xy[1]]),
    635             "Could not set image tile mode");
    636         HRM(xpsImageBrush->SetOpacity(alpha / 255.0f),
    637             "Could not set image opacity.");
    638         HRM(xpsImageBrush->QueryInterface(xpsBrush), "QI failed.");
    639     } else {
    640         //TODO(bungeman): compute how big this really needs to be.
    641         const SkScalar BIG = SkIntToScalar(1000); //SK_ScalarMax;
    642         const FLOAT BIG_F = SkScalarToFLOAT(BIG);
    643         const SkScalar bWidth = SkIntToScalar(bitmap.width());
    644         const SkScalar bHeight = SkIntToScalar(bitmap.height());
    645 
    646         //create brush canvas
    647         SkTScopedComPtr<IXpsOMCanvas> brushCanvas;
    648         HRM(this->fXpsFactory->CreateCanvas(&brushCanvas),
    649             "Could not create image brush canvas.");
    650         SkTScopedComPtr<IXpsOMVisualCollection> brushVisuals;
    651         HRM(brushCanvas->GetVisuals(&brushVisuals),
    652             "Could not get image brush canvas visuals collection.");
    653 
    654         //create central figure
    655         const SkRect bitmapPoints = SkRect::MakeLTRB(0, 0, bWidth, bHeight);
    656         SkTScopedComPtr<IXpsOMGeometryFigure> centralFigure;
    657         HR(this->createXpsRect(bitmapPoints, FALSE, TRUE, &centralFigure));
    658 
    659         SkTScopedComPtr<IXpsOMPath> centralPath;
    660         HR(this->createPath(centralFigure.get(),
    661                             brushVisuals.get(),
    662                             &centralPath));
    663         HRM(xpsImageBrush->SetTileMode(XPS_TILE_MODE_FLIPXY),
    664             "Could not set tile mode for image brush central path.");
    665         HRM(centralPath->SetFillBrushLocal(xpsImageBrush.get()),
    666             "Could not set fill brush for image brush central path.");
    667 
    668         //add left/right
    669         if (SkShader::kClamp_TileMode == xy[0]) {
    670             SkRect leftArea = SkRect::MakeLTRB(-BIG, 0, 0, bHeight);
    671             XPS_RECT leftImageViewBox = {
    672                 0.0, 0.0,
    673                 1.0, static_cast<FLOAT>(bitmap.height()),
    674             };
    675             HR(this->sideOfClamp(leftArea, leftImageViewBox,
    676                                  imageResource.get(),
    677                                  brushVisuals.get()));
    678 
    679             SkRect rightArea = SkRect::MakeLTRB(bWidth, 0, BIG, bHeight);
    680             XPS_RECT rightImageViewBox = {
    681                 bitmap.width() - 1.0f, 0.0f,
    682                 1.0f, static_cast<FLOAT>(bitmap.height()),
    683             };
    684             HR(this->sideOfClamp(rightArea, rightImageViewBox,
    685                                  imageResource.get(),
    686                                  brushVisuals.get()));
    687         }
    688 
    689         //add top/bottom
    690         if (SkShader::kClamp_TileMode == xy[1]) {
    691             SkRect topArea = SkRect::MakeLTRB(0, -BIG, bWidth, 0);
    692             XPS_RECT topImageViewBox = {
    693                 0.0, 0.0,
    694                 static_cast<FLOAT>(bitmap.width()), 1.0,
    695             };
    696             HR(this->sideOfClamp(topArea, topImageViewBox,
    697                                  imageResource.get(),
    698                                  brushVisuals.get()));
    699 
    700             SkRect bottomArea = SkRect::MakeLTRB(0, bHeight, bWidth, BIG);
    701             XPS_RECT bottomImageViewBox = {
    702                 0.0f, bitmap.height() - 1.0f,
    703                 static_cast<FLOAT>(bitmap.width()), 1.0f,
    704             };
    705             HR(this->sideOfClamp(bottomArea, bottomImageViewBox,
    706                                  imageResource.get(),
    707                                  brushVisuals.get()));
    708         }
    709 
    710         //add tl, tr, bl, br
    711         if (SkShader::kClamp_TileMode == xy[0] &&
    712             SkShader::kClamp_TileMode == xy[1]) {
    713 
    714             SkAutoLockPixels alp(bitmap);
    715 
    716             const SkColor tlColor = bitmap.getColor(0,0);
    717             const SkRect tlArea = SkRect::MakeLTRB(-BIG, -BIG, 0, 0);
    718             HR(this->cornerOfClamp(tlArea, tlColor, brushVisuals.get()));
    719 
    720             const SkColor trColor = bitmap.getColor(bitmap.width()-1,0);
    721             const SkRect trArea = SkRect::MakeLTRB(bWidth, -BIG, BIG, 0);
    722             HR(this->cornerOfClamp(trArea, trColor, brushVisuals.get()));
    723 
    724             const SkColor brColor = bitmap.getColor(bitmap.width()-1,
    725                                                     bitmap.height()-1);
    726             const SkRect brArea = SkRect::MakeLTRB(bWidth, bHeight, BIG, BIG);
    727             HR(this->cornerOfClamp(brArea, brColor, brushVisuals.get()));
    728 
    729             const SkColor blColor = bitmap.getColor(0,bitmap.height()-1);
    730             const SkRect blArea = SkRect::MakeLTRB(-BIG, bHeight, 0, BIG);
    731             HR(this->cornerOfClamp(blArea, blColor, brushVisuals.get()));
    732         }
    733 
    734         //create visual brush from canvas
    735         XPS_RECT bound = {};
    736         if (SkShader::kClamp_TileMode == xy[0] &&
    737             SkShader::kClamp_TileMode == xy[1]) {
    738 
    739             bound.x = BIG_F / -2;
    740             bound.y = BIG_F / -2;
    741             bound.width = BIG_F;
    742             bound.height = BIG_F;
    743         } else if (SkShader::kClamp_TileMode == xy[0]) {
    744             bound.x = BIG_F / -2;
    745             bound.y = 0.0f;
    746             bound.width = BIG_F;
    747             bound.height = static_cast<FLOAT>(bitmap.height());
    748         } else if (SkShader::kClamp_TileMode == xy[1]) {
    749             bound.x = 0;
    750             bound.y = BIG_F / -2;
    751             bound.width = static_cast<FLOAT>(bitmap.width());
    752             bound.height = BIG_F;
    753         }
    754         SkTScopedComPtr<IXpsOMVisualBrush> clampBrush;
    755         HRM(this->fXpsFactory->CreateVisualBrush(&bound, &bound, &clampBrush),
    756             "Could not create visual brush for image brush.");
    757         HRM(clampBrush->SetVisualLocal(brushCanvas.get()),
    758             "Could not set canvas on visual brush for image brush.");
    759         HRM(clampBrush->SetTileMode(SkToXpsTileMode[xy[0]][xy[1]]),
    760             "Could not set tile mode on visual brush for image brush.");
    761         HRM(clampBrush->SetOpacity(alpha / 255.0f),
    762             "Could not set opacity on visual brush for image brush.");
    763 
    764         HRM(clampBrush->QueryInterface(xpsBrush), "QI failed.");
    765     }
    766 
    767     SkTScopedComPtr<IXpsOMMatrixTransform> xpsMatrixToUse;
    768     HR(this->createXpsTransform(localMatrix, &xpsMatrixToUse));
    769     if (NULL != xpsMatrixToUse.get()) {
    770         HRM((*xpsBrush)->SetTransformLocal(xpsMatrixToUse.get()),
    771             "Could not set transform for image brush.");
    772     } else {
    773         //TODO(bungeman): perspective bitmaps in general.
    774     }
    775 
    776     return S_OK;
    777 }
    778 
    779 HRESULT SkXPSDevice::createXpsGradientStop(const SkColor skColor,
    780                                            const SkScalar offset,
    781                                            IXpsOMGradientStop** xpsGradStop) {
    782     XPS_COLOR gradStopXpsColor = xps_color(skColor);
    783     HRM(this->fXpsFactory->CreateGradientStop(&gradStopXpsColor,
    784                                               NULL,
    785                                               SkScalarToFLOAT(offset),
    786                                               xpsGradStop),
    787         "Could not create gradient stop.");
    788     return S_OK;
    789 }
    790 
    791 HRESULT SkXPSDevice::createXpsLinearGradient(SkShader::GradientInfo info,
    792                                              const SkAlpha alpha,
    793                                              const SkMatrix& localMatrix,
    794                                              IXpsOMMatrixTransform* xpsMatrix,
    795                                              IXpsOMBrush** xpsBrush) {
    796     XPS_POINT startPoint;
    797     XPS_POINT endPoint;
    798     if (NULL != xpsMatrix) {
    799         startPoint = xps_point(info.fPoint[0]);
    800         endPoint = xps_point(info.fPoint[1]);
    801     } else {
    802         transform_offsets(info.fColorOffsets, info.fColorCount,
    803                           info.fPoint[0], info.fPoint[1],
    804                           localMatrix);
    805         startPoint = xps_point(info.fPoint[0], localMatrix);
    806         endPoint = xps_point(info.fPoint[1], localMatrix);
    807     }
    808 
    809     SkTScopedComPtr<IXpsOMGradientStop> gradStop0;
    810     HR(createXpsGradientStop(info.fColors[0],
    811                              info.fColorOffsets[0],
    812                              &gradStop0));
    813 
    814     SkTScopedComPtr<IXpsOMGradientStop> gradStop1;
    815     HR(createXpsGradientStop(info.fColors[1],
    816                              info.fColorOffsets[1],
    817                              &gradStop1));
    818 
    819     SkTScopedComPtr<IXpsOMLinearGradientBrush> gradientBrush;
    820     HRM(this->fXpsFactory->CreateLinearGradientBrush(gradStop0.get(),
    821                                                      gradStop1.get(),
    822                                                      &startPoint,
    823                                                      &endPoint,
    824                                                      &gradientBrush),
    825         "Could not create linear gradient brush.");
    826     if (NULL != xpsMatrix) {
    827         HRM(gradientBrush->SetTransformLocal(xpsMatrix),
    828             "Could not set transform on linear gradient brush.");
    829     }
    830 
    831     SkTScopedComPtr<IXpsOMGradientStopCollection> gradStopCollection;
    832     HRM(gradientBrush->GetGradientStops(&gradStopCollection),
    833         "Could not get linear gradient stop collection.");
    834     for (int i = 2; i < info.fColorCount; ++i) {
    835         SkTScopedComPtr<IXpsOMGradientStop> gradStop;
    836         HR(createXpsGradientStop(info.fColors[i],
    837                                  info.fColorOffsets[i],
    838                                  &gradStop));
    839         HRM(gradStopCollection->Append(gradStop.get()),
    840             "Could not add linear gradient stop.");
    841     }
    842 
    843     HRM(gradientBrush->SetSpreadMethod(xps_spread_method(info.fTileMode)),
    844         "Could not set spread method of linear gradient.");
    845 
    846     HRM(gradientBrush->SetOpacity(alpha / 255.0f),
    847         "Could not set opacity of linear gradient brush.");
    848     HRM(gradientBrush->QueryInterface<IXpsOMBrush>(xpsBrush), "QI failed");
    849 
    850     return S_OK;
    851 }
    852 
    853 HRESULT SkXPSDevice::createXpsRadialGradient(SkShader::GradientInfo info,
    854                                              const SkAlpha alpha,
    855                                              const SkMatrix& localMatrix,
    856                                              IXpsOMMatrixTransform* xpsMatrix,
    857                                              IXpsOMBrush** xpsBrush) {
    858     SkTScopedComPtr<IXpsOMGradientStop> gradStop0;
    859     HR(createXpsGradientStop(info.fColors[0],
    860                              info.fColorOffsets[0],
    861                              &gradStop0));
    862 
    863     SkTScopedComPtr<IXpsOMGradientStop> gradStop1;
    864     HR(createXpsGradientStop(info.fColors[1],
    865                              info.fColorOffsets[1],
    866                              &gradStop1));
    867 
    868     //TODO: figure out how to fake better if not affine
    869     XPS_POINT centerPoint;
    870     XPS_POINT gradientOrigin;
    871     XPS_SIZE radiiSizes;
    872     if (NULL != xpsMatrix) {
    873         centerPoint = xps_point(info.fPoint[0]);
    874         gradientOrigin = xps_point(info.fPoint[0]);
    875         radiiSizes.width = SkScalarToFLOAT(info.fRadius[0]);
    876         radiiSizes.height = SkScalarToFLOAT(info.fRadius[0]);
    877     } else {
    878         centerPoint = xps_point(info.fPoint[0], localMatrix);
    879         gradientOrigin = xps_point(info.fPoint[0], localMatrix);
    880 
    881         SkScalar radius = info.fRadius[0];
    882         SkVector vec[2];
    883 
    884         vec[0].set(radius, 0);
    885         vec[1].set(0, radius);
    886         localMatrix.mapVectors(vec, 2);
    887 
    888         SkScalar d0 = vec[0].length();
    889         SkScalar d1 = vec[1].length();
    890 
    891         radiiSizes.width = SkScalarToFLOAT(d0);
    892         radiiSizes.height = SkScalarToFLOAT(d1);
    893     }
    894 
    895     SkTScopedComPtr<IXpsOMRadialGradientBrush> gradientBrush;
    896     HRM(this->fXpsFactory->CreateRadialGradientBrush(gradStop0.get(),
    897                                                      gradStop1.get(),
    898                                                      &centerPoint,
    899                                                      &gradientOrigin,
    900                                                      &radiiSizes,
    901                                                      &gradientBrush),
    902         "Could not create radial gradient brush.");
    903     if (NULL != xpsMatrix) {
    904         HRM(gradientBrush->SetTransformLocal(xpsMatrix),
    905             "Could not set transform on radial gradient brush.");
    906     }
    907 
    908     SkTScopedComPtr<IXpsOMGradientStopCollection> gradStopCollection;
    909     HRM(gradientBrush->GetGradientStops(&gradStopCollection),
    910         "Could not get radial gradient stop collection.");
    911     for (int i = 2; i < info.fColorCount; ++i) {
    912         SkTScopedComPtr<IXpsOMGradientStop> gradStop;
    913         HR(createXpsGradientStop(info.fColors[i],
    914                                  info.fColorOffsets[i],
    915                                  &gradStop));
    916         HRM(gradStopCollection->Append(gradStop.get()),
    917             "Could not add radial gradient stop.");
    918     }
    919 
    920     HRM(gradientBrush->SetSpreadMethod(xps_spread_method(info.fTileMode)),
    921         "Could not set spread method of radial gradient.");
    922 
    923     HRM(gradientBrush->SetOpacity(alpha / 255.0f),
    924         "Could not set opacity of radial gradient brush.");
    925     HRM(gradientBrush->QueryInterface<IXpsOMBrush>(xpsBrush), "QI failed.");
    926 
    927     return S_OK;
    928 }
    929 
    930 HRESULT SkXPSDevice::createXpsBrush(const SkPaint& skPaint,
    931                                     IXpsOMBrush** brush,
    932                                     const SkMatrix* parentTransform) {
    933     const SkShader *shader = skPaint.getShader();
    934     if (NULL == shader) {
    935         HR(this->createXpsSolidColorBrush(skPaint.getColor(), 0xFF, brush));
    936         return S_OK;
    937     }
    938 
    939     //Gradient shaders.
    940     SkShader::GradientInfo info;
    941     info.fColorCount = 0;
    942     info.fColors = NULL;
    943     info.fColorOffsets = NULL;
    944     SkShader::GradientType gradientType = shader->asAGradient(&info);
    945 
    946     if (SkShader::kNone_GradientType == gradientType) {
    947         //Nothing to see, move along.
    948 
    949     } else if (SkShader::kColor_GradientType == gradientType) {
    950         SkASSERT(1 == info.fColorCount);
    951         SkColor color;
    952         info.fColors = &color;
    953         SkShader::GradientType gradientType = shader->asAGradient(&info);
    954         SkAlpha alpha = skPaint.getAlpha();
    955         HR(this->createXpsSolidColorBrush(color, alpha, brush));
    956         return S_OK;
    957 
    958     } else {
    959         if (info.fColorCount == 0) {
    960             const SkColor color = skPaint.getColor();
    961             HR(this->createXpsSolidColorBrush(color, 0xFF, brush));
    962             return S_OK;
    963         }
    964 
    965         SkAutoTArray<SkColor> colors(info.fColorCount);
    966         SkAutoTArray<SkScalar> colorOffsets(info.fColorCount);
    967         info.fColors = colors.get();
    968         info.fColorOffsets = colorOffsets.get();
    969         shader->asAGradient(&info);
    970 
    971         if (1 == info.fColorCount) {
    972             SkColor color = info.fColors[0];
    973             SkAlpha alpha = skPaint.getAlpha();
    974             HR(this->createXpsSolidColorBrush(color, alpha, brush));
    975             return S_OK;
    976         }
    977 
    978         SkMatrix localMatrix = shader->getLocalMatrix();
    979         if (NULL != parentTransform) {
    980             localMatrix.preConcat(*parentTransform);
    981         }
    982         SkTScopedComPtr<IXpsOMMatrixTransform> xpsMatrixToUse;
    983         HR(this->createXpsTransform(localMatrix, &xpsMatrixToUse));
    984 
    985         if (SkShader::kLinear_GradientType == gradientType) {
    986             HR(this->createXpsLinearGradient(info,
    987                                              skPaint.getAlpha(),
    988                                              localMatrix,
    989                                              xpsMatrixToUse.get(),
    990                                              brush));
    991             return S_OK;
    992         }
    993 
    994         if (SkShader::kRadial_GradientType == gradientType) {
    995             HR(this->createXpsRadialGradient(info,
    996                                              skPaint.getAlpha(),
    997                                              localMatrix,
    998                                              xpsMatrixToUse.get(),
    999                                              brush));
   1000             return S_OK;
   1001         }
   1002 
   1003         if (SkShader::kRadial2_GradientType == gradientType ||
   1004             SkShader::kConical_GradientType == gradientType) {
   1005             //simple if affine and one is 0, otherwise will have to fake
   1006         }
   1007 
   1008         if (SkShader::kSweep_GradientType == gradientType) {
   1009             //have to fake
   1010         }
   1011     }
   1012 
   1013     SkBitmap outTexture;
   1014     SkMatrix outMatrix;
   1015     SkShader::TileMode xy[2];
   1016     SkShader::BitmapType bitmapType = shader->asABitmap(&outTexture,
   1017                                                         &outMatrix,
   1018                                                         xy);
   1019     switch (bitmapType) {
   1020         case SkShader::kNone_BitmapType:
   1021             break;
   1022         case SkShader::kDefault_BitmapType: {
   1023             //TODO: outMatrix??
   1024             SkMatrix localMatrix = shader->getLocalMatrix();
   1025             if (NULL != parentTransform) {
   1026                 localMatrix.preConcat(*parentTransform);
   1027             }
   1028 
   1029             SkTScopedComPtr<IXpsOMTileBrush> tileBrush;
   1030             HR(this->createXpsImageBrush(outTexture,
   1031                                          localMatrix,
   1032                                          xy,
   1033                                          skPaint.getAlpha(),
   1034                                          &tileBrush));
   1035 
   1036             HRM(tileBrush->QueryInterface<IXpsOMBrush>(brush), "QI failed.");
   1037 
   1038             return S_OK;
   1039         }
   1040         case SkShader::kRadial_BitmapType:
   1041         case SkShader::kSweep_BitmapType:
   1042         case SkShader::kTwoPointRadial_BitmapType:
   1043         default:
   1044             break;
   1045     }
   1046 
   1047     HR(this->createXpsSolidColorBrush(skPaint.getColor(), 0xFF, brush));
   1048     return S_OK;
   1049 }
   1050 
   1051 static bool rect_must_be_pathed(const SkPaint& paint, const SkMatrix& matrix) {
   1052     const bool zeroWidth = (0 == paint.getStrokeWidth());
   1053     const bool stroke = (SkPaint::kFill_Style != paint.getStyle());
   1054 
   1055     return paint.getPathEffect() ||
   1056            paint.getMaskFilter() ||
   1057            paint.getRasterizer() ||
   1058            (stroke && (
   1059                (matrix.hasPerspective() && !zeroWidth) ||
   1060                SkPaint::kMiter_Join != paint.getStrokeJoin() ||
   1061                (SkPaint::kMiter_Join == paint.getStrokeJoin() &&
   1062                 paint.getStrokeMiter() < SK_ScalarSqrt2)
   1063            ))
   1064     ;
   1065 }
   1066 
   1067 HRESULT SkXPSDevice::createXpsRect(const SkRect& rect, BOOL stroke, BOOL fill,
   1068                                    IXpsOMGeometryFigure** xpsRect) {
   1069     const SkPoint points[4] = {
   1070         { rect.fLeft, rect.fTop },
   1071         { rect.fRight, rect.fTop },
   1072         { rect.fRight, rect.fBottom },
   1073         { rect.fLeft, rect.fBottom },
   1074     };
   1075     return this->createXpsQuad(points, stroke, fill, xpsRect);
   1076 }
   1077 HRESULT SkXPSDevice::createXpsQuad(const SkPoint (&points)[4],
   1078                                    BOOL stroke, BOOL fill,
   1079                                    IXpsOMGeometryFigure** xpsQuad) {
   1080     // Define the start point.
   1081     XPS_POINT startPoint = xps_point(points[0]);
   1082 
   1083     // Create the figure.
   1084     HRM(this->fXpsFactory->CreateGeometryFigure(&startPoint, xpsQuad),
   1085         "Could not create quad geometry figure.");
   1086 
   1087     // Define the type of each segment.
   1088     XPS_SEGMENT_TYPE segmentTypes[3] = {
   1089         XPS_SEGMENT_TYPE_LINE,
   1090         XPS_SEGMENT_TYPE_LINE,
   1091         XPS_SEGMENT_TYPE_LINE,
   1092     };
   1093 
   1094     // Define the x and y coordinates of each corner of the figure.
   1095     FLOAT segmentData[6] = {
   1096         SkScalarToFLOAT(points[1].fX), SkScalarToFLOAT(points[1].fY),
   1097         SkScalarToFLOAT(points[2].fX), SkScalarToFLOAT(points[2].fY),
   1098         SkScalarToFLOAT(points[3].fX), SkScalarToFLOAT(points[3].fY),
   1099     };
   1100 
   1101     // Describe if the segments are stroked.
   1102     BOOL segmentStrokes[3] = {
   1103         stroke, stroke, stroke,
   1104     };
   1105 
   1106     // Add the segment data to the figure.
   1107     HRM((*xpsQuad)->SetSegments(
   1108             3, 6,
   1109             segmentTypes , segmentData, segmentStrokes),
   1110         "Could not add segment data to quad.");
   1111 
   1112     // Set the closed and filled properties of the figure.
   1113     HRM((*xpsQuad)->SetIsClosed(stroke), "Could not set quad close.");
   1114     HRM((*xpsQuad)->SetIsFilled(fill), "Could not set quad fill.");
   1115 
   1116     return S_OK;
   1117 }
   1118 
   1119 uint32_t SkXPSDevice::getDeviceCapabilities() {
   1120     return kVector_Capability;
   1121 }
   1122 
   1123 void SkXPSDevice::clear(SkColor color) {
   1124     //TODO: override this for XPS
   1125     SkDEBUGF(("XPS clear not yet implemented."));
   1126 }
   1127 
   1128 void SkXPSDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
   1129                              size_t count, const SkPoint points[],
   1130                              const SkPaint& paint) {
   1131     //This will call back into the device to do the drawing.
   1132     d.drawPoints(mode, count, points, paint, true);
   1133 }
   1134 
   1135 void SkXPSDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode,
   1136                                int vertexCount, const SkPoint verts[],
   1137                                const SkPoint texs[], const SkColor colors[],
   1138                                SkXfermode* xmode, const uint16_t indices[],
   1139                                int indexCount, const SkPaint& paint) {
   1140     //TODO: override this for XPS
   1141     SkDEBUGF(("XPS drawVertices not yet implemented."));
   1142 }
   1143 
   1144 void SkXPSDevice::drawPaint(const SkDraw& d, const SkPaint& origPaint) {
   1145     const SkRect r = SkRect::MakeSize(this->fCurrentCanvasSize);
   1146 
   1147     //If trying to paint with a stroke, ignore that and fill.
   1148     SkPaint* fillPaint = const_cast<SkPaint*>(&origPaint);
   1149     SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
   1150     if (paint->getStyle() != SkPaint::kFill_Style) {
   1151         paint.writable()->setStyle(SkPaint::kFill_Style);
   1152     }
   1153 
   1154     this->internalDrawRect(d, r, false, *fillPaint);
   1155 }
   1156 
   1157 void SkXPSDevice::drawRect(const SkDraw& d,
   1158                            const SkRect& r,
   1159                            const SkPaint& paint) {
   1160     this->internalDrawRect(d, r, true, paint);
   1161 }
   1162 
   1163 void SkXPSDevice::internalDrawRect(const SkDraw& d,
   1164                                    const SkRect& r,
   1165                                    bool transformRect,
   1166                                    const SkPaint& paint) {
   1167     //Exit early if there is nothing to draw.
   1168     if (d.fClip->isEmpty() ||
   1169         (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
   1170         return;
   1171     }
   1172 
   1173     //Path the rect if we can't optimize it.
   1174     if (rect_must_be_pathed(paint, *d.fMatrix)) {
   1175         SkPath tmp;
   1176         tmp.addRect(r);
   1177         tmp.setFillType(SkPath::kWinding_FillType);
   1178         this->drawPath(d, tmp, paint, NULL, true);
   1179         return;
   1180     }
   1181 
   1182     //Create the shaded path.
   1183     SkTScopedComPtr<IXpsOMPath> shadedPath;
   1184     HRVM(this->fXpsFactory->CreatePath(&shadedPath),
   1185          "Could not create shaded path for rect.");
   1186 
   1187     //Create the shaded geometry.
   1188     SkTScopedComPtr<IXpsOMGeometry> shadedGeometry;
   1189     HRVM(this->fXpsFactory->CreateGeometry(&shadedGeometry),
   1190          "Could not create shaded geometry for rect.");
   1191 
   1192     //Add the geometry to the shaded path.
   1193     HRVM(shadedPath->SetGeometryLocal(shadedGeometry.get()),
   1194          "Could not set shaded geometry for rect.");
   1195 
   1196     //Set the brushes.
   1197     BOOL fill = FALSE;
   1198     BOOL stroke = FALSE;
   1199     HRV(this->shadePath(shadedPath.get(), paint, *d.fMatrix, &fill, &stroke));
   1200 
   1201     bool xpsTransformsPath = true;
   1202     //Transform the geometry.
   1203     if (transformRect && xpsTransformsPath) {
   1204         SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform;
   1205         HRV(this->createXpsTransform(*d.fMatrix, &xpsTransform));
   1206         if (xpsTransform.get()) {
   1207             HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()),
   1208                  "Could not set transform for rect.");
   1209         } else {
   1210             xpsTransformsPath = false;
   1211         }
   1212     }
   1213 
   1214     //Create the figure.
   1215     SkTScopedComPtr<IXpsOMGeometryFigure> rectFigure;
   1216     {
   1217         SkPoint points[4] = {
   1218             { r.fLeft, r.fTop },
   1219             { r.fLeft, r.fBottom },
   1220             { r.fRight, r.fBottom },
   1221             { r.fRight, r.fTop },
   1222         };
   1223         if (!xpsTransformsPath && transformRect) {
   1224             d.fMatrix->mapPoints(points, SK_ARRAY_COUNT(points));
   1225         }
   1226         HRV(this->createXpsQuad(points, stroke, fill, &rectFigure));
   1227     }
   1228 
   1229     //Get the figures of the shaded geometry.
   1230     SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures;
   1231     HRVM(shadedGeometry->GetFigures(&shadedFigures),
   1232          "Could not get shaded figures for rect.");
   1233 
   1234     //Add the figure to the shaded geometry figures.
   1235     HRVM(shadedFigures->Append(rectFigure.get()),
   1236          "Could not add shaded figure for rect.");
   1237 
   1238     HRV(this->clip(shadedPath.get(), d));
   1239 
   1240     //Add the shaded path to the current visuals.
   1241     SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals;
   1242     HRVM(this->fCurrentXpsCanvas->GetVisuals(&currentVisuals),
   1243          "Could not get current visuals for rect.");
   1244     HRVM(currentVisuals->Append(shadedPath.get()),
   1245          "Could not add rect to current visuals.");
   1246 }
   1247 
   1248 static HRESULT close_figure(const SkTDArray<XPS_SEGMENT_TYPE>& segmentTypes,
   1249                             const SkTDArray<BOOL>& segmentStrokes,
   1250                             const SkTDArray<FLOAT>& segmentData,
   1251                             BOOL stroke, BOOL fill,
   1252                             IXpsOMGeometryFigure* figure,
   1253                             IXpsOMGeometryFigureCollection* figures) {
   1254     // Add the segment data to the figure.
   1255     HRM(figure->SetSegments(segmentTypes.count(), segmentData.count(),
   1256                             segmentTypes.begin() , segmentData.begin(),
   1257                             segmentStrokes.begin()),
   1258         "Could not set path segments.");
   1259 
   1260     // Set the closed and filled properties of the figure.
   1261     HRM(figure->SetIsClosed(stroke), "Could not set path closed.");
   1262     HRM(figure->SetIsFilled(fill), "Could not set path fill.");
   1263 
   1264     // Add the figure created above to this geometry.
   1265     HRM(figures->Append(figure), "Could not add path to geometry.");
   1266     return S_OK;
   1267 }
   1268 
   1269 HRESULT SkXPSDevice::addXpsPathGeometry(
   1270         IXpsOMGeometryFigureCollection* xpsFigures,
   1271         BOOL stroke, BOOL fill, const SkPath& path) {
   1272     SkTDArray<XPS_SEGMENT_TYPE> segmentTypes;
   1273     SkTDArray<BOOL> segmentStrokes;
   1274     SkTDArray<FLOAT> segmentData;
   1275 
   1276     SkTScopedComPtr<IXpsOMGeometryFigure> xpsFigure;
   1277     SkPath::Iter iter(path, true);
   1278     SkPoint points[4];
   1279     SkPath::Verb verb;
   1280     while ((verb = iter.next(points)) != SkPath::kDone_Verb) {
   1281         switch (verb) {
   1282             case SkPath::kMove_Verb: {
   1283                 if (NULL != xpsFigure.get()) {
   1284                     HR(close_figure(segmentTypes, segmentStrokes, segmentData,
   1285                                     stroke, fill,
   1286                                     xpsFigure.get() , xpsFigures));
   1287                     xpsFigure.reset();
   1288                     segmentTypes.rewind();
   1289                     segmentStrokes.rewind();
   1290                     segmentData.rewind();
   1291                 }
   1292                 // Define the start point.
   1293                 XPS_POINT startPoint = xps_point(points[0]);
   1294                 // Create the figure.
   1295                 HRM(this->fXpsFactory->CreateGeometryFigure(&startPoint,
   1296                                                             &xpsFigure),
   1297                     "Could not create path geometry figure.");
   1298                 break;
   1299             }
   1300             case SkPath::kLine_Verb:
   1301                 if (iter.isCloseLine()) break; //ignore the line, auto-closed
   1302                 segmentTypes.push(XPS_SEGMENT_TYPE_LINE);
   1303                 segmentStrokes.push(stroke);
   1304                 segmentData.push(SkScalarToFLOAT(points[1].fX));
   1305                 segmentData.push(SkScalarToFLOAT(points[1].fY));
   1306                 break;
   1307             case SkPath::kQuad_Verb:
   1308                 segmentTypes.push(XPS_SEGMENT_TYPE_QUADRATIC_BEZIER);
   1309                 segmentStrokes.push(stroke);
   1310                 segmentData.push(SkScalarToFLOAT(points[1].fX));
   1311                 segmentData.push(SkScalarToFLOAT(points[1].fY));
   1312                 segmentData.push(SkScalarToFLOAT(points[2].fX));
   1313                 segmentData.push(SkScalarToFLOAT(points[2].fY));
   1314                 break;
   1315             case SkPath::kCubic_Verb:
   1316                 segmentTypes.push(XPS_SEGMENT_TYPE_BEZIER);
   1317                 segmentStrokes.push(stroke);
   1318                 segmentData.push(SkScalarToFLOAT(points[1].fX));
   1319                 segmentData.push(SkScalarToFLOAT(points[1].fY));
   1320                 segmentData.push(SkScalarToFLOAT(points[2].fX));
   1321                 segmentData.push(SkScalarToFLOAT(points[2].fY));
   1322                 segmentData.push(SkScalarToFLOAT(points[3].fX));
   1323                 segmentData.push(SkScalarToFLOAT(points[3].fY));
   1324                 break;
   1325             case SkPath::kClose_Verb:
   1326                 // we ignore these, and just get the whole segment from
   1327                 // the corresponding line/quad/cubic verbs
   1328                 break;
   1329             default:
   1330                 SkASSERT(!"unexpected verb");
   1331                 break;
   1332         }
   1333     }
   1334     if (NULL != xpsFigure.get()) {
   1335         HR(close_figure(segmentTypes, segmentStrokes, segmentData,
   1336                         stroke, fill,
   1337                         xpsFigure.get(), xpsFigures));
   1338     }
   1339     return S_OK;
   1340 }
   1341 
   1342 HRESULT SkXPSDevice::drawInverseWindingPath(const SkDraw& d,
   1343                                             const SkPath& devicePath,
   1344                                             IXpsOMPath* shadedPath) {
   1345     const SkRect universeRect = SkRect::MakeLTRB(0, 0,
   1346         this->fCurrentCanvasSize.fWidth, this->fCurrentCanvasSize.fHeight);
   1347 
   1348     const XPS_RECT universeRectXps = {
   1349         0.0f, 0.0f,
   1350         SkScalarToFLOAT(this->fCurrentCanvasSize.fWidth),
   1351         SkScalarToFLOAT(this->fCurrentCanvasSize.fHeight),
   1352     };
   1353 
   1354     //Get the geometry.
   1355     SkTScopedComPtr<IXpsOMGeometry> shadedGeometry;
   1356     HRM(shadedPath->GetGeometry(&shadedGeometry),
   1357         "Could not get shaded geometry for inverse path.");
   1358 
   1359     //Get the figures from the geometry.
   1360     SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures;
   1361     HRM(shadedGeometry->GetFigures(&shadedFigures),
   1362         "Could not get shaded figures for inverse path.");
   1363 
   1364     HRM(shadedGeometry->SetFillRule(XPS_FILL_RULE_NONZERO),
   1365         "Could not set shaded fill rule for inverse path.");
   1366 
   1367     //Take everything drawn so far, and make a shared resource out of it.
   1368     //Replace everything drawn so far with
   1369     //inverse canvas
   1370     //  old canvas of everything so far
   1371     //  world shaded figure, clipped to current clip
   1372     //  top canvas of everything so far, clipped to path
   1373     //Note: this is not quite right when there is nothing solid in the
   1374     //canvas of everything so far, as the bit on top will allow
   1375     //the world paint to show through.
   1376 
   1377     //Create new canvas.
   1378     SkTScopedComPtr<IXpsOMCanvas> newCanvas;
   1379     HRM(this->fXpsFactory->CreateCanvas(&newCanvas),
   1380         "Could not create inverse canvas.");
   1381 
   1382     //Save the old canvas to a dictionary on the new canvas.
   1383     SkTScopedComPtr<IXpsOMDictionary> newDictionary;
   1384     HRM(this->fXpsFactory->CreateDictionary(&newDictionary),
   1385         "Could not create inverse dictionary.");
   1386     HRM(newCanvas->SetDictionaryLocal(newDictionary.get()),
   1387         "Could not set inverse dictionary.");
   1388 
   1389     const size_t size = SK_ARRAY_COUNT(L"ID" L_GUID_ID);
   1390     wchar_t buffer[size];
   1391     wchar_t id[GUID_ID_LEN];
   1392     HR(create_id(id, GUID_ID_LEN, '_'));
   1393     swprintf_s(buffer, size, L"ID%s", id);
   1394     HRM(newDictionary->Append(buffer, this->fCurrentXpsCanvas.get()),
   1395         "Could not add canvas to inverse dictionary.");
   1396 
   1397     //Start drawing
   1398     SkTScopedComPtr<IXpsOMVisualCollection> newVisuals;
   1399     HRM(newCanvas->GetVisuals(&newVisuals),
   1400         "Could not get inverse canvas visuals.");
   1401 
   1402     //Draw old canvas from dictionary onto new canvas.
   1403     SkTScopedComPtr<IXpsOMGeometry> oldGeometry;
   1404     HRM(this->fXpsFactory->CreateGeometry(&oldGeometry),
   1405         "Could not create old inverse geometry.");
   1406 
   1407     SkTScopedComPtr<IXpsOMGeometryFigureCollection> oldFigures;
   1408     HRM(oldGeometry->GetFigures(&oldFigures),
   1409         "Could not get old inverse figures.");
   1410 
   1411     SkTScopedComPtr<IXpsOMGeometryFigure> oldFigure;
   1412     HR(this->createXpsRect(universeRect, FALSE, TRUE, &oldFigure));
   1413     HRM(oldFigures->Append(oldFigure.get()),
   1414         "Could not add old inverse figure.");
   1415 
   1416     SkTScopedComPtr<IXpsOMVisualBrush> oldBrush;
   1417     HRM(this->fXpsFactory->CreateVisualBrush(&universeRectXps,
   1418                                              &universeRectXps,
   1419                                              &oldBrush),
   1420         "Could not create old inverse brush.");
   1421 
   1422     SkTScopedComPtr<IXpsOMPath> oldPath;
   1423     HRM(this->fXpsFactory->CreatePath(&oldPath),
   1424         "Could not create old inverse path.");
   1425     HRM(oldPath->SetGeometryLocal(oldGeometry.get()),
   1426         "Could not set old inverse geometry.");
   1427     HRM(oldPath->SetFillBrushLocal(oldBrush.get()),
   1428         "Could not set old inverse fill brush.");
   1429     //the brush must be parented before setting the lookup.
   1430     HRM(newVisuals->Append(oldPath.get()),
   1431         "Could not add old inverse path to new canvas visuals.");
   1432     HRM(oldBrush->SetVisualLookup(buffer),
   1433         "Could not set old inverse brush visual lookup.");
   1434 
   1435     //Draw the clip filling shader.
   1436     SkTScopedComPtr<IXpsOMGeometryFigure> shadedFigure;
   1437     HR(this->createXpsRect(universeRect, FALSE, TRUE, &shadedFigure));
   1438     HRM(shadedFigures->Append(shadedFigure.get()),
   1439         "Could not add inverse shaded figure.");
   1440     //the geometry is already set
   1441     HR(this->clip(shadedPath, d));
   1442     HRM(newVisuals->Append(shadedPath),
   1443         "Could not add inverse shaded path to canvas visuals.");
   1444 
   1445     //Draw the old canvas on top, clipped to the original path.
   1446     SkTScopedComPtr<IXpsOMCanvas> topCanvas;
   1447     HRM(this->fXpsFactory->CreateCanvas(&topCanvas),
   1448         "Could not create top inverse canvas.");
   1449     //Clip the canvas to prevent alpha spill.
   1450     //This is the entire reason this canvas exists.
   1451     HR(this->clip(topCanvas.get(), d));
   1452 
   1453     SkTScopedComPtr<IXpsOMGeometry> topGeometry;
   1454     HRM(this->fXpsFactory->CreateGeometry(&topGeometry),
   1455         "Could not create top inverse geometry.");
   1456 
   1457     SkTScopedComPtr<IXpsOMGeometryFigureCollection> topFigures;
   1458     HRM(topGeometry->GetFigures(&topFigures),
   1459         "Could not get top inverse figures.");
   1460 
   1461     SkTScopedComPtr<IXpsOMGeometryFigure> topFigure;
   1462     HR(this->createXpsRect(universeRect, FALSE, TRUE, &topFigure));
   1463     HRM(topFigures->Append(topFigure.get()),
   1464         "Could not add old inverse figure.");
   1465 
   1466     SkTScopedComPtr<IXpsOMVisualBrush> topBrush;
   1467     HRM(this->fXpsFactory->CreateVisualBrush(&universeRectXps,
   1468                                              &universeRectXps,
   1469                                              &topBrush),
   1470         "Could not create top inverse brush.");
   1471 
   1472     SkTScopedComPtr<IXpsOMPath> topPath;
   1473     HRM(this->fXpsFactory->CreatePath(&topPath),
   1474         "Could not create top inverse path.");
   1475     HRM(topPath->SetGeometryLocal(topGeometry.get()),
   1476         "Could not set top inverse geometry.");
   1477     HRM(topPath->SetFillBrushLocal(topBrush.get()),
   1478         "Could not set top inverse fill brush.");
   1479     //the brush must be parented before setting the lookup.
   1480     HRM(newVisuals->Append(topCanvas.get()),
   1481         "Could not add top canvas to inverse canvas visuals.");
   1482     SkTScopedComPtr<IXpsOMVisualCollection> topVisuals;
   1483     HRM(topCanvas->GetVisuals(&topVisuals),
   1484         "Could not get top inverse canvas visuals.");
   1485     HRM(topVisuals->Append(topPath.get()),
   1486         "Could not add top inverse path to top canvas visuals.");
   1487     HRM(topBrush->SetVisualLookup(buffer),
   1488         "Could not set top inverse brush visual lookup.");
   1489 
   1490     HR(this->clipToPath(topPath.get(), devicePath, XPS_FILL_RULE_NONZERO));
   1491 
   1492     //swap current canvas to new canvas
   1493     this->fCurrentXpsCanvas.swap(newCanvas);
   1494 
   1495     return S_OK;
   1496 }
   1497 
   1498 void SkXPSDevice::convertToPpm(const SkMaskFilter* filter,
   1499                                SkMatrix* matrix,
   1500                                SkVector* ppuScale,
   1501                                const SkIRect& clip, SkIRect* clipIRect) {
   1502     //TODO: currently ignoring the ppm if blur ignoring transform.
   1503     if (filter) {
   1504         SkMaskFilter::BlurInfo blurInfo;
   1505         SkMaskFilter::BlurType blurType = filter->asABlur(&blurInfo);
   1506 
   1507         if (SkMaskFilter::kNone_BlurType != blurType
   1508             && blurInfo.fIgnoreTransform) {
   1509 
   1510             ppuScale->fX = SK_Scalar1;
   1511             ppuScale->fY = SK_Scalar1;
   1512             *clipIRect = clip;
   1513             return;
   1514         }
   1515     }
   1516 
   1517     //This action is in unit space, but the ppm is specified in physical space.
   1518     ppuScale->fX = SkScalarDiv(this->fCurrentPixelsPerMeter.fX,
   1519                                this->fCurrentUnitsPerMeter.fX);
   1520     ppuScale->fY = SkScalarDiv(this->fCurrentPixelsPerMeter.fY,
   1521                                this->fCurrentUnitsPerMeter.fY);
   1522 
   1523     matrix->postScale(ppuScale->fX, ppuScale->fY);
   1524 
   1525     const SkIRect& irect = clip;
   1526     SkRect clipRect = SkRect::MakeLTRB(
   1527         SkScalarMul(SkIntToScalar(irect.fLeft), ppuScale->fX),
   1528         SkScalarMul(SkIntToScalar(irect.fTop), ppuScale->fY),
   1529         SkScalarMul(SkIntToScalar(irect.fRight), ppuScale->fX),
   1530         SkScalarMul(SkIntToScalar(irect.fBottom), ppuScale->fY));
   1531     clipRect.roundOut(clipIRect);
   1532 }
   1533 
   1534 HRESULT SkXPSDevice::applyMask(const SkDraw& d,
   1535                                const SkMask& mask,
   1536                                const SkVector& ppuScale,
   1537                                IXpsOMPath* shadedPath) {
   1538     //Get the geometry object.
   1539     SkTScopedComPtr<IXpsOMGeometry> shadedGeometry;
   1540     HRM(shadedPath->GetGeometry(&shadedGeometry),
   1541         "Could not get mask shaded geometry.");
   1542 
   1543     //Get the figures from the geometry.
   1544     SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures;
   1545     HRM(shadedGeometry->GetFigures(&shadedFigures),
   1546         "Could not get mask shaded figures.");
   1547 
   1548     SkMatrix m;
   1549     m.reset();
   1550     m.setTranslate(SkIntToScalar(mask.fBounds.fLeft),
   1551                    SkIntToScalar(mask.fBounds.fTop));
   1552     m.postScale(SkScalarInvert(ppuScale.fX), SkScalarInvert(ppuScale.fY));
   1553 
   1554     SkShader::TileMode xy[2];
   1555     xy[0] = (SkShader::TileMode)3;
   1556     xy[1] = (SkShader::TileMode)3;
   1557 
   1558     SkBitmap bm;
   1559     bm.setConfig(SkBitmap::kA8_Config,
   1560                  mask.fBounds.width(),
   1561                  mask.fBounds.height(),
   1562                  mask.fRowBytes);
   1563     bm.setPixels(mask.fImage);
   1564 
   1565     SkTScopedComPtr<IXpsOMTileBrush> maskBrush;
   1566     HR(this->createXpsImageBrush(bm, m, xy, 0xFF, &maskBrush));
   1567     HRM(shadedPath->SetOpacityMaskBrushLocal(maskBrush.get()),
   1568         "Could not set mask.");
   1569 
   1570     const SkRect universeRect = SkRect::MakeLTRB(0, 0,
   1571         this->fCurrentCanvasSize.fWidth, this->fCurrentCanvasSize.fHeight);
   1572     SkTScopedComPtr<IXpsOMGeometryFigure> shadedFigure;
   1573     HRM(this->createXpsRect(universeRect, FALSE, TRUE, &shadedFigure),
   1574         "Could not create mask shaded figure.");
   1575     HRM(shadedFigures->Append(shadedFigure.get()),
   1576         "Could not add mask shaded figure.");
   1577 
   1578     HR(this->clip(shadedPath, d));
   1579 
   1580     //Add the path to the active visual collection.
   1581     SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals;
   1582     HRM(this->fCurrentXpsCanvas->GetVisuals(&currentVisuals),
   1583         "Could not get mask current visuals.");
   1584     HRM(currentVisuals->Append(shadedPath),
   1585         "Could not add masked shaded path to current visuals.");
   1586 
   1587     return S_OK;
   1588 }
   1589 
   1590 HRESULT SkXPSDevice::shadePath(IXpsOMPath* shadedPath,
   1591                                const SkPaint& shaderPaint,
   1592                                const SkMatrix& matrix,
   1593                                BOOL* fill, BOOL* stroke) {
   1594     *fill = FALSE;
   1595     *stroke = FALSE;
   1596 
   1597     const SkPaint::Style style = shaderPaint.getStyle();
   1598     const bool hasFill = SkPaint::kFill_Style == style
   1599                       || SkPaint::kStrokeAndFill_Style == style;
   1600     const bool hasStroke = SkPaint::kStroke_Style == style
   1601                         || SkPaint::kStrokeAndFill_Style == style;
   1602 
   1603     //TODO(bungeman): use dictionaries and lookups.
   1604     if (hasFill) {
   1605         *fill = TRUE;
   1606         SkTScopedComPtr<IXpsOMBrush> fillBrush;
   1607         HR(this->createXpsBrush(shaderPaint, &fillBrush, &matrix));
   1608         HRM(shadedPath->SetFillBrushLocal(fillBrush.get()),
   1609             "Could not set fill for shaded path.");
   1610     }
   1611 
   1612     if (hasStroke) {
   1613         *stroke = TRUE;
   1614         SkTScopedComPtr<IXpsOMBrush> strokeBrush;
   1615         HR(this->createXpsBrush(shaderPaint, &strokeBrush, &matrix));
   1616         HRM(shadedPath->SetStrokeBrushLocal(strokeBrush.get()),
   1617             "Could not set stroke brush for shaded path.");
   1618         HRM(shadedPath->SetStrokeThickness(
   1619                 SkScalarToFLOAT(shaderPaint.getStrokeWidth())),
   1620             "Could not set shaded path stroke thickness.");
   1621 
   1622         if (0 == shaderPaint.getStrokeWidth()) {
   1623             //XPS hair width is a hack. (XPS Spec 11.6.12).
   1624             SkTScopedComPtr<IXpsOMDashCollection> dashes;
   1625             HRM(shadedPath->GetStrokeDashes(&dashes),
   1626                 "Could not set dashes for shaded path.");
   1627             XPS_DASH dash;
   1628             dash.length = 1.0;
   1629             dash.gap = 0.0;
   1630             HRM(dashes->Append(&dash), "Could not add dashes to shaded path.");
   1631             HRM(shadedPath->SetStrokeDashOffset(-2.0),
   1632                 "Could not set dash offset for shaded path.");
   1633         }
   1634     }
   1635     return S_OK;
   1636 }
   1637 
   1638 void SkXPSDevice::drawPath(const SkDraw& d,
   1639                            const SkPath& platonicPath,
   1640                            const SkPaint& origPaint,
   1641                            const SkMatrix* prePathMatrix,
   1642                            bool pathIsMutable) {
   1643     SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
   1644 
   1645     // nothing to draw
   1646     if (d.fClip->isEmpty() ||
   1647         (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
   1648         return;
   1649     }
   1650 
   1651     SkPath modifiedPath;
   1652     const bool paintHasPathEffect = paint->getPathEffect()
   1653                                  || paint->getStyle() != SkPaint::kFill_Style;
   1654 
   1655     //Apply pre-path matrix [Platonic-path -> Skeletal-path].
   1656     SkMatrix matrix = *d.fMatrix;
   1657     SkPath* skeletalPath = const_cast<SkPath*>(&platonicPath);
   1658     if (prePathMatrix) {
   1659         if (paintHasPathEffect || paint->getRasterizer()) {
   1660             if (!pathIsMutable) {
   1661                 skeletalPath = &modifiedPath;
   1662                 pathIsMutable = true;
   1663             }
   1664             platonicPath.transform(*prePathMatrix, skeletalPath);
   1665         } else {
   1666             if (!matrix.preConcat(*prePathMatrix)) {
   1667                 return;
   1668             }
   1669         }
   1670     }
   1671 
   1672     //Apply path effect [Skeletal-path -> Fillable-path].
   1673     SkPath* fillablePath = skeletalPath;
   1674     if (paintHasPathEffect) {
   1675         if (!pathIsMutable) {
   1676             fillablePath = &modifiedPath;
   1677             pathIsMutable = true;
   1678         }
   1679         bool fill = paint->getFillPath(*skeletalPath, fillablePath);
   1680 
   1681         SkPaint* writablePaint = paint.writable();
   1682         writablePaint->setPathEffect(NULL);
   1683         if (fill) {
   1684             writablePaint->setStyle(SkPaint::kFill_Style);
   1685         } else {
   1686             writablePaint->setStyle(SkPaint::kStroke_Style);
   1687             writablePaint->setStrokeWidth(0);
   1688         }
   1689     }
   1690 
   1691     //Create the shaded path. This will be the path which is painted.
   1692     SkTScopedComPtr<IXpsOMPath> shadedPath;
   1693     HRVM(this->fXpsFactory->CreatePath(&shadedPath),
   1694          "Could not create shaded path for path.");
   1695 
   1696     //Create the geometry for the shaded path.
   1697     SkTScopedComPtr<IXpsOMGeometry> shadedGeometry;
   1698     HRVM(this->fXpsFactory->CreateGeometry(&shadedGeometry),
   1699          "Could not create shaded geometry for path.");
   1700 
   1701     //Add the geometry to the shaded path.
   1702     HRVM(shadedPath->SetGeometryLocal(shadedGeometry.get()),
   1703          "Could not add the shaded geometry to shaded path.");
   1704 
   1705     SkRasterizer* rasterizer = paint->getRasterizer();
   1706     SkMaskFilter* filter = paint->getMaskFilter();
   1707 
   1708     //Determine if we will draw or shade and mask.
   1709     if (rasterizer || filter) {
   1710         if (paint->getStyle() != SkPaint::kFill_Style) {
   1711             paint.writable()->setStyle(SkPaint::kFill_Style);
   1712         }
   1713     }
   1714 
   1715     //Set the brushes.
   1716     BOOL fill;
   1717     BOOL stroke;
   1718     HRV(this->shadePath(shadedPath.get(),
   1719                         *paint,
   1720                         *d.fMatrix,
   1721                         &fill,
   1722                         &stroke));
   1723 
   1724     //Rasterizer
   1725     if (rasterizer) {
   1726         SkIRect clipIRect;
   1727         SkVector ppuScale;
   1728         this->convertToPpm(filter,
   1729                            &matrix,
   1730                            &ppuScale,
   1731                            d.fClip->getBounds(),
   1732                            &clipIRect);
   1733 
   1734         SkMask* mask = NULL;
   1735 
   1736         //[Fillable-path -> Mask]
   1737         SkMask rasteredMask;
   1738         if (rasterizer->rasterize(
   1739                 *fillablePath,
   1740                 matrix,
   1741                 &clipIRect,
   1742                 filter,  //just to compute how much to draw.
   1743                 &rasteredMask,
   1744                 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
   1745 
   1746             SkAutoMaskFreeImage rasteredAmi(rasteredMask.fImage);
   1747             mask = &rasteredMask;
   1748 
   1749             //[Mask -> Mask]
   1750             SkMask filteredMask;
   1751             if (filter &&
   1752                 filter->filterMask(&filteredMask, *mask, *d.fMatrix, NULL)) {
   1753 
   1754                 mask = &filteredMask;
   1755             } else {
   1756                 filteredMask.fImage = NULL;
   1757             }
   1758             SkAutoMaskFreeImage filteredAmi(filteredMask.fImage);
   1759 
   1760             //Draw mask.
   1761             HRV(this->applyMask(d, *mask, ppuScale, shadedPath.get()));
   1762         }
   1763         return;
   1764     }
   1765 
   1766     //Mask filter
   1767     if (filter) {
   1768         SkIRect clipIRect;
   1769         SkVector ppuScale;
   1770         this->convertToPpm(filter,
   1771                            &matrix,
   1772                            &ppuScale,
   1773                            d.fClip->getBounds(),
   1774                            &clipIRect);
   1775 
   1776         //[Fillable-path -> Pixel-path]
   1777         SkPath* pixelPath = pathIsMutable ? fillablePath : &modifiedPath;
   1778         fillablePath->transform(matrix, pixelPath);
   1779 
   1780         SkMask* mask = NULL;
   1781 
   1782         //[Pixel-path -> Mask]
   1783         SkMask rasteredMask;
   1784         if (SkDraw::DrawToMask(
   1785                         *pixelPath,
   1786                         &clipIRect,
   1787                         filter,  //just to compute how much to draw.
   1788                         &matrix,
   1789                         &rasteredMask,
   1790                         SkMask::kComputeBoundsAndRenderImage_CreateMode,
   1791                         paint->getStyle())) {
   1792 
   1793             SkAutoMaskFreeImage rasteredAmi(rasteredMask.fImage);
   1794             mask = &rasteredMask;
   1795 
   1796             //[Mask -> Mask]
   1797             SkMask filteredMask;
   1798             if (filter->filterMask(&filteredMask,
   1799                                    rasteredMask,
   1800                                    matrix,
   1801                                    NULL)) {
   1802                 mask = &filteredMask;
   1803             } else {
   1804                 filteredMask.fImage = NULL;
   1805             }
   1806             SkAutoMaskFreeImage filteredAmi(filteredMask.fImage);
   1807 
   1808             //Draw mask.
   1809             HRV(this->applyMask(d, *mask, ppuScale, shadedPath.get()));
   1810         }
   1811         return;
   1812     }
   1813 
   1814     //Get the figures from the shaded geometry.
   1815     SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures;
   1816     HRVM(shadedGeometry->GetFigures(&shadedFigures),
   1817          "Could not get shaded figures for shaded path.");
   1818 
   1819     bool xpsTransformsPath = true;
   1820 
   1821     //Set the fill rule.
   1822     XPS_FILL_RULE xpsFillRule;
   1823     switch (platonicPath.getFillType()) {
   1824         case SkPath::kWinding_FillType:
   1825             xpsFillRule = XPS_FILL_RULE_NONZERO;
   1826             break;
   1827         case SkPath::kEvenOdd_FillType:
   1828             xpsFillRule = XPS_FILL_RULE_EVENODD;
   1829             break;
   1830         case SkPath::kInverseWinding_FillType: {
   1831             //[Fillable-path -> Device-path]
   1832             SkPath* devicePath = pathIsMutable ? fillablePath : &modifiedPath;
   1833             fillablePath->transform(matrix, devicePath);
   1834 
   1835             HRV(this->drawInverseWindingPath(d,
   1836                                              *devicePath,
   1837                                              shadedPath.get()));
   1838             return;
   1839         }
   1840         case SkPath::kInverseEvenOdd_FillType: {
   1841             const SkRect universe = SkRect::MakeLTRB(
   1842                 0, 0,
   1843                 this->fCurrentCanvasSize.fWidth,
   1844                 this->fCurrentCanvasSize.fHeight);
   1845             SkTScopedComPtr<IXpsOMGeometryFigure> addOneFigure;
   1846             HRV(this->createXpsRect(universe, FALSE, TRUE, &addOneFigure));
   1847             HRVM(shadedFigures->Append(addOneFigure.get()),
   1848                  "Could not add even-odd flip figure to shaded path.");
   1849             xpsTransformsPath = false;
   1850             xpsFillRule = XPS_FILL_RULE_EVENODD;
   1851             break;
   1852         }
   1853         default:
   1854             SkASSERT(!"Unknown SkPath::FillType.");
   1855     }
   1856     HRVM(shadedGeometry->SetFillRule(xpsFillRule),
   1857          "Could not set fill rule for shaded path.");
   1858 
   1859     //Create the XPS transform, if possible.
   1860     if (xpsTransformsPath) {
   1861         SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform;
   1862         HRV(this->createXpsTransform(matrix, &xpsTransform));
   1863 
   1864         if (xpsTransform.get()) {
   1865             HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()),
   1866                  "Could not set transform on shaded path.");
   1867         } else {
   1868             xpsTransformsPath = false;
   1869         }
   1870     }
   1871 
   1872     SkPath* devicePath = fillablePath;
   1873     if (!xpsTransformsPath) {
   1874         //[Fillable-path -> Device-path]
   1875         devicePath = pathIsMutable ? fillablePath : &modifiedPath;
   1876         fillablePath->transform(matrix, devicePath);
   1877     }
   1878     HRV(this->addXpsPathGeometry(shadedFigures.get(),
   1879                                  stroke, fill, *devicePath));
   1880 
   1881     HRV(this->clip(shadedPath.get(), d));
   1882 
   1883     //Add the path to the active visual collection.
   1884     SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals;
   1885     HRVM(this->fCurrentXpsCanvas->GetVisuals(&currentVisuals),
   1886          "Could not get current visuals for shaded path.");
   1887     HRVM(currentVisuals->Append(shadedPath.get()),
   1888          "Could not add shaded path to current visuals.");
   1889 }
   1890 
   1891 HRESULT SkXPSDevice::clip(IXpsOMVisual* xpsVisual, const SkDraw& d) {
   1892     SkPath clipPath;
   1893     SkAssertResult(d.fClip->getBoundaryPath(&clipPath));
   1894 
   1895     return this->clipToPath(xpsVisual, clipPath, XPS_FILL_RULE_EVENODD);
   1896 }
   1897 HRESULT SkXPSDevice::clipToPath(IXpsOMVisual* xpsVisual,
   1898                                 const SkPath& clipPath,
   1899                                 XPS_FILL_RULE fillRule) {
   1900     //Create the geometry.
   1901     SkTScopedComPtr<IXpsOMGeometry> clipGeometry;
   1902     HRM(this->fXpsFactory->CreateGeometry(&clipGeometry),
   1903         "Could not create clip geometry.");
   1904 
   1905     //Get the figure collection of the geometry.
   1906     SkTScopedComPtr<IXpsOMGeometryFigureCollection> clipFigures;
   1907     HRM(clipGeometry->GetFigures(&clipFigures),
   1908         "Could not get the clip figures.");
   1909 
   1910     //Create the figures into the geometry.
   1911     HR(this->addXpsPathGeometry(
   1912         clipFigures.get(),
   1913         FALSE, TRUE, clipPath));
   1914 
   1915     HRM(clipGeometry->SetFillRule(fillRule),
   1916         "Could not set fill rule.");
   1917     HRM(xpsVisual->SetClipGeometryLocal(clipGeometry.get()),
   1918         "Could not set clip geometry.");
   1919 
   1920     return S_OK;
   1921 }
   1922 
   1923 void SkXPSDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap,
   1924                              const SkIRect* srcRectOrNull,
   1925                              const SkMatrix& matrix, const SkPaint& paint) {
   1926     if (d.fClip->isEmpty()) {
   1927         return;
   1928     }
   1929 
   1930     SkIRect srcRect;
   1931     SkBitmap tmp;
   1932     const SkBitmap* bitmapPtr = &bitmap;
   1933     if (NULL == srcRectOrNull) {
   1934         srcRect.set(0, 0, bitmap.width(), bitmap.height());
   1935         bitmapPtr = &bitmap;
   1936     } else {
   1937         srcRect = *srcRectOrNull;
   1938         if (!bitmap.extractSubset(&tmp, srcRect)) {
   1939             return; // extraction failed
   1940         }
   1941         bitmapPtr = &tmp;
   1942     }
   1943 
   1944     //Create the new shaded path.
   1945     SkTScopedComPtr<IXpsOMPath> shadedPath;
   1946     HRVM(this->fXpsFactory->CreatePath(&shadedPath),
   1947          "Could not create path for bitmap.");
   1948 
   1949     //Create the shaded geometry.
   1950     SkTScopedComPtr<IXpsOMGeometry> shadedGeometry;
   1951     HRVM(this->fXpsFactory->CreateGeometry(&shadedGeometry),
   1952          "Could not create geometry for bitmap.");
   1953 
   1954     //Add the shaded geometry to the shaded path.
   1955     HRVM(shadedPath->SetGeometryLocal(shadedGeometry.get()),
   1956          "Could not set the geometry for bitmap.");
   1957 
   1958     //Get the shaded figures from the shaded geometry.
   1959     SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures;
   1960     HRVM(shadedGeometry->GetFigures(&shadedFigures),
   1961          "Could not get the figures for bitmap.");
   1962 
   1963     SkMatrix transform = matrix;
   1964     transform.postConcat(*d.fMatrix);
   1965 
   1966     SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform;
   1967     HRV(this->createXpsTransform(transform, &xpsTransform));
   1968     if (xpsTransform.get()) {
   1969         HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()),
   1970              "Could not set transform for bitmap.");
   1971     } else {
   1972         //TODO: perspective that bitmap!
   1973     }
   1974 
   1975     SkTScopedComPtr<IXpsOMGeometryFigure> rectFigure;
   1976     if (NULL != xpsTransform.get()) {
   1977         const SkShader::TileMode xy[2] = {
   1978             SkShader::kClamp_TileMode,
   1979             SkShader::kClamp_TileMode,
   1980         };
   1981         SkTScopedComPtr<IXpsOMTileBrush> xpsImageBrush;
   1982         HRV(this->createXpsImageBrush(*bitmapPtr,
   1983                                       transform,
   1984                                       xy,
   1985                                       paint.getAlpha(),
   1986                                       &xpsImageBrush));
   1987         HRVM(shadedPath->SetFillBrushLocal(xpsImageBrush.get()),
   1988              "Could not set bitmap brush.");
   1989 
   1990         const SkRect bitmapRect = SkRect::MakeLTRB(0, 0,
   1991             SkIntToScalar(srcRect.width()), SkIntToScalar(srcRect.height()));
   1992         HRV(this->createXpsRect(bitmapRect, FALSE, TRUE, &rectFigure));
   1993     }
   1994     HRVM(shadedFigures->Append(rectFigure.get()),
   1995          "Could not add bitmap figure.");
   1996 
   1997     //Get the current visual collection and add the shaded path to it.
   1998     SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals;
   1999     HRVM(this->fCurrentXpsCanvas->GetVisuals(&currentVisuals),
   2000          "Could not get current visuals for bitmap");
   2001     HRVM(currentVisuals->Append(shadedPath.get()),
   2002          "Could not add bitmap to current visuals.");
   2003 
   2004     HRV(this->clip(shadedPath.get(), d));
   2005 }
   2006 
   2007 void SkXPSDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap,
   2008                              int x, int y,
   2009                              const SkPaint& paint) {
   2010     //TODO: override this for XPS
   2011     SkDEBUGF(("XPS drawSprite not yet implemented."));
   2012 }
   2013 
   2014 HRESULT SkXPSDevice::CreateTypefaceUse(const SkPaint& paint,
   2015                                        TypefaceUse** typefaceUse) {
   2016     const SkTypeface* typeface = paint.getTypeface();
   2017 
   2018     //Check cache.
   2019     const SkFontID typefaceID = SkTypeface::UniqueID(typeface);
   2020     if (!this->fTypefaces.empty()) {
   2021         TypefaceUse* current = &this->fTypefaces.front();
   2022         const TypefaceUse* last = &this->fTypefaces.back();
   2023         for (; current <= last; ++current) {
   2024             if (current->typefaceId == typefaceID) {
   2025                 *typefaceUse = current;
   2026                 return S_OK;
   2027             }
   2028         }
   2029     }
   2030 
   2031     //TODO: create glyph only fonts
   2032     //and let the host deal with what kind of font we're looking at.
   2033     XPS_FONT_EMBEDDING embedding = XPS_FONT_EMBEDDING_RESTRICTED;
   2034 
   2035     SkTScopedComPtr<IStream> fontStream;
   2036     SkStream* fontData = SkFontHost::OpenStream(typefaceID);
   2037     HRM(SkIStream::CreateFromSkStream(fontData, true, &fontStream),
   2038         "Could not create font stream.");
   2039 
   2040     const size_t size =
   2041         SK_ARRAY_COUNT(L"/Resources/Fonts/" L_GUID_ID L".odttf");
   2042     wchar_t buffer[size];
   2043     wchar_t id[GUID_ID_LEN];
   2044     HR(create_id(id, GUID_ID_LEN));
   2045     swprintf_s(buffer, size, L"/Resources/Fonts/%s.odttf", id);
   2046 
   2047     SkTScopedComPtr<IOpcPartUri> partUri;
   2048     HRM(this->fXpsFactory->CreatePartUri(buffer, &partUri),
   2049         "Could not create font resource part uri.");
   2050 
   2051     SkTScopedComPtr<IXpsOMFontResource> xpsFontResource;
   2052     HRM(this->fXpsFactory->CreateFontResource(fontStream.get(),
   2053                                               embedding,
   2054                                               partUri.get(),
   2055                                               FALSE,
   2056                                               &xpsFontResource),
   2057         "Could not create font resource.");
   2058 
   2059     TypefaceUse& newTypefaceUse = this->fTypefaces.push_back();
   2060     newTypefaceUse.typefaceId = typefaceID;
   2061     newTypefaceUse.fontData = fontData;
   2062     newTypefaceUse.xpsFont = xpsFontResource.release();
   2063 
   2064     SkAutoGlyphCache agc = SkAutoGlyphCache(paint, NULL, &SkMatrix::I());
   2065     SkGlyphCache* glyphCache = agc.getCache();
   2066     unsigned int glyphCount = glyphCache->getGlyphCount();
   2067     newTypefaceUse.glyphsUsed = new SkBitSet(glyphCount);
   2068 
   2069     *typefaceUse = &newTypefaceUse;
   2070     return S_OK;
   2071 }
   2072 
   2073 HRESULT SkXPSDevice::AddGlyphs(const SkDraw& d,
   2074                                IXpsOMObjectFactory* xpsFactory,
   2075                                IXpsOMCanvas* canvas,
   2076                                IXpsOMFontResource* font,
   2077                                LPCWSTR text,
   2078                                XPS_GLYPH_INDEX* xpsGlyphs,
   2079                                UINT32 xpsGlyphsLen,
   2080                                XPS_POINT *origin,
   2081                                FLOAT fontSize,
   2082                                XPS_STYLE_SIMULATION sims,
   2083                                const SkMatrix& transform,
   2084                                const SkPaint& paint) {
   2085     SkTScopedComPtr<IXpsOMGlyphs> glyphs;
   2086     HRM(xpsFactory->CreateGlyphs(font, &glyphs), "Could not create glyphs.");
   2087 
   2088     //XPS uses affine transformations for everything...
   2089     //...except positioning text.
   2090     bool useCanvasForClip;
   2091     if ((transform.getType() & ~SkMatrix::kTranslate_Mask) == 0) {
   2092         origin->x += SkScalarToFLOAT(transform.getTranslateX());
   2093         origin->y += SkScalarToFLOAT(transform.getTranslateY());
   2094         useCanvasForClip = false;
   2095     } else {
   2096         SkTScopedComPtr<IXpsOMMatrixTransform> xpsMatrixToUse;
   2097         HR(this->createXpsTransform(transform, &xpsMatrixToUse));
   2098         if (xpsMatrixToUse.get()) {
   2099             HRM(glyphs->SetTransformLocal(xpsMatrixToUse.get()),
   2100                 "Could not set transform matrix.");
   2101             useCanvasForClip = true;
   2102         } else {
   2103             SkASSERT(!"Attempt to add glyphs in perspective.");
   2104             useCanvasForClip = false;
   2105         }
   2106     }
   2107 
   2108     SkTScopedComPtr<IXpsOMGlyphsEditor> glyphsEditor;
   2109     HRM(glyphs->GetGlyphsEditor(&glyphsEditor), "Could not get glyph editor.");
   2110 
   2111     if (NULL != text) {
   2112         HRM(glyphsEditor->SetUnicodeString(text),
   2113             "Could not set unicode string.");
   2114     }
   2115 
   2116     if (NULL != xpsGlyphs) {
   2117         HRM(glyphsEditor->SetGlyphIndices(xpsGlyphsLen, xpsGlyphs),
   2118             "Could not set glyphs.");
   2119     }
   2120 
   2121     HRM(glyphsEditor->ApplyEdits(), "Could not apply glyph edits.");
   2122 
   2123     SkTScopedComPtr<IXpsOMBrush> xpsFillBrush;
   2124     HR(this->createXpsBrush(
   2125             paint,
   2126             &xpsFillBrush,
   2127             useCanvasForClip ? NULL : &transform));
   2128 
   2129     HRM(glyphs->SetFillBrushLocal(xpsFillBrush.get()),
   2130         "Could not set fill brush.");
   2131 
   2132     HRM(glyphs->SetOrigin(origin), "Could not set glyph origin.");
   2133 
   2134     HRM(glyphs->SetFontRenderingEmSize(fontSize),
   2135         "Could not set font size.");
   2136 
   2137     HRM(glyphs->SetStyleSimulations(sims),
   2138         "Could not set style simulations.");
   2139 
   2140     SkTScopedComPtr<IXpsOMVisualCollection> visuals;
   2141     HRM(canvas->GetVisuals(&visuals), "Could not get glyph canvas visuals.");
   2142 
   2143     if (!useCanvasForClip) {
   2144         HR(this->clip(glyphs.get(), d));
   2145         HRM(visuals->Append(glyphs.get()), "Could not add glyphs to canvas.");
   2146     } else {
   2147         SkTScopedComPtr<IXpsOMCanvas> glyphCanvas;
   2148         HRM(this->fXpsFactory->CreateCanvas(&glyphCanvas),
   2149             "Could not create glyph canvas.");
   2150 
   2151         SkTScopedComPtr<IXpsOMVisualCollection> glyphCanvasVisuals;
   2152         HRM(glyphCanvas->GetVisuals(&glyphCanvasVisuals),
   2153             "Could not get glyph visuals collection.");
   2154 
   2155         HRM(glyphCanvasVisuals->Append(glyphs.get()),
   2156             "Could not add glyphs to page.");
   2157         HR(this->clip(glyphCanvas.get(), d));
   2158 
   2159         HRM(visuals->Append(glyphCanvas.get()),
   2160             "Could not add glyph canvas to page.");
   2161     }
   2162 
   2163     return S_OK;
   2164 }
   2165 
   2166 struct SkXPSDrawProcs : public SkDrawProcs {
   2167 public:
   2168     /** [in] Advance width and offsets for glyphs measured in
   2169     hundredths of the font em size (XPS Spec 5.1.3). */
   2170     FLOAT centemPerUnit;
   2171     /** [in,out] The accumulated glyphs used in the current typeface. */
   2172     SkBitSet* glyphUse;
   2173     /** [out] The glyphs to draw. */
   2174     SkTDArray<XPS_GLYPH_INDEX> xpsGlyphs;
   2175 };
   2176 
   2177 static void xps_draw_1_glyph(const SkDraw1Glyph& state,
   2178                              SkFixed x, SkFixed y,
   2179                              const SkGlyph& skGlyph) {
   2180     SkASSERT(skGlyph.fWidth > 0 && skGlyph.fHeight > 0);
   2181 
   2182     SkXPSDrawProcs* procs = static_cast<SkXPSDrawProcs*>(state.fDraw->fProcs);
   2183 
   2184     //Draw pre-adds half the sampling frequency for floor rounding.
   2185     if (state.fCache->isSubpixel()) {
   2186         x -= (SK_FixedHalf >> SkGlyph::kSubBits);
   2187         y -= (SK_FixedHalf >> SkGlyph::kSubBits);
   2188     } else {
   2189         x -= SK_FixedHalf;
   2190         y -= SK_FixedHalf;
   2191     }
   2192 
   2193     XPS_GLYPH_INDEX* xpsGlyph = procs->xpsGlyphs.append();
   2194     uint16_t glyphID = skGlyph.getGlyphID();
   2195     procs->glyphUse->setBit(glyphID, true);
   2196     xpsGlyph->index = glyphID;
   2197     if (1 == procs->xpsGlyphs.count()) {
   2198         xpsGlyph->advanceWidth = 0.0f;
   2199         xpsGlyph->horizontalOffset = SkFixedToFloat(x) * procs->centemPerUnit;
   2200         xpsGlyph->verticalOffset = SkFixedToFloat(y) * -procs->centemPerUnit;
   2201     } else {
   2202         const XPS_GLYPH_INDEX& first = procs->xpsGlyphs[0];
   2203         xpsGlyph->advanceWidth = 0.0f;
   2204         xpsGlyph->horizontalOffset = (SkFixedToFloat(x) * procs->centemPerUnit)
   2205                                      - first.horizontalOffset;
   2206         xpsGlyph->verticalOffset = (SkFixedToFloat(y) * -procs->centemPerUnit)
   2207                                    - first.verticalOffset;
   2208     }
   2209 }
   2210 
   2211 static void text_draw_init(const SkPaint& paint,
   2212                            const void* text, size_t byteLength,
   2213                            SkBitSet& glyphsUsed,
   2214                            SkDraw& myDraw, SkXPSDrawProcs& procs) {
   2215     procs.fD1GProc = xps_draw_1_glyph;
   2216     int numGlyphGuess;
   2217     switch (paint.getTextEncoding()) {
   2218         case SkPaint::kUTF8_TextEncoding:
   2219             numGlyphGuess = SkUTF8_CountUnichars(
   2220                 static_cast<const char *>(text),
   2221                 byteLength);
   2222             break;
   2223         case SkPaint::kUTF16_TextEncoding:
   2224             numGlyphGuess = SkUTF16_CountUnichars(
   2225                 static_cast<const uint16_t *>(text),
   2226                 byteLength);
   2227             break;
   2228         case SkPaint::kGlyphID_TextEncoding:
   2229             numGlyphGuess = byteLength / 2;
   2230             break;
   2231         default:
   2232             SK_DEBUGBREAK(true);
   2233     }
   2234     procs.xpsGlyphs.setReserve(numGlyphGuess);
   2235     procs.glyphUse = &glyphsUsed;
   2236     procs.centemPerUnit = 100.0f / SkScalarToFLOAT(paint.getTextSize());
   2237 
   2238     myDraw.fProcs = &procs;
   2239 }
   2240 
   2241 static bool text_must_be_pathed(const SkPaint& paint, const SkMatrix& matrix) {
   2242     const SkPaint::Style style = paint.getStyle();
   2243     return matrix.hasPerspective()
   2244         || SkPaint::kStroke_Style == style
   2245         || SkPaint::kStrokeAndFill_Style == style
   2246         || paint.getMaskFilter()
   2247         || paint.getRasterizer()
   2248     ;
   2249 }
   2250 
   2251 void SkXPSDevice::drawText(const SkDraw& d,
   2252                            const void* text, size_t byteLen,
   2253                            SkScalar x, SkScalar y,
   2254                            const SkPaint& paint) {
   2255     if (byteLen < 1) return;
   2256 
   2257     if (text_must_be_pathed(paint, *d.fMatrix)) {
   2258         SkPath path;
   2259         paint.getTextPath(text, byteLen, x, y, &path);
   2260         this->drawPath(d, path, paint, NULL, true);
   2261         //TODO: add automation "text"
   2262         return;
   2263     }
   2264 
   2265     TypefaceUse* typeface;
   2266     HRV(CreateTypefaceUse(paint, &typeface));
   2267 
   2268     SkDraw myDraw(d);
   2269     SkXPSDrawProcs procs;
   2270     text_draw_init(paint, text, byteLen, *typeface->glyphsUsed, myDraw, procs);
   2271 
   2272     myDraw.drawText(static_cast<const char*>(text), byteLen, x, y, paint);
   2273 
   2274     // SkDraw may have clipped out the glyphs, so we need to check
   2275     if (procs.xpsGlyphs.count() == 0) {
   2276         return;
   2277     }
   2278 
   2279     XPS_POINT origin = {
   2280         procs.xpsGlyphs[0].horizontalOffset / procs.centemPerUnit,
   2281         procs.xpsGlyphs[0].verticalOffset / -procs.centemPerUnit,
   2282     };
   2283     procs.xpsGlyphs[0].horizontalOffset = 0.0f;
   2284     procs.xpsGlyphs[0].verticalOffset = 0.0f;
   2285 
   2286     HRV(AddGlyphs(d,
   2287                   this->fXpsFactory.get(),
   2288                   this->fCurrentXpsCanvas.get(),
   2289                   typeface->xpsFont,
   2290                   NULL,
   2291                   procs.xpsGlyphs.begin(), procs.xpsGlyphs.count(),
   2292                   &origin,
   2293                   SkScalarToFLOAT(paint.getTextSize()),
   2294                   XPS_STYLE_SIMULATION_NONE,
   2295                   *d.fMatrix,
   2296                   paint));
   2297 }
   2298 
   2299 void SkXPSDevice::drawPosText(const SkDraw& d,
   2300                               const void* text, size_t byteLen,
   2301                               const SkScalar pos[],
   2302                               SkScalar constY, int scalarsPerPos,
   2303                               const SkPaint& paint) {
   2304     if (byteLen < 1) return;
   2305 
   2306     if (text_must_be_pathed(paint, *d.fMatrix)) {
   2307         SkPath path;
   2308         //TODO: make this work, Draw currently does not handle as well.
   2309         //paint.getTextPath(text, byteLength, x, y, &path);
   2310         //this->drawPath(d, path, paint, NULL, true);
   2311         //TODO: add automation "text"
   2312         return;
   2313     }
   2314 
   2315     TypefaceUse* typeface;
   2316     HRV(CreateTypefaceUse(paint, &typeface));
   2317 
   2318     SkDraw myDraw(d);
   2319     SkXPSDrawProcs procs;
   2320     text_draw_init(paint, text, byteLen, *typeface->glyphsUsed, myDraw, procs);
   2321 
   2322     myDraw.drawPosText(static_cast<const char*>(text), byteLen,
   2323                        pos, constY, scalarsPerPos,
   2324                        paint);
   2325 
   2326     // SkDraw may have clipped out the glyphs, so we need to check
   2327     if (procs.xpsGlyphs.count() == 0) {
   2328         return;
   2329     }
   2330 
   2331     XPS_POINT origin = {
   2332         procs.xpsGlyphs[0].horizontalOffset / procs.centemPerUnit,
   2333         procs.xpsGlyphs[0].verticalOffset / -procs.centemPerUnit,
   2334     };
   2335     procs.xpsGlyphs[0].horizontalOffset = 0.0f;
   2336     procs.xpsGlyphs[0].verticalOffset = 0.0f;
   2337 
   2338     HRV(AddGlyphs(d,
   2339                   this->fXpsFactory.get(),
   2340                   this->fCurrentXpsCanvas.get(),
   2341                   typeface->xpsFont,
   2342                   NULL,
   2343                   procs.xpsGlyphs.begin(), procs.xpsGlyphs.count(),
   2344                   &origin,
   2345                   SkScalarToFLOAT(paint.getTextSize()),
   2346                   XPS_STYLE_SIMULATION_NONE,
   2347                   *d.fMatrix,
   2348                   paint));
   2349 }
   2350 
   2351 void SkXPSDevice::drawTextOnPath(const SkDraw& d, const void* text, size_t len,
   2352                                  const SkPath& path, const SkMatrix* matrix,
   2353                                  const SkPaint& paint) {
   2354     //This will call back into the device to do the drawing.
   2355      d.drawTextOnPath((const char*)text, len, path, matrix, paint);
   2356 }
   2357 
   2358 void SkXPSDevice::drawDevice(const SkDraw& d, SkDevice* dev,
   2359                              int x, int y,
   2360                              const SkPaint&) {
   2361     SkXPSDevice* that = static_cast<SkXPSDevice*>(dev);
   2362 
   2363     SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform;
   2364     XPS_MATRIX rawTransform = {
   2365         1.0f,
   2366         0.0f,
   2367         0.0f,
   2368         1.0f,
   2369         static_cast<FLOAT>(x),
   2370         static_cast<FLOAT>(y),
   2371     };
   2372     HRVM(this->fXpsFactory->CreateMatrixTransform(&rawTransform, &xpsTransform),
   2373          "Could not create layer transform.");
   2374     HRVM(that->fCurrentXpsCanvas->SetTransformLocal(xpsTransform.get()),
   2375          "Could not set layer transform.");
   2376 
   2377     //Get the current visual collection and add the layer to it.
   2378     SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals;
   2379     HRVM(this->fCurrentXpsCanvas->GetVisuals(&currentVisuals),
   2380          "Could not get current visuals for layer.");
   2381     HRVM(currentVisuals->Append(that->fCurrentXpsCanvas.get()),
   2382          "Could not add layer to current visuals.");
   2383 }
   2384 
   2385 bool SkXPSDevice::onReadPixels(const SkBitmap& bitmap, int x, int y,
   2386                                SkCanvas::Config8888) {
   2387     return false;
   2388 }
   2389 
   2390 SkDevice* SkXPSDevice::onCreateCompatibleDevice(SkBitmap::Config config,
   2391                                                 int width, int height,
   2392                                                 bool isOpaque,
   2393                                                 Usage usage) {
   2394     if (SkDevice::kGeneral_Usage == usage) {
   2395         return NULL;
   2396         SK_CRASH();
   2397         //To what stream do we write?
   2398         //SkXPSDevice* dev = new SkXPSDevice(this);
   2399         //SkSize s = SkSize::Make(width, height);
   2400         //dev->BeginCanvas(s, s, SkMatrix::I());
   2401         //return dev;
   2402     }
   2403 
   2404     return new SkXPSDevice(this->fXpsFactory.get());
   2405 }
   2406 
   2407 SkXPSDevice::SkXPSDevice(IXpsOMObjectFactory* xpsFactory)
   2408     : SkDevice(make_fake_bitmap(10000, 10000))
   2409     , fCurrentPage(0) {
   2410 
   2411     HRVM(CoCreateInstance(
   2412              CLSID_XpsOMObjectFactory,
   2413              NULL,
   2414              CLSCTX_INPROC_SERVER,
   2415              IID_PPV_ARGS(&this->fXpsFactory)),
   2416          "Could not create factory for layer.");
   2417 
   2418     HRVM(this->fXpsFactory->CreateCanvas(&this->fCurrentXpsCanvas),
   2419          "Could not create canvas for layer.");
   2420 }
   2421 
   2422 bool SkXPSDevice::allowImageFilter(SkImageFilter*) {
   2423     return false;
   2424 }
   2425