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 SkAutoLockPixels alp(bitmap); 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, SkImage::kRO_LegacyBitmapMode)) { 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 paint.getRasterizer() || 1082 (stroke && ( 1083 (matrix.hasPerspective() && !zeroWidth) || 1084 SkPaint::kMiter_Join != paint.getStrokeJoin() || 1085 (SkPaint::kMiter_Join == paint.getStrokeJoin() && 1086 paint.getStrokeMiter() < SK_ScalarSqrt2) 1087 )) 1088 ; 1089 } 1090 1091 HRESULT SkXPSDevice::createXpsRect(const SkRect& rect, BOOL stroke, BOOL fill, 1092 IXpsOMGeometryFigure** xpsRect) { 1093 const SkPoint points[4] = { 1094 { rect.fLeft, rect.fTop }, 1095 { rect.fRight, rect.fTop }, 1096 { rect.fRight, rect.fBottom }, 1097 { rect.fLeft, rect.fBottom }, 1098 }; 1099 return this->createXpsQuad(points, stroke, fill, xpsRect); 1100 } 1101 HRESULT SkXPSDevice::createXpsQuad(const SkPoint (&points)[4], 1102 BOOL stroke, BOOL fill, 1103 IXpsOMGeometryFigure** xpsQuad) { 1104 // Define the start point. 1105 XPS_POINT startPoint = xps_point(points[0]); 1106 1107 // Create the figure. 1108 HRM(this->fXpsFactory->CreateGeometryFigure(&startPoint, xpsQuad), 1109 "Could not create quad geometry figure."); 1110 1111 // Define the type of each segment. 1112 XPS_SEGMENT_TYPE segmentTypes[3] = { 1113 XPS_SEGMENT_TYPE_LINE, 1114 XPS_SEGMENT_TYPE_LINE, 1115 XPS_SEGMENT_TYPE_LINE, 1116 }; 1117 1118 // Define the x and y coordinates of each corner of the figure. 1119 FLOAT segmentData[6] = { 1120 SkScalarToFLOAT(points[1].fX), SkScalarToFLOAT(points[1].fY), 1121 SkScalarToFLOAT(points[2].fX), SkScalarToFLOAT(points[2].fY), 1122 SkScalarToFLOAT(points[3].fX), SkScalarToFLOAT(points[3].fY), 1123 }; 1124 1125 // Describe if the segments are stroked. 1126 BOOL segmentStrokes[3] = { 1127 stroke, stroke, stroke, 1128 }; 1129 1130 // Add the segment data to the figure. 1131 HRM((*xpsQuad)->SetSegments( 1132 3, 6, 1133 segmentTypes , segmentData, segmentStrokes), 1134 "Could not add segment data to quad."); 1135 1136 // Set the closed and filled properties of the figure. 1137 HRM((*xpsQuad)->SetIsClosed(stroke), "Could not set quad close."); 1138 HRM((*xpsQuad)->SetIsFilled(fill), "Could not set quad fill."); 1139 1140 return S_OK; 1141 } 1142 1143 template <typename F, typename... Args> 1144 void draw(SkClipStackDevice* dev, F f, Args&&... args) { 1145 SkIRect r = dev->devClipBounds(); 1146 SkRasterClip rc(r); 1147 SkDraw draw; 1148 draw.fMatrix = &dev->ctm(); 1149 draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(r.right(), r.bottom()), nullptr, 0); 1150 draw.fRC = &rc; 1151 (draw.*f)(std::forward<Args>(args)...); 1152 } 1153 1154 1155 void SkXPSDevice::drawPoints(SkCanvas::PointMode mode, 1156 size_t count, const SkPoint points[], 1157 const SkPaint& paint) { 1158 draw(this, &SkDraw::drawPoints, mode, count, points, paint, this); 1159 } 1160 1161 void SkXPSDevice::drawVertices(const SkVertices* v, SkBlendMode blendMode, const SkPaint& paint) { 1162 draw(this, &SkDraw::drawVertices, v->mode(), v->vertexCount(), v->positions(), v->texCoords(), 1163 v->colors(), blendMode, v->indices(), v->indexCount(), paint); 1164 } 1165 1166 void SkXPSDevice::drawPaint(const SkPaint& origPaint) { 1167 const SkRect r = SkRect::MakeSize(this->fCurrentCanvasSize); 1168 1169 //If trying to paint with a stroke, ignore that and fill. 1170 SkPaint* fillPaint = const_cast<SkPaint*>(&origPaint); 1171 SkTCopyOnFirstWrite<SkPaint> paint(origPaint); 1172 if (paint->getStyle() != SkPaint::kFill_Style) { 1173 paint.writable()->setStyle(SkPaint::kFill_Style); 1174 } 1175 1176 this->internalDrawRect(r, false, *fillPaint); 1177 } 1178 1179 void SkXPSDevice::drawRect(const SkRect& r, 1180 const SkPaint& paint) { 1181 this->internalDrawRect(r, true, paint); 1182 } 1183 1184 void SkXPSDevice::drawRRect(const SkRRect& rr, 1185 const SkPaint& paint) { 1186 SkPath path; 1187 path.addRRect(rr); 1188 this->drawPath(path, paint, nullptr, true); 1189 } 1190 1191 static SkIRect size(const SkBaseDevice& dev) { return {0, 0, dev.width(), dev.height()}; } 1192 1193 void SkXPSDevice::internalDrawRect(const SkRect& r, 1194 bool transformRect, 1195 const SkPaint& paint) { 1196 //Exit early if there is nothing to draw. 1197 if (this->cs().isEmpty(size(*this)) || 1198 (paint.getAlpha() == 0 && paint.isSrcOver())) { 1199 return; 1200 } 1201 1202 //Path the rect if we can't optimize it. 1203 if (rect_must_be_pathed(paint, this->ctm())) { 1204 SkPath tmp; 1205 tmp.addRect(r); 1206 tmp.setFillType(SkPath::kWinding_FillType); 1207 this->drawPath(tmp, paint, nullptr, true); 1208 return; 1209 } 1210 1211 //Create the shaded path. 1212 SkTScopedComPtr<IXpsOMPath> shadedPath; 1213 HRVM(this->fXpsFactory->CreatePath(&shadedPath), 1214 "Could not create shaded path for rect."); 1215 1216 //Create the shaded geometry. 1217 SkTScopedComPtr<IXpsOMGeometry> shadedGeometry; 1218 HRVM(this->fXpsFactory->CreateGeometry(&shadedGeometry), 1219 "Could not create shaded geometry for rect."); 1220 1221 //Add the geometry to the shaded path. 1222 HRVM(shadedPath->SetGeometryLocal(shadedGeometry.get()), 1223 "Could not set shaded geometry for rect."); 1224 1225 //Set the brushes. 1226 BOOL fill = FALSE; 1227 BOOL stroke = FALSE; 1228 HRV(this->shadePath(shadedPath.get(), paint, this->ctm(), &fill, &stroke)); 1229 1230 bool xpsTransformsPath = true; 1231 //Transform the geometry. 1232 if (transformRect && xpsTransformsPath) { 1233 SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform; 1234 HRV(this->createXpsTransform(this->ctm(), &xpsTransform)); 1235 if (xpsTransform.get()) { 1236 HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()), 1237 "Could not set transform for rect."); 1238 } else { 1239 xpsTransformsPath = false; 1240 } 1241 } 1242 1243 //Create the figure. 1244 SkTScopedComPtr<IXpsOMGeometryFigure> rectFigure; 1245 { 1246 SkPoint points[4] = { 1247 { r.fLeft, r.fTop }, 1248 { r.fLeft, r.fBottom }, 1249 { r.fRight, r.fBottom }, 1250 { r.fRight, r.fTop }, 1251 }; 1252 if (!xpsTransformsPath && transformRect) { 1253 this->ctm().mapPoints(points, SK_ARRAY_COUNT(points)); 1254 } 1255 HRV(this->createXpsQuad(points, stroke, fill, &rectFigure)); 1256 } 1257 1258 //Get the figures of the shaded geometry. 1259 SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures; 1260 HRVM(shadedGeometry->GetFigures(&shadedFigures), 1261 "Could not get shaded figures for rect."); 1262 1263 //Add the figure to the shaded geometry figures. 1264 HRVM(shadedFigures->Append(rectFigure.get()), 1265 "Could not add shaded figure for rect."); 1266 1267 HRV(this->clip(shadedPath.get())); 1268 1269 //Add the shaded path to the current visuals. 1270 SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals; 1271 HRVM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals), 1272 "Could not get current visuals for rect."); 1273 HRVM(currentVisuals->Append(shadedPath.get()), 1274 "Could not add rect to current visuals."); 1275 } 1276 1277 static HRESULT close_figure(const SkTDArray<XPS_SEGMENT_TYPE>& segmentTypes, 1278 const SkTDArray<BOOL>& segmentStrokes, 1279 const SkTDArray<FLOAT>& segmentData, 1280 BOOL stroke, BOOL fill, 1281 IXpsOMGeometryFigure* figure, 1282 IXpsOMGeometryFigureCollection* figures) { 1283 // Add the segment data to the figure. 1284 HRM(figure->SetSegments(segmentTypes.count(), segmentData.count(), 1285 segmentTypes.begin() , segmentData.begin(), 1286 segmentStrokes.begin()), 1287 "Could not set path segments."); 1288 1289 // Set the closed and filled properties of the figure. 1290 HRM(figure->SetIsClosed(stroke), "Could not set path closed."); 1291 HRM(figure->SetIsFilled(fill), "Could not set path fill."); 1292 1293 // Add the figure created above to this geometry. 1294 HRM(figures->Append(figure), "Could not add path to geometry."); 1295 return S_OK; 1296 } 1297 1298 HRESULT SkXPSDevice::addXpsPathGeometry( 1299 IXpsOMGeometryFigureCollection* xpsFigures, 1300 BOOL stroke, BOOL fill, const SkPath& path) { 1301 SkTDArray<XPS_SEGMENT_TYPE> segmentTypes; 1302 SkTDArray<BOOL> segmentStrokes; 1303 SkTDArray<FLOAT> segmentData; 1304 1305 SkTScopedComPtr<IXpsOMGeometryFigure> xpsFigure; 1306 SkPath::Iter iter(path, true); 1307 SkPoint points[4]; 1308 SkPath::Verb verb; 1309 while ((verb = iter.next(points)) != SkPath::kDone_Verb) { 1310 switch (verb) { 1311 case SkPath::kMove_Verb: { 1312 if (xpsFigure.get()) { 1313 HR(close_figure(segmentTypes, segmentStrokes, segmentData, 1314 stroke, fill, 1315 xpsFigure.get() , xpsFigures)); 1316 xpsFigure.reset(); 1317 segmentTypes.rewind(); 1318 segmentStrokes.rewind(); 1319 segmentData.rewind(); 1320 } 1321 // Define the start point. 1322 XPS_POINT startPoint = xps_point(points[0]); 1323 // Create the figure. 1324 HRM(this->fXpsFactory->CreateGeometryFigure(&startPoint, 1325 &xpsFigure), 1326 "Could not create path geometry figure."); 1327 break; 1328 } 1329 case SkPath::kLine_Verb: 1330 if (iter.isCloseLine()) break; //ignore the line, auto-closed 1331 segmentTypes.push(XPS_SEGMENT_TYPE_LINE); 1332 segmentStrokes.push(stroke); 1333 segmentData.push(SkScalarToFLOAT(points[1].fX)); 1334 segmentData.push(SkScalarToFLOAT(points[1].fY)); 1335 break; 1336 case SkPath::kQuad_Verb: 1337 segmentTypes.push(XPS_SEGMENT_TYPE_QUADRATIC_BEZIER); 1338 segmentStrokes.push(stroke); 1339 segmentData.push(SkScalarToFLOAT(points[1].fX)); 1340 segmentData.push(SkScalarToFLOAT(points[1].fY)); 1341 segmentData.push(SkScalarToFLOAT(points[2].fX)); 1342 segmentData.push(SkScalarToFLOAT(points[2].fY)); 1343 break; 1344 case SkPath::kCubic_Verb: 1345 segmentTypes.push(XPS_SEGMENT_TYPE_BEZIER); 1346 segmentStrokes.push(stroke); 1347 segmentData.push(SkScalarToFLOAT(points[1].fX)); 1348 segmentData.push(SkScalarToFLOAT(points[1].fY)); 1349 segmentData.push(SkScalarToFLOAT(points[2].fX)); 1350 segmentData.push(SkScalarToFLOAT(points[2].fY)); 1351 segmentData.push(SkScalarToFLOAT(points[3].fX)); 1352 segmentData.push(SkScalarToFLOAT(points[3].fY)); 1353 break; 1354 case SkPath::kConic_Verb: { 1355 const SkScalar tol = SK_Scalar1 / 4; 1356 SkAutoConicToQuads converter; 1357 const SkPoint* quads = 1358 converter.computeQuads(points, iter.conicWeight(), tol); 1359 for (int i = 0; i < converter.countQuads(); ++i) { 1360 segmentTypes.push(XPS_SEGMENT_TYPE_QUADRATIC_BEZIER); 1361 segmentStrokes.push(stroke); 1362 segmentData.push(SkScalarToFLOAT(quads[2 * i + 1].fX)); 1363 segmentData.push(SkScalarToFLOAT(quads[2 * i + 1].fY)); 1364 segmentData.push(SkScalarToFLOAT(quads[2 * i + 2].fX)); 1365 segmentData.push(SkScalarToFLOAT(quads[2 * i + 2].fY)); 1366 } 1367 break; 1368 } 1369 case SkPath::kClose_Verb: 1370 // we ignore these, and just get the whole segment from 1371 // the corresponding line/quad/cubic verbs 1372 break; 1373 default: 1374 SkDEBUGFAIL("unexpected verb"); 1375 break; 1376 } 1377 } 1378 if (xpsFigure.get()) { 1379 HR(close_figure(segmentTypes, segmentStrokes, segmentData, 1380 stroke, fill, 1381 xpsFigure.get(), xpsFigures)); 1382 } 1383 return S_OK; 1384 } 1385 1386 void SkXPSDevice::convertToPpm(const SkMaskFilter* filter, 1387 SkMatrix* matrix, 1388 SkVector* ppuScale, 1389 const SkIRect& clip, SkIRect* clipIRect) { 1390 //This action is in unit space, but the ppm is specified in physical space. 1391 ppuScale->set(fCurrentPixelsPerMeter.fX / fCurrentUnitsPerMeter.fX, 1392 fCurrentPixelsPerMeter.fY / fCurrentUnitsPerMeter.fY); 1393 1394 matrix->postScale(ppuScale->fX, ppuScale->fY); 1395 1396 const SkIRect& irect = clip; 1397 SkRect clipRect = SkRect::MakeLTRB(SkIntToScalar(irect.fLeft) * ppuScale->fX, 1398 SkIntToScalar(irect.fTop) * ppuScale->fY, 1399 SkIntToScalar(irect.fRight) * ppuScale->fX, 1400 SkIntToScalar(irect.fBottom) * ppuScale->fY); 1401 clipRect.roundOut(clipIRect); 1402 } 1403 1404 HRESULT SkXPSDevice::applyMask(const SkMask& mask, 1405 const SkVector& ppuScale, 1406 IXpsOMPath* shadedPath) { 1407 //Get the geometry object. 1408 SkTScopedComPtr<IXpsOMGeometry> shadedGeometry; 1409 HRM(shadedPath->GetGeometry(&shadedGeometry), 1410 "Could not get mask shaded geometry."); 1411 1412 //Get the figures from the geometry. 1413 SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures; 1414 HRM(shadedGeometry->GetFigures(&shadedFigures), 1415 "Could not get mask shaded figures."); 1416 1417 SkMatrix m; 1418 m.reset(); 1419 m.setTranslate(SkIntToScalar(mask.fBounds.fLeft), 1420 SkIntToScalar(mask.fBounds.fTop)); 1421 m.postScale(SkScalarInvert(ppuScale.fX), SkScalarInvert(ppuScale.fY)); 1422 1423 SkShader::TileMode xy[2]; 1424 xy[0] = (SkShader::TileMode)3; 1425 xy[1] = (SkShader::TileMode)3; 1426 1427 SkBitmap bm; 1428 bm.installMaskPixels(mask); 1429 1430 SkTScopedComPtr<IXpsOMTileBrush> maskBrush; 1431 HR(this->createXpsImageBrush(bm, m, xy, 0xFF, &maskBrush)); 1432 HRM(shadedPath->SetOpacityMaskBrushLocal(maskBrush.get()), 1433 "Could not set mask."); 1434 1435 const SkRect universeRect = SkRect::MakeLTRB(0, 0, 1436 this->fCurrentCanvasSize.fWidth, this->fCurrentCanvasSize.fHeight); 1437 SkTScopedComPtr<IXpsOMGeometryFigure> shadedFigure; 1438 HRM(this->createXpsRect(universeRect, FALSE, TRUE, &shadedFigure), 1439 "Could not create mask shaded figure."); 1440 HRM(shadedFigures->Append(shadedFigure.get()), 1441 "Could not add mask shaded figure."); 1442 1443 HR(this->clip(shadedPath)); 1444 1445 //Add the path to the active visual collection. 1446 SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals; 1447 HRM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals), 1448 "Could not get mask current visuals."); 1449 HRM(currentVisuals->Append(shadedPath), 1450 "Could not add masked shaded path to current visuals."); 1451 1452 return S_OK; 1453 } 1454 1455 HRESULT SkXPSDevice::shadePath(IXpsOMPath* shadedPath, 1456 const SkPaint& shaderPaint, 1457 const SkMatrix& matrix, 1458 BOOL* fill, BOOL* stroke) { 1459 *fill = FALSE; 1460 *stroke = FALSE; 1461 1462 const SkPaint::Style style = shaderPaint.getStyle(); 1463 const bool hasFill = SkPaint::kFill_Style == style 1464 || SkPaint::kStrokeAndFill_Style == style; 1465 const bool hasStroke = SkPaint::kStroke_Style == style 1466 || SkPaint::kStrokeAndFill_Style == style; 1467 1468 //TODO(bungeman): use dictionaries and lookups. 1469 if (hasFill) { 1470 *fill = TRUE; 1471 SkTScopedComPtr<IXpsOMBrush> fillBrush; 1472 HR(this->createXpsBrush(shaderPaint, &fillBrush, &matrix)); 1473 HRM(shadedPath->SetFillBrushLocal(fillBrush.get()), 1474 "Could not set fill for shaded path."); 1475 } 1476 1477 if (hasStroke) { 1478 *stroke = TRUE; 1479 SkTScopedComPtr<IXpsOMBrush> strokeBrush; 1480 HR(this->createXpsBrush(shaderPaint, &strokeBrush, &matrix)); 1481 HRM(shadedPath->SetStrokeBrushLocal(strokeBrush.get()), 1482 "Could not set stroke brush for shaded path."); 1483 HRM(shadedPath->SetStrokeThickness( 1484 SkScalarToFLOAT(shaderPaint.getStrokeWidth())), 1485 "Could not set shaded path stroke thickness."); 1486 1487 if (0 == shaderPaint.getStrokeWidth()) { 1488 //XPS hair width is a hack. (XPS Spec 11.6.12). 1489 SkTScopedComPtr<IXpsOMDashCollection> dashes; 1490 HRM(shadedPath->GetStrokeDashes(&dashes), 1491 "Could not set dashes for shaded path."); 1492 XPS_DASH dash; 1493 dash.length = 1.0; 1494 dash.gap = 0.0; 1495 HRM(dashes->Append(&dash), "Could not add dashes to shaded path."); 1496 HRM(shadedPath->SetStrokeDashOffset(-2.0), 1497 "Could not set dash offset for shaded path."); 1498 } 1499 } 1500 return S_OK; 1501 } 1502 1503 void SkXPSDevice::drawPath(const SkPath& platonicPath, 1504 const SkPaint& origPaint, 1505 const SkMatrix* prePathMatrix, 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 if (prePathMatrix) { 1523 if (paintHasPathEffect || paint->getRasterizer()) { 1524 if (!pathIsMutable) { 1525 skeletalPath = &modifiedPath; 1526 pathIsMutable = true; 1527 } 1528 platonicPath.transform(*prePathMatrix, skeletalPath); 1529 } else { 1530 matrix.preConcat(*prePathMatrix); 1531 } 1532 } 1533 1534 //Apply path effect [Skeletal-path -> Fillable-path]. 1535 SkPath* fillablePath = skeletalPath; 1536 if (paintHasPathEffect) { 1537 if (!pathIsMutable) { 1538 fillablePath = &modifiedPath; 1539 pathIsMutable = true; 1540 } 1541 bool fill = paint->getFillPath(*skeletalPath, fillablePath); 1542 1543 SkPaint* writablePaint = paint.writable(); 1544 writablePaint->setPathEffect(nullptr); 1545 if (fill) { 1546 writablePaint->setStyle(SkPaint::kFill_Style); 1547 } else { 1548 writablePaint->setStyle(SkPaint::kStroke_Style); 1549 writablePaint->setStrokeWidth(0); 1550 } 1551 } 1552 1553 //Create the shaded path. This will be the path which is painted. 1554 SkTScopedComPtr<IXpsOMPath> shadedPath; 1555 HRVM(this->fXpsFactory->CreatePath(&shadedPath), 1556 "Could not create shaded path for path."); 1557 1558 //Create the geometry for the shaded path. 1559 SkTScopedComPtr<IXpsOMGeometry> shadedGeometry; 1560 HRVM(this->fXpsFactory->CreateGeometry(&shadedGeometry), 1561 "Could not create shaded geometry for path."); 1562 1563 //Add the geometry to the shaded path. 1564 HRVM(shadedPath->SetGeometryLocal(shadedGeometry.get()), 1565 "Could not add the shaded geometry to shaded path."); 1566 1567 SkRasterizer* rasterizer = paint->getRasterizer(); 1568 SkMaskFilter* filter = paint->getMaskFilter(); 1569 1570 //Determine if we will draw or shade and mask. 1571 if (rasterizer || filter) { 1572 if (paint->getStyle() != SkPaint::kFill_Style) { 1573 paint.writable()->setStyle(SkPaint::kFill_Style); 1574 } 1575 } 1576 1577 //Set the brushes. 1578 BOOL fill; 1579 BOOL stroke; 1580 HRV(this->shadePath(shadedPath.get(), 1581 *paint, 1582 this->ctm(), 1583 &fill, 1584 &stroke)); 1585 1586 //Rasterizer 1587 if (rasterizer) { 1588 SkIRect clipIRect; 1589 SkVector ppuScale; 1590 this->convertToPpm(filter, 1591 &matrix, 1592 &ppuScale, 1593 this->cs().bounds(size(*this)).roundOut(), 1594 &clipIRect); 1595 1596 SkMask* mask = nullptr; 1597 1598 //[Fillable-path -> Mask] 1599 SkMask rasteredMask; 1600 if (rasterizer->rasterize( 1601 *fillablePath, 1602 matrix, 1603 &clipIRect, 1604 filter, //just to compute how much to draw. 1605 &rasteredMask, 1606 SkMask::kComputeBoundsAndRenderImage_CreateMode)) { 1607 1608 SkAutoMaskFreeImage rasteredAmi(rasteredMask.fImage); 1609 mask = &rasteredMask; 1610 1611 //[Mask -> Mask] 1612 SkMask filteredMask; 1613 if (filter && filter->filterMask(&filteredMask, *mask, this->ctm(), nullptr)) { 1614 mask = &filteredMask; 1615 } 1616 SkAutoMaskFreeImage filteredAmi(filteredMask.fImage); 1617 1618 //Draw mask. 1619 HRV(this->applyMask(*mask, ppuScale, shadedPath.get())); 1620 } 1621 return; 1622 } 1623 1624 //Mask filter 1625 if (filter) { 1626 SkIRect clipIRect; 1627 SkVector ppuScale; 1628 this->convertToPpm(filter, 1629 &matrix, 1630 &ppuScale, 1631 this->cs().bounds(size(*this)).roundOut(), 1632 &clipIRect); 1633 1634 //[Fillable-path -> Pixel-path] 1635 SkPath* pixelPath = pathIsMutable ? fillablePath : &modifiedPath; 1636 fillablePath->transform(matrix, pixelPath); 1637 1638 SkMask* mask = nullptr; 1639 1640 SkASSERT(SkPaint::kFill_Style == paint->getStyle() || 1641 (SkPaint::kStroke_Style == paint->getStyle() && 0 == paint->getStrokeWidth())); 1642 SkStrokeRec::InitStyle style = (SkPaint::kFill_Style == paint->getStyle()) 1643 ? SkStrokeRec::kFill_InitStyle 1644 : SkStrokeRec::kHairline_InitStyle; 1645 //[Pixel-path -> Mask] 1646 SkMask rasteredMask; 1647 if (SkDraw::DrawToMask( 1648 *pixelPath, 1649 &clipIRect, 1650 filter, //just to compute how much to draw. 1651 &matrix, 1652 &rasteredMask, 1653 SkMask::kComputeBoundsAndRenderImage_CreateMode, 1654 style)) { 1655 1656 SkAutoMaskFreeImage rasteredAmi(rasteredMask.fImage); 1657 mask = &rasteredMask; 1658 1659 //[Mask -> Mask] 1660 SkMask filteredMask; 1661 if (filter->filterMask(&filteredMask, rasteredMask, matrix, nullptr)) { 1662 mask = &filteredMask; 1663 } 1664 SkAutoMaskFreeImage filteredAmi(filteredMask.fImage); 1665 1666 //Draw mask. 1667 HRV(this->applyMask(*mask, ppuScale, shadedPath.get())); 1668 } 1669 return; 1670 } 1671 1672 //Get the figures from the shaded geometry. 1673 SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures; 1674 HRVM(shadedGeometry->GetFigures(&shadedFigures), 1675 "Could not get shaded figures for shaded path."); 1676 1677 bool xpsTransformsPath = true; 1678 1679 //Set the fill rule. 1680 SkPath* xpsCompatiblePath = fillablePath; 1681 XPS_FILL_RULE xpsFillRule; 1682 switch (fillablePath->getFillType()) { 1683 case SkPath::kWinding_FillType: 1684 xpsFillRule = XPS_FILL_RULE_NONZERO; 1685 break; 1686 case SkPath::kEvenOdd_FillType: 1687 xpsFillRule = XPS_FILL_RULE_EVENODD; 1688 break; 1689 case SkPath::kInverseWinding_FillType: { 1690 //[Fillable-path (inverse winding) -> XPS-path (inverse even odd)] 1691 if (!pathIsMutable) { 1692 xpsCompatiblePath = &modifiedPath; 1693 pathIsMutable = true; 1694 } 1695 if (!Simplify(*fillablePath, xpsCompatiblePath)) { 1696 SkDEBUGF(("Could not simplify inverse winding path.")); 1697 return; 1698 } 1699 } 1700 // The xpsCompatiblePath is noW inverse even odd, so fall through. 1701 case SkPath::kInverseEvenOdd_FillType: { 1702 const SkRect universe = SkRect::MakeLTRB( 1703 0, 0, 1704 this->fCurrentCanvasSize.fWidth, 1705 this->fCurrentCanvasSize.fHeight); 1706 SkTScopedComPtr<IXpsOMGeometryFigure> addOneFigure; 1707 HRV(this->createXpsRect(universe, FALSE, TRUE, &addOneFigure)); 1708 HRVM(shadedFigures->Append(addOneFigure.get()), 1709 "Could not add even-odd flip figure to shaded path."); 1710 xpsTransformsPath = false; 1711 xpsFillRule = XPS_FILL_RULE_EVENODD; 1712 break; 1713 } 1714 default: 1715 SkDEBUGFAIL("Unknown SkPath::FillType."); 1716 } 1717 HRVM(shadedGeometry->SetFillRule(xpsFillRule), 1718 "Could not set fill rule for shaded path."); 1719 1720 //Create the XPS transform, if possible. 1721 if (xpsTransformsPath) { 1722 SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform; 1723 HRV(this->createXpsTransform(matrix, &xpsTransform)); 1724 1725 if (xpsTransform.get()) { 1726 HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()), 1727 "Could not set transform on shaded path."); 1728 } else { 1729 xpsTransformsPath = false; 1730 } 1731 } 1732 1733 SkPath* devicePath = xpsCompatiblePath; 1734 if (!xpsTransformsPath) { 1735 //[Fillable-path -> Device-path] 1736 devicePath = pathIsMutable ? xpsCompatiblePath : &modifiedPath; 1737 xpsCompatiblePath->transform(matrix, devicePath); 1738 } 1739 HRV(this->addXpsPathGeometry(shadedFigures.get(), 1740 stroke, fill, *devicePath)); 1741 1742 HRV(this->clip(shadedPath.get())); 1743 1744 //Add the path to the active visual collection. 1745 SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals; 1746 HRVM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals), 1747 "Could not get current visuals for shaded path."); 1748 HRVM(currentVisuals->Append(shadedPath.get()), 1749 "Could not add shaded path to current visuals."); 1750 } 1751 1752 HRESULT SkXPSDevice::clip(IXpsOMVisual* xpsVisual) { 1753 SkPath clipPath; 1754 // clipPath.addRect(this->cs().bounds(size(*this))); 1755 (void)this->cs().asPath(&clipPath); 1756 return this->clipToPath(xpsVisual, clipPath, XPS_FILL_RULE_EVENODD); 1757 } 1758 HRESULT SkXPSDevice::clipToPath(IXpsOMVisual* xpsVisual, 1759 const SkPath& clipPath, 1760 XPS_FILL_RULE fillRule) { 1761 //Create the geometry. 1762 SkTScopedComPtr<IXpsOMGeometry> clipGeometry; 1763 HRM(this->fXpsFactory->CreateGeometry(&clipGeometry), 1764 "Could not create clip geometry."); 1765 1766 //Get the figure collection of the geometry. 1767 SkTScopedComPtr<IXpsOMGeometryFigureCollection> clipFigures; 1768 HRM(clipGeometry->GetFigures(&clipFigures), 1769 "Could not get the clip figures."); 1770 1771 //Create the figures into the geometry. 1772 HR(this->addXpsPathGeometry( 1773 clipFigures.get(), 1774 FALSE, TRUE, clipPath)); 1775 1776 HRM(clipGeometry->SetFillRule(fillRule), 1777 "Could not set fill rule."); 1778 HRM(xpsVisual->SetClipGeometryLocal(clipGeometry.get()), 1779 "Could not set clip geometry."); 1780 1781 return S_OK; 1782 } 1783 1784 void SkXPSDevice::drawBitmap(const SkBitmap& bitmap, 1785 const SkMatrix& matrix, 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 = matrix; 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