DMSrcSink.cpp revision 6dea83f244cfdea52901eef6b31cee60b07a8ea0
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 "SkAndroidCodec.h" 11#include "SkCodec.h" 12#include "SkCommonFlags.h" 13#include "SkData.h" 14#include "SkDocument.h" 15#include "SkError.h" 16#include "SkImageGenerator.h" 17#include "SkMultiPictureDraw.h" 18#include "SkNullCanvas.h" 19#include "SkOSFile.h" 20#include "SkPictureData.h" 21#include "SkPictureRecorder.h" 22#include "SkRandom.h" 23#include "SkRecordDraw.h" 24#include "SkRecorder.h" 25#include "SkRemote.h" 26#include "SkSVGCanvas.h" 27#include "SkStream.h" 28#include "SkTLogic.h" 29#include "SkXMLWriter.h" 30#include "SkSwizzler.h" 31#include <functional> 32 33DEFINE_bool(multiPage, false, "For document-type backends, render the source" 34 " into multiple pages"); 35 36static bool lazy_decode_bitmap(const void* src, size_t size, SkBitmap* dst) { 37 SkAutoTUnref<SkData> encoded(SkData::NewWithCopy(src, size)); 38 return encoded && SkDEPRECATED_InstallDiscardablePixelRef(encoded, dst); 39} 40 41namespace DM { 42 43GMSrc::GMSrc(skiagm::GMRegistry::Factory factory) : fFactory(factory) {} 44 45Error GMSrc::draw(SkCanvas* canvas) const { 46 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr)); 47 canvas->concat(gm->getInitialTransform()); 48 gm->draw(canvas); 49 return ""; 50} 51 52SkISize GMSrc::size() const { 53 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr)); 54 return gm->getISize(); 55} 56 57Name GMSrc::name() const { 58 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr)); 59 return gm->getName(); 60} 61 62void GMSrc::modifyGrContextOptions(GrContextOptions* options) const { 63 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr)); 64 gm->modifyGrContextOptions(options); 65} 66 67/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 68 69BRDSrc::BRDSrc(Path path, SkBitmapRegionDecoder::Strategy strategy, Mode mode, 70 CodecSrc::DstColorType dstColorType, uint32_t sampleSize) 71 : fPath(path) 72 , fStrategy(strategy) 73 , fMode(mode) 74 , fDstColorType(dstColorType) 75 , fSampleSize(sampleSize) 76{} 77 78bool BRDSrc::veto(SinkFlags flags) const { 79 // No need to test to non-raster or indirect backends. 80 return flags.type != SinkFlags::kRaster 81 || flags.approach != SinkFlags::kDirect; 82} 83 84static SkBitmapRegionDecoder* create_brd(Path path, 85 SkBitmapRegionDecoder::Strategy strategy) { 86 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str())); 87 if (!encoded) { 88 return NULL; 89 } 90 return SkBitmapRegionDecoder::Create(encoded, strategy); 91} 92 93Error BRDSrc::draw(SkCanvas* canvas) const { 94 SkColorType colorType = canvas->imageInfo().colorType(); 95 if (kRGB_565_SkColorType == colorType && 96 CodecSrc::kGetFromCanvas_DstColorType != fDstColorType) { 97 return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); 98 } 99 switch (fDstColorType) { 100 case CodecSrc::kGetFromCanvas_DstColorType: 101 break; 102 case CodecSrc::kIndex8_Always_DstColorType: 103 colorType = kIndex_8_SkColorType; 104 break; 105 case CodecSrc::kGrayscale_Always_DstColorType: 106 colorType = kGray_8_SkColorType; 107 break; 108 } 109 110 SkAutoTDelete<SkBitmapRegionDecoder> brd(create_brd(fPath, fStrategy)); 111 if (nullptr == brd.get()) { 112 return Error::Nonfatal(SkStringPrintf("Could not create brd for %s.", fPath.c_str())); 113 } 114 115 if (!brd->conversionSupported(colorType)) { 116 return Error::Nonfatal("Cannot convert to color type.\n"); 117 } 118 119 const uint32_t width = brd->width(); 120 const uint32_t height = brd->height(); 121 // Visually inspecting very small output images is not necessary. 122 if ((width / fSampleSize <= 10 || height / fSampleSize <= 10) && 1 != fSampleSize) { 123 return Error::Nonfatal("Scaling very small images is uninteresting."); 124 } 125 switch (fMode) { 126 case kFullImage_Mode: { 127 SkBitmap bitmap; 128 if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(0, 0, width, height), 129 fSampleSize, colorType, false)) { 130 return "Cannot decode (full) region.\n"; 131 } 132 if (colorType != bitmap.colorType()) { 133 return Error::Nonfatal("Cannot convert to color type.\n"); 134 } 135 canvas->drawBitmap(bitmap, 0, 0); 136 return ""; 137 } 138 case kDivisor_Mode: { 139 const uint32_t divisor = 2; 140 if (width < divisor || height < divisor) { 141 return Error::Nonfatal("Divisor is larger than image dimension.\n"); 142 } 143 144 // Use a border to test subsets that extend outside the image. 145 // We will not allow the border to be larger than the image dimensions. Allowing 146 // these large borders causes off by one errors that indicate a problem with the 147 // test suite, not a problem with the implementation. 148 const uint32_t maxBorder = SkTMin(width, height) / (fSampleSize * divisor); 149 const uint32_t scaledBorder = SkTMin(5u, maxBorder); 150 const uint32_t unscaledBorder = scaledBorder * fSampleSize; 151 152 // We may need to clear the canvas to avoid uninitialized memory. 153 // Assume we are scaling a 780x780 image with sampleSize = 8. 154 // The output image should be 97x97. 155 // Each subset will be 390x390. 156 // Each scaled subset be 48x48. 157 // Four scaled subsets will only fill a 96x96 image. 158 // The bottom row and last column will not be touched. 159 // This is an unfortunate result of our rounding rules when scaling. 160 // Maybe we need to consider testing scaled subsets without trying to 161 // combine them to match the full scaled image? Or maybe this is the 162 // best we can do? 163 canvas->clear(0); 164 165 for (uint32_t x = 0; x < divisor; x++) { 166 for (uint32_t y = 0; y < divisor; y++) { 167 // Calculate the subset dimensions 168 uint32_t subsetWidth = width / divisor; 169 uint32_t subsetHeight = height / divisor; 170 const int left = x * subsetWidth; 171 const int top = y * subsetHeight; 172 173 // Increase the size of the last subset in each row or column, when the 174 // divisor does not divide evenly into the image dimensions 175 subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0; 176 subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0; 177 178 // Increase the size of the subset in order to have a border on each side 179 const int decodeLeft = left - unscaledBorder; 180 const int decodeTop = top - unscaledBorder; 181 const uint32_t decodeWidth = subsetWidth + unscaledBorder * 2; 182 const uint32_t decodeHeight = subsetHeight + unscaledBorder * 2; 183 SkBitmap bitmap; 184 if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(decodeLeft, 185 decodeTop, decodeWidth, decodeHeight), fSampleSize, colorType, false)) { 186 return "Cannot decode region.\n"; 187 } 188 if (colorType != bitmap.colorType()) { 189 return Error::Nonfatal("Cannot convert to color type.\n"); 190 } 191 192 canvas->drawBitmapRect(bitmap, 193 SkRect::MakeXYWH((SkScalar) scaledBorder, (SkScalar) scaledBorder, 194 (SkScalar) (subsetWidth / fSampleSize), 195 (SkScalar) (subsetHeight / fSampleSize)), 196 SkRect::MakeXYWH((SkScalar) (left / fSampleSize), 197 (SkScalar) (top / fSampleSize), 198 (SkScalar) (subsetWidth / fSampleSize), 199 (SkScalar) (subsetHeight / fSampleSize)), 200 nullptr); 201 } 202 } 203 return ""; 204 } 205 default: 206 SkASSERT(false); 207 return "Error: Should not be reached.\n"; 208 } 209} 210 211SkISize BRDSrc::size() const { 212 SkAutoTDelete<SkBitmapRegionDecoder> brd(create_brd(fPath, fStrategy)); 213 if (brd) { 214 return SkISize::Make(SkTMax(1, brd->width() / (int) fSampleSize), 215 SkTMax(1, brd->height() / (int) fSampleSize)); 216 } 217 return SkISize::Make(0, 0); 218} 219 220static SkString get_scaled_name(const Path& path, float scale) { 221 return SkStringPrintf("%s_%.3f", SkOSPath::Basename(path.c_str()).c_str(), scale); 222} 223 224Name BRDSrc::name() const { 225 // We will replicate the names used by CodecSrc so that images can 226 // be compared in Gold. 227 if (1 == fSampleSize) { 228 return SkOSPath::Basename(fPath.c_str()); 229 } 230 return get_scaled_name(fPath, 1.0f / (float) fSampleSize); 231} 232 233/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 234 235CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, float scale) 236 : fPath(path) 237 , fMode(mode) 238 , fDstColorType(dstColorType) 239 , fScale(scale) 240{} 241 242bool CodecSrc::veto(SinkFlags flags) const { 243 // No need to test decoding to non-raster or indirect backend. 244 // TODO: Once we implement GPU paths (e.g. JPEG YUV), we should use a deferred decode to 245 // let the GPU handle it. 246 return flags.type != SinkFlags::kRaster 247 || flags.approach != SinkFlags::kDirect; 248} 249 250bool get_decode_info(SkImageInfo* decodeInfo, const SkImageInfo& defaultInfo, 251 SkColorType canvasColorType, CodecSrc::DstColorType dstColorType) { 252 switch (dstColorType) { 253 case CodecSrc::kIndex8_Always_DstColorType: 254 if (kRGB_565_SkColorType == canvasColorType) { 255 return false; 256 } 257 *decodeInfo = defaultInfo.makeColorType(kIndex_8_SkColorType); 258 break; 259 case CodecSrc::kGrayscale_Always_DstColorType: 260 if (kRGB_565_SkColorType == canvasColorType) { 261 return false; 262 } 263 *decodeInfo = defaultInfo.makeColorType(kGray_8_SkColorType); 264 break; 265 default: 266 *decodeInfo = defaultInfo.makeColorType(canvasColorType); 267 break; 268 } 269 270 // FIXME: Currently we cannot draw unpremultiplied sources. 271 if (decodeInfo->alphaType() == kUnpremul_SkAlphaType) { 272 *decodeInfo = decodeInfo->makeAlphaType(kPremul_SkAlphaType); 273 } 274 return true; 275} 276 277Error CodecSrc::draw(SkCanvas* canvas) const { 278 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 279 if (!encoded) { 280 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 281 } 282 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); 283 if (nullptr == codec.get()) { 284 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); 285 } 286 287 SkImageInfo decodeInfo; 288 if (!get_decode_info(&decodeInfo, codec->getInfo(), canvas->imageInfo().colorType(), 289 fDstColorType)) { 290 return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); 291 } 292 293 // Try to scale the image if it is desired 294 SkISize size = codec->getScaledDimensions(fScale); 295 if (size == decodeInfo.dimensions() && 1.0f != fScale) { 296 return Error::Nonfatal("Test without scaling is uninteresting."); 297 } 298 299 // Visually inspecting very small output images is not necessary. We will 300 // cover these cases in unit testing. 301 if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) { 302 return Error::Nonfatal("Scaling very small images is uninteresting."); 303 } 304 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); 305 306 // Construct a color table for the decode if necessary 307 SkAutoTUnref<SkColorTable> colorTable(nullptr); 308 SkPMColor* colorPtr = nullptr; 309 int* colorCountPtr = nullptr; 310 int maxColors = 256; 311 if (kIndex_8_SkColorType == decodeInfo.colorType()) { 312 SkPMColor colors[256]; 313 colorTable.reset(new SkColorTable(colors, maxColors)); 314 colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); 315 colorCountPtr = &maxColors; 316 } 317 318 SkBitmap bitmap; 319 if (!bitmap.tryAllocPixels(decodeInfo, nullptr, colorTable.get())) { 320 return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str(), 321 decodeInfo.width(), decodeInfo.height()); 322 } 323 324 switch (fMode) { 325 case kCodec_Mode: { 326 switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(), nullptr, 327 colorPtr, colorCountPtr)) { 328 case SkCodec::kSuccess: 329 // We consider incomplete to be valid, since we should still decode what is 330 // available. 331 case SkCodec::kIncompleteInput: 332 break; 333 case SkCodec::kInvalidConversion: 334 return Error::Nonfatal("Incompatible colortype conversion"); 335 default: 336 // Everything else is considered a failure. 337 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); 338 } 339 canvas->drawBitmap(bitmap, 0, 0); 340 break; 341 } 342 case kScanline_Mode: { 343 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr, 344 colorCountPtr)) { 345 return Error::Nonfatal("Could not start scanline decoder"); 346 } 347 348 void* dst = bitmap.getAddr(0, 0); 349 size_t rowBytes = bitmap.rowBytes(); 350 uint32_t height = decodeInfo.height(); 351 switch (codec->getScanlineOrder()) { 352 case SkCodec::kTopDown_SkScanlineOrder: 353 case SkCodec::kBottomUp_SkScanlineOrder: 354 case SkCodec::kNone_SkScanlineOrder: 355 // We do not need to check the return value. On an incomplete 356 // image, memory will be filled with a default value. 357 codec->getScanlines(dst, height, rowBytes); 358 break; 359 case SkCodec::kOutOfOrder_SkScanlineOrder: { 360 for (int y = 0; y < decodeInfo.height(); y++) { 361 int dstY = codec->outputScanline(y); 362 void* dstPtr = bitmap.getAddr(0, dstY); 363 // We complete the loop, even if this call begins to fail 364 // due to an incomplete image. This ensures any uninitialized 365 // memory will be filled with the proper value. 366 codec->getScanlines(dstPtr, 1, bitmap.rowBytes()); 367 } 368 break; 369 } 370 } 371 372 canvas->drawBitmap(bitmap, 0, 0); 373 break; 374 } 375 case kStripe_Mode: { 376 const int height = decodeInfo.height(); 377 // This value is chosen arbitrarily. We exercise more cases by choosing a value that 378 // does not align with image blocks. 379 const int stripeHeight = 37; 380 const int numStripes = (height + stripeHeight - 1) / stripeHeight; 381 382 // Decode odd stripes 383 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr, 384 colorCountPtr) 385 || SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOrder()) { 386 // This mode was designed to test the new skip scanlines API in libjpeg-turbo. 387 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting 388 // to run this test for image types that do not have this scanline ordering. 389 return Error::Nonfatal("Could not start top-down scanline decoder"); 390 } 391 392 for (int i = 0; i < numStripes; i += 2) { 393 // Skip a stripe 394 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight); 395 codec->skipScanlines(linesToSkip); 396 397 // Read a stripe 398 const int startY = (i + 1) * stripeHeight; 399 const int linesToRead = SkTMin(stripeHeight, height - startY); 400 if (linesToRead > 0) { 401 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes()); 402 } 403 } 404 405 // Decode even stripes 406 const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo, nullptr, 407 colorPtr, colorCountPtr); 408 if (SkCodec::kSuccess != startResult) { 409 return "Failed to restart scanline decoder with same parameters."; 410 } 411 for (int i = 0; i < numStripes; i += 2) { 412 // Read a stripe 413 const int startY = i * stripeHeight; 414 const int linesToRead = SkTMin(stripeHeight, height - startY); 415 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes()); 416 417 // Skip a stripe 418 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight); 419 if (linesToSkip > 0) { 420 codec->skipScanlines(linesToSkip); 421 } 422 } 423 canvas->drawBitmap(bitmap, 0, 0); 424 break; 425 } 426 case kSubset_Mode: { 427 // Arbitrarily choose a divisor. 428 int divisor = 2; 429 // Total width/height of the image. 430 const int W = codec->getInfo().width(); 431 const int H = codec->getInfo().height(); 432 if (divisor > W || divisor > H) { 433 return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divisor %d is too big " 434 "for %s with dimensions (%d x %d)", divisor, 435 fPath.c_str(), W, H)); 436 } 437 // subset dimensions 438 // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries. 439 const int w = SkAlign2(W / divisor); 440 const int h = SkAlign2(H / divisor); 441 SkIRect subset; 442 SkCodec::Options opts; 443 opts.fSubset = ⊂ 444 SkBitmap subsetBm; 445 // We will reuse pixel memory from bitmap. 446 void* pixels = bitmap.getPixels(); 447 // Keep track of left and top (for drawing subsetBm into canvas). We could use 448 // fScale * x and fScale * y, but we want integers such that the next subset will start 449 // where the last one ended. So we'll add decodeInfo.width() and height(). 450 int left = 0; 451 for (int x = 0; x < W; x += w) { 452 int top = 0; 453 for (int y = 0; y < H; y+= h) { 454 // Do not make the subset go off the edge of the image. 455 const int preScaleW = SkTMin(w, W - x); 456 const int preScaleH = SkTMin(h, H - y); 457 subset.setXYWH(x, y, preScaleW, preScaleH); 458 // And scale 459 // FIXME: Should we have a version of getScaledDimensions that takes a subset 460 // into account? 461 decodeInfo = decodeInfo.makeWH( 462 SkTMax(1, SkScalarRoundToInt(preScaleW * fScale)), 463 SkTMax(1, SkScalarRoundToInt(preScaleH * fScale))); 464 size_t rowBytes = decodeInfo.minRowBytes(); 465 if (!subsetBm.installPixels(decodeInfo, pixels, rowBytes, colorTable.get(), 466 nullptr, nullptr)) { 467 return SkStringPrintf("could not install pixels for %s.", fPath.c_str()); 468 } 469 const SkCodec::Result result = codec->getPixels(decodeInfo, pixels, rowBytes, 470 &opts, colorPtr, colorCountPtr); 471 switch (result) { 472 case SkCodec::kSuccess: 473 case SkCodec::kIncompleteInput: 474 break; 475 case SkCodec::kInvalidConversion: 476 if (0 == (x|y)) { 477 // First subset is okay to return unimplemented. 478 return Error::Nonfatal("Incompatible colortype conversion"); 479 } 480 // If the first subset succeeded, a later one should not fail. 481 // fall through to failure 482 case SkCodec::kUnimplemented: 483 if (0 == (x|y)) { 484 // First subset is okay to return unimplemented. 485 return Error::Nonfatal("subset codec not supported"); 486 } 487 // If the first subset succeeded, why would a later one fail? 488 // fall through to failure 489 default: 490 return SkStringPrintf("subset codec failed to decode (%d, %d, %d, %d) " 491 "from %s with dimensions (%d x %d)\t error %d", 492 x, y, decodeInfo.width(), decodeInfo.height(), 493 fPath.c_str(), W, H, result); 494 } 495 canvas->drawBitmap(subsetBm, SkIntToScalar(left), SkIntToScalar(top)); 496 // translate by the scaled height. 497 top += decodeInfo.height(); 498 } 499 // translate by the scaled width. 500 left += decodeInfo.width(); 501 } 502 return ""; 503 } 504 } 505 return ""; 506} 507 508SkISize CodecSrc::size() const { 509 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 510 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); 511 if (nullptr == codec) { 512 return SkISize::Make(0, 0); 513 } 514 return codec->getScaledDimensions(fScale); 515} 516 517Name CodecSrc::name() const { 518 if (1.0f == fScale) { 519 return SkOSPath::Basename(fPath.c_str()); 520 } 521 return get_scaled_name(fPath, fScale); 522} 523 524/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 525 526AndroidCodecSrc::AndroidCodecSrc(Path path, Mode mode, CodecSrc::DstColorType dstColorType, 527 int sampleSize) 528 : fPath(path) 529 , fMode(mode) 530 , fDstColorType(dstColorType) 531 , fSampleSize(sampleSize) 532{} 533 534bool AndroidCodecSrc::veto(SinkFlags flags) const { 535 // No need to test decoding to non-raster or indirect backend. 536 // TODO: Once we implement GPU paths (e.g. JPEG YUV), we should use a deferred decode to 537 // let the GPU handle it. 538 return flags.type != SinkFlags::kRaster 539 || flags.approach != SinkFlags::kDirect; 540} 541 542Error AndroidCodecSrc::draw(SkCanvas* canvas) const { 543 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 544 if (!encoded) { 545 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 546 } 547 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded)); 548 if (nullptr == codec.get()) { 549 return SkStringPrintf("Couldn't create android codec for %s.", fPath.c_str()); 550 } 551 552 SkImageInfo decodeInfo; 553 if (!get_decode_info(&decodeInfo, codec->getInfo(), canvas->imageInfo().colorType(), 554 fDstColorType)) { 555 return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); 556 } 557 558 // Scale the image if it is desired. 559 SkISize size = codec->getSampledDimensions(fSampleSize); 560 561 // Visually inspecting very small output images is not necessary. We will 562 // cover these cases in unit testing. 563 if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) { 564 return Error::Nonfatal("Scaling very small images is uninteresting."); 565 } 566 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); 567 568 // Construct a color table for the decode if necessary 569 SkAutoTUnref<SkColorTable> colorTable(nullptr); 570 SkPMColor* colorPtr = nullptr; 571 int* colorCountPtr = nullptr; 572 int maxColors = 256; 573 if (kIndex_8_SkColorType == decodeInfo.colorType()) { 574 SkPMColor colors[256]; 575 colorTable.reset(new SkColorTable(colors, maxColors)); 576 colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); 577 colorCountPtr = &maxColors; 578 } 579 580 SkBitmap bitmap; 581 if (!bitmap.tryAllocPixels(decodeInfo, nullptr, colorTable.get())) { 582 return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str(), 583 decodeInfo.width(), decodeInfo.height()); 584 } 585 586 // Create options for the codec. 587 SkAndroidCodec::AndroidOptions options; 588 options.fColorPtr = colorPtr; 589 options.fColorCount = colorCountPtr; 590 options.fSampleSize = fSampleSize; 591 592 switch (fMode) { 593 case kFullImage_Mode: { 594 switch (codec->getAndroidPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(), 595 &options)) { 596 case SkCodec::kSuccess: 597 case SkCodec::kIncompleteInput: 598 break; 599 case SkCodec::kInvalidConversion: 600 return Error::Nonfatal("Cannot convert to requested color type.\n"); 601 default: 602 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); 603 } 604 canvas->drawBitmap(bitmap, 0, 0); 605 return ""; 606 } 607 case kDivisor_Mode: { 608 const int width = codec->getInfo().width(); 609 const int height = codec->getInfo().height(); 610 const int divisor = 2; 611 if (width < divisor || height < divisor) { 612 return Error::Nonfatal("Divisor is larger than image dimension.\n"); 613 } 614 615 // Keep track of the final decoded dimensions. 616 int finalScaledWidth = 0; 617 int finalScaledHeight = 0; 618 for (int x = 0; x < divisor; x++) { 619 for (int y = 0; y < divisor; y++) { 620 // Calculate the subset dimensions 621 int subsetWidth = width / divisor; 622 int subsetHeight = height / divisor; 623 const int left = x * subsetWidth; 624 const int top = y * subsetHeight; 625 626 // Increase the size of the last subset in each row or column, when the 627 // divisor does not divide evenly into the image dimensions 628 subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0; 629 subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0; 630 SkIRect subset = SkIRect::MakeXYWH(left, top, subsetWidth, subsetHeight); 631 if (!codec->getSupportedSubset(&subset)) { 632 return "Could not get supported subset to decode.\n"; 633 } 634 options.fSubset = ⊂ 635 const int scaledWidthOffset = subset.left() / fSampleSize; 636 const int scaledHeightOffset = subset.top() / fSampleSize; 637 void* pixels = bitmap.getAddr(scaledWidthOffset, scaledHeightOffset); 638 SkISize scaledSubsetSize = codec->getSampledSubsetDimensions(fSampleSize, 639 subset); 640 SkImageInfo subsetDecodeInfo = decodeInfo.makeWH(scaledSubsetSize.width(), 641 scaledSubsetSize.height()); 642 643 if (x + 1 == divisor && y + 1 == divisor) { 644 finalScaledWidth = scaledWidthOffset + scaledSubsetSize.width(); 645 finalScaledHeight = scaledHeightOffset + scaledSubsetSize.height(); 646 } 647 648 switch (codec->getAndroidPixels(subsetDecodeInfo, pixels, bitmap.rowBytes(), 649 &options)) { 650 case SkCodec::kSuccess: 651 case SkCodec::kIncompleteInput: 652 break; 653 case SkCodec::kInvalidConversion: 654 return Error::Nonfatal("Cannot convert to requested color type.\n"); 655 default: 656 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); 657 } 658 } 659 } 660 661 SkRect rect = SkRect::MakeXYWH(0, 0, (SkScalar) finalScaledWidth, 662 (SkScalar) finalScaledHeight); 663 canvas->drawBitmapRect(bitmap, rect, rect, nullptr); 664 return ""; 665 } 666 default: 667 SkASSERT(false); 668 return "Error: Should not be reached.\n"; 669 } 670} 671 672SkISize AndroidCodecSrc::size() const { 673 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 674 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded)); 675 if (nullptr == codec) { 676 return SkISize::Make(0, 0); 677 } 678 return codec->getSampledDimensions(fSampleSize); 679} 680 681Name AndroidCodecSrc::name() const { 682 // We will replicate the names used by CodecSrc so that images can 683 // be compared in Gold. 684 if (1 == fSampleSize) { 685 return SkOSPath::Basename(fPath.c_str()); 686 } 687 return get_scaled_name(fPath, 1.0f / (float) fSampleSize); 688} 689 690/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 691 692ImageSrc::ImageSrc(Path path) : fPath(path) {} 693 694bool ImageSrc::veto(SinkFlags flags) const { 695 // No need to test decoding to non-raster or indirect backend. 696 // TODO: Instead, use lazy decoding to allow the GPU to handle cases like YUV. 697 return flags.type != SinkFlags::kRaster 698 || flags.approach != SinkFlags::kDirect; 699} 700 701Error ImageSrc::draw(SkCanvas* canvas) const { 702 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 703 if (!encoded) { 704 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 705 } 706 const SkColorType dstColorType = canvas->imageInfo().colorType(); 707 708 // Decode the full image. 709 SkBitmap bitmap; 710 if (!SkImageDecoder::DecodeMemory(encoded->data(), encoded->size(), &bitmap, 711 dstColorType, SkImageDecoder::kDecodePixels_Mode)) { 712 return SkStringPrintf("Couldn't decode %s.", fPath.c_str()); 713 } 714 if (kRGB_565_SkColorType == dstColorType && !bitmap.isOpaque()) { 715 // Do not draw a bitmap with alpha to a destination without alpha. 716 return Error::Nonfatal("Uninteresting to decode image with alpha into 565."); 717 } 718 encoded.reset((SkData*)nullptr); // Might as well drop this when we're done with it. 719 canvas->drawBitmap(bitmap, 0,0); 720 return ""; 721} 722 723SkISize ImageSrc::size() const { 724 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 725 SkBitmap bitmap; 726 if (!encoded || !SkImageDecoder::DecodeMemory(encoded->data(), 727 encoded->size(), 728 &bitmap, 729 kUnknown_SkColorType, 730 SkImageDecoder::kDecodeBounds_Mode)) { 731 return SkISize::Make(0,0); 732 } 733 return bitmap.dimensions(); 734} 735 736Name ImageSrc::name() const { 737 return SkOSPath::Basename(fPath.c_str()); 738} 739 740/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 741 742static const SkRect kSKPViewport = {0,0, 1000,1000}; 743 744SKPSrc::SKPSrc(Path path) : fPath(path) {} 745 746Error SKPSrc::draw(SkCanvas* canvas) const { 747 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str())); 748 if (!stream) { 749 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 750 } 751 SkAutoTUnref<SkPicture> pic(SkPicture::CreateFromStream(stream, &lazy_decode_bitmap)); 752 if (!pic) { 753 return SkStringPrintf("Couldn't decode %s as a picture.", fPath.c_str()); 754 } 755 stream.reset((SkStream*)nullptr); // Might as well drop this when we're done with it. 756 757 canvas->clipRect(kSKPViewport); 758 canvas->drawPicture(pic); 759 return ""; 760} 761 762SkISize SKPSrc::size() const { 763 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str())); 764 if (!stream) { 765 return SkISize::Make(0,0); 766 } 767 SkPictInfo info; 768 if (!SkPicture::InternalOnly_StreamIsSKP(stream, &info)) { 769 return SkISize::Make(0,0); 770 } 771 SkRect viewport = kSKPViewport; 772 if (!viewport.intersect(info.fCullRect)) { 773 return SkISize::Make(0,0); 774 } 775 return viewport.roundOut().size(); 776} 777 778Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); } 779 780/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 781 782Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const { 783 SkAutoTDelete<SkCanvas> canvas(SkCreateNullCanvas()); 784 return src.draw(canvas); 785} 786 787/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 788 789DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?"); 790 791GPUSink::GPUSink(GrContextFactory::GLContextType ct, 792 GrGLStandard api, 793 int samples, 794 bool diText, 795 bool threaded) 796 : fContextType(ct) 797 , fGpuAPI(api) 798 , fSampleCount(samples) 799 , fUseDIText(diText) 800 , fThreaded(threaded) {} 801 802int GPUSink::enclave() const { 803 return fThreaded ? kAnyThread_Enclave : kGPU_Enclave; 804} 805 806void PreAbandonGpuContextErrorHandler(SkError, void*) {} 807 808DEFINE_bool(imm, false, "Run gpu configs in immediate mode."); 809DEFINE_bool(batchClip, false, "Clip each GrBatch to its device bounds for testing."); 810DEFINE_bool(batchBounds, false, "Draw a wireframe bounds of each GrBatch."); 811 812Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const { 813 GrContextOptions options; 814 if (FLAGS_imm) { 815 options.fImmediateMode = true; 816 } 817 if (FLAGS_batchClip) { 818 options.fClipBatchToBounds = true; 819 } 820 if (FLAGS_batchBounds) { 821 options.fDrawBatchBounds = true; 822 } 823 src.modifyGrContextOptions(&options); 824 825 GrContextFactory factory(options); 826 const SkISize size = src.size(); 827 const SkImageInfo info = 828 SkImageInfo::Make(size.width(), size.height(), kN32_SkColorType, kPremul_SkAlphaType); 829 SkAutoTUnref<SkSurface> surface( 830 NewGpuSurface(&factory, fContextType, fGpuAPI, info, fSampleCount, fUseDIText)); 831 if (!surface) { 832 return "Could not create a surface."; 833 } 834 if (FLAGS_preAbandonGpuContext) { 835 SkSetErrorCallback(&PreAbandonGpuContextErrorHandler, nullptr); 836 factory.abandonContexts(); 837 } 838 SkCanvas* canvas = surface->getCanvas(); 839 Error err = src.draw(canvas); 840 if (!err.isEmpty()) { 841 return err; 842 } 843 canvas->flush(); 844 if (FLAGS_gpuStats) { 845 canvas->getGrContext()->dumpCacheStats(log); 846 canvas->getGrContext()->dumpGpuStats(log); 847 } 848 dst->allocPixels(info); 849 canvas->readPixels(dst, 0, 0); 850 if (FLAGS_abandonGpuContext) { 851 factory.abandonContexts(); 852 } 853 return ""; 854} 855 856/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 857 858static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) { 859 // Print the given DM:Src to a document, breaking on 8.5x11 pages. 860 SkASSERT(doc); 861 int width = src.size().width(), 862 height = src.size().height(); 863 864 if (FLAGS_multiPage) { 865 const int kLetterWidth = 612, // 8.5 * 72 866 kLetterHeight = 792; // 11 * 72 867 const SkRect letter = SkRect::MakeWH(SkIntToScalar(kLetterWidth), 868 SkIntToScalar(kLetterHeight)); 869 870 int xPages = ((width - 1) / kLetterWidth) + 1; 871 int yPages = ((height - 1) / kLetterHeight) + 1; 872 873 for (int y = 0; y < yPages; ++y) { 874 for (int x = 0; x < xPages; ++x) { 875 int w = SkTMin(kLetterWidth, width - (x * kLetterWidth)); 876 int h = SkTMin(kLetterHeight, height - (y * kLetterHeight)); 877 SkCanvas* canvas = 878 doc->beginPage(SkIntToScalar(w), SkIntToScalar(h)); 879 if (!canvas) { 880 return "SkDocument::beginPage(w,h) returned nullptr"; 881 } 882 canvas->clipRect(letter); 883 canvas->translate(-letter.width() * x, -letter.height() * y); 884 Error err = src.draw(canvas); 885 if (!err.isEmpty()) { 886 return err; 887 } 888 doc->endPage(); 889 } 890 } 891 } else { 892 SkCanvas* canvas = 893 doc->beginPage(SkIntToScalar(width), SkIntToScalar(height)); 894 if (!canvas) { 895 return "SkDocument::beginPage(w,h) returned nullptr"; 896 } 897 Error err = src.draw(canvas); 898 if (!err.isEmpty()) { 899 return err; 900 } 901 doc->endPage(); 902 } 903 if (!doc->close()) { 904 return "SkDocument::close() returned false"; 905 } 906 dst->flush(); 907 return ""; 908} 909 910PDFSink::PDFSink(const char* rasterizer) : fRasterizer(rasterizer) {} 911 912Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 913 SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(dst)); 914 if (!doc) { 915 return "SkDocument::CreatePDF() returned nullptr"; 916 } 917 SkTArray<SkDocument::Attribute> info; 918 info.emplace_back(SkString("Title"), src.name()); 919 info.emplace_back(SkString("Subject"), 920 SkString("rendering correctness test")); 921 info.emplace_back(SkString("Creator"), SkString("Skia/DM")); 922 923 info.emplace_back(SkString("Keywords"), 924 SkStringPrintf("Rasterizer:%s;", fRasterizer)); 925 doc->setMetadata(info, nullptr, nullptr); 926 return draw_skdocument(src, doc.get(), dst); 927} 928 929/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 930 931XPSSink::XPSSink() {} 932 933Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 934 SkAutoTUnref<SkDocument> doc(SkDocument::CreateXPS(dst)); 935 if (!doc) { 936 return "SkDocument::CreateXPS() returned nullptr"; 937 } 938 return draw_skdocument(src, doc.get(), dst); 939} 940/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 941 942SKPSink::SKPSink() {} 943 944Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 945 SkSize size; 946 size = src.size(); 947 SkPictureRecorder recorder; 948 Error err = src.draw(recorder.beginRecording(size.width(), size.height())); 949 if (!err.isEmpty()) { 950 return err; 951 } 952 SkAutoTUnref<SkPicture> pic(recorder.endRecording()); 953 pic->serialize(dst); 954 return ""; 955} 956 957/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 958 959SVGSink::SVGSink() {} 960 961Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 962 SkAutoTDelete<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(dst)); 963 SkAutoTUnref<SkCanvas> canvas(SkSVGCanvas::Create( 964 SkRect::MakeWH(SkIntToScalar(src.size().width()), SkIntToScalar(src.size().height())), 965 xmlWriter)); 966 return src.draw(canvas); 967} 968 969/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 970 971RasterSink::RasterSink(SkColorType colorType) : fColorType(colorType) {} 972 973Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const { 974 const SkISize size = src.size(); 975 // If there's an appropriate alpha type for this color type, use it, otherwise use premul. 976 SkAlphaType alphaType = kPremul_SkAlphaType; 977 (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType); 978 979 dst->allocPixels(SkImageInfo::Make(size.width(), size.height(), fColorType, alphaType)); 980 dst->eraseColor(SK_ColorTRANSPARENT); 981 SkCanvas canvas(*dst); 982 return src.draw(&canvas); 983} 984 985/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 986 987// Handy for front-patching a Src. Do whatever up-front work you need, then call draw_to_canvas(), 988// passing the Sink draw() arguments, a size, and a function draws into an SkCanvas. 989// Several examples below. 990 991static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log, 992 SkISize size, std::function<Error(SkCanvas*)> draw) { 993 class ProxySrc : public Src { 994 public: 995 ProxySrc(SkISize size, std::function<Error(SkCanvas*)> draw) : fSize(size), fDraw(draw) {} 996 Error draw(SkCanvas* canvas) const override { return fDraw(canvas); } 997 Name name() const override { sk_throw(); return ""; } // Won't be called. 998 SkISize size() const override { return fSize; } 999 private: 1000 SkISize fSize; 1001 std::function<Error(SkCanvas*)> fDraw; 1002 }; 1003 return sink->draw(ProxySrc(size, draw), bitmap, stream, log); 1004} 1005 1006/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1007 1008static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) { 1009 SkRect bounds = SkRect::MakeIWH(srcW, srcH); 1010 matrix->mapRect(&bounds); 1011 matrix->postTranslate(-bounds.x(), -bounds.y()); 1012 return SkISize::Make(SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height())); 1013} 1014 1015ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {} 1016 1017Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1018 SkMatrix matrix = fMatrix; 1019 SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height()); 1020 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) { 1021 canvas->concat(matrix); 1022 return src.draw(canvas); 1023 }); 1024} 1025 1026// Undoes any flip or 90 degree rotate without changing the scale of the bitmap. 1027// This should be pixel-preserving. 1028ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {} 1029 1030Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1031 Error err = fSink->draw(src, bitmap, stream, log); 1032 if (!err.isEmpty()) { 1033 return err; 1034 } 1035 1036 SkMatrix inverse; 1037 if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) { 1038 return "Cannot upright --matrix."; 1039 } 1040 SkMatrix upright = SkMatrix::I(); 1041 upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX())); 1042 upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY())); 1043 upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX())); 1044 upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY())); 1045 1046 SkBitmap uprighted; 1047 SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height()); 1048 uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height())); 1049 1050 SkCanvas canvas(uprighted); 1051 canvas.concat(upright); 1052 SkPaint paint; 1053 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 1054 canvas.drawBitmap(*bitmap, 0, 0, &paint); 1055 1056 *bitmap = uprighted; 1057 bitmap->lockPixels(); 1058 return ""; 1059} 1060 1061/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1062 1063Error ViaPipe::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1064 auto size = src.size(); 1065 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) { 1066 PipeController controller(canvas, &SkImageDecoder::DecodeMemory); 1067 SkGPipeWriter pipe; 1068 const uint32_t kFlags = 0; 1069 return src.draw(pipe.startRecording(&controller, kFlags, size.width(), size.height())); 1070 }); 1071} 1072 1073Error ViaRemote::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1074 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* target) { 1075 SkAutoTDelete<SkRemote::Encoder> decoder(SkRemote::NewDecoder(target)); 1076 SkAutoTDelete<SkRemote::Encoder> cache(fCache ? SkRemote::NewCachingEncoder(decoder) 1077 : nullptr); 1078 SkAutoTDelete<SkCanvas> canvas(SkRemote::NewCanvas(cache ? cache : decoder)); 1079 return src.draw(canvas); 1080 }); 1081} 1082 1083/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1084 1085Error ViaSerialization::draw( 1086 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1087 // Record our Src into a picture. 1088 auto size = src.size(); 1089 SkPictureRecorder recorder; 1090 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 1091 SkIntToScalar(size.height()))); 1092 if (!err.isEmpty()) { 1093 return err; 1094 } 1095 SkAutoTUnref<SkPicture> pic(recorder.endRecording()); 1096 1097 // Serialize it and then deserialize it. 1098 SkDynamicMemoryWStream wStream; 1099 pic->serialize(&wStream); 1100 SkAutoTDelete<SkStream> rStream(wStream.detachAsStream()); 1101 SkAutoTUnref<SkPicture> deserialized(SkPicture::CreateFromStream(rStream, &lazy_decode_bitmap)); 1102 1103 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) { 1104 canvas->drawPicture(deserialized); 1105 return ""; 1106 }); 1107} 1108 1109/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1110 1111ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink) 1112 : Via(sink) 1113 , fW(w) 1114 , fH(h) 1115 , fFactory(factory) {} 1116 1117Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1118 auto size = src.size(); 1119 SkPictureRecorder recorder; 1120 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 1121 SkIntToScalar(size.height()), 1122 fFactory.get())); 1123 if (!err.isEmpty()) { 1124 return err; 1125 } 1126 SkAutoTUnref<SkPicture> pic(recorder.endRecordingAsPicture()); 1127 1128 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) { 1129 const int xTiles = (size.width() + fW - 1) / fW, 1130 yTiles = (size.height() + fH - 1) / fH; 1131 SkMultiPictureDraw mpd(xTiles*yTiles); 1132 SkTDArray<SkSurface*> surfaces; 1133 surfaces.setReserve(xTiles*yTiles); 1134 1135 SkImageInfo info = canvas->imageInfo().makeWH(fW, fH); 1136 for (int j = 0; j < yTiles; j++) { 1137 for (int i = 0; i < xTiles; i++) { 1138 // This lets our ultimate Sink determine the best kind of surface. 1139 // E.g., if it's a GpuSink, the surfaces and images are textures. 1140 SkSurface* s = canvas->newSurface(info); 1141 if (!s) { 1142 s = SkSurface::NewRaster(info); // Some canvases can't create surfaces. 1143 } 1144 surfaces.push(s); 1145 SkCanvas* c = s->getCanvas(); 1146 c->translate(SkIntToScalar(-i * fW), 1147 SkIntToScalar(-j * fH)); // Line up the canvas with this tile. 1148 mpd.add(c, pic); 1149 } 1150 } 1151 mpd.draw(); 1152 for (int j = 0; j < yTiles; j++) { 1153 for (int i = 0; i < xTiles; i++) { 1154 SkAutoTUnref<SkImage> image(surfaces[i+xTiles*j]->newImageSnapshot()); 1155 canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH)); 1156 } 1157 } 1158 surfaces.unrefAll(); 1159 return ""; 1160 }); 1161} 1162 1163/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1164 1165// Draw the Src into two pictures, then draw the second picture into the wrapped Sink. 1166// This tests that any shortcuts we may take while recording that second picture are legal. 1167Error ViaSecondPicture::draw( 1168 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1169 auto size = src.size(); 1170 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 1171 SkPictureRecorder recorder; 1172 SkAutoTUnref<SkPicture> pic; 1173 for (int i = 0; i < 2; i++) { 1174 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 1175 SkIntToScalar(size.height()))); 1176 if (!err.isEmpty()) { 1177 return err; 1178 } 1179 pic.reset(recorder.endRecordingAsPicture()); 1180 } 1181 canvas->drawPicture(pic); 1182 return ""; 1183 }); 1184} 1185 1186/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1187 1188// Draw the Src twice. This can help exercise caching. 1189Error ViaTwice::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1190 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) -> Error { 1191 for (int i = 0; i < 2; i++) { 1192 SkAutoCanvasRestore acr(canvas, true/*save now*/); 1193 canvas->clear(SK_ColorTRANSPARENT); 1194 Error err = src.draw(canvas); 1195 if (err.isEmpty()) { 1196 return err; 1197 } 1198 } 1199 return ""; 1200 }); 1201} 1202 1203/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1204 1205// This is like SkRecords::Draw, in that it plays back SkRecords ops into a Canvas. 1206// Unlike SkRecords::Draw, it builds a single-op sub-picture out of each Draw-type op. 1207// This is an only-slightly-exaggerated simluation of Blink's Slimming Paint pictures. 1208struct DrawsAsSingletonPictures { 1209 SkCanvas* fCanvas; 1210 const SkDrawableList& fDrawables; 1211 1212 template <typename T> 1213 void draw(const T& op, SkCanvas* canvas) { 1214 // We must pass SkMatrix::I() as our initial matrix. 1215 // By default SkRecords::Draw() uses the canvas' matrix as its initial matrix, 1216 // which would have the funky effect of applying transforms over and over. 1217 SkRecords::Draw d(canvas, nullptr, fDrawables.begin(), fDrawables.count(), &SkMatrix::I()); 1218 d(op); 1219 } 1220 1221 // Draws get their own picture. 1222 template <typename T> 1223 SK_WHEN(T::kTags & SkRecords::kDraw_Tag, void) operator()(const T& op) { 1224 SkPictureRecorder rec; 1225 this->draw(op, rec.beginRecording(SkRect::MakeLargest())); 1226 SkAutoTUnref<SkPicture> pic(rec.endRecordingAsPicture()); 1227 fCanvas->drawPicture(pic); 1228 } 1229 1230 // We'll just issue non-draws directly. 1231 template <typename T> 1232 skstd::enable_if_t<!(T::kTags & SkRecords::kDraw_Tag), void> operator()(const T& op) { 1233 this->draw(op, fCanvas); 1234 } 1235}; 1236 1237// Record Src into a picture, then record it into a macro picture with a sub-picture for each draw. 1238// Then play back that macro picture into our wrapped sink. 1239Error ViaSingletonPictures::draw( 1240 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1241 auto size = src.size(); 1242 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 1243 // Use low-level (Skia-private) recording APIs so we can read the SkRecord. 1244 SkRecord skr; 1245 SkRecorder recorder(&skr, size.width(), size.height()); 1246 Error err = src.draw(&recorder); 1247 if (!err.isEmpty()) { 1248 return err; 1249 } 1250 1251 // Record our macro-picture, with each draw op as its own sub-picture. 1252 SkPictureRecorder macroRec; 1253 SkCanvas* macroCanvas = macroRec.beginRecording(SkIntToScalar(size.width()), 1254 SkIntToScalar(size.height())); 1255 1256 SkAutoTDelete<SkDrawableList> drawables(recorder.detachDrawableList()); 1257 const SkDrawableList empty; 1258 1259 DrawsAsSingletonPictures drawsAsSingletonPictures = { 1260 macroCanvas, 1261 drawables ? *drawables : empty, 1262 }; 1263 for (int i = 0; i < skr.count(); i++) { 1264 skr.visit<void>(i, drawsAsSingletonPictures); 1265 } 1266 SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture()); 1267 1268 canvas->drawPicture(macroPic); 1269 return ""; 1270 }); 1271} 1272 1273} // namespace DM 1274