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