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