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