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