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