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