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