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