DMSrcSink.cpp revision b157917507d4f7d2651f0aeb566d31603cc02240
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 "SkCodec.h"
11#include "SkCommonFlags.h"
12#include "SkData.h"
13#include "SkDeferredCanvas.h"
14#include "SkDocument.h"
15#include "SkError.h"
16#include "SkFunction.h"
17#include "SkImageGenerator.h"
18#include "SkMultiPictureDraw.h"
19#include "SkNullCanvas.h"
20#include "SkOSFile.h"
21#include "SkPictureData.h"
22#include "SkPictureRecorder.h"
23#include "SkRandom.h"
24#include "SkRecordDraw.h"
25#include "SkRecorder.h"
26#include "SkSVGCanvas.h"
27#include "SkScanlineDecoder.h"
28#include "SkStream.h"
29#include "SkXMLWriter.h"
30#include "SkScaledCodec.h"
31
32DEFINE_bool(multiPage, false, "For document-type backends, render the source"
33            " into multiple pages");
34
35static bool lazy_decode_bitmap(const void* src, size_t size, SkBitmap* dst) {
36    SkAutoTUnref<SkData> encoded(SkData::NewWithCopy(src, size));
37    return encoded && SkInstallDiscardablePixelRef(encoded, dst);
38}
39
40namespace DM {
41
42GMSrc::GMSrc(skiagm::GMRegistry::Factory factory) : fFactory(factory) {}
43
44Error GMSrc::draw(SkCanvas* canvas) const {
45    SkAutoTDelete<skiagm::GM> gm(fFactory(NULL));
46    canvas->concat(gm->getInitialTransform());
47    gm->draw(canvas);
48    return "";
49}
50
51SkISize GMSrc::size() const {
52    SkAutoTDelete<skiagm::GM> gm(fFactory(NULL));
53    return gm->getISize();
54}
55
56Name GMSrc::name() const {
57    SkAutoTDelete<skiagm::GM> gm(fFactory(NULL));
58    return gm->getName();
59}
60
61void GMSrc::modifyGrContextOptions(GrContextOptions* options) const {
62    SkAutoTDelete<skiagm::GM> gm(fFactory(NULL));
63    gm->modifyGrContextOptions(options);
64}
65
66/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
67
68CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, float scale)
69    : fPath(path)
70    , fMode(mode)
71    , fDstColorType(dstColorType)
72    , fScale(scale)
73{}
74
75bool CodecSrc::veto(SinkFlags flags) const {
76    // No need to test decoding to non-raster or indirect backend.
77    // TODO: Once we implement GPU paths (e.g. JPEG YUV), we should use a deferred decode to
78    // let the GPU handle it.
79    return flags.type != SinkFlags::kRaster
80        || flags.approach != SinkFlags::kDirect;
81}
82
83Error CodecSrc::draw(SkCanvas* canvas) const {
84    SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
85    if (!encoded) {
86        return SkStringPrintf("Couldn't read %s.", fPath.c_str());
87    }
88    SkAutoTDelete<SkCodec> codec(SkScaledCodec::NewFromData(encoded));
89    if (NULL == codec.get()) {
90        // scaledCodec not supported, try normal codec
91        codec.reset(SkCodec::NewFromData(encoded));
92        if (NULL == codec.get()) {
93            return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
94        }
95    }
96
97    // Choose the color type to decode to
98    SkImageInfo decodeInfo = codec->getInfo();
99    SkColorType canvasColorType = canvas->imageInfo().colorType();
100    switch (fDstColorType) {
101        case kIndex8_Always_DstColorType:
102            decodeInfo = codec->getInfo().makeColorType(kIndex_8_SkColorType);
103            if (kRGB_565_SkColorType == canvasColorType) {
104                return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
105            }
106            break;
107        case kGrayscale_Always_DstColorType:
108            decodeInfo = codec->getInfo().makeColorType(kGray_8_SkColorType);
109            if (kRGB_565_SkColorType == canvasColorType) {
110                return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
111            }
112            break;
113        default:
114            decodeInfo = decodeInfo.makeColorType(canvasColorType);
115            break;
116    }
117
118    // Try to scale the image if it is desired
119    SkISize size = codec->getScaledDimensions(fScale);
120    if (size == decodeInfo.dimensions() && 1.0f != fScale) {
121        return Error::Nonfatal("Test without scaling is uninteresting.");
122    }
123    decodeInfo = decodeInfo.makeWH(size.width(), size.height());
124
125    // Construct a color table for the decode if necessary
126    SkAutoTUnref<SkColorTable> colorTable(NULL);
127    SkPMColor* colorPtr = NULL;
128    int* colorCountPtr = NULL;
129    int maxColors = 256;
130    if (kIndex_8_SkColorType == decodeInfo.colorType()) {
131        SkPMColor colors[256];
132        colorTable.reset(SkNEW_ARGS(SkColorTable, (colors, maxColors)));
133        colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
134        colorCountPtr = &maxColors;
135    }
136
137    // FIXME: Currently we cannot draw unpremultiplied sources.
138    if (decodeInfo.alphaType() == kUnpremul_SkAlphaType) {
139        decodeInfo = decodeInfo.makeAlphaType(kPremul_SkAlphaType);
140    }
141
142    SkBitmap bitmap;
143    if (!bitmap.tryAllocPixels(decodeInfo, NULL, colorTable.get())) {
144        return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str(),
145                              decodeInfo.width(), decodeInfo.height());
146    }
147
148    switch (fMode) {
149        case kNormal_Mode: {
150            switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(), NULL,
151                    colorPtr, colorCountPtr)) {
152                case SkCodec::kSuccess:
153                    // We consider incomplete to be valid, since we should still decode what is
154                    // available.
155                case SkCodec::kIncompleteInput:
156                    break;
157                case SkCodec::kInvalidConversion:
158                    return Error::Nonfatal("Incompatible colortype conversion");
159                default:
160                    // Everything else is considered a failure.
161                    return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
162            }
163            canvas->drawBitmap(bitmap, 0, 0);
164            break;
165        }
166        case kScanline_Mode: {
167            SkAutoTDelete<SkScanlineDecoder> scanlineDecoder(
168                    SkScanlineDecoder::NewFromData(encoded));
169            if (NULL == scanlineDecoder || SkCodec::kSuccess !=
170                    scanlineDecoder->start(decodeInfo, NULL, colorPtr, colorCountPtr)) {
171                return Error::Nonfatal("Cannot use scanline decoder for all images");
172            }
173
174            const SkCodec::Result result = scanlineDecoder->getScanlines(
175                    bitmap.getAddr(0, 0), decodeInfo.height(), bitmap.rowBytes());
176            switch (result) {
177                case SkCodec::kSuccess:
178                case SkCodec::kIncompleteInput:
179                    break;
180                default:
181                    return SkStringPrintf("%s failed with error message %d",
182                                          fPath.c_str(), (int) result);
183            }
184            canvas->drawBitmap(bitmap, 0, 0);
185            break;
186        }
187        case kScanline_Subset_Mode: {
188            //this mode decodes the image in divisor*divisor subsets, using a scanline decoder
189            const int divisor = 2;
190            const int w = decodeInfo.width();
191            const int h = decodeInfo.height();
192            if (divisor > w || divisor > h) {
193                return Error::Nonfatal(SkStringPrintf("Cannot decode subset: divisor %d is too big"
194                        "for %s with dimensions (%d x %d)", divisor, fPath.c_str(), w, h));
195            }
196            const int subsetWidth = w/divisor;
197            const int subsetHeight = h/divisor;
198            // One of our subsets will be larger to contain any pixels that do not divide evenly.
199            const int extraX = w % divisor;
200            const int extraY = h % divisor;
201            /*
202            * if w or h are not evenly divided by divisor need to adjust width and height of end
203            * subsets to cover entire image.
204            * Add extraX and extraY to largestSubsetBm's width and height to adjust width
205            * and height of end subsets.
206            * subsetBm is extracted from largestSubsetBm.
207            * subsetBm's size is determined based on the current subset and may be larger for end
208            * subsets.
209            */
210            SkImageInfo largestSubsetDecodeInfo =
211                    decodeInfo.makeWH(subsetWidth + extraX, subsetHeight + extraY);
212            SkBitmap largestSubsetBm;
213            if (!largestSubsetBm.tryAllocPixels(largestSubsetDecodeInfo, NULL, colorTable.get())) {
214                return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str(),
215                        largestSubsetDecodeInfo.width(), largestSubsetDecodeInfo.height());
216            }
217            const size_t rowBytes = decodeInfo.minRowBytes();
218            char* buffer = SkNEW_ARRAY(char, largestSubsetDecodeInfo.height() * rowBytes);
219            SkAutoTDeleteArray<char> lineDeleter(buffer);
220            for (int col = 0; col < divisor; col++) {
221                //currentSubsetWidth may be larger than subsetWidth for rightmost subsets
222                const int currentSubsetWidth = (col + 1 == divisor) ?
223                        subsetWidth + extraX : subsetWidth;
224                const int x = col * subsetWidth;
225                for (int row = 0; row < divisor; row++) {
226                    //currentSubsetHeight may be larger than subsetHeight for bottom subsets
227                    const int currentSubsetHeight = (row + 1 == divisor) ?
228                            subsetHeight + extraY : subsetHeight;
229                    const int y = row * subsetHeight;
230                    //create scanline decoder for each subset
231                    SkAutoTDelete<SkScanlineDecoder> subsetScanlineDecoder(
232                            SkScanlineDecoder::NewFromData(encoded));
233                    if (NULL == subsetScanlineDecoder || SkCodec::kSuccess !=
234                            subsetScanlineDecoder->start(
235                            decodeInfo, NULL, colorPtr, colorCountPtr))
236                    {
237                        if (x == 0 && y == 0) {
238                            //first try, image may not be compatible
239                            return Error::Nonfatal("Cannot use scanline decoder for all images");
240                        } else {
241                            return "Error scanline decoder is NULL";
242                        }
243                    }
244                    //skip to first line of subset
245                    const SkCodec::Result skipResult =
246                            subsetScanlineDecoder->skipScanlines(y);
247                    switch (skipResult) {
248                        case SkCodec::kSuccess:
249                        case SkCodec::kIncompleteInput:
250                            break;
251                        default:
252                            return SkStringPrintf("%s failed after attempting to skip %d scanlines"
253                                    "with error message %d", fPath.c_str(), y, (int) skipResult);
254                    }
255                    //create and set size of subsetBm
256                    SkBitmap subsetBm;
257                    SkIRect bounds = SkIRect::MakeWH(subsetWidth, subsetHeight);
258                    bounds.setXYWH(0, 0, currentSubsetWidth, currentSubsetHeight);
259                    SkAssertResult(largestSubsetBm.extractSubset(&subsetBm, bounds));
260                    SkAutoLockPixels autlockSubsetBm(subsetBm, true);
261                    const SkCodec::Result subsetResult =
262                        subsetScanlineDecoder->getScanlines(buffer, currentSubsetHeight, rowBytes);
263                    switch (subsetResult) {
264                        case SkCodec::kSuccess:
265                        case SkCodec::kIncompleteInput:
266                            break;
267                        default:
268                            return SkStringPrintf("%s failed with error message %d",
269                                    fPath.c_str(), (int) subsetResult);
270                    }
271                    const size_t bpp = decodeInfo.bytesPerPixel();
272                    /*
273                     * we copy all the lines at once becuase when calling getScanlines for
274                     * interlaced pngs the entire image must be read regardless of the number
275                     * of lines requested.  Reading an interlaced png in a loop, line-by-line, would
276                     * decode the entire image height times, which is very slow
277                     * it is aknowledged that copying each line as you read it in a loop
278                     * may be faster for other types of images.  Since this is a correctness test
279                     * that's okay.
280                    */
281                    char* bufferRow = buffer;
282                    for (int subsetY = 0; subsetY < currentSubsetHeight; ++subsetY) {
283                        memcpy(subsetBm.getAddr(0, subsetY), bufferRow + x*bpp,
284                                currentSubsetWidth*bpp);
285                        bufferRow += rowBytes;
286                    }
287
288                    subsetBm.notifyPixelsChanged();
289                    canvas->drawBitmap(subsetBm, SkIntToScalar(x), SkIntToScalar(y));
290                }
291            }
292            break;
293        }
294        case kStripe_Mode: {
295            const int height = decodeInfo.height();
296            // This value is chosen arbitrarily.  We exercise more cases by choosing a value that
297            // does not align with image blocks.
298            const int stripeHeight = 37;
299            const int numStripes = (height + stripeHeight - 1) / stripeHeight;
300
301            // Decode odd stripes
302            SkAutoTDelete<SkScanlineDecoder> decoder(SkScanlineDecoder::NewFromData(encoded));
303            if (NULL == decoder || SkCodec::kSuccess !=
304                    decoder->start(decodeInfo, NULL, colorPtr, colorCountPtr)) {
305                return Error::Nonfatal("Cannot use scanline decoder for all images");
306            }
307            for (int i = 0; i < numStripes; i += 2) {
308                // Skip a stripe
309                const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight);
310                SkCodec::Result result = decoder->skipScanlines(linesToSkip);
311                switch (result) {
312                    case SkCodec::kSuccess:
313                    case SkCodec::kIncompleteInput:
314                        break;
315                    default:
316                        return SkStringPrintf("Cannot skip scanlines for %s.", fPath.c_str());
317                }
318
319                // Read a stripe
320                const int startY = (i + 1) * stripeHeight;
321                const int linesToRead = SkTMin(stripeHeight, height - startY);
322                if (linesToRead > 0) {
323                    result = decoder->getScanlines(bitmap.getAddr(0, startY),
324                            linesToRead, bitmap.rowBytes());
325                    switch (result) {
326                        case SkCodec::kSuccess:
327                        case SkCodec::kIncompleteInput:
328                            break;
329                        default:
330                            return SkStringPrintf("Cannot get scanlines for %s.", fPath.c_str());
331                    }
332                }
333            }
334
335            // Decode even stripes
336            const SkCodec::Result startResult = decoder->start(decodeInfo, NULL, colorPtr,
337                                                               colorCountPtr);
338            if (SkCodec::kSuccess != startResult) {
339                return "Failed to restart scanline decoder with same parameters.";
340            }
341            for (int i = 0; i < numStripes; i += 2) {
342                // Read a stripe
343                const int startY = i * stripeHeight;
344                const int linesToRead = SkTMin(stripeHeight, height - startY);
345                SkCodec::Result result = decoder->getScanlines(bitmap.getAddr(0, startY),
346                        linesToRead, bitmap.rowBytes());
347                switch (result) {
348                    case SkCodec::kSuccess:
349                    case SkCodec::kIncompleteInput:
350                        break;
351                    default:
352                        return SkStringPrintf("Cannot get scanlines for %s.", fPath.c_str());
353                }
354
355                // Skip a stripe
356                const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight);
357                if (linesToSkip > 0) {
358                    result = decoder->skipScanlines(linesToSkip);
359                    switch (result) {
360                        case SkCodec::kSuccess:
361                        case SkCodec::kIncompleteInput:
362                            break;
363                        default:
364                            return SkStringPrintf("Cannot skip scanlines for %s.", fPath.c_str());
365                    }
366                }
367            }
368            canvas->drawBitmap(bitmap, 0, 0);
369            break;
370        }
371        case kSubset_Mode: {
372            // Arbitrarily choose a divisor.
373            int divisor = 2;
374            // Total width/height of the image.
375            const int W = codec->getInfo().width();
376            const int H = codec->getInfo().height();
377            if (divisor > W || divisor > H) {
378                return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divisor %d is too big "
379                                                      "for %s with dimensions (%d x %d)", divisor,
380                                                      fPath.c_str(), W, H));
381            }
382            // subset dimensions
383            // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
384            const int w = SkAlign2(W / divisor);
385            const int h = SkAlign2(H / divisor);
386            SkIRect subset;
387            SkCodec::Options opts;
388            opts.fSubset = &subset;
389            SkBitmap subsetBm;
390            // We will reuse pixel memory from bitmap.
391            void* pixels = bitmap.getPixels();
392            // Keep track of left and top (for drawing subsetBm into canvas). We could use
393            // fScale * x and fScale * y, but we want integers such that the next subset will start
394            // where the last one ended. So we'll add decodeInfo.width() and height().
395            int left = 0;
396            for (int x = 0; x < W; x += w) {
397                int top = 0;
398                for (int y = 0; y < H; y+= h) {
399                    // Do not make the subset go off the edge of the image.
400                    const int preScaleW = SkTMin(w, W - x);
401                    const int preScaleH = SkTMin(h, H - y);
402                    subset.setXYWH(x, y, preScaleW, preScaleH);
403                    // And scale
404                    // FIXME: Should we have a version of getScaledDimensions that takes a subset
405                    // into account?
406                    decodeInfo = decodeInfo.makeWH(SkScalarRoundToInt(preScaleW * fScale),
407                                                   SkScalarRoundToInt(preScaleH * fScale));
408                    size_t rowBytes = decodeInfo.minRowBytes();
409                    if (!subsetBm.installPixels(decodeInfo, pixels, rowBytes, colorTable.get(),
410                                                NULL, NULL)) {
411                        return SkStringPrintf("could not install pixels for %s.", fPath.c_str());
412                    }
413                    const SkCodec::Result result = codec->getPixels(decodeInfo, pixels, rowBytes,
414                            &opts, colorPtr, colorCountPtr);
415                    switch (result) {
416                        case SkCodec::kSuccess:
417                        case SkCodec::kIncompleteInput:
418                            break;
419                        case SkCodec::kInvalidConversion:
420                            if (0 == (x|y)) {
421                                // First subset is okay to return unimplemented.
422                                return Error::Nonfatal("Incompatible colortype conversion");
423                            }
424                            // If the first subset succeeded, a later one should not fail.
425                            // fall through to failure
426                        case SkCodec::kUnimplemented:
427                            if (0 == (x|y)) {
428                                // First subset is okay to return unimplemented.
429                                return Error::Nonfatal("subset codec not supported");
430                            }
431                            // If the first subset succeeded, why would a later one fail?
432                            // fall through to failure
433                        default:
434                            return SkStringPrintf("subset codec failed to decode (%d, %d, %d, %d) "
435                                                  "from %s with dimensions (%d x %d)\t error %d",
436                                                  x, y, decodeInfo.width(), decodeInfo.height(),
437                                                  fPath.c_str(), W, H, result);
438                    }
439                    canvas->drawBitmap(subsetBm, SkIntToScalar(left), SkIntToScalar(top));
440                    // translate by the scaled height.
441                    top += decodeInfo.height();
442                }
443                // translate by the scaled width.
444                left += decodeInfo.width();
445            }
446            return "";
447        }
448    }
449    return "";
450}
451
452SkISize CodecSrc::size() const {
453    SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
454    SkAutoTDelete<SkCodec> codec(SkScaledCodec::NewFromData(encoded));
455    if (NULL == codec) {
456        // scaledCodec not supported, try regular codec
457        codec.reset(SkCodec::NewFromData(encoded));
458        if (NULL == codec) {
459            return SkISize::Make(0, 0);
460        }
461    }
462    SkISize size = codec->getScaledDimensions(fScale);
463    return size;
464}
465
466Name CodecSrc::name() const {
467    if (1.0f == fScale) {
468        return SkOSPath::Basename(fPath.c_str());
469    } else {
470        return SkStringPrintf("%s_%.3f", SkOSPath::Basename(fPath.c_str()).c_str(), fScale);
471    }
472}
473
474/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
475
476ImageSrc::ImageSrc(Path path, int divisor) : fPath(path), fDivisor(divisor) {}
477
478bool ImageSrc::veto(SinkFlags flags) const {
479    // No need to test decoding to non-raster or indirect backend.
480    // TODO: Instead, use lazy decoding to allow the GPU to handle cases like YUV.
481    return flags.type != SinkFlags::kRaster
482        || flags.approach != SinkFlags::kDirect;
483}
484
485Error ImageSrc::draw(SkCanvas* canvas) const {
486    SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
487    if (!encoded) {
488        return SkStringPrintf("Couldn't read %s.", fPath.c_str());
489    }
490    const SkColorType dstColorType = canvas->imageInfo().colorType();
491    if (fDivisor == 0) {
492        // Decode the full image.
493        SkBitmap bitmap;
494        if (!SkImageDecoder::DecodeMemory(encoded->data(), encoded->size(), &bitmap,
495                                          dstColorType, SkImageDecoder::kDecodePixels_Mode)) {
496            return SkStringPrintf("Couldn't decode %s.", fPath.c_str());
497        }
498        if (kRGB_565_SkColorType == dstColorType && !bitmap.isOpaque()) {
499            // Do not draw a bitmap with alpha to a destination without alpha.
500            return Error::Nonfatal("Uninteresting to decode image with alpha into 565.");
501        }
502        encoded.reset((SkData*)NULL);  // Might as well drop this when we're done with it.
503        canvas->drawBitmap(bitmap, 0,0);
504        return "";
505    }
506    // Decode subsets.  This is a little involved.
507    SkAutoTDelete<SkMemoryStream> stream(new SkMemoryStream(encoded));
508    SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream.get()));
509    if (!decoder) {
510        return SkStringPrintf("Can't find a good decoder for %s.", fPath.c_str());
511    }
512    stream->rewind();
513    int w,h;
514    if (!decoder->buildTileIndex(stream.detach(), &w, &h)) {
515        return Error::Nonfatal("Subset decoding not supported.");
516    }
517
518    // Divide the image into subsets that cover the entire image.
519    if (fDivisor > w || fDivisor > h) {
520        return Error::Nonfatal(SkStringPrintf("Cannot decode subset: divisor %d is too big"
521                "for %s with dimensions (%d x %d)", fDivisor, fPath.c_str(), w, h));
522    }
523    const int subsetWidth  = w / fDivisor,
524              subsetHeight = h / fDivisor;
525    for (int y = 0; y < h; y += subsetHeight) {
526        for (int x = 0; x < w; x += subsetWidth) {
527            SkBitmap subset;
528            SkIRect rect = SkIRect::MakeXYWH(x, y, subsetWidth, subsetHeight);
529            if (!decoder->decodeSubset(&subset, rect, dstColorType)) {
530                return SkStringPrintf("Could not decode subset (%d, %d, %d, %d).",
531                                      x, y, x+subsetWidth, y+subsetHeight);
532            }
533            if (kRGB_565_SkColorType == dstColorType && !subset.isOpaque()) {
534                // Do not draw a bitmap with alpha to a destination without alpha.
535                // This is not an error, but there is nothing interesting to show.
536
537                // This should only happen on the first iteration through the loop.
538                SkASSERT(0 == x && 0 == y);
539
540                return Error::Nonfatal("Uninteresting to decode image with alpha into 565.");
541            }
542            canvas->drawBitmap(subset, SkIntToScalar(x), SkIntToScalar(y));
543        }
544    }
545    return "";
546}
547
548SkISize ImageSrc::size() const {
549    SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
550    SkBitmap bitmap;
551    if (!encoded || !SkImageDecoder::DecodeMemory(encoded->data(),
552                                                  encoded->size(),
553                                                  &bitmap,
554                                                  kUnknown_SkColorType,
555                                                  SkImageDecoder::kDecodeBounds_Mode)) {
556        return SkISize::Make(0,0);
557    }
558    return bitmap.dimensions();
559}
560
561Name ImageSrc::name() const {
562    return SkOSPath::Basename(fPath.c_str());
563}
564
565/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
566
567static const SkRect kSKPViewport = {0,0, 1000,1000};
568
569SKPSrc::SKPSrc(Path path) : fPath(path) {}
570
571Error SKPSrc::draw(SkCanvas* canvas) const {
572    SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str()));
573    if (!stream) {
574        return SkStringPrintf("Couldn't read %s.", fPath.c_str());
575    }
576    SkAutoTUnref<SkPicture> pic(SkPicture::CreateFromStream(stream, &lazy_decode_bitmap));
577    if (!pic) {
578        return SkStringPrintf("Couldn't decode %s as a picture.", fPath.c_str());
579    }
580    stream.reset((SkStream*)NULL);  // Might as well drop this when we're done with it.
581
582    canvas->clipRect(kSKPViewport);
583    canvas->drawPicture(pic);
584    return "";
585}
586
587SkISize SKPSrc::size() const {
588    SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str()));
589    if (!stream) {
590        return SkISize::Make(0,0);
591    }
592    SkPictInfo info;
593    if (!SkPicture::InternalOnly_StreamIsSKP(stream, &info)) {
594        return SkISize::Make(0,0);
595    }
596    SkRect viewport = kSKPViewport;
597    if (!viewport.intersect(info.fCullRect)) {
598        return SkISize::Make(0,0);
599    }
600    return viewport.roundOut().size();
601}
602
603Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
604
605/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
606
607Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const {
608    SkAutoTDelete<SkCanvas> canvas(SkCreateNullCanvas());
609    return src.draw(canvas);
610}
611
612/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
613
614DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?");
615
616GPUSink::GPUSink(GrContextFactory::GLContextType ct,
617                 GrGLStandard api,
618                 int samples,
619                 bool dfText,
620                 bool threaded)
621    : fContextType(ct)
622    , fGpuAPI(api)
623    , fSampleCount(samples)
624    , fUseDFText(dfText)
625    , fThreaded(threaded) {}
626
627int GPUSink::enclave() const {
628    return fThreaded ? kAnyThread_Enclave : kGPU_Enclave;
629}
630
631void PreAbandonGpuContextErrorHandler(SkError, void*) {}
632
633Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const {
634    GrContextOptions options;
635    src.modifyGrContextOptions(&options);
636
637    GrContextFactory factory(options);
638    const SkISize size = src.size();
639    const SkImageInfo info =
640        SkImageInfo::Make(size.width(), size.height(), kN32_SkColorType, kPremul_SkAlphaType);
641    SkAutoTUnref<SkSurface> surface(
642            NewGpuSurface(&factory, fContextType, fGpuAPI, info, fSampleCount, fUseDFText));
643    if (!surface) {
644        return "Could not create a surface.";
645    }
646    if (FLAGS_preAbandonGpuContext) {
647        SkSetErrorCallback(&PreAbandonGpuContextErrorHandler, NULL);
648        factory.abandonContexts();
649    }
650    SkCanvas* canvas = surface->getCanvas();
651    Error err = src.draw(canvas);
652    if (!err.isEmpty()) {
653        return err;
654    }
655    canvas->flush();
656    if (FLAGS_gpuStats) {
657        canvas->getGrContext()->dumpCacheStats(log);
658        canvas->getGrContext()->dumpGpuStats(log);
659    }
660    dst->allocPixels(info);
661    canvas->readPixels(dst, 0, 0);
662    if (FLAGS_abandonGpuContext) {
663        factory.abandonContexts();
664    }
665    return "";
666}
667
668/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
669
670static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) {
671    // Print the given DM:Src to a document, breaking on 8.5x11 pages.
672    SkASSERT(doc);
673    int width  = src.size().width(),
674        height = src.size().height();
675
676    if (FLAGS_multiPage) {
677        const int kLetterWidth = 612,  // 8.5 * 72
678                kLetterHeight = 792;   // 11 * 72
679        const SkRect letter = SkRect::MakeWH(SkIntToScalar(kLetterWidth),
680                                             SkIntToScalar(kLetterHeight));
681
682        int xPages = ((width - 1) / kLetterWidth) + 1;
683        int yPages = ((height - 1) / kLetterHeight) + 1;
684
685        for (int y = 0; y < yPages; ++y) {
686            for (int x = 0; x < xPages; ++x) {
687                int w = SkTMin(kLetterWidth, width - (x * kLetterWidth));
688                int h = SkTMin(kLetterHeight, height - (y * kLetterHeight));
689                SkCanvas* canvas =
690                        doc->beginPage(SkIntToScalar(w), SkIntToScalar(h));
691                if (!canvas) {
692                    return "SkDocument::beginPage(w,h) returned NULL";
693                }
694                canvas->clipRect(letter);
695                canvas->translate(-letter.width() * x, -letter.height() * y);
696                Error err = src.draw(canvas);
697                if (!err.isEmpty()) {
698                    return err;
699                }
700                doc->endPage();
701            }
702        }
703    } else {
704        SkCanvas* canvas =
705                doc->beginPage(SkIntToScalar(width), SkIntToScalar(height));
706        if (!canvas) {
707            return "SkDocument::beginPage(w,h) returned NULL";
708        }
709        Error err = src.draw(canvas);
710        if (!err.isEmpty()) {
711            return err;
712        }
713        doc->endPage();
714    }
715    if (!doc->close()) {
716        return "SkDocument::close() returned false";
717    }
718    dst->flush();
719    return "";
720}
721
722PDFSink::PDFSink() {}
723
724Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
725    SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(dst));
726    if (!doc) {
727        return "SkDocument::CreatePDF() returned NULL";
728    }
729    return draw_skdocument(src, doc.get(), dst);
730}
731
732/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
733
734XPSSink::XPSSink() {}
735
736Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
737    SkAutoTUnref<SkDocument> doc(SkDocument::CreateXPS(dst));
738    if (!doc) {
739        return "SkDocument::CreateXPS() returned NULL";
740    }
741    return draw_skdocument(src, doc.get(), dst);
742}
743/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
744
745SKPSink::SKPSink() {}
746
747Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
748    SkSize size;
749    size = src.size();
750    SkPictureRecorder recorder;
751    Error err = src.draw(recorder.beginRecording(size.width(), size.height()));
752    if (!err.isEmpty()) {
753        return err;
754    }
755    SkAutoTUnref<SkPicture> pic(recorder.endRecording());
756    pic->serialize(dst);
757    return "";
758}
759
760/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
761
762SVGSink::SVGSink() {}
763
764Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
765    SkAutoTDelete<SkXMLWriter> xmlWriter(SkNEW_ARGS(SkXMLStreamWriter, (dst)));
766    SkAutoTUnref<SkCanvas> canvas(SkSVGCanvas::Create(
767        SkRect::MakeWH(SkIntToScalar(src.size().width()), SkIntToScalar(src.size().height())),
768        xmlWriter));
769    return src.draw(canvas);
770}
771
772/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
773
774RasterSink::RasterSink(SkColorType colorType) : fColorType(colorType) {}
775
776Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
777    const SkISize size = src.size();
778    // If there's an appropriate alpha type for this color type, use it, otherwise use premul.
779    SkAlphaType alphaType = kPremul_SkAlphaType;
780    (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType);
781
782    dst->allocPixels(SkImageInfo::Make(size.width(), size.height(), fColorType, alphaType));
783    dst->eraseColor(SK_ColorTRANSPARENT);
784    SkCanvas canvas(*dst);
785    return src.draw(&canvas);
786}
787
788/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
789
790// Handy for front-patching a Src.  Do whatever up-front work you need, then call draw_to_canvas(),
791// passing the Sink draw() arguments, a size, and a function draws into an SkCanvas.
792// Several examples below.
793
794static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log,
795                            SkISize size, SkFunction<Error(SkCanvas*)> draw) {
796    class ProxySrc : public Src {
797    public:
798        ProxySrc(SkISize size, SkFunction<Error(SkCanvas*)> draw) : fSize(size), fDraw(draw) {}
799        Error   draw(SkCanvas* canvas) const override { return fDraw(canvas); }
800        Name                    name() const override { sk_throw(); return ""; } // Won't be called.
801        SkISize                 size() const override { return fSize; }
802    private:
803        SkISize                      fSize;
804        SkFunction<Error(SkCanvas*)> fDraw;
805    };
806    return sink->draw(ProxySrc(size, draw), bitmap, stream, log);
807}
808
809/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
810
811static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) {
812    SkRect bounds = SkRect::MakeIWH(srcW, srcH);
813    matrix->mapRect(&bounds);
814    matrix->postTranslate(-bounds.x(), -bounds.y());
815    return SkISize::Make(SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height()));
816}
817
818ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
819
820Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
821    SkMatrix matrix = fMatrix;
822    SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height());
823    return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
824        canvas->concat(matrix);
825        return src.draw(canvas);
826    });
827}
828
829// Undoes any flip or 90 degree rotate without changing the scale of the bitmap.
830// This should be pixel-preserving.
831ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
832
833Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
834    Error err = fSink->draw(src, bitmap, stream, log);
835    if (!err.isEmpty()) {
836        return err;
837    }
838
839    SkMatrix inverse;
840    if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) {
841        return "Cannot upright --matrix.";
842    }
843    SkMatrix upright = SkMatrix::I();
844    upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX()));
845    upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY()));
846    upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX()));
847    upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY()));
848
849    SkBitmap uprighted;
850    SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height());
851    uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height()));
852
853    SkCanvas canvas(uprighted);
854    canvas.concat(upright);
855    SkPaint paint;
856    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
857    canvas.drawBitmap(*bitmap, 0, 0, &paint);
858
859    *bitmap = uprighted;
860    bitmap->lockPixels();
861    return "";
862}
863
864/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
865
866Error ViaPipe::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
867    auto size = src.size();
868    return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
869        PipeController controller(canvas, &SkImageDecoder::DecodeMemory);
870        SkGPipeWriter pipe;
871        const uint32_t kFlags = 0; // We mirror SkDeferredCanvas, which doesn't use any flags.
872        return src.draw(pipe.startRecording(&controller, kFlags, size.width(), size.height()));
873    });
874}
875
876/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
877
878Error ViaDeferred::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
879    // We draw via a deferred canvas into a surface that's compatible with the original canvas,
880    // then snap that surface as an image and draw it into the original canvas.
881    return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) -> Error {
882        SkAutoTUnref<SkSurface> surface(canvas->newSurface(canvas->imageInfo()));
883        if (!surface.get()) {
884            return "can't make surface for deferred canvas";
885        }
886        SkAutoTDelete<SkDeferredCanvas> defcan(SkDeferredCanvas::Create(surface));
887        Error err = src.draw(defcan);
888        if (!err.isEmpty()) {
889            return err;
890        }
891        SkAutoTUnref<SkImage> image(defcan->newImageSnapshot());
892        if (!image) {
893            return "failed to create deferred image snapshot";
894        }
895        canvas->drawImage(image, 0, 0, NULL);
896        return "";
897    });
898}
899
900/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
901
902Error ViaSerialization::draw(
903        const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
904    // Record our Src into a picture.
905    auto size = src.size();
906    SkPictureRecorder recorder;
907    Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
908                                                 SkIntToScalar(size.height())));
909    if (!err.isEmpty()) {
910        return err;
911    }
912    SkAutoTUnref<SkPicture> pic(recorder.endRecording());
913
914    // Serialize it and then deserialize it.
915    SkDynamicMemoryWStream wStream;
916    pic->serialize(&wStream);
917    SkAutoTDelete<SkStream> rStream(wStream.detachAsStream());
918    SkAutoTUnref<SkPicture> deserialized(SkPicture::CreateFromStream(rStream, &lazy_decode_bitmap));
919
920    return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
921        canvas->drawPicture(deserialized);
922        return "";
923    });
924}
925
926/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
927
928ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink)
929    : Via(sink)
930    , fW(w)
931    , fH(h)
932    , fFactory(factory) {}
933
934Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
935    auto size = src.size();
936    SkPictureRecorder recorder;
937    Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
938                                                 SkIntToScalar(size.height()),
939                                                 fFactory.get()));
940    if (!err.isEmpty()) {
941        return err;
942    }
943    SkAutoTUnref<SkPicture> pic(recorder.endRecordingAsPicture());
944
945    return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) {
946        const int xTiles = (size.width()  + fW - 1) / fW,
947                  yTiles = (size.height() + fH - 1) / fH;
948        SkMultiPictureDraw mpd(xTiles*yTiles);
949        SkTDArray<SkSurface*> surfaces;
950        surfaces.setReserve(xTiles*yTiles);
951
952        SkImageInfo info = canvas->imageInfo().makeWH(fW, fH);
953        for (int j = 0; j < yTiles; j++) {
954            for (int i = 0; i < xTiles; i++) {
955                // This lets our ultimate Sink determine the best kind of surface.
956                // E.g., if it's a GpuSink, the surfaces and images are textures.
957                SkSurface* s = canvas->newSurface(info);
958                if (!s) {
959                    s = SkSurface::NewRaster(info);  // Some canvases can't create surfaces.
960                }
961                surfaces.push(s);
962                SkCanvas* c = s->getCanvas();
963                c->translate(SkIntToScalar(-i * fW),
964                             SkIntToScalar(-j * fH));  // Line up the canvas with this tile.
965                mpd.add(c, pic);
966            }
967        }
968        mpd.draw();
969        for (int j = 0; j < yTiles; j++) {
970            for (int i = 0; i < xTiles; i++) {
971                SkAutoTUnref<SkImage> image(surfaces[i+xTiles*j]->newImageSnapshot());
972                canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH));
973            }
974        }
975        surfaces.unrefAll();
976        return "";
977    });
978}
979
980/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
981
982// Draw the Src into two pictures, then draw the second picture into the wrapped Sink.
983// This tests that any shortcuts we may take while recording that second picture are legal.
984Error ViaSecondPicture::draw(
985        const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
986    auto size = src.size();
987    return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
988        SkPictureRecorder recorder;
989        SkAutoTUnref<SkPicture> pic;
990        for (int i = 0; i < 2; i++) {
991            Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
992                                                         SkIntToScalar(size.height())));
993            if (!err.isEmpty()) {
994                return err;
995            }
996            pic.reset(recorder.endRecordingAsPicture());
997        }
998        canvas->drawPicture(pic);
999        return "";
1000    });
1001}
1002
1003/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1004
1005// Draw the Src twice.  This can help exercise caching.
1006Error ViaTwice::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1007    return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) -> Error {
1008        for (int i = 0; i < 2; i++) {
1009            SkAutoCanvasRestore acr(canvas, true/*save now*/);
1010            canvas->clear(SK_ColorTRANSPARENT);
1011            Error err = src.draw(canvas);
1012            if (err.isEmpty()) {
1013                return err;
1014            }
1015        }
1016        return "";
1017    });
1018}
1019
1020/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1021
1022// This is like SkRecords::Draw, in that it plays back SkRecords ops into a Canvas.
1023// Unlike SkRecords::Draw, it builds a single-op sub-picture out of each Draw-type op.
1024// This is an only-slightly-exaggerated simluation of Blink's Slimming Paint pictures.
1025struct DrawsAsSingletonPictures {
1026    SkCanvas* fCanvas;
1027    const SkDrawableList& fDrawables;
1028
1029    SK_CREATE_MEMBER_DETECTOR(paint);
1030
1031    template <typename T>
1032    void draw(const T& op, SkCanvas* canvas) {
1033        // We must pass SkMatrix::I() as our initial matrix.
1034        // By default SkRecords::Draw() uses the canvas' matrix as its initial matrix,
1035        // which would have the funky effect of applying transforms over and over.
1036        SkRecords::Draw d(canvas, nullptr, fDrawables.begin(), fDrawables.count(), &SkMatrix::I());
1037        d(op);
1038    }
1039
1040    // Most things that have paints are Draw-type ops.  Create sub-pictures for each.
1041    template <typename T>
1042    SK_WHEN(HasMember_paint<T>, void) operator()(const T& op) {
1043        SkPictureRecorder rec;
1044        this->draw(op, rec.beginRecording(SkRect::MakeLargest()));
1045        SkAutoTUnref<SkPicture> pic(rec.endRecordingAsPicture());
1046        fCanvas->drawPicture(pic);
1047    }
1048
1049    // If you don't have a paint or are a SaveLayer, you're not a Draw-type op.
1050    // We cannot make subpictures out of these because they affect state.  Draw them directly.
1051    template <typename T>
1052    SK_WHEN(!HasMember_paint<T>, void) operator()(const T& op) { this->draw(op, fCanvas); }
1053    void operator()(const SkRecords::SaveLayer& op)            { this->draw(op, fCanvas); }
1054};
1055
1056// Record Src into a picture, then record it into a macro picture with a sub-picture for each draw.
1057// Then play back that macro picture into our wrapped sink.
1058Error ViaSingletonPictures::draw(
1059        const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1060    auto size = src.size();
1061    return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1062        // Use low-level (Skia-private) recording APIs so we can read the SkRecord.
1063        SkRecord skr;
1064        SkRecorder recorder(&skr, size.width(), size.height());
1065        Error err = src.draw(&recorder);
1066        if (!err.isEmpty()) {
1067            return err;
1068        }
1069
1070        // Record our macro-picture, with each draw op as its own sub-picture.
1071        SkPictureRecorder macroRec;
1072        SkCanvas* macroCanvas = macroRec.beginRecording(SkIntToScalar(size.width()),
1073                                                        SkIntToScalar(size.height()));
1074
1075        SkAutoTDelete<SkDrawableList> drawables(recorder.detachDrawableList());
1076        const SkDrawableList empty;
1077
1078        DrawsAsSingletonPictures drawsAsSingletonPictures = {
1079            macroCanvas,
1080            drawables ? *drawables : empty,
1081        };
1082        for (unsigned i = 0; i < skr.count(); i++) {
1083            skr.visit<void>(i, drawsAsSingletonPictures);
1084        }
1085        SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture());
1086
1087        canvas->drawPicture(macroPic);
1088        return "";
1089    });
1090}
1091
1092}  // namespace DM
1093