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