blob: 5db644c30ab00dafc68e71ff15a0787ca099fa6a [file] [log] [blame]
bungeman@google.comb29c8832011-10-10 13:19:10 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
halcanary47ef4d52015-03-03 09:13:09 -08008#include "SkTypes.h"
mtklein1ee76512015-11-02 10:20:27 -08009#if defined(SK_BUILD_FOR_WIN32)
halcanary47ef4d52015-03-03 09:13:09 -080010
halcanary4dbbd042016-06-07 17:21:10 -070011#include "SkLeanWindows.h"
12
bungeman@google.comb29c8832011-10-10 13:19:10 +000013#ifndef UNICODE
14#define UNICODE
15#endif
16#ifndef _UNICODE
17#define _UNICODE
18#endif
bungeman@google.comb29c8832011-10-10 13:19:10 +000019#include <ObjBase.h>
20#include <XpsObjectModel.h>
21#include <T2EmbApi.h>
22#include <FontSub.h>
halcanarybfa92752016-05-31 11:23:42 -070023#include <limits>
bungeman@google.comb29c8832011-10-10 13:19:10 +000024
25#include "SkColor.h"
bungeman@google.comb29c8832011-10-10 13:19:10 +000026#include "SkData.h"
27#include "SkDraw.h"
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +000028#include "SkEndian.h"
herbbda26432015-11-24 08:37:01 -080029#include "SkFindAndPlaceGlyph.h"
halcanary47ef4d52015-03-03 09:13:09 -080030#include "SkGeometry.h"
bungeman@google.comb29c8832011-10-10 13:19:10 +000031#include "SkGlyphCache.h"
32#include "SkHRESULT.h"
Mike Reed627778d2016-09-28 17:13:38 -040033#include "SkImage.h"
bungeman@google.comb29c8832011-10-10 13:19:10 +000034#include "SkImageEncoder.h"
35#include "SkIStream.h"
36#include "SkMaskFilter.h"
37#include "SkPaint.h"
reeda4393342016-03-18 11:22:57 -070038#include "SkPathEffect.h"
Ben Wagnerda5a1b82014-08-22 15:07:06 -040039#include "SkPathOps.h"
bungeman@google.comb29c8832011-10-10 13:19:10 +000040#include "SkPoint.h"
reed1e7f5e72016-04-27 07:49:17 -070041#include "SkRasterClip.h"
bungeman@google.comb29c8832011-10-10 13:19:10 +000042#include "SkRasterizer.h"
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +000043#include "SkSFNTHeader.h"
bungeman@google.comb29c8832011-10-10 13:19:10 +000044#include "SkShader.h"
45#include "SkSize.h"
46#include "SkStream.h"
47#include "SkTDArray.h"
48#include "SkTLazy.h"
49#include "SkTScopedComPtr.h"
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +000050#include "SkTTCFHeader.h"
reed@google.com398de9a2013-03-21 21:43:51 +000051#include "SkTypefacePriv.h"
bungeman@google.comb29c8832011-10-10 13:19:10 +000052#include "SkUtils.h"
53#include "SkXPSDevice.h"
54
55//Windows defines a FLOAT type,
56//make it clear when converting a scalar that this is what is wanted.
57#define SkScalarToFLOAT(n) SkScalarToFloat(n)
58
Ben Wagnerda5a1b82014-08-22 15:07:06 -040059//Dummy representation of a GUID from createId.
bungeman@google.comb29c8832011-10-10 13:19:10 +000060#define L_GUID_ID L"XXXXXXXXsXXXXsXXXXsXXXXsXXXXXXXXXXXX"
halcanary96fcdcc2015-08-27 07:41:13 -070061//Length of GUID representation from createId, including nullptr terminator.
bungeman@google.comb29c8832011-10-10 13:19:10 +000062#define GUID_ID_LEN SK_ARRAY_COUNT(L_GUID_ID)
63
64/**
65 Formats a GUID and places it into buffer.
66 buffer should have space for at least GUID_ID_LEN wide characters.
67 The string will always be wchar null terminated.
68 XXXXXXXXsXXXXsXXXXsXXXXsXXXXXXXXXXXX0
69 @return -1 if there was an error, > 0 if success.
70 */
71static int format_guid(const GUID& guid,
72 wchar_t* buffer, size_t bufferSize,
73 wchar_t sep = '-') {
74 SkASSERT(bufferSize >= GUID_ID_LEN);
75 return swprintf_s(buffer,
76 bufferSize,
77 L"%08lX%c%04X%c%04X%c%02X%02X%c%02X%02X%02X%02X%02X%02X",
78 guid.Data1,
79 sep,
80 guid.Data2,
81 sep,
82 guid.Data3,
83 sep,
84 guid.Data4[0],
85 guid.Data4[1],
86 sep,
87 guid.Data4[2],
88 guid.Data4[3],
89 guid.Data4[4],
90 guid.Data4[5],
91 guid.Data4[6],
92 guid.Data4[7]);
93}
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +000094
Ben Wagnerda5a1b82014-08-22 15:07:06 -040095HRESULT SkXPSDevice::createId(wchar_t* buffer, size_t bufferSize, wchar_t sep) {
bungeman@google.comb29c8832011-10-10 13:19:10 +000096 GUID guid = {};
Ben Wagnerda5a1b82014-08-22 15:07:06 -040097#ifdef SK_XPS_USE_DETERMINISTIC_IDS
98 guid.Data1 = fNextId++;
99 // The following make this a valid Type4 UUID.
100 guid.Data3 = 0x4000;
101 guid.Data4[0] = 0x80;
102#else
bungeman@google.comb29c8832011-10-10 13:19:10 +0000103 HRM(CoCreateGuid(&guid), "Could not create GUID for id.");
Ben Wagnerda5a1b82014-08-22 15:07:06 -0400104#endif
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000105
bungeman@google.comb29c8832011-10-10 13:19:10 +0000106 if (format_guid(guid, buffer, bufferSize, sep) == -1) {
107 HRM(E_UNEXPECTED, "Could not format GUID into id.");
108 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000109
bungeman@google.comb29c8832011-10-10 13:19:10 +0000110 return S_OK;
111}
112
113static SkBitmap make_fake_bitmap(int width, int height) {
114 SkBitmap bitmap;
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000115 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
bungeman@google.comb29c8832011-10-10 13:19:10 +0000116 return bitmap;
117}
118
reed@google.com900ecf22014-02-20 20:55:37 +0000119// TODO: should inherit from SkBaseDevice instead of SkBitmapDevice...
bungeman@google.comb29c8832011-10-10 13:19:10 +0000120SkXPSDevice::SkXPSDevice()
robertphillips9a53fd72015-06-22 09:46:59 -0700121 : INHERITED(make_fake_bitmap(10000, 10000), SkSurfaceProps(0, kUnknown_SkPixelGeometry))
bungeman@google.comb29c8832011-10-10 13:19:10 +0000122 , fCurrentPage(0) {
123}
124
robertphillips9a53fd72015-06-22 09:46:59 -0700125SkXPSDevice::SkXPSDevice(IXpsOMObjectFactory* xpsFactory)
126 : INHERITED(make_fake_bitmap(10000, 10000), SkSurfaceProps(0, kUnknown_SkPixelGeometry))
127 , fCurrentPage(0) {
128
129 HRVM(CoCreateInstance(
130 CLSID_XpsOMObjectFactory,
halcanary96fcdcc2015-08-27 07:41:13 -0700131 nullptr,
robertphillips9a53fd72015-06-22 09:46:59 -0700132 CLSCTX_INPROC_SERVER,
133 IID_PPV_ARGS(&this->fXpsFactory)),
134 "Could not create factory for layer.");
135
136 HRVM(this->fXpsFactory->CreateCanvas(&this->fCurrentXpsCanvas),
137 "Could not create canvas for layer.");
138}
139
bungeman@google.comb29c8832011-10-10 13:19:10 +0000140SkXPSDevice::~SkXPSDevice() {
141}
142
143SkXPSDevice::TypefaceUse::TypefaceUse()
144 : typefaceId(0xffffffff)
halcanary96fcdcc2015-08-27 07:41:13 -0700145 , fontData(nullptr)
146 , xpsFont(nullptr)
147 , glyphsUsed(nullptr) {
bungeman@google.comb29c8832011-10-10 13:19:10 +0000148}
149
150SkXPSDevice::TypefaceUse::~TypefaceUse() {
151 //xpsFont owns fontData ref
152 this->xpsFont->Release();
153 delete this->glyphsUsed;
154}
155
156bool SkXPSDevice::beginPortfolio(SkWStream* outputStream) {
157 if (!this->fAutoCo.succeeded()) return false;
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000158
bungeman@google.comb29c8832011-10-10 13:19:10 +0000159 //Create XPS Factory.
160 HRBM(CoCreateInstance(
161 CLSID_XpsOMObjectFactory,
halcanary96fcdcc2015-08-27 07:41:13 -0700162 nullptr,
bungeman@google.comb29c8832011-10-10 13:19:10 +0000163 CLSCTX_INPROC_SERVER,
164 IID_PPV_ARGS(&this->fXpsFactory)),
165 "Could not create XPS factory.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000166
bungeman@google.comb29c8832011-10-10 13:19:10 +0000167 HRBM(SkWIStream::CreateFromSkWStream(outputStream, &this->fOutputStream),
168 "Could not convert SkStream to IStream.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000169
bungeman@google.comb29c8832011-10-10 13:19:10 +0000170 return true;
171}
172
173bool SkXPSDevice::beginSheet(
174 const SkVector& unitsPerMeter,
175 const SkVector& pixelsPerMeter,
176 const SkSize& trimSize,
177 const SkRect* mediaBox,
178 const SkRect* bleedBox,
179 const SkRect* artBox,
180 const SkRect* cropBox) {
181 ++this->fCurrentPage;
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000182
bungeman@google.comb29c8832011-10-10 13:19:10 +0000183 //For simplicity, just write everything out in geometry units,
184 //then have a base canvas do the scale to physical units.
185 this->fCurrentCanvasSize = trimSize;
186 this->fCurrentUnitsPerMeter = unitsPerMeter;
187 this->fCurrentPixelsPerMeter = pixelsPerMeter;
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000188
bungeman@google.comb29c8832011-10-10 13:19:10 +0000189 this->fCurrentXpsCanvas.reset();
190 HRBM(this->fXpsFactory->CreateCanvas(&this->fCurrentXpsCanvas),
191 "Could not create base canvas.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000192
bungeman@google.comb29c8832011-10-10 13:19:10 +0000193 return true;
194}
195
halcanarybfa92752016-05-31 11:23:42 -0700196template <typename T> static constexpr size_t sk_digits_in() {
197 return static_cast<size_t>(std::numeric_limits<T>::digits10 + 1);
198}
199
bungeman@google.comb29c8832011-10-10 13:19:10 +0000200HRESULT SkXPSDevice::createXpsThumbnail(IXpsOMPage* page,
201 const unsigned int pageNum,
202 IXpsOMImageResource** image) {
203 SkTScopedComPtr<IXpsOMThumbnailGenerator> thumbnailGenerator;
204 HRM(CoCreateInstance(
205 CLSID_XpsOMThumbnailGenerator,
halcanary96fcdcc2015-08-27 07:41:13 -0700206 nullptr,
bungeman@google.comb29c8832011-10-10 13:19:10 +0000207 CLSCTX_INPROC_SERVER,
208 IID_PPV_ARGS(&thumbnailGenerator)),
209 "Could not create thumbnail generator.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000210
bungeman@google.comb29c8832011-10-10 13:19:10 +0000211 SkTScopedComPtr<IOpcPartUri> partUri;
halcanarybfa92752016-05-31 11:23:42 -0700212 constexpr size_t size = SkTMax(
213 SK_ARRAY_COUNT(L"/Documents/1/Metadata/.png") + sk_digits_in<decltype(pageNum)>(),
214 SK_ARRAY_COUNT(L"/Metadata/" L_GUID_ID L".png"));
bungeman@google.comb29c8832011-10-10 13:19:10 +0000215 wchar_t buffer[size];
216 if (pageNum > 0) {
217 swprintf_s(buffer, size, L"/Documents/1/Metadata/%u.png", pageNum);
218 } else {
219 wchar_t id[GUID_ID_LEN];
Ben Wagnerda5a1b82014-08-22 15:07:06 -0400220 HR(this->createId(id, GUID_ID_LEN));
bungeman@google.comb29c8832011-10-10 13:19:10 +0000221 swprintf_s(buffer, size, L"/Metadata/%s.png", id);
222 }
223 HRM(this->fXpsFactory->CreatePartUri(buffer, &partUri),
224 "Could not create thumbnail part uri.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000225
bungeman@google.comb29c8832011-10-10 13:19:10 +0000226 HRM(thumbnailGenerator->GenerateThumbnail(page,
227 XPS_IMAGE_TYPE_PNG,
228 XPS_THUMBNAIL_SIZE_LARGE,
229 partUri.get(),
230 image),
231 "Could not generate thumbnail.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000232
bungeman@google.comb29c8832011-10-10 13:19:10 +0000233 return S_OK;
234}
235
236HRESULT SkXPSDevice::createXpsPage(const XPS_SIZE& pageSize,
237 IXpsOMPage** page) {
halcanarybfa92752016-05-31 11:23:42 -0700238 constexpr size_t size =
239 SK_ARRAY_COUNT(L"/Documents/1/Pages/.fpage")
240 + sk_digits_in<decltype(fCurrentPage)>();
bungeman@google.comb29c8832011-10-10 13:19:10 +0000241 wchar_t buffer[size];
242 swprintf_s(buffer, size, L"/Documents/1/Pages/%u.fpage",
243 this->fCurrentPage);
244 SkTScopedComPtr<IOpcPartUri> partUri;
245 HRM(this->fXpsFactory->CreatePartUri(buffer, &partUri),
246 "Could not create page part uri.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000247
bungeman@google.comb29c8832011-10-10 13:19:10 +0000248 //If the language is unknown, use "und" (XPS Spec 2.3.5.1).
249 HRM(this->fXpsFactory->CreatePage(&pageSize,
250 L"und",
251 partUri.get(),
252 page),
253 "Could not create page.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000254
bungeman@google.comb29c8832011-10-10 13:19:10 +0000255 return S_OK;
256}
257
258HRESULT SkXPSDevice::initXpsDocumentWriter(IXpsOMImageResource* image) {
259 //Create package writer.
260 {
261 SkTScopedComPtr<IOpcPartUri> partUri;
262 HRM(this->fXpsFactory->CreatePartUri(L"/FixedDocumentSequence.fdseq",
263 &partUri),
264 "Could not create document sequence part uri.");
265 HRM(this->fXpsFactory->CreatePackageWriterOnStream(
266 this->fOutputStream.get(),
267 TRUE,
268 XPS_INTERLEAVING_OFF, //XPS_INTERLEAVING_ON,
269 partUri.get(),
halcanary96fcdcc2015-08-27 07:41:13 -0700270 nullptr,
bungeman@google.comb29c8832011-10-10 13:19:10 +0000271 image,
halcanary96fcdcc2015-08-27 07:41:13 -0700272 nullptr,
273 nullptr,
bungeman@google.comb29c8832011-10-10 13:19:10 +0000274 &this->fPackageWriter),
275 "Could not create package writer.");
276 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000277
bungeman@google.comb29c8832011-10-10 13:19:10 +0000278 //Begin the lone document.
279 {
280 SkTScopedComPtr<IOpcPartUri> partUri;
281 HRM(this->fXpsFactory->CreatePartUri(
282 L"/Documents/1/FixedDocument.fdoc",
283 &partUri),
284 "Could not create fixed document part uri.");
285 HRM(this->fPackageWriter->StartNewDocument(partUri.get(),
halcanary96fcdcc2015-08-27 07:41:13 -0700286 nullptr,
287 nullptr,
288 nullptr,
289 nullptr),
bungeman@google.comb29c8832011-10-10 13:19:10 +0000290 "Could not start document.");
291 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000292
bungeman@google.comb29c8832011-10-10 13:19:10 +0000293 return S_OK;
294}
295
296bool SkXPSDevice::endSheet() {
297 //XPS is fixed at 96dpi (XPS Spec 11.1).
298 static const float xpsDPI = 96.0f;
299 static const float inchesPerMeter = 10000.0f / 254.0f;
300 static const float targetUnitsPerMeter = xpsDPI * inchesPerMeter;
301 const float scaleX = targetUnitsPerMeter
302 / SkScalarToFLOAT(this->fCurrentUnitsPerMeter.fX);
303 const float scaleY = targetUnitsPerMeter
304 / SkScalarToFLOAT(this->fCurrentUnitsPerMeter.fY);
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000305
bungeman@google.comb29c8832011-10-10 13:19:10 +0000306 //Create the scale canvas.
307 SkTScopedComPtr<IXpsOMCanvas> scaleCanvas;
308 HRBM(this->fXpsFactory->CreateCanvas(&scaleCanvas),
309 "Could not create scale canvas.");
310 SkTScopedComPtr<IXpsOMVisualCollection> scaleCanvasVisuals;
311 HRBM(scaleCanvas->GetVisuals(&scaleCanvasVisuals),
312 "Could not get scale canvas visuals.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000313
bungeman@google.comb29c8832011-10-10 13:19:10 +0000314 SkTScopedComPtr<IXpsOMMatrixTransform> geomToPhys;
315 XPS_MATRIX rawGeomToPhys = { scaleX, 0, 0, scaleY, 0, 0, };
316 HRBM(this->fXpsFactory->CreateMatrixTransform(&rawGeomToPhys, &geomToPhys),
317 "Could not create geometry to physical transform.");
318 HRBM(scaleCanvas->SetTransformLocal(geomToPhys.get()),
319 "Could not set transform on scale canvas.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000320
bungeman@google.comb29c8832011-10-10 13:19:10 +0000321 //Add the content canvas to the scale canvas.
322 HRBM(scaleCanvasVisuals->Append(this->fCurrentXpsCanvas.get()),
323 "Could not add base canvas to scale canvas.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000324
bungeman@google.comb29c8832011-10-10 13:19:10 +0000325 //Create the page.
326 XPS_SIZE pageSize = {
327 SkScalarToFLOAT(this->fCurrentCanvasSize.width()) * scaleX,
328 SkScalarToFLOAT(this->fCurrentCanvasSize.height()) * scaleY,
329 };
330 SkTScopedComPtr<IXpsOMPage> page;
331 HRB(this->createXpsPage(pageSize, &page));
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000332
bungeman@google.comb29c8832011-10-10 13:19:10 +0000333 SkTScopedComPtr<IXpsOMVisualCollection> pageVisuals;
334 HRBM(page->GetVisuals(&pageVisuals), "Could not get page visuals.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000335
bungeman@google.comb29c8832011-10-10 13:19:10 +0000336 //Add the scale canvas to the page.
337 HRBM(pageVisuals->Append(scaleCanvas.get()),
338 "Could not add scale canvas to page.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000339
bungeman@google.comb29c8832011-10-10 13:19:10 +0000340 //Create the package writer if it hasn't been created yet.
halcanary96fcdcc2015-08-27 07:41:13 -0700341 if (nullptr == this->fPackageWriter.get()) {
bungeman@google.comb29c8832011-10-10 13:19:10 +0000342 SkTScopedComPtr<IXpsOMImageResource> image;
343 //Ignore return, thumbnail is completely optional.
344 this->createXpsThumbnail(page.get(), 0, &image);
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000345
bungeman@google.comb29c8832011-10-10 13:19:10 +0000346 HRB(this->initXpsDocumentWriter(image.get()));
347 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000348
bungeman@google.comb29c8832011-10-10 13:19:10 +0000349 HRBM(this->fPackageWriter->AddPage(page.get(),
350 &pageSize,
halcanary96fcdcc2015-08-27 07:41:13 -0700351 nullptr,
352 nullptr,
353 nullptr,
354 nullptr),
bungeman@google.comb29c8832011-10-10 13:19:10 +0000355 "Could not write the page.");
356 this->fCurrentXpsCanvas.reset();
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000357
bungeman@google.comb29c8832011-10-10 13:19:10 +0000358 return true;
359}
360
361static HRESULT subset_typeface(SkXPSDevice::TypefaceUse* current) {
362 //CreateFontPackage wants unsigned short.
363 //Microsoft, Y U NO stdint.h?
364 SkTDArray<unsigned short> keepList;
365 current->glyphsUsed->exportTo(&keepList);
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000366
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000367 int ttcCount = (current->ttcIndex + 1);
368
bungeman@google.comb29c8832011-10-10 13:19:10 +0000369 //The following are declared with the types required by CreateFontPackage.
halcanary96fcdcc2015-08-27 07:41:13 -0700370 unsigned char *fontPackageBufferRaw = nullptr;
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000371 unsigned long fontPackageBufferSize;
372 unsigned long bytesWritten;
bungeman@google.comb29c8832011-10-10 13:19:10 +0000373 unsigned long result = CreateFontPackage(
374 (unsigned char *) current->fontData->getMemoryBase(),
375 (unsigned long) current->fontData->getLength(),
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000376 &fontPackageBufferRaw,
377 &fontPackageBufferSize,
378 &bytesWritten,
379 TTFCFP_FLAGS_SUBSET | TTFCFP_FLAGS_GLYPHLIST | (ttcCount > 0 ? TTFCFP_FLAGS_TTC : 0),
380 current->ttcIndex,
bungeman@google.comb29c8832011-10-10 13:19:10 +0000381 TTFCFP_SUBSET,
382 0,
383 0,
384 0,
385 keepList.begin(),
386 keepList.count(),
387 sk_malloc_throw,
388 sk_realloc_throw,
389 sk_free,
halcanary96fcdcc2015-08-27 07:41:13 -0700390 nullptr);
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000391 SkAutoTMalloc<unsigned char> fontPackageBuffer(fontPackageBufferRaw);
bungeman@google.comb29c8832011-10-10 13:19:10 +0000392 if (result != NO_ERROR) {
393 SkDEBUGF(("CreateFontPackage Error %lu", result));
394 return E_UNEXPECTED;
395 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000396
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000397 // If it was originally a ttc, keep it a ttc.
398 // CreateFontPackage over-allocates, realloc usually decreases the size substantially.
399 size_t extra;
400 if (ttcCount > 0) {
401 // Create space for a ttc header.
402 extra = sizeof(SkTTCFHeader) + (ttcCount * sizeof(SK_OT_ULONG));
403 fontPackageBuffer.realloc(bytesWritten + extra);
404 //overlap is certain, use memmove
405 memmove(fontPackageBuffer.get() + extra, fontPackageBuffer.get(), bytesWritten);
406
407 // Write the ttc header.
408 SkTTCFHeader* ttcfHeader = reinterpret_cast<SkTTCFHeader*>(fontPackageBuffer.get());
409 ttcfHeader->ttcTag = SkTTCFHeader::TAG;
410 ttcfHeader->version = SkTTCFHeader::version_1;
411 ttcfHeader->numOffsets = SkEndian_SwapBE32(ttcCount);
412 SK_OT_ULONG* offsetPtr = SkTAfter<SK_OT_ULONG>(ttcfHeader);
413 for (int i = 0; i < ttcCount; ++i, ++offsetPtr) {
bsalomon0aa5cea2014-12-15 09:13:35 -0800414 *offsetPtr = SkEndian_SwapBE32(SkToU32(extra));
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000415 }
416
417 // Fix up offsets in sfnt table entries.
418 SkSFNTHeader* sfntHeader = SkTAddOffset<SkSFNTHeader>(fontPackageBuffer.get(), extra);
419 int numTables = SkEndian_SwapBE16(sfntHeader->numTables);
420 SkSFNTHeader::TableDirectoryEntry* tableDirectory =
421 SkTAfter<SkSFNTHeader::TableDirectoryEntry>(sfntHeader);
422 for (int i = 0; i < numTables; ++i, ++tableDirectory) {
423 tableDirectory->offset = SkEndian_SwapBE32(
bsalomon0aa5cea2014-12-15 09:13:35 -0800424 SkToU32(SkEndian_SwapBE32(SkToU32(tableDirectory->offset)) + extra));
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000425 }
426 } else {
427 extra = 0;
428 fontPackageBuffer.realloc(bytesWritten);
429 }
430
scroggoa1193e42015-01-21 12:09:53 -0800431 SkAutoTDelete<SkMemoryStream> newStream(new SkMemoryStream());
mtklein18300a32016-03-16 13:53:35 -0700432 newStream->setMemoryOwned(fontPackageBuffer.release(), bytesWritten + extra);
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000433
bungeman@google.comb29c8832011-10-10 13:19:10 +0000434 SkTScopedComPtr<IStream> newIStream;
mtklein18300a32016-03-16 13:53:35 -0700435 SkIStream::CreateFromSkStream(newStream.release(), true, &newIStream);
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000436
bungeman@google.comb29c8832011-10-10 13:19:10 +0000437 XPS_FONT_EMBEDDING embedding;
438 HRM(current->xpsFont->GetEmbeddingOption(&embedding),
439 "Could not get embedding option from font.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000440
bungeman@google.comb29c8832011-10-10 13:19:10 +0000441 SkTScopedComPtr<IOpcPartUri> partUri;
442 HRM(current->xpsFont->GetPartName(&partUri),
443 "Could not get part uri from font.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000444
bungeman@google.comb29c8832011-10-10 13:19:10 +0000445 HRM(current->xpsFont->SetContent(
446 newIStream.get(),
447 embedding,
448 partUri.get()),
449 "Could not set new stream for subsetted font.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000450
bungeman@google.comb29c8832011-10-10 13:19:10 +0000451 return S_OK;
452}
453
454bool SkXPSDevice::endPortfolio() {
455 //Subset fonts
456 if (!this->fTypefaces.empty()) {
457 SkXPSDevice::TypefaceUse* current = &this->fTypefaces.front();
458 const TypefaceUse* last = &this->fTypefaces.back();
459 for (; current <= last; ++current) {
460 //Ignore return for now, if it didn't subset, let it be.
461 subset_typeface(current);
462 }
463 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000464
bungeman@google.comb29c8832011-10-10 13:19:10 +0000465 HRBM(this->fPackageWriter->Close(), "Could not close writer.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000466
bungeman@google.comb29c8832011-10-10 13:19:10 +0000467 return true;
468}
469
470static XPS_COLOR xps_color(const SkColor skColor) {
471 //XPS uses non-pre-multiplied alpha (XPS Spec 11.4).
472 XPS_COLOR xpsColor;
473 xpsColor.colorType = XPS_COLOR_TYPE_SRGB;
474 xpsColor.value.sRGB.alpha = SkColorGetA(skColor);
475 xpsColor.value.sRGB.red = SkColorGetR(skColor);
476 xpsColor.value.sRGB.green = SkColorGetG(skColor);
477 xpsColor.value.sRGB.blue = SkColorGetB(skColor);
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000478
bungeman@google.comb29c8832011-10-10 13:19:10 +0000479 return xpsColor;
480}
481
482static XPS_POINT xps_point(const SkPoint& point) {
483 XPS_POINT xpsPoint = {
484 SkScalarToFLOAT(point.fX),
485 SkScalarToFLOAT(point.fY),
486 };
487 return xpsPoint;
488}
489
490static XPS_POINT xps_point(const SkPoint& point, const SkMatrix& matrix) {
491 SkPoint skTransformedPoint;
492 matrix.mapXY(point.fX, point.fY, &skTransformedPoint);
493 return xps_point(skTransformedPoint);
494}
495
496static XPS_SPREAD_METHOD xps_spread_method(SkShader::TileMode tileMode) {
497 switch (tileMode) {
498 case SkShader::kClamp_TileMode:
499 return XPS_SPREAD_METHOD_PAD;
500 case SkShader::kRepeat_TileMode:
501 return XPS_SPREAD_METHOD_REPEAT;
502 case SkShader::kMirror_TileMode:
503 return XPS_SPREAD_METHOD_REFLECT;
504 default:
mtklein@google.com330313a2013-08-22 15:37:26 +0000505 SkDEBUGFAIL("Unknown tile mode.");
bungeman@google.comb29c8832011-10-10 13:19:10 +0000506 }
507 return XPS_SPREAD_METHOD_PAD;
508}
509
510static void transform_offsets(SkScalar* stopOffsets, const int numOffsets,
511 const SkPoint& start, const SkPoint& end,
512 const SkMatrix& transform) {
513 SkPoint startTransformed;
514 transform.mapXY(start.fX, start.fY, &startTransformed);
515 SkPoint endTransformed;
516 transform.mapXY(end.fX, end.fY, &endTransformed);
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000517
bungeman@google.comb29c8832011-10-10 13:19:10 +0000518 //Manhattan distance between transformed start and end.
519 SkScalar startToEnd = (endTransformed.fX - startTransformed.fX)
520 + (endTransformed.fY - startTransformed.fY);
521 if (SkScalarNearlyZero(startToEnd)) {
522 for (int i = 0; i < numOffsets; ++i) {
523 stopOffsets[i] = 0;
524 }
525 return;
526 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000527
bungeman@google.comb29c8832011-10-10 13:19:10 +0000528 for (int i = 0; i < numOffsets; ++i) {
529 SkPoint stop;
530 stop.fX = SkScalarMul(end.fX - start.fX, stopOffsets[i]);
531 stop.fY = SkScalarMul(end.fY - start.fY, stopOffsets[i]);
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000532
bungeman@google.comb29c8832011-10-10 13:19:10 +0000533 SkPoint stopTransformed;
534 transform.mapXY(stop.fX, stop.fY, &stopTransformed);
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000535
bungeman@google.comb29c8832011-10-10 13:19:10 +0000536 //Manhattan distance between transformed start and stop.
537 SkScalar startToStop = (stopTransformed.fX - startTransformed.fX)
538 + (stopTransformed.fY - startTransformed.fY);
539 //Percentage along transformed line.
reed80ea19c2015-05-12 10:37:34 -0700540 stopOffsets[i] = startToStop / startToEnd;
bungeman@google.comb29c8832011-10-10 13:19:10 +0000541 }
542}
543
544HRESULT SkXPSDevice::createXpsTransform(const SkMatrix& matrix,
545 IXpsOMMatrixTransform** xpsTransform) {
546 SkScalar affine[6];
547 if (!matrix.asAffine(affine)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700548 *xpsTransform = nullptr;
bungeman@google.comb29c8832011-10-10 13:19:10 +0000549 return S_FALSE;
550 }
551 XPS_MATRIX rawXpsMatrix = {
552 SkScalarToFLOAT(affine[SkMatrix::kAScaleX]),
553 SkScalarToFLOAT(affine[SkMatrix::kASkewY]),
554 SkScalarToFLOAT(affine[SkMatrix::kASkewX]),
555 SkScalarToFLOAT(affine[SkMatrix::kAScaleY]),
556 SkScalarToFLOAT(affine[SkMatrix::kATransX]),
557 SkScalarToFLOAT(affine[SkMatrix::kATransY]),
558 };
559 HRM(this->fXpsFactory->CreateMatrixTransform(&rawXpsMatrix, xpsTransform),
560 "Could not create transform.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000561
bungeman@google.comb29c8832011-10-10 13:19:10 +0000562 return S_OK;
563}
564
565HRESULT SkXPSDevice::createPath(IXpsOMGeometryFigure* figure,
566 IXpsOMVisualCollection* visuals,
567 IXpsOMPath** path) {
568 SkTScopedComPtr<IXpsOMGeometry> geometry;
569 HRM(this->fXpsFactory->CreateGeometry(&geometry),
570 "Could not create geometry.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000571
bungeman@google.comb29c8832011-10-10 13:19:10 +0000572 SkTScopedComPtr<IXpsOMGeometryFigureCollection> figureCollection;
573 HRM(geometry->GetFigures(&figureCollection), "Could not get figures.");
574 HRM(figureCollection->Append(figure), "Could not add figure.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000575
bungeman@google.comb29c8832011-10-10 13:19:10 +0000576 HRM(this->fXpsFactory->CreatePath(path), "Could not create path.");
577 HRM((*path)->SetGeometryLocal(geometry.get()), "Could not set geometry");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000578
bungeman@google.comb29c8832011-10-10 13:19:10 +0000579 HRM(visuals->Append(*path), "Could not add path to visuals.");
580 return S_OK;
581}
582
583HRESULT SkXPSDevice::createXpsSolidColorBrush(const SkColor skColor,
584 const SkAlpha alpha,
585 IXpsOMBrush** xpsBrush) {
586 XPS_COLOR xpsColor = xps_color(skColor);
587 SkTScopedComPtr<IXpsOMSolidColorBrush> solidBrush;
halcanary96fcdcc2015-08-27 07:41:13 -0700588 HRM(this->fXpsFactory->CreateSolidColorBrush(&xpsColor, nullptr, &solidBrush),
bungeman@google.comb29c8832011-10-10 13:19:10 +0000589 "Could not create solid color brush.");
590 HRM(solidBrush->SetOpacity(alpha / 255.0f), "Could not set opacity.");
591 HRM(solidBrush->QueryInterface<IXpsOMBrush>(xpsBrush), "QI Fail.");
592 return S_OK;
593}
594
595HRESULT SkXPSDevice::sideOfClamp(const SkRect& areaToFill,
596 const XPS_RECT& imageViewBox,
597 IXpsOMImageResource* image,
598 IXpsOMVisualCollection* visuals) {
599 SkTScopedComPtr<IXpsOMGeometryFigure> areaToFillFigure;
600 HR(this->createXpsRect(areaToFill, FALSE, TRUE, &areaToFillFigure));
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000601
bungeman@google.comb29c8832011-10-10 13:19:10 +0000602 SkTScopedComPtr<IXpsOMPath> areaToFillPath;
603 HR(this->createPath(areaToFillFigure.get(), visuals, &areaToFillPath));
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000604
bungeman@google.comb29c8832011-10-10 13:19:10 +0000605 SkTScopedComPtr<IXpsOMImageBrush> areaToFillBrush;
606 HRM(this->fXpsFactory->CreateImageBrush(image,
607 &imageViewBox,
608 &imageViewBox,
609 &areaToFillBrush),
610 "Could not create brush for side of clamp.");
611 HRM(areaToFillBrush->SetTileMode(XPS_TILE_MODE_FLIPXY),
612 "Could not set tile mode for side of clamp.");
613 HRM(areaToFillPath->SetFillBrushLocal(areaToFillBrush.get()),
614 "Could not set brush for side of clamp");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000615
bungeman@google.comb29c8832011-10-10 13:19:10 +0000616 return S_OK;
617}
618
619HRESULT SkXPSDevice::cornerOfClamp(const SkRect& areaToFill,
620 const SkColor color,
621 IXpsOMVisualCollection* visuals) {
622 SkTScopedComPtr<IXpsOMGeometryFigure> areaToFillFigure;
623 HR(this->createXpsRect(areaToFill, FALSE, TRUE, &areaToFillFigure));
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000624
bungeman@google.comb29c8832011-10-10 13:19:10 +0000625 SkTScopedComPtr<IXpsOMPath> areaToFillPath;
626 HR(this->createPath(areaToFillFigure.get(), visuals, &areaToFillPath));
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000627
bungeman@google.comb29c8832011-10-10 13:19:10 +0000628 SkTScopedComPtr<IXpsOMBrush> areaToFillBrush;
629 HR(this->createXpsSolidColorBrush(color, 0xFF, &areaToFillBrush));
630 HRM(areaToFillPath->SetFillBrushLocal(areaToFillBrush.get()),
631 "Could not set brush for corner of clamp.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000632
bungeman@google.comb29c8832011-10-10 13:19:10 +0000633 return S_OK;
634}
635
636static const XPS_TILE_MODE XTM_N = XPS_TILE_MODE_NONE;
637static const XPS_TILE_MODE XTM_T = XPS_TILE_MODE_TILE;
638static const XPS_TILE_MODE XTM_X = XPS_TILE_MODE_FLIPX;
639static const XPS_TILE_MODE XTM_Y = XPS_TILE_MODE_FLIPY;
640static const XPS_TILE_MODE XTM_XY = XPS_TILE_MODE_FLIPXY;
641
642//TODO(bungeman): In the future, should skia add None,
643//handle None+Mirror and None+Repeat correctly.
644//None is currently an internal hack so masks don't repeat (None+None only).
645static XPS_TILE_MODE SkToXpsTileMode[SkShader::kTileModeCount+1]
646 [SkShader::kTileModeCount+1] = {
647 //Clamp //Repeat //Mirror //None
648/*Clamp */ XTM_N, XTM_T, XTM_Y, XTM_N,
649/*Repeat*/ XTM_T, XTM_T, XTM_Y, XTM_N,
650/*Mirror*/ XTM_X, XTM_X, XTM_XY, XTM_X,
651/*None */ XTM_N, XTM_N, XTM_Y, XTM_N,
652};
653
654HRESULT SkXPSDevice::createXpsImageBrush(
655 const SkBitmap& bitmap,
656 const SkMatrix& localMatrix,
657 const SkShader::TileMode (&xy)[2],
658 const SkAlpha alpha,
659 IXpsOMTileBrush** xpsBrush) {
660 SkDynamicMemoryWStream write;
661 if (!SkImageEncoder::EncodeStream(&write, bitmap,
662 SkImageEncoder::kPNG_Type, 100)) {
663 HRM(E_FAIL, "Unable to encode bitmap as png.");
664 }
665 SkMemoryStream* read = new SkMemoryStream;
reed42943c82016-09-12 12:01:44 -0700666 read->setData(write.detachAsData());
bungeman@google.comb29c8832011-10-10 13:19:10 +0000667 SkTScopedComPtr<IStream> readWrapper;
668 HRM(SkIStream::CreateFromSkStream(read, true, &readWrapper),
669 "Could not create stream from png data.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000670
bungeman@google.comb29c8832011-10-10 13:19:10 +0000671 const size_t size =
672 SK_ARRAY_COUNT(L"/Documents/1/Resources/Images/" L_GUID_ID L".png");
673 wchar_t buffer[size];
674 wchar_t id[GUID_ID_LEN];
Ben Wagnerda5a1b82014-08-22 15:07:06 -0400675 HR(this->createId(id, GUID_ID_LEN));
bungeman@google.comb29c8832011-10-10 13:19:10 +0000676 swprintf_s(buffer, size, L"/Documents/1/Resources/Images/%s.png", id);
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000677
bungeman@google.comb29c8832011-10-10 13:19:10 +0000678 SkTScopedComPtr<IOpcPartUri> imagePartUri;
679 HRM(this->fXpsFactory->CreatePartUri(buffer, &imagePartUri),
680 "Could not create image part uri.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000681
bungeman@google.comb29c8832011-10-10 13:19:10 +0000682 SkTScopedComPtr<IXpsOMImageResource> imageResource;
683 HRM(this->fXpsFactory->CreateImageResource(
684 readWrapper.get(),
685 XPS_IMAGE_TYPE_PNG,
686 imagePartUri.get(),
687 &imageResource),
688 "Could not create image resource.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000689
bungeman@google.comb29c8832011-10-10 13:19:10 +0000690 XPS_RECT bitmapRect = {
691 0.0, 0.0,
692 static_cast<FLOAT>(bitmap.width()), static_cast<FLOAT>(bitmap.height())
693 };
694 SkTScopedComPtr<IXpsOMImageBrush> xpsImageBrush;
695 HRM(this->fXpsFactory->CreateImageBrush(imageResource.get(),
696 &bitmapRect, &bitmapRect,
697 &xpsImageBrush),
698 "Could not create image brush.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000699
bungeman@google.comb29c8832011-10-10 13:19:10 +0000700 if (SkShader::kClamp_TileMode != xy[0] &&
701 SkShader::kClamp_TileMode != xy[1]) {
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000702
bungeman@google.comb29c8832011-10-10 13:19:10 +0000703 HRM(xpsImageBrush->SetTileMode(SkToXpsTileMode[xy[0]][xy[1]]),
704 "Could not set image tile mode");
705 HRM(xpsImageBrush->SetOpacity(alpha / 255.0f),
706 "Could not set image opacity.");
707 HRM(xpsImageBrush->QueryInterface(xpsBrush), "QI failed.");
708 } else {
709 //TODO(bungeman): compute how big this really needs to be.
710 const SkScalar BIG = SkIntToScalar(1000); //SK_ScalarMax;
711 const FLOAT BIG_F = SkScalarToFLOAT(BIG);
712 const SkScalar bWidth = SkIntToScalar(bitmap.width());
713 const SkScalar bHeight = SkIntToScalar(bitmap.height());
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000714
bungeman@google.comb29c8832011-10-10 13:19:10 +0000715 //create brush canvas
716 SkTScopedComPtr<IXpsOMCanvas> brushCanvas;
717 HRM(this->fXpsFactory->CreateCanvas(&brushCanvas),
718 "Could not create image brush canvas.");
719 SkTScopedComPtr<IXpsOMVisualCollection> brushVisuals;
720 HRM(brushCanvas->GetVisuals(&brushVisuals),
721 "Could not get image brush canvas visuals collection.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000722
bungeman@google.comb29c8832011-10-10 13:19:10 +0000723 //create central figure
724 const SkRect bitmapPoints = SkRect::MakeLTRB(0, 0, bWidth, bHeight);
725 SkTScopedComPtr<IXpsOMGeometryFigure> centralFigure;
726 HR(this->createXpsRect(bitmapPoints, FALSE, TRUE, &centralFigure));
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000727
bungeman@google.comb29c8832011-10-10 13:19:10 +0000728 SkTScopedComPtr<IXpsOMPath> centralPath;
729 HR(this->createPath(centralFigure.get(),
730 brushVisuals.get(),
731 &centralPath));
732 HRM(xpsImageBrush->SetTileMode(XPS_TILE_MODE_FLIPXY),
733 "Could not set tile mode for image brush central path.");
734 HRM(centralPath->SetFillBrushLocal(xpsImageBrush.get()),
735 "Could not set fill brush for image brush central path.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000736
bungeman@google.comb29c8832011-10-10 13:19:10 +0000737 //add left/right
738 if (SkShader::kClamp_TileMode == xy[0]) {
739 SkRect leftArea = SkRect::MakeLTRB(-BIG, 0, 0, bHeight);
740 XPS_RECT leftImageViewBox = {
741 0.0, 0.0,
742 1.0, static_cast<FLOAT>(bitmap.height()),
743 };
744 HR(this->sideOfClamp(leftArea, leftImageViewBox,
745 imageResource.get(),
746 brushVisuals.get()));
747
748 SkRect rightArea = SkRect::MakeLTRB(bWidth, 0, BIG, bHeight);
749 XPS_RECT rightImageViewBox = {
750 bitmap.width() - 1.0f, 0.0f,
751 1.0f, static_cast<FLOAT>(bitmap.height()),
752 };
753 HR(this->sideOfClamp(rightArea, rightImageViewBox,
754 imageResource.get(),
755 brushVisuals.get()));
756 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000757
bungeman@google.comb29c8832011-10-10 13:19:10 +0000758 //add top/bottom
759 if (SkShader::kClamp_TileMode == xy[1]) {
760 SkRect topArea = SkRect::MakeLTRB(0, -BIG, bWidth, 0);
761 XPS_RECT topImageViewBox = {
762 0.0, 0.0,
763 static_cast<FLOAT>(bitmap.width()), 1.0,
764 };
765 HR(this->sideOfClamp(topArea, topImageViewBox,
766 imageResource.get(),
767 brushVisuals.get()));
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000768
bungeman@google.comb29c8832011-10-10 13:19:10 +0000769 SkRect bottomArea = SkRect::MakeLTRB(0, bHeight, bWidth, BIG);
770 XPS_RECT bottomImageViewBox = {
771 0.0f, bitmap.height() - 1.0f,
772 static_cast<FLOAT>(bitmap.width()), 1.0f,
773 };
774 HR(this->sideOfClamp(bottomArea, bottomImageViewBox,
775 imageResource.get(),
776 brushVisuals.get()));
777 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000778
bungeman@google.comb29c8832011-10-10 13:19:10 +0000779 //add tl, tr, bl, br
780 if (SkShader::kClamp_TileMode == xy[0] &&
781 SkShader::kClamp_TileMode == xy[1]) {
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000782
bungeman@google.comb29c8832011-10-10 13:19:10 +0000783 SkAutoLockPixels alp(bitmap);
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000784
bungeman@google.comb29c8832011-10-10 13:19:10 +0000785 const SkColor tlColor = bitmap.getColor(0,0);
786 const SkRect tlArea = SkRect::MakeLTRB(-BIG, -BIG, 0, 0);
787 HR(this->cornerOfClamp(tlArea, tlColor, brushVisuals.get()));
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000788
bungeman@google.comb29c8832011-10-10 13:19:10 +0000789 const SkColor trColor = bitmap.getColor(bitmap.width()-1,0);
790 const SkRect trArea = SkRect::MakeLTRB(bWidth, -BIG, BIG, 0);
791 HR(this->cornerOfClamp(trArea, trColor, brushVisuals.get()));
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000792
bungeman@google.comb29c8832011-10-10 13:19:10 +0000793 const SkColor brColor = bitmap.getColor(bitmap.width()-1,
794 bitmap.height()-1);
795 const SkRect brArea = SkRect::MakeLTRB(bWidth, bHeight, BIG, BIG);
796 HR(this->cornerOfClamp(brArea, brColor, brushVisuals.get()));
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000797
bungeman@google.comb29c8832011-10-10 13:19:10 +0000798 const SkColor blColor = bitmap.getColor(0,bitmap.height()-1);
799 const SkRect blArea = SkRect::MakeLTRB(-BIG, bHeight, 0, BIG);
800 HR(this->cornerOfClamp(blArea, blColor, brushVisuals.get()));
801 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000802
bungeman@google.comb29c8832011-10-10 13:19:10 +0000803 //create visual brush from canvas
804 XPS_RECT bound = {};
805 if (SkShader::kClamp_TileMode == xy[0] &&
806 SkShader::kClamp_TileMode == xy[1]) {
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000807
bungeman@google.comb29c8832011-10-10 13:19:10 +0000808 bound.x = BIG_F / -2;
809 bound.y = BIG_F / -2;
810 bound.width = BIG_F;
811 bound.height = BIG_F;
812 } else if (SkShader::kClamp_TileMode == xy[0]) {
813 bound.x = BIG_F / -2;
814 bound.y = 0.0f;
815 bound.width = BIG_F;
816 bound.height = static_cast<FLOAT>(bitmap.height());
817 } else if (SkShader::kClamp_TileMode == xy[1]) {
818 bound.x = 0;
819 bound.y = BIG_F / -2;
820 bound.width = static_cast<FLOAT>(bitmap.width());
821 bound.height = BIG_F;
822 }
823 SkTScopedComPtr<IXpsOMVisualBrush> clampBrush;
824 HRM(this->fXpsFactory->CreateVisualBrush(&bound, &bound, &clampBrush),
825 "Could not create visual brush for image brush.");
826 HRM(clampBrush->SetVisualLocal(brushCanvas.get()),
827 "Could not set canvas on visual brush for image brush.");
828 HRM(clampBrush->SetTileMode(SkToXpsTileMode[xy[0]][xy[1]]),
829 "Could not set tile mode on visual brush for image brush.");
830 HRM(clampBrush->SetOpacity(alpha / 255.0f),
831 "Could not set opacity on visual brush for image brush.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000832
bungeman@google.comb29c8832011-10-10 13:19:10 +0000833 HRM(clampBrush->QueryInterface(xpsBrush), "QI failed.");
834 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000835
bungeman@google.comb29c8832011-10-10 13:19:10 +0000836 SkTScopedComPtr<IXpsOMMatrixTransform> xpsMatrixToUse;
837 HR(this->createXpsTransform(localMatrix, &xpsMatrixToUse));
bsalomon49f085d2014-09-05 13:34:00 -0700838 if (xpsMatrixToUse.get()) {
bungeman@google.comb29c8832011-10-10 13:19:10 +0000839 HRM((*xpsBrush)->SetTransformLocal(xpsMatrixToUse.get()),
840 "Could not set transform for image brush.");
841 } else {
842 //TODO(bungeman): perspective bitmaps in general.
843 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000844
bungeman@google.comb29c8832011-10-10 13:19:10 +0000845 return S_OK;
846}
847
848HRESULT SkXPSDevice::createXpsGradientStop(const SkColor skColor,
849 const SkScalar offset,
850 IXpsOMGradientStop** xpsGradStop) {
851 XPS_COLOR gradStopXpsColor = xps_color(skColor);
852 HRM(this->fXpsFactory->CreateGradientStop(&gradStopXpsColor,
halcanary96fcdcc2015-08-27 07:41:13 -0700853 nullptr,
bungeman@google.comb29c8832011-10-10 13:19:10 +0000854 SkScalarToFLOAT(offset),
855 xpsGradStop),
856 "Could not create gradient stop.");
857 return S_OK;
858}
859
860HRESULT SkXPSDevice::createXpsLinearGradient(SkShader::GradientInfo info,
861 const SkAlpha alpha,
862 const SkMatrix& localMatrix,
863 IXpsOMMatrixTransform* xpsMatrix,
864 IXpsOMBrush** xpsBrush) {
865 XPS_POINT startPoint;
866 XPS_POINT endPoint;
bsalomon49f085d2014-09-05 13:34:00 -0700867 if (xpsMatrix) {
bungeman@google.comb29c8832011-10-10 13:19:10 +0000868 startPoint = xps_point(info.fPoint[0]);
869 endPoint = xps_point(info.fPoint[1]);
870 } else {
871 transform_offsets(info.fColorOffsets, info.fColorCount,
872 info.fPoint[0], info.fPoint[1],
873 localMatrix);
874 startPoint = xps_point(info.fPoint[0], localMatrix);
875 endPoint = xps_point(info.fPoint[1], localMatrix);
876 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000877
bungeman@google.comb29c8832011-10-10 13:19:10 +0000878 SkTScopedComPtr<IXpsOMGradientStop> gradStop0;
879 HR(createXpsGradientStop(info.fColors[0],
880 info.fColorOffsets[0],
881 &gradStop0));
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000882
bungeman@google.comb29c8832011-10-10 13:19:10 +0000883 SkTScopedComPtr<IXpsOMGradientStop> gradStop1;
884 HR(createXpsGradientStop(info.fColors[1],
885 info.fColorOffsets[1],
886 &gradStop1));
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000887
bungeman@google.comb29c8832011-10-10 13:19:10 +0000888 SkTScopedComPtr<IXpsOMLinearGradientBrush> gradientBrush;
889 HRM(this->fXpsFactory->CreateLinearGradientBrush(gradStop0.get(),
890 gradStop1.get(),
891 &startPoint,
892 &endPoint,
893 &gradientBrush),
894 "Could not create linear gradient brush.");
bsalomon49f085d2014-09-05 13:34:00 -0700895 if (xpsMatrix) {
bungeman@google.comb29c8832011-10-10 13:19:10 +0000896 HRM(gradientBrush->SetTransformLocal(xpsMatrix),
897 "Could not set transform on linear gradient brush.");
898 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000899
bungeman@google.comb29c8832011-10-10 13:19:10 +0000900 SkTScopedComPtr<IXpsOMGradientStopCollection> gradStopCollection;
901 HRM(gradientBrush->GetGradientStops(&gradStopCollection),
902 "Could not get linear gradient stop collection.");
903 for (int i = 2; i < info.fColorCount; ++i) {
904 SkTScopedComPtr<IXpsOMGradientStop> gradStop;
905 HR(createXpsGradientStop(info.fColors[i],
906 info.fColorOffsets[i],
907 &gradStop));
908 HRM(gradStopCollection->Append(gradStop.get()),
909 "Could not add linear gradient stop.");
910 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000911
bungeman@google.comb29c8832011-10-10 13:19:10 +0000912 HRM(gradientBrush->SetSpreadMethod(xps_spread_method(info.fTileMode)),
913 "Could not set spread method of linear gradient.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000914
bungeman@google.comb29c8832011-10-10 13:19:10 +0000915 HRM(gradientBrush->SetOpacity(alpha / 255.0f),
916 "Could not set opacity of linear gradient brush.");
917 HRM(gradientBrush->QueryInterface<IXpsOMBrush>(xpsBrush), "QI failed");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000918
bungeman@google.comb29c8832011-10-10 13:19:10 +0000919 return S_OK;
920}
921
922HRESULT SkXPSDevice::createXpsRadialGradient(SkShader::GradientInfo info,
923 const SkAlpha alpha,
924 const SkMatrix& localMatrix,
925 IXpsOMMatrixTransform* xpsMatrix,
926 IXpsOMBrush** xpsBrush) {
927 SkTScopedComPtr<IXpsOMGradientStop> gradStop0;
928 HR(createXpsGradientStop(info.fColors[0],
929 info.fColorOffsets[0],
930 &gradStop0));
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000931
bungeman@google.comb29c8832011-10-10 13:19:10 +0000932 SkTScopedComPtr<IXpsOMGradientStop> gradStop1;
933 HR(createXpsGradientStop(info.fColors[1],
934 info.fColorOffsets[1],
935 &gradStop1));
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000936
bungeman@google.comb29c8832011-10-10 13:19:10 +0000937 //TODO: figure out how to fake better if not affine
938 XPS_POINT centerPoint;
939 XPS_POINT gradientOrigin;
940 XPS_SIZE radiiSizes;
bsalomon49f085d2014-09-05 13:34:00 -0700941 if (xpsMatrix) {
bungeman@google.comb29c8832011-10-10 13:19:10 +0000942 centerPoint = xps_point(info.fPoint[0]);
943 gradientOrigin = xps_point(info.fPoint[0]);
944 radiiSizes.width = SkScalarToFLOAT(info.fRadius[0]);
945 radiiSizes.height = SkScalarToFLOAT(info.fRadius[0]);
946 } else {
947 centerPoint = xps_point(info.fPoint[0], localMatrix);
948 gradientOrigin = xps_point(info.fPoint[0], localMatrix);
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000949
bungeman@google.comb29c8832011-10-10 13:19:10 +0000950 SkScalar radius = info.fRadius[0];
951 SkVector vec[2];
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000952
bungeman@google.comb29c8832011-10-10 13:19:10 +0000953 vec[0].set(radius, 0);
954 vec[1].set(0, radius);
955 localMatrix.mapVectors(vec, 2);
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000956
bungeman@google.comb29c8832011-10-10 13:19:10 +0000957 SkScalar d0 = vec[0].length();
958 SkScalar d1 = vec[1].length();
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000959
bungeman@google.comb29c8832011-10-10 13:19:10 +0000960 radiiSizes.width = SkScalarToFLOAT(d0);
961 radiiSizes.height = SkScalarToFLOAT(d1);
962 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000963
bungeman@google.comb29c8832011-10-10 13:19:10 +0000964 SkTScopedComPtr<IXpsOMRadialGradientBrush> gradientBrush;
965 HRM(this->fXpsFactory->CreateRadialGradientBrush(gradStop0.get(),
966 gradStop1.get(),
967 &centerPoint,
968 &gradientOrigin,
969 &radiiSizes,
970 &gradientBrush),
971 "Could not create radial gradient brush.");
bsalomon49f085d2014-09-05 13:34:00 -0700972 if (xpsMatrix) {
bungeman@google.comb29c8832011-10-10 13:19:10 +0000973 HRM(gradientBrush->SetTransformLocal(xpsMatrix),
974 "Could not set transform on radial gradient brush.");
975 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000976
bungeman@google.comb29c8832011-10-10 13:19:10 +0000977 SkTScopedComPtr<IXpsOMGradientStopCollection> gradStopCollection;
978 HRM(gradientBrush->GetGradientStops(&gradStopCollection),
979 "Could not get radial gradient stop collection.");
980 for (int i = 2; i < info.fColorCount; ++i) {
981 SkTScopedComPtr<IXpsOMGradientStop> gradStop;
982 HR(createXpsGradientStop(info.fColors[i],
983 info.fColorOffsets[i],
984 &gradStop));
985 HRM(gradStopCollection->Append(gradStop.get()),
986 "Could not add radial gradient stop.");
987 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000988
bungeman@google.comb29c8832011-10-10 13:19:10 +0000989 HRM(gradientBrush->SetSpreadMethod(xps_spread_method(info.fTileMode)),
990 "Could not set spread method of radial gradient.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000991
bungeman@google.comb29c8832011-10-10 13:19:10 +0000992 HRM(gradientBrush->SetOpacity(alpha / 255.0f),
993 "Could not set opacity of radial gradient brush.");
994 HRM(gradientBrush->QueryInterface<IXpsOMBrush>(xpsBrush), "QI failed.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000995
bungeman@google.comb29c8832011-10-10 13:19:10 +0000996 return S_OK;
997}
998
999HRESULT SkXPSDevice::createXpsBrush(const SkPaint& skPaint,
1000 IXpsOMBrush** brush,
1001 const SkMatrix* parentTransform) {
1002 const SkShader *shader = skPaint.getShader();
halcanary96fcdcc2015-08-27 07:41:13 -07001003 if (nullptr == shader) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00001004 HR(this->createXpsSolidColorBrush(skPaint.getColor(), 0xFF, brush));
1005 return S_OK;
1006 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001007
bungeman@google.comb29c8832011-10-10 13:19:10 +00001008 //Gradient shaders.
1009 SkShader::GradientInfo info;
1010 info.fColorCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -07001011 info.fColors = nullptr;
1012 info.fColorOffsets = nullptr;
bungeman@google.comb29c8832011-10-10 13:19:10 +00001013 SkShader::GradientType gradientType = shader->asAGradient(&info);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001014
bungeman@google.comb29c8832011-10-10 13:19:10 +00001015 if (SkShader::kNone_GradientType == gradientType) {
1016 //Nothing to see, move along.
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001017
bungeman@google.comb29c8832011-10-10 13:19:10 +00001018 } else if (SkShader::kColor_GradientType == gradientType) {
1019 SkASSERT(1 == info.fColorCount);
1020 SkColor color;
1021 info.fColors = &color;
bsalomon@google.comb58a6392013-03-21 20:29:05 +00001022 shader->asAGradient(&info);
bungeman@google.comb29c8832011-10-10 13:19:10 +00001023 SkAlpha alpha = skPaint.getAlpha();
1024 HR(this->createXpsSolidColorBrush(color, alpha, brush));
1025 return S_OK;
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001026
bungeman@google.comb29c8832011-10-10 13:19:10 +00001027 } else {
1028 if (info.fColorCount == 0) {
1029 const SkColor color = skPaint.getColor();
1030 HR(this->createXpsSolidColorBrush(color, 0xFF, brush));
1031 return S_OK;
1032 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001033
bungeman@google.comb29c8832011-10-10 13:19:10 +00001034 SkAutoTArray<SkColor> colors(info.fColorCount);
1035 SkAutoTArray<SkScalar> colorOffsets(info.fColorCount);
1036 info.fColors = colors.get();
1037 info.fColorOffsets = colorOffsets.get();
1038 shader->asAGradient(&info);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001039
bungeman@google.comb29c8832011-10-10 13:19:10 +00001040 if (1 == info.fColorCount) {
1041 SkColor color = info.fColors[0];
1042 SkAlpha alpha = skPaint.getAlpha();
1043 HR(this->createXpsSolidColorBrush(color, alpha, brush));
1044 return S_OK;
1045 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001046
bsalomon@google.comf94b3a42012-10-31 18:09:01 +00001047 SkMatrix localMatrix = shader->getLocalMatrix();
bsalomon49f085d2014-09-05 13:34:00 -07001048 if (parentTransform) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00001049 localMatrix.preConcat(*parentTransform);
1050 }
1051 SkTScopedComPtr<IXpsOMMatrixTransform> xpsMatrixToUse;
1052 HR(this->createXpsTransform(localMatrix, &xpsMatrixToUse));
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001053
bungeman@google.comb29c8832011-10-10 13:19:10 +00001054 if (SkShader::kLinear_GradientType == gradientType) {
1055 HR(this->createXpsLinearGradient(info,
1056 skPaint.getAlpha(),
1057 localMatrix,
1058 xpsMatrixToUse.get(),
1059 brush));
1060 return S_OK;
1061 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001062
bungeman@google.comb29c8832011-10-10 13:19:10 +00001063 if (SkShader::kRadial_GradientType == gradientType) {
1064 HR(this->createXpsRadialGradient(info,
1065 skPaint.getAlpha(),
1066 localMatrix,
1067 xpsMatrixToUse.get(),
1068 brush));
1069 return S_OK;
1070 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001071
reed71a6cbf2015-05-04 08:32:51 -07001072 if (SkShader::kConical_GradientType == gradientType) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00001073 //simple if affine and one is 0, otherwise will have to fake
1074 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001075
bungeman@google.comb29c8832011-10-10 13:19:10 +00001076 if (SkShader::kSweep_GradientType == gradientType) {
1077 //have to fake
1078 }
1079 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001080
bungeman@google.comb29c8832011-10-10 13:19:10 +00001081 SkBitmap outTexture;
1082 SkMatrix outMatrix;
1083 SkShader::TileMode xy[2];
Mike Reed627778d2016-09-28 17:13:38 -04001084 SkImage* image = shader->isAImage(&outMatrix, xy);
1085 if (image && image->asLegacyBitmap(&outTexture, SkImage::kRO_LegacyBitmapMode)) {
reedf5822822015-08-19 11:46:38 -07001086 //TODO: outMatrix??
1087 SkMatrix localMatrix = shader->getLocalMatrix();
1088 if (parentTransform) {
1089 localMatrix.preConcat(*parentTransform);
bungeman@google.comb29c8832011-10-10 13:19:10 +00001090 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001091
reedf5822822015-08-19 11:46:38 -07001092 SkTScopedComPtr<IXpsOMTileBrush> tileBrush;
1093 HR(this->createXpsImageBrush(outTexture,
1094 localMatrix,
1095 xy,
1096 skPaint.getAlpha(),
1097 &tileBrush));
1098
1099 HRM(tileBrush->QueryInterface<IXpsOMBrush>(brush), "QI failed.");
1100 } else {
1101 HR(this->createXpsSolidColorBrush(skPaint.getColor(), 0xFF, brush));
1102 }
bungeman@google.comb29c8832011-10-10 13:19:10 +00001103 return S_OK;
1104}
1105
1106static bool rect_must_be_pathed(const SkPaint& paint, const SkMatrix& matrix) {
1107 const bool zeroWidth = (0 == paint.getStrokeWidth());
1108 const bool stroke = (SkPaint::kFill_Style != paint.getStyle());
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001109
bungeman@google.comb29c8832011-10-10 13:19:10 +00001110 return paint.getPathEffect() ||
1111 paint.getMaskFilter() ||
1112 paint.getRasterizer() ||
1113 (stroke && (
1114 (matrix.hasPerspective() && !zeroWidth) ||
1115 SkPaint::kMiter_Join != paint.getStrokeJoin() ||
1116 (SkPaint::kMiter_Join == paint.getStrokeJoin() &&
1117 paint.getStrokeMiter() < SK_ScalarSqrt2)
1118 ))
1119 ;
1120}
1121
1122HRESULT SkXPSDevice::createXpsRect(const SkRect& rect, BOOL stroke, BOOL fill,
1123 IXpsOMGeometryFigure** xpsRect) {
1124 const SkPoint points[4] = {
1125 { rect.fLeft, rect.fTop },
1126 { rect.fRight, rect.fTop },
1127 { rect.fRight, rect.fBottom },
1128 { rect.fLeft, rect.fBottom },
1129 };
1130 return this->createXpsQuad(points, stroke, fill, xpsRect);
1131}
1132HRESULT SkXPSDevice::createXpsQuad(const SkPoint (&points)[4],
1133 BOOL stroke, BOOL fill,
1134 IXpsOMGeometryFigure** xpsQuad) {
1135 // Define the start point.
1136 XPS_POINT startPoint = xps_point(points[0]);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001137
bungeman@google.comb29c8832011-10-10 13:19:10 +00001138 // Create the figure.
1139 HRM(this->fXpsFactory->CreateGeometryFigure(&startPoint, xpsQuad),
1140 "Could not create quad geometry figure.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001141
bungeman@google.comb29c8832011-10-10 13:19:10 +00001142 // Define the type of each segment.
1143 XPS_SEGMENT_TYPE segmentTypes[3] = {
1144 XPS_SEGMENT_TYPE_LINE,
1145 XPS_SEGMENT_TYPE_LINE,
1146 XPS_SEGMENT_TYPE_LINE,
1147 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001148
bungeman@google.comb29c8832011-10-10 13:19:10 +00001149 // Define the x and y coordinates of each corner of the figure.
1150 FLOAT segmentData[6] = {
1151 SkScalarToFLOAT(points[1].fX), SkScalarToFLOAT(points[1].fY),
1152 SkScalarToFLOAT(points[2].fX), SkScalarToFLOAT(points[2].fY),
1153 SkScalarToFLOAT(points[3].fX), SkScalarToFLOAT(points[3].fY),
1154 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001155
bungeman@google.comb29c8832011-10-10 13:19:10 +00001156 // Describe if the segments are stroked.
1157 BOOL segmentStrokes[3] = {
1158 stroke, stroke, stroke,
1159 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001160
bungeman@google.comb29c8832011-10-10 13:19:10 +00001161 // Add the segment data to the figure.
1162 HRM((*xpsQuad)->SetSegments(
1163 3, 6,
1164 segmentTypes , segmentData, segmentStrokes),
1165 "Could not add segment data to quad.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001166
bungeman@google.comb29c8832011-10-10 13:19:10 +00001167 // Set the closed and filled properties of the figure.
1168 HRM((*xpsQuad)->SetIsClosed(stroke), "Could not set quad close.");
1169 HRM((*xpsQuad)->SetIsFilled(fill), "Could not set quad fill.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001170
bungeman@google.comb29c8832011-10-10 13:19:10 +00001171 return S_OK;
1172}
1173
bungeman@google.comb29c8832011-10-10 13:19:10 +00001174void SkXPSDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
1175 size_t count, const SkPoint points[],
1176 const SkPaint& paint) {
1177 //This will call back into the device to do the drawing.
1178 d.drawPoints(mode, count, points, paint, true);
1179}
1180
1181void SkXPSDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode,
1182 int vertexCount, const SkPoint verts[],
1183 const SkPoint texs[], const SkColor colors[],
1184 SkXfermode* xmode, const uint16_t indices[],
1185 int indexCount, const SkPaint& paint) {
1186 //TODO: override this for XPS
1187 SkDEBUGF(("XPS drawVertices not yet implemented."));
1188}
1189
bsalomon@google.com5dc26b92012-10-11 19:32:32 +00001190void SkXPSDevice::drawPaint(const SkDraw& d, const SkPaint& origPaint) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00001191 const SkRect r = SkRect::MakeSize(this->fCurrentCanvasSize);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001192
bungeman@google.comb29c8832011-10-10 13:19:10 +00001193 //If trying to paint with a stroke, ignore that and fill.
bsalomon@google.com5dc26b92012-10-11 19:32:32 +00001194 SkPaint* fillPaint = const_cast<SkPaint*>(&origPaint);
1195 SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1196 if (paint->getStyle() != SkPaint::kFill_Style) {
1197 paint.writable()->setStyle(SkPaint::kFill_Style);
bungeman@google.comb29c8832011-10-10 13:19:10 +00001198 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001199
bungeman@google.comb29c8832011-10-10 13:19:10 +00001200 this->internalDrawRect(d, r, false, *fillPaint);
1201}
1202
1203void SkXPSDevice::drawRect(const SkDraw& d,
1204 const SkRect& r,
1205 const SkPaint& paint) {
1206 this->internalDrawRect(d, r, true, paint);
1207}
1208
scroggo@google.comcac8d012013-11-12 17:10:02 +00001209void SkXPSDevice::drawRRect(const SkDraw& d,
1210 const SkRRect& rr,
1211 const SkPaint& paint) {
1212 SkPath path;
1213 path.addRRect(rr);
halcanary96fcdcc2015-08-27 07:41:13 -07001214 this->drawPath(d, path, paint, nullptr, true);
scroggo@google.comcac8d012013-11-12 17:10:02 +00001215}
1216
bungeman@google.comb29c8832011-10-10 13:19:10 +00001217void SkXPSDevice::internalDrawRect(const SkDraw& d,
1218 const SkRect& r,
1219 bool transformRect,
1220 const SkPaint& paint) {
1221 //Exit early if there is nothing to draw.
reed1e7f5e72016-04-27 07:49:17 -07001222 if (d.fRC->isEmpty() ||
reed374772b2016-10-05 17:33:02 -07001223 (paint.getAlpha() == 0 && paint.isSrcOver())) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00001224 return;
1225 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001226
bungeman@google.comb29c8832011-10-10 13:19:10 +00001227 //Path the rect if we can't optimize it.
1228 if (rect_must_be_pathed(paint, *d.fMatrix)) {
1229 SkPath tmp;
1230 tmp.addRect(r);
1231 tmp.setFillType(SkPath::kWinding_FillType);
halcanary96fcdcc2015-08-27 07:41:13 -07001232 this->drawPath(d, tmp, paint, nullptr, true);
bungeman@google.comb29c8832011-10-10 13:19:10 +00001233 return;
1234 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001235
bungeman@google.comb29c8832011-10-10 13:19:10 +00001236 //Create the shaded path.
1237 SkTScopedComPtr<IXpsOMPath> shadedPath;
1238 HRVM(this->fXpsFactory->CreatePath(&shadedPath),
1239 "Could not create shaded path for rect.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001240
bungeman@google.comb29c8832011-10-10 13:19:10 +00001241 //Create the shaded geometry.
1242 SkTScopedComPtr<IXpsOMGeometry> shadedGeometry;
1243 HRVM(this->fXpsFactory->CreateGeometry(&shadedGeometry),
1244 "Could not create shaded geometry for rect.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001245
bungeman@google.comb29c8832011-10-10 13:19:10 +00001246 //Add the geometry to the shaded path.
1247 HRVM(shadedPath->SetGeometryLocal(shadedGeometry.get()),
1248 "Could not set shaded geometry for rect.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001249
bungeman@google.comb29c8832011-10-10 13:19:10 +00001250 //Set the brushes.
1251 BOOL fill = FALSE;
1252 BOOL stroke = FALSE;
1253 HRV(this->shadePath(shadedPath.get(), paint, *d.fMatrix, &fill, &stroke));
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001254
bungeman@google.comb29c8832011-10-10 13:19:10 +00001255 bool xpsTransformsPath = true;
1256 //Transform the geometry.
1257 if (transformRect && xpsTransformsPath) {
1258 SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform;
1259 HRV(this->createXpsTransform(*d.fMatrix, &xpsTransform));
1260 if (xpsTransform.get()) {
1261 HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()),
1262 "Could not set transform for rect.");
1263 } else {
1264 xpsTransformsPath = false;
1265 }
1266 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001267
bungeman@google.comb29c8832011-10-10 13:19:10 +00001268 //Create the figure.
1269 SkTScopedComPtr<IXpsOMGeometryFigure> rectFigure;
1270 {
1271 SkPoint points[4] = {
1272 { r.fLeft, r.fTop },
1273 { r.fLeft, r.fBottom },
1274 { r.fRight, r.fBottom },
1275 { r.fRight, r.fTop },
1276 };
1277 if (!xpsTransformsPath && transformRect) {
1278 d.fMatrix->mapPoints(points, SK_ARRAY_COUNT(points));
1279 }
1280 HRV(this->createXpsQuad(points, stroke, fill, &rectFigure));
1281 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001282
bungeman@google.comb29c8832011-10-10 13:19:10 +00001283 //Get the figures of the shaded geometry.
1284 SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures;
1285 HRVM(shadedGeometry->GetFigures(&shadedFigures),
1286 "Could not get shaded figures for rect.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001287
bungeman@google.comb29c8832011-10-10 13:19:10 +00001288 //Add the figure to the shaded geometry figures.
1289 HRVM(shadedFigures->Append(rectFigure.get()),
1290 "Could not add shaded figure for rect.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001291
bungeman@google.comb29c8832011-10-10 13:19:10 +00001292 HRV(this->clip(shadedPath.get(), d));
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001293
bungeman@google.comb29c8832011-10-10 13:19:10 +00001294 //Add the shaded path to the current visuals.
1295 SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals;
1296 HRVM(this->fCurrentXpsCanvas->GetVisuals(&currentVisuals),
1297 "Could not get current visuals for rect.");
1298 HRVM(currentVisuals->Append(shadedPath.get()),
1299 "Could not add rect to current visuals.");
1300}
1301
1302static HRESULT close_figure(const SkTDArray<XPS_SEGMENT_TYPE>& segmentTypes,
1303 const SkTDArray<BOOL>& segmentStrokes,
1304 const SkTDArray<FLOAT>& segmentData,
1305 BOOL stroke, BOOL fill,
1306 IXpsOMGeometryFigure* figure,
1307 IXpsOMGeometryFigureCollection* figures) {
1308 // Add the segment data to the figure.
1309 HRM(figure->SetSegments(segmentTypes.count(), segmentData.count(),
1310 segmentTypes.begin() , segmentData.begin(),
1311 segmentStrokes.begin()),
1312 "Could not set path segments.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001313
bungeman@google.comb29c8832011-10-10 13:19:10 +00001314 // Set the closed and filled properties of the figure.
1315 HRM(figure->SetIsClosed(stroke), "Could not set path closed.");
1316 HRM(figure->SetIsFilled(fill), "Could not set path fill.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001317
bungeman@google.comb29c8832011-10-10 13:19:10 +00001318 // Add the figure created above to this geometry.
1319 HRM(figures->Append(figure), "Could not add path to geometry.");
1320 return S_OK;
1321}
1322
1323HRESULT SkXPSDevice::addXpsPathGeometry(
1324 IXpsOMGeometryFigureCollection* xpsFigures,
1325 BOOL stroke, BOOL fill, const SkPath& path) {
1326 SkTDArray<XPS_SEGMENT_TYPE> segmentTypes;
1327 SkTDArray<BOOL> segmentStrokes;
1328 SkTDArray<FLOAT> segmentData;
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001329
bungeman@google.comb29c8832011-10-10 13:19:10 +00001330 SkTScopedComPtr<IXpsOMGeometryFigure> xpsFigure;
1331 SkPath::Iter iter(path, true);
1332 SkPoint points[4];
1333 SkPath::Verb verb;
1334 while ((verb = iter.next(points)) != SkPath::kDone_Verb) {
1335 switch (verb) {
1336 case SkPath::kMove_Verb: {
bsalomon49f085d2014-09-05 13:34:00 -07001337 if (xpsFigure.get()) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00001338 HR(close_figure(segmentTypes, segmentStrokes, segmentData,
1339 stroke, fill,
1340 xpsFigure.get() , xpsFigures));
1341 xpsFigure.reset();
1342 segmentTypes.rewind();
1343 segmentStrokes.rewind();
1344 segmentData.rewind();
1345 }
1346 // Define the start point.
1347 XPS_POINT startPoint = xps_point(points[0]);
1348 // Create the figure.
1349 HRM(this->fXpsFactory->CreateGeometryFigure(&startPoint,
1350 &xpsFigure),
1351 "Could not create path geometry figure.");
1352 break;
1353 }
1354 case SkPath::kLine_Verb:
1355 if (iter.isCloseLine()) break; //ignore the line, auto-closed
1356 segmentTypes.push(XPS_SEGMENT_TYPE_LINE);
1357 segmentStrokes.push(stroke);
1358 segmentData.push(SkScalarToFLOAT(points[1].fX));
1359 segmentData.push(SkScalarToFLOAT(points[1].fY));
1360 break;
1361 case SkPath::kQuad_Verb:
1362 segmentTypes.push(XPS_SEGMENT_TYPE_QUADRATIC_BEZIER);
1363 segmentStrokes.push(stroke);
1364 segmentData.push(SkScalarToFLOAT(points[1].fX));
1365 segmentData.push(SkScalarToFLOAT(points[1].fY));
1366 segmentData.push(SkScalarToFLOAT(points[2].fX));
1367 segmentData.push(SkScalarToFLOAT(points[2].fY));
1368 break;
1369 case SkPath::kCubic_Verb:
1370 segmentTypes.push(XPS_SEGMENT_TYPE_BEZIER);
1371 segmentStrokes.push(stroke);
1372 segmentData.push(SkScalarToFLOAT(points[1].fX));
1373 segmentData.push(SkScalarToFLOAT(points[1].fY));
1374 segmentData.push(SkScalarToFLOAT(points[2].fX));
1375 segmentData.push(SkScalarToFLOAT(points[2].fY));
1376 segmentData.push(SkScalarToFLOAT(points[3].fX));
1377 segmentData.push(SkScalarToFLOAT(points[3].fY));
1378 break;
halcanary47ef4d52015-03-03 09:13:09 -08001379 case SkPath::kConic_Verb: {
1380 const SkScalar tol = SK_Scalar1 / 4;
1381 SkAutoConicToQuads converter;
1382 const SkPoint* quads =
1383 converter.computeQuads(points, iter.conicWeight(), tol);
1384 for (int i = 0; i < converter.countQuads(); ++i) {
1385 segmentTypes.push(XPS_SEGMENT_TYPE_QUADRATIC_BEZIER);
1386 segmentStrokes.push(stroke);
1387 segmentData.push(SkScalarToFLOAT(quads[2 * i + 1].fX));
1388 segmentData.push(SkScalarToFLOAT(quads[2 * i + 1].fY));
1389 segmentData.push(SkScalarToFLOAT(quads[2 * i + 2].fX));
1390 segmentData.push(SkScalarToFLOAT(quads[2 * i + 2].fY));
1391 }
1392 break;
1393 }
bungeman@google.comb29c8832011-10-10 13:19:10 +00001394 case SkPath::kClose_Verb:
1395 // we ignore these, and just get the whole segment from
1396 // the corresponding line/quad/cubic verbs
1397 break;
1398 default:
mtklein@google.com330313a2013-08-22 15:37:26 +00001399 SkDEBUGFAIL("unexpected verb");
bungeman@google.comb29c8832011-10-10 13:19:10 +00001400 break;
1401 }
1402 }
bsalomon49f085d2014-09-05 13:34:00 -07001403 if (xpsFigure.get()) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00001404 HR(close_figure(segmentTypes, segmentStrokes, segmentData,
1405 stroke, fill,
1406 xpsFigure.get(), xpsFigures));
1407 }
1408 return S_OK;
1409}
1410
bungeman@google.comb29c8832011-10-10 13:19:10 +00001411void SkXPSDevice::convertToPpm(const SkMaskFilter* filter,
1412 SkMatrix* matrix,
1413 SkVector* ppuScale,
1414 const SkIRect& clip, SkIRect* clipIRect) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00001415 //This action is in unit space, but the ppm is specified in physical space.
reed80ea19c2015-05-12 10:37:34 -07001416 ppuScale->set(fCurrentPixelsPerMeter.fX / fCurrentUnitsPerMeter.fX,
1417 fCurrentPixelsPerMeter.fY / fCurrentUnitsPerMeter.fY);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001418
bungeman@google.comb29c8832011-10-10 13:19:10 +00001419 matrix->postScale(ppuScale->fX, ppuScale->fY);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001420
bungeman@google.comb29c8832011-10-10 13:19:10 +00001421 const SkIRect& irect = clip;
1422 SkRect clipRect = SkRect::MakeLTRB(
1423 SkScalarMul(SkIntToScalar(irect.fLeft), ppuScale->fX),
1424 SkScalarMul(SkIntToScalar(irect.fTop), ppuScale->fY),
1425 SkScalarMul(SkIntToScalar(irect.fRight), ppuScale->fX),
1426 SkScalarMul(SkIntToScalar(irect.fBottom), ppuScale->fY));
1427 clipRect.roundOut(clipIRect);
1428}
1429
1430HRESULT SkXPSDevice::applyMask(const SkDraw& d,
1431 const SkMask& mask,
1432 const SkVector& ppuScale,
1433 IXpsOMPath* shadedPath) {
1434 //Get the geometry object.
1435 SkTScopedComPtr<IXpsOMGeometry> shadedGeometry;
1436 HRM(shadedPath->GetGeometry(&shadedGeometry),
1437 "Could not get mask shaded geometry.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001438
bungeman@google.comb29c8832011-10-10 13:19:10 +00001439 //Get the figures from the geometry.
1440 SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures;
1441 HRM(shadedGeometry->GetFigures(&shadedFigures),
1442 "Could not get mask shaded figures.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001443
bungeman@google.comb29c8832011-10-10 13:19:10 +00001444 SkMatrix m;
1445 m.reset();
1446 m.setTranslate(SkIntToScalar(mask.fBounds.fLeft),
1447 SkIntToScalar(mask.fBounds.fTop));
1448 m.postScale(SkScalarInvert(ppuScale.fX), SkScalarInvert(ppuScale.fY));
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001449
bungeman@google.comb29c8832011-10-10 13:19:10 +00001450 SkShader::TileMode xy[2];
1451 xy[0] = (SkShader::TileMode)3;
1452 xy[1] = (SkShader::TileMode)3;
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001453
bungeman@google.comb29c8832011-10-10 13:19:10 +00001454 SkBitmap bm;
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +00001455 bm.installMaskPixels(mask);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001456
bungeman@google.comb29c8832011-10-10 13:19:10 +00001457 SkTScopedComPtr<IXpsOMTileBrush> maskBrush;
1458 HR(this->createXpsImageBrush(bm, m, xy, 0xFF, &maskBrush));
1459 HRM(shadedPath->SetOpacityMaskBrushLocal(maskBrush.get()),
1460 "Could not set mask.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001461
bungeman@google.comb29c8832011-10-10 13:19:10 +00001462 const SkRect universeRect = SkRect::MakeLTRB(0, 0,
1463 this->fCurrentCanvasSize.fWidth, this->fCurrentCanvasSize.fHeight);
1464 SkTScopedComPtr<IXpsOMGeometryFigure> shadedFigure;
1465 HRM(this->createXpsRect(universeRect, FALSE, TRUE, &shadedFigure),
1466 "Could not create mask shaded figure.");
1467 HRM(shadedFigures->Append(shadedFigure.get()),
1468 "Could not add mask shaded figure.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001469
bungeman@google.comb29c8832011-10-10 13:19:10 +00001470 HR(this->clip(shadedPath, d));
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001471
bungeman@google.comb29c8832011-10-10 13:19:10 +00001472 //Add the path to the active visual collection.
1473 SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals;
1474 HRM(this->fCurrentXpsCanvas->GetVisuals(&currentVisuals),
1475 "Could not get mask current visuals.");
1476 HRM(currentVisuals->Append(shadedPath),
1477 "Could not add masked shaded path to current visuals.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001478
bungeman@google.comb29c8832011-10-10 13:19:10 +00001479 return S_OK;
1480}
1481
1482HRESULT SkXPSDevice::shadePath(IXpsOMPath* shadedPath,
1483 const SkPaint& shaderPaint,
1484 const SkMatrix& matrix,
1485 BOOL* fill, BOOL* stroke) {
1486 *fill = FALSE;
1487 *stroke = FALSE;
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001488
bungeman@google.comb29c8832011-10-10 13:19:10 +00001489 const SkPaint::Style style = shaderPaint.getStyle();
1490 const bool hasFill = SkPaint::kFill_Style == style
1491 || SkPaint::kStrokeAndFill_Style == style;
1492 const bool hasStroke = SkPaint::kStroke_Style == style
1493 || SkPaint::kStrokeAndFill_Style == style;
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001494
bungeman@google.comb29c8832011-10-10 13:19:10 +00001495 //TODO(bungeman): use dictionaries and lookups.
1496 if (hasFill) {
1497 *fill = TRUE;
1498 SkTScopedComPtr<IXpsOMBrush> fillBrush;
1499 HR(this->createXpsBrush(shaderPaint, &fillBrush, &matrix));
1500 HRM(shadedPath->SetFillBrushLocal(fillBrush.get()),
1501 "Could not set fill for shaded path.");
1502 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001503
bungeman@google.comb29c8832011-10-10 13:19:10 +00001504 if (hasStroke) {
1505 *stroke = TRUE;
1506 SkTScopedComPtr<IXpsOMBrush> strokeBrush;
1507 HR(this->createXpsBrush(shaderPaint, &strokeBrush, &matrix));
1508 HRM(shadedPath->SetStrokeBrushLocal(strokeBrush.get()),
1509 "Could not set stroke brush for shaded path.");
1510 HRM(shadedPath->SetStrokeThickness(
1511 SkScalarToFLOAT(shaderPaint.getStrokeWidth())),
1512 "Could not set shaded path stroke thickness.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001513
bungeman@google.comb29c8832011-10-10 13:19:10 +00001514 if (0 == shaderPaint.getStrokeWidth()) {
1515 //XPS hair width is a hack. (XPS Spec 11.6.12).
1516 SkTScopedComPtr<IXpsOMDashCollection> dashes;
1517 HRM(shadedPath->GetStrokeDashes(&dashes),
1518 "Could not set dashes for shaded path.");
1519 XPS_DASH dash;
1520 dash.length = 1.0;
1521 dash.gap = 0.0;
1522 HRM(dashes->Append(&dash), "Could not add dashes to shaded path.");
1523 HRM(shadedPath->SetStrokeDashOffset(-2.0),
1524 "Could not set dash offset for shaded path.");
1525 }
1526 }
1527 return S_OK;
1528}
1529
1530void SkXPSDevice::drawPath(const SkDraw& d,
1531 const SkPath& platonicPath,
bsalomon@google.com5dc26b92012-10-11 19:32:32 +00001532 const SkPaint& origPaint,
bungeman@google.comb29c8832011-10-10 13:19:10 +00001533 const SkMatrix* prePathMatrix,
1534 bool pathIsMutable) {
bsalomon@google.com5dc26b92012-10-11 19:32:32 +00001535 SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1536
bungeman@google.comb29c8832011-10-10 13:19:10 +00001537 // nothing to draw
reed1e7f5e72016-04-27 07:49:17 -07001538 if (d.fRC->isEmpty() ||
reed374772b2016-10-05 17:33:02 -07001539 (paint->getAlpha() == 0 && paint->isSrcOver())) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00001540 return;
1541 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001542
bungeman@google.comb29c8832011-10-10 13:19:10 +00001543 SkPath modifiedPath;
bsalomon@google.com5dc26b92012-10-11 19:32:32 +00001544 const bool paintHasPathEffect = paint->getPathEffect()
1545 || paint->getStyle() != SkPaint::kFill_Style;
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001546
bungeman@google.comb29c8832011-10-10 13:19:10 +00001547 //Apply pre-path matrix [Platonic-path -> Skeletal-path].
1548 SkMatrix matrix = *d.fMatrix;
1549 SkPath* skeletalPath = const_cast<SkPath*>(&platonicPath);
1550 if (prePathMatrix) {
bsalomon@google.com5dc26b92012-10-11 19:32:32 +00001551 if (paintHasPathEffect || paint->getRasterizer()) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00001552 if (!pathIsMutable) {
1553 skeletalPath = &modifiedPath;
1554 pathIsMutable = true;
1555 }
1556 platonicPath.transform(*prePathMatrix, skeletalPath);
1557 } else {
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001558 matrix.preConcat(*prePathMatrix);
bungeman@google.comb29c8832011-10-10 13:19:10 +00001559 }
1560 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001561
bungeman@google.comb29c8832011-10-10 13:19:10 +00001562 //Apply path effect [Skeletal-path -> Fillable-path].
1563 SkPath* fillablePath = skeletalPath;
1564 if (paintHasPathEffect) {
1565 if (!pathIsMutable) {
1566 fillablePath = &modifiedPath;
1567 pathIsMutable = true;
1568 }
bsalomon@google.com5dc26b92012-10-11 19:32:32 +00001569 bool fill = paint->getFillPath(*skeletalPath, fillablePath);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001570
bsalomon@google.com5dc26b92012-10-11 19:32:32 +00001571 SkPaint* writablePaint = paint.writable();
halcanary96fcdcc2015-08-27 07:41:13 -07001572 writablePaint->setPathEffect(nullptr);
bungeman@google.comb29c8832011-10-10 13:19:10 +00001573 if (fill) {
bsalomon@google.com5dc26b92012-10-11 19:32:32 +00001574 writablePaint->setStyle(SkPaint::kFill_Style);
bungeman@google.comb29c8832011-10-10 13:19:10 +00001575 } else {
bsalomon@google.com5dc26b92012-10-11 19:32:32 +00001576 writablePaint->setStyle(SkPaint::kStroke_Style);
1577 writablePaint->setStrokeWidth(0);
bungeman@google.comb29c8832011-10-10 13:19:10 +00001578 }
1579 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001580
bungeman@google.comb29c8832011-10-10 13:19:10 +00001581 //Create the shaded path. This will be the path which is painted.
1582 SkTScopedComPtr<IXpsOMPath> shadedPath;
1583 HRVM(this->fXpsFactory->CreatePath(&shadedPath),
1584 "Could not create shaded path for path.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001585
bungeman@google.comb29c8832011-10-10 13:19:10 +00001586 //Create the geometry for the shaded path.
1587 SkTScopedComPtr<IXpsOMGeometry> shadedGeometry;
1588 HRVM(this->fXpsFactory->CreateGeometry(&shadedGeometry),
1589 "Could not create shaded geometry for path.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001590
bungeman@google.comb29c8832011-10-10 13:19:10 +00001591 //Add the geometry to the shaded path.
1592 HRVM(shadedPath->SetGeometryLocal(shadedGeometry.get()),
1593 "Could not add the shaded geometry to shaded path.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001594
bsalomon@google.com5dc26b92012-10-11 19:32:32 +00001595 SkRasterizer* rasterizer = paint->getRasterizer();
1596 SkMaskFilter* filter = paint->getMaskFilter();
bungeman@google.comd998cbd2012-04-05 18:57:53 +00001597
1598 //Determine if we will draw or shade and mask.
1599 if (rasterizer || filter) {
bsalomon@google.com5dc26b92012-10-11 19:32:32 +00001600 if (paint->getStyle() != SkPaint::kFill_Style) {
1601 paint.writable()->setStyle(SkPaint::kFill_Style);
bungeman@google.comd998cbd2012-04-05 18:57:53 +00001602 }
1603 }
1604
bungeman@google.comb29c8832011-10-10 13:19:10 +00001605 //Set the brushes.
1606 BOOL fill;
1607 BOOL stroke;
1608 HRV(this->shadePath(shadedPath.get(),
bsalomon@google.com5dc26b92012-10-11 19:32:32 +00001609 *paint,
bungeman@google.comb29c8832011-10-10 13:19:10 +00001610 *d.fMatrix,
1611 &fill,
1612 &stroke));
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001613
bungeman@google.comb29c8832011-10-10 13:19:10 +00001614 //Rasterizer
bungeman@google.comd998cbd2012-04-05 18:57:53 +00001615 if (rasterizer) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00001616 SkIRect clipIRect;
1617 SkVector ppuScale;
1618 this->convertToPpm(filter,
1619 &matrix,
1620 &ppuScale,
reed1e7f5e72016-04-27 07:49:17 -07001621 d.fRC->getBounds(),
bungeman@google.comb29c8832011-10-10 13:19:10 +00001622 &clipIRect);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001623
halcanary96fcdcc2015-08-27 07:41:13 -07001624 SkMask* mask = nullptr;
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001625
bungeman@google.comb29c8832011-10-10 13:19:10 +00001626 //[Fillable-path -> Mask]
1627 SkMask rasteredMask;
bungeman@google.comd998cbd2012-04-05 18:57:53 +00001628 if (rasterizer->rasterize(
bungeman@google.comb29c8832011-10-10 13:19:10 +00001629 *fillablePath,
1630 matrix,
1631 &clipIRect,
1632 filter, //just to compute how much to draw.
1633 &rasteredMask,
1634 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001635
bungeman@google.comb29c8832011-10-10 13:19:10 +00001636 SkAutoMaskFreeImage rasteredAmi(rasteredMask.fImage);
1637 mask = &rasteredMask;
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001638
bungeman@google.comb29c8832011-10-10 13:19:10 +00001639 //[Mask -> Mask]
1640 SkMask filteredMask;
robertphillipse80eb922015-12-17 11:33:12 -08001641 if (filter && filter->filterMask(&filteredMask, *mask, *d.fMatrix, nullptr)) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00001642 mask = &filteredMask;
bungeman@google.comb29c8832011-10-10 13:19:10 +00001643 }
1644 SkAutoMaskFreeImage filteredAmi(filteredMask.fImage);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001645
bungeman@google.comb29c8832011-10-10 13:19:10 +00001646 //Draw mask.
1647 HRV(this->applyMask(d, *mask, ppuScale, shadedPath.get()));
1648 }
1649 return;
1650 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001651
bungeman@google.comb29c8832011-10-10 13:19:10 +00001652 //Mask filter
1653 if (filter) {
1654 SkIRect clipIRect;
1655 SkVector ppuScale;
1656 this->convertToPpm(filter,
1657 &matrix,
1658 &ppuScale,
reed1e7f5e72016-04-27 07:49:17 -07001659 d.fRC->getBounds(),
bungeman@google.comb29c8832011-10-10 13:19:10 +00001660 &clipIRect);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001661
bungeman@google.comb29c8832011-10-10 13:19:10 +00001662 //[Fillable-path -> Pixel-path]
1663 SkPath* pixelPath = pathIsMutable ? fillablePath : &modifiedPath;
1664 fillablePath->transform(matrix, pixelPath);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001665
halcanary96fcdcc2015-08-27 07:41:13 -07001666 SkMask* mask = nullptr;
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001667
bsalomon055e1922016-05-06 07:22:58 -07001668 SkASSERT(SkPaint::kFill_Style == paint->getStyle() ||
1669 (SkPaint::kStroke_Style == paint->getStyle() && 0 == paint->getStrokeWidth()));
1670 SkStrokeRec::InitStyle style = (SkPaint::kFill_Style == paint->getStyle())
1671 ? SkStrokeRec::kFill_InitStyle
1672 : SkStrokeRec::kHairline_InitStyle;
bungeman@google.comb29c8832011-10-10 13:19:10 +00001673 //[Pixel-path -> Mask]
1674 SkMask rasteredMask;
1675 if (SkDraw::DrawToMask(
1676 *pixelPath,
1677 &clipIRect,
1678 filter, //just to compute how much to draw.
1679 &matrix,
1680 &rasteredMask,
junov@chromium.org2ac4ef52012-04-04 15:16:51 +00001681 SkMask::kComputeBoundsAndRenderImage_CreateMode,
bsalomon055e1922016-05-06 07:22:58 -07001682 style)) {
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001683
bungeman@google.comb29c8832011-10-10 13:19:10 +00001684 SkAutoMaskFreeImage rasteredAmi(rasteredMask.fImage);
1685 mask = &rasteredMask;
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001686
bungeman@google.comb29c8832011-10-10 13:19:10 +00001687 //[Mask -> Mask]
1688 SkMask filteredMask;
robertphillipse80eb922015-12-17 11:33:12 -08001689 if (filter->filterMask(&filteredMask, rasteredMask, matrix, nullptr)) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00001690 mask = &filteredMask;
bungeman@google.comb29c8832011-10-10 13:19:10 +00001691 }
1692 SkAutoMaskFreeImage filteredAmi(filteredMask.fImage);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001693
bungeman@google.comb29c8832011-10-10 13:19:10 +00001694 //Draw mask.
1695 HRV(this->applyMask(d, *mask, ppuScale, shadedPath.get()));
1696 }
1697 return;
1698 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001699
bungeman@google.comb29c8832011-10-10 13:19:10 +00001700 //Get the figures from the shaded geometry.
1701 SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures;
1702 HRVM(shadedGeometry->GetFigures(&shadedFigures),
1703 "Could not get shaded figures for shaded path.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001704
bungeman@google.comb29c8832011-10-10 13:19:10 +00001705 bool xpsTransformsPath = true;
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001706
bungeman@google.comb29c8832011-10-10 13:19:10 +00001707 //Set the fill rule.
bungeman76db31a2014-08-25 07:31:53 -07001708 SkPath* xpsCompatiblePath = fillablePath;
bungeman@google.comb29c8832011-10-10 13:19:10 +00001709 XPS_FILL_RULE xpsFillRule;
bungeman76db31a2014-08-25 07:31:53 -07001710 switch (fillablePath->getFillType()) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00001711 case SkPath::kWinding_FillType:
1712 xpsFillRule = XPS_FILL_RULE_NONZERO;
1713 break;
1714 case SkPath::kEvenOdd_FillType:
1715 xpsFillRule = XPS_FILL_RULE_EVENODD;
1716 break;
1717 case SkPath::kInverseWinding_FillType: {
bungeman76db31a2014-08-25 07:31:53 -07001718 //[Fillable-path (inverse winding) -> XPS-path (inverse even odd)]
1719 if (!pathIsMutable) {
1720 xpsCompatiblePath = &modifiedPath;
1721 pathIsMutable = true;
1722 }
1723 if (!Simplify(*fillablePath, xpsCompatiblePath)) {
1724 SkDEBUGF(("Could not simplify inverse winding path."));
1725 return;
1726 }
bungeman@google.comb29c8832011-10-10 13:19:10 +00001727 }
bungeman76db31a2014-08-25 07:31:53 -07001728 // The xpsCompatiblePath is noW inverse even odd, so fall through.
bungeman@google.comb29c8832011-10-10 13:19:10 +00001729 case SkPath::kInverseEvenOdd_FillType: {
1730 const SkRect universe = SkRect::MakeLTRB(
1731 0, 0,
1732 this->fCurrentCanvasSize.fWidth,
1733 this->fCurrentCanvasSize.fHeight);
1734 SkTScopedComPtr<IXpsOMGeometryFigure> addOneFigure;
1735 HRV(this->createXpsRect(universe, FALSE, TRUE, &addOneFigure));
1736 HRVM(shadedFigures->Append(addOneFigure.get()),
1737 "Could not add even-odd flip figure to shaded path.");
1738 xpsTransformsPath = false;
1739 xpsFillRule = XPS_FILL_RULE_EVENODD;
1740 break;
1741 }
1742 default:
mtklein@google.com330313a2013-08-22 15:37:26 +00001743 SkDEBUGFAIL("Unknown SkPath::FillType.");
bungeman@google.comb29c8832011-10-10 13:19:10 +00001744 }
1745 HRVM(shadedGeometry->SetFillRule(xpsFillRule),
1746 "Could not set fill rule for shaded path.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001747
bungeman@google.comb29c8832011-10-10 13:19:10 +00001748 //Create the XPS transform, if possible.
1749 if (xpsTransformsPath) {
1750 SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform;
1751 HRV(this->createXpsTransform(matrix, &xpsTransform));
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001752
bungeman@google.comb29c8832011-10-10 13:19:10 +00001753 if (xpsTransform.get()) {
1754 HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()),
1755 "Could not set transform on shaded path.");
1756 } else {
1757 xpsTransformsPath = false;
1758 }
1759 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001760
bungeman76db31a2014-08-25 07:31:53 -07001761 SkPath* devicePath = xpsCompatiblePath;
bungeman@google.comb29c8832011-10-10 13:19:10 +00001762 if (!xpsTransformsPath) {
1763 //[Fillable-path -> Device-path]
bungeman76db31a2014-08-25 07:31:53 -07001764 devicePath = pathIsMutable ? xpsCompatiblePath : &modifiedPath;
1765 xpsCompatiblePath->transform(matrix, devicePath);
bungeman@google.comb29c8832011-10-10 13:19:10 +00001766 }
1767 HRV(this->addXpsPathGeometry(shadedFigures.get(),
1768 stroke, fill, *devicePath));
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001769
bungeman@google.comb29c8832011-10-10 13:19:10 +00001770 HRV(this->clip(shadedPath.get(), d));
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001771
bungeman@google.comb29c8832011-10-10 13:19:10 +00001772 //Add the path to the active visual collection.
1773 SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals;
1774 HRVM(this->fCurrentXpsCanvas->GetVisuals(&currentVisuals),
1775 "Could not get current visuals for shaded path.");
1776 HRVM(currentVisuals->Append(shadedPath.get()),
1777 "Could not add shaded path to current visuals.");
1778}
1779
1780HRESULT SkXPSDevice::clip(IXpsOMVisual* xpsVisual, const SkDraw& d) {
1781 SkPath clipPath;
reed1e7f5e72016-04-27 07:49:17 -07001782 if (d.fRC->isBW()) {
1783 SkAssertResult(d.fRC->bwRgn().getBoundaryPath(&clipPath));
1784 } else {
1785 // Don't have a way to turn a AAClip into a path, so we just use the bounds.
1786 // TODO: consider using fClipStack instead?
1787 clipPath.addRect(SkRect::Make(d.fRC->getBounds()));
1788 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001789
bungeman@google.comb29c8832011-10-10 13:19:10 +00001790 return this->clipToPath(xpsVisual, clipPath, XPS_FILL_RULE_EVENODD);
1791}
1792HRESULT SkXPSDevice::clipToPath(IXpsOMVisual* xpsVisual,
1793 const SkPath& clipPath,
1794 XPS_FILL_RULE fillRule) {
1795 //Create the geometry.
1796 SkTScopedComPtr<IXpsOMGeometry> clipGeometry;
1797 HRM(this->fXpsFactory->CreateGeometry(&clipGeometry),
1798 "Could not create clip geometry.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001799
bungeman@google.comb29c8832011-10-10 13:19:10 +00001800 //Get the figure collection of the geometry.
1801 SkTScopedComPtr<IXpsOMGeometryFigureCollection> clipFigures;
1802 HRM(clipGeometry->GetFigures(&clipFigures),
1803 "Could not get the clip figures.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001804
bungeman@google.comb29c8832011-10-10 13:19:10 +00001805 //Create the figures into the geometry.
1806 HR(this->addXpsPathGeometry(
1807 clipFigures.get(),
1808 FALSE, TRUE, clipPath));
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001809
bungeman@google.comb29c8832011-10-10 13:19:10 +00001810 HRM(clipGeometry->SetFillRule(fillRule),
1811 "Could not set fill rule.");
1812 HRM(xpsVisual->SetClipGeometryLocal(clipGeometry.get()),
1813 "Could not set clip geometry.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001814
bungeman@google.comb29c8832011-10-10 13:19:10 +00001815 return S_OK;
1816}
1817
1818void SkXPSDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap,
bungeman@google.comb29c8832011-10-10 13:19:10 +00001819 const SkMatrix& matrix, const SkPaint& paint) {
reed1e7f5e72016-04-27 07:49:17 -07001820 if (d.fRC->isEmpty()) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00001821 return;
1822 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001823
bungeman@google.comb29c8832011-10-10 13:19:10 +00001824 SkIRect srcRect;
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001825 srcRect.set(0, 0, bitmap.width(), bitmap.height());
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001826
bungeman@google.comb29c8832011-10-10 13:19:10 +00001827 //Create the new shaded path.
1828 SkTScopedComPtr<IXpsOMPath> shadedPath;
1829 HRVM(this->fXpsFactory->CreatePath(&shadedPath),
1830 "Could not create path for bitmap.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001831
bungeman@google.comb29c8832011-10-10 13:19:10 +00001832 //Create the shaded geometry.
1833 SkTScopedComPtr<IXpsOMGeometry> shadedGeometry;
1834 HRVM(this->fXpsFactory->CreateGeometry(&shadedGeometry),
1835 "Could not create geometry for bitmap.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001836
bungeman@google.comb29c8832011-10-10 13:19:10 +00001837 //Add the shaded geometry to the shaded path.
1838 HRVM(shadedPath->SetGeometryLocal(shadedGeometry.get()),
1839 "Could not set the geometry for bitmap.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001840
bungeman@google.comb29c8832011-10-10 13:19:10 +00001841 //Get the shaded figures from the shaded geometry.
1842 SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures;
1843 HRVM(shadedGeometry->GetFigures(&shadedFigures),
1844 "Could not get the figures for bitmap.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001845
bungeman@google.comb29c8832011-10-10 13:19:10 +00001846 SkMatrix transform = matrix;
1847 transform.postConcat(*d.fMatrix);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001848
bungeman@google.comb29c8832011-10-10 13:19:10 +00001849 SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform;
1850 HRV(this->createXpsTransform(transform, &xpsTransform));
1851 if (xpsTransform.get()) {
1852 HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()),
1853 "Could not set transform for bitmap.");
1854 } else {
1855 //TODO: perspective that bitmap!
1856 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001857
bungeman@google.comb29c8832011-10-10 13:19:10 +00001858 SkTScopedComPtr<IXpsOMGeometryFigure> rectFigure;
bsalomon49f085d2014-09-05 13:34:00 -07001859 if (xpsTransform.get()) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00001860 const SkShader::TileMode xy[2] = {
1861 SkShader::kClamp_TileMode,
1862 SkShader::kClamp_TileMode,
1863 };
1864 SkTScopedComPtr<IXpsOMTileBrush> xpsImageBrush;
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001865 HRV(this->createXpsImageBrush(bitmap,
bungeman@google.comb29c8832011-10-10 13:19:10 +00001866 transform,
1867 xy,
1868 paint.getAlpha(),
1869 &xpsImageBrush));
1870 HRVM(shadedPath->SetFillBrushLocal(xpsImageBrush.get()),
1871 "Could not set bitmap brush.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001872
bungeman@google.comb29c8832011-10-10 13:19:10 +00001873 const SkRect bitmapRect = SkRect::MakeLTRB(0, 0,
1874 SkIntToScalar(srcRect.width()), SkIntToScalar(srcRect.height()));
1875 HRV(this->createXpsRect(bitmapRect, FALSE, TRUE, &rectFigure));
1876 }
1877 HRVM(shadedFigures->Append(rectFigure.get()),
1878 "Could not add bitmap figure.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001879
bungeman@google.comb29c8832011-10-10 13:19:10 +00001880 //Get the current visual collection and add the shaded path to it.
1881 SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals;
1882 HRVM(this->fCurrentXpsCanvas->GetVisuals(&currentVisuals),
1883 "Could not get current visuals for bitmap");
1884 HRVM(currentVisuals->Append(shadedPath.get()),
1885 "Could not add bitmap to current visuals.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001886
bungeman@google.comb29c8832011-10-10 13:19:10 +00001887 HRV(this->clip(shadedPath.get(), d));
1888}
1889
1890void SkXPSDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap,
1891 int x, int y,
1892 const SkPaint& paint) {
1893 //TODO: override this for XPS
1894 SkDEBUGF(("XPS drawSprite not yet implemented."));
1895}
1896
1897HRESULT SkXPSDevice::CreateTypefaceUse(const SkPaint& paint,
1898 TypefaceUse** typefaceUse) {
reed@google.com398de9a2013-03-21 21:43:51 +00001899 SkAutoResolveDefaultTypeface typeface(paint.getTypeface());
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001900
bungeman@google.comb29c8832011-10-10 13:19:10 +00001901 //Check cache.
reed@google.com398de9a2013-03-21 21:43:51 +00001902 const SkFontID typefaceID = typeface->uniqueID();
bungeman@google.comb29c8832011-10-10 13:19:10 +00001903 if (!this->fTypefaces.empty()) {
1904 TypefaceUse* current = &this->fTypefaces.front();
1905 const TypefaceUse* last = &this->fTypefaces.back();
1906 for (; current <= last; ++current) {
1907 if (current->typefaceId == typefaceID) {
1908 *typefaceUse = current;
1909 return S_OK;
1910 }
1911 }
1912 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001913
bungeman@google.comb29c8832011-10-10 13:19:10 +00001914 //TODO: create glyph only fonts
1915 //and let the host deal with what kind of font we're looking at.
1916 XPS_FONT_EMBEDDING embedding = XPS_FONT_EMBEDDING_RESTRICTED;
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001917
bungeman@google.comb29c8832011-10-10 13:19:10 +00001918 SkTScopedComPtr<IStream> fontStream;
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +00001919 int ttcIndex;
1920 SkStream* fontData = typeface->openStream(&ttcIndex);
bungeman@google.com635091f2013-10-01 15:03:18 +00001921 //TODO: cannot handle FON fonts.
bungeman@google.com8cddc8d2012-01-03 22:36:33 +00001922 HRM(SkIStream::CreateFromSkStream(fontData, true, &fontStream),
bungeman@google.comb29c8832011-10-10 13:19:10 +00001923 "Could not create font stream.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001924
bungeman@google.comb29c8832011-10-10 13:19:10 +00001925 const size_t size =
1926 SK_ARRAY_COUNT(L"/Resources/Fonts/" L_GUID_ID L".odttf");
1927 wchar_t buffer[size];
1928 wchar_t id[GUID_ID_LEN];
Ben Wagnerda5a1b82014-08-22 15:07:06 -04001929 HR(this->createId(id, GUID_ID_LEN));
bungeman@google.comb29c8832011-10-10 13:19:10 +00001930 swprintf_s(buffer, size, L"/Resources/Fonts/%s.odttf", id);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001931
bungeman@google.comb29c8832011-10-10 13:19:10 +00001932 SkTScopedComPtr<IOpcPartUri> partUri;
1933 HRM(this->fXpsFactory->CreatePartUri(buffer, &partUri),
1934 "Could not create font resource part uri.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001935
bungeman@google.comb29c8832011-10-10 13:19:10 +00001936 SkTScopedComPtr<IXpsOMFontResource> xpsFontResource;
1937 HRM(this->fXpsFactory->CreateFontResource(fontStream.get(),
1938 embedding,
1939 partUri.get(),
1940 FALSE,
1941 &xpsFontResource),
1942 "Could not create font resource.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001943
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +00001944 //TODO: change openStream to return -1 for non-ttc, get rid of this.
1945 uint8_t* data = (uint8_t*)fontData->getMemoryBase();
1946 bool isTTC = (data &&
1947 fontData->getLength() >= sizeof(SkTTCFHeader) &&
1948 ((SkTTCFHeader*)data)->ttcTag == SkTTCFHeader::TAG);
1949
bungeman@google.comb29c8832011-10-10 13:19:10 +00001950 TypefaceUse& newTypefaceUse = this->fTypefaces.push_back();
1951 newTypefaceUse.typefaceId = typefaceID;
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +00001952 newTypefaceUse.ttcIndex = isTTC ? ttcIndex : -1;
bungeman@google.comb29c8832011-10-10 13:19:10 +00001953 newTypefaceUse.fontData = fontData;
1954 newTypefaceUse.xpsFont = xpsFontResource.release();
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001955
robertphillips8e0c1502015-07-07 10:28:43 -07001956 SkAutoGlyphCache agc(paint, &this->surfaceProps(), &SkMatrix::I());
bungeman@google.comb29c8832011-10-10 13:19:10 +00001957 SkGlyphCache* glyphCache = agc.getCache();
1958 unsigned int glyphCount = glyphCache->getGlyphCount();
1959 newTypefaceUse.glyphsUsed = new SkBitSet(glyphCount);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001960
bungeman@google.comb29c8832011-10-10 13:19:10 +00001961 *typefaceUse = &newTypefaceUse;
1962 return S_OK;
1963}
1964
1965HRESULT SkXPSDevice::AddGlyphs(const SkDraw& d,
1966 IXpsOMObjectFactory* xpsFactory,
1967 IXpsOMCanvas* canvas,
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +00001968 TypefaceUse* font,
bungeman@google.comb29c8832011-10-10 13:19:10 +00001969 LPCWSTR text,
1970 XPS_GLYPH_INDEX* xpsGlyphs,
1971 UINT32 xpsGlyphsLen,
1972 XPS_POINT *origin,
1973 FLOAT fontSize,
1974 XPS_STYLE_SIMULATION sims,
1975 const SkMatrix& transform,
1976 const SkPaint& paint) {
1977 SkTScopedComPtr<IXpsOMGlyphs> glyphs;
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +00001978 HRM(xpsFactory->CreateGlyphs(font->xpsFont, &glyphs), "Could not create glyphs.");
1979 HRM(glyphs->SetFontFaceIndex(font->ttcIndex), "Could not set glyph font face index.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001980
bungeman@google.comb29c8832011-10-10 13:19:10 +00001981 //XPS uses affine transformations for everything...
1982 //...except positioning text.
1983 bool useCanvasForClip;
1984 if ((transform.getType() & ~SkMatrix::kTranslate_Mask) == 0) {
1985 origin->x += SkScalarToFLOAT(transform.getTranslateX());
1986 origin->y += SkScalarToFLOAT(transform.getTranslateY());
1987 useCanvasForClip = false;
1988 } else {
1989 SkTScopedComPtr<IXpsOMMatrixTransform> xpsMatrixToUse;
1990 HR(this->createXpsTransform(transform, &xpsMatrixToUse));
1991 if (xpsMatrixToUse.get()) {
1992 HRM(glyphs->SetTransformLocal(xpsMatrixToUse.get()),
1993 "Could not set transform matrix.");
1994 useCanvasForClip = true;
1995 } else {
mtklein@google.com330313a2013-08-22 15:37:26 +00001996 SkDEBUGFAIL("Attempt to add glyphs in perspective.");
bungeman@google.comb29c8832011-10-10 13:19:10 +00001997 useCanvasForClip = false;
1998 }
1999 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002000
bungeman@google.comb29c8832011-10-10 13:19:10 +00002001 SkTScopedComPtr<IXpsOMGlyphsEditor> glyphsEditor;
2002 HRM(glyphs->GetGlyphsEditor(&glyphsEditor), "Could not get glyph editor.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002003
bsalomon49f085d2014-09-05 13:34:00 -07002004 if (text) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00002005 HRM(glyphsEditor->SetUnicodeString(text),
2006 "Could not set unicode string.");
2007 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002008
bsalomon49f085d2014-09-05 13:34:00 -07002009 if (xpsGlyphs) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00002010 HRM(glyphsEditor->SetGlyphIndices(xpsGlyphsLen, xpsGlyphs),
2011 "Could not set glyphs.");
2012 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002013
bungeman@google.comb29c8832011-10-10 13:19:10 +00002014 HRM(glyphsEditor->ApplyEdits(), "Could not apply glyph edits.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002015
bungeman@google.comb29c8832011-10-10 13:19:10 +00002016 SkTScopedComPtr<IXpsOMBrush> xpsFillBrush;
2017 HR(this->createXpsBrush(
2018 paint,
2019 &xpsFillBrush,
halcanary96fcdcc2015-08-27 07:41:13 -07002020 useCanvasForClip ? nullptr : &transform));
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002021
bungeman@google.comb29c8832011-10-10 13:19:10 +00002022 HRM(glyphs->SetFillBrushLocal(xpsFillBrush.get()),
2023 "Could not set fill brush.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002024
bungeman@google.comb29c8832011-10-10 13:19:10 +00002025 HRM(glyphs->SetOrigin(origin), "Could not set glyph origin.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002026
bungeman@google.comb29c8832011-10-10 13:19:10 +00002027 HRM(glyphs->SetFontRenderingEmSize(fontSize),
2028 "Could not set font size.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002029
bungeman@google.comb29c8832011-10-10 13:19:10 +00002030 HRM(glyphs->SetStyleSimulations(sims),
2031 "Could not set style simulations.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002032
bungeman@google.comb29c8832011-10-10 13:19:10 +00002033 SkTScopedComPtr<IXpsOMVisualCollection> visuals;
2034 HRM(canvas->GetVisuals(&visuals), "Could not get glyph canvas visuals.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002035
bungeman@google.comb29c8832011-10-10 13:19:10 +00002036 if (!useCanvasForClip) {
2037 HR(this->clip(glyphs.get(), d));
2038 HRM(visuals->Append(glyphs.get()), "Could not add glyphs to canvas.");
2039 } else {
2040 SkTScopedComPtr<IXpsOMCanvas> glyphCanvas;
2041 HRM(this->fXpsFactory->CreateCanvas(&glyphCanvas),
2042 "Could not create glyph canvas.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002043
bungeman@google.comb29c8832011-10-10 13:19:10 +00002044 SkTScopedComPtr<IXpsOMVisualCollection> glyphCanvasVisuals;
2045 HRM(glyphCanvas->GetVisuals(&glyphCanvasVisuals),
2046 "Could not get glyph visuals collection.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002047
bungeman@google.comb29c8832011-10-10 13:19:10 +00002048 HRM(glyphCanvasVisuals->Append(glyphs.get()),
2049 "Could not add glyphs to page.");
2050 HR(this->clip(glyphCanvas.get(), d));
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002051
bungeman@google.comb29c8832011-10-10 13:19:10 +00002052 HRM(visuals->Append(glyphCanvas.get()),
2053 "Could not add glyph canvas to page.");
2054 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002055
bungeman@google.comb29c8832011-10-10 13:19:10 +00002056 return S_OK;
2057}
2058
herbbda26432015-11-24 08:37:01 -08002059static int num_glyph_guess(SkPaint::TextEncoding encoding, const void* text, size_t byteLength) {
2060 switch (encoding) {
2061 case SkPaint::kUTF8_TextEncoding:
2062 return SkUTF8_CountUnichars(static_cast<const char *>(text), byteLength);
2063 case SkPaint::kUTF16_TextEncoding:
2064 return SkUTF16_CountUnichars(static_cast<const uint16_t *>(text), SkToInt(byteLength));
2065 case SkPaint::kGlyphID_TextEncoding:
2066 return SkToInt(byteLength / 2);
2067 default:
djsollenf2b340f2016-01-29 08:51:04 -08002068 SK_ABORT("Invalid Text Encoding");
bungeman@google.comb29c8832011-10-10 13:19:10 +00002069 }
herbbda26432015-11-24 08:37:01 -08002070 return 0;
bungeman@google.comb29c8832011-10-10 13:19:10 +00002071}
2072
2073static bool text_must_be_pathed(const SkPaint& paint, const SkMatrix& matrix) {
2074 const SkPaint::Style style = paint.getStyle();
2075 return matrix.hasPerspective()
2076 || SkPaint::kStroke_Style == style
2077 || SkPaint::kStrokeAndFill_Style == style
2078 || paint.getMaskFilter()
2079 || paint.getRasterizer()
2080 ;
2081}
2082
herbbda26432015-11-24 08:37:01 -08002083typedef SkTDArray<XPS_GLYPH_INDEX> GlyphRun;
2084
2085class ProcessOneGlyph {
2086public:
2087 ProcessOneGlyph(FLOAT centemPerUnit, SkBitSet* glyphUse, GlyphRun* xpsGlyphs)
2088 : fCentemPerUnit(centemPerUnit)
2089 , fGlyphUse(glyphUse)
2090 , fXpsGlyphs(xpsGlyphs) { }
2091
2092 void operator()(const SkGlyph& glyph, SkPoint position, SkPoint) {
2093 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
2094
2095 SkScalar x = position.fX;
2096 SkScalar y = position.fY;
2097
2098 XPS_GLYPH_INDEX* xpsGlyph = fXpsGlyphs->append();
2099 uint16_t glyphID = glyph.getGlyphID();
halcanarye2348cc2016-08-19 16:23:23 -07002100 fGlyphUse->set(glyphID);
herbbda26432015-11-24 08:37:01 -08002101 xpsGlyph->index = glyphID;
2102 if (1 == fXpsGlyphs->count()) {
2103 xpsGlyph->advanceWidth = 0.0f;
2104 xpsGlyph->horizontalOffset = SkScalarToFloat(x) * fCentemPerUnit;
2105 xpsGlyph->verticalOffset = SkScalarToFloat(y) * -fCentemPerUnit;
2106 }
2107 else {
2108 const XPS_GLYPH_INDEX& first = (*fXpsGlyphs)[0];
2109 xpsGlyph->advanceWidth = 0.0f;
2110 xpsGlyph->horizontalOffset = (SkScalarToFloat(x) * fCentemPerUnit)
2111 - first.horizontalOffset;
2112 xpsGlyph->verticalOffset = (SkScalarToFloat(y) * -fCentemPerUnit)
2113 - first.verticalOffset;
2114 }
2115 }
2116
2117private:
2118 /** [in] Advance width and offsets for glyphs measured in
2119 hundredths of the font em size (XPS Spec 5.1.3). */
2120 const FLOAT fCentemPerUnit;
2121 /** [in,out] The accumulated glyphs used in the current typeface. */
2122 SkBitSet* const fGlyphUse;
2123 /** [out] The glyphs to draw. */
2124 GlyphRun* const fXpsGlyphs;
2125};
2126
bungeman@google.comb29c8832011-10-10 13:19:10 +00002127void SkXPSDevice::drawText(const SkDraw& d,
2128 const void* text, size_t byteLen,
2129 SkScalar x, SkScalar y,
2130 const SkPaint& paint) {
2131 if (byteLen < 1) return;
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002132
bungeman@google.comb29c8832011-10-10 13:19:10 +00002133 if (text_must_be_pathed(paint, *d.fMatrix)) {
2134 SkPath path;
2135 paint.getTextPath(text, byteLen, x, y, &path);
halcanary96fcdcc2015-08-27 07:41:13 -07002136 this->drawPath(d, path, paint, nullptr, true);
bungeman@google.comb29c8832011-10-10 13:19:10 +00002137 //TODO: add automation "text"
2138 return;
2139 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002140
bungeman@google.comb29c8832011-10-10 13:19:10 +00002141 TypefaceUse* typeface;
2142 HRV(CreateTypefaceUse(paint, &typeface));
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002143
herbbda26432015-11-24 08:37:01 -08002144 const SkMatrix& matrix = SkMatrix::I();
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002145
herbbda26432015-11-24 08:37:01 -08002146 SkAutoGlyphCache autoCache(paint, &this->surfaceProps(), &matrix);
2147 SkGlyphCache* cache = autoCache.getCache();
reed@google.com089130c2011-12-12 21:52:18 +00002148
herbbda26432015-11-24 08:37:01 -08002149 // Advance width and offsets for glyphs measured in hundredths of the font em size
2150 // (XPS Spec 5.1.3).
2151 FLOAT centemPerUnit = 100.0f / SkScalarToFLOAT(paint.getTextSize());
2152 GlyphRun xpsGlyphs;
2153 xpsGlyphs.setReserve(num_glyph_guess(paint.getTextEncoding(),
2154 static_cast<const char*>(text), byteLen));
2155
2156 ProcessOneGlyph processOneGlyph(centemPerUnit, typeface->glyphsUsed, &xpsGlyphs);
2157
2158 SkFindAndPlaceGlyph::ProcessText(
2159 paint.getTextEncoding(), static_cast<const char*>(text), byteLen,
2160 SkPoint{ x, y }, matrix, paint.getTextAlign(), cache, processOneGlyph);
2161
2162 if (xpsGlyphs.count() == 0) {
reed@google.com089130c2011-12-12 21:52:18 +00002163 return;
2164 }
2165
bungeman@google.comb29c8832011-10-10 13:19:10 +00002166 XPS_POINT origin = {
herbbda26432015-11-24 08:37:01 -08002167 xpsGlyphs[0].horizontalOffset / centemPerUnit,
2168 xpsGlyphs[0].verticalOffset / -centemPerUnit,
bungeman@google.comb29c8832011-10-10 13:19:10 +00002169 };
herbbda26432015-11-24 08:37:01 -08002170 xpsGlyphs[0].horizontalOffset = 0.0f;
2171 xpsGlyphs[0].verticalOffset = 0.0f;
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002172
bungeman@google.comb29c8832011-10-10 13:19:10 +00002173 HRV(AddGlyphs(d,
2174 this->fXpsFactory.get(),
2175 this->fCurrentXpsCanvas.get(),
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +00002176 typeface,
halcanary96fcdcc2015-08-27 07:41:13 -07002177 nullptr,
herbbda26432015-11-24 08:37:01 -08002178 xpsGlyphs.begin(), xpsGlyphs.count(),
bungeman@google.comb29c8832011-10-10 13:19:10 +00002179 &origin,
2180 SkScalarToFLOAT(paint.getTextSize()),
2181 XPS_STYLE_SIMULATION_NONE,
2182 *d.fMatrix,
2183 paint));
2184}
2185
2186void SkXPSDevice::drawPosText(const SkDraw& d,
2187 const void* text, size_t byteLen,
fmalita05c4a432014-09-29 06:29:53 -07002188 const SkScalar pos[], int scalarsPerPos,
2189 const SkPoint& offset, const SkPaint& paint) {
bungeman@google.comb29c8832011-10-10 13:19:10 +00002190 if (byteLen < 1) return;
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002191
bungeman@google.comb29c8832011-10-10 13:19:10 +00002192 if (text_must_be_pathed(paint, *d.fMatrix)) {
2193 SkPath path;
2194 //TODO: make this work, Draw currently does not handle as well.
2195 //paint.getTextPath(text, byteLength, x, y, &path);
halcanary96fcdcc2015-08-27 07:41:13 -07002196 //this->drawPath(d, path, paint, nullptr, true);
bungeman@google.comb29c8832011-10-10 13:19:10 +00002197 //TODO: add automation "text"
2198 return;
2199 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002200
bungeman@google.comb29c8832011-10-10 13:19:10 +00002201 TypefaceUse* typeface;
2202 HRV(CreateTypefaceUse(paint, &typeface));
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002203
herbbda26432015-11-24 08:37:01 -08002204 const SkMatrix& matrix = SkMatrix::I();
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002205
herbbda26432015-11-24 08:37:01 -08002206 SkAutoGlyphCache autoCache(paint, &this->surfaceProps(), &matrix);
2207 SkGlyphCache* cache = autoCache.getCache();
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002208
herbbda26432015-11-24 08:37:01 -08002209 // Advance width and offsets for glyphs measured in hundredths of the font em size
2210 // (XPS Spec 5.1.3).
2211 FLOAT centemPerUnit = 100.0f / SkScalarToFLOAT(paint.getTextSize());
2212 GlyphRun xpsGlyphs;
2213 xpsGlyphs.setReserve(num_glyph_guess(paint.getTextEncoding(),
2214 static_cast<const char*>(text), byteLen));
2215
2216 ProcessOneGlyph processOneGlyph(centemPerUnit, typeface->glyphsUsed, &xpsGlyphs);
2217
2218 SkFindAndPlaceGlyph::ProcessPosText(
2219 paint.getTextEncoding(), static_cast<const char*>(text), byteLen,
2220 offset, matrix, pos, scalarsPerPos, paint.getTextAlign(), cache, processOneGlyph);
2221
2222 if (xpsGlyphs.count() == 0) {
reed@google.com089130c2011-12-12 21:52:18 +00002223 return;
2224 }
2225
bungeman@google.comb29c8832011-10-10 13:19:10 +00002226 XPS_POINT origin = {
herbbda26432015-11-24 08:37:01 -08002227 xpsGlyphs[0].horizontalOffset / centemPerUnit,
2228 xpsGlyphs[0].verticalOffset / -centemPerUnit,
bungeman@google.comb29c8832011-10-10 13:19:10 +00002229 };
herbbda26432015-11-24 08:37:01 -08002230 xpsGlyphs[0].horizontalOffset = 0.0f;
2231 xpsGlyphs[0].verticalOffset = 0.0f;
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002232
bungeman@google.comb29c8832011-10-10 13:19:10 +00002233 HRV(AddGlyphs(d,
2234 this->fXpsFactory.get(),
2235 this->fCurrentXpsCanvas.get(),
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +00002236 typeface,
halcanary96fcdcc2015-08-27 07:41:13 -07002237 nullptr,
herbbda26432015-11-24 08:37:01 -08002238 xpsGlyphs.begin(), xpsGlyphs.count(),
bungeman@google.comb29c8832011-10-10 13:19:10 +00002239 &origin,
2240 SkScalarToFLOAT(paint.getTextSize()),
2241 XPS_STYLE_SIMULATION_NONE,
2242 *d.fMatrix,
2243 paint));
2244}
2245
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002246void SkXPSDevice::drawDevice(const SkDraw& d, SkBaseDevice* dev,
bungeman@google.comb29c8832011-10-10 13:19:10 +00002247 int x, int y,
2248 const SkPaint&) {
2249 SkXPSDevice* that = static_cast<SkXPSDevice*>(dev);
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002250
bungeman@google.comb29c8832011-10-10 13:19:10 +00002251 SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform;
2252 XPS_MATRIX rawTransform = {
2253 1.0f,
2254 0.0f,
2255 0.0f,
2256 1.0f,
2257 static_cast<FLOAT>(x),
2258 static_cast<FLOAT>(y),
2259 };
2260 HRVM(this->fXpsFactory->CreateMatrixTransform(&rawTransform, &xpsTransform),
2261 "Could not create layer transform.");
2262 HRVM(that->fCurrentXpsCanvas->SetTransformLocal(xpsTransform.get()),
2263 "Could not set layer transform.");
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002264
bungeman@google.comb29c8832011-10-10 13:19:10 +00002265 //Get the current visual collection and add the layer to it.
2266 SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals;
2267 HRVM(this->fCurrentXpsCanvas->GetVisuals(&currentVisuals),
2268 "Could not get current visuals for layer.");
2269 HRVM(currentVisuals->Append(that->fCurrentXpsCanvas.get()),
2270 "Could not add layer to current visuals.");
2271}
2272
reed76033be2015-03-14 10:54:31 -07002273SkBaseDevice* SkXPSDevice::onCreateDevice(const CreateInfo& info, const SkPaint*) {
bungeman@google.com635091f2013-10-01 15:03:18 +00002274//Conditional for bug compatibility with PDF device.
2275#if 0
fmalita6987dca2014-11-13 08:33:37 -08002276 if (SkBaseDevice::kGeneral_Usage == info.fUsage) {
halcanary96fcdcc2015-08-27 07:41:13 -07002277 return nullptr;
bungeman@google.comb29c8832011-10-10 13:19:10 +00002278 //To what stream do we write?
2279 //SkXPSDevice* dev = new SkXPSDevice(this);
2280 //SkSize s = SkSize::Make(width, height);
2281 //dev->BeginCanvas(s, s, SkMatrix::I());
2282 //return dev;
2283 }
bungeman@google.com635091f2013-10-01 15:03:18 +00002284#endif
bungeman@google.comb29c8832011-10-10 13:19:10 +00002285 return new SkXPSDevice(this->fXpsFactory.get());
2286}
2287
mtklein1ee76512015-11-02 10:20:27 -08002288#endif//defined(SK_BUILD_FOR_WIN32)