• 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 "DMSrcSink.h"
9 #include "DDLPromiseImageHelper.h"
10 #include "DDLTileHelper.h"
11 #include "GrBackendSurface.h"
12 #include "GrContextPriv.h"
13 #include "GrGpu.h"
14 #include "MemoryCache.h"
15 #include "Resources.h"
16 #include "SkAndroidCodec.h"
17 #include "SkAutoMalloc.h"
18 #include "SkAutoPixmapStorage.h"
19 #include "SkCodec.h"
20 #include "SkCodecImageGenerator.h"
21 #include "SkColorSpace.h"
22 #include "SkColorSpaceXformCanvas.h"
23 #include "SkCommonFlags.h"
24 #include "SkCommonFlagsGpu.h"
25 #include "SkData.h"
26 #include "SkDebugCanvas.h"
27 #include "SkDeferredDisplayListRecorder.h"
28 #include "SkDocument.h"
29 #include "SkExecutor.h"
30 #include "SkImageGenerator.h"
31 #include "SkImageGeneratorCG.h"
32 #include "SkImageGeneratorWIC.h"
33 #include "SkImageInfoPriv.h"
34 #include "SkLiteDL.h"
35 #include "SkLiteRecorder.h"
36 #include "SkMakeUnique.h"
37 #include "SkMallocPixelRef.h"
38 #include "SkMultiPictureDocumentPriv.h"
39 #include "SkMultiPictureDraw.h"
40 #include "SkNullCanvas.h"
41 #include "SkOSFile.h"
42 #include "SkOSPath.h"
43 #include "SkOpts.h"
44 #include "SkPictureCommon.h"
45 #include "SkPictureData.h"
46 #include "SkPictureRecorder.h"
47 #include "SkPDFDocument.h"
48 #include "SkRandom.h"
49 #include "SkRecordDraw.h"
50 #include "SkRecorder.h"
51 #include "SkStream.h"
52 #include "SkSurface.h"
53 #include "SkSurfaceCharacterization.h"
54 #include "SkSwizzler.h"
55 #include "SkTLogic.h"
56 #include "SkTaskGroup.h"
57 #if defined(SK_BUILD_FOR_WIN)
58     #include "SkAutoCoInitialize.h"
59     #include "SkHRESULT.h"
60     #include "SkTScopedComPtr.h"
61     #include "SkXPSDocument.h"
62     #include <XpsObjectModel.h>
63 #endif
64 
65 #if defined(SK_ENABLE_SKOTTIE)
66     #include "Skottie.h"
67     #include "SkottieUtils.h"
68 #endif
69 
70 #if defined(SK_XML)
71     #include "SkSVGCanvas.h"
72     #include "SkSVGDOM.h"
73     #include "SkXMLWriter.h"
74 #endif
75 #include "TestUtils.h"
76 
77 #include <cmath>
78 #include <functional>
79 
80 #include "../third_party/skcms/skcms.h"
81 
82 DEFINE_bool(multiPage, false, "For document-type backends, render the source"
83             " into multiple pages");
84 DEFINE_bool(RAW_threading, true, "Allow RAW decodes to run on multiple threads?");
85 
86 using sk_gpu_test::GrContextFactory;
87 
88 namespace DM {
89 
GMSrc(skiagm::GMFactory factory)90 GMSrc::GMSrc(skiagm::GMFactory factory) : fFactory(factory) {}
91 
draw(SkCanvas * canvas) const92 Error GMSrc::draw(SkCanvas* canvas) const {
93     std::unique_ptr<skiagm::GM> gm(fFactory(nullptr));
94     gm->draw(canvas);
95     return "";
96 }
97 
size() const98 SkISize GMSrc::size() const {
99     std::unique_ptr<skiagm::GM> gm(fFactory(nullptr));
100     return gm->getISize();
101 }
102 
name() const103 Name GMSrc::name() const {
104     std::unique_ptr<skiagm::GM> gm(fFactory(nullptr));
105     return gm->getName();
106 }
107 
modifyGrContextOptions(GrContextOptions * options) const108 void GMSrc::modifyGrContextOptions(GrContextOptions* options) const {
109     std::unique_ptr<skiagm::GM> gm(fFactory(nullptr));
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     canvas->flush();
378 }
379 
380 // For codec srcs, we want the "draw" step to be a memcpy.  Any interesting color space or
381 // color format conversions should be performed by the codec.  Sometimes the output of the
382 // decode will be in an interesting color space.  On our srgb and f16 backends, we need to
383 // "pretend" that the color space is standard sRGB to avoid triggering color conversion
384 // at draw time.
set_bitmap_color_space(SkImageInfo * info)385 static void set_bitmap_color_space(SkImageInfo* info) {
386     *info = info->makeColorSpace(SkColorSpace::MakeSRGB());
387 }
388 
draw(SkCanvas * canvas) const389 Error CodecSrc::draw(SkCanvas* canvas) const {
390     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
391     if (!encoded) {
392         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
393     }
394 
395     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
396     if (nullptr == codec.get()) {
397         return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
398     }
399 
400     SkImageInfo decodeInfo = codec->getInfo();
401     if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType,
402                          fDstAlphaType)) {
403         return Error::Nonfatal("Skipping uninteresting test.");
404     }
405 
406     // Try to scale the image if it is desired
407     SkISize size = codec->getScaledDimensions(fScale);
408     if (size == decodeInfo.dimensions() && 1.0f != fScale) {
409         return Error::Nonfatal("Test without scaling is uninteresting.");
410     }
411 
412     // Visually inspecting very small output images is not necessary.  We will
413     // cover these cases in unit testing.
414     if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) {
415         return Error::Nonfatal("Scaling very small images is uninteresting.");
416     }
417     decodeInfo = decodeInfo.makeWH(size.width(), size.height());
418 
419     const int bpp = decodeInfo.bytesPerPixel();
420     const size_t rowBytes = size.width() * bpp;
421     const size_t safeSize = decodeInfo.computeByteSize(rowBytes);
422     SkAutoMalloc pixels(safeSize);
423 
424     SkCodec::Options options;
425     if (kCodecZeroInit_Mode == fMode) {
426         memset(pixels.get(), 0, size.height() * rowBytes);
427         options.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
428     }
429 
430     SkImageInfo bitmapInfo = decodeInfo;
431     set_bitmap_color_space(&bitmapInfo);
432     if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
433             kBGRA_8888_SkColorType == decodeInfo.colorType()) {
434         bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
435     }
436 
437     switch (fMode) {
438         case kAnimated_Mode: {
439             std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo();
440             if (frameInfos.size() <= 1) {
441                 return SkStringPrintf("%s is not an animated image.", fPath.c_str());
442             }
443 
444             // As in CodecSrc::size(), compute a roughly square grid to draw the frames
445             // into. "factor" is the number of frames to draw on one row. There will be
446             // up to "factor" rows as well.
447             const float root = sqrt((float) frameInfos.size());
448             const int factor = sk_float_ceil2int(root);
449 
450             // Used to cache a frame that future frames will depend on.
451             SkAutoMalloc priorFramePixels;
452             int cachedFrame = SkCodec::kNoFrame;
453             for (int i = 0; static_cast<size_t>(i) < frameInfos.size(); i++) {
454                 options.fFrameIndex = i;
455                 // Check for a prior frame
456                 const int reqFrame = frameInfos[i].fRequiredFrame;
457                 if (reqFrame != SkCodec::kNoFrame && reqFrame == cachedFrame
458                         && priorFramePixels.get()) {
459                     // Copy into pixels
460                     memcpy(pixels.get(), priorFramePixels.get(), safeSize);
461                     options.fPriorFrame = reqFrame;
462                 } else {
463                     options.fPriorFrame = SkCodec::kNoFrame;
464                 }
465                 SkCodec::Result result = codec->getPixels(decodeInfo, pixels.get(),
466                                                           rowBytes, &options);
467                 if (SkCodec::kInvalidInput == result && i > 0) {
468                     // Some of our test images have truncated later frames. Treat that
469                     // the same as incomplete.
470                     result = SkCodec::kIncompleteInput;
471                 }
472                 switch (result) {
473                     case SkCodec::kSuccess:
474                     case SkCodec::kErrorInInput:
475                     case SkCodec::kIncompleteInput: {
476                         // If the next frame depends on this one, store it in priorFrame.
477                         // It is possible that we may discard a frame that future frames depend on,
478                         // but the codec will simply redecode the discarded frame.
479                         // Do this before calling draw_to_canvas, which premultiplies in place. If
480                         // we're decoding to unpremul, we want to pass the unmodified frame to the
481                         // codec for decoding the next frame.
482                         if (static_cast<size_t>(i+1) < frameInfos.size()
483                                 && frameInfos[i+1].fRequiredFrame == i) {
484                             memcpy(priorFramePixels.reset(safeSize), pixels.get(), safeSize);
485                             cachedFrame = i;
486                         }
487 
488                         SkAutoCanvasRestore acr(canvas, true);
489                         const int xTranslate = (i % factor) * decodeInfo.width();
490                         const int yTranslate = (i / factor) * decodeInfo.height();
491                         canvas->translate(SkIntToScalar(xTranslate), SkIntToScalar(yTranslate));
492                         draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
493                         if (result != SkCodec::kSuccess) {
494                             return "";
495                         }
496                         break;
497                     }
498                     case SkCodec::kInvalidConversion:
499                         if (i > 0 && (decodeInfo.colorType() == kRGB_565_SkColorType)) {
500                             return Error::Nonfatal(SkStringPrintf(
501                                 "Cannot decode frame %i to 565 (%s).", i, fPath.c_str()));
502                         }
503                         // Fall through.
504                     default:
505                         return SkStringPrintf("Couldn't getPixels for frame %i in %s.",
506                                               i, fPath.c_str());
507                 }
508             }
509             break;
510         }
511         case kCodecZeroInit_Mode:
512         case kCodec_Mode: {
513             switch (codec->getPixels(decodeInfo, pixels.get(), rowBytes, &options)) {
514                 case SkCodec::kSuccess:
515                     // We consider these to be valid, since we should still decode what is
516                     // available.
517                 case SkCodec::kErrorInInput:
518                 case SkCodec::kIncompleteInput:
519                     break;
520                 default:
521                     // Everything else is considered a failure.
522                     return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
523             }
524 
525             draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
526             break;
527         }
528         case kScanline_Mode: {
529             void* dst = pixels.get();
530             uint32_t height = decodeInfo.height();
531             const bool useIncremental = [this]() {
532                 auto exts = { "png", "PNG", "gif", "GIF" };
533                 for (auto ext : exts) {
534                     if (fPath.endsWith(ext)) {
535                         return true;
536                     }
537                 }
538                 return false;
539             }();
540             // ico may use the old scanline method or the new one, depending on whether it
541             // internally holds a bmp or a png.
542             const bool ico = fPath.endsWith("ico");
543             bool useOldScanlineMethod = !useIncremental && !ico;
544             if (useIncremental || ico) {
545                 if (SkCodec::kSuccess == codec->startIncrementalDecode(decodeInfo, dst,
546                         rowBytes, &options)) {
547                     int rowsDecoded;
548                     auto result = codec->incrementalDecode(&rowsDecoded);
549                     if (SkCodec::kIncompleteInput == result || SkCodec::kErrorInInput == result) {
550                         codec->fillIncompleteImage(decodeInfo, dst, rowBytes,
551                                                    SkCodec::kNo_ZeroInitialized, height,
552                                                    rowsDecoded);
553                     }
554                 } else {
555                     if (useIncremental) {
556                         // Error: These should support incremental decode.
557                         return "Could not start incremental decode";
558                     }
559                     // Otherwise, this is an ICO. Since incremental failed, it must contain a BMP,
560                     // which should work via startScanlineDecode
561                     useOldScanlineMethod = true;
562                 }
563             }
564 
565             if (useOldScanlineMethod) {
566                 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo)) {
567                     return "Could not start scanline decoder";
568                 }
569 
570                 // We do not need to check the return value.  On an incomplete
571                 // image, memory will be filled with a default value.
572                 codec->getScanlines(dst, height, rowBytes);
573             }
574 
575             draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, fDstColorType);
576             break;
577         }
578         case kStripe_Mode: {
579             const int height = decodeInfo.height();
580             // This value is chosen arbitrarily.  We exercise more cases by choosing a value that
581             // does not align with image blocks.
582             const int stripeHeight = 37;
583             const int numStripes = (height + stripeHeight - 1) / stripeHeight;
584             void* dst = pixels.get();
585 
586             // Decode odd stripes
587             if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &options)) {
588                 return "Could not start scanline decoder";
589             }
590 
591             // This mode was designed to test the new skip scanlines API in libjpeg-turbo.
592             // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting
593             // to run this test for image types that do not have this scanline ordering.
594             // We only run this on Jpeg, which is always kTopDown.
595             SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder());
596 
597             for (int i = 0; i < numStripes; i += 2) {
598                 // Skip a stripe
599                 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight);
600                 codec->skipScanlines(linesToSkip);
601 
602                 // Read a stripe
603                 const int startY = (i + 1) * stripeHeight;
604                 const int linesToRead = SkTMin(stripeHeight, height - startY);
605                 if (linesToRead > 0) {
606                     codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead,
607                                         rowBytes);
608                 }
609             }
610 
611             // Decode even stripes
612             const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo);
613             if (SkCodec::kSuccess != startResult) {
614                 return "Failed to restart scanline decoder with same parameters.";
615             }
616             for (int i = 0; i < numStripes; i += 2) {
617                 // Read a stripe
618                 const int startY = i * stripeHeight;
619                 const int linesToRead = SkTMin(stripeHeight, height - startY);
620                 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead,
621                                     rowBytes);
622 
623                 // Skip a stripe
624                 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight);
625                 if (linesToSkip > 0) {
626                     codec->skipScanlines(linesToSkip);
627                 }
628             }
629 
630             draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, fDstColorType);
631             break;
632         }
633         case kCroppedScanline_Mode: {
634             const int width = decodeInfo.width();
635             const int height = decodeInfo.height();
636             // This value is chosen because, as we move across the image, it will sometimes
637             // align with the jpeg block sizes and it will sometimes not.  This allows us
638             // to test interestingly different code paths in the implementation.
639             const int tileSize = 36;
640             SkIRect subset;
641             for (int x = 0; x < width; x += tileSize) {
642                 subset = SkIRect::MakeXYWH(x, 0, SkTMin(tileSize, width - x), height);
643                 options.fSubset = &subset;
644                 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &options)) {
645                     return "Could not start scanline decoder.";
646                 }
647 
648                 codec->getScanlines(SkTAddOffset<void>(pixels.get(), x * bpp), height, rowBytes);
649             }
650 
651             draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
652             break;
653         }
654         case kSubset_Mode: {
655             // Arbitrarily choose a divisor.
656             int divisor = 2;
657             // Total width/height of the image.
658             const int W = codec->getInfo().width();
659             const int H = codec->getInfo().height();
660             if (divisor > W || divisor > H) {
661                 return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divisor %d is too big "
662                                                       "for %s with dimensions (%d x %d)", divisor,
663                                                       fPath.c_str(), W, H));
664             }
665             // subset dimensions
666             // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
667             const int w = SkAlign2(W / divisor);
668             const int h = SkAlign2(H / divisor);
669             SkIRect subset;
670             options.fSubset = &subset;
671             SkBitmap subsetBm;
672             // We will reuse pixel memory from bitmap.
673             void* dst = pixels.get();
674             // Keep track of left and top (for drawing subsetBm into canvas). We could use
675             // fScale * x and fScale * y, but we want integers such that the next subset will start
676             // where the last one ended. So we'll add decodeInfo.width() and height().
677             int left = 0;
678             for (int x = 0; x < W; x += w) {
679                 int top = 0;
680                 for (int y = 0; y < H; y+= h) {
681                     // Do not make the subset go off the edge of the image.
682                     const int preScaleW = SkTMin(w, W - x);
683                     const int preScaleH = SkTMin(h, H - y);
684                     subset.setXYWH(x, y, preScaleW, preScaleH);
685                     // And scale
686                     // FIXME: Should we have a version of getScaledDimensions that takes a subset
687                     // into account?
688                     const int scaledW = SkTMax(1, SkScalarRoundToInt(preScaleW * fScale));
689                     const int scaledH = SkTMax(1, SkScalarRoundToInt(preScaleH * fScale));
690                     decodeInfo = decodeInfo.makeWH(scaledW, scaledH);
691                     SkImageInfo subsetBitmapInfo = bitmapInfo.makeWH(scaledW, scaledH);
692                     size_t subsetRowBytes = subsetBitmapInfo.minRowBytes();
693                     const SkCodec::Result result = codec->getPixels(decodeInfo, dst, subsetRowBytes,
694                             &options);
695                     switch (result) {
696                         case SkCodec::kSuccess:
697                         case SkCodec::kErrorInInput:
698                         case SkCodec::kIncompleteInput:
699                             break;
700                         default:
701                             return SkStringPrintf("subset codec failed to decode (%d, %d, %d, %d) "
702                                                   "from %s with dimensions (%d x %d)\t error %d",
703                                                   x, y, decodeInfo.width(), decodeInfo.height(),
704                                                   fPath.c_str(), W, H, result);
705                     }
706                     draw_to_canvas(canvas, subsetBitmapInfo, dst, subsetRowBytes, fDstColorType,
707                                    SkIntToScalar(left), SkIntToScalar(top));
708 
709                     // translate by the scaled height.
710                     top += decodeInfo.height();
711                 }
712                 // translate by the scaled width.
713                 left += decodeInfo.width();
714             }
715             return "";
716         }
717         default:
718             SkASSERT(false);
719             return "Invalid fMode";
720     }
721     return "";
722 }
723 
size() const724 SkISize CodecSrc::size() const {
725     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
726     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
727     if (nullptr == codec) {
728         return {0, 0};
729     }
730 
731     auto imageSize = codec->getScaledDimensions(fScale);
732     if (fMode == kAnimated_Mode) {
733         // We'll draw one of each frame, so make it big enough to hold them all
734         // in a grid. The grid will be roughly square, with "factor" frames per
735         // row and up to "factor" rows.
736         const size_t count = codec->getFrameInfo().size();
737         const float root = sqrt((float) count);
738         const int factor = sk_float_ceil2int(root);
739         imageSize.fWidth  = imageSize.fWidth  * factor;
740         imageSize.fHeight = imageSize.fHeight * sk_float_ceil2int((float) count / (float) factor);
741     }
742     return imageSize;
743 }
744 
name() const745 Name CodecSrc::name() const {
746     if (1.0f == fScale) {
747         Name name = SkOSPath::Basename(fPath.c_str());
748         if (fMode == kAnimated_Mode) {
749             name.append("_animated");
750         }
751         return name;
752     }
753     SkASSERT(fMode != kAnimated_Mode);
754     return get_scaled_name(fPath, fScale);
755 }
756 
757 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
758 
AndroidCodecSrc(Path path,CodecSrc::DstColorType dstColorType,SkAlphaType dstAlphaType,int sampleSize)759 AndroidCodecSrc::AndroidCodecSrc(Path path, CodecSrc::DstColorType dstColorType,
760         SkAlphaType dstAlphaType, int sampleSize)
761     : fPath(path)
762     , fDstColorType(dstColorType)
763     , fDstAlphaType(dstAlphaType)
764     , fSampleSize(sampleSize)
765     , fRunSerially(serial_from_path_name(path))
766 {}
767 
veto(SinkFlags flags) const768 bool AndroidCodecSrc::veto(SinkFlags flags) const {
769     // No need to test decoding to non-raster or indirect backend.
770     return flags.type != SinkFlags::kRaster
771         || flags.approach != SinkFlags::kDirect;
772 }
773 
draw(SkCanvas * canvas) const774 Error AndroidCodecSrc::draw(SkCanvas* canvas) const {
775     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
776     if (!encoded) {
777         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
778     }
779     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromData(encoded));
780     if (nullptr == codec) {
781         return SkStringPrintf("Couldn't create android codec for %s.", fPath.c_str());
782     }
783 
784     SkImageInfo decodeInfo = codec->getInfo();
785     if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType,
786                          fDstAlphaType)) {
787         return Error::Nonfatal("Skipping uninteresting test.");
788     }
789 
790     // Scale the image if it is desired.
791     SkISize size = codec->getSampledDimensions(fSampleSize);
792 
793     // Visually inspecting very small output images is not necessary.  We will
794     // cover these cases in unit testing.
795     if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) {
796         return Error::Nonfatal("Scaling very small images is uninteresting.");
797     }
798     decodeInfo = decodeInfo.makeWH(size.width(), size.height());
799 
800     int bpp = decodeInfo.bytesPerPixel();
801     size_t rowBytes = size.width() * bpp;
802     SkAutoMalloc pixels(size.height() * rowBytes);
803 
804     SkBitmap bitmap;
805     SkImageInfo bitmapInfo = decodeInfo;
806     set_bitmap_color_space(&bitmapInfo);
807     if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
808             kBGRA_8888_SkColorType == decodeInfo.colorType()) {
809         bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
810     }
811 
812     // Create options for the codec.
813     SkAndroidCodec::AndroidOptions options;
814     options.fSampleSize = fSampleSize;
815 
816     switch (codec->getAndroidPixels(decodeInfo, pixels.get(), rowBytes, &options)) {
817         case SkCodec::kSuccess:
818         case SkCodec::kErrorInInput:
819         case SkCodec::kIncompleteInput:
820             break;
821         default:
822             return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
823     }
824     draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
825     return "";
826 }
827 
size() const828 SkISize AndroidCodecSrc::size() const {
829     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
830     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromData(encoded));
831     if (nullptr == codec) {
832         return {0, 0};
833     }
834     return codec->getSampledDimensions(fSampleSize);
835 }
836 
name() const837 Name AndroidCodecSrc::name() const {
838     // We will replicate the names used by CodecSrc so that images can
839     // be compared in Gold.
840     if (1 == fSampleSize) {
841         return SkOSPath::Basename(fPath.c_str());
842     }
843     return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
844 }
845 
846 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
847 
ImageGenSrc(Path path,Mode mode,SkAlphaType alphaType,bool isGpu)848 ImageGenSrc::ImageGenSrc(Path path, Mode mode, SkAlphaType alphaType, bool isGpu)
849     : fPath(path)
850     , fMode(mode)
851     , fDstAlphaType(alphaType)
852     , fIsGpu(isGpu)
853     , fRunSerially(serial_from_path_name(path))
854 {}
855 
veto(SinkFlags flags) const856 bool ImageGenSrc::veto(SinkFlags flags) const {
857     if (fIsGpu) {
858         // MSAA runs tend to run out of memory and tests the same code paths as regular gpu configs.
859         return flags.type != SinkFlags::kGPU || flags.approach != SinkFlags::kDirect ||
860                flags.multisampled == SinkFlags::kMultisampled;
861     }
862 
863     return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
864 }
865 
draw(SkCanvas * canvas) const866 Error ImageGenSrc::draw(SkCanvas* canvas) const {
867     if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) {
868         return Error::Nonfatal("Uninteresting to test image generator to 565.");
869     }
870 
871     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
872     if (!encoded) {
873         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
874     }
875 
876 #if defined(SK_BUILD_FOR_WIN)
877     // Initialize COM in order to test with WIC.
878     SkAutoCoInitialize com;
879     if (!com.succeeded()) {
880         return "Could not initialize COM.";
881     }
882 #endif
883 
884     std::unique_ptr<SkImageGenerator> gen(nullptr);
885     switch (fMode) {
886         case kCodec_Mode:
887             gen = SkCodecImageGenerator::MakeFromEncodedCodec(encoded);
888             if (!gen) {
889                 return "Could not create codec image generator.";
890             }
891             break;
892         case kPlatform_Mode: {
893 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
894             gen = SkImageGeneratorCG::MakeFromEncodedCG(encoded);
895 #elif defined(SK_BUILD_FOR_WIN)
896             gen = SkImageGeneratorWIC::MakeFromEncodedWIC(encoded);
897 #endif
898             if (!gen) {
899                 return "Could not create platform image generator.";
900             }
901             break;
902         }
903         default:
904             SkASSERT(false);
905             return "Invalid image generator mode";
906     }
907 
908     // Test deferred decoding path on GPU
909     if (fIsGpu) {
910         sk_sp<SkImage> image(SkImage::MakeFromGenerator(std::move(gen), nullptr));
911         if (!image) {
912             return "Could not create image from codec image generator.";
913         }
914         canvas->drawImage(image, 0, 0);
915         return "";
916     }
917 
918     // Test various color and alpha types on CPU
919     SkImageInfo decodeInfo = gen->getInfo().makeAlphaType(fDstAlphaType);
920 
921     int bpp = decodeInfo.bytesPerPixel();
922     size_t rowBytes = decodeInfo.width() * bpp;
923     SkAutoMalloc pixels(decodeInfo.height() * rowBytes);
924     if (!gen->getPixels(decodeInfo, pixels.get(), rowBytes)) {
925         SkString err =
926                 SkStringPrintf("Image generator could not getPixels() for %s\n", fPath.c_str());
927 
928 #if defined(SK_BUILD_FOR_WIN)
929         if (kPlatform_Mode == fMode) {
930             // Do not issue a fatal error for WIC flakiness.
931             return Error::Nonfatal(err);
932         }
933 #endif
934 
935         return err;
936     }
937 
938     set_bitmap_color_space(&decodeInfo);
939     draw_to_canvas(canvas, decodeInfo, pixels.get(), rowBytes,
940                    CodecSrc::kGetFromCanvas_DstColorType);
941     return "";
942 }
943 
size() const944 SkISize ImageGenSrc::size() const {
945     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
946     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
947     if (nullptr == codec) {
948         return {0, 0};
949     }
950     return codec->getInfo().dimensions();
951 }
952 
name() const953 Name ImageGenSrc::name() const {
954     return SkOSPath::Basename(fPath.c_str());
955 }
956 
957 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
958 
ColorCodecSrc(Path path,Mode mode,SkColorType colorType)959 ColorCodecSrc::ColorCodecSrc(Path path, Mode mode, SkColorType colorType)
960     : fPath(path)
961     , fMode(mode)
962     , fColorType(colorType)
963 {}
964 
veto(SinkFlags flags) const965 bool ColorCodecSrc::veto(SinkFlags flags) const {
966     // Test to direct raster backends (8888 and 565).
967     return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
968 }
969 
clamp_if_necessary(const SkBitmap & bitmap,SkColorType dstCT)970 void clamp_if_necessary(const SkBitmap& bitmap, SkColorType dstCT) {
971     if (kRGBA_F16_SkColorType != bitmap.colorType() || kRGBA_F16_SkColorType == dstCT) {
972         // No need to clamp if the dst is F16.  We will clamp when we encode to PNG.
973         return;
974     }
975 
976     SkRasterPipeline_MemoryCtx ptr = { bitmap.getAddr(0,0), bitmap.rowBytesAsPixels() };
977 
978     SkRasterPipeline_<256> p;
979     p.append(SkRasterPipeline::load_f16, &ptr);
980     p.append(SkRasterPipeline::clamp_0);
981     if (kPremul_SkAlphaType == bitmap.alphaType()) {
982         p.append(SkRasterPipeline::clamp_a);
983     } else {
984         p.append(SkRasterPipeline::clamp_1);
985     }
986     p.append(SkRasterPipeline::store_f16, &ptr);
987 
988     p.run(0,0, bitmap.width(), bitmap.height());
989 }
990 
draw(SkCanvas * canvas) const991 Error ColorCodecSrc::draw(SkCanvas* canvas) const {
992     if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) {
993         return Error::Nonfatal("No need to test color correction to 565 backend.");
994     }
995 
996     bool runInLegacyMode = kBaseline_Mode == fMode;
997     if (runInLegacyMode && canvas->imageInfo().colorSpace()) {
998         return Error::Nonfatal("Skipping tests that are only interesting in legacy mode.");
999     } else if (!runInLegacyMode && !canvas->imageInfo().colorSpace()) {
1000         return Error::Nonfatal("Skipping tests that are only interesting in srgb mode.");
1001     }
1002 
1003     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
1004     if (!encoded) {
1005         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
1006     }
1007 
1008     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
1009     if (nullptr == codec) {
1010         return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
1011     }
1012 
1013     // Load the dst ICC profile.  This particular dst is fairly similar to Adobe RGB.
1014     sk_sp<SkData> dstData = GetResourceAsData("icc_profiles/HP_ZR30w.icc");
1015     if (!dstData) {
1016         return "Cannot read monitor profile.  Is the resource path set correctly?";
1017     }
1018 
1019     sk_sp<SkColorSpace> dstSpace = nullptr;
1020     if (kDst_sRGB_Mode == fMode) {
1021         dstSpace = SkColorSpace::MakeSRGB();
1022     } else if (kDst_HPZR30w_Mode == fMode) {
1023         skcms_ICCProfile profile;
1024         SkAssertResult(skcms_Parse(dstData->data(), dstData->size(), &profile));
1025         dstSpace = SkColorSpace::Make(profile);
1026         SkASSERT(dstSpace);
1027     }
1028 
1029     SkImageInfo decodeInfo = codec->getInfo().makeColorType(fColorType).makeColorSpace(dstSpace);
1030     if (kUnpremul_SkAlphaType == decodeInfo.alphaType()) {
1031         decodeInfo = decodeInfo.makeAlphaType(kPremul_SkAlphaType);
1032     }
1033 
1034     SkImageInfo bitmapInfo = decodeInfo;
1035     set_bitmap_color_space(&bitmapInfo);
1036     if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
1037         kBGRA_8888_SkColorType == decodeInfo.colorType())
1038     {
1039         bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
1040     }
1041 
1042     SkBitmap bitmap;
1043     if (!bitmap.tryAllocPixels(bitmapInfo)) {
1044         return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(),
1045                               bitmapInfo.width(), bitmapInfo.height());
1046     }
1047 
1048     size_t rowBytes = bitmap.rowBytes();
1049     SkCodec::Result r = codec->getPixels(decodeInfo, bitmap.getPixels(), rowBytes);
1050     switch (r) {
1051         case SkCodec::kSuccess:
1052         case SkCodec::kErrorInInput:
1053         case SkCodec::kIncompleteInput:
1054             break;
1055         default:
1056             return SkStringPrintf("Couldn't getPixels %s. Error code %d", fPath.c_str(), r);
1057     }
1058 
1059     switch (fMode) {
1060         case kBaseline_Mode:
1061         case kDst_sRGB_Mode:
1062         case kDst_HPZR30w_Mode:
1063             // We do not support drawing unclamped F16.
1064             clamp_if_necessary(bitmap, canvas->imageInfo().colorType());
1065             canvas->drawBitmap(bitmap, 0, 0);
1066             break;
1067         default:
1068             SkASSERT(false);
1069             return "Invalid fMode";
1070     }
1071     return "";
1072 }
1073 
size() const1074 SkISize ColorCodecSrc::size() const {
1075     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
1076     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
1077     if (nullptr == codec) {
1078         return {0, 0};
1079     }
1080     return {codec->getInfo().width(), codec->getInfo().height()};
1081 }
1082 
name() const1083 Name ColorCodecSrc::name() const {
1084     return SkOSPath::Basename(fPath.c_str());
1085 }
1086 
1087 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1088 
SKPSrc(Path path)1089 SKPSrc::SKPSrc(Path path) : fPath(path) { }
1090 
draw(SkCanvas * canvas) const1091 Error SKPSrc::draw(SkCanvas* canvas) const {
1092     std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(fPath.c_str());
1093     if (!stream) {
1094         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
1095     }
1096     sk_sp<SkPicture> pic(SkPicture::MakeFromStream(stream.get()));
1097     if (!pic) {
1098         return SkStringPrintf("Couldn't parse file %s.", fPath.c_str());
1099     }
1100     stream = nullptr;  // Might as well drop this when we're done with it.
1101     canvas->clipRect(SkRect::MakeWH(FLAGS_skpViewportSize, FLAGS_skpViewportSize));
1102     canvas->drawPicture(pic);
1103     return "";
1104 }
1105 
get_cull_rect_for_skp(const char * path)1106 static SkRect get_cull_rect_for_skp(const char* path) {
1107     std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(path);
1108     if (!stream) {
1109         return SkRect::MakeEmpty();
1110     }
1111     SkPictInfo info;
1112     if (!SkPicture_StreamIsSKP(stream.get(), &info)) {
1113         return SkRect::MakeEmpty();
1114     }
1115 
1116     return info.fCullRect;
1117 }
1118 
size() const1119 SkISize SKPSrc::size() const {
1120     SkRect viewport = get_cull_rect_for_skp(fPath.c_str());
1121     if (!viewport.intersect((SkRect::MakeWH(FLAGS_skpViewportSize, FLAGS_skpViewportSize)))) {
1122         return {0, 0};
1123     }
1124     return viewport.roundOut().size();
1125 }
1126 
name() const1127 Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
1128 
1129 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1130 
BisectSrc(Path path,const char * trail)1131 BisectSrc::BisectSrc(Path path, const char* trail) : INHERITED(path), fTrail(trail) {}
1132 
draw(SkCanvas * canvas) const1133 Error BisectSrc::draw(SkCanvas* canvas) const {
1134     struct FoundPath {
1135         SkPath fPath;
1136         SkPaint fPaint;
1137         SkMatrix fViewMatrix;
1138     };
1139 
1140     // This subclass of SkCanvas just extracts all the SkPaths (drawn via drawPath) from an SKP.
1141     class PathFindingCanvas : public SkCanvas {
1142     public:
1143         PathFindingCanvas(int width, int height) : SkCanvas(width, height, nullptr) {}
1144         const SkTArray<FoundPath>& foundPaths() const { return fFoundPaths; }
1145 
1146     private:
1147         void onDrawPath(const SkPath& path, const SkPaint& paint) override {
1148             fFoundPaths.push_back() = {path, paint, this->getTotalMatrix()};
1149         }
1150 
1151         SkTArray<FoundPath> fFoundPaths;
1152     };
1153 
1154     PathFindingCanvas pathFinder(canvas->getBaseLayerSize().width(),
1155                                  canvas->getBaseLayerSize().height());
1156     Error err = this->INHERITED::draw(&pathFinder);
1157     if (!err.isEmpty()) {
1158         return err;
1159     }
1160 
1161     int start = 0, end = pathFinder.foundPaths().count();
1162     for (const char* ch = fTrail.c_str(); *ch; ++ch) {
1163         int midpt = (start + end) / 2;
1164         if ('l' == *ch) {
1165             start = midpt;
1166         } else if ('r' == *ch) {
1167             end = midpt;
1168         }
1169     }
1170 
1171     for (int i = start; i < end; ++i) {
1172         const FoundPath& path = pathFinder.foundPaths()[i];
1173         SkAutoCanvasRestore acr(canvas, true);
1174         canvas->concat(path.fViewMatrix);
1175         canvas->drawPath(path.fPath, path.fPaint);
1176     }
1177 
1178     return "";
1179 }
1180 
1181 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1182 
1183 #if defined(SK_ENABLE_SKOTTIE)
SkottieSrc(Path path)1184 SkottieSrc::SkottieSrc(Path path) : fPath(std::move(path)) {}
1185 
draw(SkCanvas * canvas) const1186 Error SkottieSrc::draw(SkCanvas* canvas) const {
1187     auto animation = skottie::Animation::Builder()
1188         .setResourceProvider(
1189                 skottie_utils::FileResourceProvider::Make(SkOSPath::Dirname(fPath.c_str())))
1190         .makeFromFile(fPath.c_str());
1191     if (!animation) {
1192         return SkStringPrintf("Unable to parse file: %s", fPath.c_str());
1193     }
1194 
1195     canvas->drawColor(SK_ColorWHITE);
1196 
1197     const auto t_rate = 1.0f / (kTileCount * kTileCount - 1);
1198 
1199     // Draw the frames in a shuffled order to exercise non-linear
1200     // frame progression. The film strip will still be in order left-to-right,
1201     // top-down, just not drawn in that order.
1202     static constexpr int frameOrder[] = { 4, 0, 3, 1, 2 };
1203     static_assert(SK_ARRAY_COUNT(frameOrder) == kTileCount, "");
1204 
1205     for (int i = 0; i < kTileCount; ++i) {
1206         const SkScalar y = frameOrder[i] * kTileSize;
1207 
1208         for (int j = 0; j < kTileCount; ++j) {
1209             const SkScalar x = frameOrder[j] * kTileSize;
1210             SkRect dest = SkRect::MakeXYWH(x, y, kTileSize, kTileSize);
1211 
1212             const auto t = t_rate * (frameOrder[i] * kTileCount + frameOrder[j]);
1213             {
1214                 SkAutoCanvasRestore acr(canvas, true);
1215                 canvas->clipRect(dest, true);
1216                 canvas->concat(SkMatrix::MakeRectToRect(SkRect::MakeSize(animation->size()),
1217                                                         dest,
1218                                                         SkMatrix::kCenter_ScaleToFit));
1219                 animation->seek(t);
1220                 animation->render(canvas);
1221             }
1222         }
1223     }
1224 
1225     return "";
1226 }
1227 
size() const1228 SkISize SkottieSrc::size() const {
1229     return SkISize::Make(kTargetSize, kTargetSize);
1230 }
1231 
name() const1232 Name SkottieSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
1233 
veto(SinkFlags flags) const1234 bool SkottieSrc::veto(SinkFlags flags) const {
1235     // No need to test to non-(raster||gpu||vector) or indirect backends.
1236     bool type_ok = flags.type == SinkFlags::kRaster
1237                 || flags.type == SinkFlags::kGPU
1238                 || flags.type == SinkFlags::kVector;
1239 
1240     return !type_ok || flags.approach != SinkFlags::kDirect;
1241 }
1242 #endif
1243 
1244 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1245 #if defined(SK_XML)
1246 // Used when the image doesn't have an intrinsic size.
1247 static const SkSize kDefaultSVGSize = {1000, 1000};
1248 
1249 // Used to force-scale tiny fixed-size images.
1250 static const SkSize kMinimumSVGSize = {128, 128};
1251 
SVGSrc(Path path)1252 SVGSrc::SVGSrc(Path path)
1253     : fName(SkOSPath::Basename(path.c_str()))
1254     , fScale(1) {
1255 
1256     sk_sp<SkData> data(SkData::MakeFromFileName(path.c_str()));
1257     if (!data) {
1258         return;
1259     }
1260 
1261     SkMemoryStream stream(std::move(data));
1262     fDom = SkSVGDOM::MakeFromStream(stream);
1263     if (!fDom) {
1264         return;
1265     }
1266 
1267     const SkSize& sz = fDom->containerSize();
1268     if (sz.isEmpty()) {
1269         // no intrinsic size
1270         fDom->setContainerSize(kDefaultSVGSize);
1271     } else {
1272         fScale = SkTMax(1.f, SkTMax(kMinimumSVGSize.width()  / sz.width(),
1273                                     kMinimumSVGSize.height() / sz.height()));
1274     }
1275 }
1276 
draw(SkCanvas * canvas) const1277 Error SVGSrc::draw(SkCanvas* canvas) const {
1278     if (!fDom) {
1279         return SkStringPrintf("Unable to parse file: %s", fName.c_str());
1280     }
1281 
1282     SkAutoCanvasRestore acr(canvas, true);
1283     canvas->scale(fScale, fScale);
1284     fDom->render(canvas);
1285 
1286     return "";
1287 }
1288 
size() const1289 SkISize SVGSrc::size() const {
1290     if (!fDom) {
1291         return {0, 0};
1292     }
1293 
1294     return SkSize{fDom->containerSize().width() * fScale, fDom->containerSize().height() * fScale}
1295             .toRound();
1296 }
1297 
name() const1298 Name SVGSrc::name() const { return fName; }
1299 
veto(SinkFlags flags) const1300 bool SVGSrc::veto(SinkFlags flags) const {
1301     // No need to test to non-(raster||gpu||vector) or indirect backends.
1302     bool type_ok = flags.type == SinkFlags::kRaster
1303                 || flags.type == SinkFlags::kGPU
1304                 || flags.type == SinkFlags::kVector;
1305 
1306     return !type_ok || flags.approach != SinkFlags::kDirect;
1307 }
1308 
1309 #endif // defined(SK_XML)
1310 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1311 
MSKPSrc(Path path)1312 MSKPSrc::MSKPSrc(Path path) : fPath(path) {
1313     std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fPath.c_str());
1314     int count = SkMultiPictureDocumentReadPageCount(stream.get());
1315     if (count > 0) {
1316         fPages.reset(count);
1317         (void)SkMultiPictureDocumentReadPageSizes(stream.get(), &fPages[0], fPages.count());
1318     }
1319 }
1320 
pageCount() const1321 int MSKPSrc::pageCount() const { return fPages.count(); }
1322 
size() const1323 SkISize MSKPSrc::size() const { return this->size(0); }
size(int i) const1324 SkISize MSKPSrc::size(int i) const {
1325     return i >= 0 && i < fPages.count() ? fPages[i].fSize.toCeil() : SkISize{0, 0};
1326 }
1327 
draw(SkCanvas * c) const1328 Error MSKPSrc::draw(SkCanvas* c) const { return this->draw(0, c); }
draw(int i,SkCanvas * canvas) const1329 Error MSKPSrc::draw(int i, SkCanvas* canvas) const {
1330     if (this->pageCount() == 0) {
1331         return SkStringPrintf("Unable to parse MultiPictureDocument file: %s", fPath.c_str());
1332     }
1333     if (i >= fPages.count() || i < 0) {
1334         return SkStringPrintf("MultiPictureDocument page number out of range: %d", i);
1335     }
1336     SkPicture* page = fPages[i].fPicture.get();
1337     if (!page) {
1338         std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fPath.c_str());
1339         if (!stream) {
1340             return SkStringPrintf("Unable to open file: %s", fPath.c_str());
1341         }
1342         if (!SkMultiPictureDocumentRead(stream.get(), &fPages[0], fPages.count())) {
1343             return SkStringPrintf("SkMultiPictureDocument reader failed on page %d: %s", i,
1344                                   fPath.c_str());
1345         }
1346         page = fPages[i].fPicture.get();
1347     }
1348     canvas->drawPicture(page);
1349     return "";
1350 }
1351 
name() const1352 Name MSKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
1353 
1354 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1355 
draw(const Src & src,SkBitmap *,SkWStream *,SkString *) const1356 Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const {
1357     return src.draw(SkMakeNullCanvas().get());
1358 }
1359 
1360 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1361 
compare_bitmaps(const SkBitmap & reference,const SkBitmap & bitmap)1362 static Error compare_bitmaps(const SkBitmap& reference, const SkBitmap& bitmap) {
1363     // The dimensions are a property of the Src only, and so should be identical.
1364     SkASSERT(reference.computeByteSize() == bitmap.computeByteSize());
1365     if (reference.computeByteSize() != bitmap.computeByteSize()) {
1366         return "Dimensions don't match reference";
1367     }
1368     // All SkBitmaps in DM are tight, so this comparison is easy.
1369     if (0 != memcmp(reference.getPixels(), bitmap.getPixels(), reference.computeByteSize())) {
1370         SkString encoded;
1371         SkString errString("Pixels don't match reference");
1372         if (bitmap_to_base64_data_uri(reference, &encoded)) {
1373             errString.append("\nExpected: ");
1374             errString.append(encoded);
1375         } else {
1376             errString.append("\nExpected image failed to encode: ");
1377             errString.append(encoded);
1378         }
1379         if (bitmap_to_base64_data_uri(bitmap, &encoded)) {
1380             errString.append("\nActual: ");
1381             errString.append(encoded);
1382         } else {
1383             errString.append("\nActual image failed to encode: ");
1384             errString.append(encoded);
1385         }
1386         return errString;
1387     }
1388     return "";
1389 }
1390 
1391 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1392 
1393 DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?");
1394 
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)1395 GPUSink::GPUSink(GrContextFactory::ContextType ct,
1396                  GrContextFactory::ContextOverrides overrides,
1397                  SkCommandLineConfigGpu::SurfType surfType,
1398                  int samples,
1399                  bool diText,
1400                  SkColorType colorType,
1401                  SkAlphaType alphaType,
1402                  sk_sp<SkColorSpace> colorSpace,
1403                  bool threaded,
1404                  const GrContextOptions& grCtxOptions)
1405         : fContextType(ct)
1406         , fContextOverrides(overrides)
1407         , fSurfType(surfType)
1408         , fSampleCount(samples)
1409         , fUseDIText(diText)
1410         , fColorType(colorType)
1411         , fAlphaType(alphaType)
1412         , fColorSpace(std::move(colorSpace))
1413         , fThreaded(threaded)
1414         , fBaseContextOptions(grCtxOptions) {}
1415 
1416 DEFINE_bool(drawOpClip, false, "Clip each GrDrawOp to its device bounds for testing.");
1417 
draw(const Src & src,SkBitmap * dst,SkWStream * dstStream,SkString * log) const1418 Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream* dstStream, SkString* log) const {
1419     return this->onDraw(src, dst, dstStream, log, fBaseContextOptions);
1420 }
1421 
onDraw(const Src & src,SkBitmap * dst,SkWStream *,SkString * log,const GrContextOptions & baseOptions) const1422 Error GPUSink::onDraw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log,
1423                       const GrContextOptions& baseOptions) const {
1424     GrContextOptions grOptions = baseOptions;
1425 
1426     // We don't expect the src to mess with the persistent cache or the executor.
1427     SkDEBUGCODE(auto cache = grOptions.fPersistentCache);
1428     SkDEBUGCODE(auto exec = grOptions.fExecutor);
1429     src.modifyGrContextOptions(&grOptions);
1430     SkASSERT(cache == grOptions.fPersistentCache);
1431     SkASSERT(exec == grOptions.fExecutor);
1432 
1433     GrContextFactory factory(grOptions);
1434     const SkISize size = src.size();
1435     SkImageInfo info =
1436             SkImageInfo::Make(size.width(), size.height(), fColorType, fAlphaType, fColorSpace);
1437     sk_sp<SkSurface> surface;
1438     GrContext* context = factory.getContextInfo(fContextType, fContextOverrides).grContext();
1439     const int maxDimension = context->contextPriv().caps()->maxTextureSize();
1440     if (maxDimension < SkTMax(size.width(), size.height())) {
1441         return Error::Nonfatal("Src too large to create a texture.\n");
1442     }
1443     uint32_t flags = fUseDIText ? SkSurfaceProps::kUseDeviceIndependentFonts_Flag : 0;
1444     SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
1445     GrBackendTexture backendTexture;
1446     GrBackendRenderTarget backendRT;
1447     switch (fSurfType) {
1448         case SkCommandLineConfigGpu::SurfType::kDefault:
1449             surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, fSampleCount,
1450                                                   &props);
1451             break;
1452         case SkCommandLineConfigGpu::SurfType::kBackendTexture:
1453             backendTexture = context->contextPriv().getGpu()->createTestingOnlyBackendTexture(
1454                     nullptr, info.width(), info.height(), info.colorType(), true, GrMipMapped::kNo);
1455             surface = SkSurface::MakeFromBackendTexture(context, backendTexture,
1456                                                         kTopLeft_GrSurfaceOrigin, fSampleCount,
1457                                                         fColorType, info.refColorSpace(), &props);
1458             break;
1459         case SkCommandLineConfigGpu::SurfType::kBackendRenderTarget:
1460             if (1 == fSampleCount) {
1461                 auto colorType = SkColorTypeToGrColorType(info.colorType());
1462                 backendRT = context->contextPriv().getGpu()->createTestingOnlyBackendRenderTarget(
1463                         info.width(), info.height(), colorType);
1464                 surface = SkSurface::MakeFromBackendRenderTarget(
1465                         context, backendRT, kBottomLeft_GrSurfaceOrigin, info.colorType(),
1466                         info.refColorSpace(), &props);
1467             }
1468             break;
1469     }
1470 
1471     if (!surface) {
1472         return "Could not create a surface.";
1473     }
1474     if (FLAGS_preAbandonGpuContext) {
1475         factory.abandonContexts();
1476     }
1477     SkCanvas* canvas = surface->getCanvas();
1478     Error err = src.draw(canvas);
1479     if (!err.isEmpty()) {
1480         return err;
1481     }
1482     canvas->flush();
1483     if (FLAGS_gpuStats) {
1484         canvas->getGrContext()->contextPriv().dumpCacheStats(log);
1485         canvas->getGrContext()->contextPriv().dumpGpuStats(log);
1486     }
1487     if (info.colorType() == kRGB_565_SkColorType || info.colorType() == kARGB_4444_SkColorType ||
1488         info.colorType() == kRGB_888x_SkColorType) {
1489         // We don't currently support readbacks into these formats on the GPU backend. Convert to
1490         // 32 bit.
1491         info = SkImageInfo::Make(size.width(), size.height(), kRGBA_8888_SkColorType,
1492                                  kPremul_SkAlphaType, fColorSpace);
1493     }
1494     dst->allocPixels(info);
1495     canvas->readPixels(*dst, 0, 0);
1496     if (FLAGS_abandonGpuContext) {
1497         factory.abandonContexts();
1498     } else if (FLAGS_releaseAndAbandonGpuContext) {
1499         factory.releaseResourcesAndAbandonContexts();
1500     }
1501     if (!context->abandoned()) {
1502         surface.reset();
1503         if (backendTexture.isValid()) {
1504             context->contextPriv().getGpu()->deleteTestingOnlyBackendTexture(backendTexture);
1505         }
1506         if (backendRT.isValid()) {
1507             context->contextPriv().getGpu()->deleteTestingOnlyBackendRenderTarget(backendRT);
1508         }
1509     }
1510     if (grOptions.fPersistentCache) {
1511         context->storeVkPipelineCacheData();
1512     }
1513     return "";
1514 }
1515 
1516 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1517 
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)1518 GPUThreadTestingSink::GPUThreadTestingSink(GrContextFactory::ContextType ct,
1519                                            GrContextFactory::ContextOverrides overrides,
1520                                            SkCommandLineConfigGpu::SurfType surfType,
1521                                            int samples,
1522                                            bool diText,
1523                                            SkColorType colorType,
1524                                            SkAlphaType alphaType,
1525                                            sk_sp<SkColorSpace> colorSpace,
1526                                            bool threaded,
1527                                            const GrContextOptions& grCtxOptions)
1528         : INHERITED(ct, overrides, surfType, samples, diText, colorType, alphaType,
1529                     std::move(colorSpace), threaded, grCtxOptions)
1530         , fExecutor(SkExecutor::MakeFIFOThreadPool(FLAGS_gpuThreads)) {
1531     SkASSERT(fExecutor);
1532 }
1533 
draw(const Src & src,SkBitmap * dst,SkWStream * wStream,SkString * log) const1534 Error GPUThreadTestingSink::draw(const Src& src, SkBitmap* dst, SkWStream* wStream,
1535                                  SkString* log) const {
1536     // Draw twice, once with worker threads, and once without. Verify that we get the same result.
1537     // Also, force us to only use the software path renderer, so we really stress-test the threaded
1538     // version of that code.
1539     GrContextOptions contextOptions = this->baseContextOptions();
1540     contextOptions.fGpuPathRenderers = GpuPathRenderers::kNone;
1541     contextOptions.fExecutor = fExecutor.get();
1542 
1543     Error err = this->onDraw(src, dst, wStream, log, contextOptions);
1544     if (!err.isEmpty() || !dst) {
1545         return err;
1546     }
1547 
1548     SkBitmap reference;
1549     SkString refLog;
1550     SkDynamicMemoryWStream refStream;
1551     contextOptions.fExecutor = nullptr;
1552     Error refErr = this->onDraw(src, &reference, &refStream, &refLog, contextOptions);
1553     if (!refErr.isEmpty()) {
1554         return refErr;
1555     }
1556 
1557     return compare_bitmaps(reference, *dst);
1558 }
1559 
1560 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1561 
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)1562 GPUPersistentCacheTestingSink::GPUPersistentCacheTestingSink(
1563         GrContextFactory::ContextType ct,
1564         GrContextFactory::ContextOverrides overrides,
1565         SkCommandLineConfigGpu::SurfType surfType,
1566         int samples,
1567         bool diText,
1568         SkColorType colorType,
1569         SkAlphaType alphaType,
1570         sk_sp<SkColorSpace> colorSpace,
1571         bool threaded,
1572         const GrContextOptions& grCtxOptions)
1573         : INHERITED(ct, overrides, surfType, samples, diText, colorType, alphaType,
1574                     std::move(colorSpace), threaded, grCtxOptions) {}
1575 
draw(const Src & src,SkBitmap * dst,SkWStream * wStream,SkString * log) const1576 Error GPUPersistentCacheTestingSink::draw(const Src& src, SkBitmap* dst, SkWStream* wStream,
1577                                           SkString* log) const {
1578     // Draw twice, once with a cold cache, and again with a warm cache. Verify that we get the same
1579     // result.
1580     sk_gpu_test::MemoryCache memoryCache;
1581     GrContextOptions contextOptions = this->baseContextOptions();
1582     contextOptions.fPersistentCache = &memoryCache;
1583 
1584     Error err = this->onDraw(src, dst, wStream, log, contextOptions);
1585     if (!err.isEmpty() || !dst) {
1586         return err;
1587     }
1588 
1589     SkBitmap reference;
1590     SkString refLog;
1591     SkDynamicMemoryWStream refStream;
1592     memoryCache.resetNumCacheMisses();
1593     Error refErr = this->onDraw(src, &reference, &refStream, &refLog, contextOptions);
1594     if (!refErr.isEmpty()) {
1595         return refErr;
1596     }
1597     SkASSERT(!memoryCache.numCacheMisses());
1598 
1599     return compare_bitmaps(reference, *dst);
1600 }
1601 
1602 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
draw_skdocument(const Src & src,SkDocument * doc,SkWStream * dst)1603 static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) {
1604     if (src.size().isEmpty()) {
1605         return "Source has empty dimensions";
1606     }
1607     SkASSERT(doc);
1608     int pageCount = src.pageCount();
1609     for (int i = 0; i < pageCount; ++i) {
1610         int width = src.size(i).width(), height = src.size(i).height();
1611         SkCanvas* canvas =
1612                 doc->beginPage(SkIntToScalar(width), SkIntToScalar(height));
1613         if (!canvas) {
1614             return "SkDocument::beginPage(w,h) returned nullptr";
1615         }
1616         Error err = src.draw(i, canvas);
1617         if (!err.isEmpty()) {
1618             return err;
1619         }
1620         doc->endPage();
1621     }
1622     doc->close();
1623     dst->flush();
1624     return "";
1625 }
1626 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1627 Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1628     SkPDF::Metadata metadata;
1629     metadata.fTitle = src.name();
1630     metadata.fSubject = "rendering correctness test";
1631     metadata.fCreator = "Skia/DM";
1632     metadata.fRasterDPI = fRasterDpi;
1633     metadata.fPDFA = fPDFA;
1634 #if SK_PDF_TEST_EXECUTOR
1635     std::unique_ptr<SkExecutor> executor = SkExecutor::MakeFIFOThreadPool();
1636     metadata.fExecutor = executor.get();
1637 #endif
1638     auto doc = SkPDF::MakeDocument(dst, metadata);
1639     if (!doc) {
1640         return "SkPDF::MakeDocument() returned nullptr";
1641     }
1642     return draw_skdocument(src, doc.get(), dst);
1643 }
1644 
1645 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1646 
XPSSink()1647 XPSSink::XPSSink() {}
1648 
1649 #ifdef SK_BUILD_FOR_WIN
make_xps_factory()1650 static SkTScopedComPtr<IXpsOMObjectFactory> make_xps_factory() {
1651     IXpsOMObjectFactory* factory;
1652     HRN(CoCreateInstance(CLSID_XpsOMObjectFactory,
1653                          nullptr,
1654                          CLSCTX_INPROC_SERVER,
1655                          IID_PPV_ARGS(&factory)));
1656     return SkTScopedComPtr<IXpsOMObjectFactory>(factory);
1657 }
1658 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1659 Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1660     SkAutoCoInitialize com;
1661     if (!com.succeeded()) {
1662         return "Could not initialize COM.";
1663     }
1664     SkTScopedComPtr<IXpsOMObjectFactory> factory = make_xps_factory();
1665     if (!factory) {
1666         return "Failed to create XPS Factory.";
1667     }
1668     auto doc = SkXPS::MakeDocument(dst, factory.get());
1669     if (!doc) {
1670         return "SkXPS::MakeDocument() returned nullptr";
1671     }
1672     return draw_skdocument(src, doc.get(), dst);
1673 }
1674 #else
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1675 Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1676     return "XPS not supported on this platform.";
1677 }
1678 #endif
1679 
1680 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1681 
SKPSink()1682 SKPSink::SKPSink() {}
1683 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1684 Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1685     SkSize size;
1686     size = src.size();
1687     SkPictureRecorder recorder;
1688     Error err = src.draw(recorder.beginRecording(size.width(), size.height()));
1689     if (!err.isEmpty()) {
1690         return err;
1691     }
1692     recorder.finishRecordingAsPicture()->serialize(dst);
1693     return "";
1694 }
1695 
1696 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1697 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1698 Error DebugSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1699     SkDebugCanvas debugCanvas(src.size().width(), src.size().height());
1700     Error err = src.draw(&debugCanvas);
1701     if (!err.isEmpty()) {
1702         return err;
1703     }
1704     std::unique_ptr<SkCanvas> nullCanvas = SkMakeNullCanvas();
1705     UrlDataManager dataManager(SkString("data"));
1706     SkJSONWriter writer(dst, SkJSONWriter::Mode::kPretty);
1707     writer.beginObject(); // root
1708     debugCanvas.toJSON(writer, dataManager, debugCanvas.getSize(), nullCanvas.get());
1709     writer.endObject(); // root
1710     writer.flush();
1711     return "";
1712 }
1713 
1714 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1715 
SVGSink(int pageIndex)1716 SVGSink::SVGSink(int pageIndex) : fPageIndex(pageIndex) {}
1717 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1718 Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1719 #if defined(SK_XML)
1720     if (src.pageCount() > 1) {
1721         int pageCount = src.pageCount();
1722         if (fPageIndex > pageCount - 1) {
1723             return Error(SkStringPrintf("Page index %d too high for document with only %d pages.",
1724                                         fPageIndex, pageCount));
1725         }
1726     }
1727     std::unique_ptr<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(dst));
1728     return src.draw(fPageIndex,
1729                     SkSVGCanvas::Make(SkRect::MakeWH(SkIntToScalar(src.size().width()),
1730                                                      SkIntToScalar(src.size().height())),
1731                                       xmlWriter.get())
1732                             .get());
1733 #else
1734     (void)fPageIndex;
1735     return Error("SVG sink is disabled.");
1736 #endif // SK_XML
1737 }
1738 
1739 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1740 
RasterSink(SkColorType colorType,sk_sp<SkColorSpace> colorSpace)1741 RasterSink::RasterSink(SkColorType colorType, sk_sp<SkColorSpace> colorSpace)
1742     : fColorType(colorType)
1743     , fColorSpace(std::move(colorSpace)) {}
1744 
draw(const Src & src,SkBitmap * dst,SkWStream *,SkString *) const1745 Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
1746     const SkISize size = src.size();
1747     // If there's an appropriate alpha type for this color type, use it, otherwise use premul.
1748     SkAlphaType alphaType = kPremul_SkAlphaType;
1749     (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType);
1750 
1751     dst->allocPixelsFlags(SkImageInfo::Make(size.width(), size.height(),
1752                                             fColorType, alphaType, fColorSpace),
1753                           SkBitmap::kZeroPixels_AllocFlag);
1754 
1755     SkCanvas canvas(*dst);
1756     return src.draw(&canvas);
1757 }
1758 
1759 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1760 
1761 // Handy for front-patching a Src.  Do whatever up-front work you need, then call draw_to_canvas(),
1762 // passing the Sink draw() arguments, a size, and a function draws into an SkCanvas.
1763 // Several examples below.
1764 
1765 template <typename Fn>
draw_to_canvas(Sink * sink,SkBitmap * bitmap,SkWStream * stream,SkString * log,SkISize size,const Fn & draw)1766 static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log,
1767                             SkISize size, const Fn& draw) {
1768     class ProxySrc : public Src {
1769     public:
1770         ProxySrc(SkISize size, const Fn& draw) : fSize(size), fDraw(draw) {}
1771         Error   draw(SkCanvas* canvas) const override { return fDraw(canvas); }
1772         Name    name() const override { return "ProxySrc"; }
1773         SkISize size() const override { return fSize; }
1774     private:
1775         SkISize   fSize;
1776         const Fn& fDraw;
1777     };
1778     return sink->draw(ProxySrc(size, draw), bitmap, stream, log);
1779 }
1780 
1781 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1782 
1783 DEFINE_bool(check, true, "If true, have most Via- modes fail if they affect the output.");
1784 
1785 // Is *bitmap identical to what you get drawing src into sink?
check_against_reference(const SkBitmap * bitmap,const Src & src,Sink * sink)1786 static Error check_against_reference(const SkBitmap* bitmap, const Src& src, Sink* sink) {
1787     // We can only check raster outputs.
1788     // (Non-raster outputs like .pdf, .skp, .svg may differ but still draw identically.)
1789     if (FLAGS_check && bitmap) {
1790         SkBitmap reference;
1791         SkString log;
1792         SkDynamicMemoryWStream wStream;
1793         Error err = sink->draw(src, &reference, &wStream, &log);
1794         // If we can draw into this Sink via some pipeline, we should be able to draw directly.
1795         SkASSERT(err.isEmpty());
1796         if (!err.isEmpty()) {
1797             return err;
1798         }
1799         return compare_bitmaps(reference, *bitmap);
1800     }
1801     return "";
1802 }
1803 
1804 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1805 
auto_compute_translate(SkMatrix * matrix,int srcW,int srcH)1806 static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) {
1807     SkRect bounds = SkRect::MakeIWH(srcW, srcH);
1808     matrix->mapRect(&bounds);
1809     matrix->postTranslate(-bounds.x(), -bounds.y());
1810     return {SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height())};
1811 }
1812 
ViaMatrix(SkMatrix matrix,Sink * sink)1813 ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
1814 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1815 Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1816     SkMatrix matrix = fMatrix;
1817     SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height());
1818     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) {
1819         canvas->concat(matrix);
1820         return src.draw(canvas);
1821     });
1822 }
1823 
1824 // Undoes any flip or 90 degree rotate without changing the scale of the bitmap.
1825 // This should be pixel-preserving.
ViaUpright(SkMatrix matrix,Sink * sink)1826 ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
1827 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1828 Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1829     Error err = fSink->draw(src, bitmap, stream, log);
1830     if (!err.isEmpty()) {
1831         return err;
1832     }
1833 
1834     SkMatrix inverse;
1835     if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) {
1836         return "Cannot upright --matrix.";
1837     }
1838     SkMatrix upright = SkMatrix::I();
1839     upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX()));
1840     upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY()));
1841     upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX()));
1842     upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY()));
1843 
1844     SkBitmap uprighted;
1845     SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height());
1846     uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height()));
1847 
1848     SkCanvas canvas(uprighted);
1849     canvas.concat(upright);
1850     SkPaint paint;
1851     paint.setBlendMode(SkBlendMode::kSrc);
1852     canvas.drawBitmap(*bitmap, 0, 0, &paint);
1853 
1854     *bitmap = uprighted;
1855     return "";
1856 }
1857 
1858 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1859 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1860 Error ViaSerialization::draw(
1861         const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1862     // Record our Src into a picture.
1863     auto size = src.size();
1864     SkPictureRecorder recorder;
1865     Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1866                                                  SkIntToScalar(size.height())));
1867     if (!err.isEmpty()) {
1868         return err;
1869     }
1870     sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture());
1871 
1872     // Serialize it and then deserialize it.
1873     sk_sp<SkPicture> deserialized(SkPicture::MakeFromData(pic->serialize().get()));
1874 
1875     err = draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) {
1876         canvas->drawPicture(deserialized);
1877         return "";
1878     });
1879     if (!err.isEmpty()) {
1880         return err;
1881     }
1882 
1883     return check_against_reference(bitmap, src, fSink.get());
1884 }
1885 
1886 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1887 
ViaTiles(int w,int h,SkBBHFactory * factory,Sink * sink)1888 ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink)
1889     : Via(sink)
1890     , fW(w)
1891     , fH(h)
1892     , fFactory(factory) {}
1893 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1894 Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1895     auto size = src.size();
1896     SkPictureRecorder recorder;
1897     Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1898                                                  SkIntToScalar(size.height()),
1899                                                  fFactory.get()));
1900     if (!err.isEmpty()) {
1901         return err;
1902     }
1903     sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture());
1904 
1905     return draw_to_canvas(fSink.get(), bitmap, stream, log, src.size(), [&](SkCanvas* canvas) {
1906         const int xTiles = (size.width()  + fW - 1) / fW,
1907                   yTiles = (size.height() + fH - 1) / fH;
1908         SkMultiPictureDraw mpd(xTiles*yTiles);
1909         SkTArray<sk_sp<SkSurface>> surfaces;
1910 //        surfaces.setReserve(xTiles*yTiles);
1911 
1912         SkImageInfo info = canvas->imageInfo().makeWH(fW, fH);
1913         for (int j = 0; j < yTiles; j++) {
1914             for (int i = 0; i < xTiles; i++) {
1915                 // This lets our ultimate Sink determine the best kind of surface.
1916                 // E.g., if it's a GpuSink, the surfaces and images are textures.
1917                 auto s = canvas->makeSurface(info);
1918                 if (!s) {
1919                     s = SkSurface::MakeRaster(info);  // Some canvases can't create surfaces.
1920                 }
1921                 surfaces.push_back(s);
1922                 SkCanvas* c = s->getCanvas();
1923                 c->translate(SkIntToScalar(-i * fW),
1924                              SkIntToScalar(-j * fH));  // Line up the canvas with this tile.
1925                 mpd.add(c, pic.get());
1926             }
1927         }
1928         mpd.draw();
1929         for (int j = 0; j < yTiles; j++) {
1930             for (int i = 0; i < xTiles; i++) {
1931                 sk_sp<SkImage> image(surfaces[i+xTiles*j]->makeImageSnapshot());
1932                 canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH));
1933             }
1934         }
1935         return "";
1936     });
1937 }
1938 
1939 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1940 
ViaDDL(int numReplays,int numDivisions,Sink * sink)1941 ViaDDL::ViaDDL(int numReplays, int numDivisions, Sink* sink)
1942         : Via(sink), fNumReplays(numReplays), fNumDivisions(numDivisions) {}
1943 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1944 Error ViaDDL::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1945     auto size = src.size();
1946     SkPictureRecorder recorder;
1947     Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1948                                                  SkIntToScalar(size.height())));
1949     if (!err.isEmpty()) {
1950         return err;
1951     }
1952     sk_sp<SkPicture> inputPicture(recorder.finishRecordingAsPicture());
1953 
1954     // this is our ultimate final drawing area/rect
1955     SkIRect viewport = SkIRect::MakeWH(size.fWidth, size.fHeight);
1956 
1957     // When we're only doing one replay we exercise the code path that delays calling release
1958     // until the SkImage is destroyed.
1959     SkDeferredDisplayListRecorder::DelayReleaseCallback delayReleaseCallback;
1960     if (fNumReplays > 1) {
1961         delayReleaseCallback = SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo;
1962     } else {
1963         delayReleaseCallback = SkDeferredDisplayListRecorder::DelayReleaseCallback::kYes;
1964     }
1965     DDLPromiseImageHelper promiseImageHelper(delayReleaseCallback);
1966     sk_sp<SkData> compressedPictureData = promiseImageHelper.deflateSKP(inputPicture.get());
1967     if (!compressedPictureData) {
1968         return SkStringPrintf("ViaDDL: Couldn't deflate SkPicture");
1969     }
1970     auto draw = [&](SkCanvas* canvas) -> Error {
1971         GrContext* context = canvas->getGrContext();
1972         if (!context || !context->contextPriv().getGpu()) {
1973             return SkStringPrintf("DDLs are GPU only");
1974         }
1975 
1976         // This is here bc this is the first point where we have access to the context
1977         promiseImageHelper.uploadAllToGPU(context);
1978         // We draw N times, with a clear between. Between each run we invalidate and delete half of
1979         // the textures backing promise images. So half the images exercise reusing a cached
1980         // GrTexture and the other half exercise the case whem the client provides a different
1981         // backing texture in fulfill.
1982         for (int replay = 0; replay < fNumReplays; ++replay) {
1983             if (replay > 0) {
1984                 // Clear the drawing of the previous replay
1985                 canvas->clear(SK_ColorTRANSPARENT);
1986             }
1987             // First, create all the tiles (including their individual dest surfaces)
1988             DDLTileHelper tiles(canvas, viewport, fNumDivisions);
1989 
1990             // Second, reinflate the compressed picture individually for each thread
1991             // This recreates the promise SkImages on each replay iteration. We are currently
1992             // relying on this to test using a SkPromiseImageTexture to fulfill different
1993             // SkImages. On each replay the promise SkImages are recreated in createSKPPerTile.
1994             tiles.createSKPPerTile(compressedPictureData.get(), promiseImageHelper);
1995 
1996             // Third, create the DDLs in parallel
1997             tiles.createDDLsInParallel();
1998 
1999             if (replay == fNumReplays - 1) {
2000                 // This drops the promiseImageHelper's refs on all the promise images if we're in
2001                 // the last run.
2002                 promiseImageHelper.reset();
2003             } else {
2004                 // This ought to ensure that all promise image textures from the last pass are
2005                 // released.
2006                 context->contextPriv().getGpu()->testingOnly_flushGpuAndSync();
2007                 promiseImageHelper.replaceEveryOtherPromiseTexture(context);
2008             }
2009 
2010             // Fourth, synchronously render the display lists into the dest tiles
2011             // TODO: it would be cool to not wait until all the tiles are drawn to begin
2012             // drawing to the GPU and composing to the final surface
2013             tiles.drawAllTilesAndFlush(context, false);
2014 
2015             // Finally, compose the drawn tiles into the result
2016             // Note: the separation between the tiles and the final composition better
2017             // matches Chrome but costs us a copy
2018             tiles.composeAllTiles(canvas);
2019             context->flush();
2020         }
2021         return "";
2022     };
2023     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, draw);
2024 }
2025 
2026 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2027 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const2028 Error ViaPicture::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
2029     auto size = src.size();
2030     Error err = draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) {
2031         SkPictureRecorder recorder;
2032         sk_sp<SkPicture> pic;
2033         Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
2034                                                      SkIntToScalar(size.height())));
2035         if (!err.isEmpty()) {
2036             return err;
2037         }
2038         pic = recorder.finishRecordingAsPicture();
2039         canvas->drawPicture(pic);
2040         return err;
2041     });
2042     if (!err.isEmpty()) {
2043         return err;
2044     }
2045 
2046     return check_against_reference(bitmap, src, fSink.get());
2047 }
2048 
2049 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2050 
2051 #ifdef TEST_VIA_SVG
2052 #include "SkXMLWriter.h"
2053 #include "SkSVGCanvas.h"
2054 #include "SkSVGDOM.h"
2055 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const2056 Error ViaSVG::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
2057     auto size = src.size();
2058     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
2059         SkDynamicMemoryWStream wstream;
2060         SkXMLStreamWriter writer(&wstream);
2061         Error err = src.draw(SkSVGCanvas::Make(SkRect::Make(size), &writer).get());
2062         if (!err.isEmpty()) {
2063             return err;
2064         }
2065         std::unique_ptr<SkStream> rstream(wstream.detachAsStream());
2066         auto dom = SkSVGDOM::MakeFromStream(*rstream);
2067         if (dom) {
2068             dom->setContainerSize(SkSize::Make(size));
2069             dom->render(canvas);
2070         }
2071         return "";
2072     });
2073 }
2074 #endif
2075 
2076 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2077 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const2078 Error ViaLite::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
2079     auto size = src.size();
2080     SkIRect bounds = {0,0, size.width(), size.height()};
2081     Error err = draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) {
2082         SkLiteDL dl;
2083         SkLiteRecorder rec;
2084         rec.reset(&dl, bounds);
2085 
2086         Error err = src.draw(&rec);
2087         if (!err.isEmpty()) {
2088             return err;
2089         }
2090         dl.draw(canvas);
2091         return err;
2092     });
2093     if (!err.isEmpty()) {
2094         return err;
2095     }
2096 
2097     return check_against_reference(bitmap, src, fSink.get());
2098 }
2099 
2100 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2101 
ViaCSXform(Sink * sink,sk_sp<SkColorSpace> cs,bool colorSpin)2102 ViaCSXform::ViaCSXform(Sink* sink, sk_sp<SkColorSpace> cs, bool colorSpin)
2103     : Via(sink)
2104     , fCS(std::move(cs))
2105     , fColorSpin(colorSpin) {}
2106 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const2107 Error ViaCSXform::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
2108     Error err = draw_to_canvas(fSink.get(), bitmap, stream, log, src.size(), [&](SkCanvas* canvas) {
2109         {
2110             SkAutoCanvasRestore acr(canvas, true);
2111             auto proxy = SkCreateColorSpaceXformCanvas(canvas, fCS);
2112             Error err = src.draw(proxy.get());
2113             if (!err.isEmpty()) {
2114                 return err;
2115             }
2116         }
2117 
2118         // Undo the color spin, so we can look at the pixels in Gold.
2119         if (fColorSpin) {
2120             SkBitmap pixels;
2121             pixels.allocPixels(canvas->imageInfo());
2122             canvas->readPixels(pixels, 0, 0);
2123 
2124             SkPaint rotateColors;
2125             SkScalar matrix[20] = { 0, 0, 1, 0, 0,   // B -> R
2126                                     1, 0, 0, 0, 0,   // R -> G
2127                                     0, 1, 0, 0, 0,   // G -> B
2128                                     0, 0, 0, 1, 0 };
2129             rotateColors.setBlendMode(SkBlendMode::kSrc);
2130             rotateColors.setColorFilter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
2131             canvas->drawBitmap(pixels, 0, 0, &rotateColors);
2132         }
2133 
2134         return Error("");
2135     });
2136 
2137     if (!err.isEmpty()) {
2138         return err;
2139     }
2140 
2141     if (bitmap && !fColorSpin) {
2142         // It should be possible to do this without all the copies, but that (I think) requires
2143         // adding API to SkBitmap.
2144         SkAutoPixmapStorage pmap;
2145         pmap.alloc(bitmap->info());
2146         bitmap->readPixels(pmap);
2147         pmap.setColorSpace(fCS);
2148         bitmap->allocPixels(pmap.info());
2149         bitmap->writePixels(pmap);
2150     }
2151 
2152     return "";
2153 }
2154 
2155 }  // namespace DM
2156