DMSrcSink.cpp revision eb602a5c94078fb2956c9bdc64bbf47a31b9c0e5
1/* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "DMSrcSink.h" 9#include "SamplePipeControllers.h" 10#include "SkCodec.h" 11#include "SkCommonFlags.h" 12#include "SkData.h" 13#include "SkDeferredCanvas.h" 14#include "SkDocument.h" 15#include "SkError.h" 16#include "SkFunction.h" 17#include "SkImageGenerator.h" 18#include "SkMultiPictureDraw.h" 19#include "SkNullCanvas.h" 20#include "SkOSFile.h" 21#include "SkPictureData.h" 22#include "SkPictureRecorder.h" 23#include "SkRandom.h" 24#include "SkRecordDraw.h" 25#include "SkRecorder.h" 26#include "SkSVGCanvas.h" 27#include "SkScanlineDecoder.h" 28#include "SkStream.h" 29#include "SkXMLWriter.h" 30 31DEFINE_bool(multiPage, false, "For document-type backends, render the source" 32 " into multiple pages"); 33 34static bool lazy_decode_bitmap(const void* src, size_t size, SkBitmap* dst) { 35 SkAutoTUnref<SkData> encoded(SkData::NewWithCopy(src, size)); 36 return encoded && SkInstallDiscardablePixelRef(encoded, dst); 37} 38 39namespace DM { 40 41GMSrc::GMSrc(skiagm::GMRegistry::Factory factory) : fFactory(factory) {} 42 43Error GMSrc::draw(SkCanvas* canvas) const { 44 SkAutoTDelete<skiagm::GM> gm(fFactory(NULL)); 45 canvas->concat(gm->getInitialTransform()); 46 gm->draw(canvas); 47 return ""; 48} 49 50SkISize GMSrc::size() const { 51 SkAutoTDelete<skiagm::GM> gm(fFactory(NULL)); 52 return gm->getISize(); 53} 54 55Name GMSrc::name() const { 56 SkAutoTDelete<skiagm::GM> gm(fFactory(NULL)); 57 return gm->getName(); 58} 59 60void GMSrc::modifyGrContextOptions(GrContextOptions* options) const { 61 SkAutoTDelete<skiagm::GM> gm(fFactory(NULL)); 62 gm->modifyGrContextOptions(options); 63} 64 65/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 66 67CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, float scale) 68 : fPath(path) 69 , fMode(mode) 70 , fDstColorType(dstColorType) 71 , fScale(scale) 72{} 73 74Error CodecSrc::draw(SkCanvas* canvas) const { 75 SkImageInfo canvasInfo; 76 if (NULL == canvas->peekPixels(&canvasInfo, NULL)) { 77 // TODO: Once we implement GPU paths (e.g. JPEG YUV), we should use a deferred decode to 78 // let the GPU handle it. 79 return Error::Nonfatal("No need to test decoding to non-raster backend."); 80 } 81 82 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 83 if (!encoded) { 84 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 85 } 86 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); 87 if (NULL == codec.get()) { 88 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); 89 } 90 91 // Choose the color type to decode to 92 SkImageInfo decodeInfo = codec->getInfo(); 93 SkColorType canvasColorType = canvasInfo.colorType(); 94 switch (fDstColorType) { 95 case kIndex8_Always_DstColorType: 96 decodeInfo = codec->getInfo().makeColorType(kIndex_8_SkColorType); 97 if (kRGB_565_SkColorType == canvasColorType) { 98 return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); 99 } 100 break; 101 case kGrayscale_Always_DstColorType: 102 decodeInfo = codec->getInfo().makeColorType(kGray_8_SkColorType); 103 if (kRGB_565_SkColorType == canvasColorType) { 104 return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); 105 } 106 break; 107 default: 108 decodeInfo = decodeInfo.makeColorType(canvasColorType); 109 break; 110 } 111 112 // Try to scale the image if it is desired 113 SkISize size = codec->getScaledDimensions(fScale); 114 if (size == decodeInfo.dimensions() && 1.0f != fScale) { 115 return Error::Nonfatal("Test without scaling is uninteresting."); 116 } 117 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); 118 119 // Construct a color table for the decode if necessary 120 SkAutoTUnref<SkColorTable> colorTable(NULL); 121 SkPMColor* colorPtr = NULL; 122 int* colorCountPtr = NULL; 123 int maxColors = 256; 124 if (kIndex_8_SkColorType == decodeInfo.colorType()) { 125 SkPMColor colors[256]; 126 colorTable.reset(SkNEW_ARGS(SkColorTable, (colors, maxColors))); 127 colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); 128 colorCountPtr = &maxColors; 129 } 130 131 // FIXME: Currently we cannot draw unpremultiplied sources. 132 if (decodeInfo.alphaType() == kUnpremul_SkAlphaType) { 133 decodeInfo = decodeInfo.makeAlphaType(kPremul_SkAlphaType); 134 } 135 136 SkBitmap bitmap; 137 if (!bitmap.tryAllocPixels(decodeInfo, NULL, colorTable.get())) { 138 return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str(), 139 decodeInfo.width(), decodeInfo.height()); 140 } 141 142 switch (fMode) { 143 case kNormal_Mode: { 144 switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(), NULL, 145 colorPtr, colorCountPtr)) { 146 case SkCodec::kSuccess: 147 // We consider incomplete to be valid, since we should still decode what is 148 // available. 149 case SkCodec::kIncompleteInput: 150 break; 151 case SkCodec::kInvalidConversion: 152 return Error::Nonfatal("Incompatible colortype conversion"); 153 default: 154 // Everything else is considered a failure. 155 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); 156 } 157 canvas->drawBitmap(bitmap, 0, 0); 158 break; 159 } 160 case kScanline_Mode: { 161 SkScanlineDecoder* scanlineDecoder = codec->getScanlineDecoder(decodeInfo, NULL, 162 colorPtr, colorCountPtr); 163 if (NULL == scanlineDecoder) { 164 return Error::Nonfatal("Cannot use scanline decoder for all images"); 165 } 166 const SkCodec::Result result = scanlineDecoder->getScanlines( 167 bitmap.getAddr(0, 0), decodeInfo.height(), bitmap.rowBytes()); 168 switch (result) { 169 case SkCodec::kSuccess: 170 case SkCodec::kIncompleteInput: 171 break; 172 default: 173 return SkStringPrintf("%s failed with error message %d", 174 fPath.c_str(), (int) result); 175 } 176 canvas->drawBitmap(bitmap, 0, 0); 177 break; 178 } 179 case kScanline_Subset_Mode: { 180 //this mode decodes the image in divisor*divisor subsets, using a scanline decoder 181 const int divisor = 2; 182 const int w = decodeInfo.width(); 183 const int h = decodeInfo.height(); 184 if (divisor > w || divisor > h) { 185 return Error::Nonfatal(SkStringPrintf("Cannot decode subset: divisor %d is too big" 186 "for %s with dimensions (%d x %d)", divisor, fPath.c_str(), w, h)); 187 } 188 const int subsetWidth = w/divisor; 189 const int subsetHeight = h/divisor; 190 // One of our subsets will be larger to contain any pixels that do not divide evenly. 191 const int extraX = w % divisor; 192 const int extraY = h % divisor; 193 /* 194 * if w or h are not evenly divided by divisor need to adjust width and height of end 195 * subsets to cover entire image. 196 * Add extraX and extraY to largestSubsetBm's width and height to adjust width 197 * and height of end subsets. 198 * subsetBm is extracted from largestSubsetBm. 199 * subsetBm's size is determined based on the current subset and may be larger for end 200 * subsets. 201 */ 202 SkImageInfo largestSubsetDecodeInfo = 203 decodeInfo.makeWH(subsetWidth + extraX, subsetHeight + extraY); 204 SkBitmap largestSubsetBm; 205 if (!largestSubsetBm.tryAllocPixels(largestSubsetDecodeInfo, NULL, colorTable.get())) { 206 return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str(), 207 largestSubsetDecodeInfo.width(), largestSubsetDecodeInfo.height()); 208 } 209 const size_t rowBytes = decodeInfo.minRowBytes(); 210 char* buffer = SkNEW_ARRAY(char, largestSubsetDecodeInfo.height() * rowBytes); 211 SkAutoTDeleteArray<char> lineDeleter(buffer); 212 for (int col = 0; col < divisor; col++) { 213 //currentSubsetWidth may be larger than subsetWidth for rightmost subsets 214 const int currentSubsetWidth = (col + 1 == divisor) ? 215 subsetWidth + extraX : subsetWidth; 216 const int x = col * subsetWidth; 217 for (int row = 0; row < divisor; row++) { 218 //currentSubsetHeight may be larger than subsetHeight for bottom subsets 219 const int currentSubsetHeight = (row + 1 == divisor) ? 220 subsetHeight + extraY : subsetHeight; 221 const int y = row * subsetHeight; 222 //create scanline decoder for each subset 223 SkScanlineDecoder* subsetScanlineDecoder = codec->getScanlineDecoder(decodeInfo, 224 NULL, colorPtr, colorCountPtr); 225 if (NULL == subsetScanlineDecoder) { 226 if (x == 0 && y == 0) { 227 //first try, image may not be compatible 228 return Error::Nonfatal("Cannot use scanline decoder for all images"); 229 } else { 230 return "Error scanline decoder is NULL"; 231 } 232 } 233 //skip to first line of subset 234 const SkCodec::Result skipResult = 235 subsetScanlineDecoder->skipScanlines(y); 236 switch (skipResult) { 237 case SkCodec::kSuccess: 238 case SkCodec::kIncompleteInput: 239 break; 240 default: 241 return SkStringPrintf("%s failed after attempting to skip %d scanlines" 242 "with error message %d", fPath.c_str(), y, (int) skipResult); 243 } 244 //create and set size of subsetBm 245 SkBitmap subsetBm; 246 SkIRect bounds = SkIRect::MakeWH(subsetWidth, subsetHeight); 247 bounds.setXYWH(0, 0, currentSubsetWidth, currentSubsetHeight); 248 SkAssertResult(largestSubsetBm.extractSubset(&subsetBm, bounds)); 249 SkAutoLockPixels autlockSubsetBm(subsetBm, true); 250 const SkCodec::Result subsetResult = 251 subsetScanlineDecoder->getScanlines(buffer, currentSubsetHeight, rowBytes); 252 switch (subsetResult) { 253 case SkCodec::kSuccess: 254 case SkCodec::kIncompleteInput: 255 break; 256 default: 257 return SkStringPrintf("%s failed with error message %d", 258 fPath.c_str(), (int) subsetResult); 259 } 260 const size_t bpp = decodeInfo.bytesPerPixel(); 261 /* 262 * we copy all the lines at once becuase when calling getScanlines for 263 * interlaced pngs the entire image must be read regardless of the number 264 * of lines requested. Reading an interlaced png in a loop, line-by-line, would 265 * decode the entire image height times, which is very slow 266 * it is aknowledged that copying each line as you read it in a loop 267 * may be faster for other types of images. Since this is a correctness test 268 * that's okay. 269 */ 270 char* bufferRow = buffer; 271 for (int subsetY = 0; subsetY < currentSubsetHeight; ++subsetY) { 272 memcpy(subsetBm.getAddr(0, subsetY), bufferRow + x*bpp, 273 currentSubsetWidth*bpp); 274 bufferRow += rowBytes; 275 } 276 277 canvas->drawBitmap(subsetBm, SkIntToScalar(x), SkIntToScalar(y)); 278 } 279 } 280 break; 281 } 282 case kStripe_Mode: { 283 const int height = decodeInfo.height(); 284 // This value is chosen arbitrarily. We exercise more cases by choosing a value that 285 // does not align with image blocks. 286 const int stripeHeight = 37; 287 const int numStripes = (height + stripeHeight - 1) / stripeHeight; 288 289 // Decode odd stripes 290 SkScanlineDecoder* decoder = codec->getScanlineDecoder(decodeInfo, NULL, colorPtr, 291 colorCountPtr); 292 if (NULL == decoder) { 293 return Error::Nonfatal("Cannot use scanline decoder for all images"); 294 } 295 for (int i = 0; i < numStripes; i += 2) { 296 // Skip a stripe 297 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight); 298 SkCodec::Result result = decoder->skipScanlines(linesToSkip); 299 switch (result) { 300 case SkCodec::kSuccess: 301 case SkCodec::kIncompleteInput: 302 break; 303 default: 304 return SkStringPrintf("Cannot skip scanlines for %s.", fPath.c_str()); 305 } 306 307 // Read a stripe 308 const int startY = (i + 1) * stripeHeight; 309 const int linesToRead = SkTMin(stripeHeight, height - startY); 310 if (linesToRead > 0) { 311 result = decoder->getScanlines(bitmap.getAddr(0, startY), 312 linesToRead, bitmap.rowBytes()); 313 switch (result) { 314 case SkCodec::kSuccess: 315 case SkCodec::kIncompleteInput: 316 break; 317 default: 318 return SkStringPrintf("Cannot get scanlines for %s.", fPath.c_str()); 319 } 320 } 321 } 322 323 // Decode even stripes 324 decoder = codec->getScanlineDecoder(decodeInfo, NULL, colorPtr, colorCountPtr); 325 if (NULL == decoder) { 326 return "Failed to create second scanline decoder."; 327 } 328 for (int i = 0; i < numStripes; i += 2) { 329 // Read a stripe 330 const int startY = i * stripeHeight; 331 const int linesToRead = SkTMin(stripeHeight, height - startY); 332 SkCodec::Result result = decoder->getScanlines(bitmap.getAddr(0, startY), 333 linesToRead, bitmap.rowBytes()); 334 switch (result) { 335 case SkCodec::kSuccess: 336 case SkCodec::kIncompleteInput: 337 break; 338 default: 339 return SkStringPrintf("Cannot get scanlines for %s.", fPath.c_str()); 340 } 341 342 // Skip a stripe 343 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight); 344 if (linesToSkip > 0) { 345 result = decoder->skipScanlines(linesToSkip); 346 switch (result) { 347 case SkCodec::kSuccess: 348 case SkCodec::kIncompleteInput: 349 break; 350 default: 351 return SkStringPrintf("Cannot skip scanlines for %s.", fPath.c_str()); 352 } 353 } 354 } 355 canvas->drawBitmap(bitmap, 0, 0); 356 break; 357 } 358 } 359 return ""; 360} 361 362SkISize CodecSrc::size() const { 363 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 364 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); 365 if (NULL != codec) { 366 SkISize size = codec->getScaledDimensions(fScale); 367 return size; 368 } else { 369 return SkISize::Make(0, 0); 370 } 371} 372 373Name CodecSrc::name() const { 374 if (1.0f == fScale) { 375 return SkOSPath::Basename(fPath.c_str()); 376 } else { 377 return SkStringPrintf("%s_%.3f", SkOSPath::Basename(fPath.c_str()).c_str(), fScale); 378 } 379} 380 381/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 382 383ImageSrc::ImageSrc(Path path, int divisor) : fPath(path), fDivisor(divisor) {} 384 385Error ImageSrc::draw(SkCanvas* canvas) const { 386 SkImageInfo canvasInfo; 387 if (NULL == canvas->peekPixels(&canvasInfo, NULL)) { 388 // TODO: Instead, use lazy decoding to allow the GPU to handle cases like YUV. 389 return Error::Nonfatal("No need to test decoding to non-raster backend."); 390 } 391 392 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 393 if (!encoded) { 394 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 395 } 396 const SkColorType dstColorType = canvasInfo.colorType(); 397 if (fDivisor == 0) { 398 // Decode the full image. 399 SkBitmap bitmap; 400 if (!SkImageDecoder::DecodeMemory(encoded->data(), encoded->size(), &bitmap, 401 dstColorType, SkImageDecoder::kDecodePixels_Mode)) { 402 return SkStringPrintf("Couldn't decode %s.", fPath.c_str()); 403 } 404 if (kRGB_565_SkColorType == dstColorType && !bitmap.isOpaque()) { 405 // Do not draw a bitmap with alpha to a destination without alpha. 406 return Error::Nonfatal("Uninteresting to decode image with alpha into 565."); 407 } 408 encoded.reset((SkData*)NULL); // Might as well drop this when we're done with it. 409 canvas->drawBitmap(bitmap, 0,0); 410 return ""; 411 } 412 // Decode subsets. This is a little involved. 413 SkAutoTDelete<SkMemoryStream> stream(new SkMemoryStream(encoded)); 414 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream.get())); 415 if (!decoder) { 416 return SkStringPrintf("Can't find a good decoder for %s.", fPath.c_str()); 417 } 418 stream->rewind(); 419 int w,h; 420 if (!decoder->buildTileIndex(stream.detach(), &w, &h)) { 421 return Error::Nonfatal("Subset decoding not supported."); 422 } 423 424 // Divide the image into subsets that cover the entire image. 425 if (fDivisor > w || fDivisor > h) { 426 return Error::Nonfatal(SkStringPrintf("Cannot decode subset: divisor %d is too big" 427 "for %s with dimensions (%d x %d)", fDivisor, fPath.c_str(), w, h)); 428 } 429 const int subsetWidth = w / fDivisor, 430 subsetHeight = h / fDivisor; 431 for (int y = 0; y < h; y += subsetHeight) { 432 for (int x = 0; x < w; x += subsetWidth) { 433 SkBitmap subset; 434 SkIRect rect = SkIRect::MakeXYWH(x, y, subsetWidth, subsetHeight); 435 if (!decoder->decodeSubset(&subset, rect, dstColorType)) { 436 return SkStringPrintf("Could not decode subset (%d, %d, %d, %d).", 437 x, y, x+subsetWidth, y+subsetHeight); 438 } 439 if (kRGB_565_SkColorType == dstColorType && !subset.isOpaque()) { 440 // Do not draw a bitmap with alpha to a destination without alpha. 441 // This is not an error, but there is nothing interesting to show. 442 443 // This should only happen on the first iteration through the loop. 444 SkASSERT(0 == x && 0 == y); 445 446 return Error::Nonfatal("Uninteresting to decode image with alpha into 565."); 447 } 448 canvas->drawBitmap(subset, SkIntToScalar(x), SkIntToScalar(y)); 449 } 450 } 451 return ""; 452} 453 454SkISize ImageSrc::size() const { 455 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 456 SkBitmap bitmap; 457 if (!encoded || !SkImageDecoder::DecodeMemory(encoded->data(), 458 encoded->size(), 459 &bitmap, 460 kUnknown_SkColorType, 461 SkImageDecoder::kDecodeBounds_Mode)) { 462 return SkISize::Make(0,0); 463 } 464 return bitmap.dimensions(); 465} 466 467Name ImageSrc::name() const { 468 return SkOSPath::Basename(fPath.c_str()); 469} 470 471/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 472 473static const SkRect kSKPViewport = {0,0, 1000,1000}; 474 475SKPSrc::SKPSrc(Path path) : fPath(path) {} 476 477Error SKPSrc::draw(SkCanvas* canvas) const { 478 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str())); 479 if (!stream) { 480 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 481 } 482 SkAutoTUnref<SkPicture> pic(SkPicture::CreateFromStream(stream, &lazy_decode_bitmap)); 483 if (!pic) { 484 return SkStringPrintf("Couldn't decode %s as a picture.", fPath.c_str()); 485 } 486 stream.reset((SkStream*)NULL); // Might as well drop this when we're done with it. 487 488 canvas->clipRect(kSKPViewport); 489 canvas->drawPicture(pic); 490 return ""; 491} 492 493SkISize SKPSrc::size() const { 494 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str())); 495 if (!stream) { 496 return SkISize::Make(0,0); 497 } 498 SkPictInfo info; 499 if (!SkPicture::InternalOnly_StreamIsSKP(stream, &info)) { 500 return SkISize::Make(0,0); 501 } 502 SkRect viewport = kSKPViewport; 503 if (!viewport.intersect(info.fCullRect)) { 504 return SkISize::Make(0,0); 505 } 506 return viewport.roundOut().size(); 507} 508 509Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); } 510 511/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 512 513Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const { 514 SkAutoTDelete<SkCanvas> canvas(SkCreateNullCanvas()); 515 return src.draw(canvas); 516} 517 518/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 519 520DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?"); 521 522GPUSink::GPUSink(GrContextFactory::GLContextType ct, 523 GrGLStandard api, 524 int samples, 525 bool dfText, 526 bool threaded) 527 : fContextType(ct) 528 , fGpuAPI(api) 529 , fSampleCount(samples) 530 , fUseDFText(dfText) 531 , fThreaded(threaded) {} 532 533int GPUSink::enclave() const { 534 return fThreaded ? kAnyThread_Enclave : kGPU_Enclave; 535} 536 537void PreAbandonGpuContextErrorHandler(SkError, void*) {} 538 539Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const { 540 GrContextOptions options; 541 src.modifyGrContextOptions(&options); 542 543 GrContextFactory factory(options); 544 const SkISize size = src.size(); 545 const SkImageInfo info = 546 SkImageInfo::Make(size.width(), size.height(), kN32_SkColorType, kPremul_SkAlphaType); 547 SkAutoTUnref<SkSurface> surface( 548 NewGpuSurface(&factory, fContextType, fGpuAPI, info, fSampleCount, fUseDFText)); 549 if (!surface) { 550 return "Could not create a surface."; 551 } 552 if (FLAGS_preAbandonGpuContext) { 553 SkSetErrorCallback(&PreAbandonGpuContextErrorHandler, NULL); 554 factory.abandonContexts(); 555 } 556 SkCanvas* canvas = surface->getCanvas(); 557 Error err = src.draw(canvas); 558 if (!err.isEmpty()) { 559 return err; 560 } 561 canvas->flush(); 562 if (FLAGS_gpuStats) { 563 canvas->getGrContext()->dumpCacheStats(log); 564 canvas->getGrContext()->dumpGpuStats(log); 565 } 566 dst->allocPixels(info); 567 canvas->readPixels(dst, 0, 0); 568 if (FLAGS_abandonGpuContext) { 569 factory.abandonContexts(); 570 } 571 return ""; 572} 573 574/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 575 576static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) { 577 // Print the given DM:Src to a document, breaking on 8.5x11 pages. 578 SkASSERT(doc); 579 int width = src.size().width(), 580 height = src.size().height(); 581 582 if (FLAGS_multiPage) { 583 const int kLetterWidth = 612, // 8.5 * 72 584 kLetterHeight = 792; // 11 * 72 585 const SkRect letter = SkRect::MakeWH(SkIntToScalar(kLetterWidth), 586 SkIntToScalar(kLetterHeight)); 587 588 int xPages = ((width - 1) / kLetterWidth) + 1; 589 int yPages = ((height - 1) / kLetterHeight) + 1; 590 591 for (int y = 0; y < yPages; ++y) { 592 for (int x = 0; x < xPages; ++x) { 593 int w = SkTMin(kLetterWidth, width - (x * kLetterWidth)); 594 int h = SkTMin(kLetterHeight, height - (y * kLetterHeight)); 595 SkCanvas* canvas = 596 doc->beginPage(SkIntToScalar(w), SkIntToScalar(h)); 597 if (!canvas) { 598 return "SkDocument::beginPage(w,h) returned NULL"; 599 } 600 canvas->clipRect(letter); 601 canvas->translate(-letter.width() * x, -letter.height() * y); 602 Error err = src.draw(canvas); 603 if (!err.isEmpty()) { 604 return err; 605 } 606 doc->endPage(); 607 } 608 } 609 } else { 610 SkCanvas* canvas = 611 doc->beginPage(SkIntToScalar(width), SkIntToScalar(height)); 612 if (!canvas) { 613 return "SkDocument::beginPage(w,h) returned NULL"; 614 } 615 Error err = src.draw(canvas); 616 if (!err.isEmpty()) { 617 return err; 618 } 619 doc->endPage(); 620 } 621 if (!doc->close()) { 622 return "SkDocument::close() returned false"; 623 } 624 dst->flush(); 625 return ""; 626} 627 628PDFSink::PDFSink() {} 629 630Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 631 SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(dst)); 632 if (!doc) { 633 return "SkDocument::CreatePDF() returned NULL"; 634 } 635 return draw_skdocument(src, doc.get(), dst); 636} 637 638/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 639 640XPSSink::XPSSink() {} 641 642Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 643 SkAutoTUnref<SkDocument> doc(SkDocument::CreateXPS(dst)); 644 if (!doc) { 645 return "SkDocument::CreateXPS() returned NULL"; 646 } 647 return draw_skdocument(src, doc.get(), dst); 648} 649/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 650 651SKPSink::SKPSink() {} 652 653Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 654 SkSize size; 655 size = src.size(); 656 SkPictureRecorder recorder; 657 Error err = src.draw(recorder.beginRecording(size.width(), size.height())); 658 if (!err.isEmpty()) { 659 return err; 660 } 661 SkAutoTUnref<SkPicture> pic(recorder.endRecording()); 662 pic->serialize(dst); 663 return ""; 664} 665 666/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 667 668SVGSink::SVGSink() {} 669 670Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 671 SkAutoTDelete<SkXMLWriter> xmlWriter(SkNEW_ARGS(SkXMLStreamWriter, (dst))); 672 SkAutoTUnref<SkCanvas> canvas(SkSVGCanvas::Create( 673 SkRect::MakeWH(SkIntToScalar(src.size().width()), SkIntToScalar(src.size().height())), 674 xmlWriter)); 675 return src.draw(canvas); 676} 677 678/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 679 680RasterSink::RasterSink(SkColorType colorType) : fColorType(colorType) {} 681 682Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const { 683 const SkISize size = src.size(); 684 // If there's an appropriate alpha type for this color type, use it, otherwise use premul. 685 SkAlphaType alphaType = kPremul_SkAlphaType; 686 (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType); 687 688 dst->allocPixels(SkImageInfo::Make(size.width(), size.height(), fColorType, alphaType)); 689 dst->eraseColor(SK_ColorTRANSPARENT); 690 SkCanvas canvas(*dst); 691 return src.draw(&canvas); 692} 693 694/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 695 696// Handy for front-patching a Src. Do whatever up-front work you need, then call draw_to_canvas(), 697// passing the Sink draw() arguments, a size, and a function draws into an SkCanvas. 698// Several examples below. 699 700static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log, 701 SkISize size, SkFunction<Error(SkCanvas*)> draw) { 702 class ProxySrc : public Src { 703 public: 704 ProxySrc(SkISize size, SkFunction<Error(SkCanvas*)> draw) : fSize(size), fDraw(draw) {} 705 Error draw(SkCanvas* canvas) const override { return fDraw(canvas); } 706 Name name() const override { sk_throw(); return ""; } // Won't be called. 707 SkISize size() const override { return fSize; } 708 private: 709 SkISize fSize; 710 SkFunction<Error(SkCanvas*)> fDraw; 711 }; 712 return sink->draw(ProxySrc(size, draw), bitmap, stream, log); 713} 714 715/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 716 717static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) { 718 SkRect bounds = SkRect::MakeIWH(srcW, srcH); 719 matrix->mapRect(&bounds); 720 matrix->postTranslate(-bounds.x(), -bounds.y()); 721 return SkISize::Make(SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height())); 722} 723 724ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {} 725 726Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 727 SkMatrix matrix = fMatrix; 728 SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height()); 729 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) { 730 canvas->concat(matrix); 731 return src.draw(canvas); 732 }); 733} 734 735// Undoes any flip or 90 degree rotate without changing the scale of the bitmap. 736// This should be pixel-preserving. 737ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {} 738 739Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 740 Error err = fSink->draw(src, bitmap, stream, log); 741 if (!err.isEmpty()) { 742 return err; 743 } 744 745 SkMatrix inverse; 746 if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) { 747 return "Cannot upright --matrix."; 748 } 749 SkMatrix upright = SkMatrix::I(); 750 upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX())); 751 upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY())); 752 upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX())); 753 upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY())); 754 755 SkBitmap uprighted; 756 SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height()); 757 uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height())); 758 759 SkCanvas canvas(uprighted); 760 canvas.concat(upright); 761 SkPaint paint; 762 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 763 canvas.drawBitmap(*bitmap, 0, 0, &paint); 764 765 *bitmap = uprighted; 766 bitmap->lockPixels(); 767 return ""; 768} 769 770/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 771 772Error ViaPipe::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 773 auto size = src.size(); 774 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) { 775 PipeController controller(canvas, &SkImageDecoder::DecodeMemory); 776 SkGPipeWriter pipe; 777 const uint32_t kFlags = 0; // We mirror SkDeferredCanvas, which doesn't use any flags. 778 return src.draw(pipe.startRecording(&controller, kFlags, size.width(), size.height())); 779 }); 780} 781 782/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 783 784Error ViaDeferred::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 785 // We draw via a deferred canvas into a surface that's compatible with the original canvas, 786 // then snap that surface as an image and draw it into the original canvas. 787 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) -> Error { 788 SkAutoTUnref<SkSurface> surface(canvas->newSurface(canvas->imageInfo())); 789 if (!surface.get()) { 790 return "can't make surface for deferred canvas"; 791 } 792 SkAutoTDelete<SkDeferredCanvas> defcan(SkDeferredCanvas::Create(surface)); 793 Error err = src.draw(defcan); 794 if (!err.isEmpty()) { 795 return err; 796 } 797 SkAutoTUnref<SkImage> image(defcan->newImageSnapshot()); 798 if (!image) { 799 return "failed to create deferred image snapshot"; 800 } 801 canvas->drawImage(image, 0, 0, NULL); 802 return ""; 803 }); 804} 805 806/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 807 808Error ViaSerialization::draw( 809 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 810 // Record our Src into a picture. 811 auto size = src.size(); 812 SkPictureRecorder recorder; 813 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 814 SkIntToScalar(size.height()))); 815 if (!err.isEmpty()) { 816 return err; 817 } 818 SkAutoTUnref<SkPicture> pic(recorder.endRecording()); 819 820 // Serialize it and then deserialize it. 821 SkDynamicMemoryWStream wStream; 822 pic->serialize(&wStream); 823 SkAutoTDelete<SkStream> rStream(wStream.detachAsStream()); 824 SkAutoTUnref<SkPicture> deserialized(SkPicture::CreateFromStream(rStream, &lazy_decode_bitmap)); 825 826 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) { 827 canvas->drawPicture(deserialized); 828 return ""; 829 }); 830} 831 832/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 833 834ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink) 835 : Via(sink) 836 , fW(w) 837 , fH(h) 838 , fFactory(factory) {} 839 840Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 841 auto size = src.size(); 842 SkPictureRecorder recorder; 843 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 844 SkIntToScalar(size.height()), 845 fFactory.get())); 846 if (!err.isEmpty()) { 847 return err; 848 } 849 SkAutoTUnref<SkPicture> pic(recorder.endRecordingAsPicture()); 850 851 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) { 852 const int xTiles = (size.width() + fW - 1) / fW, 853 yTiles = (size.height() + fH - 1) / fH; 854 SkMultiPictureDraw mpd(xTiles*yTiles); 855 SkTDArray<SkSurface*> surfaces; 856 surfaces.setReserve(xTiles*yTiles); 857 858 SkImageInfo info = canvas->imageInfo().makeWH(fW, fH); 859 for (int j = 0; j < yTiles; j++) { 860 for (int i = 0; i < xTiles; i++) { 861 // This lets our ultimate Sink determine the best kind of surface. 862 // E.g., if it's a GpuSink, the surfaces and images are textures. 863 SkSurface* s = canvas->newSurface(info); 864 if (!s) { 865 s = SkSurface::NewRaster(info); // Some canvases can't create surfaces. 866 } 867 surfaces.push(s); 868 SkCanvas* c = s->getCanvas(); 869 c->translate(SkIntToScalar(-i * fW), 870 SkIntToScalar(-j * fH)); // Line up the canvas with this tile. 871 mpd.add(c, pic); 872 } 873 } 874 mpd.draw(); 875 for (int j = 0; j < yTiles; j++) { 876 for (int i = 0; i < xTiles; i++) { 877 SkAutoTUnref<SkImage> image(surfaces[i+xTiles*j]->newImageSnapshot()); 878 canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH)); 879 } 880 } 881 surfaces.unrefAll(); 882 return ""; 883 }); 884} 885 886/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 887 888// Draw the Src into two pictures, then draw the second picture into the wrapped Sink. 889// This tests that any shortcuts we may take while recording that second picture are legal. 890Error ViaSecondPicture::draw( 891 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 892 auto size = src.size(); 893 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 894 SkPictureRecorder recorder; 895 SkAutoTUnref<SkPicture> pic; 896 for (int i = 0; i < 2; i++) { 897 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 898 SkIntToScalar(size.height()))); 899 if (!err.isEmpty()) { 900 return err; 901 } 902 pic.reset(recorder.endRecordingAsPicture()); 903 } 904 canvas->drawPicture(pic); 905 return ""; 906 }); 907} 908 909/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 910 911// Draw the Src twice. This can help exercise caching. 912Error ViaTwice::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 913 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) -> Error { 914 for (int i = 0; i < 2; i++) { 915 SkAutoCanvasRestore acr(canvas, true/*save now*/); 916 canvas->clear(SK_ColorTRANSPARENT); 917 Error err = src.draw(canvas); 918 if (err.isEmpty()) { 919 return err; 920 } 921 } 922 return ""; 923 }); 924} 925 926/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 927 928// This is like SkRecords::Draw, in that it plays back SkRecords ops into a Canvas. 929// Unlike SkRecords::Draw, it builds a single-op sub-picture out of each Draw-type op. 930// This is an only-slightly-exaggerated simluation of Blink's Slimming Paint pictures. 931struct DrawsAsSingletonPictures { 932 SkCanvas* fCanvas; 933 const SkDrawableList& fDrawables; 934 935 SK_CREATE_MEMBER_DETECTOR(paint); 936 937 template <typename T> 938 void draw(const T& op, SkCanvas* canvas) { 939 // We must pass SkMatrix::I() as our initial matrix. 940 // By default SkRecords::Draw() uses the canvas' matrix as its initial matrix, 941 // which would have the funky effect of applying transforms over and over. 942 SkRecords::Draw d(canvas, nullptr, fDrawables.begin(), fDrawables.count(), &SkMatrix::I()); 943 d(op); 944 } 945 946 // Most things that have paints are Draw-type ops. Create sub-pictures for each. 947 template <typename T> 948 SK_WHEN(HasMember_paint<T>, void) operator()(const T& op) { 949 SkPictureRecorder rec; 950 this->draw(op, rec.beginRecording(SkRect::MakeLargest())); 951 SkAutoTUnref<SkPicture> pic(rec.endRecordingAsPicture()); 952 fCanvas->drawPicture(pic); 953 } 954 955 // If you don't have a paint or are a SaveLayer, you're not a Draw-type op. 956 // We cannot make subpictures out of these because they affect state. Draw them directly. 957 template <typename T> 958 SK_WHEN(!HasMember_paint<T>, void) operator()(const T& op) { this->draw(op, fCanvas); } 959 void operator()(const SkRecords::SaveLayer& op) { this->draw(op, fCanvas); } 960}; 961 962// Record Src into a picture, then record it into a macro picture with a sub-picture for each draw. 963// Then play back that macro picture into our wrapped sink. 964Error ViaSingletonPictures::draw( 965 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 966 auto size = src.size(); 967 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 968 // Use low-level (Skia-private) recording APIs so we can read the SkRecord. 969 SkRecord skr; 970 SkRecorder recorder(&skr, size.width(), size.height()); 971 Error err = src.draw(&recorder); 972 if (!err.isEmpty()) { 973 return err; 974 } 975 976 // Record our macro-picture, with each draw op as its own sub-picture. 977 SkPictureRecorder macroRec; 978 SkCanvas* macroCanvas = macroRec.beginRecording(SkIntToScalar(size.width()), 979 SkIntToScalar(size.height())); 980 981 SkAutoTDelete<SkDrawableList> drawables(recorder.detachDrawableList()); 982 const SkDrawableList empty; 983 984 DrawsAsSingletonPictures drawsAsSingletonPictures = { 985 macroCanvas, 986 drawables ? *drawables : empty, 987 }; 988 for (unsigned i = 0; i < skr.count(); i++) { 989 skr.visit<void>(i, drawsAsSingletonPictures); 990 } 991 SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture()); 992 993 canvas->drawPicture(macroPic); 994 return ""; 995 }); 996} 997 998} // namespace DM 999