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