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