Home | History | Annotate | Download | only in dm
      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 "Resources.h"
     10 #include "SkAndroidCodec.h"
     11 #include "SkAutoMalloc.h"
     12 #include "SkBase64.h"
     13 #include "SkCodec.h"
     14 #include "SkCodecImageGenerator.h"
     15 #include "SkColorSpace.h"
     16 #include "SkColorSpaceXform.h"
     17 #include "SkColorSpaceXformCanvas.h"
     18 #include "SkColorSpace_XYZ.h"
     19 #include "SkCommonFlags.h"
     20 #include "SkCommonFlagsGpu.h"
     21 #include "SkData.h"
     22 #include "SkDebugCanvas.h"
     23 #include "SkDeferredDisplayListRecorder.h"
     24 #include "SkDocument.h"
     25 #include "SkExecutor.h"
     26 #include "SkImageGenerator.h"
     27 #include "SkImageGeneratorCG.h"
     28 #include "SkImageGeneratorWIC.h"
     29 #include "SkLiteDL.h"
     30 #include "SkLiteRecorder.h"
     31 #include "SkMallocPixelRef.h"
     32 #include "SkMultiPictureDocumentPriv.h"
     33 #include "SkMultiPictureDraw.h"
     34 #include "SkNullCanvas.h"
     35 #include "SkOSFile.h"
     36 #include "SkOSPath.h"
     37 #include "SkOpts.h"
     38 #include "SkPictureCommon.h"
     39 #include "SkPictureData.h"
     40 #include "SkPictureRecorder.h"
     41 #include "SkPipe.h"
     42 #include "SkPngEncoder.h"
     43 #include "SkRandom.h"
     44 #include "SkRecordDraw.h"
     45 #include "SkRecorder.h"
     46 #include "SkSurfaceCharacterization.h"
     47 #include "SkSVGCanvas.h"
     48 #include "SkStream.h"
     49 #include "SkSwizzler.h"
     50 #include "SkTaskGroup.h"
     51 #include "SkTLogic.h"
     52 #include <cmath>
     53 #include <functional>
     54 #include "../src/jumper/SkJumper.h"
     55 
     56 #if defined(SK_BUILD_FOR_WIN)
     57     #include "SkAutoCoInitialize.h"
     58     #include "SkHRESULT.h"
     59     #include "SkTScopedComPtr.h"
     60     #include <XpsObjectModel.h>
     61 #endif
     62 
     63 #if !defined(SK_BUILD_FOR_GOOGLE3)
     64     #include "Skottie.h"
     65 #endif
     66 
     67 #if defined(SK_XML)
     68     #include "SkSVGDOM.h"
     69     #include "SkXMLWriter.h"
     70 #endif
     71 
     72 DEFINE_bool(multiPage, false, "For document-type backends, render the source"
     73             " into multiple pages");
     74 DEFINE_bool(RAW_threading, true, "Allow RAW decodes to run on multiple threads?");
     75 
     76 using sk_gpu_test::GrContextFactory;
     77 
     78 namespace DM {
     79 
     80 GMSrc::GMSrc(skiagm::GMRegistry::Factory factory) : fFactory(factory) {}
     81 
     82 Error GMSrc::draw(SkCanvas* canvas) const {
     83     std::unique_ptr<skiagm::GM> gm(fFactory(nullptr));
     84     gm->draw(canvas);
     85     return "";
     86 }
     87 
     88 SkISize GMSrc::size() const {
     89     std::unique_ptr<skiagm::GM> gm(fFactory(nullptr));
     90     return gm->getISize();
     91 }
     92 
     93 Name GMSrc::name() const {
     94     std::unique_ptr<skiagm::GM> gm(fFactory(nullptr));
     95     return gm->getName();
     96 }
     97 
     98 void GMSrc::modifyGrContextOptions(GrContextOptions* options) const {
     99     std::unique_ptr<skiagm::GM> gm(fFactory(nullptr));
    100     gm->modifyGrContextOptions(options);
    101 }
    102 
    103 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    104 
    105 BRDSrc::BRDSrc(Path path, Mode mode, CodecSrc::DstColorType dstColorType, uint32_t sampleSize)
    106     : fPath(path)
    107     , fMode(mode)
    108     , fDstColorType(dstColorType)
    109     , fSampleSize(sampleSize)
    110 {}
    111 
    112 bool BRDSrc::veto(SinkFlags flags) const {
    113     // No need to test to non-raster or indirect backends.
    114     return flags.type != SinkFlags::kRaster
    115         || flags.approach != SinkFlags::kDirect;
    116 }
    117 
    118 static SkBitmapRegionDecoder* create_brd(Path path) {
    119     sk_sp<SkData> encoded(SkData::MakeFromFileName(path.c_str()));
    120     if (!encoded) {
    121         return nullptr;
    122     }
    123     return SkBitmapRegionDecoder::Create(encoded, SkBitmapRegionDecoder::kAndroidCodec_Strategy);
    124 }
    125 
    126 static inline void alpha8_to_gray8(SkBitmap* bitmap) {
    127     // Android requires kGray8 bitmaps to be tagged as kAlpha8.  Here we convert
    128     // them back to kGray8 so our test framework can draw them correctly.
    129     if (kAlpha_8_SkColorType == bitmap->info().colorType()) {
    130         SkImageInfo newInfo = bitmap->info().makeColorType(kGray_8_SkColorType)
    131                                             .makeAlphaType(kOpaque_SkAlphaType);
    132         *const_cast<SkImageInfo*>(&bitmap->info()) = newInfo;
    133     }
    134 }
    135 
    136 Error BRDSrc::draw(SkCanvas* canvas) const {
    137     if (canvas->imageInfo().colorSpace() &&
    138             kRGBA_F16_SkColorType != canvas->imageInfo().colorType()) {
    139         // SkAndroidCodec uses legacy premultiplication and blending.  Therefore, we only
    140         // run these tests on legacy canvases.
    141         // We allow an exception for F16, since Android uses F16.
    142         return Error::Nonfatal("Skip testing to color correct canvas.");
    143     }
    144 
    145     SkColorType colorType = canvas->imageInfo().colorType();
    146     if (kRGB_565_SkColorType == colorType &&
    147             CodecSrc::kGetFromCanvas_DstColorType != fDstColorType) {
    148         return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
    149     }
    150     switch (fDstColorType) {
    151         case CodecSrc::kGetFromCanvas_DstColorType:
    152             break;
    153         case CodecSrc::kGrayscale_Always_DstColorType:
    154             colorType = kGray_8_SkColorType;
    155             break;
    156         default:
    157             SkASSERT(false);
    158             break;
    159     }
    160 
    161     std::unique_ptr<SkBitmapRegionDecoder> brd(create_brd(fPath));
    162     if (nullptr == brd.get()) {
    163         return Error::Nonfatal(SkStringPrintf("Could not create brd for %s.", fPath.c_str()));
    164     }
    165 
    166     if (kRGB_565_SkColorType == colorType) {
    167         auto recommendedCT = brd->computeOutputColorType(colorType);
    168         if (recommendedCT != colorType) {
    169             return Error::Nonfatal("Skip decoding non-opaque to 565.");
    170         }
    171     }
    172 
    173     const uint32_t width = brd->width();
    174     const uint32_t height = brd->height();
    175     // Visually inspecting very small output images is not necessary.
    176     if ((width / fSampleSize <= 10 || height / fSampleSize <= 10) && 1 != fSampleSize) {
    177         return Error::Nonfatal("Scaling very small images is uninteresting.");
    178     }
    179     switch (fMode) {
    180         case kFullImage_Mode: {
    181             SkBitmap bitmap;
    182             if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(0, 0, width, height),
    183                     fSampleSize, colorType, false, SkColorSpace::MakeSRGB())) {
    184                 return "Cannot decode (full) region.";
    185             }
    186             alpha8_to_gray8(&bitmap);
    187 
    188             canvas->drawBitmap(bitmap, 0, 0);
    189             return "";
    190         }
    191         case kDivisor_Mode: {
    192             const uint32_t divisor = 2;
    193             if (width < divisor || height < divisor) {
    194                 return Error::Nonfatal("Divisor is larger than image dimension.");
    195             }
    196 
    197             // Use a border to test subsets that extend outside the image.
    198             // We will not allow the border to be larger than the image dimensions.  Allowing
    199             // these large borders causes off by one errors that indicate a problem with the
    200             // test suite, not a problem with the implementation.
    201             const uint32_t maxBorder = SkTMin(width, height) / (fSampleSize * divisor);
    202             const uint32_t scaledBorder = SkTMin(5u, maxBorder);
    203             const uint32_t unscaledBorder = scaledBorder * fSampleSize;
    204 
    205             // We may need to clear the canvas to avoid uninitialized memory.
    206             // Assume we are scaling a 780x780 image with sampleSize = 8.
    207             // The output image should be 97x97.
    208             // Each subset will be 390x390.
    209             // Each scaled subset be 48x48.
    210             // Four scaled subsets will only fill a 96x96 image.
    211             // The bottom row and last column will not be touched.
    212             // This is an unfortunate result of our rounding rules when scaling.
    213             // Maybe we need to consider testing scaled subsets without trying to
    214             // combine them to match the full scaled image?  Or maybe this is the
    215             // best we can do?
    216             canvas->clear(0);
    217 
    218             for (uint32_t x = 0; x < divisor; x++) {
    219                 for (uint32_t y = 0; y < divisor; y++) {
    220                     // Calculate the subset dimensions
    221                     uint32_t subsetWidth = width / divisor;
    222                     uint32_t subsetHeight = height / divisor;
    223                     const int left = x * subsetWidth;
    224                     const int top = y * subsetHeight;
    225 
    226                     // Increase the size of the last subset in each row or column, when the
    227                     // divisor does not divide evenly into the image dimensions
    228                     subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0;
    229                     subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0;
    230 
    231                     // Increase the size of the subset in order to have a border on each side
    232                     const int decodeLeft = left - unscaledBorder;
    233                     const int decodeTop = top - unscaledBorder;
    234                     const uint32_t decodeWidth = subsetWidth + unscaledBorder * 2;
    235                     const uint32_t decodeHeight = subsetHeight + unscaledBorder * 2;
    236                     SkBitmap bitmap;
    237                     if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(decodeLeft,
    238                             decodeTop, decodeWidth, decodeHeight), fSampleSize, colorType, false,
    239                             SkColorSpace::MakeSRGB())) {
    240                         return "Cannot decode region.";
    241                     }
    242 
    243                     alpha8_to_gray8(&bitmap);
    244                     canvas->drawBitmapRect(bitmap,
    245                             SkRect::MakeXYWH((SkScalar) scaledBorder, (SkScalar) scaledBorder,
    246                                     (SkScalar) (subsetWidth / fSampleSize),
    247                                     (SkScalar) (subsetHeight / fSampleSize)),
    248                             SkRect::MakeXYWH((SkScalar) (left / fSampleSize),
    249                                     (SkScalar) (top / fSampleSize),
    250                                     (SkScalar) (subsetWidth / fSampleSize),
    251                                     (SkScalar) (subsetHeight / fSampleSize)),
    252                             nullptr);
    253                 }
    254             }
    255             return "";
    256         }
    257         default:
    258             SkASSERT(false);
    259             return "Error: Should not be reached.";
    260     }
    261 }
    262 
    263 SkISize BRDSrc::size() const {
    264     std::unique_ptr<SkBitmapRegionDecoder> brd(create_brd(fPath));
    265     if (brd) {
    266         return {SkTMax(1, brd->width() / (int)fSampleSize),
    267                 SkTMax(1, brd->height() / (int)fSampleSize)};
    268     }
    269     return {0, 0};
    270 }
    271 
    272 static SkString get_scaled_name(const Path& path, float scale) {
    273     return SkStringPrintf("%s_%.3f", SkOSPath::Basename(path.c_str()).c_str(), scale);
    274 }
    275 
    276 Name BRDSrc::name() const {
    277     // We will replicate the names used by CodecSrc so that images can
    278     // be compared in Gold.
    279     if (1 == fSampleSize) {
    280         return SkOSPath::Basename(fPath.c_str());
    281     }
    282     return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
    283 }
    284 
    285 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    286 
    287 static bool serial_from_path_name(const SkString& path) {
    288     if (!FLAGS_RAW_threading) {
    289         static const char* const exts[] = {
    290             "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw",
    291             "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW",
    292         };
    293         const char* actualExt = strrchr(path.c_str(), '.');
    294         if (actualExt) {
    295             actualExt++;
    296             for (auto* ext : exts) {
    297                 if (0 == strcmp(ext, actualExt)) {
    298                     return true;
    299                 }
    300             }
    301         }
    302     }
    303     return false;
    304 }
    305 
    306 CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, SkAlphaType dstAlphaType,
    307                    float scale)
    308     : fPath(path)
    309     , fMode(mode)
    310     , fDstColorType(dstColorType)
    311     , fDstAlphaType(dstAlphaType)
    312     , fScale(scale)
    313     , fRunSerially(serial_from_path_name(path))
    314 {}
    315 
    316 bool CodecSrc::veto(SinkFlags flags) const {
    317     // Test to direct raster backends (8888 and 565).
    318     return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
    319 }
    320 
    321 // Allows us to test decodes to non-native 8888.
    322 static void swap_rb_if_necessary(SkBitmap& bitmap, CodecSrc::DstColorType dstColorType) {
    323     if (CodecSrc::kNonNative8888_Always_DstColorType != dstColorType) {
    324         return;
    325     }
    326 
    327     for (int y = 0; y < bitmap.height(); y++) {
    328         uint32_t* row = (uint32_t*) bitmap.getAddr(0, y);
    329         SkOpts::RGBA_to_BGRA(row, row, bitmap.width());
    330     }
    331 }
    332 
    333 // FIXME: Currently we cannot draw unpremultiplied sources. skbug.com/3338 and skbug.com/3339.
    334 // This allows us to still test unpremultiplied decodes.
    335 static void premultiply_if_necessary(SkBitmap& bitmap) {
    336     if (kUnpremul_SkAlphaType != bitmap.alphaType()) {
    337         return;
    338     }
    339 
    340     switch (bitmap.colorType()) {
    341         case kRGBA_F16_SkColorType: {
    342             SkJumper_MemoryCtx ctx = { bitmap.getAddr(0,0), bitmap.rowBytesAsPixels() };
    343             SkRasterPipeline_<256> p;
    344             p.append(SkRasterPipeline::load_f16, &ctx);
    345             p.append(SkRasterPipeline::premul);
    346             p.append(SkRasterPipeline::store_f16, &ctx);
    347             p.run(0,0, bitmap.width(), bitmap.height());
    348         }
    349             break;
    350         case kN32_SkColorType:
    351             for (int y = 0; y < bitmap.height(); y++) {
    352                 uint32_t* row = (uint32_t*) bitmap.getAddr(0, y);
    353                 SkOpts::RGBA_to_rgbA(row, row, bitmap.width());
    354             }
    355             break;
    356         default:
    357             // No need to premultiply kGray or k565 outputs.
    358             break;
    359     }
    360 
    361     // In the kIndex_8 case, the canvas won't even try to draw unless we mark the
    362     // bitmap as kPremul.
    363     bitmap.setAlphaType(kPremul_SkAlphaType);
    364 }
    365 
    366 static bool get_decode_info(SkImageInfo* decodeInfo, SkColorType canvasColorType,
    367                             CodecSrc::DstColorType dstColorType, SkAlphaType dstAlphaType) {
    368     switch (dstColorType) {
    369         case CodecSrc::kGrayscale_Always_DstColorType:
    370             if (kRGB_565_SkColorType == canvasColorType) {
    371                 return false;
    372             }
    373             *decodeInfo = decodeInfo->makeColorType(kGray_8_SkColorType);
    374             break;
    375         case CodecSrc::kNonNative8888_Always_DstColorType:
    376             if (kRGB_565_SkColorType == canvasColorType
    377                     || kRGBA_F16_SkColorType == canvasColorType) {
    378                 return false;
    379             }
    380 #ifdef SK_PMCOLOR_IS_RGBA
    381             *decodeInfo = decodeInfo->makeColorType(kBGRA_8888_SkColorType);
    382 #else
    383             *decodeInfo = decodeInfo->makeColorType(kRGBA_8888_SkColorType);
    384 #endif
    385             break;
    386         default:
    387             if (kRGB_565_SkColorType == canvasColorType &&
    388                     kOpaque_SkAlphaType != decodeInfo->alphaType()) {
    389                 return false;
    390             }
    391 
    392             if (kRGBA_F16_SkColorType == canvasColorType) {
    393                 sk_sp<SkColorSpace> linearSpace = decodeInfo->colorSpace()->makeLinearGamma();
    394                 *decodeInfo = decodeInfo->makeColorSpace(std::move(linearSpace));
    395             }
    396 
    397             *decodeInfo = decodeInfo->makeColorType(canvasColorType);
    398             break;
    399     }
    400 
    401     *decodeInfo = decodeInfo->makeAlphaType(dstAlphaType);
    402     return true;
    403 }
    404 
    405 static void draw_to_canvas(SkCanvas* canvas, const SkImageInfo& info, void* pixels, size_t rowBytes,
    406                            CodecSrc::DstColorType dstColorType,
    407                            SkScalar left = 0, SkScalar top = 0) {
    408     SkBitmap bitmap;
    409     bitmap.installPixels(info, pixels, rowBytes);
    410     premultiply_if_necessary(bitmap);
    411     swap_rb_if_necessary(bitmap, dstColorType);
    412     canvas->drawBitmap(bitmap, left, top);
    413 }
    414 
    415 // For codec srcs, we want the "draw" step to be a memcpy.  Any interesting color space or
    416 // color format conversions should be performed by the codec.  Sometimes the output of the
    417 // decode will be in an interesting color space.  On our srgb and f16 backends, we need to
    418 // "pretend" that the color space is standard sRGB to avoid triggering color conversion
    419 // at draw time.
    420 static void set_bitmap_color_space(SkImageInfo* info) {
    421     if (kRGBA_F16_SkColorType == info->colorType()) {
    422         *info = info->makeColorSpace(SkColorSpace::MakeSRGBLinear());
    423     } else {
    424         *info = info->makeColorSpace(SkColorSpace::MakeSRGB());
    425     }
    426 }
    427 
    428 Error CodecSrc::draw(SkCanvas* canvas) const {
    429     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
    430     if (!encoded) {
    431         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
    432     }
    433 
    434     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
    435     if (nullptr == codec.get()) {
    436         return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
    437     }
    438 
    439     SkImageInfo decodeInfo = codec->getInfo();
    440     if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType,
    441                          fDstAlphaType)) {
    442         return Error::Nonfatal("Skipping uninteresting test.");
    443     }
    444 
    445     // Try to scale the image if it is desired
    446     SkISize size = codec->getScaledDimensions(fScale);
    447     if (size == decodeInfo.dimensions() && 1.0f != fScale) {
    448         return Error::Nonfatal("Test without scaling is uninteresting.");
    449     }
    450 
    451     // Visually inspecting very small output images is not necessary.  We will
    452     // cover these cases in unit testing.
    453     if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) {
    454         return Error::Nonfatal("Scaling very small images is uninteresting.");
    455     }
    456     decodeInfo = decodeInfo.makeWH(size.width(), size.height());
    457 
    458     const int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType());
    459     const size_t rowBytes = size.width() * bpp;
    460     const size_t safeSize = decodeInfo.computeByteSize(rowBytes);
    461     SkAutoMalloc pixels(safeSize);
    462 
    463     SkCodec::Options options;
    464     options.fPremulBehavior = canvas->imageInfo().colorSpace() ?
    465             SkTransferFunctionBehavior::kRespect : SkTransferFunctionBehavior::kIgnore;
    466     if (kCodecZeroInit_Mode == fMode) {
    467         memset(pixels.get(), 0, size.height() * rowBytes);
    468         options.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
    469     }
    470 
    471     SkImageInfo bitmapInfo = decodeInfo;
    472     set_bitmap_color_space(&bitmapInfo);
    473     if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
    474             kBGRA_8888_SkColorType == decodeInfo.colorType()) {
    475         bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
    476     }
    477 
    478     switch (fMode) {
    479         case kAnimated_Mode: {
    480             std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo();
    481             if (frameInfos.size() <= 1) {
    482                 return SkStringPrintf("%s is not an animated image.", fPath.c_str());
    483             }
    484 
    485             // As in CodecSrc::size(), compute a roughly square grid to draw the frames
    486             // into. "factor" is the number of frames to draw on one row. There will be
    487             // up to "factor" rows as well.
    488             const float root = sqrt((float) frameInfos.size());
    489             const int factor = sk_float_ceil2int(root);
    490 
    491             // Used to cache a frame that future frames will depend on.
    492             SkAutoMalloc priorFramePixels;
    493             int cachedFrame = SkCodec::kNone;
    494             for (int i = 0; static_cast<size_t>(i) < frameInfos.size(); i++) {
    495                 options.fFrameIndex = i;
    496                 // Check for a prior frame
    497                 const int reqFrame = frameInfos[i].fRequiredFrame;
    498                 if (reqFrame != SkCodec::kNone && reqFrame == cachedFrame
    499                         && priorFramePixels.get()) {
    500                     // Copy into pixels
    501                     memcpy(pixels.get(), priorFramePixels.get(), safeSize);
    502                     options.fPriorFrame = reqFrame;
    503                 } else {
    504                     options.fPriorFrame = SkCodec::kNone;
    505                 }
    506                 SkCodec::Result result = codec->getPixels(decodeInfo, pixels.get(),
    507                                                           rowBytes, &options);
    508                 if (SkCodec::kInvalidInput == result && i > 0) {
    509                     // Some of our test images have truncated later frames. Treat that
    510                     // the same as incomplete.
    511                     result = SkCodec::kIncompleteInput;
    512                 }
    513                 switch (result) {
    514                     case SkCodec::kSuccess:
    515                     case SkCodec::kErrorInInput:
    516                     case SkCodec::kIncompleteInput: {
    517                         // If the next frame depends on this one, store it in priorFrame.
    518                         // It is possible that we may discard a frame that future frames depend on,
    519                         // but the codec will simply redecode the discarded frame.
    520                         // Do this before calling draw_to_canvas, which premultiplies in place. If
    521                         // we're decoding to unpremul, we want to pass the unmodified frame to the
    522                         // codec for decoding the next frame.
    523                         if (static_cast<size_t>(i+1) < frameInfos.size()
    524                                 && frameInfos[i+1].fRequiredFrame == i) {
    525                             memcpy(priorFramePixels.reset(safeSize), pixels.get(), safeSize);
    526                             cachedFrame = i;
    527                         }
    528 
    529                         SkAutoCanvasRestore acr(canvas, true);
    530                         const int xTranslate = (i % factor) * decodeInfo.width();
    531                         const int yTranslate = (i / factor) * decodeInfo.height();
    532                         canvas->translate(SkIntToScalar(xTranslate), SkIntToScalar(yTranslate));
    533                         draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
    534                         if (result != SkCodec::kSuccess) {
    535                             return "";
    536                         }
    537                         break;
    538                     }
    539                     case SkCodec::kInvalidConversion:
    540                         if (i > 0 && (decodeInfo.colorType() == kRGB_565_SkColorType)) {
    541                             return Error::Nonfatal(SkStringPrintf(
    542                                 "Cannot decode frame %i to 565 (%s).", i, fPath.c_str()));
    543                         }
    544                         // Fall through.
    545                     default:
    546                         return SkStringPrintf("Couldn't getPixels for frame %i in %s.",
    547                                               i, fPath.c_str());
    548                 }
    549             }
    550             break;
    551         }
    552         case kCodecZeroInit_Mode:
    553         case kCodec_Mode: {
    554             switch (codec->getPixels(decodeInfo, pixels.get(), rowBytes, &options)) {
    555                 case SkCodec::kSuccess:
    556                     // We consider these to be valid, since we should still decode what is
    557                     // available.
    558                 case SkCodec::kErrorInInput:
    559                 case SkCodec::kIncompleteInput:
    560                     break;
    561                 default:
    562                     // Everything else is considered a failure.
    563                     return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
    564             }
    565 
    566             draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
    567             break;
    568         }
    569         case kScanline_Mode: {
    570             void* dst = pixels.get();
    571             uint32_t height = decodeInfo.height();
    572             const bool useIncremental = [this]() {
    573                 auto exts = { "png", "PNG", "gif", "GIF" };
    574                 for (auto ext : exts) {
    575                     if (fPath.endsWith(ext)) {
    576                         return true;
    577                     }
    578                 }
    579                 return false;
    580             }();
    581             // ico may use the old scanline method or the new one, depending on whether it
    582             // internally holds a bmp or a png.
    583             const bool ico = fPath.endsWith("ico");
    584             bool useOldScanlineMethod = !useIncremental && !ico;
    585             if (useIncremental || ico) {
    586                 if (SkCodec::kSuccess == codec->startIncrementalDecode(decodeInfo, dst,
    587                         rowBytes, &options)) {
    588                     int rowsDecoded;
    589                     auto result = codec->incrementalDecode(&rowsDecoded);
    590                     if (SkCodec::kIncompleteInput == result || SkCodec::kErrorInInput == result) {
    591                         codec->fillIncompleteImage(decodeInfo, dst, rowBytes,
    592                                                    SkCodec::kNo_ZeroInitialized, height,
    593                                                    rowsDecoded);
    594                     }
    595                 } else {
    596                     if (useIncremental) {
    597                         // Error: These should support incremental decode.
    598                         return "Could not start incremental decode";
    599                     }
    600                     // Otherwise, this is an ICO. Since incremental failed, it must contain a BMP,
    601                     // which should work via startScanlineDecode
    602                     useOldScanlineMethod = true;
    603                 }
    604             }
    605 
    606             if (useOldScanlineMethod) {
    607                 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo)) {
    608                     return "Could not start scanline decoder";
    609                 }
    610 
    611                 switch (codec->getScanlineOrder()) {
    612                     case SkCodec::kTopDown_SkScanlineOrder:
    613                     case SkCodec::kBottomUp_SkScanlineOrder:
    614                         // We do not need to check the return value.  On an incomplete
    615                         // image, memory will be filled with a default value.
    616                         codec->getScanlines(dst, height, rowBytes);
    617                         break;
    618                 }
    619             }
    620 
    621             draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, fDstColorType);
    622             break;
    623         }
    624         case kStripe_Mode: {
    625             const int height = decodeInfo.height();
    626             // This value is chosen arbitrarily.  We exercise more cases by choosing a value that
    627             // does not align with image blocks.
    628             const int stripeHeight = 37;
    629             const int numStripes = (height + stripeHeight - 1) / stripeHeight;
    630             void* dst = pixels.get();
    631 
    632             // Decode odd stripes
    633             if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &options)) {
    634                 return "Could not start scanline decoder";
    635             }
    636 
    637             // This mode was designed to test the new skip scanlines API in libjpeg-turbo.
    638             // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting
    639             // to run this test for image types that do not have this scanline ordering.
    640             // We only run this on Jpeg, which is always kTopDown.
    641             SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder());
    642 
    643             for (int i = 0; i < numStripes; i += 2) {
    644                 // Skip a stripe
    645                 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight);
    646                 codec->skipScanlines(linesToSkip);
    647 
    648                 // Read a stripe
    649                 const int startY = (i + 1) * stripeHeight;
    650                 const int linesToRead = SkTMin(stripeHeight, height - startY);
    651                 if (linesToRead > 0) {
    652                     codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead,
    653                                         rowBytes);
    654                 }
    655             }
    656 
    657             // Decode even stripes
    658             const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo);
    659             if (SkCodec::kSuccess != startResult) {
    660                 return "Failed to restart scanline decoder with same parameters.";
    661             }
    662             for (int i = 0; i < numStripes; i += 2) {
    663                 // Read a stripe
    664                 const int startY = i * stripeHeight;
    665                 const int linesToRead = SkTMin(stripeHeight, height - startY);
    666                 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead,
    667                                     rowBytes);
    668 
    669                 // Skip a stripe
    670                 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight);
    671                 if (linesToSkip > 0) {
    672                     codec->skipScanlines(linesToSkip);
    673                 }
    674             }
    675 
    676             draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, fDstColorType);
    677             break;
    678         }
    679         case kCroppedScanline_Mode: {
    680             const int width = decodeInfo.width();
    681             const int height = decodeInfo.height();
    682             // This value is chosen because, as we move across the image, it will sometimes
    683             // align with the jpeg block sizes and it will sometimes not.  This allows us
    684             // to test interestingly different code paths in the implementation.
    685             const int tileSize = 36;
    686             SkIRect subset;
    687             for (int x = 0; x < width; x += tileSize) {
    688                 subset = SkIRect::MakeXYWH(x, 0, SkTMin(tileSize, width - x), height);
    689                 options.fSubset = &subset;
    690                 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &options)) {
    691                     return "Could not start scanline decoder.";
    692                 }
    693 
    694                 codec->getScanlines(SkTAddOffset<void>(pixels.get(), x * bpp), height, rowBytes);
    695             }
    696 
    697             draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
    698             break;
    699         }
    700         case kSubset_Mode: {
    701             // Arbitrarily choose a divisor.
    702             int divisor = 2;
    703             // Total width/height of the image.
    704             const int W = codec->getInfo().width();
    705             const int H = codec->getInfo().height();
    706             if (divisor > W || divisor > H) {
    707                 return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divisor %d is too big "
    708                                                       "for %s with dimensions (%d x %d)", divisor,
    709                                                       fPath.c_str(), W, H));
    710             }
    711             // subset dimensions
    712             // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
    713             const int w = SkAlign2(W / divisor);
    714             const int h = SkAlign2(H / divisor);
    715             SkIRect subset;
    716             options.fSubset = &subset;
    717             SkBitmap subsetBm;
    718             // We will reuse pixel memory from bitmap.
    719             void* dst = pixels.get();
    720             // Keep track of left and top (for drawing subsetBm into canvas). We could use
    721             // fScale * x and fScale * y, but we want integers such that the next subset will start
    722             // where the last one ended. So we'll add decodeInfo.width() and height().
    723             int left = 0;
    724             for (int x = 0; x < W; x += w) {
    725                 int top = 0;
    726                 for (int y = 0; y < H; y+= h) {
    727                     // Do not make the subset go off the edge of the image.
    728                     const int preScaleW = SkTMin(w, W - x);
    729                     const int preScaleH = SkTMin(h, H - y);
    730                     subset.setXYWH(x, y, preScaleW, preScaleH);
    731                     // And scale
    732                     // FIXME: Should we have a version of getScaledDimensions that takes a subset
    733                     // into account?
    734                     const int scaledW = SkTMax(1, SkScalarRoundToInt(preScaleW * fScale));
    735                     const int scaledH = SkTMax(1, SkScalarRoundToInt(preScaleH * fScale));
    736                     decodeInfo = decodeInfo.makeWH(scaledW, scaledH);
    737                     SkImageInfo subsetBitmapInfo = bitmapInfo.makeWH(scaledW, scaledH);
    738                     size_t subsetRowBytes = subsetBitmapInfo.minRowBytes();
    739                     const SkCodec::Result result = codec->getPixels(decodeInfo, dst, subsetRowBytes,
    740                             &options);
    741                     switch (result) {
    742                         case SkCodec::kSuccess:
    743                         case SkCodec::kErrorInInput:
    744                         case SkCodec::kIncompleteInput:
    745                             break;
    746                         default:
    747                             return SkStringPrintf("subset codec failed to decode (%d, %d, %d, %d) "
    748                                                   "from %s with dimensions (%d x %d)\t error %d",
    749                                                   x, y, decodeInfo.width(), decodeInfo.height(),
    750                                                   fPath.c_str(), W, H, result);
    751                     }
    752                     draw_to_canvas(canvas, subsetBitmapInfo, dst, subsetRowBytes, fDstColorType,
    753                                    SkIntToScalar(left), SkIntToScalar(top));
    754 
    755                     // translate by the scaled height.
    756                     top += decodeInfo.height();
    757                 }
    758                 // translate by the scaled width.
    759                 left += decodeInfo.width();
    760             }
    761             return "";
    762         }
    763         default:
    764             SkASSERT(false);
    765             return "Invalid fMode";
    766     }
    767     return "";
    768 }
    769 
    770 SkISize CodecSrc::size() const {
    771     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
    772     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
    773     if (nullptr == codec) {
    774         return {0, 0};
    775     }
    776 
    777     auto imageSize = codec->getScaledDimensions(fScale);
    778     if (fMode == kAnimated_Mode) {
    779         // We'll draw one of each frame, so make it big enough to hold them all
    780         // in a grid. The grid will be roughly square, with "factor" frames per
    781         // row and up to "factor" rows.
    782         const size_t count = codec->getFrameInfo().size();
    783         const float root = sqrt((float) count);
    784         const int factor = sk_float_ceil2int(root);
    785         imageSize.fWidth  = imageSize.fWidth  * factor;
    786         imageSize.fHeight = imageSize.fHeight * sk_float_ceil2int((float) count / (float) factor);
    787     }
    788     return imageSize;
    789 }
    790 
    791 Name CodecSrc::name() const {
    792     if (1.0f == fScale) {
    793         Name name = SkOSPath::Basename(fPath.c_str());
    794         if (fMode == kAnimated_Mode) {
    795             name.append("_animated");
    796         }
    797         return name;
    798     }
    799     SkASSERT(fMode != kAnimated_Mode);
    800     return get_scaled_name(fPath, fScale);
    801 }
    802 
    803 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    804 
    805 AndroidCodecSrc::AndroidCodecSrc(Path path, CodecSrc::DstColorType dstColorType,
    806         SkAlphaType dstAlphaType, int sampleSize)
    807     : fPath(path)
    808     , fDstColorType(dstColorType)
    809     , fDstAlphaType(dstAlphaType)
    810     , fSampleSize(sampleSize)
    811     , fRunSerially(serial_from_path_name(path))
    812 {}
    813 
    814 bool AndroidCodecSrc::veto(SinkFlags flags) const {
    815     // No need to test decoding to non-raster or indirect backend.
    816     return flags.type != SinkFlags::kRaster
    817         || flags.approach != SinkFlags::kDirect;
    818 }
    819 
    820 Error AndroidCodecSrc::draw(SkCanvas* canvas) const {
    821     if (canvas->imageInfo().colorSpace() &&
    822             kRGBA_F16_SkColorType != canvas->imageInfo().colorType()) {
    823         // SkAndroidCodec uses legacy premultiplication and blending.  Therefore, we only
    824         // run these tests on legacy canvases.
    825         // We allow an exception for F16, since Android uses F16.
    826         return Error::Nonfatal("Skip testing to color correct canvas.");
    827     }
    828 
    829     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
    830     if (!encoded) {
    831         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
    832     }
    833     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromData(encoded));
    834     if (nullptr == codec) {
    835         return SkStringPrintf("Couldn't create android codec for %s.", fPath.c_str());
    836     }
    837 
    838     SkImageInfo decodeInfo = codec->getInfo();
    839     if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType,
    840                          fDstAlphaType)) {
    841         return Error::Nonfatal("Skipping uninteresting test.");
    842     }
    843 
    844     // Scale the image if it is desired.
    845     SkISize size = codec->getSampledDimensions(fSampleSize);
    846 
    847     // Visually inspecting very small output images is not necessary.  We will
    848     // cover these cases in unit testing.
    849     if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) {
    850         return Error::Nonfatal("Scaling very small images is uninteresting.");
    851     }
    852     decodeInfo = decodeInfo.makeWH(size.width(), size.height());
    853 
    854     int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType());
    855     size_t rowBytes = size.width() * bpp;
    856     SkAutoMalloc pixels(size.height() * rowBytes);
    857 
    858     SkBitmap bitmap;
    859     SkImageInfo bitmapInfo = decodeInfo;
    860     set_bitmap_color_space(&bitmapInfo);
    861     if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
    862             kBGRA_8888_SkColorType == decodeInfo.colorType()) {
    863         bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
    864     }
    865 
    866     // Create options for the codec.
    867     SkAndroidCodec::AndroidOptions options;
    868     options.fSampleSize = fSampleSize;
    869 
    870     switch (codec->getAndroidPixels(decodeInfo, pixels.get(), rowBytes, &options)) {
    871         case SkCodec::kSuccess:
    872         case SkCodec::kErrorInInput:
    873         case SkCodec::kIncompleteInput:
    874             break;
    875         default:
    876             return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
    877     }
    878     draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
    879     return "";
    880 }
    881 
    882 SkISize AndroidCodecSrc::size() const {
    883     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
    884     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromData(encoded));
    885     if (nullptr == codec) {
    886         return {0, 0};
    887     }
    888     return codec->getSampledDimensions(fSampleSize);
    889 }
    890 
    891 Name AndroidCodecSrc::name() const {
    892     // We will replicate the names used by CodecSrc so that images can
    893     // be compared in Gold.
    894     if (1 == fSampleSize) {
    895         return SkOSPath::Basename(fPath.c_str());
    896     }
    897     return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
    898 }
    899 
    900 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    901 
    902 ImageGenSrc::ImageGenSrc(Path path, Mode mode, SkAlphaType alphaType, bool isGpu)
    903     : fPath(path)
    904     , fMode(mode)
    905     , fDstAlphaType(alphaType)
    906     , fIsGpu(isGpu)
    907     , fRunSerially(serial_from_path_name(path))
    908 {}
    909 
    910 bool ImageGenSrc::veto(SinkFlags flags) const {
    911     if (fIsGpu) {
    912         // MSAA runs tend to run out of memory and tests the same code paths as regular gpu configs.
    913         return flags.type != SinkFlags::kGPU || flags.approach != SinkFlags::kDirect ||
    914                flags.multisampled == SinkFlags::kMultisampled;
    915     }
    916 
    917     return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
    918 }
    919 
    920 Error ImageGenSrc::draw(SkCanvas* canvas) const {
    921     if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) {
    922         return Error::Nonfatal("Uninteresting to test image generator to 565.");
    923     }
    924 
    925     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
    926     if (!encoded) {
    927         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
    928     }
    929 
    930 #if defined(SK_BUILD_FOR_WIN)
    931     // Initialize COM in order to test with WIC.
    932     SkAutoCoInitialize com;
    933     if (!com.succeeded()) {
    934         return "Could not initialize COM.";
    935     }
    936 #endif
    937 
    938     std::unique_ptr<SkImageGenerator> gen(nullptr);
    939     switch (fMode) {
    940         case kCodec_Mode:
    941             gen = SkCodecImageGenerator::MakeFromEncodedCodec(encoded);
    942             if (!gen) {
    943                 return "Could not create codec image generator.";
    944             }
    945             break;
    946         case kPlatform_Mode: {
    947 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
    948             gen = SkImageGeneratorCG::MakeFromEncodedCG(encoded);
    949 #elif defined(SK_BUILD_FOR_WIN)
    950             gen.reset(SkImageGeneratorWIC::NewFromEncodedWIC(encoded.get()));
    951 #endif
    952 
    953             if (!gen) {
    954                 return "Could not create platform image generator.";
    955             }
    956             break;
    957         }
    958         default:
    959             SkASSERT(false);
    960             return "Invalid image generator mode";
    961     }
    962 
    963     // Test deferred decoding path on GPU
    964     if (fIsGpu) {
    965         sk_sp<SkImage> image(SkImage::MakeFromGenerator(std::move(gen), nullptr));
    966         if (!image) {
    967             return "Could not create image from codec image generator.";
    968         }
    969         canvas->drawImage(image, 0, 0);
    970         return "";
    971     }
    972 
    973     // Test various color and alpha types on CPU
    974     SkImageInfo decodeInfo = gen->getInfo().makeAlphaType(fDstAlphaType);
    975 
    976     SkImageGenerator::Options options;
    977     options.fBehavior = canvas->imageInfo().colorSpace() ?
    978             SkTransferFunctionBehavior::kRespect : SkTransferFunctionBehavior::kIgnore;
    979 
    980     int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType());
    981     size_t rowBytes = decodeInfo.width() * bpp;
    982     SkAutoMalloc pixels(decodeInfo.height() * rowBytes);
    983     if (!gen->getPixels(decodeInfo, pixels.get(), rowBytes, &options)) {
    984         SkString err =
    985                 SkStringPrintf("Image generator could not getPixels() for %s\n", fPath.c_str());
    986 
    987 #if defined(SK_BUILD_FOR_WIN)
    988         if (kPlatform_Mode == fMode) {
    989             // Do not issue a fatal error for WIC flakiness.
    990             return Error::Nonfatal(err);
    991         }
    992 #endif
    993 
    994         return err;
    995     }
    996 
    997     set_bitmap_color_space(&decodeInfo);
    998     draw_to_canvas(canvas, decodeInfo, pixels.get(), rowBytes,
    999                    CodecSrc::kGetFromCanvas_DstColorType);
   1000     return "";
   1001 }
   1002 
   1003 SkISize ImageGenSrc::size() const {
   1004     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
   1005     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
   1006     if (nullptr == codec) {
   1007         return {0, 0};
   1008     }
   1009     return codec->getInfo().dimensions();
   1010 }
   1011 
   1012 Name ImageGenSrc::name() const {
   1013     return SkOSPath::Basename(fPath.c_str());
   1014 }
   1015 
   1016 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1017 
   1018 ColorCodecSrc::ColorCodecSrc(Path path, Mode mode, SkColorType colorType)
   1019     : fPath(path)
   1020     , fMode(mode)
   1021     , fColorType(colorType)
   1022 {}
   1023 
   1024 bool ColorCodecSrc::veto(SinkFlags flags) const {
   1025     // Test to direct raster backends (8888 and 565).
   1026     return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
   1027 }
   1028 
   1029 void clamp_if_necessary(const SkBitmap& bitmap, SkColorType dstCT) {
   1030     if (kRGBA_F16_SkColorType != bitmap.colorType() || kRGBA_F16_SkColorType == dstCT) {
   1031         // No need to clamp if the dst is F16.  We will clamp when we encode to PNG.
   1032         return;
   1033     }
   1034 
   1035     SkJumper_MemoryCtx ptr = { bitmap.getAddr(0,0), bitmap.rowBytesAsPixels() };
   1036 
   1037     SkRasterPipeline_<256> p;
   1038     p.append(SkRasterPipeline::load_f16, &ptr);
   1039     p.append(SkRasterPipeline::clamp_0);
   1040     if (kPremul_SkAlphaType == bitmap.alphaType()) {
   1041         p.append(SkRasterPipeline::clamp_a);
   1042     } else {
   1043         p.append(SkRasterPipeline::clamp_1);
   1044     }
   1045     p.append(SkRasterPipeline::store_f16, &ptr);
   1046 
   1047     p.run(0,0, bitmap.width(), bitmap.height());
   1048 }
   1049 
   1050 Error ColorCodecSrc::draw(SkCanvas* canvas) const {
   1051     if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) {
   1052         return Error::Nonfatal("No need to test color correction to 565 backend.");
   1053     }
   1054 
   1055     bool runInLegacyMode = kBaseline_Mode == fMode;
   1056     if (runInLegacyMode && canvas->imageInfo().colorSpace()) {
   1057         return Error::Nonfatal("Skipping tests that are only interesting in legacy mode.");
   1058     } else if (!runInLegacyMode && !canvas->imageInfo().colorSpace()) {
   1059         return Error::Nonfatal("Skipping tests that are only interesting in srgb mode.");
   1060     }
   1061 
   1062     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
   1063     if (!encoded) {
   1064         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
   1065     }
   1066 
   1067     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
   1068     if (nullptr == codec) {
   1069         return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
   1070     }
   1071 
   1072     // Load the dst ICC profile.  This particular dst is fairly similar to Adobe RGB.
   1073     sk_sp<SkData> dstData = GetResourceAsData("icc_profiles/HP_ZR30w.icc");
   1074     if (!dstData) {
   1075         return "Cannot read monitor profile.  Is the resource path set correctly?";
   1076     }
   1077 
   1078     sk_sp<SkColorSpace> dstSpace = nullptr;
   1079     if (kDst_sRGB_Mode == fMode) {
   1080         dstSpace = SkColorSpace::MakeSRGB();
   1081     } else if (kDst_HPZR30w_Mode == fMode) {
   1082         dstSpace = SkColorSpace::MakeICC(dstData->data(), dstData->size());
   1083     }
   1084 
   1085     SkImageInfo decodeInfo = codec->getInfo().makeColorType(fColorType).makeColorSpace(dstSpace);
   1086     if (kUnpremul_SkAlphaType == decodeInfo.alphaType()) {
   1087         decodeInfo = decodeInfo.makeAlphaType(kPremul_SkAlphaType);
   1088     }
   1089     if (kRGBA_F16_SkColorType == fColorType) {
   1090         decodeInfo = decodeInfo.makeColorSpace(decodeInfo.colorSpace()->makeLinearGamma());
   1091     }
   1092 
   1093     SkImageInfo bitmapInfo = decodeInfo;
   1094     set_bitmap_color_space(&bitmapInfo);
   1095     if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
   1096         kBGRA_8888_SkColorType == decodeInfo.colorType())
   1097     {
   1098         bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
   1099     }
   1100 
   1101     SkBitmap bitmap;
   1102     if (!bitmap.tryAllocPixels(bitmapInfo)) {
   1103         return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(),
   1104                               bitmapInfo.width(), bitmapInfo.height());
   1105     }
   1106 
   1107     size_t rowBytes = bitmap.rowBytes();
   1108     SkCodec::Result r = codec->getPixels(decodeInfo, bitmap.getPixels(), rowBytes);
   1109     switch (r) {
   1110         case SkCodec::kSuccess:
   1111         case SkCodec::kErrorInInput:
   1112         case SkCodec::kIncompleteInput:
   1113             break;
   1114         default:
   1115             return SkStringPrintf("Couldn't getPixels %s. Error code %d", fPath.c_str(), r);
   1116     }
   1117 
   1118     switch (fMode) {
   1119         case kBaseline_Mode:
   1120         case kDst_sRGB_Mode:
   1121         case kDst_HPZR30w_Mode:
   1122             // We do not support drawing unclamped F16.
   1123             clamp_if_necessary(bitmap, canvas->imageInfo().colorType());
   1124             canvas->drawBitmap(bitmap, 0, 0);
   1125             break;
   1126         default:
   1127             SkASSERT(false);
   1128             return "Invalid fMode";
   1129     }
   1130     return "";
   1131 }
   1132 
   1133 SkISize ColorCodecSrc::size() const {
   1134     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
   1135     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
   1136     if (nullptr == codec) {
   1137         return {0, 0};
   1138     }
   1139     return {codec->getInfo().width(), codec->getInfo().height()};
   1140 }
   1141 
   1142 Name ColorCodecSrc::name() const {
   1143     return SkOSPath::Basename(fPath.c_str());
   1144 }
   1145 
   1146 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1147 
   1148 static const SkRect kSKPViewport = {0, 0, 1000, 1000};
   1149 
   1150 SKPSrc::SKPSrc(Path path) : fPath(path) { }
   1151 
   1152 static sk_sp<SkPicture> read_skp(const char* path) {
   1153     std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(path);
   1154     if (!stream) {
   1155         return nullptr;
   1156     }
   1157     sk_sp<SkPicture> pic(SkPicture::MakeFromStream(stream.get()));
   1158     if (!pic) {
   1159         return nullptr;
   1160     }
   1161     stream = nullptr;  // Might as well drop this when we're done with it.
   1162 
   1163     return pic;
   1164 }
   1165 
   1166 Error SKPSrc::draw(SkCanvas* canvas) const {
   1167     sk_sp<SkPicture> pic = read_skp(fPath.c_str());
   1168     if (!pic) {
   1169         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
   1170     }
   1171 
   1172     canvas->clipRect(kSKPViewport);
   1173     canvas->drawPicture(pic);
   1174     return "";
   1175 }
   1176 
   1177 static SkRect get_cull_rect_for_skp(const char* path) {
   1178     std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(path);
   1179     if (!stream) {
   1180         return SkRect::MakeEmpty();
   1181     }
   1182     SkPictInfo info;
   1183     if (!SkPicture_StreamIsSKP(stream.get(), &info)) {
   1184         return SkRect::MakeEmpty();
   1185     }
   1186 
   1187     return info.fCullRect;
   1188 }
   1189 
   1190 SkISize SKPSrc::size() const {
   1191     SkRect viewport = get_cull_rect_for_skp(fPath.c_str());
   1192     if (!viewport.intersect(kSKPViewport)) {
   1193         return {0, 0};
   1194     }
   1195     return viewport.roundOut().size();
   1196 }
   1197 
   1198 Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
   1199 
   1200 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1201 
   1202 static const int kNumDDLXTiles = 4;
   1203 static const int kNumDDLYTiles = 4;
   1204 static const int kDDLTileSize = 1024;
   1205 static const SkRect kDDLSKPViewport = { 0, 0,
   1206                                         kNumDDLXTiles * kDDLTileSize,
   1207                                         kNumDDLYTiles * kDDLTileSize };
   1208 
   1209 DDLSKPSrc::DDLSKPSrc(Path path) : fPath(path) { }
   1210 
   1211 Error DDLSKPSrc::draw(SkCanvas* canvas) const {
   1212     class TileData {
   1213     public:
   1214         // Note: we could just pass in surface characterization
   1215         TileData(sk_sp<SkSurface> surf, const SkIRect& clip)
   1216                 : fSurface(std::move(surf))
   1217                 , fClip(clip) {
   1218             SkAssertResult(fSurface->characterize(&fCharacterization));
   1219         }
   1220 
   1221         // This method operates in parallel
   1222         void preprocess(SkPicture* pic) {
   1223             SkDeferredDisplayListRecorder recorder(fCharacterization);
   1224 
   1225             SkCanvas* subCanvas = recorder.getCanvas();
   1226 
   1227             subCanvas->clipRect(SkRect::MakeWH(fClip.width(), fClip.height()));
   1228             subCanvas->translate(-fClip.fLeft, -fClip.fTop);
   1229 
   1230             // Note: in this use case we only render a picture to the deferred canvas
   1231             // but, more generally, clients will use arbitrary draw calls.
   1232             subCanvas->drawPicture(pic);
   1233 
   1234             fDisplayList = recorder.detach();
   1235         }
   1236 
   1237         // This method operates serially
   1238         void draw() {
   1239             fSurface->draw(fDisplayList.get());
   1240         }
   1241 
   1242         // This method also operates serially
   1243         void compose(SkCanvas* dst) {
   1244             sk_sp<SkImage> img = fSurface->makeImageSnapshot();
   1245             dst->save();
   1246             dst->clipRect(SkRect::Make(fClip));
   1247             dst->drawImage(std::move(img), fClip.fLeft, fClip.fTop);
   1248             dst->restore();
   1249         }
   1250 
   1251     private:
   1252         sk_sp<SkSurface> fSurface;
   1253         SkIRect          fClip;    // in the device space of the destination canvas
   1254         std::unique_ptr<SkDeferredDisplayList> fDisplayList;
   1255         SkSurfaceCharacterization              fCharacterization;
   1256     };
   1257 
   1258     SkTArray<TileData> tileData;
   1259     tileData.reserve(16);
   1260 
   1261     sk_sp<SkPicture> pic = read_skp(fPath.c_str());
   1262     if (!pic) {
   1263         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
   1264     }
   1265 
   1266     const SkRect cullRect = pic->cullRect();
   1267 
   1268     // All the destination tiles are the same size
   1269     const SkImageInfo tileII = SkImageInfo::MakeN32Premul(kDDLTileSize, kDDLTileSize);
   1270 
   1271     // First, create the destination tiles
   1272     for (int y = 0; y < kNumDDLYTiles; ++y) {
   1273         for (int x = 0; x < kNumDDLXTiles; ++x) {
   1274             SkRect clip = SkRect::MakeXYWH(x * kDDLTileSize, y * kDDLTileSize,
   1275                                            kDDLTileSize, kDDLTileSize);
   1276 
   1277             if (!clip.intersect(cullRect)) {
   1278                 continue;
   1279             }
   1280 
   1281             tileData.push_back(TileData(canvas->makeSurface(tileII), clip.roundOut()));
   1282         }
   1283     }
   1284 
   1285     // Second, run the cpu pre-processing in threads
   1286     SkTaskGroup().batch(tileData.count(), [&](int i) {
   1287         tileData[i].preprocess(pic.get());
   1288     });
   1289 
   1290     // Third, synchronously render the display lists into the dest tiles
   1291     // TODO: it would be cool to not wait until all the tiles are drawn to begin
   1292     // drawing to the GPU
   1293     for (int i = 0; i < tileData.count(); ++i) {
   1294         tileData[i].draw();
   1295     }
   1296 
   1297     // Finally, compose the drawn tiles into the result
   1298     // Note: the separation between the tiles and the final composition better
   1299     // matches Chrome but costs us a copy
   1300     for (int i = 0; i < tileData.count(); ++i) {
   1301         tileData[i].compose(canvas);
   1302     }
   1303 
   1304     return "";
   1305 }
   1306 
   1307 SkISize DDLSKPSrc::size() const {
   1308     SkRect viewport = get_cull_rect_for_skp(fPath.c_str());
   1309     if (!viewport.intersect(kDDLSKPViewport)) {
   1310         return {0, 0};
   1311     }
   1312     return viewport.roundOut().size();
   1313 }
   1314 
   1315 Name DDLSKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
   1316 
   1317 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1318 
   1319 #if !defined(SK_BUILD_FOR_GOOGLE3)
   1320 SkottieSrc::SkottieSrc(Path path)
   1321     : fName(SkOSPath::Basename(path.c_str())) {
   1322 
   1323     fAnimation  = skottie::Animation::MakeFromFile(path.c_str());
   1324     if (!fAnimation) {
   1325         return;
   1326     }
   1327 
   1328     // Fit kTileCount x kTileCount frames to a 1000x1000 film strip.
   1329     static constexpr SkScalar kTargetSize = 1000;
   1330     const auto scale = kTargetSize / (kTileCount * std::max(fAnimation->size().width(),
   1331                                                             fAnimation->size().height()));
   1332     fTileSize = SkSize::Make(scale * fAnimation->size().width(),
   1333                              scale * fAnimation->size().height()).toCeil();
   1334 
   1335 }
   1336 
   1337 Error SkottieSrc::draw(SkCanvas* canvas) const {
   1338     if (!fAnimation) {
   1339         return SkStringPrintf("Unable to parse file: %s", fName.c_str());
   1340     }
   1341 
   1342     canvas->drawColor(SK_ColorWHITE);
   1343 
   1344     SkPaint paint, clockPaint;
   1345     paint.setColor(0xffa0a0a0);
   1346     paint.setStyle(SkPaint::kStroke_Style);
   1347     paint.setStrokeWidth(1);
   1348     paint.setAntiAlias(true);
   1349 
   1350     clockPaint.setTextSize(12);
   1351     clockPaint.setAntiAlias(true);
   1352 
   1353     const auto ip = fAnimation->inPoint() * 1000 / fAnimation->frameRate(),
   1354                op = fAnimation->outPoint() * 1000 / fAnimation->frameRate(),
   1355                fr = (op - ip) / (kTileCount * kTileCount - 1);
   1356 
   1357     // Shuffled order to exercise non-linear frame progression.
   1358     static constexpr int frames[] = { 4, 0, 3, 1, 2 };
   1359     static_assert(SK_ARRAY_COUNT(frames) == kTileCount, "");
   1360 
   1361     const auto canvas_size = this->size();
   1362     for (int i = 0; i < kTileCount; ++i) {
   1363         const SkScalar y = frames[i] * (fTileSize.height() + 1);
   1364 
   1365         for (int j = 0; j < kTileCount; ++j) {
   1366             const SkScalar x = frames[j] * (fTileSize.width() + 1);
   1367             SkRect dest = SkRect::MakeXYWH(x, y, fTileSize.width(), fTileSize.height());
   1368 
   1369             const auto t = fr * (frames[i] * kTileCount + frames[j]);
   1370             {
   1371                 SkAutoCanvasRestore acr(canvas, true);
   1372                 canvas->clipRect(dest, true);
   1373                 canvas->concat(SkMatrix::MakeRectToRect(SkRect::MakeSize(fAnimation->size()),
   1374                                                         dest,
   1375                                                         SkMatrix::kFill_ScaleToFit));
   1376 
   1377                 fAnimation->animationTick(t);
   1378                 fAnimation->render(canvas);
   1379             }
   1380 
   1381             canvas->drawLine(x + fTileSize.width() + .5f, 0,
   1382                              x + fTileSize.width() + .5f, canvas_size.height(), paint);
   1383             const auto label = SkStringPrintf("%.3f", t);
   1384             canvas->drawText(label.c_str(), label.size(), dest.x(),
   1385                              dest.bottom(), clockPaint);
   1386         }
   1387 
   1388         canvas->drawLine(0                  , y + fTileSize.height() + .5f,
   1389                          canvas_size.width(), y + fTileSize.height() + .5f, paint);
   1390     }
   1391 
   1392     return "";
   1393 }
   1394 
   1395 SkISize SkottieSrc::size() const {
   1396     // Padding for grid.
   1397     return SkISize::Make(kTileCount * (fTileSize.width()  + 1),
   1398                          kTileCount * (fTileSize.height() + 1));
   1399 }
   1400 
   1401 Name SkottieSrc::name() const { return fName; }
   1402 
   1403 bool SkottieSrc::veto(SinkFlags flags) const {
   1404     // No need to test to non-(raster||gpu||vector) or indirect backends.
   1405     bool type_ok = flags.type == SinkFlags::kRaster
   1406                 || flags.type == SinkFlags::kGPU
   1407                 || flags.type == SinkFlags::kVector;
   1408 
   1409     return !type_ok || flags.approach != SinkFlags::kDirect;
   1410 }
   1411 #endif
   1412 
   1413 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1414 #if defined(SK_XML)
   1415 // Used when the image doesn't have an intrinsic size.
   1416 static const SkSize kDefaultSVGSize = {1000, 1000};
   1417 
   1418 // Used to force-scale tiny fixed-size images.
   1419 static const SkSize kMinimumSVGSize = {128, 128};
   1420 
   1421 SVGSrc::SVGSrc(Path path)
   1422     : fName(SkOSPath::Basename(path.c_str()))
   1423     , fScale(1) {
   1424 
   1425   SkFILEStream stream(path.c_str());
   1426   if (!stream.isValid()) {
   1427       return;
   1428   }
   1429   fDom = SkSVGDOM::MakeFromStream(stream);
   1430   if (!fDom) {
   1431       return;
   1432   }
   1433 
   1434   const SkSize& sz = fDom->containerSize();
   1435   if (sz.isEmpty()) {
   1436       // no intrinsic size
   1437       fDom->setContainerSize(kDefaultSVGSize);
   1438   } else {
   1439       fScale = SkTMax(1.f, SkTMax(kMinimumSVGSize.width()  / sz.width(),
   1440                                   kMinimumSVGSize.height() / sz.height()));
   1441   }
   1442 }
   1443 
   1444 Error SVGSrc::draw(SkCanvas* canvas) const {
   1445     if (!fDom) {
   1446         return SkStringPrintf("Unable to parse file: %s", fName.c_str());
   1447     }
   1448 
   1449     SkAutoCanvasRestore acr(canvas, true);
   1450     canvas->scale(fScale, fScale);
   1451     fDom->render(canvas);
   1452 
   1453     return "";
   1454 }
   1455 
   1456 SkISize SVGSrc::size() const {
   1457     if (!fDom) {
   1458         return {0, 0};
   1459     }
   1460 
   1461     return SkSize{fDom->containerSize().width() * fScale, fDom->containerSize().height() * fScale}
   1462             .toRound();
   1463 }
   1464 
   1465 Name SVGSrc::name() const { return fName; }
   1466 
   1467 bool SVGSrc::veto(SinkFlags flags) const {
   1468     // No need to test to non-(raster||gpu||vector) or indirect backends.
   1469     bool type_ok = flags.type == SinkFlags::kRaster
   1470                 || flags.type == SinkFlags::kGPU
   1471                 || flags.type == SinkFlags::kVector;
   1472 
   1473     return !type_ok || flags.approach != SinkFlags::kDirect;
   1474 }
   1475 
   1476 #endif // defined(SK_XML)
   1477 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1478 
   1479 MSKPSrc::MSKPSrc(Path path) : fPath(path) {
   1480     std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fPath.c_str());
   1481     int count = SkMultiPictureDocumentReadPageCount(stream.get());
   1482     if (count > 0) {
   1483         fPages.reset(count);
   1484         (void)SkMultiPictureDocumentReadPageSizes(stream.get(), &fPages[0], fPages.count());
   1485     }
   1486 }
   1487 
   1488 int MSKPSrc::pageCount() const { return fPages.count(); }
   1489 
   1490 SkISize MSKPSrc::size() const { return this->size(0); }
   1491 SkISize MSKPSrc::size(int i) const {
   1492     return i >= 0 && i < fPages.count() ? fPages[i].fSize.toCeil() : SkISize{0, 0};
   1493 }
   1494 
   1495 Error MSKPSrc::draw(SkCanvas* c) const { return this->draw(0, c); }
   1496 Error MSKPSrc::draw(int i, SkCanvas* canvas) const {
   1497     if (this->pageCount() == 0) {
   1498         return SkStringPrintf("Unable to parse MultiPictureDocument file: %s", fPath.c_str());
   1499     }
   1500     if (i >= fPages.count() || i < 0) {
   1501         return SkStringPrintf("MultiPictureDocument page number out of range: %d", i);
   1502     }
   1503     SkPicture* page = fPages[i].fPicture.get();
   1504     if (!page) {
   1505         std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fPath.c_str());
   1506         if (!stream) {
   1507             return SkStringPrintf("Unable to open file: %s", fPath.c_str());
   1508         }
   1509         if (!SkMultiPictureDocumentRead(stream.get(), &fPages[0], fPages.count())) {
   1510             return SkStringPrintf("SkMultiPictureDocument reader failed on page %d: %s", i,
   1511                                   fPath.c_str());
   1512         }
   1513         page = fPages[i].fPicture.get();
   1514     }
   1515     canvas->drawPicture(page);
   1516     return "";
   1517 }
   1518 
   1519 Name MSKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
   1520 
   1521 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1522 
   1523 Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const {
   1524     return src.draw(SkMakeNullCanvas().get());
   1525 }
   1526 
   1527 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1528 
   1529 static bool encode_png_base64(const SkBitmap& bitmap, SkString* dst) {
   1530     SkPixmap pm;
   1531     if (!bitmap.peekPixels(&pm)) {
   1532         dst->set("peekPixels failed");
   1533         return false;
   1534     }
   1535 
   1536     // We're going to embed this PNG in a data URI, so make it as small as possible
   1537     SkPngEncoder::Options options;
   1538     options.fFilterFlags = SkPngEncoder::FilterFlag::kAll;
   1539     options.fZLibLevel = 9;
   1540     options.fUnpremulBehavior = pm.colorSpace() ? SkTransferFunctionBehavior::kRespect
   1541                                                 : SkTransferFunctionBehavior::kIgnore;
   1542 
   1543     SkDynamicMemoryWStream wStream;
   1544     if (!SkPngEncoder::Encode(&wStream, pm, options)) {
   1545         dst->set("SkPngEncoder::Encode failed");
   1546         return false;
   1547     }
   1548 
   1549     sk_sp<SkData> pngData = wStream.detachAsData();
   1550     size_t len = SkBase64::Encode(pngData->data(), pngData->size(), nullptr);
   1551 
   1552     // The PNG can be almost arbitrarily large. We don't want to fill our logs with enormous URLs.
   1553     // Infra says these can be pretty big, as long as we're only outputting them on failure.
   1554     static const size_t kMaxBase64Length = 1024 * 1024;
   1555     if (len > kMaxBase64Length) {
   1556         dst->printf("Encoded image too large (%u bytes)", static_cast<uint32_t>(len));
   1557         return false;
   1558     }
   1559 
   1560     dst->resize(len);
   1561     SkBase64::Encode(pngData->data(), pngData->size(), dst->writable_str());
   1562     return true;
   1563 }
   1564 
   1565 static Error compare_bitmaps(const SkBitmap& reference, const SkBitmap& bitmap) {
   1566     // The dimensions are a property of the Src only, and so should be identical.
   1567     SkASSERT(reference.computeByteSize() == bitmap.computeByteSize());
   1568     if (reference.computeByteSize() != bitmap.computeByteSize()) {
   1569         return "Dimensions don't match reference";
   1570     }
   1571     // All SkBitmaps in DM are tight, so this comparison is easy.
   1572     if (0 != memcmp(reference.getPixels(), bitmap.getPixels(), reference.computeByteSize())) {
   1573         SkString encoded;
   1574         SkString errString("Pixels don't match reference");
   1575         if (encode_png_base64(reference, &encoded)) {
   1576             errString.append("\nExpected: data:image/png;base64,");
   1577             errString.append(encoded);
   1578         } else {
   1579             errString.append("\nExpected image failed to encode: ");
   1580             errString.append(encoded);
   1581         }
   1582         if (encode_png_base64(bitmap, &encoded)) {
   1583             errString.append("\nActual: data:image/png;base64,");
   1584             errString.append(encoded);
   1585         } else {
   1586             errString.append("\nActual image failed to encode: ");
   1587             errString.append(encoded);
   1588         }
   1589         return errString;
   1590     }
   1591     return "";
   1592 }
   1593 
   1594 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1595 
   1596 DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?");
   1597 
   1598 GPUSink::GPUSink(GrContextFactory::ContextType ct,
   1599                  GrContextFactory::ContextOverrides overrides,
   1600                  int samples,
   1601                  bool diText,
   1602                  SkColorType colorType,
   1603                  SkAlphaType alphaType,
   1604                  sk_sp<SkColorSpace> colorSpace,
   1605                  bool threaded,
   1606                  const GrContextOptions& grCtxOptions)
   1607         : fContextType(ct)
   1608         , fContextOverrides(overrides)
   1609         , fSampleCount(samples)
   1610         , fUseDIText(diText)
   1611         , fColorType(colorType)
   1612         , fAlphaType(alphaType)
   1613         , fColorSpace(std::move(colorSpace))
   1614         , fThreaded(threaded)
   1615         , fBaseContextOptions(grCtxOptions) {}
   1616 
   1617 DEFINE_bool(drawOpClip, false, "Clip each GrDrawOp to its device bounds for testing.");
   1618 
   1619 Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream* dstStream, SkString* log) const {
   1620     return this->onDraw(src, dst, dstStream, log, fBaseContextOptions);
   1621 }
   1622 
   1623 Error GPUSink::onDraw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log,
   1624                       const GrContextOptions& baseOptions) const {
   1625     GrContextOptions grOptions = baseOptions;
   1626 
   1627     src.modifyGrContextOptions(&grOptions);
   1628 
   1629     GrContextFactory factory(grOptions);
   1630     const SkISize size = src.size();
   1631     SkImageInfo info =
   1632             SkImageInfo::Make(size.width(), size.height(), fColorType, fAlphaType, fColorSpace);
   1633 #if SK_SUPPORT_GPU
   1634     GrContext* context = factory.getContextInfo(fContextType, fContextOverrides).grContext();
   1635     const int maxDimension = context->caps()->maxTextureSize();
   1636     if (maxDimension < SkTMax(size.width(), size.height())) {
   1637         return Error::Nonfatal("Src too large to create a texture.\n");
   1638     }
   1639 #endif
   1640 
   1641     auto surface(
   1642         NewGpuSurface(&factory, fContextType, fContextOverrides, info, fSampleCount, fUseDIText));
   1643     if (!surface) {
   1644         return "Could not create a surface.";
   1645     }
   1646     if (FLAGS_preAbandonGpuContext) {
   1647         factory.abandonContexts();
   1648     }
   1649     SkCanvas* canvas = surface->getCanvas();
   1650     Error err = src.draw(canvas);
   1651     if (!err.isEmpty()) {
   1652         return err;
   1653     }
   1654     canvas->flush();
   1655     if (FLAGS_gpuStats) {
   1656         canvas->getGrContext()->dumpCacheStats(log);
   1657         canvas->getGrContext()->dumpGpuStats(log);
   1658     }
   1659     if (info.colorType() == kRGB_565_SkColorType || info.colorType() == kARGB_4444_SkColorType) {
   1660         // We don't currently support readbacks into these formats on the GPU backend. Convert to
   1661         // 32 bit.
   1662         info = SkImageInfo::Make(size.width(), size.height(), kRGBA_8888_SkColorType,
   1663                                  kPremul_SkAlphaType, fColorSpace);
   1664     }
   1665     dst->allocPixels(info);
   1666     canvas->readPixels(*dst, 0, 0);
   1667     if (FLAGS_abandonGpuContext) {
   1668         factory.abandonContexts();
   1669     } else if (FLAGS_releaseAndAbandonGpuContext) {
   1670         factory.releaseResourcesAndAbandonContexts();
   1671     }
   1672     return "";
   1673 }
   1674 
   1675 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1676 
   1677 GPUThreadTestingSink::GPUThreadTestingSink(GrContextFactory::ContextType ct,
   1678                                            GrContextFactory::ContextOverrides overrides,
   1679                                            int samples,
   1680                                            bool diText,
   1681                                            SkColorType colorType,
   1682                                            SkAlphaType alphaType,
   1683                                            sk_sp<SkColorSpace> colorSpace,
   1684                                            bool threaded,
   1685                                            const GrContextOptions& grCtxOptions)
   1686         : INHERITED(ct, overrides, samples, diText, colorType, alphaType, std::move(colorSpace),
   1687                     threaded, grCtxOptions)
   1688 #if SK_SUPPORT_GPU
   1689         , fExecutor(SkExecutor::MakeFIFOThreadPool(FLAGS_gpuThreads)) {
   1690 #else
   1691         , fExecutor(nullptr) {
   1692 #endif
   1693     SkASSERT(fExecutor);
   1694 }
   1695 
   1696 Error GPUThreadTestingSink::draw(const Src& src, SkBitmap* dst, SkWStream* wStream,
   1697                                  SkString* log) const {
   1698     // Draw twice, once with worker threads, and once without. Verify that we get the same result.
   1699     // Also, force us to only use the software path renderer, so we really stress-test the threaded
   1700     // version of that code.
   1701     GrContextOptions contextOptions = this->baseContextOptions();
   1702     contextOptions.fGpuPathRenderers = GpuPathRenderers::kNone;
   1703 
   1704     contextOptions.fExecutor = fExecutor.get();
   1705     Error err = this->onDraw(src, dst, wStream, log, contextOptions);
   1706     if (!err.isEmpty() || !dst) {
   1707         return err;
   1708     }
   1709 
   1710     SkBitmap reference;
   1711     SkString refLog;
   1712     SkDynamicMemoryWStream refStream;
   1713     contextOptions.fExecutor = nullptr;
   1714     Error refErr = this->onDraw(src, &reference, &refStream, &refLog, contextOptions);
   1715     if (!refErr.isEmpty()) {
   1716         return refErr;
   1717     }
   1718 
   1719     return compare_bitmaps(reference, *dst);
   1720 }
   1721 
   1722 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1723 
   1724 static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) {
   1725     if (src.size().isEmpty()) {
   1726         return "Source has empty dimensions";
   1727     }
   1728     SkASSERT(doc);
   1729     int pageCount = src.pageCount();
   1730     for (int i = 0; i < pageCount; ++i) {
   1731         int width = src.size(i).width(), height = src.size(i).height();
   1732         SkCanvas* canvas =
   1733                 doc->beginPage(SkIntToScalar(width), SkIntToScalar(height));
   1734         if (!canvas) {
   1735             return "SkDocument::beginPage(w,h) returned nullptr";
   1736         }
   1737         Error err = src.draw(i, canvas);
   1738         if (!err.isEmpty()) {
   1739             return err;
   1740         }
   1741         doc->endPage();
   1742     }
   1743     doc->close();
   1744     dst->flush();
   1745     return "";
   1746 }
   1747 
   1748 Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
   1749     SkDocument::PDFMetadata metadata;
   1750     metadata.fTitle = src.name();
   1751     metadata.fSubject = "rendering correctness test";
   1752     metadata.fCreator = "Skia/DM";
   1753     metadata.fRasterDPI = fRasterDpi;
   1754     metadata.fPDFA = fPDFA;
   1755     sk_sp<SkDocument> doc = SkDocument::MakePDF(dst, metadata);
   1756     if (!doc) {
   1757         return "SkDocument::MakePDF() returned nullptr";
   1758     }
   1759     return draw_skdocument(src, doc.get(), dst);
   1760 }
   1761 
   1762 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1763 
   1764 XPSSink::XPSSink() {}
   1765 
   1766 #ifdef SK_BUILD_FOR_WIN
   1767 static SkTScopedComPtr<IXpsOMObjectFactory> make_xps_factory() {
   1768     IXpsOMObjectFactory* factory;
   1769     HRN(CoCreateInstance(CLSID_XpsOMObjectFactory,
   1770                          nullptr,
   1771                          CLSCTX_INPROC_SERVER,
   1772                          IID_PPV_ARGS(&factory)));
   1773     return SkTScopedComPtr<IXpsOMObjectFactory>(factory);
   1774 }
   1775 
   1776 Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
   1777     SkAutoCoInitialize com;
   1778     if (!com.succeeded()) {
   1779         return "Could not initialize COM.";
   1780     }
   1781     SkTScopedComPtr<IXpsOMObjectFactory> factory = make_xps_factory();
   1782     if (!factory) {
   1783         return "Failed to create XPS Factory.";
   1784     }
   1785     sk_sp<SkDocument> doc(SkDocument::MakeXPS(dst, factory.get()));
   1786     if (!doc) {
   1787         return "SkDocument::MakeXPS() returned nullptr";
   1788     }
   1789     return draw_skdocument(src, doc.get(), dst);
   1790 }
   1791 #else
   1792 Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
   1793     return "XPS not supported on this platform.";
   1794 }
   1795 #endif
   1796 
   1797 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1798 
   1799 PipeSink::PipeSink() {}
   1800 
   1801 Error PipeSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
   1802     return src.draw(SkPipeSerializer().beginWrite(SkRect::Make(src.size()), dst));
   1803 }
   1804 
   1805 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1806 
   1807 SKPSink::SKPSink() {}
   1808 
   1809 Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
   1810     SkSize size;
   1811     size = src.size();
   1812     SkPictureRecorder recorder;
   1813     Error err = src.draw(recorder.beginRecording(size.width(), size.height()));
   1814     if (!err.isEmpty()) {
   1815         return err;
   1816     }
   1817     recorder.finishRecordingAsPicture()->serialize(dst);
   1818     return "";
   1819 }
   1820 
   1821 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1822 
   1823 Error DebugSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
   1824     SkDebugCanvas debugCanvas(src.size().width(), src.size().height());
   1825     Error err = src.draw(&debugCanvas);
   1826     if (!err.isEmpty()) {
   1827         return err;
   1828     }
   1829     std::unique_ptr<SkCanvas> nullCanvas = SkMakeNullCanvas();
   1830     UrlDataManager dataManager(SkString("data"));
   1831     Json::Value json = debugCanvas.toJSON(
   1832             dataManager, debugCanvas.getSize(), nullCanvas.get());
   1833     std::string value = Json::StyledWriter().write(json);
   1834     return dst->write(value.c_str(), value.size()) ? "" : "SkWStream Error";
   1835 }
   1836 
   1837 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1838 
   1839 SVGSink::SVGSink() {}
   1840 
   1841 Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
   1842 #if defined(SK_XML)
   1843     std::unique_ptr<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(dst));
   1844     return src.draw(SkSVGCanvas::Make(SkRect::MakeWH(SkIntToScalar(src.size().width()),
   1845                                                      SkIntToScalar(src.size().height())),
   1846                                       xmlWriter.get()).get());
   1847 #else
   1848     return Error("SVG sink is disabled.");
   1849 #endif // SK_XML
   1850 }
   1851 
   1852 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1853 
   1854 RasterSink::RasterSink(SkColorType colorType, sk_sp<SkColorSpace> colorSpace)
   1855     : fColorType(colorType)
   1856     , fColorSpace(std::move(colorSpace)) {}
   1857 
   1858 Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
   1859     const SkISize size = src.size();
   1860     // If there's an appropriate alpha type for this color type, use it, otherwise use premul.
   1861     SkAlphaType alphaType = kPremul_SkAlphaType;
   1862     (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType);
   1863 
   1864     dst->allocPixelsFlags(SkImageInfo::Make(size.width(), size.height(),
   1865                                             fColorType, alphaType, fColorSpace),
   1866                           SkBitmap::kZeroPixels_AllocFlag);
   1867     SkCanvas canvas(*dst);
   1868     return src.draw(&canvas);
   1869 }
   1870 
   1871 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1872 
   1873 // Handy for front-patching a Src.  Do whatever up-front work you need, then call draw_to_canvas(),
   1874 // passing the Sink draw() arguments, a size, and a function draws into an SkCanvas.
   1875 // Several examples below.
   1876 
   1877 template <typename Fn>
   1878 static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log,
   1879                             SkISize size, const Fn& draw) {
   1880     class ProxySrc : public Src {
   1881     public:
   1882         ProxySrc(SkISize size, const Fn& draw) : fSize(size), fDraw(draw) {}
   1883         Error   draw(SkCanvas* canvas) const override { return fDraw(canvas); }
   1884         Name    name() const override { return "ProxySrc"; }
   1885         SkISize size() const override { return fSize; }
   1886     private:
   1887         SkISize   fSize;
   1888         const Fn& fDraw;
   1889     };
   1890     return sink->draw(ProxySrc(size, draw), bitmap, stream, log);
   1891 }
   1892 
   1893 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1894 
   1895 DEFINE_bool(check, true, "If true, have most Via- modes fail if they affect the output.");
   1896 
   1897 // Is *bitmap identical to what you get drawing src into sink?
   1898 static Error check_against_reference(const SkBitmap* bitmap, const Src& src, Sink* sink) {
   1899     // We can only check raster outputs.
   1900     // (Non-raster outputs like .pdf, .skp, .svg may differ but still draw identically.)
   1901     if (FLAGS_check && bitmap) {
   1902         SkBitmap reference;
   1903         SkString log;
   1904         SkDynamicMemoryWStream wStream;
   1905         Error err = sink->draw(src, &reference, &wStream, &log);
   1906         // If we can draw into this Sink via some pipeline, we should be able to draw directly.
   1907         SkASSERT(err.isEmpty());
   1908         if (!err.isEmpty()) {
   1909             return err;
   1910         }
   1911         return compare_bitmaps(reference, *bitmap);
   1912     }
   1913     return "";
   1914 }
   1915 
   1916 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1917 
   1918 static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) {
   1919     SkRect bounds = SkRect::MakeIWH(srcW, srcH);
   1920     matrix->mapRect(&bounds);
   1921     matrix->postTranslate(-bounds.x(), -bounds.y());
   1922     return {SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height())};
   1923 }
   1924 
   1925 ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
   1926 
   1927 Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
   1928     SkMatrix matrix = fMatrix;
   1929     SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height());
   1930     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) {
   1931         canvas->concat(matrix);
   1932         return src.draw(canvas);
   1933     });
   1934 }
   1935 
   1936 // Undoes any flip or 90 degree rotate without changing the scale of the bitmap.
   1937 // This should be pixel-preserving.
   1938 ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
   1939 
   1940 Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
   1941     Error err = fSink->draw(src, bitmap, stream, log);
   1942     if (!err.isEmpty()) {
   1943         return err;
   1944     }
   1945 
   1946     SkMatrix inverse;
   1947     if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) {
   1948         return "Cannot upright --matrix.";
   1949     }
   1950     SkMatrix upright = SkMatrix::I();
   1951     upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX()));
   1952     upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY()));
   1953     upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX()));
   1954     upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY()));
   1955 
   1956     SkBitmap uprighted;
   1957     SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height());
   1958     uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height()));
   1959 
   1960     SkCanvas canvas(uprighted);
   1961     canvas.concat(upright);
   1962     SkPaint paint;
   1963     paint.setBlendMode(SkBlendMode::kSrc);
   1964     canvas.drawBitmap(*bitmap, 0, 0, &paint);
   1965 
   1966     *bitmap = uprighted;
   1967     return "";
   1968 }
   1969 
   1970 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1971 
   1972 Error ViaSerialization::draw(
   1973         const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
   1974     // Record our Src into a picture.
   1975     auto size = src.size();
   1976     SkPictureRecorder recorder;
   1977     Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
   1978                                                  SkIntToScalar(size.height())));
   1979     if (!err.isEmpty()) {
   1980         return err;
   1981     }
   1982     sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture());
   1983 
   1984     // Serialize it and then deserialize it.
   1985     sk_sp<SkPicture> deserialized(SkPicture::MakeFromData(pic->serialize().get()));
   1986 
   1987     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) {
   1988         canvas->drawPicture(deserialized);
   1989         return check_against_reference(bitmap, src, fSink.get());
   1990     });
   1991 }
   1992 
   1993 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   1994 
   1995 ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink)
   1996     : Via(sink)
   1997     , fW(w)
   1998     , fH(h)
   1999     , fFactory(factory) {}
   2000 
   2001 Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
   2002     auto size = src.size();
   2003     SkPictureRecorder recorder;
   2004     Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
   2005                                                  SkIntToScalar(size.height()),
   2006                                                  fFactory.get()));
   2007     if (!err.isEmpty()) {
   2008         return err;
   2009     }
   2010     sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture());
   2011 
   2012     return draw_to_canvas(fSink.get(), bitmap, stream, log, src.size(), [&](SkCanvas* canvas) {
   2013         const int xTiles = (size.width()  + fW - 1) / fW,
   2014                   yTiles = (size.height() + fH - 1) / fH;
   2015         SkMultiPictureDraw mpd(xTiles*yTiles);
   2016         SkTArray<sk_sp<SkSurface>> surfaces;
   2017 //        surfaces.setReserve(xTiles*yTiles);
   2018 
   2019         SkImageInfo info = canvas->imageInfo().makeWH(fW, fH);
   2020         for (int j = 0; j < yTiles; j++) {
   2021             for (int i = 0; i < xTiles; i++) {
   2022                 // This lets our ultimate Sink determine the best kind of surface.
   2023                 // E.g., if it's a GpuSink, the surfaces and images are textures.
   2024                 auto s = canvas->makeSurface(info);
   2025                 if (!s) {
   2026                     s = SkSurface::MakeRaster(info);  // Some canvases can't create surfaces.
   2027                 }
   2028                 surfaces.push_back(s);
   2029                 SkCanvas* c = s->getCanvas();
   2030                 c->translate(SkIntToScalar(-i * fW),
   2031                              SkIntToScalar(-j * fH));  // Line up the canvas with this tile.
   2032                 mpd.add(c, pic.get());
   2033             }
   2034         }
   2035         mpd.draw();
   2036         for (int j = 0; j < yTiles; j++) {
   2037             for (int i = 0; i < xTiles; i++) {
   2038                 sk_sp<SkImage> image(surfaces[i+xTiles*j]->makeImageSnapshot());
   2039                 canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH));
   2040             }
   2041         }
   2042         return "";
   2043     });
   2044 }
   2045 
   2046 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   2047 
   2048 Error ViaPicture::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
   2049     auto size = src.size();
   2050     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
   2051         SkPictureRecorder recorder;
   2052         sk_sp<SkPicture> pic;
   2053         Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
   2054                                                      SkIntToScalar(size.height())));
   2055         if (!err.isEmpty()) {
   2056             return err;
   2057         }
   2058         pic = recorder.finishRecordingAsPicture();
   2059         canvas->drawPicture(pic);
   2060         return check_against_reference(bitmap, src, fSink.get());
   2061     });
   2062 }
   2063 
   2064 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   2065 
   2066 Error ViaPipe::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
   2067     auto size = src.size();
   2068     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
   2069         SkDynamicMemoryWStream tmpStream;
   2070         Error err = src.draw(SkPipeSerializer().beginWrite(SkRect::Make(size), &tmpStream));
   2071         if (!err.isEmpty()) {
   2072             return err;
   2073         }
   2074         sk_sp<SkData> data = tmpStream.detachAsData();
   2075         SkPipeDeserializer().playback(data->data(), data->size(), canvas);
   2076         return check_against_reference(bitmap, src, fSink.get());
   2077     });
   2078 }
   2079 
   2080 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   2081 
   2082 #ifdef TEST_VIA_SVG
   2083 #include "SkXMLWriter.h"
   2084 #include "SkSVGCanvas.h"
   2085 #include "SkSVGDOM.h"
   2086 
   2087 Error ViaSVG::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
   2088     auto size = src.size();
   2089     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
   2090         SkDynamicMemoryWStream wstream;
   2091         SkXMLStreamWriter writer(&wstream);
   2092         Error err = src.draw(SkSVGCanvas::Make(SkRect::Make(size), &writer).get());
   2093         if (!err.isEmpty()) {
   2094             return err;
   2095         }
   2096         std::unique_ptr<SkStream> rstream(wstream.detachAsStream());
   2097         auto dom = SkSVGDOM::MakeFromStream(*rstream);
   2098         if (dom) {
   2099             dom->setContainerSize(SkSize::Make(size));
   2100             dom->render(canvas);
   2101         }
   2102         return "";
   2103     });
   2104 }
   2105 #endif
   2106 
   2107 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   2108 
   2109 Error ViaLite::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
   2110     auto size = src.size();
   2111     SkIRect bounds = {0,0, size.width(), size.height()};
   2112     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
   2113         SkLiteDL dl;
   2114         SkLiteRecorder rec;
   2115         rec.reset(&dl, bounds);
   2116 
   2117         Error err = src.draw(&rec);
   2118         if (!err.isEmpty()) {
   2119             return err;
   2120         }
   2121         dl.draw(canvas);
   2122         return check_against_reference(bitmap, src, fSink.get());
   2123     });
   2124 }
   2125 
   2126 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
   2127 
   2128 ViaCSXform::ViaCSXform(Sink* sink, sk_sp<SkColorSpace> cs, bool colorSpin)
   2129     : Via(sink)
   2130     , fCS(std::move(cs))
   2131     , fColorSpin(colorSpin) {}
   2132 
   2133 Error ViaCSXform::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
   2134     return draw_to_canvas(fSink.get(), bitmap, stream, log, src.size(),
   2135                           [&](SkCanvas* canvas) -> Error {
   2136         {
   2137             SkAutoCanvasRestore acr(canvas, true);
   2138             auto proxy = SkCreateColorSpaceXformCanvas(canvas, fCS);
   2139             Error err = src.draw(proxy.get());
   2140             if (!err.isEmpty()) {
   2141                 return err;
   2142             }
   2143         }
   2144 
   2145         // Undo the color spin, so we can look at the pixels in Gold.
   2146         if (fColorSpin) {
   2147             SkBitmap pixels;
   2148             pixels.allocPixels(canvas->imageInfo());
   2149             canvas->readPixels(pixels, 0, 0);
   2150 
   2151             SkPaint rotateColors;
   2152             SkScalar matrix[20] = { 0, 0, 1, 0, 0,   // B -> R
   2153                                     1, 0, 0, 0, 0,   // R -> G
   2154                                     0, 1, 0, 0, 0,   // G -> B
   2155                                     0, 0, 0, 1, 0 };
   2156             rotateColors.setBlendMode(SkBlendMode::kSrc);
   2157             rotateColors.setColorFilter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
   2158             canvas->drawBitmap(pixels, 0, 0, &rotateColors);
   2159         }
   2160 
   2161         return "";
   2162     });
   2163 }
   2164 
   2165 }  // namespace DM
   2166