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