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