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 "SkPoint.h" 34 #include "SkRasterizer.h" 35 #include "SkSFNTHeader.h" 36 #include "SkShader.h" 37 #include "SkSize.h" 38 #include "SkStream.h" 39 #include "SkTDArray.h" 40 #include "SkTLazy.h" 41 #include "SkTScopedComPtr.h" 42 #include "SkTTCFHeader.h" 43 #include "SkTypefacePriv.h" 44 #include "SkUtils.h" 45 #include "SkXPSDevice.h" 46 47 //Windows defines a FLOAT type, 48 //make it clear when converting a scalar that this is what is wanted. 49 #define SkScalarToFLOAT(n) SkScalarToFloat(n) 50 51 //Dummy representation of a GUID from create_id. 52 #define L_GUID_ID L"XXXXXXXXsXXXXsXXXXsXXXXsXXXXXXXXXXXX" 53 //Length of GUID representation from create_id, including NULL terminator. 54 #define GUID_ID_LEN SK_ARRAY_COUNT(L_GUID_ID) 55 56 /** 57 Formats a GUID and places it into buffer. 58 buffer should have space for at least GUID_ID_LEN wide characters. 59 The string will always be wchar null terminated. 60 XXXXXXXXsXXXXsXXXXsXXXXsXXXXXXXXXXXX0 61 @return -1 if there was an error, > 0 if success. 62 */ 63 static int format_guid(const GUID& guid, 64 wchar_t* buffer, size_t bufferSize, 65 wchar_t sep = '-') { 66 SkASSERT(bufferSize >= GUID_ID_LEN); 67 return swprintf_s(buffer, 68 bufferSize, 69 L"%08lX%c%04X%c%04X%c%02X%02X%c%02X%02X%02X%02X%02X%02X", 70 guid.Data1, 71 sep, 72 guid.Data2, 73 sep, 74 guid.Data3, 75 sep, 76 guid.Data4[0], 77 guid.Data4[1], 78 sep, 79 guid.Data4[2], 80 guid.Data4[3], 81 guid.Data4[4], 82 guid.Data4[5], 83 guid.Data4[6], 84 guid.Data4[7]); 85 } 86 87 /** 88 Creates a GUID based id and places it into buffer. 89 buffer should have space for at least GUID_ID_LEN wide characters. 90 The string will always be wchar null terminated. 91 XXXXXXXXsXXXXsXXXXsXXXXsXXXXXXXXXXXX0 92 The string may begin with a digit, 93 and so may not be suitable as a bare resource key. 94 */ 95 static HRESULT create_id(wchar_t* buffer, size_t bufferSize, 96 wchar_t sep = '-') { 97 GUID guid = {}; 98 HRM(CoCreateGuid(&guid), "Could not create GUID for id."); 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.setConfig(SkBitmap::kNo_Config, width, height); 110 return bitmap; 111 } 112 113 SkXPSDevice::SkXPSDevice() 114 : SkDevice(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(create_id(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 SkASSERT(!"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(create_id(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 (NULL != 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 (NULL != 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 (NULL != 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 (NULL != 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 (NULL != 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 (NULL != 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 (NULL != 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 uint32_t SkXPSDevice::getDeviceCapabilities() { 1163 return kVector_Capability; 1164 } 1165 1166 void SkXPSDevice::clear(SkColor color) { 1167 //TODO: override this for XPS 1168 SkDEBUGF(("XPS clear not yet implemented.")); 1169 } 1170 1171 void SkXPSDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode, 1172 size_t count, const SkPoint points[], 1173 const SkPaint& paint) { 1174 //This will call back into the device to do the drawing. 1175 d.drawPoints(mode, count, points, paint, true); 1176 } 1177 1178 void SkXPSDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, 1179 int vertexCount, const SkPoint verts[], 1180 const SkPoint texs[], const SkColor colors[], 1181 SkXfermode* xmode, const uint16_t indices[], 1182 int indexCount, const SkPaint& paint) { 1183 //TODO: override this for XPS 1184 SkDEBUGF(("XPS drawVertices not yet implemented.")); 1185 } 1186 1187 void SkXPSDevice::drawPaint(const SkDraw& d, const SkPaint& origPaint) { 1188 const SkRect r = SkRect::MakeSize(this->fCurrentCanvasSize); 1189 1190 //If trying to paint with a stroke, ignore that and fill. 1191 SkPaint* fillPaint = const_cast<SkPaint*>(&origPaint); 1192 SkTCopyOnFirstWrite<SkPaint> paint(origPaint); 1193 if (paint->getStyle() != SkPaint::kFill_Style) { 1194 paint.writable()->setStyle(SkPaint::kFill_Style); 1195 } 1196 1197 this->internalDrawRect(d, r, false, *fillPaint); 1198 } 1199 1200 void SkXPSDevice::drawRect(const SkDraw& d, 1201 const SkRect& r, 1202 const SkPaint& paint) { 1203 this->internalDrawRect(d, r, true, paint); 1204 } 1205 1206 void SkXPSDevice::internalDrawRect(const SkDraw& d, 1207 const SkRect& r, 1208 bool transformRect, 1209 const SkPaint& paint) { 1210 //Exit early if there is nothing to draw. 1211 if (d.fClip->isEmpty() || 1212 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { 1213 return; 1214 } 1215 1216 //Path the rect if we can't optimize it. 1217 if (rect_must_be_pathed(paint, *d.fMatrix)) { 1218 SkPath tmp; 1219 tmp.addRect(r); 1220 tmp.setFillType(SkPath::kWinding_FillType); 1221 this->drawPath(d, tmp, paint, NULL, true); 1222 return; 1223 } 1224 1225 //Create the shaded path. 1226 SkTScopedComPtr<IXpsOMPath> shadedPath; 1227 HRVM(this->fXpsFactory->CreatePath(&shadedPath), 1228 "Could not create shaded path for rect."); 1229 1230 //Create the shaded geometry. 1231 SkTScopedComPtr<IXpsOMGeometry> shadedGeometry; 1232 HRVM(this->fXpsFactory->CreateGeometry(&shadedGeometry), 1233 "Could not create shaded geometry for rect."); 1234 1235 //Add the geometry to the shaded path. 1236 HRVM(shadedPath->SetGeometryLocal(shadedGeometry.get()), 1237 "Could not set shaded geometry for rect."); 1238 1239 //Set the brushes. 1240 BOOL fill = FALSE; 1241 BOOL stroke = FALSE; 1242 HRV(this->shadePath(shadedPath.get(), paint, *d.fMatrix, &fill, &stroke)); 1243 1244 bool xpsTransformsPath = true; 1245 //Transform the geometry. 1246 if (transformRect && xpsTransformsPath) { 1247 SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform; 1248 HRV(this->createXpsTransform(*d.fMatrix, &xpsTransform)); 1249 if (xpsTransform.get()) { 1250 HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()), 1251 "Could not set transform for rect."); 1252 } else { 1253 xpsTransformsPath = false; 1254 } 1255 } 1256 1257 //Create the figure. 1258 SkTScopedComPtr<IXpsOMGeometryFigure> rectFigure; 1259 { 1260 SkPoint points[4] = { 1261 { r.fLeft, r.fTop }, 1262 { r.fLeft, r.fBottom }, 1263 { r.fRight, r.fBottom }, 1264 { r.fRight, r.fTop }, 1265 }; 1266 if (!xpsTransformsPath && transformRect) { 1267 d.fMatrix->mapPoints(points, SK_ARRAY_COUNT(points)); 1268 } 1269 HRV(this->createXpsQuad(points, stroke, fill, &rectFigure)); 1270 } 1271 1272 //Get the figures of the shaded geometry. 1273 SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures; 1274 HRVM(shadedGeometry->GetFigures(&shadedFigures), 1275 "Could not get shaded figures for rect."); 1276 1277 //Add the figure to the shaded geometry figures. 1278 HRVM(shadedFigures->Append(rectFigure.get()), 1279 "Could not add shaded figure for rect."); 1280 1281 HRV(this->clip(shadedPath.get(), d)); 1282 1283 //Add the shaded path to the current visuals. 1284 SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals; 1285 HRVM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals), 1286 "Could not get current visuals for rect."); 1287 HRVM(currentVisuals->Append(shadedPath.get()), 1288 "Could not add rect to current visuals."); 1289 } 1290 1291 static HRESULT close_figure(const SkTDArray<XPS_SEGMENT_TYPE>& segmentTypes, 1292 const SkTDArray<BOOL>& segmentStrokes, 1293 const SkTDArray<FLOAT>& segmentData, 1294 BOOL stroke, BOOL fill, 1295 IXpsOMGeometryFigure* figure, 1296 IXpsOMGeometryFigureCollection* figures) { 1297 // Add the segment data to the figure. 1298 HRM(figure->SetSegments(segmentTypes.count(), segmentData.count(), 1299 segmentTypes.begin() , segmentData.begin(), 1300 segmentStrokes.begin()), 1301 "Could not set path segments."); 1302 1303 // Set the closed and filled properties of the figure. 1304 HRM(figure->SetIsClosed(stroke), "Could not set path closed."); 1305 HRM(figure->SetIsFilled(fill), "Could not set path fill."); 1306 1307 // Add the figure created above to this geometry. 1308 HRM(figures->Append(figure), "Could not add path to geometry."); 1309 return S_OK; 1310 } 1311 1312 HRESULT SkXPSDevice::addXpsPathGeometry( 1313 IXpsOMGeometryFigureCollection* xpsFigures, 1314 BOOL stroke, BOOL fill, const SkPath& path) { 1315 SkTDArray<XPS_SEGMENT_TYPE> segmentTypes; 1316 SkTDArray<BOOL> segmentStrokes; 1317 SkTDArray<FLOAT> segmentData; 1318 1319 SkTScopedComPtr<IXpsOMGeometryFigure> xpsFigure; 1320 SkPath::Iter iter(path, true); 1321 SkPoint points[4]; 1322 SkPath::Verb verb; 1323 while ((verb = iter.next(points)) != SkPath::kDone_Verb) { 1324 switch (verb) { 1325 case SkPath::kMove_Verb: { 1326 if (NULL != xpsFigure.get()) { 1327 HR(close_figure(segmentTypes, segmentStrokes, segmentData, 1328 stroke, fill, 1329 xpsFigure.get() , xpsFigures)); 1330 xpsFigure.reset(); 1331 segmentTypes.rewind(); 1332 segmentStrokes.rewind(); 1333 segmentData.rewind(); 1334 } 1335 // Define the start point. 1336 XPS_POINT startPoint = xps_point(points[0]); 1337 // Create the figure. 1338 HRM(this->fXpsFactory->CreateGeometryFigure(&startPoint, 1339 &xpsFigure), 1340 "Could not create path geometry figure."); 1341 break; 1342 } 1343 case SkPath::kLine_Verb: 1344 if (iter.isCloseLine()) break; //ignore the line, auto-closed 1345 segmentTypes.push(XPS_SEGMENT_TYPE_LINE); 1346 segmentStrokes.push(stroke); 1347 segmentData.push(SkScalarToFLOAT(points[1].fX)); 1348 segmentData.push(SkScalarToFLOAT(points[1].fY)); 1349 break; 1350 case SkPath::kQuad_Verb: 1351 segmentTypes.push(XPS_SEGMENT_TYPE_QUADRATIC_BEZIER); 1352 segmentStrokes.push(stroke); 1353 segmentData.push(SkScalarToFLOAT(points[1].fX)); 1354 segmentData.push(SkScalarToFLOAT(points[1].fY)); 1355 segmentData.push(SkScalarToFLOAT(points[2].fX)); 1356 segmentData.push(SkScalarToFLOAT(points[2].fY)); 1357 break; 1358 case SkPath::kCubic_Verb: 1359 segmentTypes.push(XPS_SEGMENT_TYPE_BEZIER); 1360 segmentStrokes.push(stroke); 1361 segmentData.push(SkScalarToFLOAT(points[1].fX)); 1362 segmentData.push(SkScalarToFLOAT(points[1].fY)); 1363 segmentData.push(SkScalarToFLOAT(points[2].fX)); 1364 segmentData.push(SkScalarToFLOAT(points[2].fY)); 1365 segmentData.push(SkScalarToFLOAT(points[3].fX)); 1366 segmentData.push(SkScalarToFLOAT(points[3].fY)); 1367 break; 1368 case SkPath::kClose_Verb: 1369 // we ignore these, and just get the whole segment from 1370 // the corresponding line/quad/cubic verbs 1371 break; 1372 default: 1373 SkASSERT(!"unexpected verb"); 1374 break; 1375 } 1376 } 1377 if (NULL != xpsFigure.get()) { 1378 HR(close_figure(segmentTypes, segmentStrokes, segmentData, 1379 stroke, fill, 1380 xpsFigure.get(), xpsFigures)); 1381 } 1382 return S_OK; 1383 } 1384 1385 HRESULT SkXPSDevice::drawInverseWindingPath(const SkDraw& d, 1386 const SkPath& devicePath, 1387 IXpsOMPath* shadedPath) { 1388 const SkRect universeRect = SkRect::MakeLTRB(0, 0, 1389 this->fCurrentCanvasSize.fWidth, this->fCurrentCanvasSize.fHeight); 1390 1391 const XPS_RECT universeRectXps = { 1392 0.0f, 0.0f, 1393 SkScalarToFLOAT(this->fCurrentCanvasSize.fWidth), 1394 SkScalarToFLOAT(this->fCurrentCanvasSize.fHeight), 1395 }; 1396 1397 //Get the geometry. 1398 SkTScopedComPtr<IXpsOMGeometry> shadedGeometry; 1399 HRM(shadedPath->GetGeometry(&shadedGeometry), 1400 "Could not get shaded geometry for inverse path."); 1401 1402 //Get the figures from the geometry. 1403 SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures; 1404 HRM(shadedGeometry->GetFigures(&shadedFigures), 1405 "Could not get shaded figures for inverse path."); 1406 1407 HRM(shadedGeometry->SetFillRule(XPS_FILL_RULE_NONZERO), 1408 "Could not set shaded fill rule for inverse path."); 1409 1410 //Take everything drawn so far, and make a shared resource out of it. 1411 //Replace everything drawn so far with 1412 //inverse canvas 1413 // old canvas of everything so far 1414 // world shaded figure, clipped to current clip 1415 // top canvas of everything so far, clipped to path 1416 //Note: this is not quite right when there is nothing solid in the 1417 //canvas of everything so far, as the bit on top will allow 1418 //the world paint to show through. 1419 1420 //Create new canvas. 1421 SkTScopedComPtr<IXpsOMCanvas> newCanvas; 1422 HRM(this->fXpsFactory->CreateCanvas(&newCanvas), 1423 "Could not create inverse canvas."); 1424 1425 //Save the old canvas to a dictionary on the new canvas. 1426 SkTScopedComPtr<IXpsOMDictionary> newDictionary; 1427 HRM(this->fXpsFactory->CreateDictionary(&newDictionary), 1428 "Could not create inverse dictionary."); 1429 HRM(newCanvas->SetDictionaryLocal(newDictionary.get()), 1430 "Could not set inverse dictionary."); 1431 1432 const size_t size = SK_ARRAY_COUNT(L"ID" L_GUID_ID); 1433 wchar_t buffer[size]; 1434 wchar_t id[GUID_ID_LEN]; 1435 HR(create_id(id, GUID_ID_LEN, '_')); 1436 swprintf_s(buffer, size, L"ID%s", id); 1437 HRM(newDictionary->Append(buffer, this->fCurrentXpsCanvas.get()), 1438 "Could not add canvas to inverse dictionary."); 1439 1440 //Start drawing 1441 SkTScopedComPtr<IXpsOMVisualCollection> newVisuals; 1442 HRM(newCanvas->GetVisuals(&newVisuals), 1443 "Could not get inverse canvas visuals."); 1444 1445 //Draw old canvas from dictionary onto new canvas. 1446 SkTScopedComPtr<IXpsOMGeometry> oldGeometry; 1447 HRM(this->fXpsFactory->CreateGeometry(&oldGeometry), 1448 "Could not create old inverse geometry."); 1449 1450 SkTScopedComPtr<IXpsOMGeometryFigureCollection> oldFigures; 1451 HRM(oldGeometry->GetFigures(&oldFigures), 1452 "Could not get old inverse figures."); 1453 1454 SkTScopedComPtr<IXpsOMGeometryFigure> oldFigure; 1455 HR(this->createXpsRect(universeRect, FALSE, TRUE, &oldFigure)); 1456 HRM(oldFigures->Append(oldFigure.get()), 1457 "Could not add old inverse figure."); 1458 1459 SkTScopedComPtr<IXpsOMVisualBrush> oldBrush; 1460 HRM(this->fXpsFactory->CreateVisualBrush(&universeRectXps, 1461 &universeRectXps, 1462 &oldBrush), 1463 "Could not create old inverse brush."); 1464 1465 SkTScopedComPtr<IXpsOMPath> oldPath; 1466 HRM(this->fXpsFactory->CreatePath(&oldPath), 1467 "Could not create old inverse path."); 1468 HRM(oldPath->SetGeometryLocal(oldGeometry.get()), 1469 "Could not set old inverse geometry."); 1470 HRM(oldPath->SetFillBrushLocal(oldBrush.get()), 1471 "Could not set old inverse fill brush."); 1472 //the brush must be parented before setting the lookup. 1473 HRM(newVisuals->Append(oldPath.get()), 1474 "Could not add old inverse path to new canvas visuals."); 1475 HRM(oldBrush->SetVisualLookup(buffer), 1476 "Could not set old inverse brush visual lookup."); 1477 1478 //Draw the clip filling shader. 1479 SkTScopedComPtr<IXpsOMGeometryFigure> shadedFigure; 1480 HR(this->createXpsRect(universeRect, FALSE, TRUE, &shadedFigure)); 1481 HRM(shadedFigures->Append(shadedFigure.get()), 1482 "Could not add inverse shaded figure."); 1483 //the geometry is already set 1484 HR(this->clip(shadedPath, d)); 1485 HRM(newVisuals->Append(shadedPath), 1486 "Could not add inverse shaded path to canvas visuals."); 1487 1488 //Draw the old canvas on top, clipped to the original path. 1489 SkTScopedComPtr<IXpsOMCanvas> topCanvas; 1490 HRM(this->fXpsFactory->CreateCanvas(&topCanvas), 1491 "Could not create top inverse canvas."); 1492 //Clip the canvas to prevent alpha spill. 1493 //This is the entire reason this canvas exists. 1494 HR(this->clip(topCanvas.get(), d)); 1495 1496 SkTScopedComPtr<IXpsOMGeometry> topGeometry; 1497 HRM(this->fXpsFactory->CreateGeometry(&topGeometry), 1498 "Could not create top inverse geometry."); 1499 1500 SkTScopedComPtr<IXpsOMGeometryFigureCollection> topFigures; 1501 HRM(topGeometry->GetFigures(&topFigures), 1502 "Could not get top inverse figures."); 1503 1504 SkTScopedComPtr<IXpsOMGeometryFigure> topFigure; 1505 HR(this->createXpsRect(universeRect, FALSE, TRUE, &topFigure)); 1506 HRM(topFigures->Append(topFigure.get()), 1507 "Could not add old inverse figure."); 1508 1509 SkTScopedComPtr<IXpsOMVisualBrush> topBrush; 1510 HRM(this->fXpsFactory->CreateVisualBrush(&universeRectXps, 1511 &universeRectXps, 1512 &topBrush), 1513 "Could not create top inverse brush."); 1514 1515 SkTScopedComPtr<IXpsOMPath> topPath; 1516 HRM(this->fXpsFactory->CreatePath(&topPath), 1517 "Could not create top inverse path."); 1518 HRM(topPath->SetGeometryLocal(topGeometry.get()), 1519 "Could not set top inverse geometry."); 1520 HRM(topPath->SetFillBrushLocal(topBrush.get()), 1521 "Could not set top inverse fill brush."); 1522 //the brush must be parented before setting the lookup. 1523 HRM(newVisuals->Append(topCanvas.get()), 1524 "Could not add top canvas to inverse canvas visuals."); 1525 SkTScopedComPtr<IXpsOMVisualCollection> topVisuals; 1526 HRM(topCanvas->GetVisuals(&topVisuals), 1527 "Could not get top inverse canvas visuals."); 1528 HRM(topVisuals->Append(topPath.get()), 1529 "Could not add top inverse path to top canvas visuals."); 1530 HRM(topBrush->SetVisualLookup(buffer), 1531 "Could not set top inverse brush visual lookup."); 1532 1533 HR(this->clipToPath(topPath.get(), devicePath, XPS_FILL_RULE_NONZERO)); 1534 1535 //swap current canvas to new canvas 1536 this->fCurrentXpsCanvas.swap(newCanvas); 1537 1538 return S_OK; 1539 } 1540 1541 void SkXPSDevice::convertToPpm(const SkMaskFilter* filter, 1542 SkMatrix* matrix, 1543 SkVector* ppuScale, 1544 const SkIRect& clip, SkIRect* clipIRect) { 1545 //This action is in unit space, but the ppm is specified in physical space. 1546 ppuScale->fX = SkScalarDiv(this->fCurrentPixelsPerMeter.fX, 1547 this->fCurrentUnitsPerMeter.fX); 1548 ppuScale->fY = SkScalarDiv(this->fCurrentPixelsPerMeter.fY, 1549 this->fCurrentUnitsPerMeter.fY); 1550 1551 matrix->postScale(ppuScale->fX, ppuScale->fY); 1552 1553 const SkIRect& irect = clip; 1554 SkRect clipRect = SkRect::MakeLTRB( 1555 SkScalarMul(SkIntToScalar(irect.fLeft), ppuScale->fX), 1556 SkScalarMul(SkIntToScalar(irect.fTop), ppuScale->fY), 1557 SkScalarMul(SkIntToScalar(irect.fRight), ppuScale->fX), 1558 SkScalarMul(SkIntToScalar(irect.fBottom), ppuScale->fY)); 1559 clipRect.roundOut(clipIRect); 1560 } 1561 1562 HRESULT SkXPSDevice::applyMask(const SkDraw& d, 1563 const SkMask& mask, 1564 const SkVector& ppuScale, 1565 IXpsOMPath* shadedPath) { 1566 //Get the geometry object. 1567 SkTScopedComPtr<IXpsOMGeometry> shadedGeometry; 1568 HRM(shadedPath->GetGeometry(&shadedGeometry), 1569 "Could not get mask shaded geometry."); 1570 1571 //Get the figures from the geometry. 1572 SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures; 1573 HRM(shadedGeometry->GetFigures(&shadedFigures), 1574 "Could not get mask shaded figures."); 1575 1576 SkMatrix m; 1577 m.reset(); 1578 m.setTranslate(SkIntToScalar(mask.fBounds.fLeft), 1579 SkIntToScalar(mask.fBounds.fTop)); 1580 m.postScale(SkScalarInvert(ppuScale.fX), SkScalarInvert(ppuScale.fY)); 1581 1582 SkShader::TileMode xy[2]; 1583 xy[0] = (SkShader::TileMode)3; 1584 xy[1] = (SkShader::TileMode)3; 1585 1586 SkBitmap bm; 1587 bm.setConfig(SkBitmap::kA8_Config, 1588 mask.fBounds.width(), 1589 mask.fBounds.height(), 1590 mask.fRowBytes); 1591 bm.setPixels(mask.fImage); 1592 1593 SkTScopedComPtr<IXpsOMTileBrush> maskBrush; 1594 HR(this->createXpsImageBrush(bm, m, xy, 0xFF, &maskBrush)); 1595 HRM(shadedPath->SetOpacityMaskBrushLocal(maskBrush.get()), 1596 "Could not set mask."); 1597 1598 const SkRect universeRect = SkRect::MakeLTRB(0, 0, 1599 this->fCurrentCanvasSize.fWidth, this->fCurrentCanvasSize.fHeight); 1600 SkTScopedComPtr<IXpsOMGeometryFigure> shadedFigure; 1601 HRM(this->createXpsRect(universeRect, FALSE, TRUE, &shadedFigure), 1602 "Could not create mask shaded figure."); 1603 HRM(shadedFigures->Append(shadedFigure.get()), 1604 "Could not add mask shaded figure."); 1605 1606 HR(this->clip(shadedPath, d)); 1607 1608 //Add the path to the active visual collection. 1609 SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals; 1610 HRM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals), 1611 "Could not get mask current visuals."); 1612 HRM(currentVisuals->Append(shadedPath), 1613 "Could not add masked shaded path to current visuals."); 1614 1615 return S_OK; 1616 } 1617 1618 HRESULT SkXPSDevice::shadePath(IXpsOMPath* shadedPath, 1619 const SkPaint& shaderPaint, 1620 const SkMatrix& matrix, 1621 BOOL* fill, BOOL* stroke) { 1622 *fill = FALSE; 1623 *stroke = FALSE; 1624 1625 const SkPaint::Style style = shaderPaint.getStyle(); 1626 const bool hasFill = SkPaint::kFill_Style == style 1627 || SkPaint::kStrokeAndFill_Style == style; 1628 const bool hasStroke = SkPaint::kStroke_Style == style 1629 || SkPaint::kStrokeAndFill_Style == style; 1630 1631 //TODO(bungeman): use dictionaries and lookups. 1632 if (hasFill) { 1633 *fill = TRUE; 1634 SkTScopedComPtr<IXpsOMBrush> fillBrush; 1635 HR(this->createXpsBrush(shaderPaint, &fillBrush, &matrix)); 1636 HRM(shadedPath->SetFillBrushLocal(fillBrush.get()), 1637 "Could not set fill for shaded path."); 1638 } 1639 1640 if (hasStroke) { 1641 *stroke = TRUE; 1642 SkTScopedComPtr<IXpsOMBrush> strokeBrush; 1643 HR(this->createXpsBrush(shaderPaint, &strokeBrush, &matrix)); 1644 HRM(shadedPath->SetStrokeBrushLocal(strokeBrush.get()), 1645 "Could not set stroke brush for shaded path."); 1646 HRM(shadedPath->SetStrokeThickness( 1647 SkScalarToFLOAT(shaderPaint.getStrokeWidth())), 1648 "Could not set shaded path stroke thickness."); 1649 1650 if (0 == shaderPaint.getStrokeWidth()) { 1651 //XPS hair width is a hack. (XPS Spec 11.6.12). 1652 SkTScopedComPtr<IXpsOMDashCollection> dashes; 1653 HRM(shadedPath->GetStrokeDashes(&dashes), 1654 "Could not set dashes for shaded path."); 1655 XPS_DASH dash; 1656 dash.length = 1.0; 1657 dash.gap = 0.0; 1658 HRM(dashes->Append(&dash), "Could not add dashes to shaded path."); 1659 HRM(shadedPath->SetStrokeDashOffset(-2.0), 1660 "Could not set dash offset for shaded path."); 1661 } 1662 } 1663 return S_OK; 1664 } 1665 1666 void SkXPSDevice::drawPath(const SkDraw& d, 1667 const SkPath& platonicPath, 1668 const SkPaint& origPaint, 1669 const SkMatrix* prePathMatrix, 1670 bool pathIsMutable) { 1671 SkTCopyOnFirstWrite<SkPaint> paint(origPaint); 1672 1673 // nothing to draw 1674 if (d.fClip->isEmpty() || 1675 (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) { 1676 return; 1677 } 1678 1679 SkPath modifiedPath; 1680 const bool paintHasPathEffect = paint->getPathEffect() 1681 || paint->getStyle() != SkPaint::kFill_Style; 1682 1683 //Apply pre-path matrix [Platonic-path -> Skeletal-path]. 1684 SkMatrix matrix = *d.fMatrix; 1685 SkPath* skeletalPath = const_cast<SkPath*>(&platonicPath); 1686 if (prePathMatrix) { 1687 if (paintHasPathEffect || paint->getRasterizer()) { 1688 if (!pathIsMutable) { 1689 skeletalPath = &modifiedPath; 1690 pathIsMutable = true; 1691 } 1692 platonicPath.transform(*prePathMatrix, skeletalPath); 1693 } else { 1694 if (!matrix.preConcat(*prePathMatrix)) { 1695 return; 1696 } 1697 } 1698 } 1699 1700 //Apply path effect [Skeletal-path -> Fillable-path]. 1701 SkPath* fillablePath = skeletalPath; 1702 if (paintHasPathEffect) { 1703 if (!pathIsMutable) { 1704 fillablePath = &modifiedPath; 1705 pathIsMutable = true; 1706 } 1707 bool fill = paint->getFillPath(*skeletalPath, fillablePath); 1708 1709 SkPaint* writablePaint = paint.writable(); 1710 writablePaint->setPathEffect(NULL); 1711 if (fill) { 1712 writablePaint->setStyle(SkPaint::kFill_Style); 1713 } else { 1714 writablePaint->setStyle(SkPaint::kStroke_Style); 1715 writablePaint->setStrokeWidth(0); 1716 } 1717 } 1718 1719 //Create the shaded path. This will be the path which is painted. 1720 SkTScopedComPtr<IXpsOMPath> shadedPath; 1721 HRVM(this->fXpsFactory->CreatePath(&shadedPath), 1722 "Could not create shaded path for path."); 1723 1724 //Create the geometry for the shaded path. 1725 SkTScopedComPtr<IXpsOMGeometry> shadedGeometry; 1726 HRVM(this->fXpsFactory->CreateGeometry(&shadedGeometry), 1727 "Could not create shaded geometry for path."); 1728 1729 //Add the geometry to the shaded path. 1730 HRVM(shadedPath->SetGeometryLocal(shadedGeometry.get()), 1731 "Could not add the shaded geometry to shaded path."); 1732 1733 SkRasterizer* rasterizer = paint->getRasterizer(); 1734 SkMaskFilter* filter = paint->getMaskFilter(); 1735 1736 //Determine if we will draw or shade and mask. 1737 if (rasterizer || filter) { 1738 if (paint->getStyle() != SkPaint::kFill_Style) { 1739 paint.writable()->setStyle(SkPaint::kFill_Style); 1740 } 1741 } 1742 1743 //Set the brushes. 1744 BOOL fill; 1745 BOOL stroke; 1746 HRV(this->shadePath(shadedPath.get(), 1747 *paint, 1748 *d.fMatrix, 1749 &fill, 1750 &stroke)); 1751 1752 //Rasterizer 1753 if (rasterizer) { 1754 SkIRect clipIRect; 1755 SkVector ppuScale; 1756 this->convertToPpm(filter, 1757 &matrix, 1758 &ppuScale, 1759 d.fClip->getBounds(), 1760 &clipIRect); 1761 1762 SkMask* mask = NULL; 1763 1764 //[Fillable-path -> Mask] 1765 SkMask rasteredMask; 1766 if (rasterizer->rasterize( 1767 *fillablePath, 1768 matrix, 1769 &clipIRect, 1770 filter, //just to compute how much to draw. 1771 &rasteredMask, 1772 SkMask::kComputeBoundsAndRenderImage_CreateMode)) { 1773 1774 SkAutoMaskFreeImage rasteredAmi(rasteredMask.fImage); 1775 mask = &rasteredMask; 1776 1777 //[Mask -> Mask] 1778 SkMask filteredMask; 1779 if (filter && 1780 filter->filterMask(&filteredMask, *mask, *d.fMatrix, NULL)) { 1781 1782 mask = &filteredMask; 1783 } else { 1784 filteredMask.fImage = NULL; 1785 } 1786 SkAutoMaskFreeImage filteredAmi(filteredMask.fImage); 1787 1788 //Draw mask. 1789 HRV(this->applyMask(d, *mask, ppuScale, shadedPath.get())); 1790 } 1791 return; 1792 } 1793 1794 //Mask filter 1795 if (filter) { 1796 SkIRect clipIRect; 1797 SkVector ppuScale; 1798 this->convertToPpm(filter, 1799 &matrix, 1800 &ppuScale, 1801 d.fClip->getBounds(), 1802 &clipIRect); 1803 1804 //[Fillable-path -> Pixel-path] 1805 SkPath* pixelPath = pathIsMutable ? fillablePath : &modifiedPath; 1806 fillablePath->transform(matrix, pixelPath); 1807 1808 SkMask* mask = NULL; 1809 1810 //[Pixel-path -> Mask] 1811 SkMask rasteredMask; 1812 if (SkDraw::DrawToMask( 1813 *pixelPath, 1814 &clipIRect, 1815 filter, //just to compute how much to draw. 1816 &matrix, 1817 &rasteredMask, 1818 SkMask::kComputeBoundsAndRenderImage_CreateMode, 1819 paint->getStyle())) { 1820 1821 SkAutoMaskFreeImage rasteredAmi(rasteredMask.fImage); 1822 mask = &rasteredMask; 1823 1824 //[Mask -> Mask] 1825 SkMask filteredMask; 1826 if (filter->filterMask(&filteredMask, 1827 rasteredMask, 1828 matrix, 1829 NULL)) { 1830 mask = &filteredMask; 1831 } else { 1832 filteredMask.fImage = NULL; 1833 } 1834 SkAutoMaskFreeImage filteredAmi(filteredMask.fImage); 1835 1836 //Draw mask. 1837 HRV(this->applyMask(d, *mask, ppuScale, shadedPath.get())); 1838 } 1839 return; 1840 } 1841 1842 //Get the figures from the shaded geometry. 1843 SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures; 1844 HRVM(shadedGeometry->GetFigures(&shadedFigures), 1845 "Could not get shaded figures for shaded path."); 1846 1847 bool xpsTransformsPath = true; 1848 1849 //Set the fill rule. 1850 XPS_FILL_RULE xpsFillRule; 1851 switch (platonicPath.getFillType()) { 1852 case SkPath::kWinding_FillType: 1853 xpsFillRule = XPS_FILL_RULE_NONZERO; 1854 break; 1855 case SkPath::kEvenOdd_FillType: 1856 xpsFillRule = XPS_FILL_RULE_EVENODD; 1857 break; 1858 case SkPath::kInverseWinding_FillType: { 1859 //[Fillable-path -> Device-path] 1860 SkPath* devicePath = pathIsMutable ? fillablePath : &modifiedPath; 1861 fillablePath->transform(matrix, devicePath); 1862 1863 HRV(this->drawInverseWindingPath(d, 1864 *devicePath, 1865 shadedPath.get())); 1866 return; 1867 } 1868 case SkPath::kInverseEvenOdd_FillType: { 1869 const SkRect universe = SkRect::MakeLTRB( 1870 0, 0, 1871 this->fCurrentCanvasSize.fWidth, 1872 this->fCurrentCanvasSize.fHeight); 1873 SkTScopedComPtr<IXpsOMGeometryFigure> addOneFigure; 1874 HRV(this->createXpsRect(universe, FALSE, TRUE, &addOneFigure)); 1875 HRVM(shadedFigures->Append(addOneFigure.get()), 1876 "Could not add even-odd flip figure to shaded path."); 1877 xpsTransformsPath = false; 1878 xpsFillRule = XPS_FILL_RULE_EVENODD; 1879 break; 1880 } 1881 default: 1882 SkASSERT(!"Unknown SkPath::FillType."); 1883 } 1884 HRVM(shadedGeometry->SetFillRule(xpsFillRule), 1885 "Could not set fill rule for shaded path."); 1886 1887 //Create the XPS transform, if possible. 1888 if (xpsTransformsPath) { 1889 SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform; 1890 HRV(this->createXpsTransform(matrix, &xpsTransform)); 1891 1892 if (xpsTransform.get()) { 1893 HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()), 1894 "Could not set transform on shaded path."); 1895 } else { 1896 xpsTransformsPath = false; 1897 } 1898 } 1899 1900 SkPath* devicePath = fillablePath; 1901 if (!xpsTransformsPath) { 1902 //[Fillable-path -> Device-path] 1903 devicePath = pathIsMutable ? fillablePath : &modifiedPath; 1904 fillablePath->transform(matrix, devicePath); 1905 } 1906 HRV(this->addXpsPathGeometry(shadedFigures.get(), 1907 stroke, fill, *devicePath)); 1908 1909 HRV(this->clip(shadedPath.get(), d)); 1910 1911 //Add the path to the active visual collection. 1912 SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals; 1913 HRVM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals), 1914 "Could not get current visuals for shaded path."); 1915 HRVM(currentVisuals->Append(shadedPath.get()), 1916 "Could not add shaded path to current visuals."); 1917 } 1918 1919 HRESULT SkXPSDevice::clip(IXpsOMVisual* xpsVisual, const SkDraw& d) { 1920 SkPath clipPath; 1921 SkAssertResult(d.fClip->getBoundaryPath(&clipPath)); 1922 1923 return this->clipToPath(xpsVisual, clipPath, XPS_FILL_RULE_EVENODD); 1924 } 1925 HRESULT SkXPSDevice::clipToPath(IXpsOMVisual* xpsVisual, 1926 const SkPath& clipPath, 1927 XPS_FILL_RULE fillRule) { 1928 //Create the geometry. 1929 SkTScopedComPtr<IXpsOMGeometry> clipGeometry; 1930 HRM(this->fXpsFactory->CreateGeometry(&clipGeometry), 1931 "Could not create clip geometry."); 1932 1933 //Get the figure collection of the geometry. 1934 SkTScopedComPtr<IXpsOMGeometryFigureCollection> clipFigures; 1935 HRM(clipGeometry->GetFigures(&clipFigures), 1936 "Could not get the clip figures."); 1937 1938 //Create the figures into the geometry. 1939 HR(this->addXpsPathGeometry( 1940 clipFigures.get(), 1941 FALSE, TRUE, clipPath)); 1942 1943 HRM(clipGeometry->SetFillRule(fillRule), 1944 "Could not set fill rule."); 1945 HRM(xpsVisual->SetClipGeometryLocal(clipGeometry.get()), 1946 "Could not set clip geometry."); 1947 1948 return S_OK; 1949 } 1950 1951 void SkXPSDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap, 1952 const SkMatrix& matrix, const SkPaint& paint) { 1953 if (d.fClip->isEmpty()) { 1954 return; 1955 } 1956 1957 SkIRect srcRect; 1958 srcRect.set(0, 0, bitmap.width(), bitmap.height()); 1959 1960 //Create the new shaded path. 1961 SkTScopedComPtr<IXpsOMPath> shadedPath; 1962 HRVM(this->fXpsFactory->CreatePath(&shadedPath), 1963 "Could not create path for bitmap."); 1964 1965 //Create the shaded geometry. 1966 SkTScopedComPtr<IXpsOMGeometry> shadedGeometry; 1967 HRVM(this->fXpsFactory->CreateGeometry(&shadedGeometry), 1968 "Could not create geometry for bitmap."); 1969 1970 //Add the shaded geometry to the shaded path. 1971 HRVM(shadedPath->SetGeometryLocal(shadedGeometry.get()), 1972 "Could not set the geometry for bitmap."); 1973 1974 //Get the shaded figures from the shaded geometry. 1975 SkTScopedComPtr<IXpsOMGeometryFigureCollection> shadedFigures; 1976 HRVM(shadedGeometry->GetFigures(&shadedFigures), 1977 "Could not get the figures for bitmap."); 1978 1979 SkMatrix transform = matrix; 1980 transform.postConcat(*d.fMatrix); 1981 1982 SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform; 1983 HRV(this->createXpsTransform(transform, &xpsTransform)); 1984 if (xpsTransform.get()) { 1985 HRVM(shadedGeometry->SetTransformLocal(xpsTransform.get()), 1986 "Could not set transform for bitmap."); 1987 } else { 1988 //TODO: perspective that bitmap! 1989 } 1990 1991 SkTScopedComPtr<IXpsOMGeometryFigure> rectFigure; 1992 if (NULL != xpsTransform.get()) { 1993 const SkShader::TileMode xy[2] = { 1994 SkShader::kClamp_TileMode, 1995 SkShader::kClamp_TileMode, 1996 }; 1997 SkTScopedComPtr<IXpsOMTileBrush> xpsImageBrush; 1998 HRV(this->createXpsImageBrush(bitmap, 1999 transform, 2000 xy, 2001 paint.getAlpha(), 2002 &xpsImageBrush)); 2003 HRVM(shadedPath->SetFillBrushLocal(xpsImageBrush.get()), 2004 "Could not set bitmap brush."); 2005 2006 const SkRect bitmapRect = SkRect::MakeLTRB(0, 0, 2007 SkIntToScalar(srcRect.width()), SkIntToScalar(srcRect.height())); 2008 HRV(this->createXpsRect(bitmapRect, FALSE, TRUE, &rectFigure)); 2009 } 2010 HRVM(shadedFigures->Append(rectFigure.get()), 2011 "Could not add bitmap figure."); 2012 2013 //Get the current visual collection and add the shaded path to it. 2014 SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals; 2015 HRVM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals), 2016 "Could not get current visuals for bitmap"); 2017 HRVM(currentVisuals->Append(shadedPath.get()), 2018 "Could not add bitmap to current visuals."); 2019 2020 HRV(this->clip(shadedPath.get(), d)); 2021 } 2022 2023 void SkXPSDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, 2024 int x, int y, 2025 const SkPaint& paint) { 2026 //TODO: override this for XPS 2027 SkDEBUGF(("XPS drawSprite not yet implemented.")); 2028 } 2029 2030 HRESULT SkXPSDevice::CreateTypefaceUse(const SkPaint& paint, 2031 TypefaceUse** typefaceUse) { 2032 SkAutoResolveDefaultTypeface typeface(paint.getTypeface()); 2033 2034 //Check cache. 2035 const SkFontID typefaceID = typeface->uniqueID(); 2036 if (!this->fTypefaces.empty()) { 2037 TypefaceUse* current = &this->fTypefaces.front(); 2038 const TypefaceUse* last = &this->fTypefaces.back(); 2039 for (; current <= last; ++current) { 2040 if (current->typefaceId == typefaceID) { 2041 *typefaceUse = current; 2042 return S_OK; 2043 } 2044 } 2045 } 2046 2047 //TODO: create glyph only fonts 2048 //and let the host deal with what kind of font we're looking at. 2049 XPS_FONT_EMBEDDING embedding = XPS_FONT_EMBEDDING_RESTRICTED; 2050 2051 SkTScopedComPtr<IStream> fontStream; 2052 int ttcIndex; 2053 SkStream* fontData = typeface->openStream(&ttcIndex); 2054 HRM(SkIStream::CreateFromSkStream(fontData, true, &fontStream), 2055 "Could not create font stream."); 2056 2057 const size_t size = 2058 SK_ARRAY_COUNT(L"/Resources/Fonts/" L_GUID_ID L".odttf"); 2059 wchar_t buffer[size]; 2060 wchar_t id[GUID_ID_LEN]; 2061 HR(create_id(id, GUID_ID_LEN)); 2062 swprintf_s(buffer, size, L"/Resources/Fonts/%s.odttf", id); 2063 2064 SkTScopedComPtr<IOpcPartUri> partUri; 2065 HRM(this->fXpsFactory->CreatePartUri(buffer, &partUri), 2066 "Could not create font resource part uri."); 2067 2068 SkTScopedComPtr<IXpsOMFontResource> xpsFontResource; 2069 HRM(this->fXpsFactory->CreateFontResource(fontStream.get(), 2070 embedding, 2071 partUri.get(), 2072 FALSE, 2073 &xpsFontResource), 2074 "Could not create font resource."); 2075 2076 //TODO: change openStream to return -1 for non-ttc, get rid of this. 2077 uint8_t* data = (uint8_t*)fontData->getMemoryBase(); 2078 bool isTTC = (data && 2079 fontData->getLength() >= sizeof(SkTTCFHeader) && 2080 ((SkTTCFHeader*)data)->ttcTag == SkTTCFHeader::TAG); 2081 2082 TypefaceUse& newTypefaceUse = this->fTypefaces.push_back(); 2083 newTypefaceUse.typefaceId = typefaceID; 2084 newTypefaceUse.ttcIndex = isTTC ? ttcIndex : -1; 2085 newTypefaceUse.fontData = fontData; 2086 newTypefaceUse.xpsFont = xpsFontResource.release(); 2087 2088 SkAutoGlyphCache agc = SkAutoGlyphCache(paint, NULL, &SkMatrix::I()); 2089 SkGlyphCache* glyphCache = agc.getCache(); 2090 unsigned int glyphCount = glyphCache->getGlyphCount(); 2091 newTypefaceUse.glyphsUsed = new SkBitSet(glyphCount); 2092 2093 *typefaceUse = &newTypefaceUse; 2094 return S_OK; 2095 } 2096 2097 HRESULT SkXPSDevice::AddGlyphs(const SkDraw& d, 2098 IXpsOMObjectFactory* xpsFactory, 2099 IXpsOMCanvas* canvas, 2100 TypefaceUse* font, 2101 LPCWSTR text, 2102 XPS_GLYPH_INDEX* xpsGlyphs, 2103 UINT32 xpsGlyphsLen, 2104 XPS_POINT *origin, 2105 FLOAT fontSize, 2106 XPS_STYLE_SIMULATION sims, 2107 const SkMatrix& transform, 2108 const SkPaint& paint) { 2109 SkTScopedComPtr<IXpsOMGlyphs> glyphs; 2110 HRM(xpsFactory->CreateGlyphs(font->xpsFont, &glyphs), "Could not create glyphs."); 2111 HRM(glyphs->SetFontFaceIndex(font->ttcIndex), "Could not set glyph font face index."); 2112 2113 //XPS uses affine transformations for everything... 2114 //...except positioning text. 2115 bool useCanvasForClip; 2116 if ((transform.getType() & ~SkMatrix::kTranslate_Mask) == 0) { 2117 origin->x += SkScalarToFLOAT(transform.getTranslateX()); 2118 origin->y += SkScalarToFLOAT(transform.getTranslateY()); 2119 useCanvasForClip = false; 2120 } else { 2121 SkTScopedComPtr<IXpsOMMatrixTransform> xpsMatrixToUse; 2122 HR(this->createXpsTransform(transform, &xpsMatrixToUse)); 2123 if (xpsMatrixToUse.get()) { 2124 HRM(glyphs->SetTransformLocal(xpsMatrixToUse.get()), 2125 "Could not set transform matrix."); 2126 useCanvasForClip = true; 2127 } else { 2128 SkASSERT(!"Attempt to add glyphs in perspective."); 2129 useCanvasForClip = false; 2130 } 2131 } 2132 2133 SkTScopedComPtr<IXpsOMGlyphsEditor> glyphsEditor; 2134 HRM(glyphs->GetGlyphsEditor(&glyphsEditor), "Could not get glyph editor."); 2135 2136 if (NULL != text) { 2137 HRM(glyphsEditor->SetUnicodeString(text), 2138 "Could not set unicode string."); 2139 } 2140 2141 if (NULL != xpsGlyphs) { 2142 HRM(glyphsEditor->SetGlyphIndices(xpsGlyphsLen, xpsGlyphs), 2143 "Could not set glyphs."); 2144 } 2145 2146 HRM(glyphsEditor->ApplyEdits(), "Could not apply glyph edits."); 2147 2148 SkTScopedComPtr<IXpsOMBrush> xpsFillBrush; 2149 HR(this->createXpsBrush( 2150 paint, 2151 &xpsFillBrush, 2152 useCanvasForClip ? NULL : &transform)); 2153 2154 HRM(glyphs->SetFillBrushLocal(xpsFillBrush.get()), 2155 "Could not set fill brush."); 2156 2157 HRM(glyphs->SetOrigin(origin), "Could not set glyph origin."); 2158 2159 HRM(glyphs->SetFontRenderingEmSize(fontSize), 2160 "Could not set font size."); 2161 2162 HRM(glyphs->SetStyleSimulations(sims), 2163 "Could not set style simulations."); 2164 2165 SkTScopedComPtr<IXpsOMVisualCollection> visuals; 2166 HRM(canvas->GetVisuals(&visuals), "Could not get glyph canvas visuals."); 2167 2168 if (!useCanvasForClip) { 2169 HR(this->clip(glyphs.get(), d)); 2170 HRM(visuals->Append(glyphs.get()), "Could not add glyphs to canvas."); 2171 } else { 2172 SkTScopedComPtr<IXpsOMCanvas> glyphCanvas; 2173 HRM(this->fXpsFactory->CreateCanvas(&glyphCanvas), 2174 "Could not create glyph canvas."); 2175 2176 SkTScopedComPtr<IXpsOMVisualCollection> glyphCanvasVisuals; 2177 HRM(glyphCanvas->GetVisuals(&glyphCanvasVisuals), 2178 "Could not get glyph visuals collection."); 2179 2180 HRM(glyphCanvasVisuals->Append(glyphs.get()), 2181 "Could not add glyphs to page."); 2182 HR(this->clip(glyphCanvas.get(), d)); 2183 2184 HRM(visuals->Append(glyphCanvas.get()), 2185 "Could not add glyph canvas to page."); 2186 } 2187 2188 return S_OK; 2189 } 2190 2191 struct SkXPSDrawProcs : public SkDrawProcs { 2192 public: 2193 /** [in] Advance width and offsets for glyphs measured in 2194 hundredths of the font em size (XPS Spec 5.1.3). */ 2195 FLOAT centemPerUnit; 2196 /** [in,out] The accumulated glyphs used in the current typeface. */ 2197 SkBitSet* glyphUse; 2198 /** [out] The glyphs to draw. */ 2199 SkTDArray<XPS_GLYPH_INDEX> xpsGlyphs; 2200 }; 2201 2202 static void xps_draw_1_glyph(const SkDraw1Glyph& state, 2203 SkFixed x, SkFixed y, 2204 const SkGlyph& skGlyph) { 2205 SkASSERT(skGlyph.fWidth > 0 && skGlyph.fHeight > 0); 2206 2207 SkXPSDrawProcs* procs = static_cast<SkXPSDrawProcs*>(state.fDraw->fProcs); 2208 2209 //Draw pre-adds half the sampling frequency for floor rounding. 2210 x -= state.fHalfSampleX; 2211 y -= state.fHalfSampleY; 2212 2213 XPS_GLYPH_INDEX* xpsGlyph = procs->xpsGlyphs.append(); 2214 uint16_t glyphID = skGlyph.getGlyphID(); 2215 procs->glyphUse->setBit(glyphID, true); 2216 xpsGlyph->index = glyphID; 2217 if (1 == procs->xpsGlyphs.count()) { 2218 xpsGlyph->advanceWidth = 0.0f; 2219 xpsGlyph->horizontalOffset = SkFixedToFloat(x) * procs->centemPerUnit; 2220 xpsGlyph->verticalOffset = SkFixedToFloat(y) * -procs->centemPerUnit; 2221 } else { 2222 const XPS_GLYPH_INDEX& first = procs->xpsGlyphs[0]; 2223 xpsGlyph->advanceWidth = 0.0f; 2224 xpsGlyph->horizontalOffset = (SkFixedToFloat(x) * procs->centemPerUnit) 2225 - first.horizontalOffset; 2226 xpsGlyph->verticalOffset = (SkFixedToFloat(y) * -procs->centemPerUnit) 2227 - first.verticalOffset; 2228 } 2229 } 2230 2231 static void text_draw_init(const SkPaint& paint, 2232 const void* text, size_t byteLength, 2233 SkBitSet& glyphsUsed, 2234 SkDraw& myDraw, SkXPSDrawProcs& procs) { 2235 procs.fD1GProc = xps_draw_1_glyph; 2236 size_t numGlyphGuess; 2237 switch (paint.getTextEncoding()) { 2238 case SkPaint::kUTF8_TextEncoding: 2239 numGlyphGuess = SkUTF8_CountUnichars( 2240 static_cast<const char *>(text), 2241 byteLength); 2242 break; 2243 case SkPaint::kUTF16_TextEncoding: 2244 numGlyphGuess = SkUTF16_CountUnichars( 2245 static_cast<const uint16_t *>(text), 2246 byteLength); 2247 break; 2248 case SkPaint::kGlyphID_TextEncoding: 2249 numGlyphGuess = byteLength / 2; 2250 break; 2251 default: 2252 SK_DEBUGBREAK(true); 2253 } 2254 procs.xpsGlyphs.setReserve(numGlyphGuess); 2255 procs.glyphUse = &glyphsUsed; 2256 procs.centemPerUnit = 100.0f / SkScalarToFLOAT(paint.getTextSize()); 2257 2258 myDraw.fProcs = &procs; 2259 } 2260 2261 static bool text_must_be_pathed(const SkPaint& paint, const SkMatrix& matrix) { 2262 const SkPaint::Style style = paint.getStyle(); 2263 return matrix.hasPerspective() 2264 || SkPaint::kStroke_Style == style 2265 || SkPaint::kStrokeAndFill_Style == style 2266 || paint.getMaskFilter() 2267 || paint.getRasterizer() 2268 ; 2269 } 2270 2271 void SkXPSDevice::drawText(const SkDraw& d, 2272 const void* text, size_t byteLen, 2273 SkScalar x, SkScalar y, 2274 const SkPaint& paint) { 2275 if (byteLen < 1) return; 2276 2277 if (text_must_be_pathed(paint, *d.fMatrix)) { 2278 SkPath path; 2279 paint.getTextPath(text, byteLen, x, y, &path); 2280 this->drawPath(d, path, paint, NULL, true); 2281 //TODO: add automation "text" 2282 return; 2283 } 2284 2285 TypefaceUse* typeface; 2286 HRV(CreateTypefaceUse(paint, &typeface)); 2287 2288 SkDraw myDraw(d); 2289 SkXPSDrawProcs procs; 2290 text_draw_init(paint, text, byteLen, *typeface->glyphsUsed, myDraw, procs); 2291 2292 myDraw.drawText(static_cast<const char*>(text), byteLen, x, y, paint); 2293 2294 // SkDraw may have clipped out the glyphs, so we need to check 2295 if (procs.xpsGlyphs.count() == 0) { 2296 return; 2297 } 2298 2299 XPS_POINT origin = { 2300 procs.xpsGlyphs[0].horizontalOffset / procs.centemPerUnit, 2301 procs.xpsGlyphs[0].verticalOffset / -procs.centemPerUnit, 2302 }; 2303 procs.xpsGlyphs[0].horizontalOffset = 0.0f; 2304 procs.xpsGlyphs[0].verticalOffset = 0.0f; 2305 2306 HRV(AddGlyphs(d, 2307 this->fXpsFactory.get(), 2308 this->fCurrentXpsCanvas.get(), 2309 typeface, 2310 NULL, 2311 procs.xpsGlyphs.begin(), procs.xpsGlyphs.count(), 2312 &origin, 2313 SkScalarToFLOAT(paint.getTextSize()), 2314 XPS_STYLE_SIMULATION_NONE, 2315 *d.fMatrix, 2316 paint)); 2317 } 2318 2319 void SkXPSDevice::drawPosText(const SkDraw& d, 2320 const void* text, size_t byteLen, 2321 const SkScalar pos[], 2322 SkScalar constY, int scalarsPerPos, 2323 const SkPaint& paint) { 2324 if (byteLen < 1) return; 2325 2326 if (text_must_be_pathed(paint, *d.fMatrix)) { 2327 SkPath path; 2328 //TODO: make this work, Draw currently does not handle as well. 2329 //paint.getTextPath(text, byteLength, x, y, &path); 2330 //this->drawPath(d, path, paint, NULL, true); 2331 //TODO: add automation "text" 2332 return; 2333 } 2334 2335 TypefaceUse* typeface; 2336 HRV(CreateTypefaceUse(paint, &typeface)); 2337 2338 SkDraw myDraw(d); 2339 SkXPSDrawProcs procs; 2340 text_draw_init(paint, text, byteLen, *typeface->glyphsUsed, myDraw, procs); 2341 2342 myDraw.drawPosText(static_cast<const char*>(text), byteLen, 2343 pos, constY, scalarsPerPos, 2344 paint); 2345 2346 // SkDraw may have clipped out the glyphs, so we need to check 2347 if (procs.xpsGlyphs.count() == 0) { 2348 return; 2349 } 2350 2351 XPS_POINT origin = { 2352 procs.xpsGlyphs[0].horizontalOffset / procs.centemPerUnit, 2353 procs.xpsGlyphs[0].verticalOffset / -procs.centemPerUnit, 2354 }; 2355 procs.xpsGlyphs[0].horizontalOffset = 0.0f; 2356 procs.xpsGlyphs[0].verticalOffset = 0.0f; 2357 2358 HRV(AddGlyphs(d, 2359 this->fXpsFactory.get(), 2360 this->fCurrentXpsCanvas.get(), 2361 typeface, 2362 NULL, 2363 procs.xpsGlyphs.begin(), procs.xpsGlyphs.count(), 2364 &origin, 2365 SkScalarToFLOAT(paint.getTextSize()), 2366 XPS_STYLE_SIMULATION_NONE, 2367 *d.fMatrix, 2368 paint)); 2369 } 2370 2371 void SkXPSDevice::drawTextOnPath(const SkDraw& d, const void* text, size_t len, 2372 const SkPath& path, const SkMatrix* matrix, 2373 const SkPaint& paint) { 2374 //This will call back into the device to do the drawing. 2375 d.drawTextOnPath((const char*)text, len, path, matrix, paint); 2376 } 2377 2378 void SkXPSDevice::drawDevice(const SkDraw& d, SkDevice* dev, 2379 int x, int y, 2380 const SkPaint&) { 2381 SkXPSDevice* that = static_cast<SkXPSDevice*>(dev); 2382 2383 SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform; 2384 XPS_MATRIX rawTransform = { 2385 1.0f, 2386 0.0f, 2387 0.0f, 2388 1.0f, 2389 static_cast<FLOAT>(x), 2390 static_cast<FLOAT>(y), 2391 }; 2392 HRVM(this->fXpsFactory->CreateMatrixTransform(&rawTransform, &xpsTransform), 2393 "Could not create layer transform."); 2394 HRVM(that->fCurrentXpsCanvas->SetTransformLocal(xpsTransform.get()), 2395 "Could not set layer transform."); 2396 2397 //Get the current visual collection and add the layer to it. 2398 SkTScopedComPtr<IXpsOMVisualCollection> currentVisuals; 2399 HRVM(this->fCurrentXpsCanvas->GetVisuals(¤tVisuals), 2400 "Could not get current visuals for layer."); 2401 HRVM(currentVisuals->Append(that->fCurrentXpsCanvas.get()), 2402 "Could not add layer to current visuals."); 2403 } 2404 2405 bool SkXPSDevice::onReadPixels(const SkBitmap& bitmap, int x, int y, 2406 SkCanvas::Config8888) { 2407 return false; 2408 } 2409 2410 SkDevice* SkXPSDevice::onCreateCompatibleDevice(SkBitmap::Config config, 2411 int width, int height, 2412 bool isOpaque, 2413 Usage usage) { 2414 if (SkDevice::kGeneral_Usage == usage) { 2415 return NULL; 2416 SK_CRASH(); 2417 //To what stream do we write? 2418 //SkXPSDevice* dev = new SkXPSDevice(this); 2419 //SkSize s = SkSize::Make(width, height); 2420 //dev->BeginCanvas(s, s, SkMatrix::I()); 2421 //return dev; 2422 } 2423 2424 return new SkXPSDevice(this->fXpsFactory.get()); 2425 } 2426 2427 SkXPSDevice::SkXPSDevice(IXpsOMObjectFactory* xpsFactory) 2428 : SkDevice(make_fake_bitmap(10000, 10000)) 2429 , fCurrentPage(0) { 2430 2431 HRVM(CoCreateInstance( 2432 CLSID_XpsOMObjectFactory, 2433 NULL, 2434 CLSCTX_INPROC_SERVER, 2435 IID_PPV_ARGS(&this->fXpsFactory)), 2436 "Could not create factory for layer."); 2437 2438 HRVM(this->fXpsFactory->CreateCanvas(&this->fCurrentXpsCanvas), 2439 "Could not create canvas for layer."); 2440 } 2441 2442 bool SkXPSDevice::allowImageFilter(SkImageFilter*) { 2443 return false; 2444 } 2445