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