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