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