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