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