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