DMSrcSink.cpp revision 4b43cc2af9ba32e9420484de2e23bbc821be127a
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 "Resources.h" 10#include "SkAndroidCodec.h" 11#include "SkCodec.h" 12#include "SkCodecImageGenerator.h" 13#include "SkColorSpace.h" 14#include "SkColorSpace_XYZ.h" 15#include "SkColorSpaceXform.h" 16#include "SkCommonFlags.h" 17#include "SkData.h" 18#include "SkDebugCanvas.h" 19#include "SkDeferredCanvas.h" 20#include "SkDocument.h" 21#include "SkImageGenerator.h" 22#include "SkImageGeneratorCG.h" 23#include "SkImageGeneratorWIC.h" 24#include "SkLiteDL.h" 25#include "SkLiteRecorder.h" 26#include "SkMallocPixelRef.h" 27#include "SkMultiPictureDraw.h" 28#include "SkNullCanvas.h" 29#include "SkOSFile.h" 30#include "SkOpts.h" 31#include "SkPictureData.h" 32#include "SkPictureRecorder.h" 33#include "SkPipe.h" 34#include "SkRandom.h" 35#include "SkRecordDraw.h" 36#include "SkRecorder.h" 37#include "SkSVGCanvas.h" 38#include "SkStream.h" 39#include "SkTLogic.h" 40#include "SkSwizzler.h" 41#include <functional> 42#include <cmath> 43 44#if defined(SK_BUILD_FOR_WIN) 45 #include "SkAutoCoInitialize.h" 46#endif 47 48#if defined(SK_XML) 49 #include "SkSVGDOM.h" 50 #include "SkXMLWriter.h" 51#endif 52 53DEFINE_bool(multiPage, false, "For document-type backends, render the source" 54 " into multiple pages"); 55DEFINE_bool(RAW_threading, true, "Allow RAW decodes to run on multiple threads?"); 56 57using sk_gpu_test::GrContextFactory; 58 59namespace DM { 60 61GMSrc::GMSrc(skiagm::GMRegistry::Factory factory) : fFactory(factory) {} 62 63Error GMSrc::draw(SkCanvas* canvas) const { 64 std::unique_ptr<skiagm::GM> gm(fFactory(nullptr)); 65 canvas->concat(gm->getInitialTransform()); 66 gm->draw(canvas); 67 return ""; 68} 69 70SkISize GMSrc::size() const { 71 std::unique_ptr<skiagm::GM> gm(fFactory(nullptr)); 72 return gm->getISize(); 73} 74 75Name GMSrc::name() const { 76 std::unique_ptr<skiagm::GM> gm(fFactory(nullptr)); 77 return gm->getName(); 78} 79 80void GMSrc::modifyGrContextOptions(GrContextOptions* options) const { 81 std::unique_ptr<skiagm::GM> gm(fFactory(nullptr)); 82 gm->modifyGrContextOptions(options); 83} 84 85/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 86 87BRDSrc::BRDSrc(Path path, Mode mode, CodecSrc::DstColorType dstColorType, uint32_t sampleSize) 88 : fPath(path) 89 , fMode(mode) 90 , fDstColorType(dstColorType) 91 , fSampleSize(sampleSize) 92{} 93 94bool BRDSrc::veto(SinkFlags flags) const { 95 // No need to test to non-raster or indirect backends. 96 return flags.type != SinkFlags::kRaster 97 || flags.approach != SinkFlags::kDirect; 98} 99 100static SkBitmapRegionDecoder* create_brd(Path path) { 101 sk_sp<SkData> encoded(SkData::MakeFromFileName(path.c_str())); 102 if (!encoded) { 103 return NULL; 104 } 105 return SkBitmapRegionDecoder::Create(encoded, SkBitmapRegionDecoder::kAndroidCodec_Strategy); 106} 107 108Error BRDSrc::draw(SkCanvas* canvas) const { 109 SkColorType colorType = canvas->imageInfo().colorType(); 110 if (kRGB_565_SkColorType == colorType && 111 CodecSrc::kGetFromCanvas_DstColorType != fDstColorType) { 112 return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); 113 } 114 switch (fDstColorType) { 115 case CodecSrc::kGetFromCanvas_DstColorType: 116 break; 117 case CodecSrc::kIndex8_Always_DstColorType: 118 colorType = kIndex_8_SkColorType; 119 break; 120 case CodecSrc::kGrayscale_Always_DstColorType: 121 colorType = kGray_8_SkColorType; 122 break; 123 default: 124 SkASSERT(false); 125 break; 126 } 127 128 std::unique_ptr<SkBitmapRegionDecoder> brd(create_brd(fPath)); 129 if (nullptr == brd.get()) { 130 return Error::Nonfatal(SkStringPrintf("Could not create brd for %s.", fPath.c_str())); 131 } 132 133 if (!brd->conversionSupported(colorType)) { 134 return Error::Nonfatal("Cannot convert to color type."); 135 } 136 137 const uint32_t width = brd->width(); 138 const uint32_t height = brd->height(); 139 // Visually inspecting very small output images is not necessary. 140 if ((width / fSampleSize <= 10 || height / fSampleSize <= 10) && 1 != fSampleSize) { 141 return Error::Nonfatal("Scaling very small images is uninteresting."); 142 } 143 switch (fMode) { 144 case kFullImage_Mode: { 145 SkBitmap bitmap; 146 if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(0, 0, width, height), 147 fSampleSize, colorType, false)) { 148 return "Cannot decode (full) region."; 149 } 150 if (colorType != bitmap.colorType()) { 151 return Error::Nonfatal("Cannot convert to color type."); 152 } 153 canvas->drawBitmap(bitmap, 0, 0); 154 return ""; 155 } 156 case kDivisor_Mode: { 157 const uint32_t divisor = 2; 158 if (width < divisor || height < divisor) { 159 return Error::Nonfatal("Divisor is larger than image dimension."); 160 } 161 162 // Use a border to test subsets that extend outside the image. 163 // We will not allow the border to be larger than the image dimensions. Allowing 164 // these large borders causes off by one errors that indicate a problem with the 165 // test suite, not a problem with the implementation. 166 const uint32_t maxBorder = SkTMin(width, height) / (fSampleSize * divisor); 167 const uint32_t scaledBorder = SkTMin(5u, maxBorder); 168 const uint32_t unscaledBorder = scaledBorder * fSampleSize; 169 170 // We may need to clear the canvas to avoid uninitialized memory. 171 // Assume we are scaling a 780x780 image with sampleSize = 8. 172 // The output image should be 97x97. 173 // Each subset will be 390x390. 174 // Each scaled subset be 48x48. 175 // Four scaled subsets will only fill a 96x96 image. 176 // The bottom row and last column will not be touched. 177 // This is an unfortunate result of our rounding rules when scaling. 178 // Maybe we need to consider testing scaled subsets without trying to 179 // combine them to match the full scaled image? Or maybe this is the 180 // best we can do? 181 canvas->clear(0); 182 183 for (uint32_t x = 0; x < divisor; x++) { 184 for (uint32_t y = 0; y < divisor; y++) { 185 // Calculate the subset dimensions 186 uint32_t subsetWidth = width / divisor; 187 uint32_t subsetHeight = height / divisor; 188 const int left = x * subsetWidth; 189 const int top = y * subsetHeight; 190 191 // Increase the size of the last subset in each row or column, when the 192 // divisor does not divide evenly into the image dimensions 193 subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0; 194 subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0; 195 196 // Increase the size of the subset in order to have a border on each side 197 const int decodeLeft = left - unscaledBorder; 198 const int decodeTop = top - unscaledBorder; 199 const uint32_t decodeWidth = subsetWidth + unscaledBorder * 2; 200 const uint32_t decodeHeight = subsetHeight + unscaledBorder * 2; 201 SkBitmap bitmap; 202 if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(decodeLeft, 203 decodeTop, decodeWidth, decodeHeight), fSampleSize, colorType, false)) { 204 return "Cannot decode region."; 205 } 206 if (colorType != bitmap.colorType()) { 207 return Error::Nonfatal("Cannot convert to color type."); 208 } 209 210 canvas->drawBitmapRect(bitmap, 211 SkRect::MakeXYWH((SkScalar) scaledBorder, (SkScalar) scaledBorder, 212 (SkScalar) (subsetWidth / fSampleSize), 213 (SkScalar) (subsetHeight / fSampleSize)), 214 SkRect::MakeXYWH((SkScalar) (left / fSampleSize), 215 (SkScalar) (top / fSampleSize), 216 (SkScalar) (subsetWidth / fSampleSize), 217 (SkScalar) (subsetHeight / fSampleSize)), 218 nullptr); 219 } 220 } 221 return ""; 222 } 223 default: 224 SkASSERT(false); 225 return "Error: Should not be reached."; 226 } 227} 228 229SkISize BRDSrc::size() const { 230 std::unique_ptr<SkBitmapRegionDecoder> brd(create_brd(fPath)); 231 if (brd) { 232 return SkISize::Make(SkTMax(1, brd->width() / (int) fSampleSize), 233 SkTMax(1, brd->height() / (int) fSampleSize)); 234 } 235 return SkISize::Make(0, 0); 236} 237 238static SkString get_scaled_name(const Path& path, float scale) { 239 return SkStringPrintf("%s_%.3f", SkOSPath::Basename(path.c_str()).c_str(), scale); 240} 241 242Name BRDSrc::name() const { 243 // We will replicate the names used by CodecSrc so that images can 244 // be compared in Gold. 245 if (1 == fSampleSize) { 246 return SkOSPath::Basename(fPath.c_str()); 247 } 248 return get_scaled_name(fPath, 1.0f / (float) fSampleSize); 249} 250 251/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 252 253static bool serial_from_path_name(const SkString& path) { 254 if (!FLAGS_RAW_threading) { 255 static const char* const exts[] = { 256 "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw", 257 "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW", 258 }; 259 const char* actualExt = strrchr(path.c_str(), '.'); 260 if (actualExt) { 261 actualExt++; 262 for (auto* ext : exts) { 263 if (0 == strcmp(ext, actualExt)) { 264 return true; 265 } 266 } 267 } 268 } 269 return false; 270} 271 272CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, SkAlphaType dstAlphaType, 273 float scale) 274 : fPath(path) 275 , fMode(mode) 276 , fDstColorType(dstColorType) 277 , fDstAlphaType(dstAlphaType) 278 , fScale(scale) 279 , fRunSerially(serial_from_path_name(path)) 280{} 281 282bool CodecSrc::veto(SinkFlags flags) const { 283 // Test to direct raster backends (8888 and 565). 284 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect; 285} 286 287// Allows us to test decodes to non-native 8888. 288static void swap_rb_if_necessary(SkBitmap& bitmap, CodecSrc::DstColorType dstColorType) { 289 if (CodecSrc::kNonNative8888_Always_DstColorType != dstColorType) { 290 return; 291 } 292 293 for (int y = 0; y < bitmap.height(); y++) { 294 uint32_t* row = (uint32_t*) bitmap.getAddr(0, y); 295 SkOpts::RGBA_to_BGRA(row, row, bitmap.width()); 296 } 297} 298 299// FIXME: Currently we cannot draw unpremultiplied sources. skbug.com/3338 and skbug.com/3339. 300// This allows us to still test unpremultiplied decodes. 301static void premultiply_if_necessary(SkBitmap& bitmap) { 302 if (kUnpremul_SkAlphaType != bitmap.alphaType()) { 303 return; 304 } 305 306 switch (bitmap.colorType()) { 307 case kN32_SkColorType: 308 for (int y = 0; y < bitmap.height(); y++) { 309 uint32_t* row = (uint32_t*) bitmap.getAddr(0, y); 310 SkOpts::RGBA_to_rgbA(row, row, bitmap.width()); 311 } 312 break; 313 case kIndex_8_SkColorType: { 314 SkColorTable* colorTable = bitmap.getColorTable(); 315 SkPMColor* colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); 316 SkOpts::RGBA_to_rgbA(colorPtr, colorPtr, colorTable->count()); 317 break; 318 } 319 default: 320 // No need to premultiply kGray or k565 outputs. 321 break; 322 } 323 324 // In the kIndex_8 case, the canvas won't even try to draw unless we mark the 325 // bitmap as kPremul. 326 bitmap.setAlphaType(kPremul_SkAlphaType); 327} 328 329static bool get_decode_info(SkImageInfo* decodeInfo, SkColorType canvasColorType, 330 CodecSrc::DstColorType dstColorType, SkAlphaType dstAlphaType) { 331 switch (dstColorType) { 332 case CodecSrc::kIndex8_Always_DstColorType: 333 if (kRGB_565_SkColorType == canvasColorType) { 334 return false; 335 } 336 *decodeInfo = decodeInfo->makeColorType(kIndex_8_SkColorType); 337 break; 338 case CodecSrc::kGrayscale_Always_DstColorType: 339 if (kRGB_565_SkColorType == canvasColorType) { 340 return false; 341 } 342 *decodeInfo = decodeInfo->makeColorType(kGray_8_SkColorType); 343 break; 344 case CodecSrc::kNonNative8888_Always_DstColorType: 345 if (kRGB_565_SkColorType == canvasColorType) { 346 return false; 347 } 348#ifdef SK_PMCOLOR_IS_RGBA 349 *decodeInfo = decodeInfo->makeColorType(kBGRA_8888_SkColorType); 350#else 351 *decodeInfo = decodeInfo->makeColorType(kRGBA_8888_SkColorType); 352#endif 353 break; 354 default: 355 if (kRGB_565_SkColorType == canvasColorType && 356 kOpaque_SkAlphaType != decodeInfo->alphaType()) { 357 return false; 358 } 359 *decodeInfo = decodeInfo->makeColorType(canvasColorType); 360 break; 361 } 362 363 *decodeInfo = decodeInfo->makeAlphaType(dstAlphaType); 364 return true; 365} 366 367static void draw_to_canvas(SkCanvas* canvas, const SkImageInfo& info, void* pixels, size_t rowBytes, 368 SkPMColor* colorPtr, int colorCount, CodecSrc::DstColorType dstColorType, 369 SkScalar left = 0, SkScalar top = 0) { 370 sk_sp<SkColorTable> colorTable(new SkColorTable(colorPtr, colorCount)); 371 SkBitmap bitmap; 372 bitmap.installPixels(info, pixels, rowBytes, colorTable.get(), nullptr, nullptr); 373 premultiply_if_necessary(bitmap); 374 swap_rb_if_necessary(bitmap, dstColorType); 375 canvas->drawBitmap(bitmap, left, top); 376} 377 378Error CodecSrc::draw(SkCanvas* canvas) const { 379 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 380 if (!encoded) { 381 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 382 } 383 384 std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(encoded)); 385 if (nullptr == codec.get()) { 386 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); 387 } 388 389 SkImageInfo decodeInfo = codec->getInfo(); 390 if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType, 391 fDstAlphaType)) { 392 return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); 393 } 394 395 // Try to scale the image if it is desired 396 SkISize size = codec->getScaledDimensions(fScale); 397 if (size == decodeInfo.dimensions() && 1.0f != fScale) { 398 return Error::Nonfatal("Test without scaling is uninteresting."); 399 } 400 401 // Visually inspecting very small output images is not necessary. We will 402 // cover these cases in unit testing. 403 if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) { 404 return Error::Nonfatal("Scaling very small images is uninteresting."); 405 } 406 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); 407 408 const int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType()); 409 const size_t rowBytes = size.width() * bpp; 410 const size_t safeSize = decodeInfo.getSafeSize(rowBytes); 411 SkAutoMalloc pixels(safeSize); 412 SkPMColor colorPtr[256]; 413 int colorCount = 256; 414 415 SkCodec::Options options; 416 if (kCodecZeroInit_Mode == fMode) { 417 memset(pixels.get(), 0, size.height() * rowBytes); 418 options.fZeroInitialized = SkCodec::kYes_ZeroInitialized; 419 } 420 421 SkImageInfo bitmapInfo = decodeInfo; 422 if (kRGBA_8888_SkColorType == decodeInfo.colorType() || 423 kBGRA_8888_SkColorType == decodeInfo.colorType()) { 424 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType); 425 } 426 427 switch (fMode) { 428 case kAnimated_Mode: { 429 std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo(); 430 if (frameInfos.size() <= 1) { 431 return SkStringPrintf("%s is not an animated image.", fPath.c_str()); 432 } 433 434 // As in CodecSrc::size(), compute a roughly square grid to draw the frames 435 // into. "factor" is the number of frames to draw on one row. There will be 436 // up to "factor" rows as well. 437 const float root = sqrt((float) frameInfos.size()); 438 const int factor = sk_float_ceil2int(root); 439 440 // Used to cache a frame that future frames will depend on. 441 SkAutoMalloc priorFramePixels; 442 size_t cachedFrame = SkCodec::kNone; 443 for (size_t i = 0; i < frameInfos.size(); i++) { 444 options.fFrameIndex = i; 445 // Check for a prior frame 446 const size_t reqFrame = frameInfos[i].fRequiredFrame; 447 if (reqFrame != SkCodec::kNone && reqFrame == cachedFrame 448 && priorFramePixels.get()) { 449 // Copy into pixels 450 memcpy(pixels.get(), priorFramePixels.get(), safeSize); 451 options.fHasPriorFrame = true; 452 } else { 453 options.fHasPriorFrame = false; 454 } 455 const SkCodec::Result result = codec->getPixels(decodeInfo, pixels.get(), 456 rowBytes, &options, 457 colorPtr, &colorCount); 458 switch (result) { 459 case SkCodec::kSuccess: 460 case SkCodec::kIncompleteInput: { 461 SkAutoCanvasRestore acr(canvas, true); 462 const int xTranslate = (i % factor) * decodeInfo.width(); 463 const int yTranslate = (i / factor) * decodeInfo.height(); 464 canvas->translate(SkIntToScalar(xTranslate), SkIntToScalar(yTranslate)); 465 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, 466 colorPtr, colorCount, fDstColorType); 467 if (result == SkCodec::kIncompleteInput) { 468 return ""; 469 } 470 break; 471 } 472 case SkCodec::kInvalidConversion: 473 if (i > 0 && (decodeInfo.colorType() == kRGB_565_SkColorType 474 || decodeInfo.colorType() == kIndex_8_SkColorType)) { 475 return Error::Nonfatal(SkStringPrintf( 476 "Cannot decode frame %i to 565/Index8 (%s).", i, fPath.c_str())); 477 } 478 // Fall through. 479 default: 480 return SkStringPrintf("Couldn't getPixels for frame %i in %s.", 481 i, fPath.c_str()); 482 } 483 484 // If a future frame depends on this one, store it in priorFrame. 485 // (Note that if i+1 does *not* depend on i, then no future frame can.) 486 if (i+1 < frameInfos.size() && frameInfos[i+1].fRequiredFrame == i) { 487 memcpy(priorFramePixels.reset(safeSize), pixels.get(), safeSize); 488 cachedFrame = i; 489 } 490 } 491 break; 492 } 493 case kCodecZeroInit_Mode: 494 case kCodec_Mode: { 495 switch (codec->getPixels(decodeInfo, pixels.get(), rowBytes, &options, 496 colorPtr, &colorCount)) { 497 case SkCodec::kSuccess: 498 // We consider incomplete to be valid, since we should still decode what is 499 // available. 500 case SkCodec::kIncompleteInput: 501 break; 502 default: 503 // Everything else is considered a failure. 504 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); 505 } 506 507 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr, colorCount, 508 fDstColorType); 509 break; 510 } 511 case kScanline_Mode: { 512 void* dst = pixels.get(); 513 uint32_t height = decodeInfo.height(); 514 const bool useIncremental = [this]() { 515 auto exts = { "png", "PNG", "gif", "GIF" }; 516 for (auto ext : exts) { 517 if (fPath.endsWith(ext)) { 518 return true; 519 } 520 } 521 return false; 522 }(); 523 // ico may use the old scanline method or the new one, depending on whether it 524 // internally holds a bmp or a png. 525 const bool ico = fPath.endsWith("ico"); 526 bool useOldScanlineMethod = !useIncremental && !ico; 527 if (useIncremental || ico) { 528 if (SkCodec::kSuccess == codec->startIncrementalDecode(decodeInfo, dst, 529 rowBytes, nullptr, colorPtr, &colorCount)) { 530 int rowsDecoded; 531 if (SkCodec::kIncompleteInput == codec->incrementalDecode(&rowsDecoded)) { 532 codec->fillIncompleteImage(decodeInfo, dst, rowBytes, 533 SkCodec::kNo_ZeroInitialized, height, 534 rowsDecoded); 535 } 536 } else { 537 if (useIncremental) { 538 // Error: These should support incremental decode. 539 return "Could not start incremental decode"; 540 } 541 // Otherwise, this is an ICO. Since incremental failed, it must contain a BMP, 542 // which should work via startScanlineDecode 543 useOldScanlineMethod = true; 544 } 545 } 546 547 if (useOldScanlineMethod) { 548 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr, 549 &colorCount)) { 550 return "Could not start scanline decoder"; 551 } 552 553 switch (codec->getScanlineOrder()) { 554 case SkCodec::kTopDown_SkScanlineOrder: 555 case SkCodec::kBottomUp_SkScanlineOrder: 556 // We do not need to check the return value. On an incomplete 557 // image, memory will be filled with a default value. 558 codec->getScanlines(dst, height, rowBytes); 559 break; 560 } 561 } 562 563 draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, colorPtr, colorCount, fDstColorType); 564 break; 565 } 566 case kStripe_Mode: { 567 const int height = decodeInfo.height(); 568 // This value is chosen arbitrarily. We exercise more cases by choosing a value that 569 // does not align with image blocks. 570 const int stripeHeight = 37; 571 const int numStripes = (height + stripeHeight - 1) / stripeHeight; 572 void* dst = pixels.get(); 573 574 // Decode odd stripes 575 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, nullptr, colorPtr, 576 &colorCount)) { 577 return "Could not start scanline decoder"; 578 } 579 580 // This mode was designed to test the new skip scanlines API in libjpeg-turbo. 581 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting 582 // to run this test for image types that do not have this scanline ordering. 583 // We only run this on Jpeg, which is always kTopDown. 584 SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder()); 585 586 for (int i = 0; i < numStripes; i += 2) { 587 // Skip a stripe 588 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight); 589 codec->skipScanlines(linesToSkip); 590 591 // Read a stripe 592 const int startY = (i + 1) * stripeHeight; 593 const int linesToRead = SkTMin(stripeHeight, height - startY); 594 if (linesToRead > 0) { 595 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead, 596 rowBytes); 597 } 598 } 599 600 // Decode even stripes 601 const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo, nullptr, 602 colorPtr, &colorCount); 603 if (SkCodec::kSuccess != startResult) { 604 return "Failed to restart scanline decoder with same parameters."; 605 } 606 for (int i = 0; i < numStripes; i += 2) { 607 // Read a stripe 608 const int startY = i * stripeHeight; 609 const int linesToRead = SkTMin(stripeHeight, height - startY); 610 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead, 611 rowBytes); 612 613 // Skip a stripe 614 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight); 615 if (linesToSkip > 0) { 616 codec->skipScanlines(linesToSkip); 617 } 618 } 619 620 draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, colorPtr, colorCount, fDstColorType); 621 break; 622 } 623 case kCroppedScanline_Mode: { 624 const int width = decodeInfo.width(); 625 const int height = decodeInfo.height(); 626 // This value is chosen because, as we move across the image, it will sometimes 627 // align with the jpeg block sizes and it will sometimes not. This allows us 628 // to test interestingly different code paths in the implementation. 629 const int tileSize = 36; 630 631 SkCodec::Options opts; 632 SkIRect subset; 633 for (int x = 0; x < width; x += tileSize) { 634 subset = SkIRect::MakeXYWH(x, 0, SkTMin(tileSize, width - x), height); 635 opts.fSubset = ⊂ 636 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &opts, 637 colorPtr, &colorCount)) { 638 return "Could not start scanline decoder."; 639 } 640 641 codec->getScanlines(SkTAddOffset<void>(pixels.get(), x * bpp), height, rowBytes); 642 } 643 644 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr, colorCount, 645 fDstColorType); 646 break; 647 } 648 case kSubset_Mode: { 649 // Arbitrarily choose a divisor. 650 int divisor = 2; 651 // Total width/height of the image. 652 const int W = codec->getInfo().width(); 653 const int H = codec->getInfo().height(); 654 if (divisor > W || divisor > H) { 655 return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divisor %d is too big " 656 "for %s with dimensions (%d x %d)", divisor, 657 fPath.c_str(), W, H)); 658 } 659 // subset dimensions 660 // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries. 661 const int w = SkAlign2(W / divisor); 662 const int h = SkAlign2(H / divisor); 663 SkIRect subset; 664 SkCodec::Options opts; 665 opts.fSubset = ⊂ 666 SkBitmap subsetBm; 667 // We will reuse pixel memory from bitmap. 668 void* dst = pixels.get(); 669 // Keep track of left and top (for drawing subsetBm into canvas). We could use 670 // fScale * x and fScale * y, but we want integers such that the next subset will start 671 // where the last one ended. So we'll add decodeInfo.width() and height(). 672 int left = 0; 673 for (int x = 0; x < W; x += w) { 674 int top = 0; 675 for (int y = 0; y < H; y+= h) { 676 // Do not make the subset go off the edge of the image. 677 const int preScaleW = SkTMin(w, W - x); 678 const int preScaleH = SkTMin(h, H - y); 679 subset.setXYWH(x, y, preScaleW, preScaleH); 680 // And scale 681 // FIXME: Should we have a version of getScaledDimensions that takes a subset 682 // into account? 683 const int scaledW = SkTMax(1, SkScalarRoundToInt(preScaleW * fScale)); 684 const int scaledH = SkTMax(1, SkScalarRoundToInt(preScaleH * fScale)); 685 decodeInfo = decodeInfo.makeWH(scaledW, scaledH); 686 SkImageInfo subsetBitmapInfo = bitmapInfo.makeWH(scaledW, scaledH); 687 size_t subsetRowBytes = subsetBitmapInfo.minRowBytes(); 688 const SkCodec::Result result = codec->getPixels(decodeInfo, dst, subsetRowBytes, 689 &opts, colorPtr, &colorCount); 690 switch (result) { 691 case SkCodec::kSuccess: 692 case SkCodec::kIncompleteInput: 693 break; 694 default: 695 return SkStringPrintf("subset codec failed to decode (%d, %d, %d, %d) " 696 "from %s with dimensions (%d x %d)\t error %d", 697 x, y, decodeInfo.width(), decodeInfo.height(), 698 fPath.c_str(), W, H, result); 699 } 700 draw_to_canvas(canvas, subsetBitmapInfo, dst, subsetRowBytes, colorPtr, 701 colorCount, fDstColorType, SkIntToScalar(left), 702 SkIntToScalar(top)); 703 704 // translate by the scaled height. 705 top += decodeInfo.height(); 706 } 707 // translate by the scaled width. 708 left += decodeInfo.width(); 709 } 710 return ""; 711 } 712 default: 713 SkASSERT(false); 714 return "Invalid fMode"; 715 } 716 return ""; 717} 718 719SkISize CodecSrc::size() const { 720 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 721 std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(encoded)); 722 if (nullptr == codec) { 723 return SkISize::Make(0, 0); 724 } 725 726 auto imageSize = codec->getScaledDimensions(fScale); 727 if (fMode == kAnimated_Mode) { 728 // We'll draw one of each frame, so make it big enough to hold them all 729 // in a grid. The grid will be roughly square, with "factor" frames per 730 // row and up to "factor" rows. 731 const size_t count = codec->getFrameInfo().size(); 732 const float root = sqrt((float) count); 733 const int factor = sk_float_ceil2int(root); 734 imageSize.fWidth = imageSize.fWidth * factor; 735 imageSize.fHeight = imageSize.fHeight * sk_float_ceil2int((float) count / (float) factor); 736 } 737 return imageSize; 738} 739 740Name CodecSrc::name() const { 741 if (1.0f == fScale) { 742 Name name = SkOSPath::Basename(fPath.c_str()); 743 if (fMode == kAnimated_Mode) { 744 name.append("_animated"); 745 } 746 return name; 747 } 748 SkASSERT(fMode != kAnimated_Mode); 749 return get_scaled_name(fPath, fScale); 750} 751 752/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 753 754AndroidCodecSrc::AndroidCodecSrc(Path path, CodecSrc::DstColorType dstColorType, 755 SkAlphaType dstAlphaType, int sampleSize) 756 : fPath(path) 757 , fDstColorType(dstColorType) 758 , fDstAlphaType(dstAlphaType) 759 , fSampleSize(sampleSize) 760 , fRunSerially(serial_from_path_name(path)) 761{} 762 763bool AndroidCodecSrc::veto(SinkFlags flags) const { 764 // No need to test decoding to non-raster or indirect backend. 765 return flags.type != SinkFlags::kRaster 766 || flags.approach != SinkFlags::kDirect; 767} 768 769Error AndroidCodecSrc::draw(SkCanvas* canvas) const { 770 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 771 if (!encoded) { 772 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 773 } 774 std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded)); 775 if (nullptr == codec.get()) { 776 return SkStringPrintf("Couldn't create android codec for %s.", fPath.c_str()); 777 } 778 779 SkImageInfo decodeInfo = codec->getInfo(); 780 if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType, 781 fDstAlphaType)) { 782 return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); 783 } 784 785 // Scale the image if it is desired. 786 SkISize size = codec->getSampledDimensions(fSampleSize); 787 788 // Visually inspecting very small output images is not necessary. We will 789 // cover these cases in unit testing. 790 if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) { 791 return Error::Nonfatal("Scaling very small images is uninteresting."); 792 } 793 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); 794 795 int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType()); 796 size_t rowBytes = size.width() * bpp; 797 SkAutoMalloc pixels(size.height() * rowBytes); 798 SkPMColor colorPtr[256]; 799 int colorCount = 256; 800 801 SkBitmap bitmap; 802 SkImageInfo bitmapInfo = decodeInfo; 803 if (kRGBA_8888_SkColorType == decodeInfo.colorType() || 804 kBGRA_8888_SkColorType == decodeInfo.colorType()) { 805 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType); 806 } 807 808 // Create options for the codec. 809 SkAndroidCodec::AndroidOptions options; 810 options.fColorPtr = colorPtr; 811 options.fColorCount = &colorCount; 812 options.fSampleSize = fSampleSize; 813 814 switch (codec->getAndroidPixels(decodeInfo, pixels.get(), rowBytes, &options)) { 815 case SkCodec::kSuccess: 816 case SkCodec::kIncompleteInput: 817 break; 818 default: 819 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); 820 } 821 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr, colorCount, fDstColorType); 822 return ""; 823} 824 825SkISize AndroidCodecSrc::size() const { 826 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 827 std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded)); 828 if (nullptr == codec) { 829 return SkISize::Make(0, 0); 830 } 831 return codec->getSampledDimensions(fSampleSize); 832} 833 834Name AndroidCodecSrc::name() const { 835 // We will replicate the names used by CodecSrc so that images can 836 // be compared in Gold. 837 if (1 == fSampleSize) { 838 return SkOSPath::Basename(fPath.c_str()); 839 } 840 return get_scaled_name(fPath, 1.0f / (float) fSampleSize); 841} 842 843/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 844 845ImageGenSrc::ImageGenSrc(Path path, Mode mode, SkAlphaType alphaType, bool isGpu) 846 : fPath(path) 847 , fMode(mode) 848 , fDstAlphaType(alphaType) 849 , fIsGpu(isGpu) 850 , fRunSerially(serial_from_path_name(path)) 851{} 852 853bool ImageGenSrc::veto(SinkFlags flags) const { 854 if (fIsGpu) { 855 return flags.type != SinkFlags::kGPU || flags.approach != SinkFlags::kDirect; 856 } 857 858 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect; 859} 860 861Error ImageGenSrc::draw(SkCanvas* canvas) const { 862 if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) { 863 return Error::Nonfatal("Uninteresting to test image generator to 565."); 864 } 865 866 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 867 if (!encoded) { 868 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 869 } 870 871#if defined(SK_BUILD_FOR_WIN) 872 // Initialize COM in order to test with WIC. 873 SkAutoCoInitialize com; 874 if (!com.succeeded()) { 875 return "Could not initialize COM."; 876 } 877#endif 878 879 std::unique_ptr<SkImageGenerator> gen(nullptr); 880 switch (fMode) { 881 case kCodec_Mode: 882 gen.reset(SkCodecImageGenerator::NewFromEncodedCodec(encoded.get())); 883 if (!gen) { 884 return "Could not create codec image generator."; 885 } 886 break; 887 case kPlatform_Mode: { 888#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) 889 gen.reset(SkImageGeneratorCG::NewFromEncodedCG(encoded.get())); 890#elif defined(SK_BUILD_FOR_WIN) 891 gen.reset(SkImageGeneratorWIC::NewFromEncodedWIC(encoded.get())); 892#endif 893 894 if (!gen) { 895 return "Could not create platform image generator."; 896 } 897 break; 898 } 899 default: 900 SkASSERT(false); 901 return "Invalid image generator mode"; 902 } 903 904 // Test deferred decoding path on GPU 905 if (fIsGpu) { 906 sk_sp<SkImage> image(SkImage::MakeFromGenerator(gen.release(), nullptr)); 907 if (!image) { 908 return "Could not create image from codec image generator."; 909 } 910 canvas->drawImage(image, 0, 0); 911 return ""; 912 } 913 914 // Test various color and alpha types on CPU 915 SkImageInfo decodeInfo = gen->getInfo().makeAlphaType(fDstAlphaType); 916 917 int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType()); 918 size_t rowBytes = decodeInfo.width() * bpp; 919 SkAutoMalloc pixels(decodeInfo.height() * rowBytes); 920 SkPMColor colorPtr[256]; 921 int colorCount = 256; 922 923 if (!gen->getPixels(decodeInfo, pixels.get(), rowBytes, colorPtr, &colorCount)) { 924 return SkStringPrintf("Image generator could not getPixels() for %s\n", fPath.c_str()); 925 } 926 927 draw_to_canvas(canvas, decodeInfo, pixels.get(), rowBytes, colorPtr, colorCount, 928 CodecSrc::kGetFromCanvas_DstColorType); 929 return ""; 930} 931 932SkISize ImageGenSrc::size() const { 933 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 934 std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(encoded)); 935 if (nullptr == codec) { 936 return SkISize::Make(0, 0); 937 } 938 return codec->getInfo().dimensions(); 939} 940 941Name ImageGenSrc::name() const { 942 return SkOSPath::Basename(fPath.c_str()); 943} 944 945/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 946 947ColorCodecSrc::ColorCodecSrc(Path path, Mode mode, SkColorType colorType) 948 : fPath(path) 949 , fMode(mode) 950 , fColorType(colorType) 951{} 952 953bool ColorCodecSrc::veto(SinkFlags flags) const { 954 // Test to direct raster backends (8888 and 565). 955 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect; 956} 957 958Error ColorCodecSrc::draw(SkCanvas* canvas) const { 959 if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) { 960 return Error::Nonfatal("No need to test color correction to 565 backend."); 961 } 962 963 bool runInLegacyMode = kBaseline_Mode == fMode; 964 if (runInLegacyMode && canvas->imageInfo().colorSpace()) { 965 return Error::Nonfatal("Skipping tests that are only interesting in legacy mode."); 966 } else if (!runInLegacyMode && !canvas->imageInfo().colorSpace()) { 967 return Error::Nonfatal("Skipping tests that are only interesting in srgb mode."); 968 } 969 970 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 971 if (!encoded) { 972 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 973 } 974 975 std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(encoded)); 976 if (nullptr == codec.get()) { 977 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); 978 } 979 980 // Load the dst ICC profile. This particular dst is fairly similar to Adobe RGB. 981 sk_sp<SkData> dstData = SkData::MakeFromFileName( 982 GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str()); 983 if (!dstData) { 984 return "Cannot read monitor profile. Is the resource path set correctly?"; 985 } 986 987 sk_sp<SkColorSpace> dstSpace = nullptr; 988 if (kDst_sRGB_Mode == fMode) { 989 dstSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); 990 } else if (kDst_HPZR30w_Mode == fMode) { 991 dstSpace = SkColorSpace::MakeICC(dstData->data(), dstData->size()); 992 } 993 994 SkImageInfo decodeInfo = codec->getInfo().makeColorType(fColorType).makeColorSpace(dstSpace); 995 if (kUnpremul_SkAlphaType == decodeInfo.alphaType()) { 996 decodeInfo = decodeInfo.makeAlphaType(kPremul_SkAlphaType); 997 } 998 if (kRGBA_F16_SkColorType == fColorType) { 999 SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(decodeInfo.colorSpace())->type()); 1000 SkColorSpace_XYZ* csXYZ = static_cast<SkColorSpace_XYZ*>(decodeInfo.colorSpace()); 1001 decodeInfo = decodeInfo.makeColorSpace(csXYZ->makeLinearGamma()); 1002 } 1003 1004 SkImageInfo bitmapInfo = decodeInfo; 1005 if (kRGBA_8888_SkColorType == decodeInfo.colorType() || 1006 kBGRA_8888_SkColorType == decodeInfo.colorType()) 1007 { 1008 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType); 1009 } 1010 1011 SkBitmap bitmap; 1012 if (!bitmap.tryAllocPixels(bitmapInfo)) { 1013 return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(), 1014 bitmapInfo.width(), bitmapInfo.height()); 1015 } 1016 1017 size_t rowBytes = bitmap.rowBytes(); 1018 SkCodec::Result r = codec->getPixels(decodeInfo, bitmap.getPixels(), rowBytes); 1019 if (SkCodec::kSuccess != r && SkCodec::kIncompleteInput != r) { 1020 // FIXME (raftias): 1021 // This should be a fatal error. We need to add support for 1022 // A2B images in SkColorSpaceXform. 1023 return Error::Nonfatal(SkStringPrintf("Couldn't getPixels %s. Error code %d", 1024 fPath.c_str(), r)); 1025 } 1026 1027 switch (fMode) { 1028 case kBaseline_Mode: 1029 case kDst_sRGB_Mode: 1030 case kDst_HPZR30w_Mode: 1031 canvas->drawBitmap(bitmap, 0, 0); 1032 break; 1033 default: 1034 SkASSERT(false); 1035 return "Invalid fMode"; 1036 } 1037 return ""; 1038} 1039 1040SkISize ColorCodecSrc::size() const { 1041 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 1042 std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(encoded)); 1043 if (nullptr == codec) { 1044 return SkISize::Make(0, 0); 1045 } 1046 return SkISize::Make(codec->getInfo().width(), codec->getInfo().height()); 1047} 1048 1049Name ColorCodecSrc::name() const { 1050 return SkOSPath::Basename(fPath.c_str()); 1051} 1052 1053/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1054 1055static const SkRect kSKPViewport = {0,0, 1000,1000}; 1056 1057SKPSrc::SKPSrc(Path path) : fPath(path) {} 1058 1059Error SKPSrc::draw(SkCanvas* canvas) const { 1060 std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(fPath.c_str()); 1061 if (!stream) { 1062 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 1063 } 1064 sk_sp<SkPicture> pic(SkPicture::MakeFromStream(stream.get())); 1065 if (!pic) { 1066 return SkStringPrintf("Couldn't decode %s as a picture.", fPath.c_str()); 1067 } 1068 stream = nullptr; // Might as well drop this when we're done with it. 1069 1070 canvas->clipRect(kSKPViewport); 1071 canvas->drawPicture(pic); 1072 return ""; 1073} 1074 1075SkISize SKPSrc::size() const { 1076 std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(fPath.c_str()); 1077 if (!stream) { 1078 return SkISize::Make(0,0); 1079 } 1080 SkPictInfo info; 1081 if (!SkPicture::InternalOnly_StreamIsSKP(stream.get(), &info)) { 1082 return SkISize::Make(0,0); 1083 } 1084 SkRect viewport = kSKPViewport; 1085 if (!viewport.intersect(info.fCullRect)) { 1086 return SkISize::Make(0,0); 1087 } 1088 return viewport.roundOut().size(); 1089} 1090 1091Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); } 1092 1093/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1094#if defined(SK_XML) 1095// Used when the image doesn't have an intrinsic size. 1096static const SkSize kDefaultSVGSize = SkSize::Make(1000, 1000); 1097 1098// Used to force-scale tiny fixed-size images. 1099static const SkSize kMinimumSVGSize = SkSize::Make(128, 128); 1100 1101SVGSrc::SVGSrc(Path path) : fPath(path), fScale(1) {} 1102 1103Error SVGSrc::ensureDom() const { 1104 if (!fDom) { 1105 SkFILEStream stream(fPath.c_str()); 1106 if (!stream.isValid()) { 1107 return SkStringPrintf("Unable to open file: %s", fPath.c_str()); 1108 } 1109 fDom = SkSVGDOM::MakeFromStream(stream); 1110 if (!fDom) { 1111 return SkStringPrintf("Unable to parse file: %s", fPath.c_str()); 1112 } 1113 1114 const SkSize& sz = fDom->containerSize(); 1115 if (sz.isEmpty()) { 1116 // no intrinsic size 1117 fDom->setContainerSize(kDefaultSVGSize); 1118 } else { 1119 fScale = SkTMax(1.f, SkTMax(kMinimumSVGSize.width() / sz.width(), 1120 kMinimumSVGSize.height() / sz.height())); 1121 } 1122 } 1123 1124 return ""; 1125} 1126 1127Error SVGSrc::draw(SkCanvas* canvas) const { 1128 Error err = this->ensureDom(); 1129 if (err.isEmpty()) { 1130 SkAutoCanvasRestore acr(canvas, true); 1131 canvas->scale(fScale, fScale); 1132 fDom->render(canvas); 1133 } 1134 1135 return err; 1136} 1137 1138SkISize SVGSrc::size() const { 1139 Error err = this->ensureDom(); 1140 if (!err.isEmpty()) { 1141 return SkISize::Make(0, 0); 1142 } 1143 1144 return SkSize::Make(fDom->containerSize().width() * fScale, 1145 fDom->containerSize().height() * fScale).toRound(); 1146} 1147 1148Name SVGSrc::name() const { return SkOSPath::Basename(fPath.c_str()); } 1149 1150bool SVGSrc::veto(SinkFlags flags) const { 1151 // No need to test to non-(raster||gpu) or indirect backends. 1152 bool type_ok = flags.type == SinkFlags::kRaster 1153 || flags.type == SinkFlags::kGPU; 1154 1155 return !type_ok || flags.approach != SinkFlags::kDirect; 1156} 1157 1158#endif // defined(SK_XML) 1159/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1160 1161MSKPSrc::MSKPSrc(Path path) : fPath(path) { 1162 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fPath.c_str()); 1163 (void)fReader.init(stream.get()); 1164} 1165 1166int MSKPSrc::pageCount() const { return fReader.pageCount(); } 1167 1168SkISize MSKPSrc::size() const { return this->size(0); } 1169SkISize MSKPSrc::size(int i) const { return fReader.pageSize(i).toCeil(); } 1170 1171Error MSKPSrc::draw(SkCanvas* c) const { return this->draw(0, c); } 1172Error MSKPSrc::draw(int i, SkCanvas* canvas) const { 1173 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fPath.c_str()); 1174 if (!stream) { 1175 return SkStringPrintf("Unable to open file: %s", fPath.c_str()); 1176 } 1177 if (fReader.pageCount() == 0) { 1178 return SkStringPrintf("Unable to parse MultiPictureDocument file: %s", fPath.c_str()); 1179 } 1180 if (i >= fReader.pageCount()) { 1181 return SkStringPrintf("MultiPictureDocument page number out of range: %d", i); 1182 } 1183 sk_sp<SkPicture> page = fReader.readPage(stream.get(), i); 1184 if (!page) { 1185 return SkStringPrintf("SkMultiPictureDocumentReader failed on page %d: %s", 1186 i, fPath.c_str()); 1187 } 1188 canvas->drawPicture(page); 1189 return ""; 1190} 1191 1192Name MSKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); } 1193 1194/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1195 1196Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const { 1197 std::unique_ptr<SkCanvas> canvas(SkCreateNullCanvas()); 1198 return src.draw(canvas.get()); 1199} 1200 1201/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1202 1203DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?"); 1204 1205GPUSink::GPUSink(GrContextFactory::ContextType ct, 1206 GrContextFactory::ContextOptions options, 1207 int samples, 1208 bool diText, 1209 SkColorType colorType, 1210 sk_sp<SkColorSpace> colorSpace, 1211 bool threaded) 1212 : fContextType(ct) 1213 , fContextOptions(options) 1214 , fSampleCount(samples) 1215 , fUseDIText(diText) 1216 , fColorType(colorType) 1217 , fColorSpace(std::move(colorSpace)) 1218 , fThreaded(threaded) {} 1219 1220DEFINE_bool(imm, false, "Run gpu configs in immediate mode."); 1221DEFINE_bool(batchClip, false, "Clip each GrBatch to its device bounds for testing."); 1222DEFINE_bool(batchBounds, false, "Draw a wireframe bounds of each GrBatch."); 1223DEFINE_int32(batchLookback, -1, "Maximum GrBatch lookback for combining, negative means default."); 1224DEFINE_int32(batchLookahead, -1, "Maximum GrBatch lookahead for combining, negative means " 1225 "default."); 1226 1227Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const { 1228 GrContextOptions grOptions; 1229 grOptions.fImmediateMode = FLAGS_imm; 1230 grOptions.fClipBatchToBounds = FLAGS_batchClip; 1231 grOptions.fDrawBatchBounds = FLAGS_batchBounds; 1232 grOptions.fMaxBatchLookback = FLAGS_batchLookback; 1233 grOptions.fMaxBatchLookahead = FLAGS_batchLookahead; 1234 1235 src.modifyGrContextOptions(&grOptions); 1236 1237 GrContextFactory factory(grOptions); 1238 const SkISize size = src.size(); 1239 const SkImageInfo info = 1240 SkImageInfo::Make(size.width(), size.height(), fColorType, 1241 kPremul_SkAlphaType, fColorSpace); 1242#if SK_SUPPORT_GPU 1243 GrContext* context = factory.getContextInfo(fContextType, fContextOptions).grContext(); 1244 const int maxDimension = context->caps()->maxTextureSize(); 1245 if (maxDimension < SkTMax(size.width(), size.height())) { 1246 return Error::Nonfatal("Src too large to create a texture.\n"); 1247 } 1248#endif 1249 1250 auto surface( 1251 NewGpuSurface(&factory, fContextType, fContextOptions, info, fSampleCount, fUseDIText)); 1252 if (!surface) { 1253 return "Could not create a surface."; 1254 } 1255 if (FLAGS_preAbandonGpuContext) { 1256 factory.abandonContexts(); 1257 } 1258 SkCanvas* canvas = surface->getCanvas(); 1259 Error err = src.draw(canvas); 1260 if (!err.isEmpty()) { 1261 return err; 1262 } 1263 canvas->flush(); 1264 if (FLAGS_gpuStats) { 1265 canvas->getGrContext()->dumpCacheStats(log); 1266 canvas->getGrContext()->dumpGpuStats(log); 1267 } 1268 dst->allocPixels(info); 1269 canvas->readPixels(dst, 0, 0); 1270 if (FLAGS_abandonGpuContext) { 1271 factory.abandonContexts(); 1272 } else if (FLAGS_releaseAndAbandonGpuContext) { 1273 factory.releaseResourcesAndAbandonContexts(); 1274 } 1275 return ""; 1276} 1277 1278/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1279 1280static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) { 1281 if (src.size().isEmpty()) { 1282 return "Source has empty dimensions"; 1283 } 1284 SkASSERT(doc); 1285 int pageCount = src.pageCount(); 1286 for (int i = 0; i < pageCount; ++i) { 1287 int width = src.size(i).width(), height = src.size(i).height(); 1288 SkCanvas* canvas = 1289 doc->beginPage(SkIntToScalar(width), SkIntToScalar(height)); 1290 if (!canvas) { 1291 return "SkDocument::beginPage(w,h) returned nullptr"; 1292 } 1293 Error err = src.draw(i, canvas); 1294 if (!err.isEmpty()) { 1295 return err; 1296 } 1297 doc->endPage(); 1298 } 1299 doc->close(); 1300 dst->flush(); 1301 return ""; 1302} 1303 1304Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1305 SkDocument::PDFMetadata metadata; 1306 metadata.fTitle = src.name(); 1307 metadata.fSubject = "rendering correctness test"; 1308 metadata.fCreator = "Skia/DM"; 1309 sk_sp<SkDocument> doc = SkDocument::MakePDF(dst, SK_ScalarDefaultRasterDPI, 1310 metadata, nullptr, fPDFA); 1311 if (!doc) { 1312 return "SkDocument::MakePDF() returned nullptr"; 1313 } 1314 return draw_skdocument(src, doc.get(), dst); 1315} 1316 1317/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1318 1319XPSSink::XPSSink() {} 1320 1321Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1322 sk_sp<SkDocument> doc(SkDocument::MakeXPS(dst)); 1323 if (!doc) { 1324 return "SkDocument::MakeXPS() returned nullptr"; 1325 } 1326 return draw_skdocument(src, doc.get(), dst); 1327} 1328 1329/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1330 1331PipeSink::PipeSink() {} 1332 1333Error PipeSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1334 return src.draw(SkPipeSerializer().beginWrite(SkRect::Make(src.size()), dst)); 1335} 1336 1337/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1338 1339SKPSink::SKPSink() {} 1340 1341Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1342 SkSize size; 1343 size = src.size(); 1344 SkPictureRecorder recorder; 1345 Error err = src.draw(recorder.beginRecording(size.width(), size.height())); 1346 if (!err.isEmpty()) { 1347 return err; 1348 } 1349 recorder.finishRecordingAsPicture()->serialize(dst); 1350 return ""; 1351} 1352 1353/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1354 1355Error DebugSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1356 SkDebugCanvas debugCanvas(src.size().width(), src.size().height()); 1357 Error err = src.draw(&debugCanvas); 1358 if (!err.isEmpty()) { 1359 return err; 1360 } 1361 sk_sp<SkCanvas> nullCanvas(SkCreateNullCanvas()); 1362 UrlDataManager dataManager(SkString("data")); 1363 Json::Value json = debugCanvas.toJSON( 1364 dataManager, debugCanvas.getSize(), nullCanvas.get()); 1365 std::string value = Json::StyledWriter().write(json); 1366 return dst->write(value.c_str(), value.size()) ? "" : "SkWStream Error"; 1367} 1368 1369/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1370 1371SVGSink::SVGSink() {} 1372 1373Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1374#if defined(SK_XML) 1375 std::unique_ptr<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(dst)); 1376 sk_sp<SkCanvas> canvas(SkSVGCanvas::Create( 1377 SkRect::MakeWH(SkIntToScalar(src.size().width()), SkIntToScalar(src.size().height())), 1378 xmlWriter.get())); 1379 return src.draw(canvas.get()); 1380#else 1381 return Error("SVG sink is disabled."); 1382#endif // SK_XML 1383} 1384 1385/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1386 1387RasterSink::RasterSink(SkColorType colorType, sk_sp<SkColorSpace> colorSpace) 1388 : fColorType(colorType) 1389 , fColorSpace(std::move(colorSpace)) {} 1390 1391Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const { 1392 const SkISize size = src.size(); 1393 // If there's an appropriate alpha type for this color type, use it, otherwise use premul. 1394 SkAlphaType alphaType = kPremul_SkAlphaType; 1395 (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType); 1396 1397 SkMallocPixelRef::ZeroedPRFactory factory; 1398 dst->allocPixels(SkImageInfo::Make(size.width(), size.height(), 1399 fColorType, alphaType, fColorSpace), 1400 &factory, 1401 nullptr/*colortable*/); 1402 SkCanvas canvas(*dst); 1403 return src.draw(&canvas); 1404} 1405 1406/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1407 1408// Handy for front-patching a Src. Do whatever up-front work you need, then call draw_to_canvas(), 1409// passing the Sink draw() arguments, a size, and a function draws into an SkCanvas. 1410// Several examples below. 1411 1412template <typename Fn> 1413static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log, 1414 SkISize size, const Fn& draw) { 1415 class ProxySrc : public Src { 1416 public: 1417 ProxySrc(SkISize size, const Fn& draw) : fSize(size), fDraw(draw) {} 1418 Error draw(SkCanvas* canvas) const override { return fDraw(canvas); } 1419 Name name() const override { return "ProxySrc"; } 1420 SkISize size() const override { return fSize; } 1421 private: 1422 SkISize fSize; 1423 const Fn& fDraw; 1424 }; 1425 return sink->draw(ProxySrc(size, draw), bitmap, stream, log); 1426} 1427 1428/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1429 1430DEFINE_bool(check, true, "If true, have most Via- modes fail if they affect the output."); 1431 1432// Is *bitmap identical to what you get drawing src into sink? 1433static Error check_against_reference(const SkBitmap* bitmap, const Src& src, Sink* sink) { 1434 // We can only check raster outputs. 1435 // (Non-raster outputs like .pdf, .skp, .svg may differ but still draw identically.) 1436 if (FLAGS_check && bitmap) { 1437 SkBitmap reference; 1438 SkString log; 1439 SkDynamicMemoryWStream wStream; 1440 Error err = sink->draw(src, &reference, &wStream, &log); 1441 // If we can draw into this Sink via some pipeline, we should be able to draw directly. 1442 SkASSERT(err.isEmpty()); 1443 if (!err.isEmpty()) { 1444 return err; 1445 } 1446 // The dimensions are a property of the Src only, and so should be identical. 1447 SkASSERT(reference.getSize() == bitmap->getSize()); 1448 if (reference.getSize() != bitmap->getSize()) { 1449 return "Dimensions don't match reference"; 1450 } 1451 // All SkBitmaps in DM are pre-locked and tight, so this comparison is easy. 1452 if (0 != memcmp(reference.getPixels(), bitmap->getPixels(), reference.getSize())) { 1453 return "Pixels don't match reference"; 1454 } 1455 } 1456 return ""; 1457} 1458 1459/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1460 1461static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) { 1462 SkRect bounds = SkRect::MakeIWH(srcW, srcH); 1463 matrix->mapRect(&bounds); 1464 matrix->postTranslate(-bounds.x(), -bounds.y()); 1465 return SkISize::Make(SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height())); 1466} 1467 1468ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {} 1469 1470Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1471 SkMatrix matrix = fMatrix; 1472 SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height()); 1473 return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) { 1474 canvas->concat(matrix); 1475 return src.draw(canvas); 1476 }); 1477} 1478 1479// Undoes any flip or 90 degree rotate without changing the scale of the bitmap. 1480// This should be pixel-preserving. 1481ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {} 1482 1483Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1484 Error err = fSink->draw(src, bitmap, stream, log); 1485 if (!err.isEmpty()) { 1486 return err; 1487 } 1488 1489 SkMatrix inverse; 1490 if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) { 1491 return "Cannot upright --matrix."; 1492 } 1493 SkMatrix upright = SkMatrix::I(); 1494 upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX())); 1495 upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY())); 1496 upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX())); 1497 upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY())); 1498 1499 SkBitmap uprighted; 1500 SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height()); 1501 uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height())); 1502 1503 SkCanvas canvas(uprighted); 1504 canvas.concat(upright); 1505 SkPaint paint; 1506 paint.setBlendMode(SkBlendMode::kSrc); 1507 canvas.drawBitmap(*bitmap, 0, 0, &paint); 1508 1509 *bitmap = uprighted; 1510 bitmap->lockPixels(); 1511 return ""; 1512} 1513 1514/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1515 1516Error ViaSerialization::draw( 1517 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1518 // Record our Src into a picture. 1519 auto size = src.size(); 1520 SkPictureRecorder recorder; 1521 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 1522 SkIntToScalar(size.height()))); 1523 if (!err.isEmpty()) { 1524 return err; 1525 } 1526 sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture()); 1527 1528 // Serialize it and then deserialize it. 1529 sk_sp<SkPicture> deserialized(SkPicture::MakeFromData(pic->serialize().get())); 1530 1531 return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) { 1532 canvas->drawPicture(deserialized); 1533 return check_against_reference(bitmap, src, fSink.get()); 1534 }); 1535} 1536 1537/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1538 1539ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink) 1540 : Via(sink) 1541 , fW(w) 1542 , fH(h) 1543 , fFactory(factory) {} 1544 1545Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1546 auto size = src.size(); 1547 SkPictureRecorder recorder; 1548 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 1549 SkIntToScalar(size.height()), 1550 fFactory.get())); 1551 if (!err.isEmpty()) { 1552 return err; 1553 } 1554 sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture()); 1555 1556 return draw_to_canvas(fSink.get(), bitmap, stream, log, src.size(), [&](SkCanvas* canvas) { 1557 const int xTiles = (size.width() + fW - 1) / fW, 1558 yTiles = (size.height() + fH - 1) / fH; 1559 SkMultiPictureDraw mpd(xTiles*yTiles); 1560 SkTArray<sk_sp<SkSurface>> surfaces; 1561// surfaces.setReserve(xTiles*yTiles); 1562 1563 SkImageInfo info = canvas->imageInfo().makeWH(fW, fH); 1564 for (int j = 0; j < yTiles; j++) { 1565 for (int i = 0; i < xTiles; i++) { 1566 // This lets our ultimate Sink determine the best kind of surface. 1567 // E.g., if it's a GpuSink, the surfaces and images are textures. 1568 auto s = canvas->makeSurface(info); 1569 if (!s) { 1570 s = SkSurface::MakeRaster(info); // Some canvases can't create surfaces. 1571 } 1572 surfaces.push_back(s); 1573 SkCanvas* c = s->getCanvas(); 1574 c->translate(SkIntToScalar(-i * fW), 1575 SkIntToScalar(-j * fH)); // Line up the canvas with this tile. 1576 mpd.add(c, pic.get()); 1577 } 1578 } 1579 mpd.draw(); 1580 for (int j = 0; j < yTiles; j++) { 1581 for (int i = 0; i < xTiles; i++) { 1582 sk_sp<SkImage> image(surfaces[i+xTiles*j]->makeImageSnapshot()); 1583 canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH)); 1584 } 1585 } 1586 return ""; 1587 }); 1588} 1589 1590/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1591 1592Error ViaPicture::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1593 auto size = src.size(); 1594 return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 1595 SkPictureRecorder recorder; 1596 sk_sp<SkPicture> pic; 1597 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 1598 SkIntToScalar(size.height()))); 1599 if (!err.isEmpty()) { 1600 return err; 1601 } 1602 pic = recorder.finishRecordingAsPicture(); 1603 canvas->drawPicture(pic); 1604 return check_against_reference(bitmap, src, fSink.get()); 1605 }); 1606} 1607 1608/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1609 1610Error ViaDefer::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1611 auto size = src.size(); 1612 return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 1613 SkDeferredCanvas deferred(canvas); 1614 return src.draw(&deferred); 1615 }); 1616} 1617 1618/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1619 1620Error ViaPipe::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1621 auto size = src.size(); 1622 return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 1623 SkDynamicMemoryWStream tmpStream; 1624 Error err = src.draw(SkPipeSerializer().beginWrite(SkRect::Make(size), &tmpStream)); 1625 if (!err.isEmpty()) { 1626 return err; 1627 } 1628 sk_sp<SkData> data = tmpStream.detachAsData(); 1629 SkPipeDeserializer().playback(data->data(), data->size(), canvas); 1630 return check_against_reference(bitmap, src, fSink.get()); 1631 }); 1632} 1633 1634/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1635 1636// Draw the Src into two pictures, then draw the second picture into the wrapped Sink. 1637// This tests that any shortcuts we may take while recording that second picture are legal. 1638Error ViaSecondPicture::draw( 1639 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1640 auto size = src.size(); 1641 return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 1642 SkPictureRecorder recorder; 1643 sk_sp<SkPicture> pic; 1644 for (int i = 0; i < 2; i++) { 1645 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 1646 SkIntToScalar(size.height()))); 1647 if (!err.isEmpty()) { 1648 return err; 1649 } 1650 pic = recorder.finishRecordingAsPicture(); 1651 } 1652 canvas->drawPicture(pic); 1653 return check_against_reference(bitmap, src, fSink.get()); 1654 }); 1655} 1656 1657/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1658 1659// Draw the Src twice. This can help exercise caching. 1660Error ViaTwice::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1661 return draw_to_canvas(fSink.get(), bitmap, stream, log, src.size(), [&](SkCanvas* canvas) -> Error { 1662 for (int i = 0; i < 2; i++) { 1663 SkAutoCanvasRestore acr(canvas, true/*save now*/); 1664 canvas->clear(SK_ColorTRANSPARENT); 1665 Error err = src.draw(canvas); 1666 if (err.isEmpty()) { 1667 return err; 1668 } 1669 } 1670 return check_against_reference(bitmap, src, fSink.get()); 1671 }); 1672} 1673 1674/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1675 1676// This is like SkRecords::Draw, in that it plays back SkRecords ops into a Canvas. 1677// Unlike SkRecords::Draw, it builds a single-op sub-picture out of each Draw-type op. 1678// This is an only-slightly-exaggerated simluation of Blink's Slimming Paint pictures. 1679struct DrawsAsSingletonPictures { 1680 SkCanvas* fCanvas; 1681 const SkDrawableList& fDrawables; 1682 SkRect fBounds; 1683 1684 template <typename T> 1685 void draw(const T& op, SkCanvas* canvas) { 1686 // We must pass SkMatrix::I() as our initial matrix. 1687 // By default SkRecords::Draw() uses the canvas' matrix as its initial matrix, 1688 // which would have the funky effect of applying transforms over and over. 1689 SkRecords::Draw d(canvas, nullptr, fDrawables.begin(), fDrawables.count(), &SkMatrix::I()); 1690 d(op); 1691 } 1692 1693 // Draws get their own picture. 1694 template <typename T> 1695 SK_WHEN(T::kTags & SkRecords::kDraw_Tag, void) operator()(const T& op) { 1696 SkPictureRecorder rec; 1697 this->draw(op, rec.beginRecording(fBounds)); 1698 sk_sp<SkPicture> pic(rec.finishRecordingAsPicture()); 1699 fCanvas->drawPicture(pic); 1700 } 1701 1702 // We'll just issue non-draws directly. 1703 template <typename T> 1704 skstd::enable_if_t<!(T::kTags & SkRecords::kDraw_Tag), void> operator()(const T& op) { 1705 this->draw(op, fCanvas); 1706 } 1707}; 1708 1709// Record Src into a picture, then record it into a macro picture with a sub-picture for each draw. 1710// Then play back that macro picture into our wrapped sink. 1711Error ViaSingletonPictures::draw( 1712 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1713 auto size = src.size(); 1714 return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 1715 // Use low-level (Skia-private) recording APIs so we can read the SkRecord. 1716 SkRecord skr; 1717 SkRecorder recorder(&skr, size.width(), size.height()); 1718 Error err = src.draw(&recorder); 1719 if (!err.isEmpty()) { 1720 return err; 1721 } 1722 1723 // Record our macro-picture, with each draw op as its own sub-picture. 1724 SkPictureRecorder macroRec; 1725 SkCanvas* macroCanvas = macroRec.beginRecording(SkIntToScalar(size.width()), 1726 SkIntToScalar(size.height())); 1727 1728 std::unique_ptr<SkDrawableList> drawables(recorder.detachDrawableList()); 1729 const SkDrawableList empty; 1730 1731 DrawsAsSingletonPictures drawsAsSingletonPictures = { 1732 macroCanvas, 1733 drawables ? *drawables : empty, 1734 SkRect::MakeWH((SkScalar)size.width(), (SkScalar)size.height()), 1735 }; 1736 for (int i = 0; i < skr.count(); i++) { 1737 skr.visit(i, drawsAsSingletonPictures); 1738 } 1739 sk_sp<SkPicture> macroPic(macroRec.finishRecordingAsPicture()); 1740 1741 canvas->drawPicture(macroPic); 1742 return check_against_reference(bitmap, src, fSink.get()); 1743 }); 1744} 1745 1746/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1747 1748Error ViaLite::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1749 auto size = src.size(); 1750 SkRect bounds = {0,0, (SkScalar)size.width(), (SkScalar)size.height()}; 1751 return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 1752 sk_sp<SkLiteDL> dl = SkLiteDL::New(bounds); 1753 1754 SkLiteRecorder rec; 1755 rec.reset(dl.get()); 1756 1757 Error err = src.draw(&rec); 1758 if (!err.isEmpty()) { 1759 return err; 1760 } 1761 dl->draw(canvas); 1762 return check_against_reference(bitmap, src, fSink.get()); 1763 }); 1764} 1765 1766} // namespace DM 1767