DMSrcSink.cpp revision 56e25ddf6e2c1f85c5addbe498a082268ebee6ea
1#include "DMSrcSink.h"
2#include "SamplePipeControllers.h"
3#include "SkCommonFlags.h"
4#include "SkCodec.h"
5#include "SkDocument.h"
6#include "SkError.h"
7#include "SkMultiPictureDraw.h"
8#include "SkNullCanvas.h"
9#include "SkOSFile.h"
10#include "SkPictureRecorder.h"
11#include "SkRandom.h"
12#include "SkSVGCanvas.h"
13#include "SkStream.h"
14#include "SkXMLWriter.h"
15
16DEFINE_bool(codec, false, "Use SkCodec instead of SkImageDecoder");
17
18namespace DM {
19
20GMSrc::GMSrc(skiagm::GMRegistry::Factory factory) : fFactory(factory) {}
21
22Error GMSrc::draw(SkCanvas* canvas) const {
23    SkAutoTDelete<skiagm::GM> gm(fFactory(NULL));
24    canvas->concat(gm->getInitialTransform());
25    gm->draw(canvas);
26    return "";
27}
28
29SkISize GMSrc::size() const {
30    SkAutoTDelete<skiagm::GM> gm(fFactory(NULL));
31    return gm->getISize();
32}
33
34Name GMSrc::name() const {
35    SkAutoTDelete<skiagm::GM> gm(fFactory(NULL));
36    return gm->getName();
37}
38
39/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
40
41ImageSrc::ImageSrc(Path path, int divisor) : fPath(path), fDivisor(divisor) {}
42
43Error ImageSrc::draw(SkCanvas* canvas) const {
44    SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
45    if (!encoded) {
46        return SkStringPrintf("Couldn't read %s.", fPath.c_str());
47    }
48    const SkColorType dstColorType = canvas->imageInfo().colorType();
49    if (fDivisor == 0) {
50        // Decode the full image.
51        SkBitmap bitmap;
52        if (FLAGS_codec) {
53            SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
54            if (!codec) {
55                return SkStringPrintf("Couldn't decode %s.", fPath.c_str());
56            }
57            SkImageInfo info;
58            if (!codec->getInfo(&info)) {
59                return SkStringPrintf("Couldn't getInfo %s.", fPath.c_str());
60            }
61            info = info.makeColorType(dstColorType);
62            if (info.alphaType() == kUnpremul_SkAlphaType) {
63                // FIXME: Currently we cannot draw unpremultiplied sources.
64                info = info.makeAlphaType(kPremul_SkAlphaType);
65            }
66            if (!bitmap.tryAllocPixels(info)) {
67                return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str(),
68                                      info.width(), info.height());
69            }
70            SkAutoLockPixels alp(bitmap);
71            const SkImageGenerator::Result result = codec->getPixels(info, bitmap.getPixels(),
72                                                                     bitmap.rowBytes());
73            switch (result) {
74                case SkImageGenerator::kSuccess:
75                // We consider incomplete to be valid, since we should still decode what is
76                // available.
77                case SkImageGenerator::kIncompleteInput:
78                    break;
79                case SkImageGenerator::kInvalidConversion:
80                    return Error::Nonfatal("Incompatible colortype conversion");
81                default:
82                    // Everything else is considered a failure.
83                    return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
84            }
85        } else {
86            if (!SkImageDecoder::DecodeMemory(encoded->data(), encoded->size(), &bitmap,
87                                              dstColorType, SkImageDecoder::kDecodePixels_Mode)) {
88                return SkStringPrintf("Couldn't decode %s.", fPath.c_str());
89            }
90            if (kRGB_565_SkColorType == dstColorType && !bitmap.isOpaque()) {
91                // Do not draw a bitmap with alpha to a destination without alpha.
92                return Error::Nonfatal("Uninteresting to decode image with alpha into 565.");
93            }
94        }
95        encoded.reset((SkData*)NULL);  // Might as well drop this when we're done with it.
96        canvas->drawBitmap(bitmap, 0,0);
97        return "";
98    }
99    // Decode subsets.  This is a little involved.
100    SkAutoTDelete<SkMemoryStream> stream(new SkMemoryStream(encoded));
101    SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream.get()));
102    if (!decoder) {
103        return SkStringPrintf("Can't find a good decoder for %s.", fPath.c_str());
104    }
105    stream->rewind();
106    int w,h;
107    if (!decoder->buildTileIndex(stream.detach(), &w, &h) || w*h == 1) {
108        return Error::Nonfatal("Subset decoding not supported.");
109    }
110
111    // Divide the image into subsets that cover the entire image.
112    if (fDivisor > w || fDivisor > h) {
113        return SkStringPrintf("divisor %d is too big for %s with dimensions (%d x %d)",
114                              fDivisor, fPath.c_str(), w, h);
115    }
116    const int subsetWidth  = w / fDivisor,
117              subsetHeight = h / fDivisor;
118    for (int y = 0; y < h; y += subsetHeight) {
119        for (int x = 0; x < w; x += subsetWidth) {
120            SkBitmap subset;
121            SkIRect rect = SkIRect::MakeXYWH(x, y, subsetWidth, subsetHeight);
122            if (!decoder->decodeSubset(&subset, rect, dstColorType)) {
123                return SkStringPrintf("Could not decode subset (%d, %d, %d, %d).",
124                                      x, y, x+subsetWidth, y+subsetHeight);
125            }
126            if (kRGB_565_SkColorType == dstColorType && !subset.isOpaque()) {
127                // Do not draw a bitmap with alpha to a destination without alpha.
128                // This is not an error, but there is nothing interesting to show.
129
130                // This should only happen on the first iteration through the loop.
131                SkASSERT(0 == x && 0 == y);
132
133                return Error::Nonfatal("Uninteresting to decode image with alpha into 565.");
134            }
135            canvas->drawBitmap(subset, SkIntToScalar(x), SkIntToScalar(y));
136        }
137    }
138    return "";
139}
140
141SkISize ImageSrc::size() const {
142    SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
143    SkBitmap bitmap;
144    if (!encoded || !SkImageDecoder::DecodeMemory(encoded->data(),
145                                                  encoded->size(),
146                                                  &bitmap,
147                                                  kUnknown_SkColorType,
148                                                  SkImageDecoder::kDecodeBounds_Mode)) {
149        return SkISize::Make(0,0);
150    }
151    return bitmap.dimensions();
152}
153
154Name ImageSrc::name() const {
155    return SkOSPath::Basename(fPath.c_str());
156}
157
158/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
159
160static const SkRect kSKPViewport = {0,0, 1000,1000};
161
162SKPSrc::SKPSrc(Path path) : fPath(path) {}
163
164Error SKPSrc::draw(SkCanvas* canvas) const {
165    SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str()));
166    if (!stream) {
167        return SkStringPrintf("Couldn't read %s.", fPath.c_str());
168    }
169    SkAutoTUnref<SkPicture> pic(SkPicture::CreateFromStream(stream));
170    if (!pic) {
171        return SkStringPrintf("Couldn't decode %s as a picture.", fPath.c_str());
172    }
173    stream.reset((SkStream*)NULL);  // Might as well drop this when we're done with it.
174    canvas->clipRect(kSKPViewport);
175    canvas->drawPicture(pic);
176    return "";
177}
178
179SkISize SKPSrc::size() const {
180    // This may be unnecessarily large.
181    return kSKPViewport.roundOut().size();
182}
183
184Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
185
186/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
187
188Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const {
189    SkAutoTDelete<SkCanvas> canvas(SkCreateNullCanvas());
190    return src.draw(canvas);
191}
192
193/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
194
195DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?");
196
197GPUSink::GPUSink(GrContextFactory::GLContextType ct,
198                 GrGLStandard api,
199                 int samples,
200                 bool dfText,
201                 bool threaded)
202    : fContextType(ct)
203    , fGpuAPI(api)
204    , fSampleCount(samples)
205    , fUseDFText(dfText)
206    , fThreaded(threaded) {}
207
208int GPUSink::enclave() const {
209    return fThreaded ? kAnyThread_Enclave : kGPU_Enclave;
210}
211
212void PreAbandonGpuContextErrorHandler(SkError, void*) {}
213
214Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const {
215    GrContextFactory factory;
216    const SkISize size = src.size();
217    const SkImageInfo info =
218        SkImageInfo::Make(size.width(), size.height(), kN32_SkColorType, kPremul_SkAlphaType);
219    SkAutoTUnref<SkSurface> surface(
220            NewGpuSurface(&factory, fContextType, fGpuAPI, info, fSampleCount, fUseDFText));
221    if (!surface) {
222        return "Could not create a surface.";
223    }
224    if (FLAGS_preAbandonGpuContext) {
225        SkSetErrorCallback(&PreAbandonGpuContextErrorHandler, NULL);
226        factory.abandonContexts();
227    }
228    SkCanvas* canvas = surface->getCanvas();
229    Error err = src.draw(canvas);
230    if (!err.isEmpty()) {
231        return err;
232    }
233    canvas->flush();
234    if (FLAGS_gpuStats) {
235        canvas->getGrContext()->dumpCacheStats(log);
236        canvas->getGrContext()->dumpGpuStats(log);
237    }
238    dst->allocPixels(info);
239    canvas->readPixels(dst, 0, 0);
240    if (FLAGS_abandonGpuContext) {
241        factory.abandonContexts();
242    }
243    return "";
244}
245
246/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
247
248static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) {
249    // Print the given DM:Src to a document, breaking on 8.5x11 pages.
250    SkASSERT(doc);
251    int width  = src.size().width(),
252        height = src.size().height();
253
254    const int kLetterWidth  = 612,  // 8.5 * 72
255              kLetterHeight = 792;  // 11 * 72
256    const SkRect letter = SkRect::MakeWH(SkIntToScalar(kLetterWidth),
257                                         SkIntToScalar(kLetterHeight));
258
259    int xPages = ((width - 1) / kLetterWidth) + 1;
260    int yPages = ((height - 1) / kLetterHeight) + 1;
261
262    for (int y = 0; y < yPages; ++y) {
263        for (int x = 0; x < xPages; ++x) {
264            int w = SkTMin(kLetterWidth, width - (x * kLetterWidth));
265            int h = SkTMin(kLetterHeight, height - (y * kLetterHeight));
266            SkCanvas* canvas =
267                    doc->beginPage(SkIntToScalar(w), SkIntToScalar(h));
268            canvas->clipRect(letter);
269            canvas->translate(-letter.width() * x, -letter.height() * y);
270            Error err = src.draw(canvas);
271            if (!err.isEmpty()) {
272                return err;
273            }
274            doc->endPage();
275        }
276    }
277    doc->close();
278    dst->flush();
279    return "";
280}
281
282PDFSink::PDFSink() {}
283
284Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
285    SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(dst));
286    if (!doc) {
287        return "SkDocument::CreatePDF() returned NULL";
288    }
289    return draw_skdocument(src, doc.get(), dst);
290}
291
292/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
293
294XPSSink::XPSSink() {}
295
296Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
297    SkAutoTUnref<SkDocument> doc(SkDocument::CreateXPS(dst));
298    if (!doc) {
299        return "SkDocument::CreateXPS() returned NULL";
300    }
301    return draw_skdocument(src, doc.get(), dst);
302}
303/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
304
305SKPSink::SKPSink() {}
306
307Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
308    SkSize size;
309    size = src.size();
310    SkPictureRecorder recorder;
311    Error err = src.draw(recorder.beginRecording(size.width(), size.height()));
312    if (!err.isEmpty()) {
313        return err;
314    }
315    SkAutoTUnref<SkPicture> pic(recorder.endRecording());
316    pic->serialize(dst);
317    return "";
318}
319
320/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
321
322SVGSink::SVGSink() {}
323
324Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
325    SkAutoTDelete<SkXMLWriter> xmlWriter(SkNEW_ARGS(SkXMLStreamWriter, (dst)));
326    SkAutoTUnref<SkCanvas> canvas(SkSVGCanvas::Create(
327        SkRect::MakeWH(SkIntToScalar(src.size().width()), SkIntToScalar(src.size().height())),
328        xmlWriter));
329    return src.draw(canvas);
330}
331
332/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
333
334RasterSink::RasterSink(SkColorType colorType) : fColorType(colorType) {}
335
336Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
337    const SkISize size = src.size();
338    // If there's an appropriate alpha type for this color type, use it, otherwise use premul.
339    SkAlphaType alphaType = kPremul_SkAlphaType;
340    (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType);
341
342    dst->allocPixels(SkImageInfo::Make(size.width(), size.height(), fColorType, alphaType));
343    dst->eraseColor(SK_ColorTRANSPARENT);
344    SkCanvas canvas(*dst);
345    return src.draw(&canvas);
346}
347
348/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
349
350static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) {
351    SkRect bounds = SkRect::MakeIWH(srcW, srcH);
352    matrix->mapRect(&bounds);
353    matrix->postTranslate(-bounds.x(), -bounds.y());
354    return SkISize::Make(SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height()));
355}
356
357ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : fMatrix(matrix), fSink(sink) {}
358
359Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
360    // We turn our arguments into a Src, then draw that Src into our Sink to fill bitmap or stream.
361    struct ProxySrc : public Src {
362        const Src&  fSrc;
363        SkMatrix    fMatrix;
364        SkISize     fSize;
365
366        ProxySrc(const Src& src, SkMatrix matrix) : fSrc(src), fMatrix(matrix) {
367            fSize = auto_compute_translate(&fMatrix, src.size().width(), src.size().height());
368        }
369
370        Error draw(SkCanvas* canvas) const SK_OVERRIDE {
371            canvas->concat(fMatrix);
372            return fSrc.draw(canvas);
373        }
374        SkISize size() const SK_OVERRIDE { return fSize; }
375        Name name() const SK_OVERRIDE { sk_throw(); return ""; }  // No one should be calling this.
376    } proxy(src, fMatrix);
377    return fSink->draw(proxy, bitmap, stream, log);
378}
379
380// Undoes any flip or 90 degree rotate without changing the scale of the bitmap.
381// This should be pixel-preserving.
382ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : fMatrix(matrix), fSink(sink) {}
383
384Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
385    Error err = fSink->draw(src, bitmap, stream, log);
386    if (!err.isEmpty()) {
387        return err;
388    }
389
390    SkMatrix inverse;
391    if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) {
392        return "Cannot upright --matrix.";
393    }
394    SkMatrix upright = SkMatrix::I();
395    upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX()));
396    upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY()));
397    upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX()));
398    upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY()));
399
400    SkBitmap uprighted;
401    SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height());
402    uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height()));
403
404    SkCanvas canvas(uprighted);
405    canvas.concat(upright);
406    SkPaint paint;
407    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
408    canvas.drawBitmap(*bitmap, 0, 0, &paint);
409
410    *bitmap = uprighted;
411    bitmap->lockPixels();
412    return "";
413}
414
415/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
416
417ViaPipe::ViaPipe(Sink* sink) : fSink(sink) {}
418
419Error ViaPipe::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
420    // We turn ourselves into another Src that draws our argument into bitmap/stream via pipe.
421    struct ProxySrc : public Src {
422        const Src& fSrc;
423        ProxySrc(const Src& src) : fSrc(src) {}
424
425        Error draw(SkCanvas* canvas) const SK_OVERRIDE {
426            SkISize size = this->size();
427            PipeController controller(canvas, &SkImageDecoder::DecodeMemory);
428            SkGPipeWriter pipe;
429            const uint32_t kFlags = 0; // We mirror SkDeferredCanvas, which doesn't use any flags.
430            return fSrc.draw(pipe.startRecording(&controller, kFlags, size.width(), size.height()));
431        }
432        SkISize size() const SK_OVERRIDE { return fSrc.size(); }
433        Name name() const SK_OVERRIDE { sk_throw(); return ""; }  // No one should be calling this.
434    } proxy(src);
435    return fSink->draw(proxy, bitmap, stream, log);
436}
437
438/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
439
440ViaSerialization::ViaSerialization(Sink* sink) : fSink(sink) {}
441
442Error ViaSerialization::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log)
443    const {
444    // Record our Src into a picture.
445    SkSize size;
446    size = src.size();
447    SkPictureRecorder recorder;
448    Error err = src.draw(recorder.beginRecording(size.width(), size.height()));
449    if (!err.isEmpty()) {
450        return err;
451    }
452    SkAutoTUnref<SkPicture> pic(recorder.endRecording());
453
454    // Serialize it and then deserialize it.
455    SkDynamicMemoryWStream wStream;
456    pic->serialize(&wStream);
457    SkAutoTDelete<SkStream> rStream(wStream.detachAsStream());
458    SkAutoTUnref<SkPicture> deserialized(SkPicture::CreateFromStream(rStream));
459
460    // Turn that deserialized picture into a Src, draw it into our Sink to fill bitmap or stream.
461    struct ProxySrc : public Src {
462        const SkPicture* fPic;
463        const SkISize fSize;
464        ProxySrc(const SkPicture* pic, SkISize size) : fPic(pic), fSize(size) {}
465
466        Error draw(SkCanvas* canvas) const SK_OVERRIDE {
467            canvas->drawPicture(fPic);
468            return "";
469        }
470        SkISize size() const SK_OVERRIDE { return fSize; }
471        Name name() const SK_OVERRIDE { sk_throw(); return ""; }  // No one should be calling this.
472    } proxy(deserialized, src.size());
473    return fSink->draw(proxy, bitmap, stream, log);
474}
475
476/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
477
478ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink)
479    : fW(w)
480    , fH(h)
481    , fFactory(factory)
482    , fSink(sink) {}
483
484Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
485    // Record our Src into a picture.
486    SkSize size;
487    size = src.size();
488    SkPictureRecorder recorder;
489    Error err = src.draw(recorder.beginRecording(size.width(), size.height(), fFactory.get()));
490    if (!err.isEmpty()) {
491        return err;
492    }
493    SkAutoTUnref<SkPicture> pic(recorder.endRecording());
494
495    // Turn that picture into a Src that draws into our Sink via tiles + MPD.
496    struct ProxySrc : public Src {
497        const int fW, fH;
498        const SkPicture* fPic;
499        const SkISize fSize;
500        ProxySrc(int w, int h, const SkPicture* pic, SkISize size)
501            : fW(w), fH(h), fPic(pic), fSize(size) {}
502
503        Error draw(SkCanvas* canvas) const SK_OVERRIDE {
504            const int xTiles = (fSize.width()  + fW - 1) / fW,
505                      yTiles = (fSize.height() + fH - 1) / fH;
506            SkMultiPictureDraw mpd(xTiles*yTiles);
507            SkTDArray<SkSurface*> surfaces;
508            surfaces.setReserve(xTiles*yTiles);
509
510            SkImageInfo info = canvas->imageInfo().makeWH(fW, fH);
511            for (int j = 0; j < yTiles; j++) {
512                for (int i = 0; i < xTiles; i++) {
513                    // This lets our ultimate Sink determine the best kind of surface.
514                    // E.g., if it's a GpuSink, the surfaces and images are textures.
515                    SkSurface* s = canvas->newSurface(info);
516                    if (!s) {
517                        s = SkSurface::NewRaster(info);  // Some canvases can't create surfaces.
518                    }
519                    surfaces.push(s);
520                    SkCanvas* c = s->getCanvas();
521                    c->translate(SkIntToScalar(-i * fW),
522                                 SkIntToScalar(-j * fH));  // Line up the canvas with this tile.
523                    mpd.add(c, fPic);
524                }
525            }
526            mpd.draw();
527            for (int j = 0; j < yTiles; j++) {
528                for (int i = 0; i < xTiles; i++) {
529                    SkAutoTUnref<SkImage> image(surfaces[i+xTiles*j]->newImageSnapshot());
530                    canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH));
531                }
532            }
533            surfaces.unrefAll();
534            return "";
535        }
536        SkISize size() const SK_OVERRIDE { return fSize; }
537        Name name() const SK_OVERRIDE { sk_throw(); return ""; }  // No one should be calling this.
538    } proxy(fW, fH, pic, src.size());
539    return fSink->draw(proxy, bitmap, stream, log);
540}
541
542}  // namespace DM
543