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