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