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