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