• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "dm/DMSrcSink.h"
9 #include "include/codec/SkAndroidCodec.h"
10 #include "include/codec/SkCodec.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkData.h"
13 #include "include/core/SkDeferredDisplayListRecorder.h"
14 #include "include/core/SkDocument.h"
15 #include "include/core/SkExecutor.h"
16 #include "include/core/SkImageGenerator.h"
17 #include "include/core/SkMallocPixelRef.h"
18 #include "include/core/SkMultiPictureDraw.h"
19 #include "include/core/SkPictureRecorder.h"
20 #include "include/core/SkStream.h"
21 #include "include/core/SkSurface.h"
22 #include "include/core/SkSurfaceCharacterization.h"
23 #include "include/docs/SkPDFDocument.h"
24 #include "include/gpu/GrBackendSurface.h"
25 #include "include/ports/SkImageGeneratorCG.h"
26 #include "include/ports/SkImageGeneratorWIC.h"
27 #include "include/private/SkImageInfoPriv.h"
28 #include "include/private/SkTLogic.h"
29 #include "include/third_party/skcms/skcms.h"
30 #include "include/utils/SkNullCanvas.h"
31 #include "include/utils/SkRandom.h"
32 #include "src/codec/SkCodecImageGenerator.h"
33 #include "src/codec/SkSwizzler.h"
34 #include "src/core/SkAutoMalloc.h"
35 #include "src/core/SkAutoPixmapStorage.h"
36 #include "src/core/SkMakeUnique.h"
37 #include "src/core/SkOSFile.h"
38 #include "src/core/SkOpts.h"
39 #include "src/core/SkPictureCommon.h"
40 #include "src/core/SkPictureData.h"
41 #include "src/core/SkRecordDraw.h"
42 #include "src/core/SkRecorder.h"
43 #include "src/core/SkTaskGroup.h"
44 #include "src/gpu/GrContextPriv.h"
45 #include "src/gpu/GrGpu.h"
46 #include "src/utils/SkMultiPictureDocumentPriv.h"
47 #include "src/utils/SkOSPath.h"
48 #include "tools/DDLPromiseImageHelper.h"
49 #include "tools/DDLTileHelper.h"
50 #include "tools/Resources.h"
51 #include "tools/debugger/DebugCanvas.h"
52 #include "tools/gpu/MemoryCache.h"
53 #if defined(SK_BUILD_FOR_WIN)
54     #include "include/docs/SkXPSDocument.h"
55     #include "src/utils/win/SkAutoCoInitialize.h"
56     #include "src/utils/win/SkHRESULT.h"
57     #include "src/utils/win/SkTScopedComPtr.h"
58     #include <XpsObjectModel.h>
59 #endif
60 
61 #if defined(SK_ENABLE_SKOTTIE)
62     #include "modules/skottie/include/Skottie.h"
63     #include "modules/skottie/utils/SkottieUtils.h"
64 #endif
65 
66 #if defined(SK_XML)
67     #include "experimental/svg/model/SkSVGDOM.h"
68     #include "include/svg/SkSVGCanvas.h"
69     #include "src/xml/SkXMLWriter.h"
70 #endif
71 #include "tests/TestUtils.h"
72 
73 #include <cmath>
74 #include <functional>
75 
76 static DEFINE_bool(multiPage, false,
77                    "For document-type backends, render the source into multiple pages");
78 static DEFINE_bool(RAW_threading, true, "Allow RAW decodes to run on multiple threads?");
79 
80 DECLARE_int(gpuThreads);
81 
82 using sk_gpu_test::GrContextFactory;
83 
84 namespace DM {
85 
GMSrc(skiagm::GMFactory factory)86 GMSrc::GMSrc(skiagm::GMFactory factory) : fFactory(factory) {}
87 
draw(SkCanvas * canvas) const88 Error GMSrc::draw(SkCanvas* canvas) const {
89     std::unique_ptr<skiagm::GM> gm(fFactory());
90     SkString errorMsg;
91     skiagm::DrawResult drawResult = gm->draw(canvas, &errorMsg);
92     if (skiagm::DrawResult::kSkip == drawResult) {
93         return Error::Nonfatal(std::move(errorMsg));  // Cause this test to be skipped.
94     }
95     return errorMsg;
96 }
97 
size() const98 SkISize GMSrc::size() const {
99     std::unique_ptr<skiagm::GM> gm(fFactory());
100     return gm->getISize();
101 }
102 
name() const103 Name GMSrc::name() const {
104     std::unique_ptr<skiagm::GM> gm(fFactory());
105     return gm->getName();
106 }
107 
modifyGrContextOptions(GrContextOptions * options) const108 void GMSrc::modifyGrContextOptions(GrContextOptions* options) const {
109     std::unique_ptr<skiagm::GM> gm(fFactory());
110     gm->modifyGrContextOptions(options);
111 }
112 
113 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
114 
BRDSrc(Path path,Mode mode,CodecSrc::DstColorType dstColorType,uint32_t sampleSize)115 BRDSrc::BRDSrc(Path path, Mode mode, CodecSrc::DstColorType dstColorType, uint32_t sampleSize)
116     : fPath(path)
117     , fMode(mode)
118     , fDstColorType(dstColorType)
119     , fSampleSize(sampleSize)
120 {}
121 
veto(SinkFlags flags) const122 bool BRDSrc::veto(SinkFlags flags) const {
123     // No need to test to non-raster or indirect backends.
124     return flags.type != SinkFlags::kRaster
125         || flags.approach != SinkFlags::kDirect;
126 }
127 
create_brd(Path path)128 static SkBitmapRegionDecoder* create_brd(Path path) {
129     sk_sp<SkData> encoded(SkData::MakeFromFileName(path.c_str()));
130     if (!encoded) {
131         return nullptr;
132     }
133     return SkBitmapRegionDecoder::Create(encoded, SkBitmapRegionDecoder::kAndroidCodec_Strategy);
134 }
135 
alpha8_to_gray8(SkBitmap * bitmap)136 static inline void alpha8_to_gray8(SkBitmap* bitmap) {
137     // Android requires kGray8 bitmaps to be tagged as kAlpha8.  Here we convert
138     // them back to kGray8 so our test framework can draw them correctly.
139     if (kAlpha_8_SkColorType == bitmap->info().colorType()) {
140         SkImageInfo newInfo = bitmap->info().makeColorType(kGray_8_SkColorType)
141                                             .makeAlphaType(kOpaque_SkAlphaType);
142         *const_cast<SkImageInfo*>(&bitmap->info()) = newInfo;
143     }
144 }
145 
draw(SkCanvas * canvas) const146 Error BRDSrc::draw(SkCanvas* canvas) const {
147     SkColorType colorType = canvas->imageInfo().colorType();
148     if (kRGB_565_SkColorType == colorType &&
149             CodecSrc::kGetFromCanvas_DstColorType != fDstColorType) {
150         return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
151     }
152     switch (fDstColorType) {
153         case CodecSrc::kGetFromCanvas_DstColorType:
154             break;
155         case CodecSrc::kGrayscale_Always_DstColorType:
156             colorType = kGray_8_SkColorType;
157             break;
158         default:
159             SkASSERT(false);
160             break;
161     }
162 
163     std::unique_ptr<SkBitmapRegionDecoder> brd(create_brd(fPath));
164     if (nullptr == brd.get()) {
165         return Error::Nonfatal(SkStringPrintf("Could not create brd for %s.", fPath.c_str()));
166     }
167 
168     auto recommendedCT = brd->computeOutputColorType(colorType);
169     if (kRGB_565_SkColorType == colorType && recommendedCT != colorType) {
170         return Error::Nonfatal("Skip decoding non-opaque to 565.");
171     }
172     colorType = recommendedCT;
173 
174     auto colorSpace = brd->computeOutputColorSpace(colorType, nullptr);
175 
176     const uint32_t width = brd->width();
177     const uint32_t height = brd->height();
178     // Visually inspecting very small output images is not necessary.
179     if ((width / fSampleSize <= 10 || height / fSampleSize <= 10) && 1 != fSampleSize) {
180         return Error::Nonfatal("Scaling very small images is uninteresting.");
181     }
182     switch (fMode) {
183         case kFullImage_Mode: {
184             SkBitmap bitmap;
185             if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(0, 0, width, height),
186                     fSampleSize, colorType, false, colorSpace)) {
187                 return "Cannot decode (full) region.";
188             }
189             alpha8_to_gray8(&bitmap);
190 
191             canvas->drawBitmap(bitmap, 0, 0);
192             return "";
193         }
194         case kDivisor_Mode: {
195             const uint32_t divisor = 2;
196             if (width < divisor || height < divisor) {
197                 return Error::Nonfatal("Divisor is larger than image dimension.");
198             }
199 
200             // Use a border to test subsets that extend outside the image.
201             // We will not allow the border to be larger than the image dimensions.  Allowing
202             // these large borders causes off by one errors that indicate a problem with the
203             // test suite, not a problem with the implementation.
204             const uint32_t maxBorder = SkTMin(width, height) / (fSampleSize * divisor);
205             const uint32_t scaledBorder = SkTMin(5u, maxBorder);
206             const uint32_t unscaledBorder = scaledBorder * fSampleSize;
207 
208             // We may need to clear the canvas to avoid uninitialized memory.
209             // Assume we are scaling a 780x780 image with sampleSize = 8.
210             // The output image should be 97x97.
211             // Each subset will be 390x390.
212             // Each scaled subset be 48x48.
213             // Four scaled subsets will only fill a 96x96 image.
214             // The bottom row and last column will not be touched.
215             // This is an unfortunate result of our rounding rules when scaling.
216             // Maybe we need to consider testing scaled subsets without trying to
217             // combine them to match the full scaled image?  Or maybe this is the
218             // best we can do?
219             canvas->clear(0);
220 
221             for (uint32_t x = 0; x < divisor; x++) {
222                 for (uint32_t y = 0; y < divisor; y++) {
223                     // Calculate the subset dimensions
224                     uint32_t subsetWidth = width / divisor;
225                     uint32_t subsetHeight = height / divisor;
226                     const int left = x * subsetWidth;
227                     const int top = y * subsetHeight;
228 
229                     // Increase the size of the last subset in each row or column, when the
230                     // divisor does not divide evenly into the image dimensions
231                     subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0;
232                     subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0;
233 
234                     // Increase the size of the subset in order to have a border on each side
235                     const int decodeLeft = left - unscaledBorder;
236                     const int decodeTop = top - unscaledBorder;
237                     const uint32_t decodeWidth = subsetWidth + unscaledBorder * 2;
238                     const uint32_t decodeHeight = subsetHeight + unscaledBorder * 2;
239                     SkBitmap bitmap;
240                     if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(decodeLeft,
241                             decodeTop, decodeWidth, decodeHeight), fSampleSize, colorType, false,
242                             colorSpace)) {
243                         return "Cannot decode region.";
244                     }
245 
246                     alpha8_to_gray8(&bitmap);
247                     canvas->drawBitmapRect(bitmap,
248                             SkRect::MakeXYWH((SkScalar) scaledBorder, (SkScalar) scaledBorder,
249                                     (SkScalar) (subsetWidth / fSampleSize),
250                                     (SkScalar) (subsetHeight / fSampleSize)),
251                             SkRect::MakeXYWH((SkScalar) (left / fSampleSize),
252                                     (SkScalar) (top / fSampleSize),
253                                     (SkScalar) (subsetWidth / fSampleSize),
254                                     (SkScalar) (subsetHeight / fSampleSize)),
255                             nullptr);
256                 }
257             }
258             return "";
259         }
260         default:
261             SkASSERT(false);
262             return "Error: Should not be reached.";
263     }
264 }
265 
size() const266 SkISize BRDSrc::size() const {
267     std::unique_ptr<SkBitmapRegionDecoder> brd(create_brd(fPath));
268     if (brd) {
269         return {SkTMax(1, brd->width() / (int)fSampleSize),
270                 SkTMax(1, brd->height() / (int)fSampleSize)};
271     }
272     return {0, 0};
273 }
274 
get_scaled_name(const Path & path,float scale)275 static SkString get_scaled_name(const Path& path, float scale) {
276     return SkStringPrintf("%s_%.3f", SkOSPath::Basename(path.c_str()).c_str(), scale);
277 }
278 
name() const279 Name BRDSrc::name() const {
280     // We will replicate the names used by CodecSrc so that images can
281     // be compared in Gold.
282     if (1 == fSampleSize) {
283         return SkOSPath::Basename(fPath.c_str());
284     }
285     return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
286 }
287 
288 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
289 
serial_from_path_name(const SkString & path)290 static bool serial_from_path_name(const SkString& path) {
291     if (!FLAGS_RAW_threading) {
292         static const char* const exts[] = {
293             "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw",
294             "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW",
295         };
296         const char* actualExt = strrchr(path.c_str(), '.');
297         if (actualExt) {
298             actualExt++;
299             for (auto* ext : exts) {
300                 if (0 == strcmp(ext, actualExt)) {
301                     return true;
302                 }
303             }
304         }
305     }
306     return false;
307 }
308 
CodecSrc(Path path,Mode mode,DstColorType dstColorType,SkAlphaType dstAlphaType,float scale)309 CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, SkAlphaType dstAlphaType,
310                    float scale)
311     : fPath(path)
312     , fMode(mode)
313     , fDstColorType(dstColorType)
314     , fDstAlphaType(dstAlphaType)
315     , fScale(scale)
316     , fRunSerially(serial_from_path_name(path))
317 {}
318 
veto(SinkFlags flags) const319 bool CodecSrc::veto(SinkFlags flags) const {
320     // Test to direct raster backends (8888 and 565).
321     return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
322 }
323 
324 // Allows us to test decodes to non-native 8888.
swap_rb_if_necessary(SkBitmap & bitmap,CodecSrc::DstColorType dstColorType)325 static void swap_rb_if_necessary(SkBitmap& bitmap, CodecSrc::DstColorType dstColorType) {
326     if (CodecSrc::kNonNative8888_Always_DstColorType != dstColorType) {
327         return;
328     }
329 
330     for (int y = 0; y < bitmap.height(); y++) {
331         uint32_t* row = (uint32_t*) bitmap.getAddr(0, y);
332         SkOpts::RGBA_to_BGRA(row, row, bitmap.width());
333     }
334 }
335 
get_decode_info(SkImageInfo * decodeInfo,SkColorType canvasColorType,CodecSrc::DstColorType dstColorType,SkAlphaType dstAlphaType)336 static bool get_decode_info(SkImageInfo* decodeInfo, SkColorType canvasColorType,
337                             CodecSrc::DstColorType dstColorType, SkAlphaType dstAlphaType) {
338     switch (dstColorType) {
339         case CodecSrc::kGrayscale_Always_DstColorType:
340             if (kRGB_565_SkColorType == canvasColorType) {
341                 return false;
342             }
343             *decodeInfo = decodeInfo->makeColorType(kGray_8_SkColorType);
344             break;
345         case CodecSrc::kNonNative8888_Always_DstColorType:
346             if (kRGB_565_SkColorType == canvasColorType
347                     || kRGBA_F16_SkColorType == canvasColorType) {
348                 return false;
349             }
350 #ifdef SK_PMCOLOR_IS_RGBA
351             *decodeInfo = decodeInfo->makeColorType(kBGRA_8888_SkColorType);
352 #else
353             *decodeInfo = decodeInfo->makeColorType(kRGBA_8888_SkColorType);
354 #endif
355             break;
356         default:
357             if (kRGB_565_SkColorType == canvasColorType &&
358                     kOpaque_SkAlphaType != decodeInfo->alphaType()) {
359                 return false;
360             }
361 
362             *decodeInfo = decodeInfo->makeColorType(canvasColorType);
363             break;
364     }
365 
366     *decodeInfo = decodeInfo->makeAlphaType(dstAlphaType);
367     return true;
368 }
369 
draw_to_canvas(SkCanvas * canvas,const SkImageInfo & info,void * pixels,size_t rowBytes,CodecSrc::DstColorType dstColorType,SkScalar left=0,SkScalar top=0)370 static void draw_to_canvas(SkCanvas* canvas, const SkImageInfo& info, void* pixels, size_t rowBytes,
371                            CodecSrc::DstColorType dstColorType,
372                            SkScalar left = 0, SkScalar top = 0) {
373     SkBitmap bitmap;
374     bitmap.installPixels(info, pixels, rowBytes);
375     swap_rb_if_necessary(bitmap, dstColorType);
376     canvas->drawBitmap(bitmap, left, top);
377 }
378 
379 // For codec srcs, we want the "draw" step to be a memcpy.  Any interesting color space or
380 // color format conversions should be performed by the codec.  Sometimes the output of the
381 // decode will be in an interesting color space.  On our srgb and f16 backends, we need to
382 // "pretend" that the color space is standard sRGB to avoid triggering color conversion
383 // at draw time.
set_bitmap_color_space(SkImageInfo * info)384 static void set_bitmap_color_space(SkImageInfo* info) {
385     *info = info->makeColorSpace(SkColorSpace::MakeSRGB());
386 }
387 
draw(SkCanvas * canvas) const388 Error CodecSrc::draw(SkCanvas* canvas) const {
389     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
390     if (!encoded) {
391         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
392     }
393 
394     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
395     if (nullptr == codec.get()) {
396         return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
397     }
398 
399     SkImageInfo decodeInfo = codec->getInfo();
400     if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType,
401                          fDstAlphaType)) {
402         return Error::Nonfatal("Skipping uninteresting test.");
403     }
404 
405     // Try to scale the image if it is desired
406     SkISize size = codec->getScaledDimensions(fScale);
407     if (size == decodeInfo.dimensions() && 1.0f != fScale) {
408         return Error::Nonfatal("Test without scaling is uninteresting.");
409     }
410 
411     // Visually inspecting very small output images is not necessary.  We will
412     // cover these cases in unit testing.
413     if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) {
414         return Error::Nonfatal("Scaling very small images is uninteresting.");
415     }
416     decodeInfo = decodeInfo.makeWH(size.width(), size.height());
417 
418     const int bpp = decodeInfo.bytesPerPixel();
419     const size_t rowBytes = size.width() * bpp;
420     const size_t safeSize = decodeInfo.computeByteSize(rowBytes);
421     SkAutoMalloc pixels(safeSize);
422 
423     SkCodec::Options options;
424     if (kCodecZeroInit_Mode == fMode) {
425         memset(pixels.get(), 0, size.height() * rowBytes);
426         options.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
427     }
428 
429     SkImageInfo bitmapInfo = decodeInfo;
430     set_bitmap_color_space(&bitmapInfo);
431     if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
432             kBGRA_8888_SkColorType == decodeInfo.colorType()) {
433         bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
434     }
435 
436     switch (fMode) {
437         case kAnimated_Mode: {
438             std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo();
439             if (frameInfos.size() <= 1) {
440                 return SkStringPrintf("%s is not an animated image.", fPath.c_str());
441             }
442 
443             // As in CodecSrc::size(), compute a roughly square grid to draw the frames
444             // into. "factor" is the number of frames to draw on one row. There will be
445             // up to "factor" rows as well.
446             const float root = sqrt((float) frameInfos.size());
447             const int factor = sk_float_ceil2int(root);
448 
449             // Used to cache a frame that future frames will depend on.
450             SkAutoMalloc priorFramePixels;
451             int cachedFrame = SkCodec::kNoFrame;
452             for (int i = 0; static_cast<size_t>(i) < frameInfos.size(); i++) {
453                 options.fFrameIndex = i;
454                 // Check for a prior frame
455                 const int reqFrame = frameInfos[i].fRequiredFrame;
456                 if (reqFrame != SkCodec::kNoFrame && reqFrame == cachedFrame
457                         && priorFramePixels.get()) {
458                     // Copy into pixels
459                     memcpy(pixels.get(), priorFramePixels.get(), safeSize);
460                     options.fPriorFrame = reqFrame;
461                 } else {
462                     options.fPriorFrame = SkCodec::kNoFrame;
463                 }
464                 SkCodec::Result result = codec->getPixels(decodeInfo, pixels.get(),
465                                                           rowBytes, &options);
466                 if (SkCodec::kInvalidInput == result && i > 0) {
467                     // Some of our test images have truncated later frames. Treat that
468                     // the same as incomplete.
469                     result = SkCodec::kIncompleteInput;
470                 }
471                 switch (result) {
472                     case SkCodec::kSuccess:
473                     case SkCodec::kErrorInInput:
474                     case SkCodec::kIncompleteInput: {
475                         // If the next frame depends on this one, store it in priorFrame.
476                         // It is possible that we may discard a frame that future frames depend on,
477                         // but the codec will simply redecode the discarded frame.
478                         // Do this before calling draw_to_canvas, which premultiplies in place. If
479                         // we're decoding to unpremul, we want to pass the unmodified frame to the
480                         // codec for decoding the next frame.
481                         if (static_cast<size_t>(i+1) < frameInfos.size()
482                                 && frameInfos[i+1].fRequiredFrame == i) {
483                             memcpy(priorFramePixels.reset(safeSize), pixels.get(), safeSize);
484                             cachedFrame = i;
485                         }
486 
487                         SkAutoCanvasRestore acr(canvas, true);
488                         const int xTranslate = (i % factor) * decodeInfo.width();
489                         const int yTranslate = (i / factor) * decodeInfo.height();
490                         canvas->translate(SkIntToScalar(xTranslate), SkIntToScalar(yTranslate));
491                         draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
492                         if (result != SkCodec::kSuccess) {
493                             return "";
494                         }
495                         break;
496                     }
497                     case SkCodec::kInvalidConversion:
498                         if (i > 0 && (decodeInfo.colorType() == kRGB_565_SkColorType)) {
499                             return Error::Nonfatal(SkStringPrintf(
500                                 "Cannot decode frame %i to 565 (%s).", i, fPath.c_str()));
501                         }
502                         // Fall through.
503                     default:
504                         return SkStringPrintf("Couldn't getPixels for frame %i in %s.",
505                                               i, fPath.c_str());
506                 }
507             }
508             break;
509         }
510         case kCodecZeroInit_Mode:
511         case kCodec_Mode: {
512             switch (codec->getPixels(decodeInfo, pixels.get(), rowBytes, &options)) {
513                 case SkCodec::kSuccess:
514                     // We consider these to be valid, since we should still decode what is
515                     // available.
516                 case SkCodec::kErrorInInput:
517                 case SkCodec::kIncompleteInput:
518                     break;
519                 default:
520                     // Everything else is considered a failure.
521                     return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
522             }
523 
524             draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
525             break;
526         }
527         case kScanline_Mode: {
528             void* dst = pixels.get();
529             uint32_t height = decodeInfo.height();
530             const bool useIncremental = [this]() {
531                 auto exts = { "png", "PNG", "gif", "GIF" };
532                 for (auto ext : exts) {
533                     if (fPath.endsWith(ext)) {
534                         return true;
535                     }
536                 }
537                 return false;
538             }();
539             // ico may use the old scanline method or the new one, depending on whether it
540             // internally holds a bmp or a png.
541             const bool ico = fPath.endsWith("ico");
542             bool useOldScanlineMethod = !useIncremental && !ico;
543             if (useIncremental || ico) {
544                 if (SkCodec::kSuccess == codec->startIncrementalDecode(decodeInfo, dst,
545                         rowBytes, &options)) {
546                     int rowsDecoded;
547                     auto result = codec->incrementalDecode(&rowsDecoded);
548                     if (SkCodec::kIncompleteInput == result || SkCodec::kErrorInInput == result) {
549                         codec->fillIncompleteImage(decodeInfo, dst, rowBytes,
550                                                    SkCodec::kNo_ZeroInitialized, height,
551                                                    rowsDecoded);
552                     }
553                 } else {
554                     if (useIncremental) {
555                         // Error: These should support incremental decode.
556                         return "Could not start incremental decode";
557                     }
558                     // Otherwise, this is an ICO. Since incremental failed, it must contain a BMP,
559                     // which should work via startScanlineDecode
560                     useOldScanlineMethod = true;
561                 }
562             }
563 
564             if (useOldScanlineMethod) {
565                 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo)) {
566                     return "Could not start scanline decoder";
567                 }
568 
569                 // We do not need to check the return value.  On an incomplete
570                 // image, memory will be filled with a default value.
571                 codec->getScanlines(dst, height, rowBytes);
572             }
573 
574             draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, fDstColorType);
575             break;
576         }
577         case kStripe_Mode: {
578             const int height = decodeInfo.height();
579             // This value is chosen arbitrarily.  We exercise more cases by choosing a value that
580             // does not align with image blocks.
581             const int stripeHeight = 37;
582             const int numStripes = (height + stripeHeight - 1) / stripeHeight;
583             void* dst = pixels.get();
584 
585             // Decode odd stripes
586             if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &options)) {
587                 return "Could not start scanline decoder";
588             }
589 
590             // This mode was designed to test the new skip scanlines API in libjpeg-turbo.
591             // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting
592             // to run this test for image types that do not have this scanline ordering.
593             // We only run this on Jpeg, which is always kTopDown.
594             SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder());
595 
596             for (int i = 0; i < numStripes; i += 2) {
597                 // Skip a stripe
598                 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight);
599                 codec->skipScanlines(linesToSkip);
600 
601                 // Read a stripe
602                 const int startY = (i + 1) * stripeHeight;
603                 const int linesToRead = SkTMin(stripeHeight, height - startY);
604                 if (linesToRead > 0) {
605                     codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead,
606                                         rowBytes);
607                 }
608             }
609 
610             // Decode even stripes
611             const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo);
612             if (SkCodec::kSuccess != startResult) {
613                 return "Failed to restart scanline decoder with same parameters.";
614             }
615             for (int i = 0; i < numStripes; i += 2) {
616                 // Read a stripe
617                 const int startY = i * stripeHeight;
618                 const int linesToRead = SkTMin(stripeHeight, height - startY);
619                 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead,
620                                     rowBytes);
621 
622                 // Skip a stripe
623                 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight);
624                 if (linesToSkip > 0) {
625                     codec->skipScanlines(linesToSkip);
626                 }
627             }
628 
629             draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, fDstColorType);
630             break;
631         }
632         case kCroppedScanline_Mode: {
633             const int width = decodeInfo.width();
634             const int height = decodeInfo.height();
635             // This value is chosen because, as we move across the image, it will sometimes
636             // align with the jpeg block sizes and it will sometimes not.  This allows us
637             // to test interestingly different code paths in the implementation.
638             const int tileSize = 36;
639             SkIRect subset;
640             for (int x = 0; x < width; x += tileSize) {
641                 subset = SkIRect::MakeXYWH(x, 0, SkTMin(tileSize, width - x), height);
642                 options.fSubset = &subset;
643                 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &options)) {
644                     return "Could not start scanline decoder.";
645                 }
646 
647                 codec->getScanlines(SkTAddOffset<void>(pixels.get(), x * bpp), height, rowBytes);
648             }
649 
650             draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
651             break;
652         }
653         case kSubset_Mode: {
654             // Arbitrarily choose a divisor.
655             int divisor = 2;
656             // Total width/height of the image.
657             const int W = codec->getInfo().width();
658             const int H = codec->getInfo().height();
659             if (divisor > W || divisor > H) {
660                 return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divisor %d is too big "
661                                                       "for %s with dimensions (%d x %d)", divisor,
662                                                       fPath.c_str(), W, H));
663             }
664             // subset dimensions
665             // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
666             const int w = SkAlign2(W / divisor);
667             const int h = SkAlign2(H / divisor);
668             SkIRect subset;
669             options.fSubset = &subset;
670             SkBitmap subsetBm;
671             // We will reuse pixel memory from bitmap.
672             void* dst = pixels.get();
673             // Keep track of left and top (for drawing subsetBm into canvas). We could use
674             // fScale * x and fScale * y, but we want integers such that the next subset will start
675             // where the last one ended. So we'll add decodeInfo.width() and height().
676             int left = 0;
677             for (int x = 0; x < W; x += w) {
678                 int top = 0;
679                 for (int y = 0; y < H; y+= h) {
680                     // Do not make the subset go off the edge of the image.
681                     const int preScaleW = SkTMin(w, W - x);
682                     const int preScaleH = SkTMin(h, H - y);
683                     subset.setXYWH(x, y, preScaleW, preScaleH);
684                     // And scale
685                     // FIXME: Should we have a version of getScaledDimensions that takes a subset
686                     // into account?
687                     const int scaledW = SkTMax(1, SkScalarRoundToInt(preScaleW * fScale));
688                     const int scaledH = SkTMax(1, SkScalarRoundToInt(preScaleH * fScale));
689                     decodeInfo = decodeInfo.makeWH(scaledW, scaledH);
690                     SkImageInfo subsetBitmapInfo = bitmapInfo.makeWH(scaledW, scaledH);
691                     size_t subsetRowBytes = subsetBitmapInfo.minRowBytes();
692                     const SkCodec::Result result = codec->getPixels(decodeInfo, dst, subsetRowBytes,
693                             &options);
694                     switch (result) {
695                         case SkCodec::kSuccess:
696                         case SkCodec::kErrorInInput:
697                         case SkCodec::kIncompleteInput:
698                             break;
699                         default:
700                             return SkStringPrintf("subset codec failed to decode (%d, %d, %d, %d) "
701                                                   "from %s with dimensions (%d x %d)\t error %d",
702                                                   x, y, decodeInfo.width(), decodeInfo.height(),
703                                                   fPath.c_str(), W, H, result);
704                     }
705                     draw_to_canvas(canvas, subsetBitmapInfo, dst, subsetRowBytes, fDstColorType,
706                                    SkIntToScalar(left), SkIntToScalar(top));
707 
708                     // translate by the scaled height.
709                     top += decodeInfo.height();
710                 }
711                 // translate by the scaled width.
712                 left += decodeInfo.width();
713             }
714             return "";
715         }
716         default:
717             SkASSERT(false);
718             return "Invalid fMode";
719     }
720     return "";
721 }
722 
size() const723 SkISize CodecSrc::size() const {
724     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
725     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
726     if (nullptr == codec) {
727         return {0, 0};
728     }
729 
730     auto imageSize = codec->getScaledDimensions(fScale);
731     if (fMode == kAnimated_Mode) {
732         // We'll draw one of each frame, so make it big enough to hold them all
733         // in a grid. The grid will be roughly square, with "factor" frames per
734         // row and up to "factor" rows.
735         const size_t count = codec->getFrameInfo().size();
736         const float root = sqrt((float) count);
737         const int factor = sk_float_ceil2int(root);
738         imageSize.fWidth  = imageSize.fWidth  * factor;
739         imageSize.fHeight = imageSize.fHeight * sk_float_ceil2int((float) count / (float) factor);
740     }
741     return imageSize;
742 }
743 
name() const744 Name CodecSrc::name() const {
745     if (1.0f == fScale) {
746         Name name = SkOSPath::Basename(fPath.c_str());
747         if (fMode == kAnimated_Mode) {
748             name.append("_animated");
749         }
750         return name;
751     }
752     SkASSERT(fMode != kAnimated_Mode);
753     return get_scaled_name(fPath, fScale);
754 }
755 
756 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
757 
AndroidCodecSrc(Path path,CodecSrc::DstColorType dstColorType,SkAlphaType dstAlphaType,int sampleSize)758 AndroidCodecSrc::AndroidCodecSrc(Path path, CodecSrc::DstColorType dstColorType,
759         SkAlphaType dstAlphaType, int sampleSize)
760     : fPath(path)
761     , fDstColorType(dstColorType)
762     , fDstAlphaType(dstAlphaType)
763     , fSampleSize(sampleSize)
764     , fRunSerially(serial_from_path_name(path))
765 {}
766 
veto(SinkFlags flags) const767 bool AndroidCodecSrc::veto(SinkFlags flags) const {
768     // No need to test decoding to non-raster or indirect backend.
769     return flags.type != SinkFlags::kRaster
770         || flags.approach != SinkFlags::kDirect;
771 }
772 
draw(SkCanvas * canvas) const773 Error AndroidCodecSrc::draw(SkCanvas* canvas) const {
774     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
775     if (!encoded) {
776         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
777     }
778     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromData(encoded));
779     if (nullptr == codec) {
780         return SkStringPrintf("Couldn't create android codec for %s.", fPath.c_str());
781     }
782 
783     SkImageInfo decodeInfo = codec->getInfo();
784     if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType,
785                          fDstAlphaType)) {
786         return Error::Nonfatal("Skipping uninteresting test.");
787     }
788 
789     // Scale the image if it is desired.
790     SkISize size = codec->getSampledDimensions(fSampleSize);
791 
792     // Visually inspecting very small output images is not necessary.  We will
793     // cover these cases in unit testing.
794     if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) {
795         return Error::Nonfatal("Scaling very small images is uninteresting.");
796     }
797     decodeInfo = decodeInfo.makeWH(size.width(), size.height());
798 
799     int bpp = decodeInfo.bytesPerPixel();
800     size_t rowBytes = size.width() * bpp;
801     SkAutoMalloc pixels(size.height() * rowBytes);
802 
803     SkBitmap bitmap;
804     SkImageInfo bitmapInfo = decodeInfo;
805     set_bitmap_color_space(&bitmapInfo);
806     if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
807             kBGRA_8888_SkColorType == decodeInfo.colorType()) {
808         bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
809     }
810 
811     // Create options for the codec.
812     SkAndroidCodec::AndroidOptions options;
813     options.fSampleSize = fSampleSize;
814 
815     switch (codec->getAndroidPixels(decodeInfo, pixels.get(), rowBytes, &options)) {
816         case SkCodec::kSuccess:
817         case SkCodec::kErrorInInput:
818         case SkCodec::kIncompleteInput:
819             break;
820         default:
821             return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
822     }
823     draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
824     return "";
825 }
826 
size() const827 SkISize AndroidCodecSrc::size() const {
828     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
829     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromData(encoded));
830     if (nullptr == codec) {
831         return {0, 0};
832     }
833     return codec->getSampledDimensions(fSampleSize);
834 }
835 
name() const836 Name AndroidCodecSrc::name() const {
837     // We will replicate the names used by CodecSrc so that images can
838     // be compared in Gold.
839     if (1 == fSampleSize) {
840         return SkOSPath::Basename(fPath.c_str());
841     }
842     return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
843 }
844 
845 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
846 
ImageGenSrc(Path path,Mode mode,SkAlphaType alphaType,bool isGpu)847 ImageGenSrc::ImageGenSrc(Path path, Mode mode, SkAlphaType alphaType, bool isGpu)
848     : fPath(path)
849     , fMode(mode)
850     , fDstAlphaType(alphaType)
851     , fIsGpu(isGpu)
852     , fRunSerially(serial_from_path_name(path))
853 {}
854 
veto(SinkFlags flags) const855 bool ImageGenSrc::veto(SinkFlags flags) const {
856     if (fIsGpu) {
857         // MSAA runs tend to run out of memory and tests the same code paths as regular gpu configs.
858         return flags.type != SinkFlags::kGPU || flags.approach != SinkFlags::kDirect ||
859                flags.multisampled == SinkFlags::kMultisampled;
860     }
861 
862     return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
863 }
864 
draw(SkCanvas * canvas) const865 Error ImageGenSrc::draw(SkCanvas* canvas) const {
866     if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) {
867         return Error::Nonfatal("Uninteresting to test image generator to 565.");
868     }
869 
870     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
871     if (!encoded) {
872         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
873     }
874 
875 #if defined(SK_BUILD_FOR_WIN)
876     // Initialize COM in order to test with WIC.
877     SkAutoCoInitialize com;
878     if (!com.succeeded()) {
879         return "Could not initialize COM.";
880     }
881 #endif
882 
883     std::unique_ptr<SkImageGenerator> gen(nullptr);
884     switch (fMode) {
885         case kCodec_Mode:
886             gen = SkCodecImageGenerator::MakeFromEncodedCodec(encoded);
887             if (!gen) {
888                 return "Could not create codec image generator.";
889             }
890             break;
891         case kPlatform_Mode: {
892 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
893             gen = SkImageGeneratorCG::MakeFromEncodedCG(encoded);
894 #elif defined(SK_BUILD_FOR_WIN)
895             gen = SkImageGeneratorWIC::MakeFromEncodedWIC(encoded);
896 #endif
897             if (!gen) {
898                 return "Could not create platform image generator.";
899             }
900             break;
901         }
902         default:
903             SkASSERT(false);
904             return "Invalid image generator mode";
905     }
906 
907     // Test deferred decoding path on GPU
908     if (fIsGpu) {
909         sk_sp<SkImage> image(SkImage::MakeFromGenerator(std::move(gen), nullptr));
910         if (!image) {
911             return "Could not create image from codec image generator.";
912         }
913         canvas->drawImage(image, 0, 0);
914         return "";
915     }
916 
917     // Test various color and alpha types on CPU
918     SkImageInfo decodeInfo = gen->getInfo().makeAlphaType(fDstAlphaType);
919 
920     int bpp = decodeInfo.bytesPerPixel();
921     size_t rowBytes = decodeInfo.width() * bpp;
922     SkAutoMalloc pixels(decodeInfo.height() * rowBytes);
923     if (!gen->getPixels(decodeInfo, pixels.get(), rowBytes)) {
924         SkString err =
925                 SkStringPrintf("Image generator could not getPixels() for %s\n", fPath.c_str());
926 
927 #if defined(SK_BUILD_FOR_WIN)
928         if (kPlatform_Mode == fMode) {
929             // Do not issue a fatal error for WIC flakiness.
930             return Error::Nonfatal(err);
931         }
932 #endif
933 
934         return err;
935     }
936 
937     set_bitmap_color_space(&decodeInfo);
938     draw_to_canvas(canvas, decodeInfo, pixels.get(), rowBytes,
939                    CodecSrc::kGetFromCanvas_DstColorType);
940     return "";
941 }
942 
size() const943 SkISize ImageGenSrc::size() const {
944     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
945     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
946     if (nullptr == codec) {
947         return {0, 0};
948     }
949     return codec->getInfo().dimensions();
950 }
951 
name() const952 Name ImageGenSrc::name() const {
953     return SkOSPath::Basename(fPath.c_str());
954 }
955 
956 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
957 
ColorCodecSrc(Path path,bool decode_to_dst)958 ColorCodecSrc::ColorCodecSrc(Path path, bool decode_to_dst) : fPath(path)
959                                                             , fDecodeToDst(decode_to_dst) {}
960 
veto(SinkFlags flags) const961 bool ColorCodecSrc::veto(SinkFlags flags) const {
962     // Test to direct raster backends (8888 and 565).
963     return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
964 }
965 
draw(SkCanvas * canvas) const966 Error ColorCodecSrc::draw(SkCanvas* canvas) const {
967     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
968     if (!encoded) {
969         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
970     }
971 
972     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
973     if (nullptr == codec) {
974         return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
975     }
976 
977     SkImageInfo info = codec->getInfo();
978     if (fDecodeToDst) {
979         info = canvas->imageInfo().makeWH(info.width(),
980                                           info.height());
981     }
982 
983     SkBitmap bitmap;
984     if (!bitmap.tryAllocPixels(info)) {
985         return SkStringPrintf("Image(%s) is too large (%d x %d)",
986                               fPath.c_str(), info.width(), info.height());
987     }
988 
989     switch (auto r = codec->getPixels(info, bitmap.getPixels(), bitmap.rowBytes())) {
990         case SkCodec::kSuccess:
991         case SkCodec::kErrorInInput:
992         case SkCodec::kIncompleteInput:
993             canvas->drawBitmap(bitmap, 0,0);
994             return "";
995         case SkCodec::kInvalidConversion:
996             // TODO(mtklein): why are there formats we can't decode to?
997             return Error::Nonfatal("SkCodec can't decode to this format.");
998         default:
999             return SkStringPrintf("Couldn't getPixels %s. Error code %d", fPath.c_str(), r);
1000     }
1001 }
1002 
size() const1003 SkISize ColorCodecSrc::size() const {
1004     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
1005     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
1006     if (nullptr == codec) {
1007         return {0, 0};
1008     }
1009     return {codec->getInfo().width(), codec->getInfo().height()};
1010 }
1011 
name() const1012 Name ColorCodecSrc::name() const {
1013     return SkOSPath::Basename(fPath.c_str());
1014 }
1015 
1016 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1017 
1018 static DEFINE_int(skpViewportSize, 1000,
1019                   "Width & height of the viewport used to crop skp rendering.");
1020 
SKPSrc(Path path)1021 SKPSrc::SKPSrc(Path path) : fPath(path) { }
1022 
draw(SkCanvas * canvas) const1023 Error SKPSrc::draw(SkCanvas* canvas) const {
1024     std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(fPath.c_str());
1025     if (!stream) {
1026         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
1027     }
1028     sk_sp<SkPicture> pic(SkPicture::MakeFromStream(stream.get()));
1029     if (!pic) {
1030         return SkStringPrintf("Couldn't parse file %s.", fPath.c_str());
1031     }
1032     stream = nullptr;  // Might as well drop this when we're done with it.
1033     canvas->clipRect(SkRect::MakeWH(FLAGS_skpViewportSize, FLAGS_skpViewportSize));
1034     canvas->drawPicture(pic);
1035     return "";
1036 }
1037 
get_cull_rect_for_skp(const char * path)1038 static SkRect get_cull_rect_for_skp(const char* path) {
1039     std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(path);
1040     if (!stream) {
1041         return SkRect::MakeEmpty();
1042     }
1043     SkPictInfo info;
1044     if (!SkPicture_StreamIsSKP(stream.get(), &info)) {
1045         return SkRect::MakeEmpty();
1046     }
1047 
1048     return info.fCullRect;
1049 }
1050 
size() const1051 SkISize SKPSrc::size() const {
1052     SkRect viewport = get_cull_rect_for_skp(fPath.c_str());
1053     if (!viewport.intersect((SkRect::MakeWH(FLAGS_skpViewportSize, FLAGS_skpViewportSize)))) {
1054         return {0, 0};
1055     }
1056     return viewport.roundOut().size();
1057 }
1058 
name() const1059 Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
1060 
1061 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1062 
BisectSrc(Path path,const char * trail)1063 BisectSrc::BisectSrc(Path path, const char* trail) : INHERITED(path), fTrail(trail) {}
1064 
draw(SkCanvas * canvas) const1065 Error BisectSrc::draw(SkCanvas* canvas) const {
1066     struct FoundPath {
1067         SkPath fPath;
1068         SkPaint fPaint;
1069         SkMatrix fViewMatrix;
1070     };
1071 
1072     // This subclass of SkCanvas just extracts all the SkPaths (drawn via drawPath) from an SKP.
1073     class PathFindingCanvas : public SkCanvas {
1074     public:
1075         PathFindingCanvas(int width, int height) : SkCanvas(width, height, nullptr) {}
1076         const SkTArray<FoundPath>& foundPaths() const { return fFoundPaths; }
1077 
1078     private:
1079         void onDrawPath(const SkPath& path, const SkPaint& paint) override {
1080             fFoundPaths.push_back() = {path, paint, this->getTotalMatrix()};
1081         }
1082 
1083         SkTArray<FoundPath> fFoundPaths;
1084     };
1085 
1086     PathFindingCanvas pathFinder(canvas->getBaseLayerSize().width(),
1087                                  canvas->getBaseLayerSize().height());
1088     Error err = this->INHERITED::draw(&pathFinder);
1089     if (!err.isEmpty()) {
1090         return err;
1091     }
1092 
1093     int start = 0, end = pathFinder.foundPaths().count();
1094     for (const char* ch = fTrail.c_str(); *ch; ++ch) {
1095         int midpt = (start + end) / 2;
1096         if ('l' == *ch) {
1097             start = midpt;
1098         } else if ('r' == *ch) {
1099             end = midpt;
1100         }
1101     }
1102 
1103     for (int i = start; i < end; ++i) {
1104         const FoundPath& path = pathFinder.foundPaths()[i];
1105         SkAutoCanvasRestore acr(canvas, true);
1106         canvas->concat(path.fViewMatrix);
1107         canvas->drawPath(path.fPath, path.fPaint);
1108     }
1109 
1110     return "";
1111 }
1112 
1113 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1114 
1115 #if defined(SK_ENABLE_SKOTTIE)
SkottieSrc(Path path)1116 SkottieSrc::SkottieSrc(Path path) : fPath(std::move(path)) {}
1117 
draw(SkCanvas * canvas) const1118 Error SkottieSrc::draw(SkCanvas* canvas) const {
1119     auto animation = skottie::Animation::Builder()
1120         .setResourceProvider(
1121                 skottie_utils::FileResourceProvider::Make(SkOSPath::Dirname(fPath.c_str())))
1122         .makeFromFile(fPath.c_str());
1123     if (!animation) {
1124         return SkStringPrintf("Unable to parse file: %s", fPath.c_str());
1125     }
1126 
1127     canvas->drawColor(SK_ColorWHITE);
1128 
1129     const auto t_rate = 1.0f / (kTileCount * kTileCount - 1);
1130 
1131     // Draw the frames in a shuffled order to exercise non-linear
1132     // frame progression. The film strip will still be in order left-to-right,
1133     // top-down, just not drawn in that order.
1134     static constexpr int frameOrder[] = { 4, 0, 3, 1, 2 };
1135     static_assert(SK_ARRAY_COUNT(frameOrder) == kTileCount, "");
1136 
1137     for (int i = 0; i < kTileCount; ++i) {
1138         const SkScalar y = frameOrder[i] * kTileSize;
1139 
1140         for (int j = 0; j < kTileCount; ++j) {
1141             const SkScalar x = frameOrder[j] * kTileSize;
1142             SkRect dest = SkRect::MakeXYWH(x, y, kTileSize, kTileSize);
1143 
1144             const auto t = t_rate * (frameOrder[i] * kTileCount + frameOrder[j]);
1145             {
1146                 SkAutoCanvasRestore acr(canvas, true);
1147                 canvas->clipRect(dest, true);
1148                 canvas->concat(SkMatrix::MakeRectToRect(SkRect::MakeSize(animation->size()),
1149                                                         dest,
1150                                                         SkMatrix::kCenter_ScaleToFit));
1151                 animation->seek(t);
1152                 animation->render(canvas);
1153             }
1154         }
1155     }
1156 
1157     return "";
1158 }
1159 
size() const1160 SkISize SkottieSrc::size() const {
1161     return SkISize::Make(kTargetSize, kTargetSize);
1162 }
1163 
name() const1164 Name SkottieSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
1165 
veto(SinkFlags flags) const1166 bool SkottieSrc::veto(SinkFlags flags) const {
1167     // No need to test to non-(raster||gpu||vector) or indirect backends.
1168     bool type_ok = flags.type == SinkFlags::kRaster
1169                 || flags.type == SinkFlags::kGPU
1170                 || flags.type == SinkFlags::kVector;
1171 
1172     return !type_ok || flags.approach != SinkFlags::kDirect;
1173 }
1174 #endif
1175 
1176 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1177 #if defined(SK_XML)
1178 // Used when the image doesn't have an intrinsic size.
1179 static const SkSize kDefaultSVGSize = {1000, 1000};
1180 
1181 // Used to force-scale tiny fixed-size images.
1182 static const SkSize kMinimumSVGSize = {128, 128};
1183 
SVGSrc(Path path)1184 SVGSrc::SVGSrc(Path path)
1185     : fName(SkOSPath::Basename(path.c_str()))
1186     , fScale(1) {
1187 
1188     sk_sp<SkData> data(SkData::MakeFromFileName(path.c_str()));
1189     if (!data) {
1190         return;
1191     }
1192 
1193     SkMemoryStream stream(std::move(data));
1194     fDom = SkSVGDOM::MakeFromStream(stream);
1195     if (!fDom) {
1196         return;
1197     }
1198 
1199     const SkSize& sz = fDom->containerSize();
1200     if (sz.isEmpty()) {
1201         // no intrinsic size
1202         fDom->setContainerSize(kDefaultSVGSize);
1203     } else {
1204         fScale = SkTMax(1.f, SkTMax(kMinimumSVGSize.width()  / sz.width(),
1205                                     kMinimumSVGSize.height() / sz.height()));
1206     }
1207 }
1208 
draw(SkCanvas * canvas) const1209 Error SVGSrc::draw(SkCanvas* canvas) const {
1210     if (!fDom) {
1211         return SkStringPrintf("Unable to parse file: %s", fName.c_str());
1212     }
1213 
1214     SkAutoCanvasRestore acr(canvas, true);
1215     canvas->scale(fScale, fScale);
1216     fDom->render(canvas);
1217 
1218     return "";
1219 }
1220 
size() const1221 SkISize SVGSrc::size() const {
1222     if (!fDom) {
1223         return {0, 0};
1224     }
1225 
1226     return SkSize{fDom->containerSize().width() * fScale, fDom->containerSize().height() * fScale}
1227             .toRound();
1228 }
1229 
name() const1230 Name SVGSrc::name() const { return fName; }
1231 
veto(SinkFlags flags) const1232 bool SVGSrc::veto(SinkFlags flags) const {
1233     // No need to test to non-(raster||gpu||vector) or indirect backends.
1234     bool type_ok = flags.type == SinkFlags::kRaster
1235                 || flags.type == SinkFlags::kGPU
1236                 || flags.type == SinkFlags::kVector;
1237 
1238     return !type_ok || flags.approach != SinkFlags::kDirect;
1239 }
1240 
1241 #endif // defined(SK_XML)
1242 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1243 
MSKPSrc(Path path)1244 MSKPSrc::MSKPSrc(Path path) : fPath(path) {
1245     std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fPath.c_str());
1246     int count = SkMultiPictureDocumentReadPageCount(stream.get());
1247     if (count > 0) {
1248         fPages.reset(count);
1249         (void)SkMultiPictureDocumentReadPageSizes(stream.get(), &fPages[0], fPages.count());
1250     }
1251 }
1252 
pageCount() const1253 int MSKPSrc::pageCount() const { return fPages.count(); }
1254 
size() const1255 SkISize MSKPSrc::size() const { return this->size(0); }
size(int i) const1256 SkISize MSKPSrc::size(int i) const {
1257     return i >= 0 && i < fPages.count() ? fPages[i].fSize.toCeil() : SkISize{0, 0};
1258 }
1259 
draw(SkCanvas * c) const1260 Error MSKPSrc::draw(SkCanvas* c) const { return this->draw(0, c); }
draw(int i,SkCanvas * canvas) const1261 Error MSKPSrc::draw(int i, SkCanvas* canvas) const {
1262     if (this->pageCount() == 0) {
1263         return SkStringPrintf("Unable to parse MultiPictureDocument file: %s", fPath.c_str());
1264     }
1265     if (i >= fPages.count() || i < 0) {
1266         return SkStringPrintf("MultiPictureDocument page number out of range: %d", i);
1267     }
1268     SkPicture* page = fPages[i].fPicture.get();
1269     if (!page) {
1270         std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fPath.c_str());
1271         if (!stream) {
1272             return SkStringPrintf("Unable to open file: %s", fPath.c_str());
1273         }
1274         if (!SkMultiPictureDocumentRead(stream.get(), &fPages[0], fPages.count())) {
1275             return SkStringPrintf("SkMultiPictureDocument reader failed on page %d: %s", i,
1276                                   fPath.c_str());
1277         }
1278         page = fPages[i].fPicture.get();
1279     }
1280     canvas->drawPicture(page);
1281     return "";
1282 }
1283 
name() const1284 Name MSKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
1285 
1286 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1287 
draw(const Src & src,SkBitmap *,SkWStream *,SkString *) const1288 Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const {
1289     return src.draw(SkMakeNullCanvas().get());
1290 }
1291 
1292 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1293 
compare_bitmaps(const SkBitmap & reference,const SkBitmap & bitmap)1294 static Error compare_bitmaps(const SkBitmap& reference, const SkBitmap& bitmap) {
1295     // The dimensions are a property of the Src only, and so should be identical.
1296     SkASSERT(reference.computeByteSize() == bitmap.computeByteSize());
1297     if (reference.computeByteSize() != bitmap.computeByteSize()) {
1298         return "Dimensions don't match reference";
1299     }
1300     // All SkBitmaps in DM are tight, so this comparison is easy.
1301     if (0 != memcmp(reference.getPixels(), bitmap.getPixels(), reference.computeByteSize())) {
1302         SkString encoded;
1303         SkString errString("Pixels don't match reference");
1304         if (bitmap_to_base64_data_uri(reference, &encoded)) {
1305             errString.append("\nExpected: ");
1306             errString.append(encoded);
1307         } else {
1308             errString.append("\nExpected image failed to encode: ");
1309             errString.append(encoded);
1310         }
1311         if (bitmap_to_base64_data_uri(bitmap, &encoded)) {
1312             errString.append("\nActual: ");
1313             errString.append(encoded);
1314         } else {
1315             errString.append("\nActual image failed to encode: ");
1316             errString.append(encoded);
1317         }
1318         return errString;
1319     }
1320     return "";
1321 }
1322 
1323 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1324 
1325 static DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?");
1326 static DEFINE_bool(preAbandonGpuContext, false,
1327                    "Test abandoning the GrContext before running the test.");
1328 static DEFINE_bool(abandonGpuContext, false,
1329                    "Test abandoning the GrContext after running each test.");
1330 static DEFINE_bool(releaseAndAbandonGpuContext, false,
1331                    "Test releasing all gpu resources and abandoning the GrContext "
1332                    "after running each test");
1333 static DEFINE_bool(drawOpClip, false, "Clip each GrDrawOp to its device bounds for testing.");
1334 static DEFINE_bool(programBinaryCache, true, "Use in-memory program binary cache");
1335 
GPUSink(GrContextFactory::ContextType ct,GrContextFactory::ContextOverrides overrides,SkCommandLineConfigGpu::SurfType surfType,int samples,bool diText,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,bool threaded,const GrContextOptions & grCtxOptions)1336 GPUSink::GPUSink(GrContextFactory::ContextType ct,
1337                  GrContextFactory::ContextOverrides overrides,
1338                  SkCommandLineConfigGpu::SurfType surfType,
1339                  int samples,
1340                  bool diText,
1341                  SkColorType colorType,
1342                  SkAlphaType alphaType,
1343                  sk_sp<SkColorSpace> colorSpace,
1344                  bool threaded,
1345                  const GrContextOptions& grCtxOptions)
1346         : fContextType(ct)
1347         , fContextOverrides(overrides)
1348         , fSurfType(surfType)
1349         , fSampleCount(samples)
1350         , fUseDIText(diText)
1351         , fColorType(colorType)
1352         , fAlphaType(alphaType)
1353         , fColorSpace(std::move(colorSpace))
1354         , fThreaded(threaded)
1355         , fBaseContextOptions(grCtxOptions) {
1356     if (FLAGS_programBinaryCache) {
1357         fBaseContextOptions.fPersistentCache = &fMemoryCache;
1358     }
1359 }
1360 
draw(const Src & src,SkBitmap * dst,SkWStream * dstStream,SkString * log) const1361 Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream* dstStream, SkString* log) const {
1362     return this->onDraw(src, dst, dstStream, log, fBaseContextOptions);
1363 }
1364 
onDraw(const Src & src,SkBitmap * dst,SkWStream *,SkString * log,const GrContextOptions & baseOptions) const1365 Error GPUSink::onDraw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log,
1366                       const GrContextOptions& baseOptions) const {
1367     GrContextOptions grOptions = baseOptions;
1368 
1369     // We don't expect the src to mess with the persistent cache or the executor.
1370     SkDEBUGCODE(auto cache = grOptions.fPersistentCache);
1371     SkDEBUGCODE(auto exec = grOptions.fExecutor);
1372     src.modifyGrContextOptions(&grOptions);
1373     SkASSERT(cache == grOptions.fPersistentCache);
1374     SkASSERT(exec == grOptions.fExecutor);
1375 
1376     GrContextFactory factory(grOptions);
1377     const SkISize size = src.size();
1378     SkImageInfo info =
1379             SkImageInfo::Make(size.width(), size.height(), fColorType, fAlphaType, fColorSpace);
1380     sk_sp<SkSurface> surface;
1381     GrContext* context = factory.getContextInfo(fContextType, fContextOverrides).grContext();
1382     const int maxDimension = context->priv().caps()->maxTextureSize();
1383     if (maxDimension < SkTMax(size.width(), size.height())) {
1384         return Error::Nonfatal("Src too large to create a texture.\n");
1385     }
1386     uint32_t flags = fUseDIText ? SkSurfaceProps::kUseDeviceIndependentFonts_Flag : 0;
1387     SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
1388     GrBackendTexture backendTexture;
1389     GrBackendRenderTarget backendRT;
1390     switch (fSurfType) {
1391         case SkCommandLineConfigGpu::SurfType::kDefault:
1392             surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, fSampleCount,
1393                                                   &props);
1394             break;
1395         case SkCommandLineConfigGpu::SurfType::kBackendTexture:
1396             backendTexture = context->createBackendTexture(
1397                     info.width(), info.height(), info.colorType(), SkColors::kTransparent,
1398                     GrMipMapped::kNo, GrRenderable::kYes, GrProtected::kNo);
1399             surface = SkSurface::MakeFromBackendTexture(context, backendTexture,
1400                                                         kTopLeft_GrSurfaceOrigin, fSampleCount,
1401                                                         fColorType, info.refColorSpace(), &props);
1402             break;
1403         case SkCommandLineConfigGpu::SurfType::kBackendRenderTarget:
1404             if (1 == fSampleCount) {
1405                 auto colorType = SkColorTypeToGrColorType(info.colorType());
1406                 backendRT = context->priv().getGpu()->createTestingOnlyBackendRenderTarget(
1407                         info.width(), info.height(), colorType);
1408                 surface = SkSurface::MakeFromBackendRenderTarget(
1409                         context, backendRT, kBottomLeft_GrSurfaceOrigin, info.colorType(),
1410                         info.refColorSpace(), &props);
1411             }
1412             break;
1413     }
1414 
1415     if (!surface) {
1416         return "Could not create a surface.";
1417     }
1418     if (FLAGS_preAbandonGpuContext) {
1419         factory.abandonContexts();
1420     }
1421     SkCanvas* canvas = surface->getCanvas();
1422     Error err = src.draw(canvas);
1423     if (!err.isEmpty()) {
1424         return err;
1425     }
1426     surface->flush();
1427     if (FLAGS_gpuStats) {
1428         canvas->getGrContext()->priv().dumpCacheStats(log);
1429         canvas->getGrContext()->priv().dumpGpuStats(log);
1430     }
1431     if (info.colorType() == kRGB_565_SkColorType || info.colorType() == kARGB_4444_SkColorType ||
1432         info.colorType() == kRGB_888x_SkColorType) {
1433         // We don't currently support readbacks into these formats on the GPU backend. Convert to
1434         // 32 bit.
1435         info = SkImageInfo::Make(size.width(), size.height(), kRGBA_8888_SkColorType,
1436                                  kPremul_SkAlphaType, fColorSpace);
1437     }
1438     dst->allocPixels(info);
1439     canvas->readPixels(*dst, 0, 0);
1440     if (FLAGS_abandonGpuContext) {
1441         factory.abandonContexts();
1442     } else if (FLAGS_releaseAndAbandonGpuContext) {
1443         factory.releaseResourcesAndAbandonContexts();
1444     }
1445     if (!context->abandoned()) {
1446         surface.reset();
1447         if (backendTexture.isValid()) {
1448             context->deleteBackendTexture(backendTexture);
1449         }
1450         if (backendRT.isValid()) {
1451             context->priv().getGpu()->deleteTestingOnlyBackendRenderTarget(backendRT);
1452         }
1453     }
1454     if (grOptions.fPersistentCache) {
1455         context->storeVkPipelineCacheData();
1456     }
1457     return "";
1458 }
1459 
1460 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1461 
GPUThreadTestingSink(GrContextFactory::ContextType ct,GrContextFactory::ContextOverrides overrides,SkCommandLineConfigGpu::SurfType surfType,int samples,bool diText,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,bool threaded,const GrContextOptions & grCtxOptions)1462 GPUThreadTestingSink::GPUThreadTestingSink(GrContextFactory::ContextType ct,
1463                                            GrContextFactory::ContextOverrides overrides,
1464                                            SkCommandLineConfigGpu::SurfType surfType,
1465                                            int samples,
1466                                            bool diText,
1467                                            SkColorType colorType,
1468                                            SkAlphaType alphaType,
1469                                            sk_sp<SkColorSpace> colorSpace,
1470                                            bool threaded,
1471                                            const GrContextOptions& grCtxOptions)
1472         : INHERITED(ct, overrides, surfType, samples, diText, colorType, alphaType,
1473                     std::move(colorSpace), threaded, grCtxOptions)
1474         , fExecutor(SkExecutor::MakeFIFOThreadPool(FLAGS_gpuThreads)) {
1475     SkASSERT(fExecutor);
1476 }
1477 
draw(const Src & src,SkBitmap * dst,SkWStream * wStream,SkString * log) const1478 Error GPUThreadTestingSink::draw(const Src& src, SkBitmap* dst, SkWStream* wStream,
1479                                  SkString* log) const {
1480     // Draw twice, once with worker threads, and once without. Verify that we get the same result.
1481     // Also, force us to only use the software path renderer, so we really stress-test the threaded
1482     // version of that code.
1483     GrContextOptions contextOptions = this->baseContextOptions();
1484     contextOptions.fGpuPathRenderers = GpuPathRenderers::kNone;
1485     contextOptions.fExecutor = fExecutor.get();
1486 
1487     Error err = this->onDraw(src, dst, wStream, log, contextOptions);
1488     if (!err.isEmpty() || !dst) {
1489         return err;
1490     }
1491 
1492     SkBitmap reference;
1493     SkString refLog;
1494     SkDynamicMemoryWStream refStream;
1495     contextOptions.fExecutor = nullptr;
1496     Error refErr = this->onDraw(src, &reference, &refStream, &refLog, contextOptions);
1497     if (!refErr.isEmpty()) {
1498         return refErr;
1499     }
1500 
1501     return compare_bitmaps(reference, *dst);
1502 }
1503 
1504 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1505 
GPUPersistentCacheTestingSink(GrContextFactory::ContextType ct,GrContextFactory::ContextOverrides overrides,SkCommandLineConfigGpu::SurfType surfType,int samples,bool diText,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,bool threaded,const GrContextOptions & grCtxOptions,int cacheType)1506 GPUPersistentCacheTestingSink::GPUPersistentCacheTestingSink(
1507         GrContextFactory::ContextType ct,
1508         GrContextFactory::ContextOverrides overrides,
1509         SkCommandLineConfigGpu::SurfType surfType,
1510         int samples,
1511         bool diText,
1512         SkColorType colorType,
1513         SkAlphaType alphaType,
1514         sk_sp<SkColorSpace> colorSpace,
1515         bool threaded,
1516         const GrContextOptions& grCtxOptions,
1517         int cacheType)
1518         : INHERITED(ct, overrides, surfType, samples, diText, colorType, alphaType,
1519                     std::move(colorSpace), threaded, grCtxOptions)
1520         , fCacheType(cacheType) {}
1521 
draw(const Src & src,SkBitmap * dst,SkWStream * wStream,SkString * log) const1522 Error GPUPersistentCacheTestingSink::draw(const Src& src, SkBitmap* dst, SkWStream* wStream,
1523                                           SkString* log) const {
1524     // Draw twice, once with a cold cache, and again with a warm cache. Verify that we get the same
1525     // result.
1526     sk_gpu_test::MemoryCache memoryCache;
1527     GrContextOptions contextOptions = this->baseContextOptions();
1528     contextOptions.fPersistentCache = &memoryCache;
1529     contextOptions.fDisallowGLSLBinaryCaching = (fCacheType == 2);
1530     // anglebug.com/3619
1531     contextOptions.fGpuPathRenderers =
1532             contextOptions.fGpuPathRenderers & ~GpuPathRenderers::kStencilAndCover;
1533 
1534     Error err = this->onDraw(src, dst, wStream, log, contextOptions);
1535     if (!err.isEmpty() || !dst) {
1536         return err;
1537     }
1538 
1539     SkBitmap reference;
1540     SkString refLog;
1541     SkDynamicMemoryWStream refStream;
1542     memoryCache.resetNumCacheMisses();
1543     Error refErr = this->onDraw(src, &reference, &refStream, &refLog, contextOptions);
1544     if (!refErr.isEmpty()) {
1545         return refErr;
1546     }
1547     SkASSERT(!memoryCache.numCacheMisses());
1548 
1549     return compare_bitmaps(reference, *dst);
1550 }
1551 
1552 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
draw_skdocument(const Src & src,SkDocument * doc,SkWStream * dst)1553 static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) {
1554     if (src.size().isEmpty()) {
1555         return "Source has empty dimensions";
1556     }
1557     SkASSERT(doc);
1558     int pageCount = src.pageCount();
1559     for (int i = 0; i < pageCount; ++i) {
1560         int width = src.size(i).width(), height = src.size(i).height();
1561         SkCanvas* canvas =
1562                 doc->beginPage(SkIntToScalar(width), SkIntToScalar(height));
1563         if (!canvas) {
1564             return "SkDocument::beginPage(w,h) returned nullptr";
1565         }
1566         Error err = src.draw(i, canvas);
1567         if (!err.isEmpty()) {
1568             return err;
1569         }
1570         doc->endPage();
1571     }
1572     doc->close();
1573     dst->flush();
1574     return "";
1575 }
1576 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1577 Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1578     SkPDF::Metadata metadata;
1579     metadata.fTitle = src.name();
1580     metadata.fSubject = "rendering correctness test";
1581     metadata.fCreator = "Skia/DM";
1582     metadata.fRasterDPI = fRasterDpi;
1583     metadata.fPDFA = fPDFA;
1584 #if SK_PDF_TEST_EXECUTOR
1585     std::unique_ptr<SkExecutor> executor = SkExecutor::MakeFIFOThreadPool();
1586     metadata.fExecutor = executor.get();
1587 #endif
1588     auto doc = SkPDF::MakeDocument(dst, metadata);
1589     if (!doc) {
1590         return "SkPDF::MakeDocument() returned nullptr";
1591     }
1592     return draw_skdocument(src, doc.get(), dst);
1593 }
1594 
1595 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1596 
XPSSink()1597 XPSSink::XPSSink() {}
1598 
1599 #ifdef SK_BUILD_FOR_WIN
make_xps_factory()1600 static SkTScopedComPtr<IXpsOMObjectFactory> make_xps_factory() {
1601     IXpsOMObjectFactory* factory;
1602     HRN(CoCreateInstance(CLSID_XpsOMObjectFactory,
1603                          nullptr,
1604                          CLSCTX_INPROC_SERVER,
1605                          IID_PPV_ARGS(&factory)));
1606     return SkTScopedComPtr<IXpsOMObjectFactory>(factory);
1607 }
1608 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1609 Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1610     SkAutoCoInitialize com;
1611     if (!com.succeeded()) {
1612         return "Could not initialize COM.";
1613     }
1614     SkTScopedComPtr<IXpsOMObjectFactory> factory = make_xps_factory();
1615     if (!factory) {
1616         return "Failed to create XPS Factory.";
1617     }
1618     auto doc = SkXPS::MakeDocument(dst, factory.get());
1619     if (!doc) {
1620         return "SkXPS::MakeDocument() returned nullptr";
1621     }
1622     return draw_skdocument(src, doc.get(), dst);
1623 }
1624 #else
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1625 Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1626     return "XPS not supported on this platform.";
1627 }
1628 #endif
1629 
1630 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1631 
SKPSink()1632 SKPSink::SKPSink() {}
1633 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1634 Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1635     SkSize size;
1636     size = src.size();
1637     SkPictureRecorder recorder;
1638     Error err = src.draw(recorder.beginRecording(size.width(), size.height()));
1639     if (!err.isEmpty()) {
1640         return err;
1641     }
1642     recorder.finishRecordingAsPicture()->serialize(dst);
1643     return "";
1644 }
1645 
1646 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1647 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1648 Error DebugSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1649     DebugCanvas debugCanvas(src.size().width(), src.size().height());
1650     Error err = src.draw(&debugCanvas);
1651     if (!err.isEmpty()) {
1652         return err;
1653     }
1654     std::unique_ptr<SkCanvas> nullCanvas = SkMakeNullCanvas();
1655     UrlDataManager dataManager(SkString("data"));
1656     SkJSONWriter writer(dst, SkJSONWriter::Mode::kPretty);
1657     writer.beginObject(); // root
1658     debugCanvas.toJSON(writer, dataManager, debugCanvas.getSize(), nullCanvas.get());
1659     writer.endObject(); // root
1660     writer.flush();
1661     return "";
1662 }
1663 
1664 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1665 
SVGSink(int pageIndex)1666 SVGSink::SVGSink(int pageIndex) : fPageIndex(pageIndex) {}
1667 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1668 Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1669 #if defined(SK_XML)
1670     if (src.pageCount() > 1) {
1671         int pageCount = src.pageCount();
1672         if (fPageIndex > pageCount - 1) {
1673             return Error(SkStringPrintf("Page index %d too high for document with only %d pages.",
1674                                         fPageIndex, pageCount));
1675         }
1676     }
1677     return src.draw(fPageIndex,
1678                     SkSVGCanvas::Make(SkRect::MakeWH(SkIntToScalar(src.size().width()),
1679                                                      SkIntToScalar(src.size().height())),
1680                                       dst)
1681                             .get());
1682 #else
1683     (void)fPageIndex;
1684     return Error("SVG sink is disabled.");
1685 #endif // SK_XML
1686 }
1687 
1688 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1689 
RasterSink(SkColorType colorType,sk_sp<SkColorSpace> colorSpace)1690 RasterSink::RasterSink(SkColorType colorType, sk_sp<SkColorSpace> colorSpace)
1691     : fColorType(colorType)
1692     , fColorSpace(std::move(colorSpace)) {}
1693 
draw(const Src & src,SkBitmap * dst,SkWStream *,SkString *) const1694 Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
1695     const SkISize size = src.size();
1696     // If there's an appropriate alpha type for this color type, use it, otherwise use premul.
1697     SkAlphaType alphaType = kPremul_SkAlphaType;
1698     (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType);
1699 
1700     dst->allocPixelsFlags(SkImageInfo::Make(size.width(), size.height(),
1701                                             fColorType, alphaType, fColorSpace),
1702                           SkBitmap::kZeroPixels_AllocFlag);
1703 
1704     SkCanvas canvas(*dst);
1705     return src.draw(&canvas);
1706 }
1707 
1708 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1709 
1710 // Handy for front-patching a Src.  Do whatever up-front work you need, then call draw_to_canvas(),
1711 // passing the Sink draw() arguments, a size, and a function draws into an SkCanvas.
1712 // Several examples below.
1713 
1714 template <typename Fn>
draw_to_canvas(Sink * sink,SkBitmap * bitmap,SkWStream * stream,SkString * log,SkISize size,const Fn & draw)1715 static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log,
1716                             SkISize size, const Fn& draw) {
1717     class ProxySrc : public Src {
1718     public:
1719         ProxySrc(SkISize size, const Fn& draw) : fSize(size), fDraw(draw) {}
1720         Error   draw(SkCanvas* canvas) const override { return fDraw(canvas); }
1721         Name    name() const override { return "ProxySrc"; }
1722         SkISize size() const override { return fSize; }
1723     private:
1724         SkISize   fSize;
1725         const Fn& fDraw;
1726     };
1727     return sink->draw(ProxySrc(size, draw), bitmap, stream, log);
1728 }
1729 
1730 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1731 
1732 static DEFINE_bool(check, true, "If true, have most Via- modes fail if they affect the output.");
1733 
1734 // Is *bitmap identical to what you get drawing src into sink?
check_against_reference(const SkBitmap * bitmap,const Src & src,Sink * sink)1735 static Error check_against_reference(const SkBitmap* bitmap, const Src& src, Sink* sink) {
1736     // We can only check raster outputs.
1737     // (Non-raster outputs like .pdf, .skp, .svg may differ but still draw identically.)
1738     if (FLAGS_check && bitmap) {
1739         SkBitmap reference;
1740         SkString log;
1741         SkDynamicMemoryWStream wStream;
1742         Error err = sink->draw(src, &reference, &wStream, &log);
1743         // If we can draw into this Sink via some pipeline, we should be able to draw directly.
1744         SkASSERT(err.isEmpty());
1745         if (!err.isEmpty()) {
1746             return err;
1747         }
1748         return compare_bitmaps(reference, *bitmap);
1749     }
1750     return "";
1751 }
1752 
1753 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1754 
auto_compute_translate(SkMatrix * matrix,int srcW,int srcH)1755 static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) {
1756     SkRect bounds = SkRect::MakeIWH(srcW, srcH);
1757     matrix->mapRect(&bounds);
1758     matrix->postTranslate(-bounds.x(), -bounds.y());
1759     return {SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height())};
1760 }
1761 
ViaMatrix(SkMatrix matrix,Sink * sink)1762 ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
1763 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1764 Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1765     SkMatrix matrix = fMatrix;
1766     SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height());
1767     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) {
1768         canvas->concat(matrix);
1769         return src.draw(canvas);
1770     });
1771 }
1772 
1773 // Undoes any flip or 90 degree rotate without changing the scale of the bitmap.
1774 // This should be pixel-preserving.
ViaUpright(SkMatrix matrix,Sink * sink)1775 ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
1776 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1777 Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1778     Error err = fSink->draw(src, bitmap, stream, log);
1779     if (!err.isEmpty()) {
1780         return err;
1781     }
1782 
1783     SkMatrix inverse;
1784     if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) {
1785         return "Cannot upright --matrix.";
1786     }
1787     SkMatrix upright = SkMatrix::I();
1788     upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX()));
1789     upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY()));
1790     upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX()));
1791     upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY()));
1792 
1793     SkBitmap uprighted;
1794     SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height());
1795     uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height()));
1796 
1797     SkCanvas canvas(uprighted);
1798     canvas.concat(upright);
1799     SkPaint paint;
1800     paint.setBlendMode(SkBlendMode::kSrc);
1801     canvas.drawBitmap(*bitmap, 0, 0, &paint);
1802 
1803     *bitmap = uprighted;
1804     return "";
1805 }
1806 
1807 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1808 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1809 Error ViaSerialization::draw(
1810         const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1811     // Record our Src into a picture.
1812     auto size = src.size();
1813     SkPictureRecorder recorder;
1814     Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1815                                                  SkIntToScalar(size.height())));
1816     if (!err.isEmpty()) {
1817         return err;
1818     }
1819     sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture());
1820 
1821     // Serialize it and then deserialize it.
1822     sk_sp<SkPicture> deserialized(SkPicture::MakeFromData(pic->serialize().get()));
1823 
1824     err = draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) {
1825         canvas->drawPicture(deserialized);
1826         return "";
1827     });
1828     if (!err.isEmpty()) {
1829         return err;
1830     }
1831 
1832     return check_against_reference(bitmap, src, fSink.get());
1833 }
1834 
1835 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1836 
ViaTiles(int w,int h,SkBBHFactory * factory,Sink * sink)1837 ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink)
1838     : Via(sink)
1839     , fW(w)
1840     , fH(h)
1841     , fFactory(factory) {}
1842 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1843 Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1844     auto size = src.size();
1845     SkPictureRecorder recorder;
1846     Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1847                                                  SkIntToScalar(size.height()),
1848                                                  fFactory.get()));
1849     if (!err.isEmpty()) {
1850         return err;
1851     }
1852     sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture());
1853 
1854     return draw_to_canvas(fSink.get(), bitmap, stream, log, src.size(), [&](SkCanvas* canvas) {
1855         const int xTiles = (size.width()  + fW - 1) / fW,
1856                   yTiles = (size.height() + fH - 1) / fH;
1857         SkMultiPictureDraw mpd(xTiles*yTiles);
1858         SkTArray<sk_sp<SkSurface>> surfaces;
1859 //        surfaces.setReserve(xTiles*yTiles);
1860 
1861         SkImageInfo info = canvas->imageInfo().makeWH(fW, fH);
1862         for (int j = 0; j < yTiles; j++) {
1863             for (int i = 0; i < xTiles; i++) {
1864                 // This lets our ultimate Sink determine the best kind of surface.
1865                 // E.g., if it's a GpuSink, the surfaces and images are textures.
1866                 auto s = canvas->makeSurface(info);
1867                 if (!s) {
1868                     s = SkSurface::MakeRaster(info);  // Some canvases can't create surfaces.
1869                 }
1870                 surfaces.push_back(s);
1871                 SkCanvas* c = s->getCanvas();
1872                 c->translate(SkIntToScalar(-i * fW),
1873                              SkIntToScalar(-j * fH));  // Line up the canvas with this tile.
1874                 mpd.add(c, pic.get());
1875             }
1876         }
1877         mpd.draw();
1878         for (int j = 0; j < yTiles; j++) {
1879             for (int i = 0; i < xTiles; i++) {
1880                 sk_sp<SkImage> image(surfaces[i+xTiles*j]->makeImageSnapshot());
1881                 canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH));
1882             }
1883         }
1884         return "";
1885     });
1886 }
1887 
1888 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1889 
ViaDDL(int numReplays,int numDivisions,Sink * sink)1890 ViaDDL::ViaDDL(int numReplays, int numDivisions, Sink* sink)
1891         : Via(sink), fNumReplays(numReplays), fNumDivisions(numDivisions) {}
1892 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1893 Error ViaDDL::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1894     auto size = src.size();
1895     SkPictureRecorder recorder;
1896     Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1897                                                  SkIntToScalar(size.height())));
1898     if (!err.isEmpty()) {
1899         return err;
1900     }
1901     sk_sp<SkPicture> inputPicture(recorder.finishRecordingAsPicture());
1902 
1903     // this is our ultimate final drawing area/rect
1904     SkIRect viewport = SkIRect::MakeWH(size.fWidth, size.fHeight);
1905 
1906     DDLPromiseImageHelper promiseImageHelper;
1907     sk_sp<SkData> compressedPictureData = promiseImageHelper.deflateSKP(inputPicture.get());
1908     if (!compressedPictureData) {
1909         return SkStringPrintf("ViaDDL: Couldn't deflate SkPicture");
1910     }
1911     auto draw = [&](SkCanvas* canvas) -> Error {
1912         GrContext* context = canvas->getGrContext();
1913         if (!context || !context->priv().getGpu()) {
1914             return SkStringPrintf("DDLs are GPU only");
1915         }
1916 
1917         // This is here bc this is the first point where we have access to the context
1918         promiseImageHelper.uploadAllToGPU(context);
1919         // We draw N times, with a clear between.
1920         for (int replay = 0; replay < fNumReplays; ++replay) {
1921             if (replay > 0) {
1922                 // Clear the drawing of the previous replay
1923                 canvas->clear(SK_ColorTRANSPARENT);
1924             }
1925             // First, create all the tiles (including their individual dest surfaces)
1926             DDLTileHelper tiles(canvas, viewport, fNumDivisions);
1927 
1928             // Second, reinflate the compressed picture individually for each thread
1929             // This recreates the promise SkImages on each replay iteration. We are currently
1930             // relying on this to test using a SkPromiseImageTexture to fulfill different
1931             // SkImages. On each replay the promise SkImages are recreated in createSKPPerTile.
1932             tiles.createSKPPerTile(compressedPictureData.get(), promiseImageHelper);
1933 
1934             // Third, create the DDLs in parallel
1935             tiles.createDDLsInParallel();
1936 
1937             if (replay == fNumReplays - 1) {
1938                 // This drops the promiseImageHelper's refs on all the promise images if we're in
1939                 // the last run.
1940                 promiseImageHelper.reset();
1941             }
1942 
1943             // Fourth, synchronously render the display lists into the dest tiles
1944             // TODO: it would be cool to not wait until all the tiles are drawn to begin
1945             // drawing to the GPU and composing to the final surface
1946             tiles.drawAllTilesAndFlush(context, false);
1947 
1948             // Finally, compose the drawn tiles into the result
1949             // Note: the separation between the tiles and the final composition better
1950             // matches Chrome but costs us a copy
1951             tiles.composeAllTiles(canvas);
1952             context->flush();
1953         }
1954         return "";
1955     };
1956     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, draw);
1957 }
1958 
1959 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1960 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1961 Error ViaPicture::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1962     auto size = src.size();
1963     Error err = draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) {
1964         SkPictureRecorder recorder;
1965         sk_sp<SkPicture> pic;
1966         Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1967                                                      SkIntToScalar(size.height())));
1968         if (!err.isEmpty()) {
1969             return err;
1970         }
1971         pic = recorder.finishRecordingAsPicture();
1972         canvas->drawPicture(pic);
1973         return err;
1974     });
1975     if (!err.isEmpty()) {
1976         return err;
1977     }
1978 
1979     return check_against_reference(bitmap, src, fSink.get());
1980 }
1981 
1982 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1983 
1984 #ifdef TEST_VIA_SVG
1985 #include "experimental/svg/model/SkSVGDOM.h"
1986 #include "include/svg/SkSVGCanvas.h"
1987 #include "src/xml/SkXMLWriter.h"
1988 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1989 Error ViaSVG::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1990     auto size = src.size();
1991     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1992         SkDynamicMemoryWStream wstream;
1993         SkXMLStreamWriter writer(&wstream);
1994         Error err = src.draw(SkSVGCanvas::Make(SkRect::Make(size), &writer).get());
1995         if (!err.isEmpty()) {
1996             return err;
1997         }
1998         std::unique_ptr<SkStream> rstream(wstream.detachAsStream());
1999         auto dom = SkSVGDOM::MakeFromStream(*rstream);
2000         if (dom) {
2001             dom->setContainerSize(SkSize::Make(size));
2002             dom->render(canvas);
2003         }
2004         return "";
2005     });
2006 }
2007 #endif
2008 
2009 }  // namespace DM
2010