gfx/skia/trunk/src/device/xps/SkXPSDevice.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial