gfx/skia/trunk/src/device/xps/SkXPSDevice.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial