1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2011 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
9*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_BUILD_FOR_WIN)
10*c8dee2aaSAndroid Build Coastguard Worker
11*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkLeanWindows.h"
12*c8dee2aaSAndroid Build Coastguard Worker
13*c8dee2aaSAndroid Build Coastguard Worker #ifndef UNICODE
14*c8dee2aaSAndroid Build Coastguard Worker #define UNICODE
15*c8dee2aaSAndroid Build Coastguard Worker #endif
16*c8dee2aaSAndroid Build Coastguard Worker #ifndef _UNICODE
17*c8dee2aaSAndroid Build Coastguard Worker #define _UNICODE
18*c8dee2aaSAndroid Build Coastguard Worker #endif
19*c8dee2aaSAndroid Build Coastguard Worker #include <ObjBase.h>
20*c8dee2aaSAndroid Build Coastguard Worker #include <XpsObjectModel.h>
21*c8dee2aaSAndroid Build Coastguard Worker #include <T2EmbApi.h>
22*c8dee2aaSAndroid Build Coastguard Worker #include <FontSub.h>
23*c8dee2aaSAndroid Build Coastguard Worker #include <limits>
24*c8dee2aaSAndroid Build Coastguard Worker
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathEffect.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathUtils.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStream.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkVertices.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "include/encode/SkPngEncoder.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "include/pathops/SkPathOps.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTDArray.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkEndian.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTLazy.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkUtils.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkDraw.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkFontPriv.h"
45*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkGeometry.h"
46*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkImagePriv.h"
47*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMaskFilterBase.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkRasterClip.h"
49*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkStrikeCache.h"
50*c8dee2aaSAndroid Build Coastguard Worker #include "src/image/SkImage_Base.h"
51*c8dee2aaSAndroid Build Coastguard Worker #include "src/sfnt/SkSFNTHeader.h"
52*c8dee2aaSAndroid Build Coastguard Worker #include "src/sfnt/SkTTCFHeader.h"
53*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkColorShader.h"
54*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkShaderBase.h"
55*c8dee2aaSAndroid Build Coastguard Worker #include "src/text/GlyphRun.h"
56*c8dee2aaSAndroid Build Coastguard Worker #include "src/utils/SkClipStackUtils.h"
57*c8dee2aaSAndroid Build Coastguard Worker #include "src/utils/win/SkHRESULT.h"
58*c8dee2aaSAndroid Build Coastguard Worker #include "src/utils/win/SkIStream.h"
59*c8dee2aaSAndroid Build Coastguard Worker #include "src/utils/win/SkTScopedComPtr.h"
60*c8dee2aaSAndroid Build Coastguard Worker #include "src/xps/SkXPSDevice.h"
61*c8dee2aaSAndroid Build Coastguard Worker
62*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
63*c8dee2aaSAndroid Build Coastguard Worker
64*c8dee2aaSAndroid Build Coastguard Worker //Windows defines a FLOAT type,
65*c8dee2aaSAndroid Build Coastguard Worker //make it clear when converting a scalar that this is what is wanted.
66*c8dee2aaSAndroid Build Coastguard Worker #define SkScalarToFLOAT(n) SkScalarToFloat(n)
67*c8dee2aaSAndroid Build Coastguard Worker
68*c8dee2aaSAndroid Build Coastguard Worker //Placeholder representation of a GUID from createId.
69*c8dee2aaSAndroid Build Coastguard Worker #define L_GUID_ID L"XXXXXXXXsXXXXsXXXXsXXXXsXXXXXXXXXXXX"
70*c8dee2aaSAndroid Build Coastguard Worker //Length of GUID representation from createId, including nullptr terminator.
71*c8dee2aaSAndroid Build Coastguard Worker #define GUID_ID_LEN std::size(L_GUID_ID)
72*c8dee2aaSAndroid Build Coastguard Worker
73*c8dee2aaSAndroid Build Coastguard Worker /**
74*c8dee2aaSAndroid Build Coastguard Worker Formats a GUID and places it into buffer.
75*c8dee2aaSAndroid Build Coastguard Worker buffer should have space for at least GUID_ID_LEN wide characters.
76*c8dee2aaSAndroid Build Coastguard Worker The string will always be wchar null terminated.
77*c8dee2aaSAndroid Build Coastguard Worker XXXXXXXXsXXXXsXXXXsXXXXsXXXXXXXXXXXX0
78*c8dee2aaSAndroid Build Coastguard Worker @return -1 if there was an error, > 0 if success.
79*c8dee2aaSAndroid Build Coastguard Worker */
format_guid(const GUID & guid,wchar_t * buffer,size_t bufferSize,wchar_t sep='-')80*c8dee2aaSAndroid Build Coastguard Worker static int format_guid(const GUID& guid,
81*c8dee2aaSAndroid Build Coastguard Worker wchar_t* buffer, size_t bufferSize,
82*c8dee2aaSAndroid Build Coastguard Worker wchar_t sep = '-') {
83*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(bufferSize >= GUID_ID_LEN);
84*c8dee2aaSAndroid Build Coastguard Worker return swprintf_s(buffer,
85*c8dee2aaSAndroid Build Coastguard Worker bufferSize,
86*c8dee2aaSAndroid Build Coastguard Worker L"%08lX%c%04X%c%04X%c%02X%02X%c%02X%02X%02X%02X%02X%02X",
87*c8dee2aaSAndroid Build Coastguard Worker guid.Data1,
88*c8dee2aaSAndroid Build Coastguard Worker sep,
89*c8dee2aaSAndroid Build Coastguard Worker guid.Data2,
90*c8dee2aaSAndroid Build Coastguard Worker sep,
91*c8dee2aaSAndroid Build Coastguard Worker guid.Data3,
92*c8dee2aaSAndroid Build Coastguard Worker sep,
93*c8dee2aaSAndroid Build Coastguard Worker guid.Data4[0],
94*c8dee2aaSAndroid Build Coastguard Worker guid.Data4[1],
95*c8dee2aaSAndroid Build Coastguard Worker sep,
96*c8dee2aaSAndroid Build Coastguard Worker guid.Data4[2],
97*c8dee2aaSAndroid Build Coastguard Worker guid.Data4[3],
98*c8dee2aaSAndroid Build Coastguard Worker guid.Data4[4],
99*c8dee2aaSAndroid Build Coastguard Worker guid.Data4[5],
100*c8dee2aaSAndroid Build Coastguard Worker guid.Data4[6],
101*c8dee2aaSAndroid Build Coastguard Worker guid.Data4[7]);
102*c8dee2aaSAndroid Build Coastguard Worker }
103*c8dee2aaSAndroid Build Coastguard Worker
createId(wchar_t * buffer,size_t bufferSize,wchar_t sep)104*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::createId(wchar_t* buffer, size_t bufferSize, wchar_t sep) {
105*c8dee2aaSAndroid Build Coastguard Worker GUID guid = {};
106*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_XPS_USE_DETERMINISTIC_IDS
107*c8dee2aaSAndroid Build Coastguard Worker guid.Data1 = fNextId++;
108*c8dee2aaSAndroid Build Coastguard Worker // The following make this a valid Type4 UUID.
109*c8dee2aaSAndroid Build Coastguard Worker guid.Data3 = 0x4000;
110*c8dee2aaSAndroid Build Coastguard Worker guid.Data4[0] = 0x80;
111*c8dee2aaSAndroid Build Coastguard Worker #else
112*c8dee2aaSAndroid Build Coastguard Worker HRM(CoCreateGuid(&guid), "Could not create GUID for id.");
113*c8dee2aaSAndroid Build Coastguard Worker #endif
114*c8dee2aaSAndroid Build Coastguard Worker
115*c8dee2aaSAndroid Build Coastguard Worker if (format_guid(guid, buffer, bufferSize, sep) == -1) {
116*c8dee2aaSAndroid Build Coastguard Worker HRM(E_UNEXPECTED, "Could not format GUID into id.");
117*c8dee2aaSAndroid Build Coastguard Worker }
118*c8dee2aaSAndroid Build Coastguard Worker
119*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
120*c8dee2aaSAndroid Build Coastguard Worker }
121*c8dee2aaSAndroid Build Coastguard Worker
SkXPSDevice(SkISize s)122*c8dee2aaSAndroid Build Coastguard Worker SkXPSDevice::SkXPSDevice(SkISize s)
123*c8dee2aaSAndroid Build Coastguard Worker : SkClipStackDevice(SkImageInfo::MakeUnknown(s.width(), s.height()), SkSurfaceProps())
124*c8dee2aaSAndroid Build Coastguard Worker , fCurrentPage(0)
125*c8dee2aaSAndroid Build Coastguard Worker , fTopTypefaces(&fTypefaces) {}
126*c8dee2aaSAndroid Build Coastguard Worker
~SkXPSDevice()127*c8dee2aaSAndroid Build Coastguard Worker SkXPSDevice::~SkXPSDevice() {}
128*c8dee2aaSAndroid Build Coastguard Worker
beginPortfolio(SkWStream * outputStream,IXpsOMObjectFactory * factory)129*c8dee2aaSAndroid Build Coastguard Worker bool SkXPSDevice::beginPortfolio(SkWStream* outputStream, IXpsOMObjectFactory* factory) {
130*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(factory);
131*c8dee2aaSAndroid Build Coastguard Worker fXpsFactory.reset(SkRefComPtr(factory));
132*c8dee2aaSAndroid Build Coastguard Worker HRB(SkWIStream::CreateFromSkWStream(outputStream, &this->fOutputStream));
133*c8dee2aaSAndroid Build Coastguard Worker return true;
134*c8dee2aaSAndroid Build Coastguard Worker }
135*c8dee2aaSAndroid Build Coastguard Worker
beginSheet(const SkVector & unitsPerMeter,const SkVector & pixelsPerMeter,const SkSize & trimSize,const SkRect * mediaBox,const SkRect * bleedBox,const SkRect * artBox,const SkRect * cropBox)136*c8dee2aaSAndroid Build Coastguard Worker bool SkXPSDevice::beginSheet(
137*c8dee2aaSAndroid Build Coastguard Worker const SkVector& unitsPerMeter,
138*c8dee2aaSAndroid Build Coastguard Worker const SkVector& pixelsPerMeter,
139*c8dee2aaSAndroid Build Coastguard Worker const SkSize& trimSize,
140*c8dee2aaSAndroid Build Coastguard Worker const SkRect* mediaBox,
141*c8dee2aaSAndroid Build Coastguard Worker const SkRect* bleedBox,
142*c8dee2aaSAndroid Build Coastguard Worker const SkRect* artBox,
143*c8dee2aaSAndroid Build Coastguard Worker const SkRect* cropBox) {
144*c8dee2aaSAndroid Build Coastguard Worker ++this->fCurrentPage;
145*c8dee2aaSAndroid Build Coastguard Worker
146*c8dee2aaSAndroid Build Coastguard Worker //For simplicity, just write everything out in geometry units,
147*c8dee2aaSAndroid Build Coastguard Worker //then have a base canvas do the scale to physical units.
148*c8dee2aaSAndroid Build Coastguard Worker this->fCurrentCanvasSize = trimSize;
149*c8dee2aaSAndroid Build Coastguard Worker this->fCurrentUnitsPerMeter = unitsPerMeter;
150*c8dee2aaSAndroid Build Coastguard Worker this->fCurrentPixelsPerMeter = pixelsPerMeter;
151*c8dee2aaSAndroid Build Coastguard Worker return this->createCanvasForLayer();
152*c8dee2aaSAndroid Build Coastguard Worker }
153*c8dee2aaSAndroid Build Coastguard Worker
createCanvasForLayer()154*c8dee2aaSAndroid Build Coastguard Worker bool SkXPSDevice::createCanvasForLayer() {
155*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fXpsFactory);
156*c8dee2aaSAndroid Build Coastguard Worker fCurrentXpsCanvas.reset();
157*c8dee2aaSAndroid Build Coastguard Worker HRB(fXpsFactory->CreateCanvas(&fCurrentXpsCanvas));
158*c8dee2aaSAndroid Build Coastguard Worker return true;
159*c8dee2aaSAndroid Build Coastguard Worker }
160*c8dee2aaSAndroid Build Coastguard Worker
sk_digits_in()161*c8dee2aaSAndroid Build Coastguard Worker template <typename T> static constexpr size_t sk_digits_in() {
162*c8dee2aaSAndroid Build Coastguard Worker return static_cast<size_t>(std::numeric_limits<T>::digits10 + 1);
163*c8dee2aaSAndroid Build Coastguard Worker }
164*c8dee2aaSAndroid Build Coastguard Worker
createXpsThumbnail(IXpsOMPage * page,const unsigned int pageNum,IXpsOMImageResource ** image)165*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::createXpsThumbnail(IXpsOMPage* page,
166*c8dee2aaSAndroid Build Coastguard Worker const unsigned int pageNum,
167*c8dee2aaSAndroid Build Coastguard Worker IXpsOMImageResource** image) {
168*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMThumbnailGenerator> thumbnailGenerator;
169*c8dee2aaSAndroid Build Coastguard Worker HRM(CoCreateInstance(
170*c8dee2aaSAndroid Build Coastguard Worker CLSID_XpsOMThumbnailGenerator,
171*c8dee2aaSAndroid Build Coastguard Worker nullptr,
172*c8dee2aaSAndroid Build Coastguard Worker CLSCTX_INPROC_SERVER,
173*c8dee2aaSAndroid Build Coastguard Worker IID_PPV_ARGS(&thumbnailGenerator)),
174*c8dee2aaSAndroid Build Coastguard Worker "Could not create thumbnail generator.");
175*c8dee2aaSAndroid Build Coastguard Worker
176*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IOpcPartUri> partUri;
177*c8dee2aaSAndroid Build Coastguard Worker constexpr size_t size = std::max(
178*c8dee2aaSAndroid Build Coastguard Worker std::size(L"/Documents/1/Metadata/.png") + sk_digits_in<decltype(pageNum)>(),
179*c8dee2aaSAndroid Build Coastguard Worker std::size(L"/Metadata/" L_GUID_ID L".png"));
180*c8dee2aaSAndroid Build Coastguard Worker wchar_t buffer[size];
181*c8dee2aaSAndroid Build Coastguard Worker if (pageNum > 0) {
182*c8dee2aaSAndroid Build Coastguard Worker swprintf_s(buffer, size, L"/Documents/1/Metadata/%u.png", pageNum);
183*c8dee2aaSAndroid Build Coastguard Worker } else {
184*c8dee2aaSAndroid Build Coastguard Worker wchar_t id[GUID_ID_LEN];
185*c8dee2aaSAndroid Build Coastguard Worker HR(this->createId(id, GUID_ID_LEN));
186*c8dee2aaSAndroid Build Coastguard Worker swprintf_s(buffer, size, L"/Metadata/%s.png", id);
187*c8dee2aaSAndroid Build Coastguard Worker }
188*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreatePartUri(buffer, &partUri),
189*c8dee2aaSAndroid Build Coastguard Worker "Could not create thumbnail part uri.");
190*c8dee2aaSAndroid Build Coastguard Worker
191*c8dee2aaSAndroid Build Coastguard Worker HRM(thumbnailGenerator->GenerateThumbnail(page,
192*c8dee2aaSAndroid Build Coastguard Worker XPS_IMAGE_TYPE_PNG,
193*c8dee2aaSAndroid Build Coastguard Worker XPS_THUMBNAIL_SIZE_LARGE,
194*c8dee2aaSAndroid Build Coastguard Worker partUri.get(),
195*c8dee2aaSAndroid Build Coastguard Worker image),
196*c8dee2aaSAndroid Build Coastguard Worker "Could not generate thumbnail.");
197*c8dee2aaSAndroid Build Coastguard Worker
198*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
199*c8dee2aaSAndroid Build Coastguard Worker }
200*c8dee2aaSAndroid Build Coastguard Worker
createXpsPage(const XPS_SIZE & pageSize,IXpsOMPage ** page)201*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::createXpsPage(const XPS_SIZE& pageSize,
202*c8dee2aaSAndroid Build Coastguard Worker IXpsOMPage** page) {
203*c8dee2aaSAndroid Build Coastguard Worker constexpr size_t size =
204*c8dee2aaSAndroid Build Coastguard Worker std::size(L"/Documents/1/Pages/.fpage")
205*c8dee2aaSAndroid Build Coastguard Worker + sk_digits_in<decltype(fCurrentPage)>();
206*c8dee2aaSAndroid Build Coastguard Worker wchar_t buffer[size];
207*c8dee2aaSAndroid Build Coastguard Worker swprintf_s(buffer, size, L"/Documents/1/Pages/%u.fpage",
208*c8dee2aaSAndroid Build Coastguard Worker this->fCurrentPage);
209*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IOpcPartUri> partUri;
210*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreatePartUri(buffer, &partUri),
211*c8dee2aaSAndroid Build Coastguard Worker "Could not create page part uri.");
212*c8dee2aaSAndroid Build Coastguard Worker
213*c8dee2aaSAndroid Build Coastguard Worker //If the language is unknown, use "und" (XPS Spec 2.3.5.1).
214*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreatePage(&pageSize,
215*c8dee2aaSAndroid Build Coastguard Worker L"und",
216*c8dee2aaSAndroid Build Coastguard Worker partUri.get(),
217*c8dee2aaSAndroid Build Coastguard Worker page),
218*c8dee2aaSAndroid Build Coastguard Worker "Could not create page.");
219*c8dee2aaSAndroid Build Coastguard Worker
220*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
221*c8dee2aaSAndroid Build Coastguard Worker }
222*c8dee2aaSAndroid Build Coastguard Worker
initXpsDocumentWriter(IXpsOMImageResource * image)223*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::initXpsDocumentWriter(IXpsOMImageResource* image) {
224*c8dee2aaSAndroid Build Coastguard Worker //Create package writer.
225*c8dee2aaSAndroid Build Coastguard Worker {
226*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IOpcPartUri> partUri;
227*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreatePartUri(L"/FixedDocumentSequence.fdseq",
228*c8dee2aaSAndroid Build Coastguard Worker &partUri),
229*c8dee2aaSAndroid Build Coastguard Worker "Could not create document sequence part uri.");
230*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreatePackageWriterOnStream(
231*c8dee2aaSAndroid Build Coastguard Worker this->fOutputStream.get(),
232*c8dee2aaSAndroid Build Coastguard Worker TRUE,
233*c8dee2aaSAndroid Build Coastguard Worker XPS_INTERLEAVING_OFF, //XPS_INTERLEAVING_ON,
234*c8dee2aaSAndroid Build Coastguard Worker partUri.get(),
235*c8dee2aaSAndroid Build Coastguard Worker nullptr,
236*c8dee2aaSAndroid Build Coastguard Worker image,
237*c8dee2aaSAndroid Build Coastguard Worker nullptr,
238*c8dee2aaSAndroid Build Coastguard Worker nullptr,
239*c8dee2aaSAndroid Build Coastguard Worker &this->fPackageWriter),
240*c8dee2aaSAndroid Build Coastguard Worker "Could not create package writer.");
241*c8dee2aaSAndroid Build Coastguard Worker }
242*c8dee2aaSAndroid Build Coastguard Worker
243*c8dee2aaSAndroid Build Coastguard Worker //Begin the lone document.
244*c8dee2aaSAndroid Build Coastguard Worker {
245*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IOpcPartUri> partUri;
246*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreatePartUri(
247*c8dee2aaSAndroid Build Coastguard Worker L"/Documents/1/FixedDocument.fdoc",
248*c8dee2aaSAndroid Build Coastguard Worker &partUri),
249*c8dee2aaSAndroid Build Coastguard Worker "Could not create fixed document part uri.");
250*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fPackageWriter->StartNewDocument(partUri.get(),
251*c8dee2aaSAndroid Build Coastguard Worker nullptr,
252*c8dee2aaSAndroid Build Coastguard Worker nullptr,
253*c8dee2aaSAndroid Build Coastguard Worker nullptr,
254*c8dee2aaSAndroid Build Coastguard Worker nullptr),
255*c8dee2aaSAndroid Build Coastguard Worker "Could not start document.");
256*c8dee2aaSAndroid Build Coastguard Worker }
257*c8dee2aaSAndroid Build Coastguard Worker
258*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
259*c8dee2aaSAndroid Build Coastguard Worker }
260*c8dee2aaSAndroid Build Coastguard Worker
endSheet()261*c8dee2aaSAndroid Build Coastguard Worker bool SkXPSDevice::endSheet() {
262*c8dee2aaSAndroid Build Coastguard Worker //XPS is fixed at 96dpi (XPS Spec 11.1).
263*c8dee2aaSAndroid Build Coastguard Worker static const float xpsDPI = 96.0f;
264*c8dee2aaSAndroid Build Coastguard Worker static const float inchesPerMeter = 10000.0f / 254.0f;
265*c8dee2aaSAndroid Build Coastguard Worker static const float targetUnitsPerMeter = xpsDPI * inchesPerMeter;
266*c8dee2aaSAndroid Build Coastguard Worker const float scaleX = targetUnitsPerMeter
267*c8dee2aaSAndroid Build Coastguard Worker / SkScalarToFLOAT(this->fCurrentUnitsPerMeter.fX);
268*c8dee2aaSAndroid Build Coastguard Worker const float scaleY = targetUnitsPerMeter
269*c8dee2aaSAndroid Build Coastguard Worker / SkScalarToFLOAT(this->fCurrentUnitsPerMeter.fY);
270*c8dee2aaSAndroid Build Coastguard Worker
271*c8dee2aaSAndroid Build Coastguard Worker //Create the scale canvas.
272*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMCanvas> scaleCanvas;
273*c8dee2aaSAndroid Build Coastguard Worker HRBM(this->fXpsFactory->CreateCanvas(&scaleCanvas),
274*c8dee2aaSAndroid Build Coastguard Worker "Could not create scale canvas.");
275*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMVisualCollection> scaleCanvasVisuals;
276*c8dee2aaSAndroid Build Coastguard Worker HRBM(scaleCanvas->GetVisuals(&scaleCanvasVisuals),
277*c8dee2aaSAndroid Build Coastguard Worker "Could not get scale canvas visuals.");
278*c8dee2aaSAndroid Build Coastguard Worker
279*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMMatrixTransform> geomToPhys;
280*c8dee2aaSAndroid Build Coastguard Worker XPS_MATRIX rawGeomToPhys = { scaleX, 0, 0, scaleY, 0, 0, };
281*c8dee2aaSAndroid Build Coastguard Worker HRBM(this->fXpsFactory->CreateMatrixTransform(&rawGeomToPhys, &geomToPhys),
282*c8dee2aaSAndroid Build Coastguard Worker "Could not create geometry to physical transform.");
283*c8dee2aaSAndroid Build Coastguard Worker HRBM(scaleCanvas->SetTransformLocal(geomToPhys.get()),
284*c8dee2aaSAndroid Build Coastguard Worker "Could not set transform on scale canvas.");
285*c8dee2aaSAndroid Build Coastguard Worker
286*c8dee2aaSAndroid Build Coastguard Worker //Add the content canvas to the scale canvas.
287*c8dee2aaSAndroid Build Coastguard Worker HRBM(scaleCanvasVisuals->Append(this->fCurrentXpsCanvas.get()),
288*c8dee2aaSAndroid Build Coastguard Worker "Could not add base canvas to scale canvas.");
289*c8dee2aaSAndroid Build Coastguard Worker
290*c8dee2aaSAndroid Build Coastguard Worker //Create the page.
291*c8dee2aaSAndroid Build Coastguard Worker XPS_SIZE pageSize = {
292*c8dee2aaSAndroid Build Coastguard Worker SkScalarToFLOAT(this->fCurrentCanvasSize.width()) * scaleX,
293*c8dee2aaSAndroid Build Coastguard Worker SkScalarToFLOAT(this->fCurrentCanvasSize.height()) * scaleY,
294*c8dee2aaSAndroid Build Coastguard Worker };
295*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMPage> page;
296*c8dee2aaSAndroid Build Coastguard Worker HRB(this->createXpsPage(pageSize, &page));
297*c8dee2aaSAndroid Build Coastguard Worker
298*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMVisualCollection> pageVisuals;
299*c8dee2aaSAndroid Build Coastguard Worker HRBM(page->GetVisuals(&pageVisuals), "Could not get page visuals.");
300*c8dee2aaSAndroid Build Coastguard Worker
301*c8dee2aaSAndroid Build Coastguard Worker //Add the scale canvas to the page.
302*c8dee2aaSAndroid Build Coastguard Worker HRBM(pageVisuals->Append(scaleCanvas.get()),
303*c8dee2aaSAndroid Build Coastguard Worker "Could not add scale canvas to page.");
304*c8dee2aaSAndroid Build Coastguard Worker
305*c8dee2aaSAndroid Build Coastguard Worker //Create the package writer if it hasn't been created yet.
306*c8dee2aaSAndroid Build Coastguard Worker if (nullptr == this->fPackageWriter.get()) {
307*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMImageResource> image;
308*c8dee2aaSAndroid Build Coastguard Worker //Ignore return, thumbnail is completely optional.
309*c8dee2aaSAndroid Build Coastguard Worker this->createXpsThumbnail(page.get(), 0, &image);
310*c8dee2aaSAndroid Build Coastguard Worker
311*c8dee2aaSAndroid Build Coastguard Worker HRB(this->initXpsDocumentWriter(image.get()));
312*c8dee2aaSAndroid Build Coastguard Worker }
313*c8dee2aaSAndroid Build Coastguard Worker
314*c8dee2aaSAndroid Build Coastguard Worker HRBM(this->fPackageWriter->AddPage(page.get(),
315*c8dee2aaSAndroid Build Coastguard Worker &pageSize,
316*c8dee2aaSAndroid Build Coastguard Worker nullptr,
317*c8dee2aaSAndroid Build Coastguard Worker nullptr,
318*c8dee2aaSAndroid Build Coastguard Worker nullptr,
319*c8dee2aaSAndroid Build Coastguard Worker nullptr),
320*c8dee2aaSAndroid Build Coastguard Worker "Could not write the page.");
321*c8dee2aaSAndroid Build Coastguard Worker this->fCurrentXpsCanvas.reset();
322*c8dee2aaSAndroid Build Coastguard Worker
323*c8dee2aaSAndroid Build Coastguard Worker return true;
324*c8dee2aaSAndroid Build Coastguard Worker }
325*c8dee2aaSAndroid Build Coastguard Worker
subset_typeface(const SkXPSDevice::TypefaceUse & current)326*c8dee2aaSAndroid Build Coastguard Worker static HRESULT subset_typeface(const SkXPSDevice::TypefaceUse& current) {
327*c8dee2aaSAndroid Build Coastguard Worker //The CreateFontPackage API is only supported on desktop, not in UWP
328*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_WINUWP)
329*c8dee2aaSAndroid Build Coastguard Worker return E_NOTIMPL;
330*c8dee2aaSAndroid Build Coastguard Worker #else
331*c8dee2aaSAndroid Build Coastguard Worker //CreateFontPackage wants unsigned short.
332*c8dee2aaSAndroid Build Coastguard Worker //Microsoft, Y U NO stdint.h?
333*c8dee2aaSAndroid Build Coastguard Worker std::vector<unsigned short> keepList;
334*c8dee2aaSAndroid Build Coastguard Worker current.glyphsUsed.forEachSetIndex([&keepList](size_t v) {
335*c8dee2aaSAndroid Build Coastguard Worker keepList.push_back((unsigned short)v);
336*c8dee2aaSAndroid Build Coastguard Worker });
337*c8dee2aaSAndroid Build Coastguard Worker
338*c8dee2aaSAndroid Build Coastguard Worker int ttcCount = (current.ttcIndex + 1);
339*c8dee2aaSAndroid Build Coastguard Worker
340*c8dee2aaSAndroid Build Coastguard Worker //The following are declared with the types required by CreateFontPackage.
341*c8dee2aaSAndroid Build Coastguard Worker unsigned char *fontPackageBufferRaw = nullptr;
342*c8dee2aaSAndroid Build Coastguard Worker unsigned long fontPackageBufferSize;
343*c8dee2aaSAndroid Build Coastguard Worker unsigned long bytesWritten;
344*c8dee2aaSAndroid Build Coastguard Worker unsigned long result = CreateFontPackage(
345*c8dee2aaSAndroid Build Coastguard Worker (const unsigned char *) current.fontData->getMemoryBase(),
346*c8dee2aaSAndroid Build Coastguard Worker (unsigned long) current.fontData->getLength(),
347*c8dee2aaSAndroid Build Coastguard Worker &fontPackageBufferRaw,
348*c8dee2aaSAndroid Build Coastguard Worker &fontPackageBufferSize,
349*c8dee2aaSAndroid Build Coastguard Worker &bytesWritten,
350*c8dee2aaSAndroid Build Coastguard Worker TTFCFP_FLAGS_SUBSET | TTFCFP_FLAGS_GLYPHLIST | (ttcCount > 0 ? TTFCFP_FLAGS_TTC : 0),
351*c8dee2aaSAndroid Build Coastguard Worker current.ttcIndex,
352*c8dee2aaSAndroid Build Coastguard Worker TTFCFP_SUBSET,
353*c8dee2aaSAndroid Build Coastguard Worker 0,
354*c8dee2aaSAndroid Build Coastguard Worker 0,
355*c8dee2aaSAndroid Build Coastguard Worker 0,
356*c8dee2aaSAndroid Build Coastguard Worker keepList.data(),
357*c8dee2aaSAndroid Build Coastguard Worker SkTo<unsigned short>(keepList.size()),
358*c8dee2aaSAndroid Build Coastguard Worker sk_malloc_throw,
359*c8dee2aaSAndroid Build Coastguard Worker sk_realloc_throw,
360*c8dee2aaSAndroid Build Coastguard Worker sk_free,
361*c8dee2aaSAndroid Build Coastguard Worker nullptr);
362*c8dee2aaSAndroid Build Coastguard Worker AutoTMalloc<unsigned char> fontPackageBuffer(fontPackageBufferRaw);
363*c8dee2aaSAndroid Build Coastguard Worker if (result != NO_ERROR) {
364*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGF("CreateFontPackage Error %lu", result);
365*c8dee2aaSAndroid Build Coastguard Worker return E_UNEXPECTED;
366*c8dee2aaSAndroid Build Coastguard Worker }
367*c8dee2aaSAndroid Build Coastguard Worker
368*c8dee2aaSAndroid Build Coastguard Worker // If it was originally a ttc, keep it a ttc.
369*c8dee2aaSAndroid Build Coastguard Worker // CreateFontPackage over-allocates, realloc usually decreases the size substantially.
370*c8dee2aaSAndroid Build Coastguard Worker size_t extra;
371*c8dee2aaSAndroid Build Coastguard Worker if (ttcCount > 0) {
372*c8dee2aaSAndroid Build Coastguard Worker // Create space for a ttc header.
373*c8dee2aaSAndroid Build Coastguard Worker extra = sizeof(SkTTCFHeader) + (ttcCount * sizeof(SK_OT_ULONG));
374*c8dee2aaSAndroid Build Coastguard Worker fontPackageBuffer.realloc(bytesWritten + extra);
375*c8dee2aaSAndroid Build Coastguard Worker //overlap is certain, use memmove
376*c8dee2aaSAndroid Build Coastguard Worker memmove(fontPackageBuffer.get() + extra, fontPackageBuffer.get(), bytesWritten);
377*c8dee2aaSAndroid Build Coastguard Worker
378*c8dee2aaSAndroid Build Coastguard Worker // Write the ttc header.
379*c8dee2aaSAndroid Build Coastguard Worker SkTTCFHeader* ttcfHeader = reinterpret_cast<SkTTCFHeader*>(fontPackageBuffer.get());
380*c8dee2aaSAndroid Build Coastguard Worker ttcfHeader->ttcTag = SkTTCFHeader::TAG;
381*c8dee2aaSAndroid Build Coastguard Worker ttcfHeader->version = SkTTCFHeader::version_1;
382*c8dee2aaSAndroid Build Coastguard Worker ttcfHeader->numOffsets = SkEndian_SwapBE32(ttcCount);
383*c8dee2aaSAndroid Build Coastguard Worker SK_OT_ULONG* offsetPtr = SkTAfter<SK_OT_ULONG>(ttcfHeader);
384*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < ttcCount; ++i, ++offsetPtr) {
385*c8dee2aaSAndroid Build Coastguard Worker *offsetPtr = SkEndian_SwapBE32(SkToU32(extra));
386*c8dee2aaSAndroid Build Coastguard Worker }
387*c8dee2aaSAndroid Build Coastguard Worker
388*c8dee2aaSAndroid Build Coastguard Worker // Fix up offsets in sfnt table entries.
389*c8dee2aaSAndroid Build Coastguard Worker SkSFNTHeader* sfntHeader = SkTAddOffset<SkSFNTHeader>(fontPackageBuffer.get(), extra);
390*c8dee2aaSAndroid Build Coastguard Worker int numTables = SkEndian_SwapBE16(sfntHeader->numTables);
391*c8dee2aaSAndroid Build Coastguard Worker SkSFNTHeader::TableDirectoryEntry* tableDirectory =
392*c8dee2aaSAndroid Build Coastguard Worker SkTAfter<SkSFNTHeader::TableDirectoryEntry>(sfntHeader);
393*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < numTables; ++i, ++tableDirectory) {
394*c8dee2aaSAndroid Build Coastguard Worker tableDirectory->offset = SkEndian_SwapBE32(
395*c8dee2aaSAndroid Build Coastguard Worker SkToU32(SkEndian_SwapBE32(SkToU32(tableDirectory->offset)) + extra));
396*c8dee2aaSAndroid Build Coastguard Worker }
397*c8dee2aaSAndroid Build Coastguard Worker } else {
398*c8dee2aaSAndroid Build Coastguard Worker extra = 0;
399*c8dee2aaSAndroid Build Coastguard Worker fontPackageBuffer.realloc(bytesWritten);
400*c8dee2aaSAndroid Build Coastguard Worker }
401*c8dee2aaSAndroid Build Coastguard Worker
402*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkMemoryStream> newStream(new SkMemoryStream());
403*c8dee2aaSAndroid Build Coastguard Worker newStream->setMemoryOwned(fontPackageBuffer.release(), bytesWritten + extra);
404*c8dee2aaSAndroid Build Coastguard Worker
405*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IStream> newIStream;
406*c8dee2aaSAndroid Build Coastguard Worker SkIStream::CreateFromSkStream(std::move(newStream), &newIStream);
407*c8dee2aaSAndroid Build Coastguard Worker
408*c8dee2aaSAndroid Build Coastguard Worker XPS_FONT_EMBEDDING embedding;
409*c8dee2aaSAndroid Build Coastguard Worker HRM(current.xpsFont->GetEmbeddingOption(&embedding),
410*c8dee2aaSAndroid Build Coastguard Worker "Could not get embedding option from font.");
411*c8dee2aaSAndroid Build Coastguard Worker
412*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IOpcPartUri> partUri;
413*c8dee2aaSAndroid Build Coastguard Worker HRM(current.xpsFont->GetPartName(&partUri),
414*c8dee2aaSAndroid Build Coastguard Worker "Could not get part uri from font.");
415*c8dee2aaSAndroid Build Coastguard Worker
416*c8dee2aaSAndroid Build Coastguard Worker HRM(current.xpsFont->SetContent(
417*c8dee2aaSAndroid Build Coastguard Worker newIStream.get(),
418*c8dee2aaSAndroid Build Coastguard Worker embedding,
419*c8dee2aaSAndroid Build Coastguard Worker partUri.get()),
420*c8dee2aaSAndroid Build Coastguard Worker "Could not set new stream for subsetted font.");
421*c8dee2aaSAndroid Build Coastguard Worker
422*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
423*c8dee2aaSAndroid Build Coastguard Worker #endif //SK_WINUWP
424*c8dee2aaSAndroid Build Coastguard Worker }
425*c8dee2aaSAndroid Build Coastguard Worker
endPortfolio()426*c8dee2aaSAndroid Build Coastguard Worker bool SkXPSDevice::endPortfolio() {
427*c8dee2aaSAndroid Build Coastguard Worker //Subset fonts
428*c8dee2aaSAndroid Build Coastguard Worker for (const TypefaceUse& current : *this->fTopTypefaces) {
429*c8dee2aaSAndroid Build Coastguard Worker //Ignore return for now, if it didn't subset, let it be.
430*c8dee2aaSAndroid Build Coastguard Worker subset_typeface(current);
431*c8dee2aaSAndroid Build Coastguard Worker }
432*c8dee2aaSAndroid Build Coastguard Worker
433*c8dee2aaSAndroid Build Coastguard Worker if (this->fPackageWriter) {
434*c8dee2aaSAndroid Build Coastguard Worker HRBM(this->fPackageWriter->Close(), "Could not close writer.");
435*c8dee2aaSAndroid Build Coastguard Worker }
436*c8dee2aaSAndroid Build Coastguard Worker
437*c8dee2aaSAndroid Build Coastguard Worker return true;
438*c8dee2aaSAndroid Build Coastguard Worker }
439*c8dee2aaSAndroid Build Coastguard Worker
xps_color(const SkColor skColor)440*c8dee2aaSAndroid Build Coastguard Worker static XPS_COLOR xps_color(const SkColor skColor) {
441*c8dee2aaSAndroid Build Coastguard Worker //XPS uses non-pre-multiplied alpha (XPS Spec 11.4).
442*c8dee2aaSAndroid Build Coastguard Worker XPS_COLOR xpsColor;
443*c8dee2aaSAndroid Build Coastguard Worker xpsColor.colorType = XPS_COLOR_TYPE_SRGB;
444*c8dee2aaSAndroid Build Coastguard Worker xpsColor.value.sRGB.alpha = SkColorGetA(skColor);
445*c8dee2aaSAndroid Build Coastguard Worker xpsColor.value.sRGB.red = SkColorGetR(skColor);
446*c8dee2aaSAndroid Build Coastguard Worker xpsColor.value.sRGB.green = SkColorGetG(skColor);
447*c8dee2aaSAndroid Build Coastguard Worker xpsColor.value.sRGB.blue = SkColorGetB(skColor);
448*c8dee2aaSAndroid Build Coastguard Worker
449*c8dee2aaSAndroid Build Coastguard Worker return xpsColor;
450*c8dee2aaSAndroid Build Coastguard Worker }
451*c8dee2aaSAndroid Build Coastguard Worker
xps_point(const SkPoint & point)452*c8dee2aaSAndroid Build Coastguard Worker static XPS_POINT xps_point(const SkPoint& point) {
453*c8dee2aaSAndroid Build Coastguard Worker XPS_POINT xpsPoint = {
454*c8dee2aaSAndroid Build Coastguard Worker SkScalarToFLOAT(point.fX),
455*c8dee2aaSAndroid Build Coastguard Worker SkScalarToFLOAT(point.fY),
456*c8dee2aaSAndroid Build Coastguard Worker };
457*c8dee2aaSAndroid Build Coastguard Worker return xpsPoint;
458*c8dee2aaSAndroid Build Coastguard Worker }
459*c8dee2aaSAndroid Build Coastguard Worker
xps_point(const SkPoint & point,const SkMatrix & matrix)460*c8dee2aaSAndroid Build Coastguard Worker static XPS_POINT xps_point(const SkPoint& point, const SkMatrix& matrix) {
461*c8dee2aaSAndroid Build Coastguard Worker SkPoint skTransformedPoint;
462*c8dee2aaSAndroid Build Coastguard Worker matrix.mapXY(point.fX, point.fY, &skTransformedPoint);
463*c8dee2aaSAndroid Build Coastguard Worker return xps_point(skTransformedPoint);
464*c8dee2aaSAndroid Build Coastguard Worker }
465*c8dee2aaSAndroid Build Coastguard Worker
xps_spread_method(SkTileMode tileMode)466*c8dee2aaSAndroid Build Coastguard Worker static XPS_SPREAD_METHOD xps_spread_method(SkTileMode tileMode) {
467*c8dee2aaSAndroid Build Coastguard Worker switch (tileMode) {
468*c8dee2aaSAndroid Build Coastguard Worker case SkTileMode::kClamp:
469*c8dee2aaSAndroid Build Coastguard Worker return XPS_SPREAD_METHOD_PAD;
470*c8dee2aaSAndroid Build Coastguard Worker case SkTileMode::kRepeat:
471*c8dee2aaSAndroid Build Coastguard Worker return XPS_SPREAD_METHOD_REPEAT;
472*c8dee2aaSAndroid Build Coastguard Worker case SkTileMode::kMirror:
473*c8dee2aaSAndroid Build Coastguard Worker return XPS_SPREAD_METHOD_REFLECT;
474*c8dee2aaSAndroid Build Coastguard Worker case SkTileMode::kDecal:
475*c8dee2aaSAndroid Build Coastguard Worker // TODO: fake
476*c8dee2aaSAndroid Build Coastguard Worker return XPS_SPREAD_METHOD_PAD;
477*c8dee2aaSAndroid Build Coastguard Worker default:
478*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("Unknown tile mode.");
479*c8dee2aaSAndroid Build Coastguard Worker }
480*c8dee2aaSAndroid Build Coastguard Worker return XPS_SPREAD_METHOD_PAD;
481*c8dee2aaSAndroid Build Coastguard Worker }
482*c8dee2aaSAndroid Build Coastguard Worker
transform_offsets(SkScalar * stopOffsets,const int numOffsets,const SkPoint & start,const SkPoint & end,const SkMatrix & transform)483*c8dee2aaSAndroid Build Coastguard Worker static void transform_offsets(SkScalar* stopOffsets, const int numOffsets,
484*c8dee2aaSAndroid Build Coastguard Worker const SkPoint& start, const SkPoint& end,
485*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& transform) {
486*c8dee2aaSAndroid Build Coastguard Worker SkPoint startTransformed;
487*c8dee2aaSAndroid Build Coastguard Worker transform.mapXY(start.fX, start.fY, &startTransformed);
488*c8dee2aaSAndroid Build Coastguard Worker SkPoint endTransformed;
489*c8dee2aaSAndroid Build Coastguard Worker transform.mapXY(end.fX, end.fY, &endTransformed);
490*c8dee2aaSAndroid Build Coastguard Worker
491*c8dee2aaSAndroid Build Coastguard Worker //Manhattan distance between transformed start and end.
492*c8dee2aaSAndroid Build Coastguard Worker SkScalar startToEnd = (endTransformed.fX - startTransformed.fX)
493*c8dee2aaSAndroid Build Coastguard Worker + (endTransformed.fY - startTransformed.fY);
494*c8dee2aaSAndroid Build Coastguard Worker if (SkScalarNearlyZero(startToEnd)) {
495*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < numOffsets; ++i) {
496*c8dee2aaSAndroid Build Coastguard Worker stopOffsets[i] = 0;
497*c8dee2aaSAndroid Build Coastguard Worker }
498*c8dee2aaSAndroid Build Coastguard Worker return;
499*c8dee2aaSAndroid Build Coastguard Worker }
500*c8dee2aaSAndroid Build Coastguard Worker
501*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < numOffsets; ++i) {
502*c8dee2aaSAndroid Build Coastguard Worker SkPoint stop;
503*c8dee2aaSAndroid Build Coastguard Worker stop.fX = (end.fX - start.fX) * stopOffsets[i];
504*c8dee2aaSAndroid Build Coastguard Worker stop.fY = (end.fY - start.fY) * stopOffsets[i];
505*c8dee2aaSAndroid Build Coastguard Worker
506*c8dee2aaSAndroid Build Coastguard Worker SkPoint stopTransformed;
507*c8dee2aaSAndroid Build Coastguard Worker transform.mapXY(stop.fX, stop.fY, &stopTransformed);
508*c8dee2aaSAndroid Build Coastguard Worker
509*c8dee2aaSAndroid Build Coastguard Worker //Manhattan distance between transformed start and stop.
510*c8dee2aaSAndroid Build Coastguard Worker SkScalar startToStop = (stopTransformed.fX - startTransformed.fX)
511*c8dee2aaSAndroid Build Coastguard Worker + (stopTransformed.fY - startTransformed.fY);
512*c8dee2aaSAndroid Build Coastguard Worker //Percentage along transformed line.
513*c8dee2aaSAndroid Build Coastguard Worker stopOffsets[i] = startToStop / startToEnd;
514*c8dee2aaSAndroid Build Coastguard Worker }
515*c8dee2aaSAndroid Build Coastguard Worker }
516*c8dee2aaSAndroid Build Coastguard Worker
createXpsTransform(const SkMatrix & matrix,IXpsOMMatrixTransform ** xpsTransform)517*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::createXpsTransform(const SkMatrix& matrix,
518*c8dee2aaSAndroid Build Coastguard Worker IXpsOMMatrixTransform** xpsTransform) {
519*c8dee2aaSAndroid Build Coastguard Worker SkScalar affine[6];
520*c8dee2aaSAndroid Build Coastguard Worker if (!matrix.asAffine(affine)) {
521*c8dee2aaSAndroid Build Coastguard Worker *xpsTransform = nullptr;
522*c8dee2aaSAndroid Build Coastguard Worker return S_FALSE;
523*c8dee2aaSAndroid Build Coastguard Worker }
524*c8dee2aaSAndroid Build Coastguard Worker XPS_MATRIX rawXpsMatrix = {
525*c8dee2aaSAndroid Build Coastguard Worker SkScalarToFLOAT(affine[SkMatrix::kAScaleX]),
526*c8dee2aaSAndroid Build Coastguard Worker SkScalarToFLOAT(affine[SkMatrix::kASkewY]),
527*c8dee2aaSAndroid Build Coastguard Worker SkScalarToFLOAT(affine[SkMatrix::kASkewX]),
528*c8dee2aaSAndroid Build Coastguard Worker SkScalarToFLOAT(affine[SkMatrix::kAScaleY]),
529*c8dee2aaSAndroid Build Coastguard Worker SkScalarToFLOAT(affine[SkMatrix::kATransX]),
530*c8dee2aaSAndroid Build Coastguard Worker SkScalarToFLOAT(affine[SkMatrix::kATransY]),
531*c8dee2aaSAndroid Build Coastguard Worker };
532*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreateMatrixTransform(&rawXpsMatrix, xpsTransform),
533*c8dee2aaSAndroid Build Coastguard Worker "Could not create transform.");
534*c8dee2aaSAndroid Build Coastguard Worker
535*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
536*c8dee2aaSAndroid Build Coastguard Worker }
537*c8dee2aaSAndroid Build Coastguard Worker
createPath(IXpsOMGeometryFigure * figure,IXpsOMVisualCollection * visuals,IXpsOMPath ** path)538*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::createPath(IXpsOMGeometryFigure* figure,
539*c8dee2aaSAndroid Build Coastguard Worker IXpsOMVisualCollection* visuals,
540*c8dee2aaSAndroid Build Coastguard Worker IXpsOMPath** path) {
541*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometry> geometry;
542*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreateGeometry(&geometry),
543*c8dee2aaSAndroid Build Coastguard Worker "Could not create geometry.");
544*c8dee2aaSAndroid Build Coastguard Worker
545*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometryFigureCollection> figureCollection;
546*c8dee2aaSAndroid Build Coastguard Worker HRM(geometry->GetFigures(&figureCollection), "Could not get figures.");
547*c8dee2aaSAndroid Build Coastguard Worker HRM(figureCollection->Append(figure), "Could not add figure.");
548*c8dee2aaSAndroid Build Coastguard Worker
549*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreatePath(path), "Could not create path.");
550*c8dee2aaSAndroid Build Coastguard Worker HRM((*path)->SetGeometryLocal(geometry.get()), "Could not set geometry");
551*c8dee2aaSAndroid Build Coastguard Worker
552*c8dee2aaSAndroid Build Coastguard Worker HRM(visuals->Append(*path), "Could not add path to visuals.");
553*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
554*c8dee2aaSAndroid Build Coastguard Worker }
555*c8dee2aaSAndroid Build Coastguard Worker
createXpsSolidColorBrush(const SkColor skColor,const SkAlpha alpha,IXpsOMBrush ** xpsBrush)556*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::createXpsSolidColorBrush(const SkColor skColor,
557*c8dee2aaSAndroid Build Coastguard Worker const SkAlpha alpha,
558*c8dee2aaSAndroid Build Coastguard Worker IXpsOMBrush** xpsBrush) {
559*c8dee2aaSAndroid Build Coastguard Worker XPS_COLOR xpsColor = xps_color(skColor);
560*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMSolidColorBrush> solidBrush;
561*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreateSolidColorBrush(&xpsColor, nullptr, &solidBrush),
562*c8dee2aaSAndroid Build Coastguard Worker "Could not create solid color brush.");
563*c8dee2aaSAndroid Build Coastguard Worker HRM(solidBrush->SetOpacity(alpha / 255.0f), "Could not set opacity.");
564*c8dee2aaSAndroid Build Coastguard Worker HRM(solidBrush->QueryInterface<IXpsOMBrush>(xpsBrush), "QI Fail.");
565*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
566*c8dee2aaSAndroid Build Coastguard Worker }
567*c8dee2aaSAndroid Build Coastguard Worker
sideOfClamp(const SkRect & areaToFill,const XPS_RECT & imageViewBox,IXpsOMImageResource * image,IXpsOMVisualCollection * visuals)568*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::sideOfClamp(const SkRect& areaToFill,
569*c8dee2aaSAndroid Build Coastguard Worker const XPS_RECT& imageViewBox,
570*c8dee2aaSAndroid Build Coastguard Worker IXpsOMImageResource* image,
571*c8dee2aaSAndroid Build Coastguard Worker IXpsOMVisualCollection* visuals) {
572*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometryFigure> areaToFillFigure;
573*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsRect(areaToFill, FALSE, TRUE, &areaToFillFigure));
574*c8dee2aaSAndroid Build Coastguard Worker
575*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMPath> areaToFillPath;
576*c8dee2aaSAndroid Build Coastguard Worker HR(this->createPath(areaToFillFigure.get(), visuals, &areaToFillPath));
577*c8dee2aaSAndroid Build Coastguard Worker
578*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMImageBrush> areaToFillBrush;
579*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreateImageBrush(image,
580*c8dee2aaSAndroid Build Coastguard Worker &imageViewBox,
581*c8dee2aaSAndroid Build Coastguard Worker &imageViewBox,
582*c8dee2aaSAndroid Build Coastguard Worker &areaToFillBrush),
583*c8dee2aaSAndroid Build Coastguard Worker "Could not create brush for side of clamp.");
584*c8dee2aaSAndroid Build Coastguard Worker HRM(areaToFillBrush->SetTileMode(XPS_TILE_MODE_FLIPXY),
585*c8dee2aaSAndroid Build Coastguard Worker "Could not set tile mode for side of clamp.");
586*c8dee2aaSAndroid Build Coastguard Worker HRM(areaToFillPath->SetFillBrushLocal(areaToFillBrush.get()),
587*c8dee2aaSAndroid Build Coastguard Worker "Could not set brush for side of clamp");
588*c8dee2aaSAndroid Build Coastguard Worker
589*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
590*c8dee2aaSAndroid Build Coastguard Worker }
591*c8dee2aaSAndroid Build Coastguard Worker
cornerOfClamp(const SkRect & areaToFill,const SkColor color,IXpsOMVisualCollection * visuals)592*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::cornerOfClamp(const SkRect& areaToFill,
593*c8dee2aaSAndroid Build Coastguard Worker const SkColor color,
594*c8dee2aaSAndroid Build Coastguard Worker IXpsOMVisualCollection* visuals) {
595*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometryFigure> areaToFillFigure;
596*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsRect(areaToFill, FALSE, TRUE, &areaToFillFigure));
597*c8dee2aaSAndroid Build Coastguard Worker
598*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMPath> areaToFillPath;
599*c8dee2aaSAndroid Build Coastguard Worker HR(this->createPath(areaToFillFigure.get(), visuals, &areaToFillPath));
600*c8dee2aaSAndroid Build Coastguard Worker
601*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMBrush> areaToFillBrush;
602*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsSolidColorBrush(color, 0xFF, &areaToFillBrush));
603*c8dee2aaSAndroid Build Coastguard Worker HRM(areaToFillPath->SetFillBrushLocal(areaToFillBrush.get()),
604*c8dee2aaSAndroid Build Coastguard Worker "Could not set brush for corner of clamp.");
605*c8dee2aaSAndroid Build Coastguard Worker
606*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
607*c8dee2aaSAndroid Build Coastguard Worker }
608*c8dee2aaSAndroid Build Coastguard Worker
609*c8dee2aaSAndroid Build Coastguard Worker static const XPS_TILE_MODE XTM_N = XPS_TILE_MODE_NONE;
610*c8dee2aaSAndroid Build Coastguard Worker static const XPS_TILE_MODE XTM_T = XPS_TILE_MODE_TILE;
611*c8dee2aaSAndroid Build Coastguard Worker static const XPS_TILE_MODE XTM_X = XPS_TILE_MODE_FLIPX;
612*c8dee2aaSAndroid Build Coastguard Worker static const XPS_TILE_MODE XTM_Y = XPS_TILE_MODE_FLIPY;
613*c8dee2aaSAndroid Build Coastguard Worker static const XPS_TILE_MODE XTM_XY = XPS_TILE_MODE_FLIPXY;
614*c8dee2aaSAndroid Build Coastguard Worker
615*c8dee2aaSAndroid Build Coastguard Worker //TODO(bungeman): In the future, should skia add None,
616*c8dee2aaSAndroid Build Coastguard Worker //handle None+Mirror and None+Repeat correctly.
617*c8dee2aaSAndroid Build Coastguard Worker //None is currently an internal hack so masks don't repeat (None+None only).
618*c8dee2aaSAndroid Build Coastguard Worker static XPS_TILE_MODE gSkToXpsTileMode[kSkTileModeCount+1]
619*c8dee2aaSAndroid Build Coastguard Worker [kSkTileModeCount+1] = {
620*c8dee2aaSAndroid Build Coastguard Worker //Clamp //Repeat //Mirror //None
621*c8dee2aaSAndroid Build Coastguard Worker /*Clamp */ {XTM_N, XTM_T, XTM_Y, XTM_N},
622*c8dee2aaSAndroid Build Coastguard Worker /*Repeat*/ {XTM_T, XTM_T, XTM_Y, XTM_N},
623*c8dee2aaSAndroid Build Coastguard Worker /*Mirror*/ {XTM_X, XTM_X, XTM_XY, XTM_X},
624*c8dee2aaSAndroid Build Coastguard Worker /*None */ {XTM_N, XTM_N, XTM_Y, XTM_N},
625*c8dee2aaSAndroid Build Coastguard Worker };
626*c8dee2aaSAndroid Build Coastguard Worker
SkToXpsTileMode(SkTileMode tmx,SkTileMode tmy)627*c8dee2aaSAndroid Build Coastguard Worker static XPS_TILE_MODE SkToXpsTileMode(SkTileMode tmx, SkTileMode tmy) {
628*c8dee2aaSAndroid Build Coastguard Worker return gSkToXpsTileMode[(unsigned)tmx][(unsigned)tmy];
629*c8dee2aaSAndroid Build Coastguard Worker }
630*c8dee2aaSAndroid Build Coastguard Worker
createXpsImageBrush(const SkPixmap & bitmap,const SkMatrix & localMatrix,const SkTileMode (& xy)[2],const SkAlpha alpha,IXpsOMTileBrush ** xpsBrush)631*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::createXpsImageBrush(
632*c8dee2aaSAndroid Build Coastguard Worker const SkPixmap& bitmap,
633*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& localMatrix,
634*c8dee2aaSAndroid Build Coastguard Worker const SkTileMode (&xy)[2],
635*c8dee2aaSAndroid Build Coastguard Worker const SkAlpha alpha,
636*c8dee2aaSAndroid Build Coastguard Worker IXpsOMTileBrush** xpsBrush) {
637*c8dee2aaSAndroid Build Coastguard Worker SkDynamicMemoryWStream write;
638*c8dee2aaSAndroid Build Coastguard Worker if (!SkPngEncoder::Encode(&write, bitmap, {})) {
639*c8dee2aaSAndroid Build Coastguard Worker HRM(E_FAIL, "Unable to encode bitmap as png.");
640*c8dee2aaSAndroid Build Coastguard Worker }
641*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IStream> read;
642*c8dee2aaSAndroid Build Coastguard Worker HRM(SkIStream::CreateFromSkStream(write.detachAsStream(), &read),
643*c8dee2aaSAndroid Build Coastguard Worker "Could not create stream from png data.");
644*c8dee2aaSAndroid Build Coastguard Worker
645*c8dee2aaSAndroid Build Coastguard Worker const size_t size =
646*c8dee2aaSAndroid Build Coastguard Worker std::size(L"/Documents/1/Resources/Images/" L_GUID_ID L".png");
647*c8dee2aaSAndroid Build Coastguard Worker wchar_t buffer[size];
648*c8dee2aaSAndroid Build Coastguard Worker wchar_t id[GUID_ID_LEN];
649*c8dee2aaSAndroid Build Coastguard Worker HR(this->createId(id, GUID_ID_LEN));
650*c8dee2aaSAndroid Build Coastguard Worker swprintf_s(buffer, size, L"/Documents/1/Resources/Images/%s.png", id);
651*c8dee2aaSAndroid Build Coastguard Worker
652*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IOpcPartUri> imagePartUri;
653*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreatePartUri(buffer, &imagePartUri),
654*c8dee2aaSAndroid Build Coastguard Worker "Could not create image part uri.");
655*c8dee2aaSAndroid Build Coastguard Worker
656*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMImageResource> imageResource;
657*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreateImageResource(
658*c8dee2aaSAndroid Build Coastguard Worker read.get(),
659*c8dee2aaSAndroid Build Coastguard Worker XPS_IMAGE_TYPE_PNG,
660*c8dee2aaSAndroid Build Coastguard Worker imagePartUri.get(),
661*c8dee2aaSAndroid Build Coastguard Worker &imageResource),
662*c8dee2aaSAndroid Build Coastguard Worker "Could not create image resource.");
663*c8dee2aaSAndroid Build Coastguard Worker
664*c8dee2aaSAndroid Build Coastguard Worker XPS_RECT bitmapRect = {
665*c8dee2aaSAndroid Build Coastguard Worker 0.0, 0.0,
666*c8dee2aaSAndroid Build Coastguard Worker static_cast<FLOAT>(bitmap.width()), static_cast<FLOAT>(bitmap.height())
667*c8dee2aaSAndroid Build Coastguard Worker };
668*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMImageBrush> xpsImageBrush;
669*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreateImageBrush(imageResource.get(),
670*c8dee2aaSAndroid Build Coastguard Worker &bitmapRect, &bitmapRect,
671*c8dee2aaSAndroid Build Coastguard Worker &xpsImageBrush),
672*c8dee2aaSAndroid Build Coastguard Worker "Could not create image brush.");
673*c8dee2aaSAndroid Build Coastguard Worker
674*c8dee2aaSAndroid Build Coastguard Worker if (SkTileMode::kClamp != xy[0] &&
675*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp != xy[1]) {
676*c8dee2aaSAndroid Build Coastguard Worker
677*c8dee2aaSAndroid Build Coastguard Worker HRM(xpsImageBrush->SetTileMode(SkToXpsTileMode(xy[0], xy[1])),
678*c8dee2aaSAndroid Build Coastguard Worker "Could not set image tile mode");
679*c8dee2aaSAndroid Build Coastguard Worker HRM(xpsImageBrush->SetOpacity(alpha / 255.0f),
680*c8dee2aaSAndroid Build Coastguard Worker "Could not set image opacity.");
681*c8dee2aaSAndroid Build Coastguard Worker HRM(xpsImageBrush->QueryInterface(xpsBrush), "QI failed.");
682*c8dee2aaSAndroid Build Coastguard Worker } else {
683*c8dee2aaSAndroid Build Coastguard Worker //TODO(bungeman): compute how big this really needs to be.
684*c8dee2aaSAndroid Build Coastguard Worker const SkScalar BIG = SkIntToScalar(1000); //SK_ScalarMax;
685*c8dee2aaSAndroid Build Coastguard Worker const FLOAT BIG_F = SkScalarToFLOAT(BIG);
686*c8dee2aaSAndroid Build Coastguard Worker const SkScalar bWidth = SkIntToScalar(bitmap.width());
687*c8dee2aaSAndroid Build Coastguard Worker const SkScalar bHeight = SkIntToScalar(bitmap.height());
688*c8dee2aaSAndroid Build Coastguard Worker
689*c8dee2aaSAndroid Build Coastguard Worker //create brush canvas
690*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMCanvas> brushCanvas;
691*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreateCanvas(&brushCanvas),
692*c8dee2aaSAndroid Build Coastguard Worker "Could not create image brush canvas.");
693*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMVisualCollection> brushVisuals;
694*c8dee2aaSAndroid Build Coastguard Worker HRM(brushCanvas->GetVisuals(&brushVisuals),
695*c8dee2aaSAndroid Build Coastguard Worker "Could not get image brush canvas visuals collection.");
696*c8dee2aaSAndroid Build Coastguard Worker
697*c8dee2aaSAndroid Build Coastguard Worker //create central figure
698*c8dee2aaSAndroid Build Coastguard Worker const SkRect bitmapPoints = SkRect::MakeLTRB(0, 0, bWidth, bHeight);
699*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometryFigure> centralFigure;
700*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsRect(bitmapPoints, FALSE, TRUE, ¢ralFigure));
701*c8dee2aaSAndroid Build Coastguard Worker
702*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMPath> centralPath;
703*c8dee2aaSAndroid Build Coastguard Worker HR(this->createPath(centralFigure.get(),
704*c8dee2aaSAndroid Build Coastguard Worker brushVisuals.get(),
705*c8dee2aaSAndroid Build Coastguard Worker ¢ralPath));
706*c8dee2aaSAndroid Build Coastguard Worker HRM(xpsImageBrush->SetTileMode(XPS_TILE_MODE_FLIPXY),
707*c8dee2aaSAndroid Build Coastguard Worker "Could not set tile mode for image brush central path.");
708*c8dee2aaSAndroid Build Coastguard Worker HRM(centralPath->SetFillBrushLocal(xpsImageBrush.get()),
709*c8dee2aaSAndroid Build Coastguard Worker "Could not set fill brush for image brush central path.");
710*c8dee2aaSAndroid Build Coastguard Worker
711*c8dee2aaSAndroid Build Coastguard Worker //add left/right
712*c8dee2aaSAndroid Build Coastguard Worker if (SkTileMode::kClamp == xy[0]) {
713*c8dee2aaSAndroid Build Coastguard Worker SkRect leftArea = SkRect::MakeLTRB(-BIG, 0, 0, bHeight);
714*c8dee2aaSAndroid Build Coastguard Worker XPS_RECT leftImageViewBox = {
715*c8dee2aaSAndroid Build Coastguard Worker 0.0, 0.0,
716*c8dee2aaSAndroid Build Coastguard Worker 1.0, static_cast<FLOAT>(bitmap.height()),
717*c8dee2aaSAndroid Build Coastguard Worker };
718*c8dee2aaSAndroid Build Coastguard Worker HR(this->sideOfClamp(leftArea, leftImageViewBox,
719*c8dee2aaSAndroid Build Coastguard Worker imageResource.get(),
720*c8dee2aaSAndroid Build Coastguard Worker brushVisuals.get()));
721*c8dee2aaSAndroid Build Coastguard Worker
722*c8dee2aaSAndroid Build Coastguard Worker SkRect rightArea = SkRect::MakeLTRB(bWidth, 0, BIG, bHeight);
723*c8dee2aaSAndroid Build Coastguard Worker XPS_RECT rightImageViewBox = {
724*c8dee2aaSAndroid Build Coastguard Worker bitmap.width() - 1.0f, 0.0f,
725*c8dee2aaSAndroid Build Coastguard Worker 1.0f, static_cast<FLOAT>(bitmap.height()),
726*c8dee2aaSAndroid Build Coastguard Worker };
727*c8dee2aaSAndroid Build Coastguard Worker HR(this->sideOfClamp(rightArea, rightImageViewBox,
728*c8dee2aaSAndroid Build Coastguard Worker imageResource.get(),
729*c8dee2aaSAndroid Build Coastguard Worker brushVisuals.get()));
730*c8dee2aaSAndroid Build Coastguard Worker }
731*c8dee2aaSAndroid Build Coastguard Worker
732*c8dee2aaSAndroid Build Coastguard Worker //add top/bottom
733*c8dee2aaSAndroid Build Coastguard Worker if (SkTileMode::kClamp == xy[1]) {
734*c8dee2aaSAndroid Build Coastguard Worker SkRect topArea = SkRect::MakeLTRB(0, -BIG, bWidth, 0);
735*c8dee2aaSAndroid Build Coastguard Worker XPS_RECT topImageViewBox = {
736*c8dee2aaSAndroid Build Coastguard Worker 0.0, 0.0,
737*c8dee2aaSAndroid Build Coastguard Worker static_cast<FLOAT>(bitmap.width()), 1.0,
738*c8dee2aaSAndroid Build Coastguard Worker };
739*c8dee2aaSAndroid Build Coastguard Worker HR(this->sideOfClamp(topArea, topImageViewBox,
740*c8dee2aaSAndroid Build Coastguard Worker imageResource.get(),
741*c8dee2aaSAndroid Build Coastguard Worker brushVisuals.get()));
742*c8dee2aaSAndroid Build Coastguard Worker
743*c8dee2aaSAndroid Build Coastguard Worker SkRect bottomArea = SkRect::MakeLTRB(0, bHeight, bWidth, BIG);
744*c8dee2aaSAndroid Build Coastguard Worker XPS_RECT bottomImageViewBox = {
745*c8dee2aaSAndroid Build Coastguard Worker 0.0f, bitmap.height() - 1.0f,
746*c8dee2aaSAndroid Build Coastguard Worker static_cast<FLOAT>(bitmap.width()), 1.0f,
747*c8dee2aaSAndroid Build Coastguard Worker };
748*c8dee2aaSAndroid Build Coastguard Worker HR(this->sideOfClamp(bottomArea, bottomImageViewBox,
749*c8dee2aaSAndroid Build Coastguard Worker imageResource.get(),
750*c8dee2aaSAndroid Build Coastguard Worker brushVisuals.get()));
751*c8dee2aaSAndroid Build Coastguard Worker }
752*c8dee2aaSAndroid Build Coastguard Worker
753*c8dee2aaSAndroid Build Coastguard Worker //add tl, tr, bl, br
754*c8dee2aaSAndroid Build Coastguard Worker if (SkTileMode::kClamp == xy[0] &&
755*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp == xy[1]) {
756*c8dee2aaSAndroid Build Coastguard Worker
757*c8dee2aaSAndroid Build Coastguard Worker const SkColor tlColor = bitmap.getColor(0,0);
758*c8dee2aaSAndroid Build Coastguard Worker const SkRect tlArea = SkRect::MakeLTRB(-BIG, -BIG, 0, 0);
759*c8dee2aaSAndroid Build Coastguard Worker HR(this->cornerOfClamp(tlArea, tlColor, brushVisuals.get()));
760*c8dee2aaSAndroid Build Coastguard Worker
761*c8dee2aaSAndroid Build Coastguard Worker const SkColor trColor = bitmap.getColor(bitmap.width()-1,0);
762*c8dee2aaSAndroid Build Coastguard Worker const SkRect trArea = SkRect::MakeLTRB(bWidth, -BIG, BIG, 0);
763*c8dee2aaSAndroid Build Coastguard Worker HR(this->cornerOfClamp(trArea, trColor, brushVisuals.get()));
764*c8dee2aaSAndroid Build Coastguard Worker
765*c8dee2aaSAndroid Build Coastguard Worker const SkColor brColor = bitmap.getColor(bitmap.width()-1,
766*c8dee2aaSAndroid Build Coastguard Worker bitmap.height()-1);
767*c8dee2aaSAndroid Build Coastguard Worker const SkRect brArea = SkRect::MakeLTRB(bWidth, bHeight, BIG, BIG);
768*c8dee2aaSAndroid Build Coastguard Worker HR(this->cornerOfClamp(brArea, brColor, brushVisuals.get()));
769*c8dee2aaSAndroid Build Coastguard Worker
770*c8dee2aaSAndroid Build Coastguard Worker const SkColor blColor = bitmap.getColor(0,bitmap.height()-1);
771*c8dee2aaSAndroid Build Coastguard Worker const SkRect blArea = SkRect::MakeLTRB(-BIG, bHeight, 0, BIG);
772*c8dee2aaSAndroid Build Coastguard Worker HR(this->cornerOfClamp(blArea, blColor, brushVisuals.get()));
773*c8dee2aaSAndroid Build Coastguard Worker }
774*c8dee2aaSAndroid Build Coastguard Worker
775*c8dee2aaSAndroid Build Coastguard Worker //create visual brush from canvas
776*c8dee2aaSAndroid Build Coastguard Worker XPS_RECT bound = {};
777*c8dee2aaSAndroid Build Coastguard Worker if (SkTileMode::kClamp == xy[0] &&
778*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp == xy[1]) {
779*c8dee2aaSAndroid Build Coastguard Worker
780*c8dee2aaSAndroid Build Coastguard Worker bound.x = BIG_F / -2;
781*c8dee2aaSAndroid Build Coastguard Worker bound.y = BIG_F / -2;
782*c8dee2aaSAndroid Build Coastguard Worker bound.width = BIG_F;
783*c8dee2aaSAndroid Build Coastguard Worker bound.height = BIG_F;
784*c8dee2aaSAndroid Build Coastguard Worker } else if (SkTileMode::kClamp == xy[0]) {
785*c8dee2aaSAndroid Build Coastguard Worker bound.x = BIG_F / -2;
786*c8dee2aaSAndroid Build Coastguard Worker bound.y = 0.0f;
787*c8dee2aaSAndroid Build Coastguard Worker bound.width = BIG_F;
788*c8dee2aaSAndroid Build Coastguard Worker bound.height = static_cast<FLOAT>(bitmap.height());
789*c8dee2aaSAndroid Build Coastguard Worker } else if (SkTileMode::kClamp == xy[1]) {
790*c8dee2aaSAndroid Build Coastguard Worker bound.x = 0;
791*c8dee2aaSAndroid Build Coastguard Worker bound.y = BIG_F / -2;
792*c8dee2aaSAndroid Build Coastguard Worker bound.width = static_cast<FLOAT>(bitmap.width());
793*c8dee2aaSAndroid Build Coastguard Worker bound.height = BIG_F;
794*c8dee2aaSAndroid Build Coastguard Worker }
795*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMVisualBrush> clampBrush;
796*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreateVisualBrush(&bound, &bound, &clampBrush),
797*c8dee2aaSAndroid Build Coastguard Worker "Could not create visual brush for image brush.");
798*c8dee2aaSAndroid Build Coastguard Worker HRM(clampBrush->SetVisualLocal(brushCanvas.get()),
799*c8dee2aaSAndroid Build Coastguard Worker "Could not set canvas on visual brush for image brush.");
800*c8dee2aaSAndroid Build Coastguard Worker HRM(clampBrush->SetTileMode(SkToXpsTileMode(xy[0], xy[1])),
801*c8dee2aaSAndroid Build Coastguard Worker "Could not set tile mode on visual brush for image brush.");
802*c8dee2aaSAndroid Build Coastguard Worker HRM(clampBrush->SetOpacity(alpha / 255.0f),
803*c8dee2aaSAndroid Build Coastguard Worker "Could not set opacity on visual brush for image brush.");
804*c8dee2aaSAndroid Build Coastguard Worker
805*c8dee2aaSAndroid Build Coastguard Worker HRM(clampBrush->QueryInterface(xpsBrush), "QI failed.");
806*c8dee2aaSAndroid Build Coastguard Worker }
807*c8dee2aaSAndroid Build Coastguard Worker
808*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMMatrixTransform> xpsMatrixToUse;
809*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsTransform(localMatrix, &xpsMatrixToUse));
810*c8dee2aaSAndroid Build Coastguard Worker if (xpsMatrixToUse.get()) {
811*c8dee2aaSAndroid Build Coastguard Worker HRM((*xpsBrush)->SetTransformLocal(xpsMatrixToUse.get()),
812*c8dee2aaSAndroid Build Coastguard Worker "Could not set transform for image brush.");
813*c8dee2aaSAndroid Build Coastguard Worker } else {
814*c8dee2aaSAndroid Build Coastguard Worker //TODO(bungeman): perspective bitmaps in general.
815*c8dee2aaSAndroid Build Coastguard Worker }
816*c8dee2aaSAndroid Build Coastguard Worker
817*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
818*c8dee2aaSAndroid Build Coastguard Worker }
819*c8dee2aaSAndroid Build Coastguard Worker
createXpsGradientStop(const SkColor skColor,const SkScalar offset,IXpsOMGradientStop ** xpsGradStop)820*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::createXpsGradientStop(const SkColor skColor,
821*c8dee2aaSAndroid Build Coastguard Worker const SkScalar offset,
822*c8dee2aaSAndroid Build Coastguard Worker IXpsOMGradientStop** xpsGradStop) {
823*c8dee2aaSAndroid Build Coastguard Worker XPS_COLOR gradStopXpsColor = xps_color(skColor);
824*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreateGradientStop(&gradStopXpsColor,
825*c8dee2aaSAndroid Build Coastguard Worker nullptr,
826*c8dee2aaSAndroid Build Coastguard Worker SkScalarToFLOAT(offset),
827*c8dee2aaSAndroid Build Coastguard Worker xpsGradStop),
828*c8dee2aaSAndroid Build Coastguard Worker "Could not create gradient stop.");
829*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
830*c8dee2aaSAndroid Build Coastguard Worker }
831*c8dee2aaSAndroid Build Coastguard Worker
createXpsLinearGradient(SkShaderBase::GradientInfo info,const SkAlpha alpha,const SkMatrix & localMatrix,IXpsOMMatrixTransform * xpsMatrix,IXpsOMBrush ** xpsBrush)832*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::createXpsLinearGradient(SkShaderBase::GradientInfo info,
833*c8dee2aaSAndroid Build Coastguard Worker const SkAlpha alpha,
834*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& localMatrix,
835*c8dee2aaSAndroid Build Coastguard Worker IXpsOMMatrixTransform* xpsMatrix,
836*c8dee2aaSAndroid Build Coastguard Worker IXpsOMBrush** xpsBrush) {
837*c8dee2aaSAndroid Build Coastguard Worker XPS_POINT startPoint;
838*c8dee2aaSAndroid Build Coastguard Worker XPS_POINT endPoint;
839*c8dee2aaSAndroid Build Coastguard Worker if (xpsMatrix) {
840*c8dee2aaSAndroid Build Coastguard Worker startPoint = xps_point(info.fPoint[0]);
841*c8dee2aaSAndroid Build Coastguard Worker endPoint = xps_point(info.fPoint[1]);
842*c8dee2aaSAndroid Build Coastguard Worker } else {
843*c8dee2aaSAndroid Build Coastguard Worker transform_offsets(info.fColorOffsets, info.fColorCount,
844*c8dee2aaSAndroid Build Coastguard Worker info.fPoint[0], info.fPoint[1],
845*c8dee2aaSAndroid Build Coastguard Worker localMatrix);
846*c8dee2aaSAndroid Build Coastguard Worker startPoint = xps_point(info.fPoint[0], localMatrix);
847*c8dee2aaSAndroid Build Coastguard Worker endPoint = xps_point(info.fPoint[1], localMatrix);
848*c8dee2aaSAndroid Build Coastguard Worker }
849*c8dee2aaSAndroid Build Coastguard Worker
850*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGradientStop> gradStop0;
851*c8dee2aaSAndroid Build Coastguard Worker HR(createXpsGradientStop(info.fColors[0],
852*c8dee2aaSAndroid Build Coastguard Worker info.fColorOffsets[0],
853*c8dee2aaSAndroid Build Coastguard Worker &gradStop0));
854*c8dee2aaSAndroid Build Coastguard Worker
855*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGradientStop> gradStop1;
856*c8dee2aaSAndroid Build Coastguard Worker HR(createXpsGradientStop(info.fColors[1],
857*c8dee2aaSAndroid Build Coastguard Worker info.fColorOffsets[1],
858*c8dee2aaSAndroid Build Coastguard Worker &gradStop1));
859*c8dee2aaSAndroid Build Coastguard Worker
860*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMLinearGradientBrush> gradientBrush;
861*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreateLinearGradientBrush(gradStop0.get(),
862*c8dee2aaSAndroid Build Coastguard Worker gradStop1.get(),
863*c8dee2aaSAndroid Build Coastguard Worker &startPoint,
864*c8dee2aaSAndroid Build Coastguard Worker &endPoint,
865*c8dee2aaSAndroid Build Coastguard Worker &gradientBrush),
866*c8dee2aaSAndroid Build Coastguard Worker "Could not create linear gradient brush.");
867*c8dee2aaSAndroid Build Coastguard Worker if (xpsMatrix) {
868*c8dee2aaSAndroid Build Coastguard Worker HRM(gradientBrush->SetTransformLocal(xpsMatrix),
869*c8dee2aaSAndroid Build Coastguard Worker "Could not set transform on linear gradient brush.");
870*c8dee2aaSAndroid Build Coastguard Worker }
871*c8dee2aaSAndroid Build Coastguard Worker
872*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGradientStopCollection> gradStopCollection;
873*c8dee2aaSAndroid Build Coastguard Worker HRM(gradientBrush->GetGradientStops(&gradStopCollection),
874*c8dee2aaSAndroid Build Coastguard Worker "Could not get linear gradient stop collection.");
875*c8dee2aaSAndroid Build Coastguard Worker for (int i = 2; i < info.fColorCount; ++i) {
876*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGradientStop> gradStop;
877*c8dee2aaSAndroid Build Coastguard Worker HR(createXpsGradientStop(info.fColors[i],
878*c8dee2aaSAndroid Build Coastguard Worker info.fColorOffsets[i],
879*c8dee2aaSAndroid Build Coastguard Worker &gradStop));
880*c8dee2aaSAndroid Build Coastguard Worker HRM(gradStopCollection->Append(gradStop.get()),
881*c8dee2aaSAndroid Build Coastguard Worker "Could not add linear gradient stop.");
882*c8dee2aaSAndroid Build Coastguard Worker }
883*c8dee2aaSAndroid Build Coastguard Worker
884*c8dee2aaSAndroid Build Coastguard Worker HRM(gradientBrush->SetSpreadMethod(xps_spread_method((SkTileMode)info.fTileMode)),
885*c8dee2aaSAndroid Build Coastguard Worker "Could not set spread method of linear gradient.");
886*c8dee2aaSAndroid Build Coastguard Worker
887*c8dee2aaSAndroid Build Coastguard Worker HRM(gradientBrush->SetOpacity(alpha / 255.0f),
888*c8dee2aaSAndroid Build Coastguard Worker "Could not set opacity of linear gradient brush.");
889*c8dee2aaSAndroid Build Coastguard Worker HRM(gradientBrush->QueryInterface<IXpsOMBrush>(xpsBrush), "QI failed");
890*c8dee2aaSAndroid Build Coastguard Worker
891*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
892*c8dee2aaSAndroid Build Coastguard Worker }
893*c8dee2aaSAndroid Build Coastguard Worker
createXpsRadialGradient(SkShaderBase::GradientInfo info,const SkAlpha alpha,const SkMatrix & localMatrix,IXpsOMMatrixTransform * xpsMatrix,IXpsOMBrush ** xpsBrush)894*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::createXpsRadialGradient(SkShaderBase::GradientInfo info,
895*c8dee2aaSAndroid Build Coastguard Worker const SkAlpha alpha,
896*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& localMatrix,
897*c8dee2aaSAndroid Build Coastguard Worker IXpsOMMatrixTransform* xpsMatrix,
898*c8dee2aaSAndroid Build Coastguard Worker IXpsOMBrush** xpsBrush) {
899*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGradientStop> gradStop0;
900*c8dee2aaSAndroid Build Coastguard Worker HR(createXpsGradientStop(info.fColors[0],
901*c8dee2aaSAndroid Build Coastguard Worker info.fColorOffsets[0],
902*c8dee2aaSAndroid Build Coastguard Worker &gradStop0));
903*c8dee2aaSAndroid Build Coastguard Worker
904*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGradientStop> gradStop1;
905*c8dee2aaSAndroid Build Coastguard Worker HR(createXpsGradientStop(info.fColors[1],
906*c8dee2aaSAndroid Build Coastguard Worker info.fColorOffsets[1],
907*c8dee2aaSAndroid Build Coastguard Worker &gradStop1));
908*c8dee2aaSAndroid Build Coastguard Worker
909*c8dee2aaSAndroid Build Coastguard Worker //TODO: figure out how to fake better if not affine
910*c8dee2aaSAndroid Build Coastguard Worker XPS_POINT centerPoint;
911*c8dee2aaSAndroid Build Coastguard Worker XPS_POINT gradientOrigin;
912*c8dee2aaSAndroid Build Coastguard Worker XPS_SIZE radiiSizes;
913*c8dee2aaSAndroid Build Coastguard Worker if (xpsMatrix) {
914*c8dee2aaSAndroid Build Coastguard Worker centerPoint = xps_point(info.fPoint[0]);
915*c8dee2aaSAndroid Build Coastguard Worker gradientOrigin = xps_point(info.fPoint[0]);
916*c8dee2aaSAndroid Build Coastguard Worker radiiSizes.width = SkScalarToFLOAT(info.fRadius[0]);
917*c8dee2aaSAndroid Build Coastguard Worker radiiSizes.height = SkScalarToFLOAT(info.fRadius[0]);
918*c8dee2aaSAndroid Build Coastguard Worker } else {
919*c8dee2aaSAndroid Build Coastguard Worker centerPoint = xps_point(info.fPoint[0], localMatrix);
920*c8dee2aaSAndroid Build Coastguard Worker gradientOrigin = xps_point(info.fPoint[0], localMatrix);
921*c8dee2aaSAndroid Build Coastguard Worker
922*c8dee2aaSAndroid Build Coastguard Worker SkScalar radius = info.fRadius[0];
923*c8dee2aaSAndroid Build Coastguard Worker SkVector vec[2];
924*c8dee2aaSAndroid Build Coastguard Worker
925*c8dee2aaSAndroid Build Coastguard Worker vec[0].set(radius, 0);
926*c8dee2aaSAndroid Build Coastguard Worker vec[1].set(0, radius);
927*c8dee2aaSAndroid Build Coastguard Worker localMatrix.mapVectors(vec, 2);
928*c8dee2aaSAndroid Build Coastguard Worker
929*c8dee2aaSAndroid Build Coastguard Worker SkScalar d0 = vec[0].length();
930*c8dee2aaSAndroid Build Coastguard Worker SkScalar d1 = vec[1].length();
931*c8dee2aaSAndroid Build Coastguard Worker
932*c8dee2aaSAndroid Build Coastguard Worker radiiSizes.width = SkScalarToFLOAT(d0);
933*c8dee2aaSAndroid Build Coastguard Worker radiiSizes.height = SkScalarToFLOAT(d1);
934*c8dee2aaSAndroid Build Coastguard Worker }
935*c8dee2aaSAndroid Build Coastguard Worker
936*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMRadialGradientBrush> gradientBrush;
937*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreateRadialGradientBrush(gradStop0.get(),
938*c8dee2aaSAndroid Build Coastguard Worker gradStop1.get(),
939*c8dee2aaSAndroid Build Coastguard Worker ¢erPoint,
940*c8dee2aaSAndroid Build Coastguard Worker &gradientOrigin,
941*c8dee2aaSAndroid Build Coastguard Worker &radiiSizes,
942*c8dee2aaSAndroid Build Coastguard Worker &gradientBrush),
943*c8dee2aaSAndroid Build Coastguard Worker "Could not create radial gradient brush.");
944*c8dee2aaSAndroid Build Coastguard Worker if (xpsMatrix) {
945*c8dee2aaSAndroid Build Coastguard Worker HRM(gradientBrush->SetTransformLocal(xpsMatrix),
946*c8dee2aaSAndroid Build Coastguard Worker "Could not set transform on radial gradient brush.");
947*c8dee2aaSAndroid Build Coastguard Worker }
948*c8dee2aaSAndroid Build Coastguard Worker
949*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGradientStopCollection> gradStopCollection;
950*c8dee2aaSAndroid Build Coastguard Worker HRM(gradientBrush->GetGradientStops(&gradStopCollection),
951*c8dee2aaSAndroid Build Coastguard Worker "Could not get radial gradient stop collection.");
952*c8dee2aaSAndroid Build Coastguard Worker for (int i = 2; i < info.fColorCount; ++i) {
953*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGradientStop> gradStop;
954*c8dee2aaSAndroid Build Coastguard Worker HR(createXpsGradientStop(info.fColors[i],
955*c8dee2aaSAndroid Build Coastguard Worker info.fColorOffsets[i],
956*c8dee2aaSAndroid Build Coastguard Worker &gradStop));
957*c8dee2aaSAndroid Build Coastguard Worker HRM(gradStopCollection->Append(gradStop.get()),
958*c8dee2aaSAndroid Build Coastguard Worker "Could not add radial gradient stop.");
959*c8dee2aaSAndroid Build Coastguard Worker }
960*c8dee2aaSAndroid Build Coastguard Worker
961*c8dee2aaSAndroid Build Coastguard Worker HRM(gradientBrush->SetSpreadMethod(xps_spread_method((SkTileMode)info.fTileMode)),
962*c8dee2aaSAndroid Build Coastguard Worker "Could not set spread method of radial gradient.");
963*c8dee2aaSAndroid Build Coastguard Worker
964*c8dee2aaSAndroid Build Coastguard Worker HRM(gradientBrush->SetOpacity(alpha / 255.0f),
965*c8dee2aaSAndroid Build Coastguard Worker "Could not set opacity of radial gradient brush.");
966*c8dee2aaSAndroid Build Coastguard Worker HRM(gradientBrush->QueryInterface<IXpsOMBrush>(xpsBrush), "QI failed.");
967*c8dee2aaSAndroid Build Coastguard Worker
968*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
969*c8dee2aaSAndroid Build Coastguard Worker }
970*c8dee2aaSAndroid Build Coastguard Worker
createXpsBrush(const SkPaint & skPaint,IXpsOMBrush ** brush,const SkMatrix * parentTransform)971*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::createXpsBrush(const SkPaint& skPaint,
972*c8dee2aaSAndroid Build Coastguard Worker IXpsOMBrush** brush,
973*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix* parentTransform) {
974*c8dee2aaSAndroid Build Coastguard Worker const SkShader *shader = skPaint.getShader();
975*c8dee2aaSAndroid Build Coastguard Worker if (nullptr == shader) {
976*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsSolidColorBrush(skPaint.getColor(), 0xFF, brush));
977*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
978*c8dee2aaSAndroid Build Coastguard Worker }
979*c8dee2aaSAndroid Build Coastguard Worker
980*c8dee2aaSAndroid Build Coastguard Worker //Gradient shaders.
981*c8dee2aaSAndroid Build Coastguard Worker auto shaderBase = as_SB(shader);
982*c8dee2aaSAndroid Build Coastguard Worker
983*c8dee2aaSAndroid Build Coastguard Worker if (shaderBase->type() == SkShaderBase::ShaderType::kColor) {
984*c8dee2aaSAndroid Build Coastguard Worker auto colorShader = static_cast<const SkColorShader*>(shader);
985*c8dee2aaSAndroid Build Coastguard Worker SkAlpha alpha = skPaint.getAlpha();
986*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsSolidColorBrush(colorShader->color(), alpha, brush));
987*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
988*c8dee2aaSAndroid Build Coastguard Worker } else if (shaderBase->type() == SkShaderBase::ShaderType::kGradientBase) {
989*c8dee2aaSAndroid Build Coastguard Worker SkShaderBase::GradientInfo info;
990*c8dee2aaSAndroid Build Coastguard Worker SkShaderBase::GradientType gradientType = shaderBase->asGradient(&info);
991*c8dee2aaSAndroid Build Coastguard Worker if (info.fColorCount == 0) {
992*c8dee2aaSAndroid Build Coastguard Worker const SkColor color = skPaint.getColor();
993*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsSolidColorBrush(color, 0xFF, brush));
994*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
995*c8dee2aaSAndroid Build Coastguard Worker }
996*c8dee2aaSAndroid Build Coastguard Worker
997*c8dee2aaSAndroid Build Coastguard Worker SkMatrix localMatrix;
998*c8dee2aaSAndroid Build Coastguard Worker AutoTArray<SkColor> colors(info.fColorCount);
999*c8dee2aaSAndroid Build Coastguard Worker AutoTArray<SkScalar> colorOffsets(info.fColorCount);
1000*c8dee2aaSAndroid Build Coastguard Worker info.fColors = colors.get();
1001*c8dee2aaSAndroid Build Coastguard Worker info.fColorOffsets = colorOffsets.get();
1002*c8dee2aaSAndroid Build Coastguard Worker shaderBase->asGradient(&info, &localMatrix);
1003*c8dee2aaSAndroid Build Coastguard Worker
1004*c8dee2aaSAndroid Build Coastguard Worker if (1 == info.fColorCount) {
1005*c8dee2aaSAndroid Build Coastguard Worker SkColor color = info.fColors[0];
1006*c8dee2aaSAndroid Build Coastguard Worker SkAlpha alpha = skPaint.getAlpha();
1007*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsSolidColorBrush(color, alpha, brush));
1008*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
1009*c8dee2aaSAndroid Build Coastguard Worker }
1010*c8dee2aaSAndroid Build Coastguard Worker
1011*c8dee2aaSAndroid Build Coastguard Worker if (parentTransform) {
1012*c8dee2aaSAndroid Build Coastguard Worker localMatrix.preConcat(*parentTransform);
1013*c8dee2aaSAndroid Build Coastguard Worker }
1014*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMMatrixTransform> xpsMatrixToUse;
1015*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsTransform(localMatrix, &xpsMatrixToUse));
1016*c8dee2aaSAndroid Build Coastguard Worker
1017*c8dee2aaSAndroid Build Coastguard Worker if (gradientType == SkShaderBase::GradientType::kLinear) {
1018*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsLinearGradient(info,
1019*c8dee2aaSAndroid Build Coastguard Worker skPaint.getAlpha(),
1020*c8dee2aaSAndroid Build Coastguard Worker localMatrix,
1021*c8dee2aaSAndroid Build Coastguard Worker xpsMatrixToUse.get(),
1022*c8dee2aaSAndroid Build Coastguard Worker brush));
1023*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
1024*c8dee2aaSAndroid Build Coastguard Worker }
1025*c8dee2aaSAndroid Build Coastguard Worker
1026*c8dee2aaSAndroid Build Coastguard Worker if (gradientType == SkShaderBase::GradientType::kRadial) {
1027*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsRadialGradient(info,
1028*c8dee2aaSAndroid Build Coastguard Worker skPaint.getAlpha(),
1029*c8dee2aaSAndroid Build Coastguard Worker localMatrix,
1030*c8dee2aaSAndroid Build Coastguard Worker xpsMatrixToUse.get(),
1031*c8dee2aaSAndroid Build Coastguard Worker brush));
1032*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
1033*c8dee2aaSAndroid Build Coastguard Worker }
1034*c8dee2aaSAndroid Build Coastguard Worker
1035*c8dee2aaSAndroid Build Coastguard Worker if (gradientType == SkShaderBase::GradientType::kConical) {
1036*c8dee2aaSAndroid Build Coastguard Worker //simple if affine and one is 0, otherwise will have to fake
1037*c8dee2aaSAndroid Build Coastguard Worker }
1038*c8dee2aaSAndroid Build Coastguard Worker
1039*c8dee2aaSAndroid Build Coastguard Worker if (gradientType == SkShaderBase::GradientType::kSweep) {
1040*c8dee2aaSAndroid Build Coastguard Worker //have to fake
1041*c8dee2aaSAndroid Build Coastguard Worker }
1042*c8dee2aaSAndroid Build Coastguard Worker }
1043*c8dee2aaSAndroid Build Coastguard Worker
1044*c8dee2aaSAndroid Build Coastguard Worker SkBitmap outTexture;
1045*c8dee2aaSAndroid Build Coastguard Worker SkMatrix outMatrix;
1046*c8dee2aaSAndroid Build Coastguard Worker SkTileMode xy[2];
1047*c8dee2aaSAndroid Build Coastguard Worker SkImage* image = shader->isAImage(&outMatrix, xy);
1048*c8dee2aaSAndroid Build Coastguard Worker if (image->asLegacyBitmap(&outTexture)) {
1049*c8dee2aaSAndroid Build Coastguard Worker if (parentTransform) {
1050*c8dee2aaSAndroid Build Coastguard Worker outMatrix.postConcat(*parentTransform);
1051*c8dee2aaSAndroid Build Coastguard Worker }
1052*c8dee2aaSAndroid Build Coastguard Worker
1053*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMTileBrush> tileBrush;
1054*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsImageBrush(outTexture.pixmap(), outMatrix, xy, skPaint.getAlpha(),
1055*c8dee2aaSAndroid Build Coastguard Worker &tileBrush));
1056*c8dee2aaSAndroid Build Coastguard Worker
1057*c8dee2aaSAndroid Build Coastguard Worker HRM(tileBrush->QueryInterface<IXpsOMBrush>(brush), "QI failed.");
1058*c8dee2aaSAndroid Build Coastguard Worker } else {
1059*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsSolidColorBrush(skPaint.getColor(), 0xFF, brush));
1060*c8dee2aaSAndroid Build Coastguard Worker }
1061*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
1062*c8dee2aaSAndroid Build Coastguard Worker }
1063*c8dee2aaSAndroid Build Coastguard Worker
rect_must_be_pathed(const SkPaint & paint,const SkMatrix & matrix)1064*c8dee2aaSAndroid Build Coastguard Worker static bool rect_must_be_pathed(const SkPaint& paint, const SkMatrix& matrix) {
1065*c8dee2aaSAndroid Build Coastguard Worker const bool zeroWidth = (0 == paint.getStrokeWidth());
1066*c8dee2aaSAndroid Build Coastguard Worker const bool stroke = (SkPaint::kFill_Style != paint.getStyle());
1067*c8dee2aaSAndroid Build Coastguard Worker
1068*c8dee2aaSAndroid Build Coastguard Worker return paint.getPathEffect() ||
1069*c8dee2aaSAndroid Build Coastguard Worker paint.getMaskFilter() ||
1070*c8dee2aaSAndroid Build Coastguard Worker (stroke && (
1071*c8dee2aaSAndroid Build Coastguard Worker (matrix.hasPerspective() && !zeroWidth) ||
1072*c8dee2aaSAndroid Build Coastguard Worker SkPaint::kMiter_Join != paint.getStrokeJoin() ||
1073*c8dee2aaSAndroid Build Coastguard Worker (SkPaint::kMiter_Join == paint.getStrokeJoin() &&
1074*c8dee2aaSAndroid Build Coastguard Worker paint.getStrokeMiter() < SK_ScalarSqrt2)
1075*c8dee2aaSAndroid Build Coastguard Worker ))
1076*c8dee2aaSAndroid Build Coastguard Worker ;
1077*c8dee2aaSAndroid Build Coastguard Worker }
1078*c8dee2aaSAndroid Build Coastguard Worker
createXpsRect(const SkRect & rect,BOOL stroke,BOOL fill,IXpsOMGeometryFigure ** xpsRect)1079*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::createXpsRect(const SkRect& rect, BOOL stroke, BOOL fill,
1080*c8dee2aaSAndroid Build Coastguard Worker IXpsOMGeometryFigure** xpsRect) {
1081*c8dee2aaSAndroid Build Coastguard Worker const SkPoint points[4] = {
1082*c8dee2aaSAndroid Build Coastguard Worker { rect.fLeft, rect.fTop },
1083*c8dee2aaSAndroid Build Coastguard Worker { rect.fRight, rect.fTop },
1084*c8dee2aaSAndroid Build Coastguard Worker { rect.fRight, rect.fBottom },
1085*c8dee2aaSAndroid Build Coastguard Worker { rect.fLeft, rect.fBottom },
1086*c8dee2aaSAndroid Build Coastguard Worker };
1087*c8dee2aaSAndroid Build Coastguard Worker return this->createXpsQuad(points, stroke, fill, xpsRect);
1088*c8dee2aaSAndroid Build Coastguard Worker }
createXpsQuad(const SkPoint (& points)[4],BOOL stroke,BOOL fill,IXpsOMGeometryFigure ** xpsQuad)1089*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::createXpsQuad(const SkPoint (&points)[4],
1090*c8dee2aaSAndroid Build Coastguard Worker BOOL stroke, BOOL fill,
1091*c8dee2aaSAndroid Build Coastguard Worker IXpsOMGeometryFigure** xpsQuad) {
1092*c8dee2aaSAndroid Build Coastguard Worker // Define the start point.
1093*c8dee2aaSAndroid Build Coastguard Worker XPS_POINT startPoint = xps_point(points[0]);
1094*c8dee2aaSAndroid Build Coastguard Worker
1095*c8dee2aaSAndroid Build Coastguard Worker // Create the figure.
1096*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreateGeometryFigure(&startPoint, xpsQuad),
1097*c8dee2aaSAndroid Build Coastguard Worker "Could not create quad geometry figure.");
1098*c8dee2aaSAndroid Build Coastguard Worker
1099*c8dee2aaSAndroid Build Coastguard Worker // Define the type of each segment.
1100*c8dee2aaSAndroid Build Coastguard Worker XPS_SEGMENT_TYPE segmentTypes[3] = {
1101*c8dee2aaSAndroid Build Coastguard Worker XPS_SEGMENT_TYPE_LINE,
1102*c8dee2aaSAndroid Build Coastguard Worker XPS_SEGMENT_TYPE_LINE,
1103*c8dee2aaSAndroid Build Coastguard Worker XPS_SEGMENT_TYPE_LINE,
1104*c8dee2aaSAndroid Build Coastguard Worker };
1105*c8dee2aaSAndroid Build Coastguard Worker
1106*c8dee2aaSAndroid Build Coastguard Worker // Define the x and y coordinates of each corner of the figure.
1107*c8dee2aaSAndroid Build Coastguard Worker FLOAT segmentData[6] = {
1108*c8dee2aaSAndroid Build Coastguard Worker SkScalarToFLOAT(points[1].fX), SkScalarToFLOAT(points[1].fY),
1109*c8dee2aaSAndroid Build Coastguard Worker SkScalarToFLOAT(points[2].fX), SkScalarToFLOAT(points[2].fY),
1110*c8dee2aaSAndroid Build Coastguard Worker SkScalarToFLOAT(points[3].fX), SkScalarToFLOAT(points[3].fY),
1111*c8dee2aaSAndroid Build Coastguard Worker };
1112*c8dee2aaSAndroid Build Coastguard Worker
1113*c8dee2aaSAndroid Build Coastguard Worker // Describe if the segments are stroked.
1114*c8dee2aaSAndroid Build Coastguard Worker BOOL segmentStrokes[3] = {
1115*c8dee2aaSAndroid Build Coastguard Worker stroke, stroke, stroke,
1116*c8dee2aaSAndroid Build Coastguard Worker };
1117*c8dee2aaSAndroid Build Coastguard Worker
1118*c8dee2aaSAndroid Build Coastguard Worker // Add the segment data to the figure.
1119*c8dee2aaSAndroid Build Coastguard Worker HRM((*xpsQuad)->SetSegments(
1120*c8dee2aaSAndroid Build Coastguard Worker 3, 6,
1121*c8dee2aaSAndroid Build Coastguard Worker segmentTypes , segmentData, segmentStrokes),
1122*c8dee2aaSAndroid Build Coastguard Worker "Could not add segment data to quad.");
1123*c8dee2aaSAndroid Build Coastguard Worker
1124*c8dee2aaSAndroid Build Coastguard Worker // Set the closed and filled properties of the figure.
1125*c8dee2aaSAndroid Build Coastguard Worker HRM((*xpsQuad)->SetIsClosed(stroke), "Could not set quad close.");
1126*c8dee2aaSAndroid Build Coastguard Worker HRM((*xpsQuad)->SetIsFilled(fill), "Could not set quad fill.");
1127*c8dee2aaSAndroid Build Coastguard Worker
1128*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
1129*c8dee2aaSAndroid Build Coastguard Worker }
1130*c8dee2aaSAndroid Build Coastguard Worker
drawPoints(SkCanvas::PointMode mode,size_t count,const SkPoint points[],const SkPaint & paint)1131*c8dee2aaSAndroid Build Coastguard Worker void SkXPSDevice::drawPoints(SkCanvas::PointMode mode,
1132*c8dee2aaSAndroid Build Coastguard Worker size_t count, const SkPoint points[],
1133*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint) {
1134*c8dee2aaSAndroid Build Coastguard Worker //TODO
1135*c8dee2aaSAndroid Build Coastguard Worker }
1136*c8dee2aaSAndroid Build Coastguard Worker
drawVertices(const SkVertices *,sk_sp<SkBlender>,const SkPaint &,bool)1137*c8dee2aaSAndroid Build Coastguard Worker void SkXPSDevice::drawVertices(const SkVertices*, sk_sp<SkBlender>, const SkPaint&, bool) {
1138*c8dee2aaSAndroid Build Coastguard Worker //TODO
1139*c8dee2aaSAndroid Build Coastguard Worker }
1140*c8dee2aaSAndroid Build Coastguard Worker
drawMesh(const SkMesh &,sk_sp<SkBlender>,const SkPaint &)1141*c8dee2aaSAndroid Build Coastguard Worker void SkXPSDevice::drawMesh(const SkMesh&, sk_sp<SkBlender>, const SkPaint&) {
1142*c8dee2aaSAndroid Build Coastguard Worker // TODO
1143*c8dee2aaSAndroid Build Coastguard Worker }
1144*c8dee2aaSAndroid Build Coastguard Worker
drawPaint(const SkPaint & origPaint)1145*c8dee2aaSAndroid Build Coastguard Worker void SkXPSDevice::drawPaint(const SkPaint& origPaint) {
1146*c8dee2aaSAndroid Build Coastguard Worker const SkRect r = SkRect::MakeSize(this->fCurrentCanvasSize);
1147*c8dee2aaSAndroid Build Coastguard Worker
1148*c8dee2aaSAndroid Build Coastguard Worker //If trying to paint with a stroke, ignore that and fill.
1149*c8dee2aaSAndroid Build Coastguard Worker SkPaint* fillPaint = const_cast<SkPaint*>(&origPaint);
1150*c8dee2aaSAndroid Build Coastguard Worker SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1151*c8dee2aaSAndroid Build Coastguard Worker if (paint->getStyle() != SkPaint::kFill_Style) {
1152*c8dee2aaSAndroid Build Coastguard Worker paint.writable()->setStyle(SkPaint::kFill_Style);
1153*c8dee2aaSAndroid Build Coastguard Worker }
1154*c8dee2aaSAndroid Build Coastguard Worker
1155*c8dee2aaSAndroid Build Coastguard Worker this->internalDrawRect(r, false, *fillPaint);
1156*c8dee2aaSAndroid Build Coastguard Worker }
1157*c8dee2aaSAndroid Build Coastguard Worker
drawRect(const SkRect & r,const SkPaint & paint)1158*c8dee2aaSAndroid Build Coastguard Worker void SkXPSDevice::drawRect(const SkRect& r,
1159*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint) {
1160*c8dee2aaSAndroid Build Coastguard Worker this->internalDrawRect(r, true, paint);
1161*c8dee2aaSAndroid Build Coastguard Worker }
1162*c8dee2aaSAndroid Build Coastguard Worker
drawRRect(const SkRRect & rr,const SkPaint & paint)1163*c8dee2aaSAndroid Build Coastguard Worker void SkXPSDevice::drawRRect(const SkRRect& rr,
1164*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint) {
1165*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
1166*c8dee2aaSAndroid Build Coastguard Worker path.addRRect(rr);
1167*c8dee2aaSAndroid Build Coastguard Worker this->drawPath(path, paint, true);
1168*c8dee2aaSAndroid Build Coastguard Worker }
1169*c8dee2aaSAndroid Build Coastguard Worker
internalDrawRect(const SkRect & r,bool transformRect,const SkPaint & paint)1170*c8dee2aaSAndroid Build Coastguard Worker void SkXPSDevice::internalDrawRect(const SkRect& r,
1171*c8dee2aaSAndroid Build Coastguard Worker bool transformRect,
1172*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint) {
1173*c8dee2aaSAndroid Build Coastguard Worker //Exit early if there is nothing to draw.
1174*c8dee2aaSAndroid Build Coastguard Worker if (this->isClipEmpty() || (paint.getAlpha() == 0 && paint.isSrcOver())) {
1175*c8dee2aaSAndroid Build Coastguard Worker return;
1176*c8dee2aaSAndroid Build Coastguard Worker }
1177*c8dee2aaSAndroid Build Coastguard Worker
1178*c8dee2aaSAndroid Build Coastguard Worker //Path the rect if we can't optimize it.
1179*c8dee2aaSAndroid Build Coastguard Worker if (rect_must_be_pathed(paint, this->localToDevice())) {
1180*c8dee2aaSAndroid Build Coastguard Worker SkPath tmp;
1181*c8dee2aaSAndroid Build Coastguard Worker tmp.addRect(r);
1182*c8dee2aaSAndroid Build Coastguard Worker tmp.setFillType(SkPathFillType::kWinding);
1183*c8dee2aaSAndroid Build Coastguard Worker this->drawPath(tmp, paint, true);
1184*c8dee2aaSAndroid Build Coastguard Worker return;
1185*c8dee2aaSAndroid Build Coastguard Worker }
1186*c8dee2aaSAndroid Build Coastguard Worker
1187*c8dee2aaSAndroid Build Coastguard Worker //Create the shaded path.
1188*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMPath> shadedPath;
1189*c8dee2aaSAndroid Build Coastguard Worker HRVM(this->fXpsFactory->CreatePath(&shadedPath),
1190*c8dee2aaSAndroid Build Coastguard Worker "Could not create shaded path for rect.");
1191*c8dee2aaSAndroid Build Coastguard Worker
1192*c8dee2aaSAndroid Build Coastguard Worker //Create the shaded geometry.
1193*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometry> shadedGeometry;
1194*c8dee2aaSAndroid Build Coastguard Worker HRVM(this->fXpsFactory->CreateGeometry(&shadedGeometry),
1195*c8dee2aaSAndroid Build Coastguard Worker "Could not create shaded geometry for rect.");
1196*c8dee2aaSAndroid Build Coastguard Worker
1197*c8dee2aaSAndroid Build Coastguard Worker //Add the geometry to the shaded path.
1198*c8dee2aaSAndroid Build Coastguard Worker HRVM(shadedPath->SetGeometryLocal(shadedGeometry.get()),
1199*c8dee2aaSAndroid Build Coastguard Worker "Could not set shaded geometry for rect.");
1200*c8dee2aaSAndroid Build Coastguard Worker
1201*c8dee2aaSAndroid Build Coastguard Worker //Set the brushes.
1202*c8dee2aaSAndroid Build Coastguard Worker BOOL fill = FALSE;
1203*c8dee2aaSAndroid Build Coastguard Worker BOOL stroke = FALSE;
1204*c8dee2aaSAndroid Build Coastguard Worker HRV(this->shadePath(shadedPath.get(), paint, this->localToDevice(), &fill, &stroke));
1205*c8dee2aaSAndroid Build Coastguard Worker
1206*c8dee2aaSAndroid Build Coastguard Worker bool xpsTransformsPath = true;
1207*c8dee2aaSAndroid Build Coastguard Worker //Transform the geometry.
1208*c8dee2aaSAndroid Build Coastguard Worker if (transformRect && xpsTransformsPath) {
1209*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform;
1210*c8dee2aaSAndroid Build Coastguard Worker HRV(this->createXpsTransform(this->localToDevice(), &xpsTransform));
1211*c8dee2aaSAndroid Build Coastguard Worker if (xpsTransform.get()) {
1212*c8dee2aaSAndroid Build Coastguard Worker HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()),
1213*c8dee2aaSAndroid Build Coastguard Worker "Could not set transform for rect.");
1214*c8dee2aaSAndroid Build Coastguard Worker } else {
1215*c8dee2aaSAndroid Build Coastguard Worker xpsTransformsPath = false;
1216*c8dee2aaSAndroid Build Coastguard Worker }
1217*c8dee2aaSAndroid Build Coastguard Worker }
1218*c8dee2aaSAndroid Build Coastguard Worker
1219*c8dee2aaSAndroid Build Coastguard Worker //Create the figure.
1220*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometryFigure> rectFigure;
1221*c8dee2aaSAndroid Build Coastguard Worker {
1222*c8dee2aaSAndroid Build Coastguard Worker SkPoint points[4] = {
1223*c8dee2aaSAndroid Build Coastguard Worker { r.fLeft, r.fTop },
1224*c8dee2aaSAndroid Build Coastguard Worker { r.fLeft, r.fBottom },
1225*c8dee2aaSAndroid Build Coastguard Worker { r.fRight, r.fBottom },
1226*c8dee2aaSAndroid Build Coastguard Worker { r.fRight, r.fTop },
1227*c8dee2aaSAndroid Build Coastguard Worker };
1228*c8dee2aaSAndroid Build Coastguard Worker if (!xpsTransformsPath && transformRect) {
1229*c8dee2aaSAndroid Build Coastguard Worker this->localToDevice().mapPoints(points, std::size(points));
1230*c8dee2aaSAndroid Build Coastguard Worker }
1231*c8dee2aaSAndroid Build Coastguard Worker HRV(this->createXpsQuad(points, stroke, fill, &rectFigure));
1232*c8dee2aaSAndroid Build Coastguard Worker }
1233*c8dee2aaSAndroid Build Coastguard Worker
1234*c8dee2aaSAndroid Build Coastguard Worker //Get the figures of the shaded geometry.
1235*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures;
1236*c8dee2aaSAndroid Build Coastguard Worker HRVM(shadedGeometry->GetFigures(&shadedFigures),
1237*c8dee2aaSAndroid Build Coastguard Worker "Could not get shaded figures for rect.");
1238*c8dee2aaSAndroid Build Coastguard Worker
1239*c8dee2aaSAndroid Build Coastguard Worker //Add the figure to the shaded geometry figures.
1240*c8dee2aaSAndroid Build Coastguard Worker HRVM(shadedFigures->Append(rectFigure.get()),
1241*c8dee2aaSAndroid Build Coastguard Worker "Could not add shaded figure for rect.");
1242*c8dee2aaSAndroid Build Coastguard Worker
1243*c8dee2aaSAndroid Build Coastguard Worker HRV(this->clip(shadedPath.get()));
1244*c8dee2aaSAndroid Build Coastguard Worker
1245*c8dee2aaSAndroid Build Coastguard Worker //Add the shaded path to the current visuals.
1246*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals;
1247*c8dee2aaSAndroid Build Coastguard Worker HRVM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals),
1248*c8dee2aaSAndroid Build Coastguard Worker "Could not get current visuals for rect.");
1249*c8dee2aaSAndroid Build Coastguard Worker HRVM(currentVisuals->Append(shadedPath.get()),
1250*c8dee2aaSAndroid Build Coastguard Worker "Could not add rect to current visuals.");
1251*c8dee2aaSAndroid Build Coastguard Worker }
1252*c8dee2aaSAndroid Build Coastguard Worker
close_figure(const SkTDArray<XPS_SEGMENT_TYPE> & segmentTypes,const SkTDArray<FLOAT> & segmentData,const SkTDArray<BOOL> & segmentStrokes,BOOL stroke,BOOL fill,IXpsOMGeometryFigure * figure,IXpsOMGeometryFigureCollection * figures)1253*c8dee2aaSAndroid Build Coastguard Worker static HRESULT close_figure(const SkTDArray<XPS_SEGMENT_TYPE>& segmentTypes,
1254*c8dee2aaSAndroid Build Coastguard Worker const SkTDArray<FLOAT>& segmentData,
1255*c8dee2aaSAndroid Build Coastguard Worker const SkTDArray<BOOL>& segmentStrokes,
1256*c8dee2aaSAndroid Build Coastguard Worker BOOL stroke, BOOL fill,
1257*c8dee2aaSAndroid Build Coastguard Worker IXpsOMGeometryFigure* figure,
1258*c8dee2aaSAndroid Build Coastguard Worker IXpsOMGeometryFigureCollection* figures) {
1259*c8dee2aaSAndroid Build Coastguard Worker // Either all are empty or none are empty.
1260*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(( segmentTypes.empty() && segmentData.empty() && segmentStrokes.empty()) ||
1261*c8dee2aaSAndroid Build Coastguard Worker (!segmentTypes.empty() && !segmentData.empty() && !segmentStrokes.empty()));
1262*c8dee2aaSAndroid Build Coastguard Worker
1263*c8dee2aaSAndroid Build Coastguard Worker // SkTDArray::begin() may return nullptr when the segment is empty,
1264*c8dee2aaSAndroid Build Coastguard Worker // but IXpsOMGeometryFigure::SetSegments returns E_POINTER if any of the pointers are nullptr
1265*c8dee2aaSAndroid Build Coastguard Worker // even if the counts are all 0.
1266*c8dee2aaSAndroid Build Coastguard Worker if (!segmentTypes.empty() && !segmentData.empty() && !segmentStrokes.empty()) {
1267*c8dee2aaSAndroid Build Coastguard Worker // Add the segment data to the figure.
1268*c8dee2aaSAndroid Build Coastguard Worker HRM(figure->SetSegments(segmentTypes.size(), segmentData.size(),
1269*c8dee2aaSAndroid Build Coastguard Worker segmentTypes.begin(), segmentData.begin(), segmentStrokes.begin()),
1270*c8dee2aaSAndroid Build Coastguard Worker "Could not set path segments.");
1271*c8dee2aaSAndroid Build Coastguard Worker }
1272*c8dee2aaSAndroid Build Coastguard Worker
1273*c8dee2aaSAndroid Build Coastguard Worker // Set the closed and filled properties of the figure.
1274*c8dee2aaSAndroid Build Coastguard Worker HRM(figure->SetIsClosed(stroke), "Could not set path closed.");
1275*c8dee2aaSAndroid Build Coastguard Worker HRM(figure->SetIsFilled(fill), "Could not set path fill.");
1276*c8dee2aaSAndroid Build Coastguard Worker
1277*c8dee2aaSAndroid Build Coastguard Worker // Add the figure created above to this geometry.
1278*c8dee2aaSAndroid Build Coastguard Worker HRM(figures->Append(figure), "Could not add path to geometry.");
1279*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
1280*c8dee2aaSAndroid Build Coastguard Worker }
1281*c8dee2aaSAndroid Build Coastguard Worker
addXpsPathGeometry(IXpsOMGeometryFigureCollection * xpsFigures,BOOL stroke,BOOL fill,const SkPath & path)1282*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::addXpsPathGeometry(
1283*c8dee2aaSAndroid Build Coastguard Worker IXpsOMGeometryFigureCollection* xpsFigures,
1284*c8dee2aaSAndroid Build Coastguard Worker BOOL stroke, BOOL fill, const SkPath& path) {
1285*c8dee2aaSAndroid Build Coastguard Worker SkTDArray<XPS_SEGMENT_TYPE> segmentTypes;
1286*c8dee2aaSAndroid Build Coastguard Worker SkTDArray<FLOAT> segmentData;
1287*c8dee2aaSAndroid Build Coastguard Worker SkTDArray<BOOL> segmentStrokes;
1288*c8dee2aaSAndroid Build Coastguard Worker
1289*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometryFigure> xpsFigure;
1290*c8dee2aaSAndroid Build Coastguard Worker SkPath::Iter iter(path, true);
1291*c8dee2aaSAndroid Build Coastguard Worker SkPoint points[4];
1292*c8dee2aaSAndroid Build Coastguard Worker SkPath::Verb verb;
1293*c8dee2aaSAndroid Build Coastguard Worker while ((verb = iter.next(points)) != SkPath::kDone_Verb) {
1294*c8dee2aaSAndroid Build Coastguard Worker switch (verb) {
1295*c8dee2aaSAndroid Build Coastguard Worker case SkPath::kMove_Verb: {
1296*c8dee2aaSAndroid Build Coastguard Worker if (xpsFigure.get()) {
1297*c8dee2aaSAndroid Build Coastguard Worker HR(close_figure(segmentTypes, segmentData, segmentStrokes,
1298*c8dee2aaSAndroid Build Coastguard Worker stroke, fill,
1299*c8dee2aaSAndroid Build Coastguard Worker xpsFigure.get() , xpsFigures));
1300*c8dee2aaSAndroid Build Coastguard Worker segmentTypes.clear();
1301*c8dee2aaSAndroid Build Coastguard Worker segmentData.clear();
1302*c8dee2aaSAndroid Build Coastguard Worker segmentStrokes.clear();
1303*c8dee2aaSAndroid Build Coastguard Worker xpsFigure.reset();
1304*c8dee2aaSAndroid Build Coastguard Worker }
1305*c8dee2aaSAndroid Build Coastguard Worker // Define the start point.
1306*c8dee2aaSAndroid Build Coastguard Worker XPS_POINT startPoint = xps_point(points[0]);
1307*c8dee2aaSAndroid Build Coastguard Worker // Create the figure.
1308*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreateGeometryFigure(&startPoint,
1309*c8dee2aaSAndroid Build Coastguard Worker &xpsFigure),
1310*c8dee2aaSAndroid Build Coastguard Worker "Could not create path geometry figure.");
1311*c8dee2aaSAndroid Build Coastguard Worker break;
1312*c8dee2aaSAndroid Build Coastguard Worker }
1313*c8dee2aaSAndroid Build Coastguard Worker case SkPath::kLine_Verb:
1314*c8dee2aaSAndroid Build Coastguard Worker if (iter.isCloseLine()) break; //ignore the line, auto-closed
1315*c8dee2aaSAndroid Build Coastguard Worker segmentTypes.push_back(XPS_SEGMENT_TYPE_LINE);
1316*c8dee2aaSAndroid Build Coastguard Worker segmentData.push_back(SkScalarToFLOAT(points[1].fX));
1317*c8dee2aaSAndroid Build Coastguard Worker segmentData.push_back(SkScalarToFLOAT(points[1].fY));
1318*c8dee2aaSAndroid Build Coastguard Worker segmentStrokes.push_back(stroke);
1319*c8dee2aaSAndroid Build Coastguard Worker break;
1320*c8dee2aaSAndroid Build Coastguard Worker case SkPath::kQuad_Verb:
1321*c8dee2aaSAndroid Build Coastguard Worker segmentTypes.push_back(XPS_SEGMENT_TYPE_QUADRATIC_BEZIER);
1322*c8dee2aaSAndroid Build Coastguard Worker segmentData.push_back(SkScalarToFLOAT(points[1].fX));
1323*c8dee2aaSAndroid Build Coastguard Worker segmentData.push_back(SkScalarToFLOAT(points[1].fY));
1324*c8dee2aaSAndroid Build Coastguard Worker segmentData.push_back(SkScalarToFLOAT(points[2].fX));
1325*c8dee2aaSAndroid Build Coastguard Worker segmentData.push_back(SkScalarToFLOAT(points[2].fY));
1326*c8dee2aaSAndroid Build Coastguard Worker segmentStrokes.push_back(stroke);
1327*c8dee2aaSAndroid Build Coastguard Worker break;
1328*c8dee2aaSAndroid Build Coastguard Worker case SkPath::kCubic_Verb:
1329*c8dee2aaSAndroid Build Coastguard Worker segmentTypes.push_back(XPS_SEGMENT_TYPE_BEZIER);
1330*c8dee2aaSAndroid Build Coastguard Worker segmentData.push_back(SkScalarToFLOAT(points[1].fX));
1331*c8dee2aaSAndroid Build Coastguard Worker segmentData.push_back(SkScalarToFLOAT(points[1].fY));
1332*c8dee2aaSAndroid Build Coastguard Worker segmentData.push_back(SkScalarToFLOAT(points[2].fX));
1333*c8dee2aaSAndroid Build Coastguard Worker segmentData.push_back(SkScalarToFLOAT(points[2].fY));
1334*c8dee2aaSAndroid Build Coastguard Worker segmentData.push_back(SkScalarToFLOAT(points[3].fX));
1335*c8dee2aaSAndroid Build Coastguard Worker segmentData.push_back(SkScalarToFLOAT(points[3].fY));
1336*c8dee2aaSAndroid Build Coastguard Worker segmentStrokes.push_back(stroke);
1337*c8dee2aaSAndroid Build Coastguard Worker break;
1338*c8dee2aaSAndroid Build Coastguard Worker case SkPath::kConic_Verb: {
1339*c8dee2aaSAndroid Build Coastguard Worker const SkScalar tol = SK_Scalar1 / 4;
1340*c8dee2aaSAndroid Build Coastguard Worker SkAutoConicToQuads converter;
1341*c8dee2aaSAndroid Build Coastguard Worker const SkPoint* quads =
1342*c8dee2aaSAndroid Build Coastguard Worker converter.computeQuads(points, iter.conicWeight(), tol);
1343*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < converter.countQuads(); ++i) {
1344*c8dee2aaSAndroid Build Coastguard Worker segmentTypes.push_back(XPS_SEGMENT_TYPE_QUADRATIC_BEZIER);
1345*c8dee2aaSAndroid Build Coastguard Worker segmentData.push_back(SkScalarToFLOAT(quads[2 * i + 1].fX));
1346*c8dee2aaSAndroid Build Coastguard Worker segmentData.push_back(SkScalarToFLOAT(quads[2 * i + 1].fY));
1347*c8dee2aaSAndroid Build Coastguard Worker segmentData.push_back(SkScalarToFLOAT(quads[2 * i + 2].fX));
1348*c8dee2aaSAndroid Build Coastguard Worker segmentData.push_back(SkScalarToFLOAT(quads[2 * i + 2].fY));
1349*c8dee2aaSAndroid Build Coastguard Worker segmentStrokes.push_back(stroke);
1350*c8dee2aaSAndroid Build Coastguard Worker }
1351*c8dee2aaSAndroid Build Coastguard Worker break;
1352*c8dee2aaSAndroid Build Coastguard Worker }
1353*c8dee2aaSAndroid Build Coastguard Worker case SkPath::kClose_Verb:
1354*c8dee2aaSAndroid Build Coastguard Worker // we ignore these, and just get the whole segment from
1355*c8dee2aaSAndroid Build Coastguard Worker // the corresponding line/quad/cubic verbs
1356*c8dee2aaSAndroid Build Coastguard Worker break;
1357*c8dee2aaSAndroid Build Coastguard Worker default:
1358*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("unexpected verb");
1359*c8dee2aaSAndroid Build Coastguard Worker break;
1360*c8dee2aaSAndroid Build Coastguard Worker }
1361*c8dee2aaSAndroid Build Coastguard Worker }
1362*c8dee2aaSAndroid Build Coastguard Worker if (xpsFigure.get()) {
1363*c8dee2aaSAndroid Build Coastguard Worker HR(close_figure(segmentTypes, segmentData, segmentStrokes,
1364*c8dee2aaSAndroid Build Coastguard Worker stroke, fill,
1365*c8dee2aaSAndroid Build Coastguard Worker xpsFigure.get(), xpsFigures));
1366*c8dee2aaSAndroid Build Coastguard Worker }
1367*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
1368*c8dee2aaSAndroid Build Coastguard Worker }
1369*c8dee2aaSAndroid Build Coastguard Worker
convertToPpm(const SkMaskFilter * filter,SkMatrix * matrix,SkVector * ppuScale,const SkIRect & clip,SkIRect * clipIRect)1370*c8dee2aaSAndroid Build Coastguard Worker void SkXPSDevice::convertToPpm(const SkMaskFilter* filter,
1371*c8dee2aaSAndroid Build Coastguard Worker SkMatrix* matrix,
1372*c8dee2aaSAndroid Build Coastguard Worker SkVector* ppuScale,
1373*c8dee2aaSAndroid Build Coastguard Worker const SkIRect& clip, SkIRect* clipIRect) {
1374*c8dee2aaSAndroid Build Coastguard Worker //This action is in unit space, but the ppm is specified in physical space.
1375*c8dee2aaSAndroid Build Coastguard Worker ppuScale->set(fCurrentPixelsPerMeter.fX / fCurrentUnitsPerMeter.fX,
1376*c8dee2aaSAndroid Build Coastguard Worker fCurrentPixelsPerMeter.fY / fCurrentUnitsPerMeter.fY);
1377*c8dee2aaSAndroid Build Coastguard Worker
1378*c8dee2aaSAndroid Build Coastguard Worker matrix->postScale(ppuScale->fX, ppuScale->fY);
1379*c8dee2aaSAndroid Build Coastguard Worker
1380*c8dee2aaSAndroid Build Coastguard Worker const SkIRect& irect = clip;
1381*c8dee2aaSAndroid Build Coastguard Worker SkRect clipRect = SkRect::MakeLTRB(SkIntToScalar(irect.fLeft) * ppuScale->fX,
1382*c8dee2aaSAndroid Build Coastguard Worker SkIntToScalar(irect.fTop) * ppuScale->fY,
1383*c8dee2aaSAndroid Build Coastguard Worker SkIntToScalar(irect.fRight) * ppuScale->fX,
1384*c8dee2aaSAndroid Build Coastguard Worker SkIntToScalar(irect.fBottom) * ppuScale->fY);
1385*c8dee2aaSAndroid Build Coastguard Worker clipRect.roundOut(clipIRect);
1386*c8dee2aaSAndroid Build Coastguard Worker }
1387*c8dee2aaSAndroid Build Coastguard Worker
applyMask(const SkMask & mask,const SkVector & ppuScale,IXpsOMPath * shadedPath)1388*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::applyMask(const SkMask& mask,
1389*c8dee2aaSAndroid Build Coastguard Worker const SkVector& ppuScale,
1390*c8dee2aaSAndroid Build Coastguard Worker IXpsOMPath* shadedPath) {
1391*c8dee2aaSAndroid Build Coastguard Worker //Get the geometry object.
1392*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometry> shadedGeometry;
1393*c8dee2aaSAndroid Build Coastguard Worker HRM(shadedPath->GetGeometry(&shadedGeometry),
1394*c8dee2aaSAndroid Build Coastguard Worker "Could not get mask shaded geometry.");
1395*c8dee2aaSAndroid Build Coastguard Worker
1396*c8dee2aaSAndroid Build Coastguard Worker //Get the figures from the geometry.
1397*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures;
1398*c8dee2aaSAndroid Build Coastguard Worker HRM(shadedGeometry->GetFigures(&shadedFigures),
1399*c8dee2aaSAndroid Build Coastguard Worker "Could not get mask shaded figures.");
1400*c8dee2aaSAndroid Build Coastguard Worker
1401*c8dee2aaSAndroid Build Coastguard Worker SkMatrix m;
1402*c8dee2aaSAndroid Build Coastguard Worker m.reset();
1403*c8dee2aaSAndroid Build Coastguard Worker m.setTranslate(SkIntToScalar(mask.fBounds.fLeft),
1404*c8dee2aaSAndroid Build Coastguard Worker SkIntToScalar(mask.fBounds.fTop));
1405*c8dee2aaSAndroid Build Coastguard Worker m.postScale(SkScalarInvert(ppuScale.fX), SkScalarInvert(ppuScale.fY));
1406*c8dee2aaSAndroid Build Coastguard Worker
1407*c8dee2aaSAndroid Build Coastguard Worker SkTileMode xy[2];
1408*c8dee2aaSAndroid Build Coastguard Worker xy[0] = (SkTileMode)3;
1409*c8dee2aaSAndroid Build Coastguard Worker xy[1] = (SkTileMode)3;
1410*c8dee2aaSAndroid Build Coastguard Worker
1411*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(mask.fFormat == SkMask::kA8_Format);
1412*c8dee2aaSAndroid Build Coastguard Worker SkPixmap pm(SkImageInfo::MakeA8(mask.fBounds.width(), mask.fBounds.height()),
1413*c8dee2aaSAndroid Build Coastguard Worker mask.fImage, mask.fRowBytes);
1414*c8dee2aaSAndroid Build Coastguard Worker
1415*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMTileBrush> maskBrush;
1416*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsImageBrush(pm, m, xy, 0xFF, &maskBrush));
1417*c8dee2aaSAndroid Build Coastguard Worker HRM(shadedPath->SetOpacityMaskBrushLocal(maskBrush.get()),
1418*c8dee2aaSAndroid Build Coastguard Worker "Could not set mask.");
1419*c8dee2aaSAndroid Build Coastguard Worker
1420*c8dee2aaSAndroid Build Coastguard Worker const SkRect universeRect = SkRect::MakeLTRB(0, 0,
1421*c8dee2aaSAndroid Build Coastguard Worker this->fCurrentCanvasSize.fWidth, this->fCurrentCanvasSize.fHeight);
1422*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometryFigure> shadedFigure;
1423*c8dee2aaSAndroid Build Coastguard Worker HRM(this->createXpsRect(universeRect, FALSE, TRUE, &shadedFigure),
1424*c8dee2aaSAndroid Build Coastguard Worker "Could not create mask shaded figure.");
1425*c8dee2aaSAndroid Build Coastguard Worker HRM(shadedFigures->Append(shadedFigure.get()),
1426*c8dee2aaSAndroid Build Coastguard Worker "Could not add mask shaded figure.");
1427*c8dee2aaSAndroid Build Coastguard Worker
1428*c8dee2aaSAndroid Build Coastguard Worker HR(this->clip(shadedPath));
1429*c8dee2aaSAndroid Build Coastguard Worker
1430*c8dee2aaSAndroid Build Coastguard Worker //Add the path to the active visual collection.
1431*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals;
1432*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals),
1433*c8dee2aaSAndroid Build Coastguard Worker "Could not get mask current visuals.");
1434*c8dee2aaSAndroid Build Coastguard Worker HRM(currentVisuals->Append(shadedPath),
1435*c8dee2aaSAndroid Build Coastguard Worker "Could not add masked shaded path to current visuals.");
1436*c8dee2aaSAndroid Build Coastguard Worker
1437*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
1438*c8dee2aaSAndroid Build Coastguard Worker }
1439*c8dee2aaSAndroid Build Coastguard Worker
shadePath(IXpsOMPath * shadedPath,const SkPaint & shaderPaint,const SkMatrix & matrix,BOOL * fill,BOOL * stroke)1440*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::shadePath(IXpsOMPath* shadedPath,
1441*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& shaderPaint,
1442*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& matrix,
1443*c8dee2aaSAndroid Build Coastguard Worker BOOL* fill, BOOL* stroke) {
1444*c8dee2aaSAndroid Build Coastguard Worker *fill = FALSE;
1445*c8dee2aaSAndroid Build Coastguard Worker *stroke = FALSE;
1446*c8dee2aaSAndroid Build Coastguard Worker
1447*c8dee2aaSAndroid Build Coastguard Worker const SkPaint::Style style = shaderPaint.getStyle();
1448*c8dee2aaSAndroid Build Coastguard Worker const bool hasFill = SkPaint::kFill_Style == style
1449*c8dee2aaSAndroid Build Coastguard Worker || SkPaint::kStrokeAndFill_Style == style;
1450*c8dee2aaSAndroid Build Coastguard Worker const bool hasStroke = SkPaint::kStroke_Style == style
1451*c8dee2aaSAndroid Build Coastguard Worker || SkPaint::kStrokeAndFill_Style == style;
1452*c8dee2aaSAndroid Build Coastguard Worker
1453*c8dee2aaSAndroid Build Coastguard Worker //TODO(bungeman): use dictionaries and lookups.
1454*c8dee2aaSAndroid Build Coastguard Worker if (hasFill) {
1455*c8dee2aaSAndroid Build Coastguard Worker *fill = TRUE;
1456*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMBrush> fillBrush;
1457*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsBrush(shaderPaint, &fillBrush, &matrix));
1458*c8dee2aaSAndroid Build Coastguard Worker HRM(shadedPath->SetFillBrushLocal(fillBrush.get()),
1459*c8dee2aaSAndroid Build Coastguard Worker "Could not set fill for shaded path.");
1460*c8dee2aaSAndroid Build Coastguard Worker }
1461*c8dee2aaSAndroid Build Coastguard Worker
1462*c8dee2aaSAndroid Build Coastguard Worker if (hasStroke) {
1463*c8dee2aaSAndroid Build Coastguard Worker *stroke = TRUE;
1464*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMBrush> strokeBrush;
1465*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsBrush(shaderPaint, &strokeBrush, &matrix));
1466*c8dee2aaSAndroid Build Coastguard Worker HRM(shadedPath->SetStrokeBrushLocal(strokeBrush.get()),
1467*c8dee2aaSAndroid Build Coastguard Worker "Could not set stroke brush for shaded path.");
1468*c8dee2aaSAndroid Build Coastguard Worker HRM(shadedPath->SetStrokeThickness(
1469*c8dee2aaSAndroid Build Coastguard Worker SkScalarToFLOAT(shaderPaint.getStrokeWidth())),
1470*c8dee2aaSAndroid Build Coastguard Worker "Could not set shaded path stroke thickness.");
1471*c8dee2aaSAndroid Build Coastguard Worker
1472*c8dee2aaSAndroid Build Coastguard Worker if (0 == shaderPaint.getStrokeWidth()) {
1473*c8dee2aaSAndroid Build Coastguard Worker //XPS hair width is a hack. (XPS Spec 11.6.12).
1474*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMDashCollection> dashes;
1475*c8dee2aaSAndroid Build Coastguard Worker HRM(shadedPath->GetStrokeDashes(&dashes),
1476*c8dee2aaSAndroid Build Coastguard Worker "Could not set dashes for shaded path.");
1477*c8dee2aaSAndroid Build Coastguard Worker XPS_DASH dash;
1478*c8dee2aaSAndroid Build Coastguard Worker dash.length = 1.0;
1479*c8dee2aaSAndroid Build Coastguard Worker dash.gap = 0.0;
1480*c8dee2aaSAndroid Build Coastguard Worker HRM(dashes->Append(&dash), "Could not add dashes to shaded path.");
1481*c8dee2aaSAndroid Build Coastguard Worker HRM(shadedPath->SetStrokeDashOffset(-2.0),
1482*c8dee2aaSAndroid Build Coastguard Worker "Could not set dash offset for shaded path.");
1483*c8dee2aaSAndroid Build Coastguard Worker }
1484*c8dee2aaSAndroid Build Coastguard Worker }
1485*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
1486*c8dee2aaSAndroid Build Coastguard Worker }
1487*c8dee2aaSAndroid Build Coastguard Worker
drawPath(const SkPath & platonicPath,const SkPaint & origPaint,bool pathIsMutable)1488*c8dee2aaSAndroid Build Coastguard Worker void SkXPSDevice::drawPath(const SkPath& platonicPath,
1489*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& origPaint,
1490*c8dee2aaSAndroid Build Coastguard Worker bool pathIsMutable) {
1491*c8dee2aaSAndroid Build Coastguard Worker SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1492*c8dee2aaSAndroid Build Coastguard Worker
1493*c8dee2aaSAndroid Build Coastguard Worker // nothing to draw
1494*c8dee2aaSAndroid Build Coastguard Worker if (this->isClipEmpty() || (paint->getAlpha() == 0 && paint->isSrcOver())) {
1495*c8dee2aaSAndroid Build Coastguard Worker return;
1496*c8dee2aaSAndroid Build Coastguard Worker }
1497*c8dee2aaSAndroid Build Coastguard Worker
1498*c8dee2aaSAndroid Build Coastguard Worker SkPath modifiedPath;
1499*c8dee2aaSAndroid Build Coastguard Worker const bool paintHasPathEffect = paint->getPathEffect()
1500*c8dee2aaSAndroid Build Coastguard Worker || paint->getStyle() != SkPaint::kFill_Style;
1501*c8dee2aaSAndroid Build Coastguard Worker
1502*c8dee2aaSAndroid Build Coastguard Worker //Apply pre-path matrix [Platonic-path -> Skeletal-path].
1503*c8dee2aaSAndroid Build Coastguard Worker SkMatrix matrix = this->localToDevice();
1504*c8dee2aaSAndroid Build Coastguard Worker SkPath* skeletalPath = const_cast<SkPath*>(&platonicPath);
1505*c8dee2aaSAndroid Build Coastguard Worker
1506*c8dee2aaSAndroid Build Coastguard Worker //Apply path effect [Skeletal-path -> Fillable-path].
1507*c8dee2aaSAndroid Build Coastguard Worker SkPath* fillablePath = skeletalPath;
1508*c8dee2aaSAndroid Build Coastguard Worker if (paintHasPathEffect) {
1509*c8dee2aaSAndroid Build Coastguard Worker if (!pathIsMutable) {
1510*c8dee2aaSAndroid Build Coastguard Worker fillablePath = &modifiedPath;
1511*c8dee2aaSAndroid Build Coastguard Worker pathIsMutable = true;
1512*c8dee2aaSAndroid Build Coastguard Worker }
1513*c8dee2aaSAndroid Build Coastguard Worker bool fill = skpathutils::FillPathWithPaint(*skeletalPath, *paint, fillablePath);
1514*c8dee2aaSAndroid Build Coastguard Worker
1515*c8dee2aaSAndroid Build Coastguard Worker SkPaint* writablePaint = paint.writable();
1516*c8dee2aaSAndroid Build Coastguard Worker writablePaint->setPathEffect(nullptr);
1517*c8dee2aaSAndroid Build Coastguard Worker if (fill) {
1518*c8dee2aaSAndroid Build Coastguard Worker writablePaint->setStyle(SkPaint::kFill_Style);
1519*c8dee2aaSAndroid Build Coastguard Worker } else {
1520*c8dee2aaSAndroid Build Coastguard Worker writablePaint->setStyle(SkPaint::kStroke_Style);
1521*c8dee2aaSAndroid Build Coastguard Worker writablePaint->setStrokeWidth(0);
1522*c8dee2aaSAndroid Build Coastguard Worker }
1523*c8dee2aaSAndroid Build Coastguard Worker }
1524*c8dee2aaSAndroid Build Coastguard Worker
1525*c8dee2aaSAndroid Build Coastguard Worker //Create the shaded path. This will be the path which is painted.
1526*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMPath> shadedPath;
1527*c8dee2aaSAndroid Build Coastguard Worker HRVM(this->fXpsFactory->CreatePath(&shadedPath),
1528*c8dee2aaSAndroid Build Coastguard Worker "Could not create shaded path for path.");
1529*c8dee2aaSAndroid Build Coastguard Worker
1530*c8dee2aaSAndroid Build Coastguard Worker //Create the geometry for the shaded path.
1531*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometry> shadedGeometry;
1532*c8dee2aaSAndroid Build Coastguard Worker HRVM(this->fXpsFactory->CreateGeometry(&shadedGeometry),
1533*c8dee2aaSAndroid Build Coastguard Worker "Could not create shaded geometry for path.");
1534*c8dee2aaSAndroid Build Coastguard Worker
1535*c8dee2aaSAndroid Build Coastguard Worker //Add the geometry to the shaded path.
1536*c8dee2aaSAndroid Build Coastguard Worker HRVM(shadedPath->SetGeometryLocal(shadedGeometry.get()),
1537*c8dee2aaSAndroid Build Coastguard Worker "Could not add the shaded geometry to shaded path.");
1538*c8dee2aaSAndroid Build Coastguard Worker
1539*c8dee2aaSAndroid Build Coastguard Worker SkMaskFilter* filter = paint->getMaskFilter();
1540*c8dee2aaSAndroid Build Coastguard Worker
1541*c8dee2aaSAndroid Build Coastguard Worker //Determine if we will draw or shade and mask.
1542*c8dee2aaSAndroid Build Coastguard Worker if (filter) {
1543*c8dee2aaSAndroid Build Coastguard Worker if (paint->getStyle() != SkPaint::kFill_Style) {
1544*c8dee2aaSAndroid Build Coastguard Worker paint.writable()->setStyle(SkPaint::kFill_Style);
1545*c8dee2aaSAndroid Build Coastguard Worker }
1546*c8dee2aaSAndroid Build Coastguard Worker }
1547*c8dee2aaSAndroid Build Coastguard Worker
1548*c8dee2aaSAndroid Build Coastguard Worker //Set the brushes.
1549*c8dee2aaSAndroid Build Coastguard Worker BOOL fill;
1550*c8dee2aaSAndroid Build Coastguard Worker BOOL stroke;
1551*c8dee2aaSAndroid Build Coastguard Worker HRV(this->shadePath(shadedPath.get(),
1552*c8dee2aaSAndroid Build Coastguard Worker *paint,
1553*c8dee2aaSAndroid Build Coastguard Worker this->localToDevice(),
1554*c8dee2aaSAndroid Build Coastguard Worker &fill,
1555*c8dee2aaSAndroid Build Coastguard Worker &stroke));
1556*c8dee2aaSAndroid Build Coastguard Worker
1557*c8dee2aaSAndroid Build Coastguard Worker //Mask filter
1558*c8dee2aaSAndroid Build Coastguard Worker if (filter) {
1559*c8dee2aaSAndroid Build Coastguard Worker SkIRect clipIRect;
1560*c8dee2aaSAndroid Build Coastguard Worker SkVector ppuScale;
1561*c8dee2aaSAndroid Build Coastguard Worker this->convertToPpm(filter,
1562*c8dee2aaSAndroid Build Coastguard Worker &matrix,
1563*c8dee2aaSAndroid Build Coastguard Worker &ppuScale,
1564*c8dee2aaSAndroid Build Coastguard Worker this->devClipBounds(),
1565*c8dee2aaSAndroid Build Coastguard Worker &clipIRect);
1566*c8dee2aaSAndroid Build Coastguard Worker
1567*c8dee2aaSAndroid Build Coastguard Worker //[Fillable-path -> Pixel-path]
1568*c8dee2aaSAndroid Build Coastguard Worker SkPath* pixelPath = pathIsMutable ? fillablePath : &modifiedPath;
1569*c8dee2aaSAndroid Build Coastguard Worker fillablePath->transform(matrix, pixelPath);
1570*c8dee2aaSAndroid Build Coastguard Worker
1571*c8dee2aaSAndroid Build Coastguard Worker SkMask* mask = nullptr;
1572*c8dee2aaSAndroid Build Coastguard Worker
1573*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(SkPaint::kFill_Style == paint->getStyle() ||
1574*c8dee2aaSAndroid Build Coastguard Worker (SkPaint::kStroke_Style == paint->getStyle() && 0 == paint->getStrokeWidth()));
1575*c8dee2aaSAndroid Build Coastguard Worker SkStrokeRec::InitStyle style = (SkPaint::kFill_Style == paint->getStyle())
1576*c8dee2aaSAndroid Build Coastguard Worker ? SkStrokeRec::kFill_InitStyle
1577*c8dee2aaSAndroid Build Coastguard Worker : SkStrokeRec::kHairline_InitStyle;
1578*c8dee2aaSAndroid Build Coastguard Worker //[Pixel-path -> Mask]
1579*c8dee2aaSAndroid Build Coastguard Worker SkMaskBuilder rasteredMask;
1580*c8dee2aaSAndroid Build Coastguard Worker if (SkDraw::DrawToMask(
1581*c8dee2aaSAndroid Build Coastguard Worker *pixelPath,
1582*c8dee2aaSAndroid Build Coastguard Worker clipIRect,
1583*c8dee2aaSAndroid Build Coastguard Worker filter, //just to compute how much to draw.
1584*c8dee2aaSAndroid Build Coastguard Worker &matrix,
1585*c8dee2aaSAndroid Build Coastguard Worker &rasteredMask,
1586*c8dee2aaSAndroid Build Coastguard Worker SkMaskBuilder::kComputeBoundsAndRenderImage_CreateMode,
1587*c8dee2aaSAndroid Build Coastguard Worker style)) {
1588*c8dee2aaSAndroid Build Coastguard Worker
1589*c8dee2aaSAndroid Build Coastguard Worker SkAutoMaskFreeImage rasteredAmi(rasteredMask.image());
1590*c8dee2aaSAndroid Build Coastguard Worker mask = &rasteredMask;
1591*c8dee2aaSAndroid Build Coastguard Worker
1592*c8dee2aaSAndroid Build Coastguard Worker //[Mask -> Mask]
1593*c8dee2aaSAndroid Build Coastguard Worker SkMaskBuilder filteredMask;
1594*c8dee2aaSAndroid Build Coastguard Worker if (as_MFB(filter)->filterMask(&filteredMask, rasteredMask, matrix, nullptr)) {
1595*c8dee2aaSAndroid Build Coastguard Worker mask = &filteredMask;
1596*c8dee2aaSAndroid Build Coastguard Worker }
1597*c8dee2aaSAndroid Build Coastguard Worker SkAutoMaskFreeImage filteredAmi(filteredMask.image());
1598*c8dee2aaSAndroid Build Coastguard Worker
1599*c8dee2aaSAndroid Build Coastguard Worker //Draw mask.
1600*c8dee2aaSAndroid Build Coastguard Worker HRV(this->applyMask(*mask, ppuScale, shadedPath.get()));
1601*c8dee2aaSAndroid Build Coastguard Worker }
1602*c8dee2aaSAndroid Build Coastguard Worker return;
1603*c8dee2aaSAndroid Build Coastguard Worker }
1604*c8dee2aaSAndroid Build Coastguard Worker
1605*c8dee2aaSAndroid Build Coastguard Worker //Get the figures from the shaded geometry.
1606*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures;
1607*c8dee2aaSAndroid Build Coastguard Worker HRVM(shadedGeometry->GetFigures(&shadedFigures),
1608*c8dee2aaSAndroid Build Coastguard Worker "Could not get shaded figures for shaded path.");
1609*c8dee2aaSAndroid Build Coastguard Worker
1610*c8dee2aaSAndroid Build Coastguard Worker bool xpsTransformsPath = true;
1611*c8dee2aaSAndroid Build Coastguard Worker
1612*c8dee2aaSAndroid Build Coastguard Worker //Set the fill rule.
1613*c8dee2aaSAndroid Build Coastguard Worker SkPath* xpsCompatiblePath = fillablePath;
1614*c8dee2aaSAndroid Build Coastguard Worker XPS_FILL_RULE xpsFillRule;
1615*c8dee2aaSAndroid Build Coastguard Worker switch (fillablePath->getFillType()) {
1616*c8dee2aaSAndroid Build Coastguard Worker case SkPathFillType::kWinding:
1617*c8dee2aaSAndroid Build Coastguard Worker xpsFillRule = XPS_FILL_RULE_NONZERO;
1618*c8dee2aaSAndroid Build Coastguard Worker break;
1619*c8dee2aaSAndroid Build Coastguard Worker case SkPathFillType::kEvenOdd:
1620*c8dee2aaSAndroid Build Coastguard Worker xpsFillRule = XPS_FILL_RULE_EVENODD;
1621*c8dee2aaSAndroid Build Coastguard Worker break;
1622*c8dee2aaSAndroid Build Coastguard Worker case SkPathFillType::kInverseWinding: {
1623*c8dee2aaSAndroid Build Coastguard Worker //[Fillable-path (inverse winding) -> XPS-path (inverse even odd)]
1624*c8dee2aaSAndroid Build Coastguard Worker if (!pathIsMutable) {
1625*c8dee2aaSAndroid Build Coastguard Worker xpsCompatiblePath = &modifiedPath;
1626*c8dee2aaSAndroid Build Coastguard Worker pathIsMutable = true;
1627*c8dee2aaSAndroid Build Coastguard Worker }
1628*c8dee2aaSAndroid Build Coastguard Worker if (!Simplify(*fillablePath, xpsCompatiblePath)) {
1629*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGF("Could not simplify inverse winding path.");
1630*c8dee2aaSAndroid Build Coastguard Worker return;
1631*c8dee2aaSAndroid Build Coastguard Worker }
1632*c8dee2aaSAndroid Build Coastguard Worker }
1633*c8dee2aaSAndroid Build Coastguard Worker [[fallthrough]]; // The xpsCompatiblePath is now inverse even odd, so fall through.
1634*c8dee2aaSAndroid Build Coastguard Worker case SkPathFillType::kInverseEvenOdd: {
1635*c8dee2aaSAndroid Build Coastguard Worker const SkRect universe = SkRect::MakeLTRB(
1636*c8dee2aaSAndroid Build Coastguard Worker 0, 0,
1637*c8dee2aaSAndroid Build Coastguard Worker this->fCurrentCanvasSize.fWidth,
1638*c8dee2aaSAndroid Build Coastguard Worker this->fCurrentCanvasSize.fHeight);
1639*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometryFigure> addOneFigure;
1640*c8dee2aaSAndroid Build Coastguard Worker HRV(this->createXpsRect(universe, FALSE, TRUE, &addOneFigure));
1641*c8dee2aaSAndroid Build Coastguard Worker HRVM(shadedFigures->Append(addOneFigure.get()),
1642*c8dee2aaSAndroid Build Coastguard Worker "Could not add even-odd flip figure to shaded path.");
1643*c8dee2aaSAndroid Build Coastguard Worker xpsTransformsPath = false;
1644*c8dee2aaSAndroid Build Coastguard Worker xpsFillRule = XPS_FILL_RULE_EVENODD;
1645*c8dee2aaSAndroid Build Coastguard Worker break;
1646*c8dee2aaSAndroid Build Coastguard Worker }
1647*c8dee2aaSAndroid Build Coastguard Worker default:
1648*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("Unknown SkPath::FillType.");
1649*c8dee2aaSAndroid Build Coastguard Worker }
1650*c8dee2aaSAndroid Build Coastguard Worker HRVM(shadedGeometry->SetFillRule(xpsFillRule),
1651*c8dee2aaSAndroid Build Coastguard Worker "Could not set fill rule for shaded path.");
1652*c8dee2aaSAndroid Build Coastguard Worker
1653*c8dee2aaSAndroid Build Coastguard Worker //Create the XPS transform, if possible.
1654*c8dee2aaSAndroid Build Coastguard Worker if (xpsTransformsPath) {
1655*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform;
1656*c8dee2aaSAndroid Build Coastguard Worker HRV(this->createXpsTransform(matrix, &xpsTransform));
1657*c8dee2aaSAndroid Build Coastguard Worker
1658*c8dee2aaSAndroid Build Coastguard Worker if (xpsTransform.get()) {
1659*c8dee2aaSAndroid Build Coastguard Worker HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()),
1660*c8dee2aaSAndroid Build Coastguard Worker "Could not set transform on shaded path.");
1661*c8dee2aaSAndroid Build Coastguard Worker } else {
1662*c8dee2aaSAndroid Build Coastguard Worker xpsTransformsPath = false;
1663*c8dee2aaSAndroid Build Coastguard Worker }
1664*c8dee2aaSAndroid Build Coastguard Worker }
1665*c8dee2aaSAndroid Build Coastguard Worker
1666*c8dee2aaSAndroid Build Coastguard Worker SkPath* devicePath = xpsCompatiblePath;
1667*c8dee2aaSAndroid Build Coastguard Worker if (!xpsTransformsPath) {
1668*c8dee2aaSAndroid Build Coastguard Worker //[Fillable-path -> Device-path]
1669*c8dee2aaSAndroid Build Coastguard Worker devicePath = pathIsMutable ? xpsCompatiblePath : &modifiedPath;
1670*c8dee2aaSAndroid Build Coastguard Worker xpsCompatiblePath->transform(matrix, devicePath);
1671*c8dee2aaSAndroid Build Coastguard Worker }
1672*c8dee2aaSAndroid Build Coastguard Worker HRV(this->addXpsPathGeometry(shadedFigures.get(),
1673*c8dee2aaSAndroid Build Coastguard Worker stroke, fill, *devicePath));
1674*c8dee2aaSAndroid Build Coastguard Worker
1675*c8dee2aaSAndroid Build Coastguard Worker HRV(this->clip(shadedPath.get()));
1676*c8dee2aaSAndroid Build Coastguard Worker
1677*c8dee2aaSAndroid Build Coastguard Worker //Add the path to the active visual collection.
1678*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals;
1679*c8dee2aaSAndroid Build Coastguard Worker HRVM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals),
1680*c8dee2aaSAndroid Build Coastguard Worker "Could not get current visuals for shaded path.");
1681*c8dee2aaSAndroid Build Coastguard Worker HRVM(currentVisuals->Append(shadedPath.get()),
1682*c8dee2aaSAndroid Build Coastguard Worker "Could not add shaded path to current visuals.");
1683*c8dee2aaSAndroid Build Coastguard Worker }
1684*c8dee2aaSAndroid Build Coastguard Worker
clip(IXpsOMVisual * xpsVisual)1685*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::clip(IXpsOMVisual* xpsVisual) {
1686*c8dee2aaSAndroid Build Coastguard Worker if (this->cs().isWideOpen()) {
1687*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
1688*c8dee2aaSAndroid Build Coastguard Worker }
1689*c8dee2aaSAndroid Build Coastguard Worker SkPath clipPath;
1690*c8dee2aaSAndroid Build Coastguard Worker // clipPath.addRect(this->devClipBounds()));
1691*c8dee2aaSAndroid Build Coastguard Worker SkClipStack_AsPath(this->cs(), &clipPath);
1692*c8dee2aaSAndroid Build Coastguard Worker // TODO: handle all the kinds of paths, like drawPath does
1693*c8dee2aaSAndroid Build Coastguard Worker return this->clipToPath(xpsVisual, clipPath, XPS_FILL_RULE_EVENODD);
1694*c8dee2aaSAndroid Build Coastguard Worker }
clipToPath(IXpsOMVisual * xpsVisual,const SkPath & clipPath,XPS_FILL_RULE fillRule)1695*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::clipToPath(IXpsOMVisual* xpsVisual,
1696*c8dee2aaSAndroid Build Coastguard Worker const SkPath& clipPath,
1697*c8dee2aaSAndroid Build Coastguard Worker XPS_FILL_RULE fillRule) {
1698*c8dee2aaSAndroid Build Coastguard Worker //Create the geometry.
1699*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometry> clipGeometry;
1700*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreateGeometry(&clipGeometry),
1701*c8dee2aaSAndroid Build Coastguard Worker "Could not create clip geometry.");
1702*c8dee2aaSAndroid Build Coastguard Worker
1703*c8dee2aaSAndroid Build Coastguard Worker //Get the figure collection of the geometry.
1704*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGeometryFigureCollection> clipFigures;
1705*c8dee2aaSAndroid Build Coastguard Worker HRM(clipGeometry->GetFigures(&clipFigures),
1706*c8dee2aaSAndroid Build Coastguard Worker "Could not get the clip figures.");
1707*c8dee2aaSAndroid Build Coastguard Worker
1708*c8dee2aaSAndroid Build Coastguard Worker //Create the figures into the geometry.
1709*c8dee2aaSAndroid Build Coastguard Worker HR(this->addXpsPathGeometry(
1710*c8dee2aaSAndroid Build Coastguard Worker clipFigures.get(),
1711*c8dee2aaSAndroid Build Coastguard Worker FALSE, TRUE, clipPath));
1712*c8dee2aaSAndroid Build Coastguard Worker
1713*c8dee2aaSAndroid Build Coastguard Worker HRM(clipGeometry->SetFillRule(fillRule),
1714*c8dee2aaSAndroid Build Coastguard Worker "Could not set fill rule.");
1715*c8dee2aaSAndroid Build Coastguard Worker HRM(xpsVisual->SetClipGeometryLocal(clipGeometry.get()),
1716*c8dee2aaSAndroid Build Coastguard Worker "Could not set clip geometry.");
1717*c8dee2aaSAndroid Build Coastguard Worker
1718*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
1719*c8dee2aaSAndroid Build Coastguard Worker }
1720*c8dee2aaSAndroid Build Coastguard Worker
CreateTypefaceUse(const SkFont & font,TypefaceUse ** typefaceUse)1721*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::CreateTypefaceUse(const SkFont& font,
1722*c8dee2aaSAndroid Build Coastguard Worker TypefaceUse** typefaceUse) {
1723*c8dee2aaSAndroid Build Coastguard Worker SkTypeface* typeface = font.getTypeface();
1724*c8dee2aaSAndroid Build Coastguard Worker
1725*c8dee2aaSAndroid Build Coastguard Worker //Check cache.
1726*c8dee2aaSAndroid Build Coastguard Worker const SkTypefaceID typefaceID = typeface->uniqueID();
1727*c8dee2aaSAndroid Build Coastguard Worker for (TypefaceUse& current : *this->fTopTypefaces) {
1728*c8dee2aaSAndroid Build Coastguard Worker if (current.typefaceId == typefaceID) {
1729*c8dee2aaSAndroid Build Coastguard Worker *typefaceUse = ¤t;
1730*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
1731*c8dee2aaSAndroid Build Coastguard Worker }
1732*c8dee2aaSAndroid Build Coastguard Worker }
1733*c8dee2aaSAndroid Build Coastguard Worker
1734*c8dee2aaSAndroid Build Coastguard Worker //TODO: create glyph only fonts
1735*c8dee2aaSAndroid Build Coastguard Worker //and let the host deal with what kind of font we're looking at.
1736*c8dee2aaSAndroid Build Coastguard Worker XPS_FONT_EMBEDDING embedding = XPS_FONT_EMBEDDING_RESTRICTED;
1737*c8dee2aaSAndroid Build Coastguard Worker
1738*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IStream> fontStream;
1739*c8dee2aaSAndroid Build Coastguard Worker int ttcIndex;
1740*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkStreamAsset> fontData = typeface->openStream(&ttcIndex);
1741*c8dee2aaSAndroid Build Coastguard Worker if (!fontData) {
1742*c8dee2aaSAndroid Build Coastguard Worker return E_NOTIMPL;
1743*c8dee2aaSAndroid Build Coastguard Worker }
1744*c8dee2aaSAndroid Build Coastguard Worker //TODO: cannot handle FON fonts.
1745*c8dee2aaSAndroid Build Coastguard Worker HRM(SkIStream::CreateFromSkStream(fontData->duplicate(), &fontStream),
1746*c8dee2aaSAndroid Build Coastguard Worker "Could not create font stream.");
1747*c8dee2aaSAndroid Build Coastguard Worker
1748*c8dee2aaSAndroid Build Coastguard Worker const size_t size =
1749*c8dee2aaSAndroid Build Coastguard Worker std::size(L"/Resources/Fonts/" L_GUID_ID L".odttf");
1750*c8dee2aaSAndroid Build Coastguard Worker wchar_t buffer[size];
1751*c8dee2aaSAndroid Build Coastguard Worker wchar_t id[GUID_ID_LEN];
1752*c8dee2aaSAndroid Build Coastguard Worker HR(this->createId(id, GUID_ID_LEN));
1753*c8dee2aaSAndroid Build Coastguard Worker swprintf_s(buffer, size, L"/Resources/Fonts/%s.odttf", id);
1754*c8dee2aaSAndroid Build Coastguard Worker
1755*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IOpcPartUri> partUri;
1756*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreatePartUri(buffer, &partUri),
1757*c8dee2aaSAndroid Build Coastguard Worker "Could not create font resource part uri.");
1758*c8dee2aaSAndroid Build Coastguard Worker
1759*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMFontResource> xpsFontResource;
1760*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreateFontResource(fontStream.get(),
1761*c8dee2aaSAndroid Build Coastguard Worker embedding,
1762*c8dee2aaSAndroid Build Coastguard Worker partUri.get(),
1763*c8dee2aaSAndroid Build Coastguard Worker FALSE,
1764*c8dee2aaSAndroid Build Coastguard Worker &xpsFontResource),
1765*c8dee2aaSAndroid Build Coastguard Worker "Could not create font resource.");
1766*c8dee2aaSAndroid Build Coastguard Worker
1767*c8dee2aaSAndroid Build Coastguard Worker //TODO: change openStream to return -1 for non-ttc, get rid of this.
1768*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* data = (const uint8_t*)fontData->getMemoryBase();
1769*c8dee2aaSAndroid Build Coastguard Worker bool isTTC = (data &&
1770*c8dee2aaSAndroid Build Coastguard Worker fontData->getLength() >= sizeof(SkTTCFHeader) &&
1771*c8dee2aaSAndroid Build Coastguard Worker ((const SkTTCFHeader*)data)->ttcTag == SkTTCFHeader::TAG);
1772*c8dee2aaSAndroid Build Coastguard Worker
1773*c8dee2aaSAndroid Build Coastguard Worker int glyphCount = typeface->countGlyphs();
1774*c8dee2aaSAndroid Build Coastguard Worker
1775*c8dee2aaSAndroid Build Coastguard Worker TypefaceUse& newTypefaceUse = this->fTopTypefaces->emplace_back(
1776*c8dee2aaSAndroid Build Coastguard Worker typefaceID,
1777*c8dee2aaSAndroid Build Coastguard Worker isTTC ? ttcIndex : -1,
1778*c8dee2aaSAndroid Build Coastguard Worker std::move(fontData),
1779*c8dee2aaSAndroid Build Coastguard Worker std::move(xpsFontResource),
1780*c8dee2aaSAndroid Build Coastguard Worker glyphCount);
1781*c8dee2aaSAndroid Build Coastguard Worker
1782*c8dee2aaSAndroid Build Coastguard Worker *typefaceUse = &newTypefaceUse;
1783*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
1784*c8dee2aaSAndroid Build Coastguard Worker }
1785*c8dee2aaSAndroid Build Coastguard Worker
AddGlyphs(IXpsOMObjectFactory * xpsFactory,IXpsOMCanvas * canvas,const TypefaceUse * font,LPCWSTR text,XPS_GLYPH_INDEX * xpsGlyphs,UINT32 xpsGlyphsLen,XPS_POINT * origin,FLOAT fontSize,XPS_STYLE_SIMULATION sims,const SkMatrix & transform,const SkPaint & paint)1786*c8dee2aaSAndroid Build Coastguard Worker HRESULT SkXPSDevice::AddGlyphs(IXpsOMObjectFactory* xpsFactory,
1787*c8dee2aaSAndroid Build Coastguard Worker IXpsOMCanvas* canvas,
1788*c8dee2aaSAndroid Build Coastguard Worker const TypefaceUse* font,
1789*c8dee2aaSAndroid Build Coastguard Worker LPCWSTR text,
1790*c8dee2aaSAndroid Build Coastguard Worker XPS_GLYPH_INDEX* xpsGlyphs,
1791*c8dee2aaSAndroid Build Coastguard Worker UINT32 xpsGlyphsLen,
1792*c8dee2aaSAndroid Build Coastguard Worker XPS_POINT *origin,
1793*c8dee2aaSAndroid Build Coastguard Worker FLOAT fontSize,
1794*c8dee2aaSAndroid Build Coastguard Worker XPS_STYLE_SIMULATION sims,
1795*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& transform,
1796*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint) {
1797*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGlyphs> glyphs;
1798*c8dee2aaSAndroid Build Coastguard Worker HRM(xpsFactory->CreateGlyphs(font->xpsFont.get(), &glyphs), "Could not create glyphs.");
1799*c8dee2aaSAndroid Build Coastguard Worker HRM(glyphs->SetFontFaceIndex(font->ttcIndex), "Could not set glyph font face index.");
1800*c8dee2aaSAndroid Build Coastguard Worker
1801*c8dee2aaSAndroid Build Coastguard Worker //XPS uses affine transformations for everything...
1802*c8dee2aaSAndroid Build Coastguard Worker //...except positioning text.
1803*c8dee2aaSAndroid Build Coastguard Worker bool useCanvasForClip;
1804*c8dee2aaSAndroid Build Coastguard Worker if (transform.isTranslate()) {
1805*c8dee2aaSAndroid Build Coastguard Worker origin->x += SkScalarToFLOAT(transform.getTranslateX());
1806*c8dee2aaSAndroid Build Coastguard Worker origin->y += SkScalarToFLOAT(transform.getTranslateY());
1807*c8dee2aaSAndroid Build Coastguard Worker useCanvasForClip = false;
1808*c8dee2aaSAndroid Build Coastguard Worker } else {
1809*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMMatrixTransform> xpsMatrixToUse;
1810*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsTransform(transform, &xpsMatrixToUse));
1811*c8dee2aaSAndroid Build Coastguard Worker if (xpsMatrixToUse.get()) {
1812*c8dee2aaSAndroid Build Coastguard Worker HRM(glyphs->SetTransformLocal(xpsMatrixToUse.get()),
1813*c8dee2aaSAndroid Build Coastguard Worker "Could not set transform matrix.");
1814*c8dee2aaSAndroid Build Coastguard Worker useCanvasForClip = true;
1815*c8dee2aaSAndroid Build Coastguard Worker } else {
1816*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("Attempt to add glyphs in perspective.");
1817*c8dee2aaSAndroid Build Coastguard Worker useCanvasForClip = false;
1818*c8dee2aaSAndroid Build Coastguard Worker }
1819*c8dee2aaSAndroid Build Coastguard Worker }
1820*c8dee2aaSAndroid Build Coastguard Worker
1821*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMGlyphsEditor> glyphsEditor;
1822*c8dee2aaSAndroid Build Coastguard Worker HRM(glyphs->GetGlyphsEditor(&glyphsEditor), "Could not get glyph editor.");
1823*c8dee2aaSAndroid Build Coastguard Worker
1824*c8dee2aaSAndroid Build Coastguard Worker if (text) {
1825*c8dee2aaSAndroid Build Coastguard Worker HRM(glyphsEditor->SetUnicodeString(text),
1826*c8dee2aaSAndroid Build Coastguard Worker "Could not set unicode string.");
1827*c8dee2aaSAndroid Build Coastguard Worker }
1828*c8dee2aaSAndroid Build Coastguard Worker
1829*c8dee2aaSAndroid Build Coastguard Worker if (xpsGlyphs) {
1830*c8dee2aaSAndroid Build Coastguard Worker HRM(glyphsEditor->SetGlyphIndices(xpsGlyphsLen, xpsGlyphs),
1831*c8dee2aaSAndroid Build Coastguard Worker "Could not set glyphs.");
1832*c8dee2aaSAndroid Build Coastguard Worker }
1833*c8dee2aaSAndroid Build Coastguard Worker
1834*c8dee2aaSAndroid Build Coastguard Worker HRM(glyphsEditor->ApplyEdits(), "Could not apply glyph edits.");
1835*c8dee2aaSAndroid Build Coastguard Worker
1836*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMBrush> xpsFillBrush;
1837*c8dee2aaSAndroid Build Coastguard Worker HR(this->createXpsBrush(
1838*c8dee2aaSAndroid Build Coastguard Worker paint,
1839*c8dee2aaSAndroid Build Coastguard Worker &xpsFillBrush,
1840*c8dee2aaSAndroid Build Coastguard Worker useCanvasForClip ? nullptr : &transform));
1841*c8dee2aaSAndroid Build Coastguard Worker
1842*c8dee2aaSAndroid Build Coastguard Worker HRM(glyphs->SetFillBrushLocal(xpsFillBrush.get()),
1843*c8dee2aaSAndroid Build Coastguard Worker "Could not set fill brush.");
1844*c8dee2aaSAndroid Build Coastguard Worker
1845*c8dee2aaSAndroid Build Coastguard Worker HRM(glyphs->SetOrigin(origin), "Could not set glyph origin.");
1846*c8dee2aaSAndroid Build Coastguard Worker
1847*c8dee2aaSAndroid Build Coastguard Worker HRM(glyphs->SetFontRenderingEmSize(fontSize),
1848*c8dee2aaSAndroid Build Coastguard Worker "Could not set font size.");
1849*c8dee2aaSAndroid Build Coastguard Worker
1850*c8dee2aaSAndroid Build Coastguard Worker HRM(glyphs->SetStyleSimulations(sims),
1851*c8dee2aaSAndroid Build Coastguard Worker "Could not set style simulations.");
1852*c8dee2aaSAndroid Build Coastguard Worker
1853*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMVisualCollection> visuals;
1854*c8dee2aaSAndroid Build Coastguard Worker HRM(canvas->GetVisuals(&visuals), "Could not get glyph canvas visuals.");
1855*c8dee2aaSAndroid Build Coastguard Worker
1856*c8dee2aaSAndroid Build Coastguard Worker if (!useCanvasForClip) {
1857*c8dee2aaSAndroid Build Coastguard Worker HR(this->clip(glyphs.get()));
1858*c8dee2aaSAndroid Build Coastguard Worker HRM(visuals->Append(glyphs.get()), "Could not add glyphs to canvas.");
1859*c8dee2aaSAndroid Build Coastguard Worker } else {
1860*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMCanvas> glyphCanvas;
1861*c8dee2aaSAndroid Build Coastguard Worker HRM(this->fXpsFactory->CreateCanvas(&glyphCanvas),
1862*c8dee2aaSAndroid Build Coastguard Worker "Could not create glyph canvas.");
1863*c8dee2aaSAndroid Build Coastguard Worker
1864*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMVisualCollection> glyphCanvasVisuals;
1865*c8dee2aaSAndroid Build Coastguard Worker HRM(glyphCanvas->GetVisuals(&glyphCanvasVisuals),
1866*c8dee2aaSAndroid Build Coastguard Worker "Could not get glyph visuals collection.");
1867*c8dee2aaSAndroid Build Coastguard Worker
1868*c8dee2aaSAndroid Build Coastguard Worker HRM(glyphCanvasVisuals->Append(glyphs.get()),
1869*c8dee2aaSAndroid Build Coastguard Worker "Could not add glyphs to page.");
1870*c8dee2aaSAndroid Build Coastguard Worker HR(this->clip(glyphCanvas.get()));
1871*c8dee2aaSAndroid Build Coastguard Worker
1872*c8dee2aaSAndroid Build Coastguard Worker HRM(visuals->Append(glyphCanvas.get()),
1873*c8dee2aaSAndroid Build Coastguard Worker "Could not add glyph canvas to page.");
1874*c8dee2aaSAndroid Build Coastguard Worker }
1875*c8dee2aaSAndroid Build Coastguard Worker
1876*c8dee2aaSAndroid Build Coastguard Worker return S_OK;
1877*c8dee2aaSAndroid Build Coastguard Worker }
1878*c8dee2aaSAndroid Build Coastguard Worker
text_must_be_pathed(const SkPaint & paint,const SkMatrix & matrix)1879*c8dee2aaSAndroid Build Coastguard Worker static bool text_must_be_pathed(const SkPaint& paint, const SkMatrix& matrix) {
1880*c8dee2aaSAndroid Build Coastguard Worker const SkPaint::Style style = paint.getStyle();
1881*c8dee2aaSAndroid Build Coastguard Worker return matrix.hasPerspective()
1882*c8dee2aaSAndroid Build Coastguard Worker || SkPaint::kStroke_Style == style
1883*c8dee2aaSAndroid Build Coastguard Worker || SkPaint::kStrokeAndFill_Style == style
1884*c8dee2aaSAndroid Build Coastguard Worker || paint.getMaskFilter()
1885*c8dee2aaSAndroid Build Coastguard Worker ;
1886*c8dee2aaSAndroid Build Coastguard Worker }
1887*c8dee2aaSAndroid Build Coastguard Worker
onDrawGlyphRunList(SkCanvas *,const sktext::GlyphRunList & glyphRunList,const SkPaint & paint)1888*c8dee2aaSAndroid Build Coastguard Worker void SkXPSDevice::onDrawGlyphRunList(SkCanvas*,
1889*c8dee2aaSAndroid Build Coastguard Worker const sktext::GlyphRunList& glyphRunList,
1890*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint) {
1891*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!glyphRunList.hasRSXForm());
1892*c8dee2aaSAndroid Build Coastguard Worker
1893*c8dee2aaSAndroid Build Coastguard Worker for (const auto& run : glyphRunList) {
1894*c8dee2aaSAndroid Build Coastguard Worker const SkGlyphID* glyphIDs = run.glyphsIDs().data();
1895*c8dee2aaSAndroid Build Coastguard Worker size_t glyphCount = run.glyphsIDs().size();
1896*c8dee2aaSAndroid Build Coastguard Worker const SkFont& font = run.font();
1897*c8dee2aaSAndroid Build Coastguard Worker
1898*c8dee2aaSAndroid Build Coastguard Worker if (!glyphCount || !glyphIDs || font.getSize() <= 0) {
1899*c8dee2aaSAndroid Build Coastguard Worker continue;
1900*c8dee2aaSAndroid Build Coastguard Worker }
1901*c8dee2aaSAndroid Build Coastguard Worker
1902*c8dee2aaSAndroid Build Coastguard Worker TypefaceUse* typeface;
1903*c8dee2aaSAndroid Build Coastguard Worker if (FAILED(CreateTypefaceUse(font, &typeface)) ||
1904*c8dee2aaSAndroid Build Coastguard Worker text_must_be_pathed(paint, this->localToDevice())) {
1905*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
1906*c8dee2aaSAndroid Build Coastguard Worker //TODO: make this work, Draw currently does not handle as well.
1907*c8dee2aaSAndroid Build Coastguard Worker //paint.getTextPath(text, byteLength, x, y, &path);
1908*c8dee2aaSAndroid Build Coastguard Worker //this->drawPath(path, paint, nullptr, true);
1909*c8dee2aaSAndroid Build Coastguard Worker //TODO: add automation "text"
1910*c8dee2aaSAndroid Build Coastguard Worker continue;
1911*c8dee2aaSAndroid Build Coastguard Worker }
1912*c8dee2aaSAndroid Build Coastguard Worker
1913*c8dee2aaSAndroid Build Coastguard Worker //TODO: handle font scale and skew in x (text_scale_skew)
1914*c8dee2aaSAndroid Build Coastguard Worker
1915*c8dee2aaSAndroid Build Coastguard Worker // Advance width and offsets for glyphs measured in hundredths of the font em size
1916*c8dee2aaSAndroid Build Coastguard Worker // (XPS Spec 5.1.3).
1917*c8dee2aaSAndroid Build Coastguard Worker FLOAT centemPerUnit = 100.0f / SkScalarToFLOAT(font.getSize());
1918*c8dee2aaSAndroid Build Coastguard Worker AutoSTMalloc<32, XPS_GLYPH_INDEX> xpsGlyphs(glyphCount);
1919*c8dee2aaSAndroid Build Coastguard Worker size_t numGlyphs = typeface->glyphsUsed.size();
1920*c8dee2aaSAndroid Build Coastguard Worker size_t actualGlyphCount = 0;
1921*c8dee2aaSAndroid Build Coastguard Worker
1922*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < glyphCount; ++i) {
1923*c8dee2aaSAndroid Build Coastguard Worker if (numGlyphs <= glyphIDs[i]) {
1924*c8dee2aaSAndroid Build Coastguard Worker continue;
1925*c8dee2aaSAndroid Build Coastguard Worker }
1926*c8dee2aaSAndroid Build Coastguard Worker const SkPoint& position = run.positions()[i];
1927*c8dee2aaSAndroid Build Coastguard Worker XPS_GLYPH_INDEX& xpsGlyph = xpsGlyphs[actualGlyphCount++];
1928*c8dee2aaSAndroid Build Coastguard Worker xpsGlyph.index = glyphIDs[i];
1929*c8dee2aaSAndroid Build Coastguard Worker xpsGlyph.advanceWidth = 0.0f;
1930*c8dee2aaSAndroid Build Coastguard Worker xpsGlyph.horizontalOffset = (SkScalarToFloat(position.fX) * centemPerUnit);
1931*c8dee2aaSAndroid Build Coastguard Worker xpsGlyph.verticalOffset = (SkScalarToFloat(position.fY) * -centemPerUnit);
1932*c8dee2aaSAndroid Build Coastguard Worker typeface->glyphsUsed.set(xpsGlyph.index);
1933*c8dee2aaSAndroid Build Coastguard Worker }
1934*c8dee2aaSAndroid Build Coastguard Worker
1935*c8dee2aaSAndroid Build Coastguard Worker if (actualGlyphCount == 0) {
1936*c8dee2aaSAndroid Build Coastguard Worker return;
1937*c8dee2aaSAndroid Build Coastguard Worker }
1938*c8dee2aaSAndroid Build Coastguard Worker
1939*c8dee2aaSAndroid Build Coastguard Worker XPS_POINT origin = {
1940*c8dee2aaSAndroid Build Coastguard Worker glyphRunList.origin().x(),
1941*c8dee2aaSAndroid Build Coastguard Worker glyphRunList.origin().y(),
1942*c8dee2aaSAndroid Build Coastguard Worker };
1943*c8dee2aaSAndroid Build Coastguard Worker
1944*c8dee2aaSAndroid Build Coastguard Worker HRV(AddGlyphs(this->fXpsFactory.get(),
1945*c8dee2aaSAndroid Build Coastguard Worker this->fCurrentXpsCanvas.get(),
1946*c8dee2aaSAndroid Build Coastguard Worker typeface,
1947*c8dee2aaSAndroid Build Coastguard Worker nullptr,
1948*c8dee2aaSAndroid Build Coastguard Worker xpsGlyphs.get(), actualGlyphCount,
1949*c8dee2aaSAndroid Build Coastguard Worker &origin,
1950*c8dee2aaSAndroid Build Coastguard Worker SkScalarToFLOAT(font.getSize()),
1951*c8dee2aaSAndroid Build Coastguard Worker XPS_STYLE_SIMULATION_NONE,
1952*c8dee2aaSAndroid Build Coastguard Worker this->localToDevice(),
1953*c8dee2aaSAndroid Build Coastguard Worker paint));
1954*c8dee2aaSAndroid Build Coastguard Worker }
1955*c8dee2aaSAndroid Build Coastguard Worker }
1956*c8dee2aaSAndroid Build Coastguard Worker
drawDevice(SkDevice * dev,const SkSamplingOptions &,const SkPaint &)1957*c8dee2aaSAndroid Build Coastguard Worker void SkXPSDevice::drawDevice(SkDevice* dev, const SkSamplingOptions&, const SkPaint&) {
1958*c8dee2aaSAndroid Build Coastguard Worker SkXPSDevice* that = static_cast<SkXPSDevice*>(dev);
1959*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(that->fTopTypefaces == this->fTopTypefaces);
1960*c8dee2aaSAndroid Build Coastguard Worker
1961*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform;
1962*c8dee2aaSAndroid Build Coastguard Worker HRVM(this->createXpsTransform(dev->getRelativeTransform(*this), &xpsTransform),
1963*c8dee2aaSAndroid Build Coastguard Worker "Could not create layer transform.");
1964*c8dee2aaSAndroid Build Coastguard Worker HRVM(that->fCurrentXpsCanvas->SetTransformLocal(xpsTransform.get()),
1965*c8dee2aaSAndroid Build Coastguard Worker "Could not set layer transform.");
1966*c8dee2aaSAndroid Build Coastguard Worker
1967*c8dee2aaSAndroid Build Coastguard Worker //Get the current visual collection and add the layer to it.
1968*c8dee2aaSAndroid Build Coastguard Worker SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals;
1969*c8dee2aaSAndroid Build Coastguard Worker HRVM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals),
1970*c8dee2aaSAndroid Build Coastguard Worker "Could not get current visuals for layer.");
1971*c8dee2aaSAndroid Build Coastguard Worker HRVM(currentVisuals->Append(that->fCurrentXpsCanvas.get()),
1972*c8dee2aaSAndroid Build Coastguard Worker "Could not add layer to current visuals.");
1973*c8dee2aaSAndroid Build Coastguard Worker }
1974*c8dee2aaSAndroid Build Coastguard Worker
createDevice(const CreateInfo & info,const SkPaint *)1975*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkDevice> SkXPSDevice::createDevice(const CreateInfo& info, const SkPaint*) {
1976*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkXPSDevice> dev = sk_make_sp<SkXPSDevice>(info.fInfo.dimensions());
1977*c8dee2aaSAndroid Build Coastguard Worker dev->fXpsFactory.reset(SkRefComPtr(fXpsFactory.get()));
1978*c8dee2aaSAndroid Build Coastguard Worker dev->fCurrentCanvasSize = this->fCurrentCanvasSize;
1979*c8dee2aaSAndroid Build Coastguard Worker dev->fCurrentUnitsPerMeter = this->fCurrentUnitsPerMeter;
1980*c8dee2aaSAndroid Build Coastguard Worker dev->fCurrentPixelsPerMeter = this->fCurrentPixelsPerMeter;
1981*c8dee2aaSAndroid Build Coastguard Worker dev->fTopTypefaces = this->fTopTypefaces;
1982*c8dee2aaSAndroid Build Coastguard Worker SkAssertResult(dev->createCanvasForLayer());
1983*c8dee2aaSAndroid Build Coastguard Worker return dev;
1984*c8dee2aaSAndroid Build Coastguard Worker }
1985*c8dee2aaSAndroid Build Coastguard Worker
drawOval(const SkRect & o,const SkPaint & p)1986*c8dee2aaSAndroid Build Coastguard Worker void SkXPSDevice::drawOval( const SkRect& o, const SkPaint& p) {
1987*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
1988*c8dee2aaSAndroid Build Coastguard Worker path.addOval(o);
1989*c8dee2aaSAndroid Build Coastguard Worker this->drawPath(path, p, true);
1990*c8dee2aaSAndroid Build Coastguard Worker }
1991*c8dee2aaSAndroid Build Coastguard Worker
drawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint)1992*c8dee2aaSAndroid Build Coastguard Worker void SkXPSDevice::drawImageRect(const SkImage* image,
1993*c8dee2aaSAndroid Build Coastguard Worker const SkRect* src,
1994*c8dee2aaSAndroid Build Coastguard Worker const SkRect& dst,
1995*c8dee2aaSAndroid Build Coastguard Worker const SkSamplingOptions& sampling,
1996*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint,
1997*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::SrcRectConstraint constraint) {
1998*c8dee2aaSAndroid Build Coastguard Worker // TODO: support gpu images
1999*c8dee2aaSAndroid Build Coastguard Worker SkBitmap bitmap;
2000*c8dee2aaSAndroid Build Coastguard Worker if (!as_IB(image)->getROPixels(nullptr, &bitmap)) {
2001*c8dee2aaSAndroid Build Coastguard Worker return;
2002*c8dee2aaSAndroid Build Coastguard Worker }
2003*c8dee2aaSAndroid Build Coastguard Worker
2004*c8dee2aaSAndroid Build Coastguard Worker SkRect bitmapBounds = SkRect::Make(bitmap.bounds());
2005*c8dee2aaSAndroid Build Coastguard Worker SkRect srcBounds = src ? *src : bitmapBounds;
2006*c8dee2aaSAndroid Build Coastguard Worker SkMatrix matrix = SkMatrix::RectToRect(srcBounds, dst);
2007*c8dee2aaSAndroid Build Coastguard Worker SkRect actualDst;
2008*c8dee2aaSAndroid Build Coastguard Worker if (!src || bitmapBounds.contains(*src)) {
2009*c8dee2aaSAndroid Build Coastguard Worker actualDst = dst;
2010*c8dee2aaSAndroid Build Coastguard Worker } else {
2011*c8dee2aaSAndroid Build Coastguard Worker if (!srcBounds.intersect(bitmapBounds)) {
2012*c8dee2aaSAndroid Build Coastguard Worker return;
2013*c8dee2aaSAndroid Build Coastguard Worker }
2014*c8dee2aaSAndroid Build Coastguard Worker matrix.mapRect(&actualDst, srcBounds);
2015*c8dee2aaSAndroid Build Coastguard Worker }
2016*c8dee2aaSAndroid Build Coastguard Worker
2017*c8dee2aaSAndroid Build Coastguard Worker auto bitmapShader = SkMakeBitmapShaderForPaint(paint, bitmap,
2018*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp, SkTileMode::kClamp,
2019*c8dee2aaSAndroid Build Coastguard Worker sampling, &matrix, kNever_SkCopyPixelsMode);
2020*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(bitmapShader);
2021*c8dee2aaSAndroid Build Coastguard Worker if (!bitmapShader) { return; }
2022*c8dee2aaSAndroid Build Coastguard Worker SkPaint paintWithShader(paint);
2023*c8dee2aaSAndroid Build Coastguard Worker paintWithShader.setStyle(SkPaint::kFill_Style);
2024*c8dee2aaSAndroid Build Coastguard Worker paintWithShader.setShader(std::move(bitmapShader));
2025*c8dee2aaSAndroid Build Coastguard Worker this->drawRect(actualDst, paintWithShader);
2026*c8dee2aaSAndroid Build Coastguard Worker }
2027*c8dee2aaSAndroid Build Coastguard Worker #endif//defined(SK_BUILD_FOR_WIN)
2028