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