1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/device/xps/SkXPSDevice.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2451 @@ 1.4 +/* 1.5 + * Copyright 2011 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#ifndef UNICODE 1.12 +#define UNICODE 1.13 +#endif 1.14 +#ifndef _UNICODE 1.15 +#define _UNICODE 1.16 +#endif 1.17 +#include "SkTypes.h" 1.18 +#include <ObjBase.h> 1.19 +#include <XpsObjectModel.h> 1.20 +#include <T2EmbApi.h> 1.21 +#include <FontSub.h> 1.22 + 1.23 +#include "SkColor.h" 1.24 +#include "SkConstexprMath.h" 1.25 +#include "SkData.h" 1.26 +#include "SkDraw.h" 1.27 +#include "SkDrawProcs.h" 1.28 +#include "SkEndian.h" 1.29 +#include "SkFontHost.h" 1.30 +#include "SkGlyphCache.h" 1.31 +#include "SkHRESULT.h" 1.32 +#include "SkImageEncoder.h" 1.33 +#include "SkIStream.h" 1.34 +#include "SkMaskFilter.h" 1.35 +#include "SkPaint.h" 1.36 +#include "SkPoint.h" 1.37 +#include "SkRasterizer.h" 1.38 +#include "SkSFNTHeader.h" 1.39 +#include "SkShader.h" 1.40 +#include "SkSize.h" 1.41 +#include "SkStream.h" 1.42 +#include "SkTDArray.h" 1.43 +#include "SkTLazy.h" 1.44 +#include "SkTScopedComPtr.h" 1.45 +#include "SkTTCFHeader.h" 1.46 +#include "SkTypefacePriv.h" 1.47 +#include "SkUtils.h" 1.48 +#include "SkXPSDevice.h" 1.49 + 1.50 +//Windows defines a FLOAT type, 1.51 +//make it clear when converting a scalar that this is what is wanted. 1.52 +#define SkScalarToFLOAT(n) SkScalarToFloat(n) 1.53 + 1.54 +//Dummy representation of a GUID from create_id. 1.55 +#define L_GUID_ID L"XXXXXXXXsXXXXsXXXXsXXXXsXXXXXXXXXXXX" 1.56 +//Length of GUID representation from create_id, including NULL terminator. 1.57 +#define GUID_ID_LEN SK_ARRAY_COUNT(L_GUID_ID) 1.58 + 1.59 +/** 1.60 + Formats a GUID and places it into buffer. 1.61 + buffer should have space for at least GUID_ID_LEN wide characters. 1.62 + The string will always be wchar null terminated. 1.63 + XXXXXXXXsXXXXsXXXXsXXXXsXXXXXXXXXXXX0 1.64 + @return -1 if there was an error, > 0 if success. 1.65 + */ 1.66 +static int format_guid(const GUID& guid, 1.67 + wchar_t* buffer, size_t bufferSize, 1.68 + wchar_t sep = '-') { 1.69 + SkASSERT(bufferSize >= GUID_ID_LEN); 1.70 + return swprintf_s(buffer, 1.71 + bufferSize, 1.72 + L"%08lX%c%04X%c%04X%c%02X%02X%c%02X%02X%02X%02X%02X%02X", 1.73 + guid.Data1, 1.74 + sep, 1.75 + guid.Data2, 1.76 + sep, 1.77 + guid.Data3, 1.78 + sep, 1.79 + guid.Data4[0], 1.80 + guid.Data4[1], 1.81 + sep, 1.82 + guid.Data4[2], 1.83 + guid.Data4[3], 1.84 + guid.Data4[4], 1.85 + guid.Data4[5], 1.86 + guid.Data4[6], 1.87 + guid.Data4[7]); 1.88 +} 1.89 + 1.90 +/** 1.91 + Creates a GUID based id and places it into buffer. 1.92 + buffer should have space for at least GUID_ID_LEN wide characters. 1.93 + The string will always be wchar null terminated. 1.94 + XXXXXXXXsXXXXsXXXXsXXXXsXXXXXXXXXXXX0 1.95 + The string may begin with a digit, 1.96 + and so may not be suitable as a bare resource key. 1.97 + */ 1.98 +static HRESULT create_id(wchar_t* buffer, size_t bufferSize, 1.99 + wchar_t sep = '-') { 1.100 + GUID guid = {}; 1.101 + HRM(CoCreateGuid(&guid), "Could not create GUID for id."); 1.102 + 1.103 + if (format_guid(guid, buffer, bufferSize, sep) == -1) { 1.104 + HRM(E_UNEXPECTED, "Could not format GUID into id."); 1.105 + } 1.106 + 1.107 + return S_OK; 1.108 +} 1.109 + 1.110 +static SkBitmap make_fake_bitmap(int width, int height) { 1.111 + SkBitmap bitmap; 1.112 + bitmap.setConfig(SkImageInfo::MakeUnknown(width, height)); 1.113 + return bitmap; 1.114 +} 1.115 + 1.116 +// TODO: should inherit from SkBaseDevice instead of SkBitmapDevice... 1.117 +SkXPSDevice::SkXPSDevice() 1.118 + : SkBitmapDevice(make_fake_bitmap(10000, 10000)) 1.119 + , fCurrentPage(0) { 1.120 +} 1.121 + 1.122 +SkXPSDevice::~SkXPSDevice() { 1.123 +} 1.124 + 1.125 +SkXPSDevice::TypefaceUse::TypefaceUse() 1.126 + : typefaceId(0xffffffff) 1.127 + , fontData(NULL) 1.128 + , xpsFont(NULL) 1.129 + , glyphsUsed(NULL) { 1.130 +} 1.131 + 1.132 +SkXPSDevice::TypefaceUse::~TypefaceUse() { 1.133 + //xpsFont owns fontData ref 1.134 + this->xpsFont->Release(); 1.135 + delete this->glyphsUsed; 1.136 +} 1.137 + 1.138 +bool SkXPSDevice::beginPortfolio(SkWStream* outputStream) { 1.139 + if (!this->fAutoCo.succeeded()) return false; 1.140 + 1.141 + //Create XPS Factory. 1.142 + HRBM(CoCreateInstance( 1.143 + CLSID_XpsOMObjectFactory, 1.144 + NULL, 1.145 + CLSCTX_INPROC_SERVER, 1.146 + IID_PPV_ARGS(&this->fXpsFactory)), 1.147 + "Could not create XPS factory."); 1.148 + 1.149 + HRBM(SkWIStream::CreateFromSkWStream(outputStream, &this->fOutputStream), 1.150 + "Could not convert SkStream to IStream."); 1.151 + 1.152 + return true; 1.153 +} 1.154 + 1.155 +bool SkXPSDevice::beginSheet( 1.156 + const SkVector& unitsPerMeter, 1.157 + const SkVector& pixelsPerMeter, 1.158 + const SkSize& trimSize, 1.159 + const SkRect* mediaBox, 1.160 + const SkRect* bleedBox, 1.161 + const SkRect* artBox, 1.162 + const SkRect* cropBox) { 1.163 + ++this->fCurrentPage; 1.164 + 1.165 + //For simplicity, just write everything out in geometry units, 1.166 + //then have a base canvas do the scale to physical units. 1.167 + this->fCurrentCanvasSize = trimSize; 1.168 + this->fCurrentUnitsPerMeter = unitsPerMeter; 1.169 + this->fCurrentPixelsPerMeter = pixelsPerMeter; 1.170 + 1.171 + this->fCurrentXpsCanvas.reset(); 1.172 + HRBM(this->fXpsFactory->CreateCanvas(&this->fCurrentXpsCanvas), 1.173 + "Could not create base canvas."); 1.174 + 1.175 + return true; 1.176 +} 1.177 + 1.178 +HRESULT SkXPSDevice::createXpsThumbnail(IXpsOMPage* page, 1.179 + const unsigned int pageNum, 1.180 + IXpsOMImageResource** image) { 1.181 + SkTScopedComPtr<IXpsOMThumbnailGenerator> thumbnailGenerator; 1.182 + HRM(CoCreateInstance( 1.183 + CLSID_XpsOMThumbnailGenerator, 1.184 + NULL, 1.185 + CLSCTX_INPROC_SERVER, 1.186 + IID_PPV_ARGS(&thumbnailGenerator)), 1.187 + "Could not create thumbnail generator."); 1.188 + 1.189 + SkTScopedComPtr<IOpcPartUri> partUri; 1.190 + static const size_t size = SkTUMax< 1.191 + SK_ARRAY_COUNT(L"/Documents/1/Metadata/.png") + SK_DIGITS_IN(pageNum), 1.192 + SK_ARRAY_COUNT(L"/Metadata/" L_GUID_ID L".png") 1.193 + >::value; 1.194 + wchar_t buffer[size]; 1.195 + if (pageNum > 0) { 1.196 + swprintf_s(buffer, size, L"/Documents/1/Metadata/%u.png", pageNum); 1.197 + } else { 1.198 + wchar_t id[GUID_ID_LEN]; 1.199 + HR(create_id(id, GUID_ID_LEN)); 1.200 + swprintf_s(buffer, size, L"/Metadata/%s.png", id); 1.201 + } 1.202 + HRM(this->fXpsFactory->CreatePartUri(buffer, &partUri), 1.203 + "Could not create thumbnail part uri."); 1.204 + 1.205 + HRM(thumbnailGenerator->GenerateThumbnail(page, 1.206 + XPS_IMAGE_TYPE_PNG, 1.207 + XPS_THUMBNAIL_SIZE_LARGE, 1.208 + partUri.get(), 1.209 + image), 1.210 + "Could not generate thumbnail."); 1.211 + 1.212 + return S_OK; 1.213 +} 1.214 + 1.215 +HRESULT SkXPSDevice::createXpsPage(const XPS_SIZE& pageSize, 1.216 + IXpsOMPage** page) { 1.217 + static const size_t size = SK_ARRAY_COUNT(L"/Documents/1/Pages/.fpage") 1.218 + + SK_DIGITS_IN(fCurrentPage); 1.219 + wchar_t buffer[size]; 1.220 + swprintf_s(buffer, size, L"/Documents/1/Pages/%u.fpage", 1.221 + this->fCurrentPage); 1.222 + SkTScopedComPtr<IOpcPartUri> partUri; 1.223 + HRM(this->fXpsFactory->CreatePartUri(buffer, &partUri), 1.224 + "Could not create page part uri."); 1.225 + 1.226 + //If the language is unknown, use "und" (XPS Spec 2.3.5.1). 1.227 + HRM(this->fXpsFactory->CreatePage(&pageSize, 1.228 + L"und", 1.229 + partUri.get(), 1.230 + page), 1.231 + "Could not create page."); 1.232 + 1.233 + return S_OK; 1.234 +} 1.235 + 1.236 +HRESULT SkXPSDevice::initXpsDocumentWriter(IXpsOMImageResource* image) { 1.237 + //Create package writer. 1.238 + { 1.239 + SkTScopedComPtr<IOpcPartUri> partUri; 1.240 + HRM(this->fXpsFactory->CreatePartUri(L"/FixedDocumentSequence.fdseq", 1.241 + &partUri), 1.242 + "Could not create document sequence part uri."); 1.243 + HRM(this->fXpsFactory->CreatePackageWriterOnStream( 1.244 + this->fOutputStream.get(), 1.245 + TRUE, 1.246 + XPS_INTERLEAVING_OFF, //XPS_INTERLEAVING_ON, 1.247 + partUri.get(), 1.248 + NULL, 1.249 + image, 1.250 + NULL, 1.251 + NULL, 1.252 + &this->fPackageWriter), 1.253 + "Could not create package writer."); 1.254 + } 1.255 + 1.256 + //Begin the lone document. 1.257 + { 1.258 + SkTScopedComPtr<IOpcPartUri> partUri; 1.259 + HRM(this->fXpsFactory->CreatePartUri( 1.260 + L"/Documents/1/FixedDocument.fdoc", 1.261 + &partUri), 1.262 + "Could not create fixed document part uri."); 1.263 + HRM(this->fPackageWriter->StartNewDocument(partUri.get(), 1.264 + NULL, 1.265 + NULL, 1.266 + NULL, 1.267 + NULL), 1.268 + "Could not start document."); 1.269 + } 1.270 + 1.271 + return S_OK; 1.272 +} 1.273 + 1.274 +bool SkXPSDevice::endSheet() { 1.275 + //XPS is fixed at 96dpi (XPS Spec 11.1). 1.276 + static const float xpsDPI = 96.0f; 1.277 + static const float inchesPerMeter = 10000.0f / 254.0f; 1.278 + static const float targetUnitsPerMeter = xpsDPI * inchesPerMeter; 1.279 + const float scaleX = targetUnitsPerMeter 1.280 + / SkScalarToFLOAT(this->fCurrentUnitsPerMeter.fX); 1.281 + const float scaleY = targetUnitsPerMeter 1.282 + / SkScalarToFLOAT(this->fCurrentUnitsPerMeter.fY); 1.283 + 1.284 + //Create the scale canvas. 1.285 + SkTScopedComPtr<IXpsOMCanvas> scaleCanvas; 1.286 + HRBM(this->fXpsFactory->CreateCanvas(&scaleCanvas), 1.287 + "Could not create scale canvas."); 1.288 + SkTScopedComPtr<IXpsOMVisualCollection> scaleCanvasVisuals; 1.289 + HRBM(scaleCanvas->GetVisuals(&scaleCanvasVisuals), 1.290 + "Could not get scale canvas visuals."); 1.291 + 1.292 + SkTScopedComPtr<IXpsOMMatrixTransform> geomToPhys; 1.293 + XPS_MATRIX rawGeomToPhys = { scaleX, 0, 0, scaleY, 0, 0, }; 1.294 + HRBM(this->fXpsFactory->CreateMatrixTransform(&rawGeomToPhys, &geomToPhys), 1.295 + "Could not create geometry to physical transform."); 1.296 + HRBM(scaleCanvas->SetTransformLocal(geomToPhys.get()), 1.297 + "Could not set transform on scale canvas."); 1.298 + 1.299 + //Add the content canvas to the scale canvas. 1.300 + HRBM(scaleCanvasVisuals->Append(this->fCurrentXpsCanvas.get()), 1.301 + "Could not add base canvas to scale canvas."); 1.302 + 1.303 + //Create the page. 1.304 + XPS_SIZE pageSize = { 1.305 + SkScalarToFLOAT(this->fCurrentCanvasSize.width()) * scaleX, 1.306 + SkScalarToFLOAT(this->fCurrentCanvasSize.height()) * scaleY, 1.307 + }; 1.308 + SkTScopedComPtr<IXpsOMPage> page; 1.309 + HRB(this->createXpsPage(pageSize, &page)); 1.310 + 1.311 + SkTScopedComPtr<IXpsOMVisualCollection> pageVisuals; 1.312 + HRBM(page->GetVisuals(&pageVisuals), "Could not get page visuals."); 1.313 + 1.314 + //Add the scale canvas to the page. 1.315 + HRBM(pageVisuals->Append(scaleCanvas.get()), 1.316 + "Could not add scale canvas to page."); 1.317 + 1.318 + //Create the package writer if it hasn't been created yet. 1.319 + if (NULL == this->fPackageWriter.get()) { 1.320 + SkTScopedComPtr<IXpsOMImageResource> image; 1.321 + //Ignore return, thumbnail is completely optional. 1.322 + this->createXpsThumbnail(page.get(), 0, &image); 1.323 + 1.324 + HRB(this->initXpsDocumentWriter(image.get())); 1.325 + } 1.326 + 1.327 + HRBM(this->fPackageWriter->AddPage(page.get(), 1.328 + &pageSize, 1.329 + NULL, 1.330 + NULL, 1.331 + NULL, 1.332 + NULL), 1.333 + "Could not write the page."); 1.334 + this->fCurrentXpsCanvas.reset(); 1.335 + 1.336 + return true; 1.337 +} 1.338 + 1.339 +static HRESULT subset_typeface(SkXPSDevice::TypefaceUse* current) { 1.340 + //CreateFontPackage wants unsigned short. 1.341 + //Microsoft, Y U NO stdint.h? 1.342 + SkTDArray<unsigned short> keepList; 1.343 + current->glyphsUsed->exportTo(&keepList); 1.344 + 1.345 + int ttcCount = (current->ttcIndex + 1); 1.346 + 1.347 + //The following are declared with the types required by CreateFontPackage. 1.348 + unsigned char *fontPackageBufferRaw = NULL; 1.349 + unsigned long fontPackageBufferSize; 1.350 + unsigned long bytesWritten; 1.351 + unsigned long result = CreateFontPackage( 1.352 + (unsigned char *) current->fontData->getMemoryBase(), 1.353 + (unsigned long) current->fontData->getLength(), 1.354 + &fontPackageBufferRaw, 1.355 + &fontPackageBufferSize, 1.356 + &bytesWritten, 1.357 + TTFCFP_FLAGS_SUBSET | TTFCFP_FLAGS_GLYPHLIST | (ttcCount > 0 ? TTFCFP_FLAGS_TTC : 0), 1.358 + current->ttcIndex, 1.359 + TTFCFP_SUBSET, 1.360 + 0, 1.361 + 0, 1.362 + 0, 1.363 + keepList.begin(), 1.364 + keepList.count(), 1.365 + sk_malloc_throw, 1.366 + sk_realloc_throw, 1.367 + sk_free, 1.368 + NULL); 1.369 + SkAutoTMalloc<unsigned char> fontPackageBuffer(fontPackageBufferRaw); 1.370 + if (result != NO_ERROR) { 1.371 + SkDEBUGF(("CreateFontPackage Error %lu", result)); 1.372 + return E_UNEXPECTED; 1.373 + } 1.374 + 1.375 + // If it was originally a ttc, keep it a ttc. 1.376 + // CreateFontPackage over-allocates, realloc usually decreases the size substantially. 1.377 + size_t extra; 1.378 + if (ttcCount > 0) { 1.379 + // Create space for a ttc header. 1.380 + extra = sizeof(SkTTCFHeader) + (ttcCount * sizeof(SK_OT_ULONG)); 1.381 + fontPackageBuffer.realloc(bytesWritten + extra); 1.382 + //overlap is certain, use memmove 1.383 + memmove(fontPackageBuffer.get() + extra, fontPackageBuffer.get(), bytesWritten); 1.384 + 1.385 + // Write the ttc header. 1.386 + SkTTCFHeader* ttcfHeader = reinterpret_cast<SkTTCFHeader*>(fontPackageBuffer.get()); 1.387 + ttcfHeader->ttcTag = SkTTCFHeader::TAG; 1.388 + ttcfHeader->version = SkTTCFHeader::version_1; 1.389 + ttcfHeader->numOffsets = SkEndian_SwapBE32(ttcCount); 1.390 + SK_OT_ULONG* offsetPtr = SkTAfter<SK_OT_ULONG>(ttcfHeader); 1.391 + for (int i = 0; i < ttcCount; ++i, ++offsetPtr) { 1.392 + *offsetPtr = SkEndian_SwapBE32(extra); 1.393 + } 1.394 + 1.395 + // Fix up offsets in sfnt table entries. 1.396 + SkSFNTHeader* sfntHeader = SkTAddOffset<SkSFNTHeader>(fontPackageBuffer.get(), extra); 1.397 + int numTables = SkEndian_SwapBE16(sfntHeader->numTables); 1.398 + SkSFNTHeader::TableDirectoryEntry* tableDirectory = 1.399 + SkTAfter<SkSFNTHeader::TableDirectoryEntry>(sfntHeader); 1.400 + for (int i = 0; i < numTables; ++i, ++tableDirectory) { 1.401 + tableDirectory->offset = SkEndian_SwapBE32( 1.402 + SkEndian_SwapBE32(tableDirectory->offset) + extra); 1.403 + } 1.404 + } else { 1.405 + extra = 0; 1.406 + fontPackageBuffer.realloc(bytesWritten); 1.407 + } 1.408 + 1.409 + SkAutoTUnref<SkMemoryStream> newStream(new SkMemoryStream()); 1.410 + newStream->setMemoryOwned(fontPackageBuffer.detach(), bytesWritten + extra); 1.411 + 1.412 + SkTScopedComPtr<IStream> newIStream; 1.413 + SkIStream::CreateFromSkStream(newStream.detach(), true, &newIStream); 1.414 + 1.415 + XPS_FONT_EMBEDDING embedding; 1.416 + HRM(current->xpsFont->GetEmbeddingOption(&embedding), 1.417 + "Could not get embedding option from font."); 1.418 + 1.419 + SkTScopedComPtr<IOpcPartUri> partUri; 1.420 + HRM(current->xpsFont->GetPartName(&partUri), 1.421 + "Could not get part uri from font."); 1.422 + 1.423 + HRM(current->xpsFont->SetContent( 1.424 + newIStream.get(), 1.425 + embedding, 1.426 + partUri.get()), 1.427 + "Could not set new stream for subsetted font."); 1.428 + 1.429 + return S_OK; 1.430 +} 1.431 + 1.432 +bool SkXPSDevice::endPortfolio() { 1.433 + //Subset fonts 1.434 + if (!this->fTypefaces.empty()) { 1.435 + SkXPSDevice::TypefaceUse* current = &this->fTypefaces.front(); 1.436 + const TypefaceUse* last = &this->fTypefaces.back(); 1.437 + for (; current <= last; ++current) { 1.438 + //Ignore return for now, if it didn't subset, let it be. 1.439 + subset_typeface(current); 1.440 + } 1.441 + } 1.442 + 1.443 + HRBM(this->fPackageWriter->Close(), "Could not close writer."); 1.444 + 1.445 + return true; 1.446 +} 1.447 + 1.448 +static XPS_COLOR xps_color(const SkColor skColor) { 1.449 + //XPS uses non-pre-multiplied alpha (XPS Spec 11.4). 1.450 + XPS_COLOR xpsColor; 1.451 + xpsColor.colorType = XPS_COLOR_TYPE_SRGB; 1.452 + xpsColor.value.sRGB.alpha = SkColorGetA(skColor); 1.453 + xpsColor.value.sRGB.red = SkColorGetR(skColor); 1.454 + xpsColor.value.sRGB.green = SkColorGetG(skColor); 1.455 + xpsColor.value.sRGB.blue = SkColorGetB(skColor); 1.456 + 1.457 + return xpsColor; 1.458 +} 1.459 + 1.460 +static XPS_POINT xps_point(const SkPoint& point) { 1.461 + XPS_POINT xpsPoint = { 1.462 + SkScalarToFLOAT(point.fX), 1.463 + SkScalarToFLOAT(point.fY), 1.464 + }; 1.465 + return xpsPoint; 1.466 +} 1.467 + 1.468 +static XPS_POINT xps_point(const SkPoint& point, const SkMatrix& matrix) { 1.469 + SkPoint skTransformedPoint; 1.470 + matrix.mapXY(point.fX, point.fY, &skTransformedPoint); 1.471 + return xps_point(skTransformedPoint); 1.472 +} 1.473 + 1.474 +static XPS_SPREAD_METHOD xps_spread_method(SkShader::TileMode tileMode) { 1.475 + switch (tileMode) { 1.476 + case SkShader::kClamp_TileMode: 1.477 + return XPS_SPREAD_METHOD_PAD; 1.478 + case SkShader::kRepeat_TileMode: 1.479 + return XPS_SPREAD_METHOD_REPEAT; 1.480 + case SkShader::kMirror_TileMode: 1.481 + return XPS_SPREAD_METHOD_REFLECT; 1.482 + default: 1.483 + SkDEBUGFAIL("Unknown tile mode."); 1.484 + } 1.485 + return XPS_SPREAD_METHOD_PAD; 1.486 +} 1.487 + 1.488 +static void transform_offsets(SkScalar* stopOffsets, const int numOffsets, 1.489 + const SkPoint& start, const SkPoint& end, 1.490 + const SkMatrix& transform) { 1.491 + SkPoint startTransformed; 1.492 + transform.mapXY(start.fX, start.fY, &startTransformed); 1.493 + SkPoint endTransformed; 1.494 + transform.mapXY(end.fX, end.fY, &endTransformed); 1.495 + 1.496 + //Manhattan distance between transformed start and end. 1.497 + SkScalar startToEnd = (endTransformed.fX - startTransformed.fX) 1.498 + + (endTransformed.fY - startTransformed.fY); 1.499 + if (SkScalarNearlyZero(startToEnd)) { 1.500 + for (int i = 0; i < numOffsets; ++i) { 1.501 + stopOffsets[i] = 0; 1.502 + } 1.503 + return; 1.504 + } 1.505 + 1.506 + for (int i = 0; i < numOffsets; ++i) { 1.507 + SkPoint stop; 1.508 + stop.fX = SkScalarMul(end.fX - start.fX, stopOffsets[i]); 1.509 + stop.fY = SkScalarMul(end.fY - start.fY, stopOffsets[i]); 1.510 + 1.511 + SkPoint stopTransformed; 1.512 + transform.mapXY(stop.fX, stop.fY, &stopTransformed); 1.513 + 1.514 + //Manhattan distance between transformed start and stop. 1.515 + SkScalar startToStop = (stopTransformed.fX - startTransformed.fX) 1.516 + + (stopTransformed.fY - startTransformed.fY); 1.517 + //Percentage along transformed line. 1.518 + stopOffsets[i] = SkScalarDiv(startToStop, startToEnd); 1.519 + } 1.520 +} 1.521 + 1.522 +HRESULT SkXPSDevice::createXpsTransform(const SkMatrix& matrix, 1.523 + IXpsOMMatrixTransform** xpsTransform) { 1.524 + SkScalar affine[6]; 1.525 + if (!matrix.asAffine(affine)) { 1.526 + *xpsTransform = NULL; 1.527 + return S_FALSE; 1.528 + } 1.529 + XPS_MATRIX rawXpsMatrix = { 1.530 + SkScalarToFLOAT(affine[SkMatrix::kAScaleX]), 1.531 + SkScalarToFLOAT(affine[SkMatrix::kASkewY]), 1.532 + SkScalarToFLOAT(affine[SkMatrix::kASkewX]), 1.533 + SkScalarToFLOAT(affine[SkMatrix::kAScaleY]), 1.534 + SkScalarToFLOAT(affine[SkMatrix::kATransX]), 1.535 + SkScalarToFLOAT(affine[SkMatrix::kATransY]), 1.536 + }; 1.537 + HRM(this->fXpsFactory->CreateMatrixTransform(&rawXpsMatrix, xpsTransform), 1.538 + "Could not create transform."); 1.539 + 1.540 + return S_OK; 1.541 +} 1.542 + 1.543 +HRESULT SkXPSDevice::createPath(IXpsOMGeometryFigure* figure, 1.544 + IXpsOMVisualCollection* visuals, 1.545 + IXpsOMPath** path) { 1.546 + SkTScopedComPtr<IXpsOMGeometry> geometry; 1.547 + HRM(this->fXpsFactory->CreateGeometry(&geometry), 1.548 + "Could not create geometry."); 1.549 + 1.550 + SkTScopedComPtr<IXpsOMGeometryFigureCollection> figureCollection; 1.551 + HRM(geometry->GetFigures(&figureCollection), "Could not get figures."); 1.552 + HRM(figureCollection->Append(figure), "Could not add figure."); 1.553 + 1.554 + HRM(this->fXpsFactory->CreatePath(path), "Could not create path."); 1.555 + HRM((*path)->SetGeometryLocal(geometry.get()), "Could not set geometry"); 1.556 + 1.557 + HRM(visuals->Append(*path), "Could not add path to visuals."); 1.558 + return S_OK; 1.559 +} 1.560 + 1.561 +HRESULT SkXPSDevice::createXpsSolidColorBrush(const SkColor skColor, 1.562 + const SkAlpha alpha, 1.563 + IXpsOMBrush** xpsBrush) { 1.564 + XPS_COLOR xpsColor = xps_color(skColor); 1.565 + SkTScopedComPtr<IXpsOMSolidColorBrush> solidBrush; 1.566 + HRM(this->fXpsFactory->CreateSolidColorBrush(&xpsColor, NULL, &solidBrush), 1.567 + "Could not create solid color brush."); 1.568 + HRM(solidBrush->SetOpacity(alpha / 255.0f), "Could not set opacity."); 1.569 + HRM(solidBrush->QueryInterface<IXpsOMBrush>(xpsBrush), "QI Fail."); 1.570 + return S_OK; 1.571 +} 1.572 + 1.573 +HRESULT SkXPSDevice::sideOfClamp(const SkRect& areaToFill, 1.574 + const XPS_RECT& imageViewBox, 1.575 + IXpsOMImageResource* image, 1.576 + IXpsOMVisualCollection* visuals) { 1.577 + SkTScopedComPtr<IXpsOMGeometryFigure> areaToFillFigure; 1.578 + HR(this->createXpsRect(areaToFill, FALSE, TRUE, &areaToFillFigure)); 1.579 + 1.580 + SkTScopedComPtr<IXpsOMPath> areaToFillPath; 1.581 + HR(this->createPath(areaToFillFigure.get(), visuals, &areaToFillPath)); 1.582 + 1.583 + SkTScopedComPtr<IXpsOMImageBrush> areaToFillBrush; 1.584 + HRM(this->fXpsFactory->CreateImageBrush(image, 1.585 + &imageViewBox, 1.586 + &imageViewBox, 1.587 + &areaToFillBrush), 1.588 + "Could not create brush for side of clamp."); 1.589 + HRM(areaToFillBrush->SetTileMode(XPS_TILE_MODE_FLIPXY), 1.590 + "Could not set tile mode for side of clamp."); 1.591 + HRM(areaToFillPath->SetFillBrushLocal(areaToFillBrush.get()), 1.592 + "Could not set brush for side of clamp"); 1.593 + 1.594 + return S_OK; 1.595 +} 1.596 + 1.597 +HRESULT SkXPSDevice::cornerOfClamp(const SkRect& areaToFill, 1.598 + const SkColor color, 1.599 + IXpsOMVisualCollection* visuals) { 1.600 + SkTScopedComPtr<IXpsOMGeometryFigure> areaToFillFigure; 1.601 + HR(this->createXpsRect(areaToFill, FALSE, TRUE, &areaToFillFigure)); 1.602 + 1.603 + SkTScopedComPtr<IXpsOMPath> areaToFillPath; 1.604 + HR(this->createPath(areaToFillFigure.get(), visuals, &areaToFillPath)); 1.605 + 1.606 + SkTScopedComPtr<IXpsOMBrush> areaToFillBrush; 1.607 + HR(this->createXpsSolidColorBrush(color, 0xFF, &areaToFillBrush)); 1.608 + HRM(areaToFillPath->SetFillBrushLocal(areaToFillBrush.get()), 1.609 + "Could not set brush for corner of clamp."); 1.610 + 1.611 + return S_OK; 1.612 +} 1.613 + 1.614 +static const XPS_TILE_MODE XTM_N = XPS_TILE_MODE_NONE; 1.615 +static const XPS_TILE_MODE XTM_T = XPS_TILE_MODE_TILE; 1.616 +static const XPS_TILE_MODE XTM_X = XPS_TILE_MODE_FLIPX; 1.617 +static const XPS_TILE_MODE XTM_Y = XPS_TILE_MODE_FLIPY; 1.618 +static const XPS_TILE_MODE XTM_XY = XPS_TILE_MODE_FLIPXY; 1.619 + 1.620 +//TODO(bungeman): In the future, should skia add None, 1.621 +//handle None+Mirror and None+Repeat correctly. 1.622 +//None is currently an internal hack so masks don't repeat (None+None only). 1.623 +static XPS_TILE_MODE SkToXpsTileMode[SkShader::kTileModeCount+1] 1.624 + [SkShader::kTileModeCount+1] = { 1.625 + //Clamp //Repeat //Mirror //None 1.626 +/*Clamp */ XTM_N, XTM_T, XTM_Y, XTM_N, 1.627 +/*Repeat*/ XTM_T, XTM_T, XTM_Y, XTM_N, 1.628 +/*Mirror*/ XTM_X, XTM_X, XTM_XY, XTM_X, 1.629 +/*None */ XTM_N, XTM_N, XTM_Y, XTM_N, 1.630 +}; 1.631 + 1.632 +HRESULT SkXPSDevice::createXpsImageBrush( 1.633 + const SkBitmap& bitmap, 1.634 + const SkMatrix& localMatrix, 1.635 + const SkShader::TileMode (&xy)[2], 1.636 + const SkAlpha alpha, 1.637 + IXpsOMTileBrush** xpsBrush) { 1.638 + SkDynamicMemoryWStream write; 1.639 + if (!SkImageEncoder::EncodeStream(&write, bitmap, 1.640 + SkImageEncoder::kPNG_Type, 100)) { 1.641 + HRM(E_FAIL, "Unable to encode bitmap as png."); 1.642 + } 1.643 + SkMemoryStream* read = new SkMemoryStream; 1.644 + read->setData(write.copyToData())->unref(); 1.645 + SkTScopedComPtr<IStream> readWrapper; 1.646 + HRM(SkIStream::CreateFromSkStream(read, true, &readWrapper), 1.647 + "Could not create stream from png data."); 1.648 + 1.649 + const size_t size = 1.650 + SK_ARRAY_COUNT(L"/Documents/1/Resources/Images/" L_GUID_ID L".png"); 1.651 + wchar_t buffer[size]; 1.652 + wchar_t id[GUID_ID_LEN]; 1.653 + HR(create_id(id, GUID_ID_LEN)); 1.654 + swprintf_s(buffer, size, L"/Documents/1/Resources/Images/%s.png", id); 1.655 + 1.656 + SkTScopedComPtr<IOpcPartUri> imagePartUri; 1.657 + HRM(this->fXpsFactory->CreatePartUri(buffer, &imagePartUri), 1.658 + "Could not create image part uri."); 1.659 + 1.660 + SkTScopedComPtr<IXpsOMImageResource> imageResource; 1.661 + HRM(this->fXpsFactory->CreateImageResource( 1.662 + readWrapper.get(), 1.663 + XPS_IMAGE_TYPE_PNG, 1.664 + imagePartUri.get(), 1.665 + &imageResource), 1.666 + "Could not create image resource."); 1.667 + 1.668 + XPS_RECT bitmapRect = { 1.669 + 0.0, 0.0, 1.670 + static_cast<FLOAT>(bitmap.width()), static_cast<FLOAT>(bitmap.height()) 1.671 + }; 1.672 + SkTScopedComPtr<IXpsOMImageBrush> xpsImageBrush; 1.673 + HRM(this->fXpsFactory->CreateImageBrush(imageResource.get(), 1.674 + &bitmapRect, &bitmapRect, 1.675 + &xpsImageBrush), 1.676 + "Could not create image brush."); 1.677 + 1.678 + if (SkShader::kClamp_TileMode != xy[0] && 1.679 + SkShader::kClamp_TileMode != xy[1]) { 1.680 + 1.681 + HRM(xpsImageBrush->SetTileMode(SkToXpsTileMode[xy[0]][xy[1]]), 1.682 + "Could not set image tile mode"); 1.683 + HRM(xpsImageBrush->SetOpacity(alpha / 255.0f), 1.684 + "Could not set image opacity."); 1.685 + HRM(xpsImageBrush->QueryInterface(xpsBrush), "QI failed."); 1.686 + } else { 1.687 + //TODO(bungeman): compute how big this really needs to be. 1.688 + const SkScalar BIG = SkIntToScalar(1000); //SK_ScalarMax; 1.689 + const FLOAT BIG_F = SkScalarToFLOAT(BIG); 1.690 + const SkScalar bWidth = SkIntToScalar(bitmap.width()); 1.691 + const SkScalar bHeight = SkIntToScalar(bitmap.height()); 1.692 + 1.693 + //create brush canvas 1.694 + SkTScopedComPtr<IXpsOMCanvas> brushCanvas; 1.695 + HRM(this->fXpsFactory->CreateCanvas(&brushCanvas), 1.696 + "Could not create image brush canvas."); 1.697 + SkTScopedComPtr<IXpsOMVisualCollection> brushVisuals; 1.698 + HRM(brushCanvas->GetVisuals(&brushVisuals), 1.699 + "Could not get image brush canvas visuals collection."); 1.700 + 1.701 + //create central figure 1.702 + const SkRect bitmapPoints = SkRect::MakeLTRB(0, 0, bWidth, bHeight); 1.703 + SkTScopedComPtr<IXpsOMGeometryFigure> centralFigure; 1.704 + HR(this->createXpsRect(bitmapPoints, FALSE, TRUE, ¢ralFigure)); 1.705 + 1.706 + SkTScopedComPtr<IXpsOMPath> centralPath; 1.707 + HR(this->createPath(centralFigure.get(), 1.708 + brushVisuals.get(), 1.709 + ¢ralPath)); 1.710 + HRM(xpsImageBrush->SetTileMode(XPS_TILE_MODE_FLIPXY), 1.711 + "Could not set tile mode for image brush central path."); 1.712 + HRM(centralPath->SetFillBrushLocal(xpsImageBrush.get()), 1.713 + "Could not set fill brush for image brush central path."); 1.714 + 1.715 + //add left/right 1.716 + if (SkShader::kClamp_TileMode == xy[0]) { 1.717 + SkRect leftArea = SkRect::MakeLTRB(-BIG, 0, 0, bHeight); 1.718 + XPS_RECT leftImageViewBox = { 1.719 + 0.0, 0.0, 1.720 + 1.0, static_cast<FLOAT>(bitmap.height()), 1.721 + }; 1.722 + HR(this->sideOfClamp(leftArea, leftImageViewBox, 1.723 + imageResource.get(), 1.724 + brushVisuals.get())); 1.725 + 1.726 + SkRect rightArea = SkRect::MakeLTRB(bWidth, 0, BIG, bHeight); 1.727 + XPS_RECT rightImageViewBox = { 1.728 + bitmap.width() - 1.0f, 0.0f, 1.729 + 1.0f, static_cast<FLOAT>(bitmap.height()), 1.730 + }; 1.731 + HR(this->sideOfClamp(rightArea, rightImageViewBox, 1.732 + imageResource.get(), 1.733 + brushVisuals.get())); 1.734 + } 1.735 + 1.736 + //add top/bottom 1.737 + if (SkShader::kClamp_TileMode == xy[1]) { 1.738 + SkRect topArea = SkRect::MakeLTRB(0, -BIG, bWidth, 0); 1.739 + XPS_RECT topImageViewBox = { 1.740 + 0.0, 0.0, 1.741 + static_cast<FLOAT>(bitmap.width()), 1.0, 1.742 + }; 1.743 + HR(this->sideOfClamp(topArea, topImageViewBox, 1.744 + imageResource.get(), 1.745 + brushVisuals.get())); 1.746 + 1.747 + SkRect bottomArea = SkRect::MakeLTRB(0, bHeight, bWidth, BIG); 1.748 + XPS_RECT bottomImageViewBox = { 1.749 + 0.0f, bitmap.height() - 1.0f, 1.750 + static_cast<FLOAT>(bitmap.width()), 1.0f, 1.751 + }; 1.752 + HR(this->sideOfClamp(bottomArea, bottomImageViewBox, 1.753 + imageResource.get(), 1.754 + brushVisuals.get())); 1.755 + } 1.756 + 1.757 + //add tl, tr, bl, br 1.758 + if (SkShader::kClamp_TileMode == xy[0] && 1.759 + SkShader::kClamp_TileMode == xy[1]) { 1.760 + 1.761 + SkAutoLockPixels alp(bitmap); 1.762 + 1.763 + const SkColor tlColor = bitmap.getColor(0,0); 1.764 + const SkRect tlArea = SkRect::MakeLTRB(-BIG, -BIG, 0, 0); 1.765 + HR(this->cornerOfClamp(tlArea, tlColor, brushVisuals.get())); 1.766 + 1.767 + const SkColor trColor = bitmap.getColor(bitmap.width()-1,0); 1.768 + const SkRect trArea = SkRect::MakeLTRB(bWidth, -BIG, BIG, 0); 1.769 + HR(this->cornerOfClamp(trArea, trColor, brushVisuals.get())); 1.770 + 1.771 + const SkColor brColor = bitmap.getColor(bitmap.width()-1, 1.772 + bitmap.height()-1); 1.773 + const SkRect brArea = SkRect::MakeLTRB(bWidth, bHeight, BIG, BIG); 1.774 + HR(this->cornerOfClamp(brArea, brColor, brushVisuals.get())); 1.775 + 1.776 + const SkColor blColor = bitmap.getColor(0,bitmap.height()-1); 1.777 + const SkRect blArea = SkRect::MakeLTRB(-BIG, bHeight, 0, BIG); 1.778 + HR(this->cornerOfClamp(blArea, blColor, brushVisuals.get())); 1.779 + } 1.780 + 1.781 + //create visual brush from canvas 1.782 + XPS_RECT bound = {}; 1.783 + if (SkShader::kClamp_TileMode == xy[0] && 1.784 + SkShader::kClamp_TileMode == xy[1]) { 1.785 + 1.786 + bound.x = BIG_F / -2; 1.787 + bound.y = BIG_F / -2; 1.788 + bound.width = BIG_F; 1.789 + bound.height = BIG_F; 1.790 + } else if (SkShader::kClamp_TileMode == xy[0]) { 1.791 + bound.x = BIG_F / -2; 1.792 + bound.y = 0.0f; 1.793 + bound.width = BIG_F; 1.794 + bound.height = static_cast<FLOAT>(bitmap.height()); 1.795 + } else if (SkShader::kClamp_TileMode == xy[1]) { 1.796 + bound.x = 0; 1.797 + bound.y = BIG_F / -2; 1.798 + bound.width = static_cast<FLOAT>(bitmap.width()); 1.799 + bound.height = BIG_F; 1.800 + } 1.801 + SkTScopedComPtr<IXpsOMVisualBrush> clampBrush; 1.802 + HRM(this->fXpsFactory->CreateVisualBrush(&bound, &bound, &clampBrush), 1.803 + "Could not create visual brush for image brush."); 1.804 + HRM(clampBrush->SetVisualLocal(brushCanvas.get()), 1.805 + "Could not set canvas on visual brush for image brush."); 1.806 + HRM(clampBrush->SetTileMode(SkToXpsTileMode[xy[0]][xy[1]]), 1.807 + "Could not set tile mode on visual brush for image brush."); 1.808 + HRM(clampBrush->SetOpacity(alpha / 255.0f), 1.809 + "Could not set opacity on visual brush for image brush."); 1.810 + 1.811 + HRM(clampBrush->QueryInterface(xpsBrush), "QI failed."); 1.812 + } 1.813 + 1.814 + SkTScopedComPtr<IXpsOMMatrixTransform> xpsMatrixToUse; 1.815 + HR(this->createXpsTransform(localMatrix, &xpsMatrixToUse)); 1.816 + if (NULL != xpsMatrixToUse.get()) { 1.817 + HRM((*xpsBrush)->SetTransformLocal(xpsMatrixToUse.get()), 1.818 + "Could not set transform for image brush."); 1.819 + } else { 1.820 + //TODO(bungeman): perspective bitmaps in general. 1.821 + } 1.822 + 1.823 + return S_OK; 1.824 +} 1.825 + 1.826 +HRESULT SkXPSDevice::createXpsGradientStop(const SkColor skColor, 1.827 + const SkScalar offset, 1.828 + IXpsOMGradientStop** xpsGradStop) { 1.829 + XPS_COLOR gradStopXpsColor = xps_color(skColor); 1.830 + HRM(this->fXpsFactory->CreateGradientStop(&gradStopXpsColor, 1.831 + NULL, 1.832 + SkScalarToFLOAT(offset), 1.833 + xpsGradStop), 1.834 + "Could not create gradient stop."); 1.835 + return S_OK; 1.836 +} 1.837 + 1.838 +HRESULT SkXPSDevice::createXpsLinearGradient(SkShader::GradientInfo info, 1.839 + const SkAlpha alpha, 1.840 + const SkMatrix& localMatrix, 1.841 + IXpsOMMatrixTransform* xpsMatrix, 1.842 + IXpsOMBrush** xpsBrush) { 1.843 + XPS_POINT startPoint; 1.844 + XPS_POINT endPoint; 1.845 + if (NULL != xpsMatrix) { 1.846 + startPoint = xps_point(info.fPoint[0]); 1.847 + endPoint = xps_point(info.fPoint[1]); 1.848 + } else { 1.849 + transform_offsets(info.fColorOffsets, info.fColorCount, 1.850 + info.fPoint[0], info.fPoint[1], 1.851 + localMatrix); 1.852 + startPoint = xps_point(info.fPoint[0], localMatrix); 1.853 + endPoint = xps_point(info.fPoint[1], localMatrix); 1.854 + } 1.855 + 1.856 + SkTScopedComPtr<IXpsOMGradientStop> gradStop0; 1.857 + HR(createXpsGradientStop(info.fColors[0], 1.858 + info.fColorOffsets[0], 1.859 + &gradStop0)); 1.860 + 1.861 + SkTScopedComPtr<IXpsOMGradientStop> gradStop1; 1.862 + HR(createXpsGradientStop(info.fColors[1], 1.863 + info.fColorOffsets[1], 1.864 + &gradStop1)); 1.865 + 1.866 + SkTScopedComPtr<IXpsOMLinearGradientBrush> gradientBrush; 1.867 + HRM(this->fXpsFactory->CreateLinearGradientBrush(gradStop0.get(), 1.868 + gradStop1.get(), 1.869 + &startPoint, 1.870 + &endPoint, 1.871 + &gradientBrush), 1.872 + "Could not create linear gradient brush."); 1.873 + if (NULL != xpsMatrix) { 1.874 + HRM(gradientBrush->SetTransformLocal(xpsMatrix), 1.875 + "Could not set transform on linear gradient brush."); 1.876 + } 1.877 + 1.878 + SkTScopedComPtr<IXpsOMGradientStopCollection> gradStopCollection; 1.879 + HRM(gradientBrush->GetGradientStops(&gradStopCollection), 1.880 + "Could not get linear gradient stop collection."); 1.881 + for (int i = 2; i < info.fColorCount; ++i) { 1.882 + SkTScopedComPtr<IXpsOMGradientStop> gradStop; 1.883 + HR(createXpsGradientStop(info.fColors[i], 1.884 + info.fColorOffsets[i], 1.885 + &gradStop)); 1.886 + HRM(gradStopCollection->Append(gradStop.get()), 1.887 + "Could not add linear gradient stop."); 1.888 + } 1.889 + 1.890 + HRM(gradientBrush->SetSpreadMethod(xps_spread_method(info.fTileMode)), 1.891 + "Could not set spread method of linear gradient."); 1.892 + 1.893 + HRM(gradientBrush->SetOpacity(alpha / 255.0f), 1.894 + "Could not set opacity of linear gradient brush."); 1.895 + HRM(gradientBrush->QueryInterface<IXpsOMBrush>(xpsBrush), "QI failed"); 1.896 + 1.897 + return S_OK; 1.898 +} 1.899 + 1.900 +HRESULT SkXPSDevice::createXpsRadialGradient(SkShader::GradientInfo info, 1.901 + const SkAlpha alpha, 1.902 + const SkMatrix& localMatrix, 1.903 + IXpsOMMatrixTransform* xpsMatrix, 1.904 + IXpsOMBrush** xpsBrush) { 1.905 + SkTScopedComPtr<IXpsOMGradientStop> gradStop0; 1.906 + HR(createXpsGradientStop(info.fColors[0], 1.907 + info.fColorOffsets[0], 1.908 + &gradStop0)); 1.909 + 1.910 + SkTScopedComPtr<IXpsOMGradientStop> gradStop1; 1.911 + HR(createXpsGradientStop(info.fColors[1], 1.912 + info.fColorOffsets[1], 1.913 + &gradStop1)); 1.914 + 1.915 + //TODO: figure out how to fake better if not affine 1.916 + XPS_POINT centerPoint; 1.917 + XPS_POINT gradientOrigin; 1.918 + XPS_SIZE radiiSizes; 1.919 + if (NULL != xpsMatrix) { 1.920 + centerPoint = xps_point(info.fPoint[0]); 1.921 + gradientOrigin = xps_point(info.fPoint[0]); 1.922 + radiiSizes.width = SkScalarToFLOAT(info.fRadius[0]); 1.923 + radiiSizes.height = SkScalarToFLOAT(info.fRadius[0]); 1.924 + } else { 1.925 + centerPoint = xps_point(info.fPoint[0], localMatrix); 1.926 + gradientOrigin = xps_point(info.fPoint[0], localMatrix); 1.927 + 1.928 + SkScalar radius = info.fRadius[0]; 1.929 + SkVector vec[2]; 1.930 + 1.931 + vec[0].set(radius, 0); 1.932 + vec[1].set(0, radius); 1.933 + localMatrix.mapVectors(vec, 2); 1.934 + 1.935 + SkScalar d0 = vec[0].length(); 1.936 + SkScalar d1 = vec[1].length(); 1.937 + 1.938 + radiiSizes.width = SkScalarToFLOAT(d0); 1.939 + radiiSizes.height = SkScalarToFLOAT(d1); 1.940 + } 1.941 + 1.942 + SkTScopedComPtr<IXpsOMRadialGradientBrush> gradientBrush; 1.943 + HRM(this->fXpsFactory->CreateRadialGradientBrush(gradStop0.get(), 1.944 + gradStop1.get(), 1.945 + ¢erPoint, 1.946 + &gradientOrigin, 1.947 + &radiiSizes, 1.948 + &gradientBrush), 1.949 + "Could not create radial gradient brush."); 1.950 + if (NULL != xpsMatrix) { 1.951 + HRM(gradientBrush->SetTransformLocal(xpsMatrix), 1.952 + "Could not set transform on radial gradient brush."); 1.953 + } 1.954 + 1.955 + SkTScopedComPtr<IXpsOMGradientStopCollection> gradStopCollection; 1.956 + HRM(gradientBrush->GetGradientStops(&gradStopCollection), 1.957 + "Could not get radial gradient stop collection."); 1.958 + for (int i = 2; i < info.fColorCount; ++i) { 1.959 + SkTScopedComPtr<IXpsOMGradientStop> gradStop; 1.960 + HR(createXpsGradientStop(info.fColors[i], 1.961 + info.fColorOffsets[i], 1.962 + &gradStop)); 1.963 + HRM(gradStopCollection->Append(gradStop.get()), 1.964 + "Could not add radial gradient stop."); 1.965 + } 1.966 + 1.967 + HRM(gradientBrush->SetSpreadMethod(xps_spread_method(info.fTileMode)), 1.968 + "Could not set spread method of radial gradient."); 1.969 + 1.970 + HRM(gradientBrush->SetOpacity(alpha / 255.0f), 1.971 + "Could not set opacity of radial gradient brush."); 1.972 + HRM(gradientBrush->QueryInterface<IXpsOMBrush>(xpsBrush), "QI failed."); 1.973 + 1.974 + return S_OK; 1.975 +} 1.976 + 1.977 +HRESULT SkXPSDevice::createXpsBrush(const SkPaint& skPaint, 1.978 + IXpsOMBrush** brush, 1.979 + const SkMatrix* parentTransform) { 1.980 + const SkShader *shader = skPaint.getShader(); 1.981 + if (NULL == shader) { 1.982 + HR(this->createXpsSolidColorBrush(skPaint.getColor(), 0xFF, brush)); 1.983 + return S_OK; 1.984 + } 1.985 + 1.986 + //Gradient shaders. 1.987 + SkShader::GradientInfo info; 1.988 + info.fColorCount = 0; 1.989 + info.fColors = NULL; 1.990 + info.fColorOffsets = NULL; 1.991 + SkShader::GradientType gradientType = shader->asAGradient(&info); 1.992 + 1.993 + if (SkShader::kNone_GradientType == gradientType) { 1.994 + //Nothing to see, move along. 1.995 + 1.996 + } else if (SkShader::kColor_GradientType == gradientType) { 1.997 + SkASSERT(1 == info.fColorCount); 1.998 + SkColor color; 1.999 + info.fColors = &color; 1.1000 + shader->asAGradient(&info); 1.1001 + SkAlpha alpha = skPaint.getAlpha(); 1.1002 + HR(this->createXpsSolidColorBrush(color, alpha, brush)); 1.1003 + return S_OK; 1.1004 + 1.1005 + } else { 1.1006 + if (info.fColorCount == 0) { 1.1007 + const SkColor color = skPaint.getColor(); 1.1008 + HR(this->createXpsSolidColorBrush(color, 0xFF, brush)); 1.1009 + return S_OK; 1.1010 + } 1.1011 + 1.1012 + SkAutoTArray<SkColor> colors(info.fColorCount); 1.1013 + SkAutoTArray<SkScalar> colorOffsets(info.fColorCount); 1.1014 + info.fColors = colors.get(); 1.1015 + info.fColorOffsets = colorOffsets.get(); 1.1016 + shader->asAGradient(&info); 1.1017 + 1.1018 + if (1 == info.fColorCount) { 1.1019 + SkColor color = info.fColors[0]; 1.1020 + SkAlpha alpha = skPaint.getAlpha(); 1.1021 + HR(this->createXpsSolidColorBrush(color, alpha, brush)); 1.1022 + return S_OK; 1.1023 + } 1.1024 + 1.1025 + SkMatrix localMatrix = shader->getLocalMatrix(); 1.1026 + if (NULL != parentTransform) { 1.1027 + localMatrix.preConcat(*parentTransform); 1.1028 + } 1.1029 + SkTScopedComPtr<IXpsOMMatrixTransform> xpsMatrixToUse; 1.1030 + HR(this->createXpsTransform(localMatrix, &xpsMatrixToUse)); 1.1031 + 1.1032 + if (SkShader::kLinear_GradientType == gradientType) { 1.1033 + HR(this->createXpsLinearGradient(info, 1.1034 + skPaint.getAlpha(), 1.1035 + localMatrix, 1.1036 + xpsMatrixToUse.get(), 1.1037 + brush)); 1.1038 + return S_OK; 1.1039 + } 1.1040 + 1.1041 + if (SkShader::kRadial_GradientType == gradientType) { 1.1042 + HR(this->createXpsRadialGradient(info, 1.1043 + skPaint.getAlpha(), 1.1044 + localMatrix, 1.1045 + xpsMatrixToUse.get(), 1.1046 + brush)); 1.1047 + return S_OK; 1.1048 + } 1.1049 + 1.1050 + if (SkShader::kRadial2_GradientType == gradientType || 1.1051 + SkShader::kConical_GradientType == gradientType) { 1.1052 + //simple if affine and one is 0, otherwise will have to fake 1.1053 + } 1.1054 + 1.1055 + if (SkShader::kSweep_GradientType == gradientType) { 1.1056 + //have to fake 1.1057 + } 1.1058 + } 1.1059 + 1.1060 + SkBitmap outTexture; 1.1061 + SkMatrix outMatrix; 1.1062 + SkShader::TileMode xy[2]; 1.1063 + SkShader::BitmapType bitmapType = shader->asABitmap(&outTexture, 1.1064 + &outMatrix, 1.1065 + xy); 1.1066 + switch (bitmapType) { 1.1067 + case SkShader::kNone_BitmapType: 1.1068 + break; 1.1069 + case SkShader::kDefault_BitmapType: { 1.1070 + //TODO: outMatrix?? 1.1071 + SkMatrix localMatrix = shader->getLocalMatrix(); 1.1072 + if (NULL != parentTransform) { 1.1073 + localMatrix.preConcat(*parentTransform); 1.1074 + } 1.1075 + 1.1076 + SkTScopedComPtr<IXpsOMTileBrush> tileBrush; 1.1077 + HR(this->createXpsImageBrush(outTexture, 1.1078 + localMatrix, 1.1079 + xy, 1.1080 + skPaint.getAlpha(), 1.1081 + &tileBrush)); 1.1082 + 1.1083 + HRM(tileBrush->QueryInterface<IXpsOMBrush>(brush), "QI failed."); 1.1084 + 1.1085 + return S_OK; 1.1086 + } 1.1087 + case SkShader::kRadial_BitmapType: 1.1088 + case SkShader::kSweep_BitmapType: 1.1089 + case SkShader::kTwoPointRadial_BitmapType: 1.1090 + default: 1.1091 + break; 1.1092 + } 1.1093 + 1.1094 + HR(this->createXpsSolidColorBrush(skPaint.getColor(), 0xFF, brush)); 1.1095 + return S_OK; 1.1096 +} 1.1097 + 1.1098 +static bool rect_must_be_pathed(const SkPaint& paint, const SkMatrix& matrix) { 1.1099 + const bool zeroWidth = (0 == paint.getStrokeWidth()); 1.1100 + const bool stroke = (SkPaint::kFill_Style != paint.getStyle()); 1.1101 + 1.1102 + return paint.getPathEffect() || 1.1103 + paint.getMaskFilter() || 1.1104 + paint.getRasterizer() || 1.1105 + (stroke && ( 1.1106 + (matrix.hasPerspective() && !zeroWidth) || 1.1107 + SkPaint::kMiter_Join != paint.getStrokeJoin() || 1.1108 + (SkPaint::kMiter_Join == paint.getStrokeJoin() && 1.1109 + paint.getStrokeMiter() < SK_ScalarSqrt2) 1.1110 + )) 1.1111 + ; 1.1112 +} 1.1113 + 1.1114 +HRESULT SkXPSDevice::createXpsRect(const SkRect& rect, BOOL stroke, BOOL fill, 1.1115 + IXpsOMGeometryFigure** xpsRect) { 1.1116 + const SkPoint points[4] = { 1.1117 + { rect.fLeft, rect.fTop }, 1.1118 + { rect.fRight, rect.fTop }, 1.1119 + { rect.fRight, rect.fBottom }, 1.1120 + { rect.fLeft, rect.fBottom }, 1.1121 + }; 1.1122 + return this->createXpsQuad(points, stroke, fill, xpsRect); 1.1123 +} 1.1124 +HRESULT SkXPSDevice::createXpsQuad(const SkPoint (&points)[4], 1.1125 + BOOL stroke, BOOL fill, 1.1126 + IXpsOMGeometryFigure** xpsQuad) { 1.1127 + // Define the start point. 1.1128 + XPS_POINT startPoint = xps_point(points[0]); 1.1129 + 1.1130 + // Create the figure. 1.1131 + HRM(this->fXpsFactory->CreateGeometryFigure(&startPoint, xpsQuad), 1.1132 + "Could not create quad geometry figure."); 1.1133 + 1.1134 + // Define the type of each segment. 1.1135 + XPS_SEGMENT_TYPE segmentTypes[3] = { 1.1136 + XPS_SEGMENT_TYPE_LINE, 1.1137 + XPS_SEGMENT_TYPE_LINE, 1.1138 + XPS_SEGMENT_TYPE_LINE, 1.1139 + }; 1.1140 + 1.1141 + // Define the x and y coordinates of each corner of the figure. 1.1142 + FLOAT segmentData[6] = { 1.1143 + SkScalarToFLOAT(points[1].fX), SkScalarToFLOAT(points[1].fY), 1.1144 + SkScalarToFLOAT(points[2].fX), SkScalarToFLOAT(points[2].fY), 1.1145 + SkScalarToFLOAT(points[3].fX), SkScalarToFLOAT(points[3].fY), 1.1146 + }; 1.1147 + 1.1148 + // Describe if the segments are stroked. 1.1149 + BOOL segmentStrokes[3] = { 1.1150 + stroke, stroke, stroke, 1.1151 + }; 1.1152 + 1.1153 + // Add the segment data to the figure. 1.1154 + HRM((*xpsQuad)->SetSegments( 1.1155 + 3, 6, 1.1156 + segmentTypes , segmentData, segmentStrokes), 1.1157 + "Could not add segment data to quad."); 1.1158 + 1.1159 + // Set the closed and filled properties of the figure. 1.1160 + HRM((*xpsQuad)->SetIsClosed(stroke), "Could not set quad close."); 1.1161 + HRM((*xpsQuad)->SetIsFilled(fill), "Could not set quad fill."); 1.1162 + 1.1163 + return S_OK; 1.1164 +} 1.1165 + 1.1166 +void SkXPSDevice::clear(SkColor color) { 1.1167 + //TODO: override this for XPS 1.1168 + SkDEBUGF(("XPS clear not yet implemented.")); 1.1169 +} 1.1170 + 1.1171 +void SkXPSDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode, 1.1172 + size_t count, const SkPoint points[], 1.1173 + const SkPaint& paint) { 1.1174 + //This will call back into the device to do the drawing. 1.1175 + d.drawPoints(mode, count, points, paint, true); 1.1176 +} 1.1177 + 1.1178 +void SkXPSDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, 1.1179 + int vertexCount, const SkPoint verts[], 1.1180 + const SkPoint texs[], const SkColor colors[], 1.1181 + SkXfermode* xmode, const uint16_t indices[], 1.1182 + int indexCount, const SkPaint& paint) { 1.1183 + //TODO: override this for XPS 1.1184 + SkDEBUGF(("XPS drawVertices not yet implemented.")); 1.1185 +} 1.1186 + 1.1187 +void SkXPSDevice::drawPaint(const SkDraw& d, const SkPaint& origPaint) { 1.1188 + const SkRect r = SkRect::MakeSize(this->fCurrentCanvasSize); 1.1189 + 1.1190 + //If trying to paint with a stroke, ignore that and fill. 1.1191 + SkPaint* fillPaint = const_cast<SkPaint*>(&origPaint); 1.1192 + SkTCopyOnFirstWrite<SkPaint> paint(origPaint); 1.1193 + if (paint->getStyle() != SkPaint::kFill_Style) { 1.1194 + paint.writable()->setStyle(SkPaint::kFill_Style); 1.1195 + } 1.1196 + 1.1197 + this->internalDrawRect(d, r, false, *fillPaint); 1.1198 +} 1.1199 + 1.1200 +void SkXPSDevice::drawRect(const SkDraw& d, 1.1201 + const SkRect& r, 1.1202 + const SkPaint& paint) { 1.1203 + this->internalDrawRect(d, r, true, paint); 1.1204 +} 1.1205 + 1.1206 +void SkXPSDevice::drawRRect(const SkDraw& d, 1.1207 + const SkRRect& rr, 1.1208 + const SkPaint& paint) { 1.1209 + SkPath path; 1.1210 + path.addRRect(rr); 1.1211 + this->drawPath(d, path, paint, NULL, true); 1.1212 +} 1.1213 + 1.1214 +void SkXPSDevice::internalDrawRect(const SkDraw& d, 1.1215 + const SkRect& r, 1.1216 + bool transformRect, 1.1217 + const SkPaint& paint) { 1.1218 + //Exit early if there is nothing to draw. 1.1219 + if (d.fClip->isEmpty() || 1.1220 + (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { 1.1221 + return; 1.1222 + } 1.1223 + 1.1224 + //Path the rect if we can't optimize it. 1.1225 + if (rect_must_be_pathed(paint, *d.fMatrix)) { 1.1226 + SkPath tmp; 1.1227 + tmp.addRect(r); 1.1228 + tmp.setFillType(SkPath::kWinding_FillType); 1.1229 + this->drawPath(d, tmp, paint, NULL, true); 1.1230 + return; 1.1231 + } 1.1232 + 1.1233 + //Create the shaded path. 1.1234 + SkTScopedComPtr<IXpsOMPath> shadedPath; 1.1235 + HRVM(this->fXpsFactory->CreatePath(&shadedPath), 1.1236 + "Could not create shaded path for rect."); 1.1237 + 1.1238 + //Create the shaded geometry. 1.1239 + SkTScopedComPtr<IXpsOMGeometry> shadedGeometry; 1.1240 + HRVM(this->fXpsFactory->CreateGeometry(&shadedGeometry), 1.1241 + "Could not create shaded geometry for rect."); 1.1242 + 1.1243 + //Add the geometry to the shaded path. 1.1244 + HRVM(shadedPath->SetGeometryLocal(shadedGeometry.get()), 1.1245 + "Could not set shaded geometry for rect."); 1.1246 + 1.1247 + //Set the brushes. 1.1248 + BOOL fill = FALSE; 1.1249 + BOOL stroke = FALSE; 1.1250 + HRV(this->shadePath(shadedPath.get(), paint, *d.fMatrix, &fill, &stroke)); 1.1251 + 1.1252 + bool xpsTransformsPath = true; 1.1253 + //Transform the geometry. 1.1254 + if (transformRect && xpsTransformsPath) { 1.1255 + SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform; 1.1256 + HRV(this->createXpsTransform(*d.fMatrix, &xpsTransform)); 1.1257 + if (xpsTransform.get()) { 1.1258 + HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()), 1.1259 + "Could not set transform for rect."); 1.1260 + } else { 1.1261 + xpsTransformsPath = false; 1.1262 + } 1.1263 + } 1.1264 + 1.1265 + //Create the figure. 1.1266 + SkTScopedComPtr<IXpsOMGeometryFigure> rectFigure; 1.1267 + { 1.1268 + SkPoint points[4] = { 1.1269 + { r.fLeft, r.fTop }, 1.1270 + { r.fLeft, r.fBottom }, 1.1271 + { r.fRight, r.fBottom }, 1.1272 + { r.fRight, r.fTop }, 1.1273 + }; 1.1274 + if (!xpsTransformsPath && transformRect) { 1.1275 + d.fMatrix->mapPoints(points, SK_ARRAY_COUNT(points)); 1.1276 + } 1.1277 + HRV(this->createXpsQuad(points, stroke, fill, &rectFigure)); 1.1278 + } 1.1279 + 1.1280 + //Get the figures of the shaded geometry. 1.1281 + SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures; 1.1282 + HRVM(shadedGeometry->GetFigures(&shadedFigures), 1.1283 + "Could not get shaded figures for rect."); 1.1284 + 1.1285 + //Add the figure to the shaded geometry figures. 1.1286 + HRVM(shadedFigures->Append(rectFigure.get()), 1.1287 + "Could not add shaded figure for rect."); 1.1288 + 1.1289 + HRV(this->clip(shadedPath.get(), d)); 1.1290 + 1.1291 + //Add the shaded path to the current visuals. 1.1292 + SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals; 1.1293 + HRVM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals), 1.1294 + "Could not get current visuals for rect."); 1.1295 + HRVM(currentVisuals->Append(shadedPath.get()), 1.1296 + "Could not add rect to current visuals."); 1.1297 +} 1.1298 + 1.1299 +static HRESULT close_figure(const SkTDArray<XPS_SEGMENT_TYPE>& segmentTypes, 1.1300 + const SkTDArray<BOOL>& segmentStrokes, 1.1301 + const SkTDArray<FLOAT>& segmentData, 1.1302 + BOOL stroke, BOOL fill, 1.1303 + IXpsOMGeometryFigure* figure, 1.1304 + IXpsOMGeometryFigureCollection* figures) { 1.1305 + // Add the segment data to the figure. 1.1306 + HRM(figure->SetSegments(segmentTypes.count(), segmentData.count(), 1.1307 + segmentTypes.begin() , segmentData.begin(), 1.1308 + segmentStrokes.begin()), 1.1309 + "Could not set path segments."); 1.1310 + 1.1311 + // Set the closed and filled properties of the figure. 1.1312 + HRM(figure->SetIsClosed(stroke), "Could not set path closed."); 1.1313 + HRM(figure->SetIsFilled(fill), "Could not set path fill."); 1.1314 + 1.1315 + // Add the figure created above to this geometry. 1.1316 + HRM(figures->Append(figure), "Could not add path to geometry."); 1.1317 + return S_OK; 1.1318 +} 1.1319 + 1.1320 +HRESULT SkXPSDevice::addXpsPathGeometry( 1.1321 + IXpsOMGeometryFigureCollection* xpsFigures, 1.1322 + BOOL stroke, BOOL fill, const SkPath& path) { 1.1323 + SkTDArray<XPS_SEGMENT_TYPE> segmentTypes; 1.1324 + SkTDArray<BOOL> segmentStrokes; 1.1325 + SkTDArray<FLOAT> segmentData; 1.1326 + 1.1327 + SkTScopedComPtr<IXpsOMGeometryFigure> xpsFigure; 1.1328 + SkPath::Iter iter(path, true); 1.1329 + SkPoint points[4]; 1.1330 + SkPath::Verb verb; 1.1331 + while ((verb = iter.next(points)) != SkPath::kDone_Verb) { 1.1332 + switch (verb) { 1.1333 + case SkPath::kMove_Verb: { 1.1334 + if (NULL != xpsFigure.get()) { 1.1335 + HR(close_figure(segmentTypes, segmentStrokes, segmentData, 1.1336 + stroke, fill, 1.1337 + xpsFigure.get() , xpsFigures)); 1.1338 + xpsFigure.reset(); 1.1339 + segmentTypes.rewind(); 1.1340 + segmentStrokes.rewind(); 1.1341 + segmentData.rewind(); 1.1342 + } 1.1343 + // Define the start point. 1.1344 + XPS_POINT startPoint = xps_point(points[0]); 1.1345 + // Create the figure. 1.1346 + HRM(this->fXpsFactory->CreateGeometryFigure(&startPoint, 1.1347 + &xpsFigure), 1.1348 + "Could not create path geometry figure."); 1.1349 + break; 1.1350 + } 1.1351 + case SkPath::kLine_Verb: 1.1352 + if (iter.isCloseLine()) break; //ignore the line, auto-closed 1.1353 + segmentTypes.push(XPS_SEGMENT_TYPE_LINE); 1.1354 + segmentStrokes.push(stroke); 1.1355 + segmentData.push(SkScalarToFLOAT(points[1].fX)); 1.1356 + segmentData.push(SkScalarToFLOAT(points[1].fY)); 1.1357 + break; 1.1358 + case SkPath::kQuad_Verb: 1.1359 + segmentTypes.push(XPS_SEGMENT_TYPE_QUADRATIC_BEZIER); 1.1360 + segmentStrokes.push(stroke); 1.1361 + segmentData.push(SkScalarToFLOAT(points[1].fX)); 1.1362 + segmentData.push(SkScalarToFLOAT(points[1].fY)); 1.1363 + segmentData.push(SkScalarToFLOAT(points[2].fX)); 1.1364 + segmentData.push(SkScalarToFLOAT(points[2].fY)); 1.1365 + break; 1.1366 + case SkPath::kCubic_Verb: 1.1367 + segmentTypes.push(XPS_SEGMENT_TYPE_BEZIER); 1.1368 + segmentStrokes.push(stroke); 1.1369 + segmentData.push(SkScalarToFLOAT(points[1].fX)); 1.1370 + segmentData.push(SkScalarToFLOAT(points[1].fY)); 1.1371 + segmentData.push(SkScalarToFLOAT(points[2].fX)); 1.1372 + segmentData.push(SkScalarToFLOAT(points[2].fY)); 1.1373 + segmentData.push(SkScalarToFLOAT(points[3].fX)); 1.1374 + segmentData.push(SkScalarToFLOAT(points[3].fY)); 1.1375 + break; 1.1376 + case SkPath::kClose_Verb: 1.1377 + // we ignore these, and just get the whole segment from 1.1378 + // the corresponding line/quad/cubic verbs 1.1379 + break; 1.1380 + default: 1.1381 + SkDEBUGFAIL("unexpected verb"); 1.1382 + break; 1.1383 + } 1.1384 + } 1.1385 + if (NULL != xpsFigure.get()) { 1.1386 + HR(close_figure(segmentTypes, segmentStrokes, segmentData, 1.1387 + stroke, fill, 1.1388 + xpsFigure.get(), xpsFigures)); 1.1389 + } 1.1390 + return S_OK; 1.1391 +} 1.1392 + 1.1393 +HRESULT SkXPSDevice::drawInverseWindingPath(const SkDraw& d, 1.1394 + const SkPath& devicePath, 1.1395 + IXpsOMPath* shadedPath) { 1.1396 + const SkRect universeRect = SkRect::MakeLTRB(0, 0, 1.1397 + this->fCurrentCanvasSize.fWidth, this->fCurrentCanvasSize.fHeight); 1.1398 + 1.1399 + const XPS_RECT universeRectXps = { 1.1400 + 0.0f, 0.0f, 1.1401 + SkScalarToFLOAT(this->fCurrentCanvasSize.fWidth), 1.1402 + SkScalarToFLOAT(this->fCurrentCanvasSize.fHeight), 1.1403 + }; 1.1404 + 1.1405 + //Get the geometry. 1.1406 + SkTScopedComPtr<IXpsOMGeometry> shadedGeometry; 1.1407 + HRM(shadedPath->GetGeometry(&shadedGeometry), 1.1408 + "Could not get shaded geometry for inverse path."); 1.1409 + 1.1410 + //Get the figures from the geometry. 1.1411 + SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures; 1.1412 + HRM(shadedGeometry->GetFigures(&shadedFigures), 1.1413 + "Could not get shaded figures for inverse path."); 1.1414 + 1.1415 + HRM(shadedGeometry->SetFillRule(XPS_FILL_RULE_NONZERO), 1.1416 + "Could not set shaded fill rule for inverse path."); 1.1417 + 1.1418 + //Take everything drawn so far, and make a shared resource out of it. 1.1419 + //Replace everything drawn so far with 1.1420 + //inverse canvas 1.1421 + // old canvas of everything so far 1.1422 + // world shaded figure, clipped to current clip 1.1423 + // top canvas of everything so far, clipped to path 1.1424 + //Note: this is not quite right when there is nothing solid in the 1.1425 + //canvas of everything so far, as the bit on top will allow 1.1426 + //the world paint to show through. 1.1427 + 1.1428 + //Create new canvas. 1.1429 + SkTScopedComPtr<IXpsOMCanvas> newCanvas; 1.1430 + HRM(this->fXpsFactory->CreateCanvas(&newCanvas), 1.1431 + "Could not create inverse canvas."); 1.1432 + 1.1433 + //Save the old canvas to a dictionary on the new canvas. 1.1434 + SkTScopedComPtr<IXpsOMDictionary> newDictionary; 1.1435 + HRM(this->fXpsFactory->CreateDictionary(&newDictionary), 1.1436 + "Could not create inverse dictionary."); 1.1437 + HRM(newCanvas->SetDictionaryLocal(newDictionary.get()), 1.1438 + "Could not set inverse dictionary."); 1.1439 + 1.1440 + const size_t size = SK_ARRAY_COUNT(L"ID" L_GUID_ID); 1.1441 + wchar_t buffer[size]; 1.1442 + wchar_t id[GUID_ID_LEN]; 1.1443 + HR(create_id(id, GUID_ID_LEN, '_')); 1.1444 + swprintf_s(buffer, size, L"ID%s", id); 1.1445 + HRM(newDictionary->Append(buffer, this->fCurrentXpsCanvas.get()), 1.1446 + "Could not add canvas to inverse dictionary."); 1.1447 + 1.1448 + //Start drawing 1.1449 + SkTScopedComPtr<IXpsOMVisualCollection> newVisuals; 1.1450 + HRM(newCanvas->GetVisuals(&newVisuals), 1.1451 + "Could not get inverse canvas visuals."); 1.1452 + 1.1453 + //Draw old canvas from dictionary onto new canvas. 1.1454 + SkTScopedComPtr<IXpsOMGeometry> oldGeometry; 1.1455 + HRM(this->fXpsFactory->CreateGeometry(&oldGeometry), 1.1456 + "Could not create old inverse geometry."); 1.1457 + 1.1458 + SkTScopedComPtr<IXpsOMGeometryFigureCollection> oldFigures; 1.1459 + HRM(oldGeometry->GetFigures(&oldFigures), 1.1460 + "Could not get old inverse figures."); 1.1461 + 1.1462 + SkTScopedComPtr<IXpsOMGeometryFigure> oldFigure; 1.1463 + HR(this->createXpsRect(universeRect, FALSE, TRUE, &oldFigure)); 1.1464 + HRM(oldFigures->Append(oldFigure.get()), 1.1465 + "Could not add old inverse figure."); 1.1466 + 1.1467 + SkTScopedComPtr<IXpsOMVisualBrush> oldBrush; 1.1468 + HRM(this->fXpsFactory->CreateVisualBrush(&universeRectXps, 1.1469 + &universeRectXps, 1.1470 + &oldBrush), 1.1471 + "Could not create old inverse brush."); 1.1472 + 1.1473 + SkTScopedComPtr<IXpsOMPath> oldPath; 1.1474 + HRM(this->fXpsFactory->CreatePath(&oldPath), 1.1475 + "Could not create old inverse path."); 1.1476 + HRM(oldPath->SetGeometryLocal(oldGeometry.get()), 1.1477 + "Could not set old inverse geometry."); 1.1478 + HRM(oldPath->SetFillBrushLocal(oldBrush.get()), 1.1479 + "Could not set old inverse fill brush."); 1.1480 + //the brush must be parented before setting the lookup. 1.1481 + HRM(newVisuals->Append(oldPath.get()), 1.1482 + "Could not add old inverse path to new canvas visuals."); 1.1483 + HRM(oldBrush->SetVisualLookup(buffer), 1.1484 + "Could not set old inverse brush visual lookup."); 1.1485 + 1.1486 + //Draw the clip filling shader. 1.1487 + SkTScopedComPtr<IXpsOMGeometryFigure> shadedFigure; 1.1488 + HR(this->createXpsRect(universeRect, FALSE, TRUE, &shadedFigure)); 1.1489 + HRM(shadedFigures->Append(shadedFigure.get()), 1.1490 + "Could not add inverse shaded figure."); 1.1491 + //the geometry is already set 1.1492 + HR(this->clip(shadedPath, d)); 1.1493 + HRM(newVisuals->Append(shadedPath), 1.1494 + "Could not add inverse shaded path to canvas visuals."); 1.1495 + 1.1496 + //Draw the old canvas on top, clipped to the original path. 1.1497 + SkTScopedComPtr<IXpsOMCanvas> topCanvas; 1.1498 + HRM(this->fXpsFactory->CreateCanvas(&topCanvas), 1.1499 + "Could not create top inverse canvas."); 1.1500 + //Clip the canvas to prevent alpha spill. 1.1501 + //This is the entire reason this canvas exists. 1.1502 + HR(this->clip(topCanvas.get(), d)); 1.1503 + 1.1504 + SkTScopedComPtr<IXpsOMGeometry> topGeometry; 1.1505 + HRM(this->fXpsFactory->CreateGeometry(&topGeometry), 1.1506 + "Could not create top inverse geometry."); 1.1507 + 1.1508 + SkTScopedComPtr<IXpsOMGeometryFigureCollection> topFigures; 1.1509 + HRM(topGeometry->GetFigures(&topFigures), 1.1510 + "Could not get top inverse figures."); 1.1511 + 1.1512 + SkTScopedComPtr<IXpsOMGeometryFigure> topFigure; 1.1513 + HR(this->createXpsRect(universeRect, FALSE, TRUE, &topFigure)); 1.1514 + HRM(topFigures->Append(topFigure.get()), 1.1515 + "Could not add old inverse figure."); 1.1516 + 1.1517 + SkTScopedComPtr<IXpsOMVisualBrush> topBrush; 1.1518 + HRM(this->fXpsFactory->CreateVisualBrush(&universeRectXps, 1.1519 + &universeRectXps, 1.1520 + &topBrush), 1.1521 + "Could not create top inverse brush."); 1.1522 + 1.1523 + SkTScopedComPtr<IXpsOMPath> topPath; 1.1524 + HRM(this->fXpsFactory->CreatePath(&topPath), 1.1525 + "Could not create top inverse path."); 1.1526 + HRM(topPath->SetGeometryLocal(topGeometry.get()), 1.1527 + "Could not set top inverse geometry."); 1.1528 + HRM(topPath->SetFillBrushLocal(topBrush.get()), 1.1529 + "Could not set top inverse fill brush."); 1.1530 + //the brush must be parented before setting the lookup. 1.1531 + HRM(newVisuals->Append(topCanvas.get()), 1.1532 + "Could not add top canvas to inverse canvas visuals."); 1.1533 + SkTScopedComPtr<IXpsOMVisualCollection> topVisuals; 1.1534 + HRM(topCanvas->GetVisuals(&topVisuals), 1.1535 + "Could not get top inverse canvas visuals."); 1.1536 + HRM(topVisuals->Append(topPath.get()), 1.1537 + "Could not add top inverse path to top canvas visuals."); 1.1538 + HRM(topBrush->SetVisualLookup(buffer), 1.1539 + "Could not set top inverse brush visual lookup."); 1.1540 + 1.1541 + HR(this->clipToPath(topPath.get(), devicePath, XPS_FILL_RULE_NONZERO)); 1.1542 + 1.1543 + //swap current canvas to new canvas 1.1544 + this->fCurrentXpsCanvas.swap(newCanvas); 1.1545 + 1.1546 + return S_OK; 1.1547 +} 1.1548 + 1.1549 +void SkXPSDevice::convertToPpm(const SkMaskFilter* filter, 1.1550 + SkMatrix* matrix, 1.1551 + SkVector* ppuScale, 1.1552 + const SkIRect& clip, SkIRect* clipIRect) { 1.1553 + //This action is in unit space, but the ppm is specified in physical space. 1.1554 + ppuScale->fX = SkScalarDiv(this->fCurrentPixelsPerMeter.fX, 1.1555 + this->fCurrentUnitsPerMeter.fX); 1.1556 + ppuScale->fY = SkScalarDiv(this->fCurrentPixelsPerMeter.fY, 1.1557 + this->fCurrentUnitsPerMeter.fY); 1.1558 + 1.1559 + matrix->postScale(ppuScale->fX, ppuScale->fY); 1.1560 + 1.1561 + const SkIRect& irect = clip; 1.1562 + SkRect clipRect = SkRect::MakeLTRB( 1.1563 + SkScalarMul(SkIntToScalar(irect.fLeft), ppuScale->fX), 1.1564 + SkScalarMul(SkIntToScalar(irect.fTop), ppuScale->fY), 1.1565 + SkScalarMul(SkIntToScalar(irect.fRight), ppuScale->fX), 1.1566 + SkScalarMul(SkIntToScalar(irect.fBottom), ppuScale->fY)); 1.1567 + clipRect.roundOut(clipIRect); 1.1568 +} 1.1569 + 1.1570 +HRESULT SkXPSDevice::applyMask(const SkDraw& d, 1.1571 + const SkMask& mask, 1.1572 + const SkVector& ppuScale, 1.1573 + IXpsOMPath* shadedPath) { 1.1574 + //Get the geometry object. 1.1575 + SkTScopedComPtr<IXpsOMGeometry> shadedGeometry; 1.1576 + HRM(shadedPath->GetGeometry(&shadedGeometry), 1.1577 + "Could not get mask shaded geometry."); 1.1578 + 1.1579 + //Get the figures from the geometry. 1.1580 + SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures; 1.1581 + HRM(shadedGeometry->GetFigures(&shadedFigures), 1.1582 + "Could not get mask shaded figures."); 1.1583 + 1.1584 + SkMatrix m; 1.1585 + m.reset(); 1.1586 + m.setTranslate(SkIntToScalar(mask.fBounds.fLeft), 1.1587 + SkIntToScalar(mask.fBounds.fTop)); 1.1588 + m.postScale(SkScalarInvert(ppuScale.fX), SkScalarInvert(ppuScale.fY)); 1.1589 + 1.1590 + SkShader::TileMode xy[2]; 1.1591 + xy[0] = (SkShader::TileMode)3; 1.1592 + xy[1] = (SkShader::TileMode)3; 1.1593 + 1.1594 + SkBitmap bm; 1.1595 + bm.setConfig(SkBitmap::kA8_Config, 1.1596 + mask.fBounds.width(), 1.1597 + mask.fBounds.height(), 1.1598 + mask.fRowBytes); 1.1599 + bm.setPixels(mask.fImage); 1.1600 + 1.1601 + SkTScopedComPtr<IXpsOMTileBrush> maskBrush; 1.1602 + HR(this->createXpsImageBrush(bm, m, xy, 0xFF, &maskBrush)); 1.1603 + HRM(shadedPath->SetOpacityMaskBrushLocal(maskBrush.get()), 1.1604 + "Could not set mask."); 1.1605 + 1.1606 + const SkRect universeRect = SkRect::MakeLTRB(0, 0, 1.1607 + this->fCurrentCanvasSize.fWidth, this->fCurrentCanvasSize.fHeight); 1.1608 + SkTScopedComPtr<IXpsOMGeometryFigure> shadedFigure; 1.1609 + HRM(this->createXpsRect(universeRect, FALSE, TRUE, &shadedFigure), 1.1610 + "Could not create mask shaded figure."); 1.1611 + HRM(shadedFigures->Append(shadedFigure.get()), 1.1612 + "Could not add mask shaded figure."); 1.1613 + 1.1614 + HR(this->clip(shadedPath, d)); 1.1615 + 1.1616 + //Add the path to the active visual collection. 1.1617 + SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals; 1.1618 + HRM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals), 1.1619 + "Could not get mask current visuals."); 1.1620 + HRM(currentVisuals->Append(shadedPath), 1.1621 + "Could not add masked shaded path to current visuals."); 1.1622 + 1.1623 + return S_OK; 1.1624 +} 1.1625 + 1.1626 +HRESULT SkXPSDevice::shadePath(IXpsOMPath* shadedPath, 1.1627 + const SkPaint& shaderPaint, 1.1628 + const SkMatrix& matrix, 1.1629 + BOOL* fill, BOOL* stroke) { 1.1630 + *fill = FALSE; 1.1631 + *stroke = FALSE; 1.1632 + 1.1633 + const SkPaint::Style style = shaderPaint.getStyle(); 1.1634 + const bool hasFill = SkPaint::kFill_Style == style 1.1635 + || SkPaint::kStrokeAndFill_Style == style; 1.1636 + const bool hasStroke = SkPaint::kStroke_Style == style 1.1637 + || SkPaint::kStrokeAndFill_Style == style; 1.1638 + 1.1639 + //TODO(bungeman): use dictionaries and lookups. 1.1640 + if (hasFill) { 1.1641 + *fill = TRUE; 1.1642 + SkTScopedComPtr<IXpsOMBrush> fillBrush; 1.1643 + HR(this->createXpsBrush(shaderPaint, &fillBrush, &matrix)); 1.1644 + HRM(shadedPath->SetFillBrushLocal(fillBrush.get()), 1.1645 + "Could not set fill for shaded path."); 1.1646 + } 1.1647 + 1.1648 + if (hasStroke) { 1.1649 + *stroke = TRUE; 1.1650 + SkTScopedComPtr<IXpsOMBrush> strokeBrush; 1.1651 + HR(this->createXpsBrush(shaderPaint, &strokeBrush, &matrix)); 1.1652 + HRM(shadedPath->SetStrokeBrushLocal(strokeBrush.get()), 1.1653 + "Could not set stroke brush for shaded path."); 1.1654 + HRM(shadedPath->SetStrokeThickness( 1.1655 + SkScalarToFLOAT(shaderPaint.getStrokeWidth())), 1.1656 + "Could not set shaded path stroke thickness."); 1.1657 + 1.1658 + if (0 == shaderPaint.getStrokeWidth()) { 1.1659 + //XPS hair width is a hack. (XPS Spec 11.6.12). 1.1660 + SkTScopedComPtr<IXpsOMDashCollection> dashes; 1.1661 + HRM(shadedPath->GetStrokeDashes(&dashes), 1.1662 + "Could not set dashes for shaded path."); 1.1663 + XPS_DASH dash; 1.1664 + dash.length = 1.0; 1.1665 + dash.gap = 0.0; 1.1666 + HRM(dashes->Append(&dash), "Could not add dashes to shaded path."); 1.1667 + HRM(shadedPath->SetStrokeDashOffset(-2.0), 1.1668 + "Could not set dash offset for shaded path."); 1.1669 + } 1.1670 + } 1.1671 + return S_OK; 1.1672 +} 1.1673 + 1.1674 +void SkXPSDevice::drawPath(const SkDraw& d, 1.1675 + const SkPath& platonicPath, 1.1676 + const SkPaint& origPaint, 1.1677 + const SkMatrix* prePathMatrix, 1.1678 + bool pathIsMutable) { 1.1679 + SkTCopyOnFirstWrite<SkPaint> paint(origPaint); 1.1680 + 1.1681 + // nothing to draw 1.1682 + if (d.fClip->isEmpty() || 1.1683 + (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) { 1.1684 + return; 1.1685 + } 1.1686 + 1.1687 + SkPath modifiedPath; 1.1688 + const bool paintHasPathEffect = paint->getPathEffect() 1.1689 + || paint->getStyle() != SkPaint::kFill_Style; 1.1690 + 1.1691 + //Apply pre-path matrix [Platonic-path -> Skeletal-path]. 1.1692 + SkMatrix matrix = *d.fMatrix; 1.1693 + SkPath* skeletalPath = const_cast<SkPath*>(&platonicPath); 1.1694 + if (prePathMatrix) { 1.1695 + if (paintHasPathEffect || paint->getRasterizer()) { 1.1696 + if (!pathIsMutable) { 1.1697 + skeletalPath = &modifiedPath; 1.1698 + pathIsMutable = true; 1.1699 + } 1.1700 + platonicPath.transform(*prePathMatrix, skeletalPath); 1.1701 + } else { 1.1702 + if (!matrix.preConcat(*prePathMatrix)) { 1.1703 + return; 1.1704 + } 1.1705 + } 1.1706 + } 1.1707 + 1.1708 + //Apply path effect [Skeletal-path -> Fillable-path]. 1.1709 + SkPath* fillablePath = skeletalPath; 1.1710 + if (paintHasPathEffect) { 1.1711 + if (!pathIsMutable) { 1.1712 + fillablePath = &modifiedPath; 1.1713 + pathIsMutable = true; 1.1714 + } 1.1715 + bool fill = paint->getFillPath(*skeletalPath, fillablePath); 1.1716 + 1.1717 + SkPaint* writablePaint = paint.writable(); 1.1718 + writablePaint->setPathEffect(NULL); 1.1719 + if (fill) { 1.1720 + writablePaint->setStyle(SkPaint::kFill_Style); 1.1721 + } else { 1.1722 + writablePaint->setStyle(SkPaint::kStroke_Style); 1.1723 + writablePaint->setStrokeWidth(0); 1.1724 + } 1.1725 + } 1.1726 + 1.1727 + //Create the shaded path. This will be the path which is painted. 1.1728 + SkTScopedComPtr<IXpsOMPath> shadedPath; 1.1729 + HRVM(this->fXpsFactory->CreatePath(&shadedPath), 1.1730 + "Could not create shaded path for path."); 1.1731 + 1.1732 + //Create the geometry for the shaded path. 1.1733 + SkTScopedComPtr<IXpsOMGeometry> shadedGeometry; 1.1734 + HRVM(this->fXpsFactory->CreateGeometry(&shadedGeometry), 1.1735 + "Could not create shaded geometry for path."); 1.1736 + 1.1737 + //Add the geometry to the shaded path. 1.1738 + HRVM(shadedPath->SetGeometryLocal(shadedGeometry.get()), 1.1739 + "Could not add the shaded geometry to shaded path."); 1.1740 + 1.1741 + SkRasterizer* rasterizer = paint->getRasterizer(); 1.1742 + SkMaskFilter* filter = paint->getMaskFilter(); 1.1743 + 1.1744 + //Determine if we will draw or shade and mask. 1.1745 + if (rasterizer || filter) { 1.1746 + if (paint->getStyle() != SkPaint::kFill_Style) { 1.1747 + paint.writable()->setStyle(SkPaint::kFill_Style); 1.1748 + } 1.1749 + } 1.1750 + 1.1751 + //Set the brushes. 1.1752 + BOOL fill; 1.1753 + BOOL stroke; 1.1754 + HRV(this->shadePath(shadedPath.get(), 1.1755 + *paint, 1.1756 + *d.fMatrix, 1.1757 + &fill, 1.1758 + &stroke)); 1.1759 + 1.1760 + //Rasterizer 1.1761 + if (rasterizer) { 1.1762 + SkIRect clipIRect; 1.1763 + SkVector ppuScale; 1.1764 + this->convertToPpm(filter, 1.1765 + &matrix, 1.1766 + &ppuScale, 1.1767 + d.fClip->getBounds(), 1.1768 + &clipIRect); 1.1769 + 1.1770 + SkMask* mask = NULL; 1.1771 + 1.1772 + //[Fillable-path -> Mask] 1.1773 + SkMask rasteredMask; 1.1774 + if (rasterizer->rasterize( 1.1775 + *fillablePath, 1.1776 + matrix, 1.1777 + &clipIRect, 1.1778 + filter, //just to compute how much to draw. 1.1779 + &rasteredMask, 1.1780 + SkMask::kComputeBoundsAndRenderImage_CreateMode)) { 1.1781 + 1.1782 + SkAutoMaskFreeImage rasteredAmi(rasteredMask.fImage); 1.1783 + mask = &rasteredMask; 1.1784 + 1.1785 + //[Mask -> Mask] 1.1786 + SkMask filteredMask; 1.1787 + if (filter && 1.1788 + filter->filterMask(&filteredMask, *mask, *d.fMatrix, NULL)) { 1.1789 + 1.1790 + mask = &filteredMask; 1.1791 + } else { 1.1792 + filteredMask.fImage = NULL; 1.1793 + } 1.1794 + SkAutoMaskFreeImage filteredAmi(filteredMask.fImage); 1.1795 + 1.1796 + //Draw mask. 1.1797 + HRV(this->applyMask(d, *mask, ppuScale, shadedPath.get())); 1.1798 + } 1.1799 + return; 1.1800 + } 1.1801 + 1.1802 + //Mask filter 1.1803 + if (filter) { 1.1804 + SkIRect clipIRect; 1.1805 + SkVector ppuScale; 1.1806 + this->convertToPpm(filter, 1.1807 + &matrix, 1.1808 + &ppuScale, 1.1809 + d.fClip->getBounds(), 1.1810 + &clipIRect); 1.1811 + 1.1812 + //[Fillable-path -> Pixel-path] 1.1813 + SkPath* pixelPath = pathIsMutable ? fillablePath : &modifiedPath; 1.1814 + fillablePath->transform(matrix, pixelPath); 1.1815 + 1.1816 + SkMask* mask = NULL; 1.1817 + 1.1818 + //[Pixel-path -> Mask] 1.1819 + SkMask rasteredMask; 1.1820 + if (SkDraw::DrawToMask( 1.1821 + *pixelPath, 1.1822 + &clipIRect, 1.1823 + filter, //just to compute how much to draw. 1.1824 + &matrix, 1.1825 + &rasteredMask, 1.1826 + SkMask::kComputeBoundsAndRenderImage_CreateMode, 1.1827 + paint->getStyle())) { 1.1828 + 1.1829 + SkAutoMaskFreeImage rasteredAmi(rasteredMask.fImage); 1.1830 + mask = &rasteredMask; 1.1831 + 1.1832 + //[Mask -> Mask] 1.1833 + SkMask filteredMask; 1.1834 + if (filter->filterMask(&filteredMask, 1.1835 + rasteredMask, 1.1836 + matrix, 1.1837 + NULL)) { 1.1838 + mask = &filteredMask; 1.1839 + } else { 1.1840 + filteredMask.fImage = NULL; 1.1841 + } 1.1842 + SkAutoMaskFreeImage filteredAmi(filteredMask.fImage); 1.1843 + 1.1844 + //Draw mask. 1.1845 + HRV(this->applyMask(d, *mask, ppuScale, shadedPath.get())); 1.1846 + } 1.1847 + return; 1.1848 + } 1.1849 + 1.1850 + //Get the figures from the shaded geometry. 1.1851 + SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures; 1.1852 + HRVM(shadedGeometry->GetFigures(&shadedFigures), 1.1853 + "Could not get shaded figures for shaded path."); 1.1854 + 1.1855 + bool xpsTransformsPath = true; 1.1856 + 1.1857 + //Set the fill rule. 1.1858 + XPS_FILL_RULE xpsFillRule; 1.1859 + switch (platonicPath.getFillType()) { 1.1860 + case SkPath::kWinding_FillType: 1.1861 + xpsFillRule = XPS_FILL_RULE_NONZERO; 1.1862 + break; 1.1863 + case SkPath::kEvenOdd_FillType: 1.1864 + xpsFillRule = XPS_FILL_RULE_EVENODD; 1.1865 + break; 1.1866 + case SkPath::kInverseWinding_FillType: { 1.1867 + //[Fillable-path -> Device-path] 1.1868 + SkPath* devicePath = pathIsMutable ? fillablePath : &modifiedPath; 1.1869 + fillablePath->transform(matrix, devicePath); 1.1870 + 1.1871 + HRV(this->drawInverseWindingPath(d, 1.1872 + *devicePath, 1.1873 + shadedPath.get())); 1.1874 + return; 1.1875 + } 1.1876 + case SkPath::kInverseEvenOdd_FillType: { 1.1877 + const SkRect universe = SkRect::MakeLTRB( 1.1878 + 0, 0, 1.1879 + this->fCurrentCanvasSize.fWidth, 1.1880 + this->fCurrentCanvasSize.fHeight); 1.1881 + SkTScopedComPtr<IXpsOMGeometryFigure> addOneFigure; 1.1882 + HRV(this->createXpsRect(universe, FALSE, TRUE, &addOneFigure)); 1.1883 + HRVM(shadedFigures->Append(addOneFigure.get()), 1.1884 + "Could not add even-odd flip figure to shaded path."); 1.1885 + xpsTransformsPath = false; 1.1886 + xpsFillRule = XPS_FILL_RULE_EVENODD; 1.1887 + break; 1.1888 + } 1.1889 + default: 1.1890 + SkDEBUGFAIL("Unknown SkPath::FillType."); 1.1891 + } 1.1892 + HRVM(shadedGeometry->SetFillRule(xpsFillRule), 1.1893 + "Could not set fill rule for shaded path."); 1.1894 + 1.1895 + //Create the XPS transform, if possible. 1.1896 + if (xpsTransformsPath) { 1.1897 + SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform; 1.1898 + HRV(this->createXpsTransform(matrix, &xpsTransform)); 1.1899 + 1.1900 + if (xpsTransform.get()) { 1.1901 + HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()), 1.1902 + "Could not set transform on shaded path."); 1.1903 + } else { 1.1904 + xpsTransformsPath = false; 1.1905 + } 1.1906 + } 1.1907 + 1.1908 + SkPath* devicePath = fillablePath; 1.1909 + if (!xpsTransformsPath) { 1.1910 + //[Fillable-path -> Device-path] 1.1911 + devicePath = pathIsMutable ? fillablePath : &modifiedPath; 1.1912 + fillablePath->transform(matrix, devicePath); 1.1913 + } 1.1914 + HRV(this->addXpsPathGeometry(shadedFigures.get(), 1.1915 + stroke, fill, *devicePath)); 1.1916 + 1.1917 + HRV(this->clip(shadedPath.get(), d)); 1.1918 + 1.1919 + //Add the path to the active visual collection. 1.1920 + SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals; 1.1921 + HRVM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals), 1.1922 + "Could not get current visuals for shaded path."); 1.1923 + HRVM(currentVisuals->Append(shadedPath.get()), 1.1924 + "Could not add shaded path to current visuals."); 1.1925 +} 1.1926 + 1.1927 +HRESULT SkXPSDevice::clip(IXpsOMVisual* xpsVisual, const SkDraw& d) { 1.1928 + SkPath clipPath; 1.1929 + SkAssertResult(d.fClip->getBoundaryPath(&clipPath)); 1.1930 + 1.1931 + return this->clipToPath(xpsVisual, clipPath, XPS_FILL_RULE_EVENODD); 1.1932 +} 1.1933 +HRESULT SkXPSDevice::clipToPath(IXpsOMVisual* xpsVisual, 1.1934 + const SkPath& clipPath, 1.1935 + XPS_FILL_RULE fillRule) { 1.1936 + //Create the geometry. 1.1937 + SkTScopedComPtr<IXpsOMGeometry> clipGeometry; 1.1938 + HRM(this->fXpsFactory->CreateGeometry(&clipGeometry), 1.1939 + "Could not create clip geometry."); 1.1940 + 1.1941 + //Get the figure collection of the geometry. 1.1942 + SkTScopedComPtr<IXpsOMGeometryFigureCollection> clipFigures; 1.1943 + HRM(clipGeometry->GetFigures(&clipFigures), 1.1944 + "Could not get the clip figures."); 1.1945 + 1.1946 + //Create the figures into the geometry. 1.1947 + HR(this->addXpsPathGeometry( 1.1948 + clipFigures.get(), 1.1949 + FALSE, TRUE, clipPath)); 1.1950 + 1.1951 + HRM(clipGeometry->SetFillRule(fillRule), 1.1952 + "Could not set fill rule."); 1.1953 + HRM(xpsVisual->SetClipGeometryLocal(clipGeometry.get()), 1.1954 + "Could not set clip geometry."); 1.1955 + 1.1956 + return S_OK; 1.1957 +} 1.1958 + 1.1959 +void SkXPSDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap, 1.1960 + const SkMatrix& matrix, const SkPaint& paint) { 1.1961 + if (d.fClip->isEmpty()) { 1.1962 + return; 1.1963 + } 1.1964 + 1.1965 + SkIRect srcRect; 1.1966 + srcRect.set(0, 0, bitmap.width(), bitmap.height()); 1.1967 + 1.1968 + //Create the new shaded path. 1.1969 + SkTScopedComPtr<IXpsOMPath> shadedPath; 1.1970 + HRVM(this->fXpsFactory->CreatePath(&shadedPath), 1.1971 + "Could not create path for bitmap."); 1.1972 + 1.1973 + //Create the shaded geometry. 1.1974 + SkTScopedComPtr<IXpsOMGeometry> shadedGeometry; 1.1975 + HRVM(this->fXpsFactory->CreateGeometry(&shadedGeometry), 1.1976 + "Could not create geometry for bitmap."); 1.1977 + 1.1978 + //Add the shaded geometry to the shaded path. 1.1979 + HRVM(shadedPath->SetGeometryLocal(shadedGeometry.get()), 1.1980 + "Could not set the geometry for bitmap."); 1.1981 + 1.1982 + //Get the shaded figures from the shaded geometry. 1.1983 + SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures; 1.1984 + HRVM(shadedGeometry->GetFigures(&shadedFigures), 1.1985 + "Could not get the figures for bitmap."); 1.1986 + 1.1987 + SkMatrix transform = matrix; 1.1988 + transform.postConcat(*d.fMatrix); 1.1989 + 1.1990 + SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform; 1.1991 + HRV(this->createXpsTransform(transform, &xpsTransform)); 1.1992 + if (xpsTransform.get()) { 1.1993 + HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()), 1.1994 + "Could not set transform for bitmap."); 1.1995 + } else { 1.1996 + //TODO: perspective that bitmap! 1.1997 + } 1.1998 + 1.1999 + SkTScopedComPtr<IXpsOMGeometryFigure> rectFigure; 1.2000 + if (NULL != xpsTransform.get()) { 1.2001 + const SkShader::TileMode xy[2] = { 1.2002 + SkShader::kClamp_TileMode, 1.2003 + SkShader::kClamp_TileMode, 1.2004 + }; 1.2005 + SkTScopedComPtr<IXpsOMTileBrush> xpsImageBrush; 1.2006 + HRV(this->createXpsImageBrush(bitmap, 1.2007 + transform, 1.2008 + xy, 1.2009 + paint.getAlpha(), 1.2010 + &xpsImageBrush)); 1.2011 + HRVM(shadedPath->SetFillBrushLocal(xpsImageBrush.get()), 1.2012 + "Could not set bitmap brush."); 1.2013 + 1.2014 + const SkRect bitmapRect = SkRect::MakeLTRB(0, 0, 1.2015 + SkIntToScalar(srcRect.width()), SkIntToScalar(srcRect.height())); 1.2016 + HRV(this->createXpsRect(bitmapRect, FALSE, TRUE, &rectFigure)); 1.2017 + } 1.2018 + HRVM(shadedFigures->Append(rectFigure.get()), 1.2019 + "Could not add bitmap figure."); 1.2020 + 1.2021 + //Get the current visual collection and add the shaded path to it. 1.2022 + SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals; 1.2023 + HRVM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals), 1.2024 + "Could not get current visuals for bitmap"); 1.2025 + HRVM(currentVisuals->Append(shadedPath.get()), 1.2026 + "Could not add bitmap to current visuals."); 1.2027 + 1.2028 + HRV(this->clip(shadedPath.get(), d)); 1.2029 +} 1.2030 + 1.2031 +void SkXPSDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, 1.2032 + int x, int y, 1.2033 + const SkPaint& paint) { 1.2034 + //TODO: override this for XPS 1.2035 + SkDEBUGF(("XPS drawSprite not yet implemented.")); 1.2036 +} 1.2037 + 1.2038 +HRESULT SkXPSDevice::CreateTypefaceUse(const SkPaint& paint, 1.2039 + TypefaceUse** typefaceUse) { 1.2040 + SkAutoResolveDefaultTypeface typeface(paint.getTypeface()); 1.2041 + 1.2042 + //Check cache. 1.2043 + const SkFontID typefaceID = typeface->uniqueID(); 1.2044 + if (!this->fTypefaces.empty()) { 1.2045 + TypefaceUse* current = &this->fTypefaces.front(); 1.2046 + const TypefaceUse* last = &this->fTypefaces.back(); 1.2047 + for (; current <= last; ++current) { 1.2048 + if (current->typefaceId == typefaceID) { 1.2049 + *typefaceUse = current; 1.2050 + return S_OK; 1.2051 + } 1.2052 + } 1.2053 + } 1.2054 + 1.2055 + //TODO: create glyph only fonts 1.2056 + //and let the host deal with what kind of font we're looking at. 1.2057 + XPS_FONT_EMBEDDING embedding = XPS_FONT_EMBEDDING_RESTRICTED; 1.2058 + 1.2059 + SkTScopedComPtr<IStream> fontStream; 1.2060 + int ttcIndex; 1.2061 + SkStream* fontData = typeface->openStream(&ttcIndex); 1.2062 + //TODO: cannot handle FON fonts. 1.2063 + HRM(SkIStream::CreateFromSkStream(fontData, true, &fontStream), 1.2064 + "Could not create font stream."); 1.2065 + 1.2066 + const size_t size = 1.2067 + SK_ARRAY_COUNT(L"/Resources/Fonts/" L_GUID_ID L".odttf"); 1.2068 + wchar_t buffer[size]; 1.2069 + wchar_t id[GUID_ID_LEN]; 1.2070 + HR(create_id(id, GUID_ID_LEN)); 1.2071 + swprintf_s(buffer, size, L"/Resources/Fonts/%s.odttf", id); 1.2072 + 1.2073 + SkTScopedComPtr<IOpcPartUri> partUri; 1.2074 + HRM(this->fXpsFactory->CreatePartUri(buffer, &partUri), 1.2075 + "Could not create font resource part uri."); 1.2076 + 1.2077 + SkTScopedComPtr<IXpsOMFontResource> xpsFontResource; 1.2078 + HRM(this->fXpsFactory->CreateFontResource(fontStream.get(), 1.2079 + embedding, 1.2080 + partUri.get(), 1.2081 + FALSE, 1.2082 + &xpsFontResource), 1.2083 + "Could not create font resource."); 1.2084 + 1.2085 + //TODO: change openStream to return -1 for non-ttc, get rid of this. 1.2086 + uint8_t* data = (uint8_t*)fontData->getMemoryBase(); 1.2087 + bool isTTC = (data && 1.2088 + fontData->getLength() >= sizeof(SkTTCFHeader) && 1.2089 + ((SkTTCFHeader*)data)->ttcTag == SkTTCFHeader::TAG); 1.2090 + 1.2091 + TypefaceUse& newTypefaceUse = this->fTypefaces.push_back(); 1.2092 + newTypefaceUse.typefaceId = typefaceID; 1.2093 + newTypefaceUse.ttcIndex = isTTC ? ttcIndex : -1; 1.2094 + newTypefaceUse.fontData = fontData; 1.2095 + newTypefaceUse.xpsFont = xpsFontResource.release(); 1.2096 + 1.2097 + SkAutoGlyphCache agc(paint, NULL, &SkMatrix::I()); 1.2098 + SkGlyphCache* glyphCache = agc.getCache(); 1.2099 + unsigned int glyphCount = glyphCache->getGlyphCount(); 1.2100 + newTypefaceUse.glyphsUsed = new SkBitSet(glyphCount); 1.2101 + 1.2102 + *typefaceUse = &newTypefaceUse; 1.2103 + return S_OK; 1.2104 +} 1.2105 + 1.2106 +HRESULT SkXPSDevice::AddGlyphs(const SkDraw& d, 1.2107 + IXpsOMObjectFactory* xpsFactory, 1.2108 + IXpsOMCanvas* canvas, 1.2109 + TypefaceUse* font, 1.2110 + LPCWSTR text, 1.2111 + XPS_GLYPH_INDEX* xpsGlyphs, 1.2112 + UINT32 xpsGlyphsLen, 1.2113 + XPS_POINT *origin, 1.2114 + FLOAT fontSize, 1.2115 + XPS_STYLE_SIMULATION sims, 1.2116 + const SkMatrix& transform, 1.2117 + const SkPaint& paint) { 1.2118 + SkTScopedComPtr<IXpsOMGlyphs> glyphs; 1.2119 + HRM(xpsFactory->CreateGlyphs(font->xpsFont, &glyphs), "Could not create glyphs."); 1.2120 + HRM(glyphs->SetFontFaceIndex(font->ttcIndex), "Could not set glyph font face index."); 1.2121 + 1.2122 + //XPS uses affine transformations for everything... 1.2123 + //...except positioning text. 1.2124 + bool useCanvasForClip; 1.2125 + if ((transform.getType() & ~SkMatrix::kTranslate_Mask) == 0) { 1.2126 + origin->x += SkScalarToFLOAT(transform.getTranslateX()); 1.2127 + origin->y += SkScalarToFLOAT(transform.getTranslateY()); 1.2128 + useCanvasForClip = false; 1.2129 + } else { 1.2130 + SkTScopedComPtr<IXpsOMMatrixTransform> xpsMatrixToUse; 1.2131 + HR(this->createXpsTransform(transform, &xpsMatrixToUse)); 1.2132 + if (xpsMatrixToUse.get()) { 1.2133 + HRM(glyphs->SetTransformLocal(xpsMatrixToUse.get()), 1.2134 + "Could not set transform matrix."); 1.2135 + useCanvasForClip = true; 1.2136 + } else { 1.2137 + SkDEBUGFAIL("Attempt to add glyphs in perspective."); 1.2138 + useCanvasForClip = false; 1.2139 + } 1.2140 + } 1.2141 + 1.2142 + SkTScopedComPtr<IXpsOMGlyphsEditor> glyphsEditor; 1.2143 + HRM(glyphs->GetGlyphsEditor(&glyphsEditor), "Could not get glyph editor."); 1.2144 + 1.2145 + if (NULL != text) { 1.2146 + HRM(glyphsEditor->SetUnicodeString(text), 1.2147 + "Could not set unicode string."); 1.2148 + } 1.2149 + 1.2150 + if (NULL != xpsGlyphs) { 1.2151 + HRM(glyphsEditor->SetGlyphIndices(xpsGlyphsLen, xpsGlyphs), 1.2152 + "Could not set glyphs."); 1.2153 + } 1.2154 + 1.2155 + HRM(glyphsEditor->ApplyEdits(), "Could not apply glyph edits."); 1.2156 + 1.2157 + SkTScopedComPtr<IXpsOMBrush> xpsFillBrush; 1.2158 + HR(this->createXpsBrush( 1.2159 + paint, 1.2160 + &xpsFillBrush, 1.2161 + useCanvasForClip ? NULL : &transform)); 1.2162 + 1.2163 + HRM(glyphs->SetFillBrushLocal(xpsFillBrush.get()), 1.2164 + "Could not set fill brush."); 1.2165 + 1.2166 + HRM(glyphs->SetOrigin(origin), "Could not set glyph origin."); 1.2167 + 1.2168 + HRM(glyphs->SetFontRenderingEmSize(fontSize), 1.2169 + "Could not set font size."); 1.2170 + 1.2171 + HRM(glyphs->SetStyleSimulations(sims), 1.2172 + "Could not set style simulations."); 1.2173 + 1.2174 + SkTScopedComPtr<IXpsOMVisualCollection> visuals; 1.2175 + HRM(canvas->GetVisuals(&visuals), "Could not get glyph canvas visuals."); 1.2176 + 1.2177 + if (!useCanvasForClip) { 1.2178 + HR(this->clip(glyphs.get(), d)); 1.2179 + HRM(visuals->Append(glyphs.get()), "Could not add glyphs to canvas."); 1.2180 + } else { 1.2181 + SkTScopedComPtr<IXpsOMCanvas> glyphCanvas; 1.2182 + HRM(this->fXpsFactory->CreateCanvas(&glyphCanvas), 1.2183 + "Could not create glyph canvas."); 1.2184 + 1.2185 + SkTScopedComPtr<IXpsOMVisualCollection> glyphCanvasVisuals; 1.2186 + HRM(glyphCanvas->GetVisuals(&glyphCanvasVisuals), 1.2187 + "Could not get glyph visuals collection."); 1.2188 + 1.2189 + HRM(glyphCanvasVisuals->Append(glyphs.get()), 1.2190 + "Could not add glyphs to page."); 1.2191 + HR(this->clip(glyphCanvas.get(), d)); 1.2192 + 1.2193 + HRM(visuals->Append(glyphCanvas.get()), 1.2194 + "Could not add glyph canvas to page."); 1.2195 + } 1.2196 + 1.2197 + return S_OK; 1.2198 +} 1.2199 + 1.2200 +struct SkXPSDrawProcs : public SkDrawProcs { 1.2201 +public: 1.2202 + /** [in] Advance width and offsets for glyphs measured in 1.2203 + hundredths of the font em size (XPS Spec 5.1.3). */ 1.2204 + FLOAT centemPerUnit; 1.2205 + /** [in,out] The accumulated glyphs used in the current typeface. */ 1.2206 + SkBitSet* glyphUse; 1.2207 + /** [out] The glyphs to draw. */ 1.2208 + SkTDArray<XPS_GLYPH_INDEX> xpsGlyphs; 1.2209 +}; 1.2210 + 1.2211 +static void xps_draw_1_glyph(const SkDraw1Glyph& state, 1.2212 + SkFixed x, SkFixed y, 1.2213 + const SkGlyph& skGlyph) { 1.2214 + SkASSERT(skGlyph.fWidth > 0 && skGlyph.fHeight > 0); 1.2215 + 1.2216 + SkXPSDrawProcs* procs = static_cast<SkXPSDrawProcs*>(state.fDraw->fProcs); 1.2217 + 1.2218 + //Draw pre-adds half the sampling frequency for floor rounding. 1.2219 + x -= state.fHalfSampleX; 1.2220 + y -= state.fHalfSampleY; 1.2221 + 1.2222 + XPS_GLYPH_INDEX* xpsGlyph = procs->xpsGlyphs.append(); 1.2223 + uint16_t glyphID = skGlyph.getGlyphID(); 1.2224 + procs->glyphUse->setBit(glyphID, true); 1.2225 + xpsGlyph->index = glyphID; 1.2226 + if (1 == procs->xpsGlyphs.count()) { 1.2227 + xpsGlyph->advanceWidth = 0.0f; 1.2228 + xpsGlyph->horizontalOffset = SkFixedToFloat(x) * procs->centemPerUnit; 1.2229 + xpsGlyph->verticalOffset = SkFixedToFloat(y) * -procs->centemPerUnit; 1.2230 + } else { 1.2231 + const XPS_GLYPH_INDEX& first = procs->xpsGlyphs[0]; 1.2232 + xpsGlyph->advanceWidth = 0.0f; 1.2233 + xpsGlyph->horizontalOffset = (SkFixedToFloat(x) * procs->centemPerUnit) 1.2234 + - first.horizontalOffset; 1.2235 + xpsGlyph->verticalOffset = (SkFixedToFloat(y) * -procs->centemPerUnit) 1.2236 + - first.verticalOffset; 1.2237 + } 1.2238 +} 1.2239 + 1.2240 +static void text_draw_init(const SkPaint& paint, 1.2241 + const void* text, size_t byteLength, 1.2242 + SkBitSet& glyphsUsed, 1.2243 + SkDraw& myDraw, SkXPSDrawProcs& procs) { 1.2244 + procs.fD1GProc = xps_draw_1_glyph; 1.2245 + size_t numGlyphGuess; 1.2246 + switch (paint.getTextEncoding()) { 1.2247 + case SkPaint::kUTF8_TextEncoding: 1.2248 + numGlyphGuess = SkUTF8_CountUnichars( 1.2249 + static_cast<const char *>(text), 1.2250 + byteLength); 1.2251 + break; 1.2252 + case SkPaint::kUTF16_TextEncoding: 1.2253 + numGlyphGuess = SkUTF16_CountUnichars( 1.2254 + static_cast<const uint16_t *>(text), 1.2255 + byteLength); 1.2256 + break; 1.2257 + case SkPaint::kGlyphID_TextEncoding: 1.2258 + numGlyphGuess = byteLength / 2; 1.2259 + break; 1.2260 + default: 1.2261 + SK_DEBUGBREAK(true); 1.2262 + } 1.2263 + procs.xpsGlyphs.setReserve(numGlyphGuess); 1.2264 + procs.glyphUse = &glyphsUsed; 1.2265 + procs.centemPerUnit = 100.0f / SkScalarToFLOAT(paint.getTextSize()); 1.2266 + 1.2267 + myDraw.fProcs = &procs; 1.2268 +} 1.2269 + 1.2270 +static bool text_must_be_pathed(const SkPaint& paint, const SkMatrix& matrix) { 1.2271 + const SkPaint::Style style = paint.getStyle(); 1.2272 + return matrix.hasPerspective() 1.2273 + || SkPaint::kStroke_Style == style 1.2274 + || SkPaint::kStrokeAndFill_Style == style 1.2275 + || paint.getMaskFilter() 1.2276 + || paint.getRasterizer() 1.2277 + ; 1.2278 +} 1.2279 + 1.2280 +void SkXPSDevice::drawText(const SkDraw& d, 1.2281 + const void* text, size_t byteLen, 1.2282 + SkScalar x, SkScalar y, 1.2283 + const SkPaint& paint) { 1.2284 + if (byteLen < 1) return; 1.2285 + 1.2286 + if (text_must_be_pathed(paint, *d.fMatrix)) { 1.2287 + SkPath path; 1.2288 + paint.getTextPath(text, byteLen, x, y, &path); 1.2289 + this->drawPath(d, path, paint, NULL, true); 1.2290 + //TODO: add automation "text" 1.2291 + return; 1.2292 + } 1.2293 + 1.2294 + TypefaceUse* typeface; 1.2295 + HRV(CreateTypefaceUse(paint, &typeface)); 1.2296 + 1.2297 + SkDraw myDraw(d); 1.2298 + myDraw.fMatrix = &SkMatrix::I(); 1.2299 + SkXPSDrawProcs procs; 1.2300 + text_draw_init(paint, text, byteLen, *typeface->glyphsUsed, myDraw, procs); 1.2301 + 1.2302 + myDraw.drawText(static_cast<const char*>(text), byteLen, x, y, paint); 1.2303 + 1.2304 + // SkDraw may have clipped out the glyphs, so we need to check 1.2305 + if (procs.xpsGlyphs.count() == 0) { 1.2306 + return; 1.2307 + } 1.2308 + 1.2309 + XPS_POINT origin = { 1.2310 + procs.xpsGlyphs[0].horizontalOffset / procs.centemPerUnit, 1.2311 + procs.xpsGlyphs[0].verticalOffset / -procs.centemPerUnit, 1.2312 + }; 1.2313 + procs.xpsGlyphs[0].horizontalOffset = 0.0f; 1.2314 + procs.xpsGlyphs[0].verticalOffset = 0.0f; 1.2315 + 1.2316 + HRV(AddGlyphs(d, 1.2317 + this->fXpsFactory.get(), 1.2318 + this->fCurrentXpsCanvas.get(), 1.2319 + typeface, 1.2320 + NULL, 1.2321 + procs.xpsGlyphs.begin(), procs.xpsGlyphs.count(), 1.2322 + &origin, 1.2323 + SkScalarToFLOAT(paint.getTextSize()), 1.2324 + XPS_STYLE_SIMULATION_NONE, 1.2325 + *d.fMatrix, 1.2326 + paint)); 1.2327 +} 1.2328 + 1.2329 +void SkXPSDevice::drawPosText(const SkDraw& d, 1.2330 + const void* text, size_t byteLen, 1.2331 + const SkScalar pos[], 1.2332 + SkScalar constY, int scalarsPerPos, 1.2333 + const SkPaint& paint) { 1.2334 + if (byteLen < 1) return; 1.2335 + 1.2336 + if (text_must_be_pathed(paint, *d.fMatrix)) { 1.2337 + SkPath path; 1.2338 + //TODO: make this work, Draw currently does not handle as well. 1.2339 + //paint.getTextPath(text, byteLength, x, y, &path); 1.2340 + //this->drawPath(d, path, paint, NULL, true); 1.2341 + //TODO: add automation "text" 1.2342 + return; 1.2343 + } 1.2344 + 1.2345 + TypefaceUse* typeface; 1.2346 + HRV(CreateTypefaceUse(paint, &typeface)); 1.2347 + 1.2348 + SkDraw myDraw(d); 1.2349 + myDraw.fMatrix = &SkMatrix::I(); 1.2350 + SkXPSDrawProcs procs; 1.2351 + text_draw_init(paint, text, byteLen, *typeface->glyphsUsed, myDraw, procs); 1.2352 + 1.2353 + myDraw.drawPosText(static_cast<const char*>(text), byteLen, 1.2354 + pos, constY, scalarsPerPos, 1.2355 + paint); 1.2356 + 1.2357 + // SkDraw may have clipped out the glyphs, so we need to check 1.2358 + if (procs.xpsGlyphs.count() == 0) { 1.2359 + return; 1.2360 + } 1.2361 + 1.2362 + XPS_POINT origin = { 1.2363 + procs.xpsGlyphs[0].horizontalOffset / procs.centemPerUnit, 1.2364 + procs.xpsGlyphs[0].verticalOffset / -procs.centemPerUnit, 1.2365 + }; 1.2366 + procs.xpsGlyphs[0].horizontalOffset = 0.0f; 1.2367 + procs.xpsGlyphs[0].verticalOffset = 0.0f; 1.2368 + 1.2369 + HRV(AddGlyphs(d, 1.2370 + this->fXpsFactory.get(), 1.2371 + this->fCurrentXpsCanvas.get(), 1.2372 + typeface, 1.2373 + NULL, 1.2374 + procs.xpsGlyphs.begin(), procs.xpsGlyphs.count(), 1.2375 + &origin, 1.2376 + SkScalarToFLOAT(paint.getTextSize()), 1.2377 + XPS_STYLE_SIMULATION_NONE, 1.2378 + *d.fMatrix, 1.2379 + paint)); 1.2380 +} 1.2381 + 1.2382 +void SkXPSDevice::drawTextOnPath(const SkDraw& d, const void* text, size_t len, 1.2383 + const SkPath& path, const SkMatrix* matrix, 1.2384 + const SkPaint& paint) { 1.2385 + //This will call back into the device to do the drawing. 1.2386 + d.drawTextOnPath((const char*)text, len, path, matrix, paint); 1.2387 +} 1.2388 + 1.2389 +void SkXPSDevice::drawDevice(const SkDraw& d, SkBaseDevice* dev, 1.2390 + int x, int y, 1.2391 + const SkPaint&) { 1.2392 + SkXPSDevice* that = static_cast<SkXPSDevice*>(dev); 1.2393 + 1.2394 + SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform; 1.2395 + XPS_MATRIX rawTransform = { 1.2396 + 1.0f, 1.2397 + 0.0f, 1.2398 + 0.0f, 1.2399 + 1.0f, 1.2400 + static_cast<FLOAT>(x), 1.2401 + static_cast<FLOAT>(y), 1.2402 + }; 1.2403 + HRVM(this->fXpsFactory->CreateMatrixTransform(&rawTransform, &xpsTransform), 1.2404 + "Could not create layer transform."); 1.2405 + HRVM(that->fCurrentXpsCanvas->SetTransformLocal(xpsTransform.get()), 1.2406 + "Could not set layer transform."); 1.2407 + 1.2408 + //Get the current visual collection and add the layer to it. 1.2409 + SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals; 1.2410 + HRVM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals), 1.2411 + "Could not get current visuals for layer."); 1.2412 + HRVM(currentVisuals->Append(that->fCurrentXpsCanvas.get()), 1.2413 + "Could not add layer to current visuals."); 1.2414 +} 1.2415 + 1.2416 +bool SkXPSDevice::onReadPixels(const SkBitmap& bitmap, int x, int y, 1.2417 + SkCanvas::Config8888) { 1.2418 + return false; 1.2419 +} 1.2420 + 1.2421 +SkBaseDevice* SkXPSDevice::onCreateDevice(const SkImageInfo&, Usage) { 1.2422 +//Conditional for bug compatibility with PDF device. 1.2423 +#if 0 1.2424 + if (SkBaseDevice::kGeneral_Usage == usage) { 1.2425 + return NULL; 1.2426 + SK_CRASH(); 1.2427 + //To what stream do we write? 1.2428 + //SkXPSDevice* dev = new SkXPSDevice(this); 1.2429 + //SkSize s = SkSize::Make(width, height); 1.2430 + //dev->BeginCanvas(s, s, SkMatrix::I()); 1.2431 + //return dev; 1.2432 + } 1.2433 +#endif 1.2434 + return new SkXPSDevice(this->fXpsFactory.get()); 1.2435 +} 1.2436 + 1.2437 +SkXPSDevice::SkXPSDevice(IXpsOMObjectFactory* xpsFactory) 1.2438 + : SkBitmapDevice(make_fake_bitmap(10000, 10000)) 1.2439 + , fCurrentPage(0) { 1.2440 + 1.2441 + HRVM(CoCreateInstance( 1.2442 + CLSID_XpsOMObjectFactory, 1.2443 + NULL, 1.2444 + CLSCTX_INPROC_SERVER, 1.2445 + IID_PPV_ARGS(&this->fXpsFactory)), 1.2446 + "Could not create factory for layer."); 1.2447 + 1.2448 + HRVM(this->fXpsFactory->CreateCanvas(&this->fCurrentXpsCanvas), 1.2449 + "Could not create canvas for layer."); 1.2450 +} 1.2451 + 1.2452 +bool SkXPSDevice::allowImageFilter(const SkImageFilter*) { 1.2453 + return false; 1.2454 +}