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