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