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