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