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