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