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 "Resources.h"
10 #include "SkAndroidCodec.h"
11 #include "SkAutoMalloc.h"
12 #include "SkCodec.h"
13 #include "SkCodecImageGenerator.h"
14 #include "SkColorSpace.h"
15 #include "SkColorSpaceXform.h"
16 #include "SkColorSpaceXformCanvas.h"
17 #include "SkColorSpace_XYZ.h"
18 #include "SkCommonFlags.h"
19 #include "SkData.h"
20 #include "SkDebugCanvas.h"
21 #include "SkDeferredCanvas.h"
22 #include "SkDocument.h"
23 #include "SkImageGenerator.h"
24 #include "SkImageGeneratorCG.h"
25 #include "SkImageGeneratorWIC.h"
26 #include "SkLiteDL.h"
27 #include "SkLiteRecorder.h"
28 #include "SkMallocPixelRef.h"
29 #include "SkMultiPictureDraw.h"
30 #include "SkNullCanvas.h"
31 #include "SkOSFile.h"
32 #include "SkOSPath.h"
33 #include "SkOpts.h"
34 #include "SkPictureData.h"
35 #include "SkPictureRecorder.h"
36 #include "SkPipe.h"
37 #include "SkRandom.h"
38 #include "SkRecordDraw.h"
39 #include "SkRecorder.h"
40 #include "SkSVGCanvas.h"
41 #include "SkStream.h"
42 #include "SkSwizzler.h"
43 #include "SkTLogic.h"
44 #include <cmath>
45 #include <functional>
46 
47 #if defined(SK_BUILD_FOR_WIN)
48     #include "SkAutoCoInitialize.h"
49     #include "SkHRESULT.h"
50     #include "SkTScopedComPtr.h"
51     #include <XpsObjectModel.h>
52 #endif
53 
54 #if defined(SK_XML)
55     #include "SkSVGDOM.h"
56     #include "SkXMLWriter.h"
57 #endif
58 
59 DEFINE_bool(multiPage, false, "For document-type backends, render the source"
60             " into multiple pages");
61 DEFINE_bool(RAW_threading, true, "Allow RAW decodes to run on multiple threads?");
62 
63 using sk_gpu_test::GrContextFactory;
64 
65 namespace DM {
66 
GMSrc(skiagm::GMRegistry::Factory factory)67 GMSrc::GMSrc(skiagm::GMRegistry::Factory factory) : fFactory(factory) {}
68 
draw(SkCanvas * canvas) const69 Error GMSrc::draw(SkCanvas* canvas) const {
70     std::unique_ptr<skiagm::GM> gm(fFactory(nullptr));
71     canvas->concat(gm->getInitialTransform());
72     gm->draw(canvas);
73     return "";
74 }
75 
size() const76 SkISize GMSrc::size() const {
77     std::unique_ptr<skiagm::GM> gm(fFactory(nullptr));
78     return gm->getISize();
79 }
80 
name() const81 Name GMSrc::name() const {
82     std::unique_ptr<skiagm::GM> gm(fFactory(nullptr));
83     return gm->getName();
84 }
85 
modifyGrContextOptions(GrContextOptions * options) const86 void GMSrc::modifyGrContextOptions(GrContextOptions* options) const {
87     std::unique_ptr<skiagm::GM> gm(fFactory(nullptr));
88     gm->modifyGrContextOptions(options);
89 }
90 
91 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
92 
BRDSrc(Path path,Mode mode,CodecSrc::DstColorType dstColorType,uint32_t sampleSize)93 BRDSrc::BRDSrc(Path path, Mode mode, CodecSrc::DstColorType dstColorType, uint32_t sampleSize)
94     : fPath(path)
95     , fMode(mode)
96     , fDstColorType(dstColorType)
97     , fSampleSize(sampleSize)
98 {}
99 
veto(SinkFlags flags) const100 bool BRDSrc::veto(SinkFlags flags) const {
101     // No need to test to non-raster or indirect backends.
102     return flags.type != SinkFlags::kRaster
103         || flags.approach != SinkFlags::kDirect;
104 }
105 
create_brd(Path path)106 static SkBitmapRegionDecoder* create_brd(Path path) {
107     sk_sp<SkData> encoded(SkData::MakeFromFileName(path.c_str()));
108     if (!encoded) {
109         return NULL;
110     }
111     return SkBitmapRegionDecoder::Create(encoded, SkBitmapRegionDecoder::kAndroidCodec_Strategy);
112 }
113 
alpha8_to_gray8(SkBitmap * bitmap)114 static inline void alpha8_to_gray8(SkBitmap* bitmap) {
115     // Android requires kGray8 bitmaps to be tagged as kAlpha8.  Here we convert
116     // them back to kGray8 so our test framework can draw them correctly.
117     if (kAlpha_8_SkColorType == bitmap->info().colorType()) {
118         SkImageInfo newInfo = bitmap->info().makeColorType(kGray_8_SkColorType)
119                                             .makeAlphaType(kOpaque_SkAlphaType);
120         *const_cast<SkImageInfo*>(&bitmap->info()) = newInfo;
121     }
122 }
123 
draw(SkCanvas * canvas) const124 Error BRDSrc::draw(SkCanvas* canvas) const {
125     SkColorType colorType = canvas->imageInfo().colorType();
126     if (kRGB_565_SkColorType == colorType &&
127             CodecSrc::kGetFromCanvas_DstColorType != fDstColorType) {
128         return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
129     }
130     switch (fDstColorType) {
131         case CodecSrc::kGetFromCanvas_DstColorType:
132             break;
133         case CodecSrc::kIndex8_Always_DstColorType:
134             colorType = kIndex_8_SkColorType;
135             break;
136         case CodecSrc::kGrayscale_Always_DstColorType:
137             colorType = kGray_8_SkColorType;
138             break;
139         default:
140             SkASSERT(false);
141             break;
142     }
143 
144     std::unique_ptr<SkBitmapRegionDecoder> brd(create_brd(fPath));
145     if (nullptr == brd.get()) {
146         return Error::Nonfatal(SkStringPrintf("Could not create brd for %s.", fPath.c_str()));
147     }
148 
149     if (!brd->conversionSupported(colorType)) {
150         return Error::Nonfatal("Cannot convert to color type.");
151     }
152 
153     const uint32_t width = brd->width();
154     const uint32_t height = brd->height();
155     // Visually inspecting very small output images is not necessary.
156     if ((width / fSampleSize <= 10 || height / fSampleSize <= 10) && 1 != fSampleSize) {
157         return Error::Nonfatal("Scaling very small images is uninteresting.");
158     }
159     switch (fMode) {
160         case kFullImage_Mode: {
161             SkBitmap bitmap;
162             if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(0, 0, width, height),
163                     fSampleSize, colorType, false, SkColorSpace::MakeSRGB())) {
164                 return "Cannot decode (full) region.";
165             }
166             alpha8_to_gray8(&bitmap);
167             canvas->drawBitmap(bitmap, 0, 0);
168             return "";
169         }
170         case kDivisor_Mode: {
171             const uint32_t divisor = 2;
172             if (width < divisor || height < divisor) {
173                 return Error::Nonfatal("Divisor is larger than image dimension.");
174             }
175 
176             // Use a border to test subsets that extend outside the image.
177             // We will not allow the border to be larger than the image dimensions.  Allowing
178             // these large borders causes off by one errors that indicate a problem with the
179             // test suite, not a problem with the implementation.
180             const uint32_t maxBorder = SkTMin(width, height) / (fSampleSize * divisor);
181             const uint32_t scaledBorder = SkTMin(5u, maxBorder);
182             const uint32_t unscaledBorder = scaledBorder * fSampleSize;
183 
184             // We may need to clear the canvas to avoid uninitialized memory.
185             // Assume we are scaling a 780x780 image with sampleSize = 8.
186             // The output image should be 97x97.
187             // Each subset will be 390x390.
188             // Each scaled subset be 48x48.
189             // Four scaled subsets will only fill a 96x96 image.
190             // The bottom row and last column will not be touched.
191             // This is an unfortunate result of our rounding rules when scaling.
192             // Maybe we need to consider testing scaled subsets without trying to
193             // combine them to match the full scaled image?  Or maybe this is the
194             // best we can do?
195             canvas->clear(0);
196 
197             for (uint32_t x = 0; x < divisor; x++) {
198                 for (uint32_t y = 0; y < divisor; y++) {
199                     // Calculate the subset dimensions
200                     uint32_t subsetWidth = width / divisor;
201                     uint32_t subsetHeight = height / divisor;
202                     const int left = x * subsetWidth;
203                     const int top = y * subsetHeight;
204 
205                     // Increase the size of the last subset in each row or column, when the
206                     // divisor does not divide evenly into the image dimensions
207                     subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0;
208                     subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0;
209 
210                     // Increase the size of the subset in order to have a border on each side
211                     const int decodeLeft = left - unscaledBorder;
212                     const int decodeTop = top - unscaledBorder;
213                     const uint32_t decodeWidth = subsetWidth + unscaledBorder * 2;
214                     const uint32_t decodeHeight = subsetHeight + unscaledBorder * 2;
215                     SkBitmap bitmap;
216                     if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(decodeLeft,
217                             decodeTop, decodeWidth, decodeHeight), fSampleSize, colorType, false,
218                             SkColorSpace::MakeSRGB())) {
219                         return "Cannot decode region.";
220                     }
221 
222                     alpha8_to_gray8(&bitmap);
223                     canvas->drawBitmapRect(bitmap,
224                             SkRect::MakeXYWH((SkScalar) scaledBorder, (SkScalar) scaledBorder,
225                                     (SkScalar) (subsetWidth / fSampleSize),
226                                     (SkScalar) (subsetHeight / fSampleSize)),
227                             SkRect::MakeXYWH((SkScalar) (left / fSampleSize),
228                                     (SkScalar) (top / fSampleSize),
229                                     (SkScalar) (subsetWidth / fSampleSize),
230                                     (SkScalar) (subsetHeight / fSampleSize)),
231                             nullptr);
232                 }
233             }
234             return "";
235         }
236         default:
237             SkASSERT(false);
238             return "Error: Should not be reached.";
239     }
240 }
241 
size() const242 SkISize BRDSrc::size() const {
243     std::unique_ptr<SkBitmapRegionDecoder> brd(create_brd(fPath));
244     if (brd) {
245         return SkISize::Make(SkTMax(1, brd->width() / (int) fSampleSize),
246                 SkTMax(1, brd->height() / (int) fSampleSize));
247     }
248     return SkISize::Make(0, 0);
249 }
250 
get_scaled_name(const Path & path,float scale)251 static SkString get_scaled_name(const Path& path, float scale) {
252     return SkStringPrintf("%s_%.3f", SkOSPath::Basename(path.c_str()).c_str(), scale);
253 }
254 
name() const255 Name BRDSrc::name() const {
256     // We will replicate the names used by CodecSrc so that images can
257     // be compared in Gold.
258     if (1 == fSampleSize) {
259         return SkOSPath::Basename(fPath.c_str());
260     }
261     return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
262 }
263 
264 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
265 
serial_from_path_name(const SkString & path)266 static bool serial_from_path_name(const SkString& path) {
267     if (!FLAGS_RAW_threading) {
268         static const char* const exts[] = {
269             "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw",
270             "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW",
271         };
272         const char* actualExt = strrchr(path.c_str(), '.');
273         if (actualExt) {
274             actualExt++;
275             for (auto* ext : exts) {
276                 if (0 == strcmp(ext, actualExt)) {
277                     return true;
278                 }
279             }
280         }
281     }
282     return false;
283 }
284 
CodecSrc(Path path,Mode mode,DstColorType dstColorType,SkAlphaType dstAlphaType,float scale)285 CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, SkAlphaType dstAlphaType,
286                    float scale)
287     : fPath(path)
288     , fMode(mode)
289     , fDstColorType(dstColorType)
290     , fDstAlphaType(dstAlphaType)
291     , fScale(scale)
292     , fRunSerially(serial_from_path_name(path))
293 {}
294 
veto(SinkFlags flags) const295 bool CodecSrc::veto(SinkFlags flags) const {
296     // Test to direct raster backends (8888 and 565).
297     return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
298 }
299 
300 // Allows us to test decodes to non-native 8888.
swap_rb_if_necessary(SkBitmap & bitmap,CodecSrc::DstColorType dstColorType)301 static void swap_rb_if_necessary(SkBitmap& bitmap, CodecSrc::DstColorType dstColorType) {
302     if (CodecSrc::kNonNative8888_Always_DstColorType != dstColorType) {
303         return;
304     }
305 
306     for (int y = 0; y < bitmap.height(); y++) {
307         uint32_t* row = (uint32_t*) bitmap.getAddr(0, y);
308         SkOpts::RGBA_to_BGRA(row, row, bitmap.width());
309     }
310 }
311 
312 // FIXME: Currently we cannot draw unpremultiplied sources. skbug.com/3338 and skbug.com/3339.
313 // This allows us to still test unpremultiplied decodes.
premultiply_if_necessary(SkBitmap & bitmap)314 static void premultiply_if_necessary(SkBitmap& bitmap) {
315     if (kUnpremul_SkAlphaType != bitmap.alphaType()) {
316         return;
317     }
318 
319     switch (bitmap.colorType()) {
320         case kN32_SkColorType:
321             for (int y = 0; y < bitmap.height(); y++) {
322                 uint32_t* row = (uint32_t*) bitmap.getAddr(0, y);
323                 SkOpts::RGBA_to_rgbA(row, row, bitmap.width());
324             }
325             break;
326         case kIndex_8_SkColorType: {
327             SkColorTable* colorTable = bitmap.getColorTable();
328             SkPMColor* colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
329             SkOpts::RGBA_to_rgbA(colorPtr, colorPtr, colorTable->count());
330             break;
331         }
332         default:
333             // No need to premultiply kGray or k565 outputs.
334             break;
335     }
336 
337     // In the kIndex_8 case, the canvas won't even try to draw unless we mark the
338     // bitmap as kPremul.
339     bitmap.setAlphaType(kPremul_SkAlphaType);
340 }
341 
get_decode_info(SkImageInfo * decodeInfo,SkColorType canvasColorType,CodecSrc::DstColorType dstColorType,SkAlphaType dstAlphaType)342 static bool get_decode_info(SkImageInfo* decodeInfo, SkColorType canvasColorType,
343                             CodecSrc::DstColorType dstColorType, SkAlphaType dstAlphaType) {
344     switch (dstColorType) {
345         case CodecSrc::kIndex8_Always_DstColorType:
346             if (kRGB_565_SkColorType == canvasColorType) {
347                 return false;
348             }
349             *decodeInfo = decodeInfo->makeColorType(kIndex_8_SkColorType);
350             break;
351         case CodecSrc::kGrayscale_Always_DstColorType:
352             if (kRGB_565_SkColorType == canvasColorType) {
353                 return false;
354             }
355             *decodeInfo = decodeInfo->makeColorType(kGray_8_SkColorType);
356             break;
357         case CodecSrc::kNonNative8888_Always_DstColorType:
358             if (kRGB_565_SkColorType == canvasColorType) {
359                 return false;
360             }
361 #ifdef SK_PMCOLOR_IS_RGBA
362             *decodeInfo = decodeInfo->makeColorType(kBGRA_8888_SkColorType);
363 #else
364             *decodeInfo = decodeInfo->makeColorType(kRGBA_8888_SkColorType);
365 #endif
366             break;
367         default:
368             if (kRGB_565_SkColorType == canvasColorType &&
369                     kOpaque_SkAlphaType != decodeInfo->alphaType()) {
370                 return false;
371             }
372 
373             if (kRGBA_F16_SkColorType == canvasColorType) {
374                 if (kUnpremul_SkAlphaType == dstAlphaType) {
375                     // Testing kPremul is enough for adequate coverage of F16 decoding.
376                     return false;
377                 }
378 
379                 sk_sp<SkColorSpace> linearSpace =
380                         as_CSB(decodeInfo->colorSpace())->makeLinearGamma();
381                 *decodeInfo = decodeInfo->makeColorSpace(std::move(linearSpace));
382             }
383 
384             *decodeInfo = decodeInfo->makeColorType(canvasColorType);
385             break;
386     }
387 
388     *decodeInfo = decodeInfo->makeAlphaType(dstAlphaType);
389     return true;
390 }
391 
draw_to_canvas(SkCanvas * canvas,const SkImageInfo & info,void * pixels,size_t rowBytes,SkPMColor * colorPtr,int colorCount,CodecSrc::DstColorType dstColorType,SkScalar left=0,SkScalar top=0)392 static void draw_to_canvas(SkCanvas* canvas, const SkImageInfo& info, void* pixels, size_t rowBytes,
393                            SkPMColor* colorPtr, int colorCount, CodecSrc::DstColorType dstColorType,
394                            SkScalar left = 0, SkScalar top = 0) {
395     sk_sp<SkColorTable> colorTable(new SkColorTable(colorPtr, colorCount));
396     SkBitmap bitmap;
397     bitmap.installPixels(info, pixels, rowBytes, colorTable.get(), nullptr, nullptr);
398     premultiply_if_necessary(bitmap);
399     swap_rb_if_necessary(bitmap, dstColorType);
400     canvas->drawBitmap(bitmap, left, top);
401 }
402 
draw(SkCanvas * canvas) const403 Error CodecSrc::draw(SkCanvas* canvas) const {
404     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
405     if (!encoded) {
406         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
407     }
408 
409     std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(encoded));
410     if (nullptr == codec.get()) {
411         return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
412     }
413 
414     SkImageInfo decodeInfo = codec->getInfo();
415     if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType,
416                          fDstAlphaType)) {
417         return Error::Nonfatal("Skipping uninteresting test.");
418     }
419 
420     // Try to scale the image if it is desired
421     SkISize size = codec->getScaledDimensions(fScale);
422     if (size == decodeInfo.dimensions() && 1.0f != fScale) {
423         return Error::Nonfatal("Test without scaling is uninteresting.");
424     }
425 
426     // Visually inspecting very small output images is not necessary.  We will
427     // cover these cases in unit testing.
428     if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) {
429         return Error::Nonfatal("Scaling very small images is uninteresting.");
430     }
431     decodeInfo = decodeInfo.makeWH(size.width(), size.height());
432 
433     const int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType());
434     const size_t rowBytes = size.width() * bpp;
435     const size_t safeSize = decodeInfo.getSafeSize(rowBytes);
436     SkAutoMalloc pixels(safeSize);
437     SkPMColor colorPtr[256];
438     int colorCount = 256;
439 
440     SkCodec::Options options;
441     if (kCodecZeroInit_Mode == fMode) {
442         memset(pixels.get(), 0, size.height() * rowBytes);
443         options.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
444     }
445 
446     SkImageInfo bitmapInfo = decodeInfo;
447     if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
448             kBGRA_8888_SkColorType == decodeInfo.colorType()) {
449         bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
450     }
451 
452     switch (fMode) {
453         case kAnimated_Mode: {
454             std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo();
455             if (frameInfos.size() <= 1) {
456                 return SkStringPrintf("%s is not an animated image.", fPath.c_str());
457             }
458 
459             // As in CodecSrc::size(), compute a roughly square grid to draw the frames
460             // into. "factor" is the number of frames to draw on one row. There will be
461             // up to "factor" rows as well.
462             const float root = sqrt((float) frameInfos.size());
463             const int factor = sk_float_ceil2int(root);
464 
465             // Used to cache a frame that future frames will depend on.
466             SkAutoMalloc priorFramePixels;
467             size_t cachedFrame = SkCodec::kNone;
468             for (size_t i = 0; i < frameInfos.size(); i++) {
469                 options.fFrameIndex = i;
470                 // Check for a prior frame
471                 const size_t reqFrame = frameInfos[i].fRequiredFrame;
472                 if (reqFrame != SkCodec::kNone && reqFrame == cachedFrame
473                         && priorFramePixels.get()) {
474                     // Copy into pixels
475                     memcpy(pixels.get(), priorFramePixels.get(), safeSize);
476                     options.fHasPriorFrame = true;
477                 } else {
478                     options.fHasPriorFrame = false;
479                 }
480                 SkCodec::Result result = codec->getPixels(decodeInfo, pixels.get(),
481                                                           rowBytes, &options,
482                                                           colorPtr, &colorCount);
483                 if (SkCodec::kInvalidInput == result && i > 0) {
484                     // Some of our test images have truncated later frames. Treat that
485                     // the same as incomplete.
486                     result = SkCodec::kIncompleteInput;
487                 }
488                 switch (result) {
489                     case SkCodec::kSuccess:
490                     case SkCodec::kIncompleteInput: {
491                         SkAutoCanvasRestore acr(canvas, true);
492                         const int xTranslate = (i % factor) * decodeInfo.width();
493                         const int yTranslate = (i / factor) * decodeInfo.height();
494                         canvas->translate(SkIntToScalar(xTranslate), SkIntToScalar(yTranslate));
495                         draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes,
496                                        colorPtr, colorCount, fDstColorType);
497                         if (result == SkCodec::kIncompleteInput) {
498                             return "";
499                         }
500                         break;
501                     }
502                     case SkCodec::kInvalidConversion:
503                         if (i > 0 && (decodeInfo.colorType() == kRGB_565_SkColorType
504                                       || decodeInfo.colorType() == kIndex_8_SkColorType)) {
505                             return Error::Nonfatal(SkStringPrintf(
506                                 "Cannot decode frame %i to 565/Index8 (%s).", i, fPath.c_str()));
507                         }
508                         // Fall through.
509                     default:
510                         return SkStringPrintf("Couldn't getPixels for frame %i in %s.",
511                                               i, fPath.c_str());
512                 }
513 
514                 // If a future frame depends on this one, store it in priorFrame.
515                 // (Note that if i+1 does *not* depend on i, then no future frame can.)
516                 if (i+1 < frameInfos.size() && frameInfos[i+1].fRequiredFrame == i) {
517                     memcpy(priorFramePixels.reset(safeSize), pixels.get(), safeSize);
518                     cachedFrame = i;
519                 }
520             }
521             break;
522         }
523         case kCodecZeroInit_Mode:
524         case kCodec_Mode: {
525             switch (codec->getPixels(decodeInfo, pixels.get(), rowBytes, &options,
526                     colorPtr, &colorCount)) {
527                 case SkCodec::kSuccess:
528                     // We consider incomplete to be valid, since we should still decode what is
529                     // available.
530                 case SkCodec::kIncompleteInput:
531                     break;
532                 default:
533                     // Everything else is considered a failure.
534                     return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
535             }
536 
537             draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr, colorCount,
538                            fDstColorType);
539             break;
540         }
541         case kScanline_Mode: {
542             void* dst = pixels.get();
543             uint32_t height = decodeInfo.height();
544             const bool useIncremental = [this]() {
545                 auto exts = { "png", "PNG", "gif", "GIF" };
546                 for (auto ext : exts) {
547                     if (fPath.endsWith(ext)) {
548                         return true;
549                     }
550                 }
551                 return false;
552             }();
553             // ico may use the old scanline method or the new one, depending on whether it
554             // internally holds a bmp or a png.
555             const bool ico = fPath.endsWith("ico");
556             bool useOldScanlineMethod = !useIncremental && !ico;
557             if (useIncremental || ico) {
558                 if (SkCodec::kSuccess == codec->startIncrementalDecode(decodeInfo, dst,
559                         rowBytes, nullptr, colorPtr, &colorCount)) {
560                     int rowsDecoded;
561                     if (SkCodec::kIncompleteInput == codec->incrementalDecode(&rowsDecoded)) {
562                         codec->fillIncompleteImage(decodeInfo, dst, rowBytes,
563                                                    SkCodec::kNo_ZeroInitialized, height,
564                                                    rowsDecoded);
565                     }
566                 } else {
567                     if (useIncremental) {
568                         // Error: These should support incremental decode.
569                         return "Could not start incremental decode";
570                     }
571                     // Otherwise, this is an ICO. Since incremental failed, it must contain a BMP,
572                     // which should work via startScanlineDecode
573                     useOldScanlineMethod = true;
574                 }
575             }
576 
577             if (useOldScanlineMethod) {
578                 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr,
579                                                                     &colorCount)) {
580                     return "Could not start scanline decoder";
581                 }
582 
583                 switch (codec->getScanlineOrder()) {
584                     case SkCodec::kTopDown_SkScanlineOrder:
585                     case SkCodec::kBottomUp_SkScanlineOrder:
586                         // We do not need to check the return value.  On an incomplete
587                         // image, memory will be filled with a default value.
588                         codec->getScanlines(dst, height, rowBytes);
589                         break;
590                 }
591             }
592 
593             draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, colorPtr, colorCount, fDstColorType);
594             break;
595         }
596         case kStripe_Mode: {
597             const int height = decodeInfo.height();
598             // This value is chosen arbitrarily.  We exercise more cases by choosing a value that
599             // does not align with image blocks.
600             const int stripeHeight = 37;
601             const int numStripes = (height + stripeHeight - 1) / stripeHeight;
602             void* dst = pixels.get();
603 
604             // Decode odd stripes
605             if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, nullptr, colorPtr,
606                                                                 &colorCount)) {
607                 return "Could not start scanline decoder";
608             }
609 
610             // This mode was designed to test the new skip scanlines API in libjpeg-turbo.
611             // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting
612             // to run this test for image types that do not have this scanline ordering.
613             // We only run this on Jpeg, which is always kTopDown.
614             SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder());
615 
616             for (int i = 0; i < numStripes; i += 2) {
617                 // Skip a stripe
618                 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight);
619                 codec->skipScanlines(linesToSkip);
620 
621                 // Read a stripe
622                 const int startY = (i + 1) * stripeHeight;
623                 const int linesToRead = SkTMin(stripeHeight, height - startY);
624                 if (linesToRead > 0) {
625                     codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead,
626                                         rowBytes);
627                 }
628             }
629 
630             // Decode even stripes
631             const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo, nullptr,
632                     colorPtr, &colorCount);
633             if (SkCodec::kSuccess != startResult) {
634                 return "Failed to restart scanline decoder with same parameters.";
635             }
636             for (int i = 0; i < numStripes; i += 2) {
637                 // Read a stripe
638                 const int startY = i * stripeHeight;
639                 const int linesToRead = SkTMin(stripeHeight, height - startY);
640                 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead,
641                                     rowBytes);
642 
643                 // Skip a stripe
644                 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight);
645                 if (linesToSkip > 0) {
646                     codec->skipScanlines(linesToSkip);
647                 }
648             }
649 
650             draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, colorPtr, colorCount, fDstColorType);
651             break;
652         }
653         case kCroppedScanline_Mode: {
654             const int width = decodeInfo.width();
655             const int height = decodeInfo.height();
656             // This value is chosen because, as we move across the image, it will sometimes
657             // align with the jpeg block sizes and it will sometimes not.  This allows us
658             // to test interestingly different code paths in the implementation.
659             const int tileSize = 36;
660 
661             SkCodec::Options opts;
662             SkIRect subset;
663             for (int x = 0; x < width; x += tileSize) {
664                 subset = SkIRect::MakeXYWH(x, 0, SkTMin(tileSize, width - x), height);
665                 opts.fSubset = &subset;
666                 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &opts,
667                         colorPtr, &colorCount)) {
668                     return "Could not start scanline decoder.";
669                 }
670 
671                 codec->getScanlines(SkTAddOffset<void>(pixels.get(), x * bpp), height, rowBytes);
672             }
673 
674             draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr, colorCount,
675                            fDstColorType);
676             break;
677         }
678         case kSubset_Mode: {
679             // Arbitrarily choose a divisor.
680             int divisor = 2;
681             // Total width/height of the image.
682             const int W = codec->getInfo().width();
683             const int H = codec->getInfo().height();
684             if (divisor > W || divisor > H) {
685                 return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divisor %d is too big "
686                                                       "for %s with dimensions (%d x %d)", divisor,
687                                                       fPath.c_str(), W, H));
688             }
689             // subset dimensions
690             // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
691             const int w = SkAlign2(W / divisor);
692             const int h = SkAlign2(H / divisor);
693             SkIRect subset;
694             SkCodec::Options opts;
695             opts.fSubset = &subset;
696             SkBitmap subsetBm;
697             // We will reuse pixel memory from bitmap.
698             void* dst = pixels.get();
699             // Keep track of left and top (for drawing subsetBm into canvas). We could use
700             // fScale * x and fScale * y, but we want integers such that the next subset will start
701             // where the last one ended. So we'll add decodeInfo.width() and height().
702             int left = 0;
703             for (int x = 0; x < W; x += w) {
704                 int top = 0;
705                 for (int y = 0; y < H; y+= h) {
706                     // Do not make the subset go off the edge of the image.
707                     const int preScaleW = SkTMin(w, W - x);
708                     const int preScaleH = SkTMin(h, H - y);
709                     subset.setXYWH(x, y, preScaleW, preScaleH);
710                     // And scale
711                     // FIXME: Should we have a version of getScaledDimensions that takes a subset
712                     // into account?
713                     const int scaledW = SkTMax(1, SkScalarRoundToInt(preScaleW * fScale));
714                     const int scaledH = SkTMax(1, SkScalarRoundToInt(preScaleH * fScale));
715                     decodeInfo = decodeInfo.makeWH(scaledW, scaledH);
716                     SkImageInfo subsetBitmapInfo = bitmapInfo.makeWH(scaledW, scaledH);
717                     size_t subsetRowBytes = subsetBitmapInfo.minRowBytes();
718                     const SkCodec::Result result = codec->getPixels(decodeInfo, dst, subsetRowBytes,
719                             &opts, colorPtr, &colorCount);
720                     switch (result) {
721                         case SkCodec::kSuccess:
722                         case SkCodec::kIncompleteInput:
723                             break;
724                         default:
725                             return SkStringPrintf("subset codec failed to decode (%d, %d, %d, %d) "
726                                                   "from %s with dimensions (%d x %d)\t error %d",
727                                                   x, y, decodeInfo.width(), decodeInfo.height(),
728                                                   fPath.c_str(), W, H, result);
729                     }
730                     draw_to_canvas(canvas, subsetBitmapInfo, dst, subsetRowBytes, colorPtr,
731                                    colorCount, fDstColorType, SkIntToScalar(left),
732                                    SkIntToScalar(top));
733 
734                     // translate by the scaled height.
735                     top += decodeInfo.height();
736                 }
737                 // translate by the scaled width.
738                 left += decodeInfo.width();
739             }
740             return "";
741         }
742         default:
743             SkASSERT(false);
744             return "Invalid fMode";
745     }
746     return "";
747 }
748 
size() const749 SkISize CodecSrc::size() const {
750     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
751     std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(encoded));
752     if (nullptr == codec) {
753         return SkISize::Make(0, 0);
754     }
755 
756     auto imageSize = codec->getScaledDimensions(fScale);
757     if (fMode == kAnimated_Mode) {
758         // We'll draw one of each frame, so make it big enough to hold them all
759         // in a grid. The grid will be roughly square, with "factor" frames per
760         // row and up to "factor" rows.
761         const size_t count = codec->getFrameInfo().size();
762         const float root = sqrt((float) count);
763         const int factor = sk_float_ceil2int(root);
764         imageSize.fWidth  = imageSize.fWidth  * factor;
765         imageSize.fHeight = imageSize.fHeight * sk_float_ceil2int((float) count / (float) factor);
766     }
767     return imageSize;
768 }
769 
name() const770 Name CodecSrc::name() const {
771     if (1.0f == fScale) {
772         Name name = SkOSPath::Basename(fPath.c_str());
773         if (fMode == kAnimated_Mode) {
774             name.append("_animated");
775         }
776         return name;
777     }
778     SkASSERT(fMode != kAnimated_Mode);
779     return get_scaled_name(fPath, fScale);
780 }
781 
782 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
783 
AndroidCodecSrc(Path path,CodecSrc::DstColorType dstColorType,SkAlphaType dstAlphaType,int sampleSize)784 AndroidCodecSrc::AndroidCodecSrc(Path path, CodecSrc::DstColorType dstColorType,
785         SkAlphaType dstAlphaType, int sampleSize)
786     : fPath(path)
787     , fDstColorType(dstColorType)
788     , fDstAlphaType(dstAlphaType)
789     , fSampleSize(sampleSize)
790     , fRunSerially(serial_from_path_name(path))
791 {}
792 
veto(SinkFlags flags) const793 bool AndroidCodecSrc::veto(SinkFlags flags) const {
794     // No need to test decoding to non-raster or indirect backend.
795     return flags.type != SinkFlags::kRaster
796         || flags.approach != SinkFlags::kDirect;
797 }
798 
draw(SkCanvas * canvas) const799 Error AndroidCodecSrc::draw(SkCanvas* canvas) const {
800     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
801     if (!encoded) {
802         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
803     }
804     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded));
805     if (nullptr == codec.get()) {
806         return SkStringPrintf("Couldn't create android codec for %s.", fPath.c_str());
807     }
808 
809     SkImageInfo decodeInfo = codec->getInfo();
810     if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType,
811                          fDstAlphaType)) {
812         return Error::Nonfatal("Skipping uninteresting test.");
813     }
814 
815     // Scale the image if it is desired.
816     SkISize size = codec->getSampledDimensions(fSampleSize);
817 
818     // Visually inspecting very small output images is not necessary.  We will
819     // cover these cases in unit testing.
820     if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) {
821         return Error::Nonfatal("Scaling very small images is uninteresting.");
822     }
823     decodeInfo = decodeInfo.makeWH(size.width(), size.height());
824 
825     int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType());
826     size_t rowBytes = size.width() * bpp;
827     SkAutoMalloc pixels(size.height() * rowBytes);
828     SkPMColor colorPtr[256];
829     int colorCount = 256;
830 
831     SkBitmap bitmap;
832     SkImageInfo bitmapInfo = decodeInfo;
833     if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
834             kBGRA_8888_SkColorType == decodeInfo.colorType()) {
835         bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
836     }
837 
838     // Create options for the codec.
839     SkAndroidCodec::AndroidOptions options;
840     options.fColorPtr = colorPtr;
841     options.fColorCount = &colorCount;
842     options.fSampleSize = fSampleSize;
843 
844     switch (codec->getAndroidPixels(decodeInfo, pixels.get(), rowBytes, &options)) {
845         case SkCodec::kSuccess:
846         case SkCodec::kIncompleteInput:
847             break;
848         default:
849             return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
850     }
851     draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr, colorCount, fDstColorType);
852     return "";
853 }
854 
size() const855 SkISize AndroidCodecSrc::size() const {
856     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
857     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded));
858     if (nullptr == codec) {
859         return SkISize::Make(0, 0);
860     }
861     return codec->getSampledDimensions(fSampleSize);
862 }
863 
name() const864 Name AndroidCodecSrc::name() const {
865     // We will replicate the names used by CodecSrc so that images can
866     // be compared in Gold.
867     if (1 == fSampleSize) {
868         return SkOSPath::Basename(fPath.c_str());
869     }
870     return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
871 }
872 
873 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
874 
ImageGenSrc(Path path,Mode mode,SkAlphaType alphaType,bool isGpu)875 ImageGenSrc::ImageGenSrc(Path path, Mode mode, SkAlphaType alphaType, bool isGpu)
876     : fPath(path)
877     , fMode(mode)
878     , fDstAlphaType(alphaType)
879     , fIsGpu(isGpu)
880     , fRunSerially(serial_from_path_name(path))
881 {}
882 
veto(SinkFlags flags) const883 bool ImageGenSrc::veto(SinkFlags flags) const {
884     if (fIsGpu) {
885         // MSAA runs tend to run out of memory and tests the same code paths as regular gpu configs.
886         return flags.type != SinkFlags::kGPU || flags.approach != SinkFlags::kDirect ||
887                flags.multisampled == SinkFlags::kMultisampled;
888     }
889 
890     return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
891 }
892 
draw(SkCanvas * canvas) const893 Error ImageGenSrc::draw(SkCanvas* canvas) const {
894     if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) {
895         return Error::Nonfatal("Uninteresting to test image generator to 565.");
896     }
897 
898     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
899     if (!encoded) {
900         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
901     }
902 
903 #if defined(SK_BUILD_FOR_WIN)
904     // Initialize COM in order to test with WIC.
905     SkAutoCoInitialize com;
906     if (!com.succeeded()) {
907         return "Could not initialize COM.";
908     }
909 #endif
910 
911     std::unique_ptr<SkImageGenerator> gen(nullptr);
912     switch (fMode) {
913         case kCodec_Mode:
914             gen = SkCodecImageGenerator::MakeFromEncodedCodec(encoded);
915             if (!gen) {
916                 return "Could not create codec image generator.";
917             }
918             break;
919         case kPlatform_Mode: {
920 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
921             gen.reset(SkImageGeneratorCG::NewFromEncodedCG(encoded.get()));
922 #elif defined(SK_BUILD_FOR_WIN)
923             gen.reset(SkImageGeneratorWIC::NewFromEncodedWIC(encoded.get()));
924 #endif
925 
926             if (!gen) {
927                 return "Could not create platform image generator.";
928             }
929             break;
930         }
931         default:
932             SkASSERT(false);
933             return "Invalid image generator mode";
934     }
935 
936     // Test deferred decoding path on GPU
937     if (fIsGpu) {
938         sk_sp<SkImage> image(SkImage::MakeFromGenerator(std::move(gen), nullptr));
939         if (!image) {
940             return "Could not create image from codec image generator.";
941         }
942         canvas->drawImage(image, 0, 0);
943         return "";
944     }
945 
946     // Test various color and alpha types on CPU
947     SkImageInfo decodeInfo = gen->getInfo().makeAlphaType(fDstAlphaType);
948 
949     int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType());
950     size_t rowBytes = decodeInfo.width() * bpp;
951     SkAutoMalloc pixels(decodeInfo.height() * rowBytes);
952     SkPMColor colorPtr[256];
953     int colorCount = 256;
954 
955     if (!gen->getPixels(decodeInfo, pixels.get(), rowBytes, colorPtr, &colorCount)) {
956         SkString err =
957                 SkStringPrintf("Image generator could not getPixels() for %s\n", fPath.c_str());
958 
959 #if defined(SK_BUILD_FOR_WIN)
960         if (kPlatform_Mode == fMode) {
961             // Do not issue a fatal error for WIC flakiness.
962             return Error::Nonfatal(err);
963         }
964 #endif
965 
966         return err;
967     }
968 
969     draw_to_canvas(canvas, decodeInfo, pixels.get(), rowBytes, colorPtr, colorCount,
970                    CodecSrc::kGetFromCanvas_DstColorType);
971     return "";
972 }
973 
size() const974 SkISize ImageGenSrc::size() const {
975     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
976     std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(encoded));
977     if (nullptr == codec) {
978         return SkISize::Make(0, 0);
979     }
980     return codec->getInfo().dimensions();
981 }
982 
name() const983 Name ImageGenSrc::name() const {
984     return SkOSPath::Basename(fPath.c_str());
985 }
986 
987 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
988 
ColorCodecSrc(Path path,Mode mode,SkColorType colorType)989 ColorCodecSrc::ColorCodecSrc(Path path, Mode mode, SkColorType colorType)
990     : fPath(path)
991     , fMode(mode)
992     , fColorType(colorType)
993 {}
994 
veto(SinkFlags flags) const995 bool ColorCodecSrc::veto(SinkFlags flags) const {
996     // Test to direct raster backends (8888 and 565).
997     return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
998 }
999 
draw(SkCanvas * canvas) const1000 Error ColorCodecSrc::draw(SkCanvas* canvas) const {
1001     if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) {
1002         return Error::Nonfatal("No need to test color correction to 565 backend.");
1003     }
1004 
1005     bool runInLegacyMode = kBaseline_Mode == fMode;
1006     if (runInLegacyMode && canvas->imageInfo().colorSpace()) {
1007         return Error::Nonfatal("Skipping tests that are only interesting in legacy mode.");
1008     } else if (!runInLegacyMode && !canvas->imageInfo().colorSpace()) {
1009         return Error::Nonfatal("Skipping tests that are only interesting in srgb mode.");
1010     }
1011 
1012     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
1013     if (!encoded) {
1014         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
1015     }
1016 
1017     std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(encoded));
1018     if (nullptr == codec.get()) {
1019         return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
1020     }
1021 
1022     // Load the dst ICC profile.  This particular dst is fairly similar to Adobe RGB.
1023     sk_sp<SkData> dstData = SkData::MakeFromFileName(
1024             GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str());
1025     if (!dstData) {
1026         return "Cannot read monitor profile.  Is the resource path set correctly?";
1027     }
1028 
1029     sk_sp<SkColorSpace> dstSpace = nullptr;
1030     if (kDst_sRGB_Mode == fMode) {
1031         dstSpace = SkColorSpace::MakeSRGB();
1032     } else if (kDst_HPZR30w_Mode == fMode) {
1033         dstSpace = SkColorSpace::MakeICC(dstData->data(), dstData->size());
1034     }
1035 
1036     SkImageInfo decodeInfo = codec->getInfo().makeColorType(fColorType).makeColorSpace(dstSpace);
1037     if (kUnpremul_SkAlphaType == decodeInfo.alphaType()) {
1038         decodeInfo = decodeInfo.makeAlphaType(kPremul_SkAlphaType);
1039     }
1040     if (kRGBA_F16_SkColorType == fColorType) {
1041         SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(decodeInfo.colorSpace())->type());
1042         SkColorSpace_XYZ* csXYZ = static_cast<SkColorSpace_XYZ*>(decodeInfo.colorSpace());
1043         decodeInfo = decodeInfo.makeColorSpace(csXYZ->makeLinearGamma());
1044     }
1045 
1046     SkImageInfo bitmapInfo = decodeInfo;
1047     if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
1048         kBGRA_8888_SkColorType == decodeInfo.colorType())
1049     {
1050         bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
1051     }
1052 
1053     SkBitmap bitmap;
1054     if (!bitmap.tryAllocPixels(bitmapInfo)) {
1055         return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(),
1056                               bitmapInfo.width(), bitmapInfo.height());
1057     }
1058 
1059     size_t rowBytes = bitmap.rowBytes();
1060     SkCodec::Result r = codec->getPixels(decodeInfo, bitmap.getPixels(), rowBytes);
1061     if (SkCodec::kSuccess != r && SkCodec::kIncompleteInput != r) {
1062         return SkStringPrintf("Couldn't getPixels %s. Error code %d", fPath.c_str(), r);
1063     }
1064 
1065     switch (fMode) {
1066         case kBaseline_Mode:
1067         case kDst_sRGB_Mode:
1068         case kDst_HPZR30w_Mode:
1069             canvas->drawBitmap(bitmap, 0, 0);
1070             break;
1071         default:
1072             SkASSERT(false);
1073             return "Invalid fMode";
1074     }
1075     return "";
1076 }
1077 
size() const1078 SkISize ColorCodecSrc::size() const {
1079     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
1080     std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(encoded));
1081     if (nullptr == codec) {
1082         return SkISize::Make(0, 0);
1083     }
1084     return SkISize::Make(codec->getInfo().width(), codec->getInfo().height());
1085 }
1086 
name() const1087 Name ColorCodecSrc::name() const {
1088     return SkOSPath::Basename(fPath.c_str());
1089 }
1090 
1091 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1092 
1093 static const SkRect kSKPViewport = {0,0, 1000,1000};
1094 
SKPSrc(Path path)1095 SKPSrc::SKPSrc(Path path) : fPath(path) {}
1096 
draw(SkCanvas * canvas) const1097 Error SKPSrc::draw(SkCanvas* canvas) const {
1098     std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(fPath.c_str());
1099     if (!stream) {
1100         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
1101     }
1102     sk_sp<SkPicture> pic(SkPicture::MakeFromStream(stream.get()));
1103     if (!pic) {
1104         return SkStringPrintf("Couldn't decode %s as a picture.", fPath.c_str());
1105     }
1106     stream = nullptr;  // Might as well drop this when we're done with it.
1107 
1108     canvas->clipRect(kSKPViewport);
1109     canvas->drawPicture(pic);
1110     return "";
1111 }
1112 
size() const1113 SkISize SKPSrc::size() const {
1114     std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(fPath.c_str());
1115     if (!stream) {
1116         return SkISize::Make(0,0);
1117     }
1118     SkPictInfo info;
1119     if (!SkPicture::InternalOnly_StreamIsSKP(stream.get(), &info)) {
1120         return SkISize::Make(0,0);
1121     }
1122     SkRect viewport = kSKPViewport;
1123     if (!viewport.intersect(info.fCullRect)) {
1124         return SkISize::Make(0,0);
1125     }
1126     return viewport.roundOut().size();
1127 }
1128 
name() const1129 Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
1130 
1131 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1132 #if defined(SK_XML)
1133 // Used when the image doesn't have an intrinsic size.
1134 static const SkSize kDefaultSVGSize = SkSize::Make(1000, 1000);
1135 
1136 // Used to force-scale tiny fixed-size images.
1137 static const SkSize kMinimumSVGSize = SkSize::Make(128, 128);
1138 
SVGSrc(Path path)1139 SVGSrc::SVGSrc(Path path)
1140     : fName(SkOSPath::Basename(path.c_str()))
1141     , fScale(1) {
1142 
1143   SkFILEStream stream(path.c_str());
1144   if (!stream.isValid()) {
1145       return;
1146   }
1147   fDom = SkSVGDOM::MakeFromStream(stream);
1148   if (!fDom) {
1149       return;
1150   }
1151 
1152   const SkSize& sz = fDom->containerSize();
1153   if (sz.isEmpty()) {
1154       // no intrinsic size
1155       fDom->setContainerSize(kDefaultSVGSize);
1156   } else {
1157       fScale = SkTMax(1.f, SkTMax(kMinimumSVGSize.width()  / sz.width(),
1158                                   kMinimumSVGSize.height() / sz.height()));
1159   }
1160 }
1161 
draw(SkCanvas * canvas) const1162 Error SVGSrc::draw(SkCanvas* canvas) const {
1163     if (!fDom) {
1164         return SkStringPrintf("Unable to parse file: %s", fName.c_str());
1165     }
1166 
1167     SkAutoCanvasRestore acr(canvas, true);
1168     canvas->scale(fScale, fScale);
1169     fDom->render(canvas);
1170 
1171     return "";
1172 }
1173 
size() const1174 SkISize SVGSrc::size() const {
1175     if (!fDom) {
1176         return SkISize::Make(0, 0);
1177     }
1178 
1179     return SkSize::Make(fDom->containerSize().width()  * fScale,
1180                         fDom->containerSize().height() * fScale).toRound();
1181 }
1182 
name() const1183 Name SVGSrc::name() const { return fName; }
1184 
veto(SinkFlags flags) const1185 bool SVGSrc::veto(SinkFlags flags) const {
1186     // No need to test to non-(raster||gpu) or indirect backends.
1187     bool type_ok = flags.type == SinkFlags::kRaster
1188                 || flags.type == SinkFlags::kGPU;
1189 
1190     return !type_ok || flags.approach != SinkFlags::kDirect;
1191 }
1192 
1193 #endif // defined(SK_XML)
1194 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1195 
MSKPSrc(Path path)1196 MSKPSrc::MSKPSrc(Path path) : fPath(path) {
1197     std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fPath.c_str());
1198     (void)fReader.init(stream.get());
1199 }
1200 
pageCount() const1201 int MSKPSrc::pageCount() const { return fReader.pageCount(); }
1202 
size() const1203 SkISize MSKPSrc::size() const { return this->size(0); }
size(int i) const1204 SkISize MSKPSrc::size(int i) const { return fReader.pageSize(i).toCeil(); }
1205 
draw(SkCanvas * c) const1206 Error MSKPSrc::draw(SkCanvas* c) const { return this->draw(0, c); }
draw(int i,SkCanvas * canvas) const1207 Error MSKPSrc::draw(int i, SkCanvas* canvas) const {
1208     std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fPath.c_str());
1209     if (!stream) {
1210         return SkStringPrintf("Unable to open file: %s", fPath.c_str());
1211     }
1212     if (fReader.pageCount() == 0) {
1213         return SkStringPrintf("Unable to parse MultiPictureDocument file: %s", fPath.c_str());
1214     }
1215     if (i >= fReader.pageCount()) {
1216         return SkStringPrintf("MultiPictureDocument page number out of range: %d", i);
1217     }
1218     sk_sp<SkPicture> page = fReader.readPage(stream.get(), i);
1219     if (!page) {
1220         return SkStringPrintf("SkMultiPictureDocumentReader failed on page %d: %s",
1221                               i, fPath.c_str());
1222     }
1223     canvas->drawPicture(page);
1224     return "";
1225 }
1226 
name() const1227 Name MSKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
1228 
1229 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1230 
draw(const Src & src,SkBitmap *,SkWStream *,SkString *) const1231 Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const {
1232     return src.draw(SkMakeNullCanvas().get());
1233 }
1234 
1235 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1236 
1237 DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?");
1238 
GPUSink(GrContextFactory::ContextType ct,GrContextFactory::ContextOverrides overrides,int samples,bool diText,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,bool threaded)1239 GPUSink::GPUSink(GrContextFactory::ContextType ct,
1240                  GrContextFactory::ContextOverrides overrides,
1241                  int samples,
1242                  bool diText,
1243                  SkColorType colorType,
1244                  sk_sp<SkColorSpace> colorSpace,
1245                  bool threaded)
1246     : fContextType(ct)
1247     , fContextOverrides(overrides)
1248     , fSampleCount(samples)
1249     , fUseDIText(diText)
1250     , fColorType(colorType)
1251     , fColorSpace(std::move(colorSpace))
1252     , fThreaded(threaded) {}
1253 
1254 DEFINE_bool(imm, false, "Run gpu configs in immediate mode.");
1255 DEFINE_bool(drawOpClip, false, "Clip each GrDrawOp to its device bounds for testing.");
1256 DEFINE_int32(opLookback, -1, "Maximum GrOp lookback for combining, negative means default.");
1257 DEFINE_int32(opLookahead, -1, "Maximum GrOp lookahead for combining, negative means default.");
1258 
draw(const Src & src,SkBitmap * dst,SkWStream *,SkString * log) const1259 Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const {
1260     GrContextOptions grOptions;
1261     grOptions.fImmediateMode = FLAGS_imm;
1262     grOptions.fMaxOpCombineLookback = FLAGS_opLookback;
1263     grOptions.fMaxOpCombineLookahead = FLAGS_opLookahead;
1264 
1265     src.modifyGrContextOptions(&grOptions);
1266 
1267     GrContextFactory factory(grOptions);
1268     const SkISize size = src.size();
1269     const SkImageInfo info =
1270         SkImageInfo::Make(size.width(), size.height(), fColorType,
1271                           kPremul_SkAlphaType, fColorSpace);
1272 #if SK_SUPPORT_GPU
1273     GrContext* context = factory.getContextInfo(fContextType, fContextOverrides).grContext();
1274     const int maxDimension = context->caps()->maxTextureSize();
1275     if (maxDimension < SkTMax(size.width(), size.height())) {
1276         return Error::Nonfatal("Src too large to create a texture.\n");
1277     }
1278 #endif
1279 
1280     auto surface(
1281         NewGpuSurface(&factory, fContextType, fContextOverrides, info, fSampleCount, fUseDIText));
1282     if (!surface) {
1283         return "Could not create a surface.";
1284     }
1285     if (FLAGS_preAbandonGpuContext) {
1286         factory.abandonContexts();
1287     }
1288     SkCanvas* canvas = surface->getCanvas();
1289     Error err = src.draw(canvas);
1290     if (!err.isEmpty()) {
1291         return err;
1292     }
1293     canvas->flush();
1294     if (FLAGS_gpuStats) {
1295         canvas->getGrContext()->dumpCacheStats(log);
1296         canvas->getGrContext()->dumpGpuStats(log);
1297     }
1298     dst->allocPixels(info);
1299     canvas->readPixels(dst, 0, 0);
1300     if (FLAGS_abandonGpuContext) {
1301         factory.abandonContexts();
1302     } else if (FLAGS_releaseAndAbandonGpuContext) {
1303         factory.releaseResourcesAndAbandonContexts();
1304     }
1305     return "";
1306 }
1307 
1308 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1309 
draw_skdocument(const Src & src,SkDocument * doc,SkWStream * dst)1310 static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) {
1311     if (src.size().isEmpty()) {
1312         return "Source has empty dimensions";
1313     }
1314     SkASSERT(doc);
1315     int pageCount = src.pageCount();
1316     for (int i = 0; i < pageCount; ++i) {
1317         int width = src.size(i).width(), height = src.size(i).height();
1318         SkCanvas* canvas =
1319                 doc->beginPage(SkIntToScalar(width), SkIntToScalar(height));
1320         if (!canvas) {
1321             return "SkDocument::beginPage(w,h) returned nullptr";
1322         }
1323         Error err = src.draw(i, canvas);
1324         if (!err.isEmpty()) {
1325             return err;
1326         }
1327         doc->endPage();
1328     }
1329     doc->close();
1330     dst->flush();
1331     return "";
1332 }
1333 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1334 Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1335     SkDocument::PDFMetadata metadata;
1336     metadata.fTitle = src.name();
1337     metadata.fSubject = "rendering correctness test";
1338     metadata.fCreator = "Skia/DM";
1339     sk_sp<SkDocument> doc = SkDocument::MakePDF(dst, SK_ScalarDefaultRasterDPI,
1340                                                 metadata, nullptr, fPDFA);
1341     if (!doc) {
1342         return "SkDocument::MakePDF() returned nullptr";
1343     }
1344     return draw_skdocument(src, doc.get(), dst);
1345 }
1346 
1347 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1348 
XPSSink()1349 XPSSink::XPSSink() {}
1350 
1351 #ifdef SK_BUILD_FOR_WIN
make_xps_factory()1352 static SkTScopedComPtr<IXpsOMObjectFactory> make_xps_factory() {
1353     IXpsOMObjectFactory* factory;
1354     HRN(CoCreateInstance(CLSID_XpsOMObjectFactory,
1355                          nullptr,
1356                          CLSCTX_INPROC_SERVER,
1357                          IID_PPV_ARGS(&factory)));
1358     return SkTScopedComPtr<IXpsOMObjectFactory>(factory);
1359 }
1360 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1361 Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1362     SkAutoCoInitialize com;
1363     if (!com.succeeded()) {
1364         return "Could not initialize COM.";
1365     }
1366     SkTScopedComPtr<IXpsOMObjectFactory> factory = make_xps_factory();
1367     if (!factory) {
1368         return "Failed to create XPS Factory.";
1369     }
1370     sk_sp<SkDocument> doc(SkDocument::MakeXPS(dst, factory.get()));
1371     if (!doc) {
1372         return "SkDocument::MakeXPS() returned nullptr";
1373     }
1374     return draw_skdocument(src, doc.get(), dst);
1375 }
1376 #else
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1377 Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1378     return "XPS not supported on this platform.";
1379 }
1380 #endif
1381 
1382 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1383 
PipeSink()1384 PipeSink::PipeSink() {}
1385 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1386 Error PipeSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1387     return src.draw(SkPipeSerializer().beginWrite(SkRect::Make(src.size()), dst));
1388 }
1389 
1390 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1391 
SKPSink()1392 SKPSink::SKPSink() {}
1393 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1394 Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1395     SkSize size;
1396     size = src.size();
1397     SkPictureRecorder recorder;
1398     Error err = src.draw(recorder.beginRecording(size.width(), size.height()));
1399     if (!err.isEmpty()) {
1400         return err;
1401     }
1402     recorder.finishRecordingAsPicture()->serialize(dst);
1403     return "";
1404 }
1405 
1406 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1407 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1408 Error DebugSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1409     SkDebugCanvas debugCanvas(src.size().width(), src.size().height());
1410     Error err = src.draw(&debugCanvas);
1411     if (!err.isEmpty()) {
1412         return err;
1413     }
1414     std::unique_ptr<SkCanvas> nullCanvas = SkMakeNullCanvas();
1415     UrlDataManager dataManager(SkString("data"));
1416     Json::Value json = debugCanvas.toJSON(
1417             dataManager, debugCanvas.getSize(), nullCanvas.get());
1418     std::string value = Json::StyledWriter().write(json);
1419     return dst->write(value.c_str(), value.size()) ? "" : "SkWStream Error";
1420 }
1421 
1422 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1423 
SVGSink()1424 SVGSink::SVGSink() {}
1425 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1426 Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1427 #if defined(SK_XML)
1428     std::unique_ptr<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(dst));
1429     return src.draw(SkSVGCanvas::Make(SkRect::MakeWH(SkIntToScalar(src.size().width()),
1430                                                      SkIntToScalar(src.size().height())),
1431                                       xmlWriter.get()).get());
1432 #else
1433     return Error("SVG sink is disabled.");
1434 #endif // SK_XML
1435 }
1436 
1437 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1438 
RasterSink(SkColorType colorType,sk_sp<SkColorSpace> colorSpace)1439 RasterSink::RasterSink(SkColorType colorType, sk_sp<SkColorSpace> colorSpace)
1440     : fColorType(colorType)
1441     , fColorSpace(std::move(colorSpace)) {}
1442 
draw(const Src & src,SkBitmap * dst,SkWStream *,SkString *) const1443 Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
1444     const SkISize size = src.size();
1445     // If there's an appropriate alpha type for this color type, use it, otherwise use premul.
1446     SkAlphaType alphaType = kPremul_SkAlphaType;
1447     (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType);
1448 
1449     SkMallocPixelRef::ZeroedPRFactory factory;
1450     dst->allocPixels(SkImageInfo::Make(size.width(), size.height(),
1451                                        fColorType, alphaType, fColorSpace),
1452                      &factory,
1453                      nullptr/*colortable*/);
1454     SkCanvas canvas(*dst);
1455     return src.draw(&canvas);
1456 }
1457 
1458 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1459 
1460 // Handy for front-patching a Src.  Do whatever up-front work you need, then call draw_to_canvas(),
1461 // passing the Sink draw() arguments, a size, and a function draws into an SkCanvas.
1462 // Several examples below.
1463 
1464 template <typename Fn>
draw_to_canvas(Sink * sink,SkBitmap * bitmap,SkWStream * stream,SkString * log,SkISize size,const Fn & draw)1465 static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log,
1466                             SkISize size, const Fn& draw) {
1467     class ProxySrc : public Src {
1468     public:
1469         ProxySrc(SkISize size, const Fn& draw) : fSize(size), fDraw(draw) {}
1470         Error   draw(SkCanvas* canvas) const override { return fDraw(canvas); }
1471         Name    name() const override { return "ProxySrc"; }
1472         SkISize size() const override { return fSize; }
1473     private:
1474         SkISize   fSize;
1475         const Fn& fDraw;
1476     };
1477     return sink->draw(ProxySrc(size, draw), bitmap, stream, log);
1478 }
1479 
1480 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1481 
1482 DEFINE_bool(check, true, "If true, have most Via- modes fail if they affect the output.");
1483 
1484 // Is *bitmap identical to what you get drawing src into sink?
check_against_reference(const SkBitmap * bitmap,const Src & src,Sink * sink)1485 static Error check_against_reference(const SkBitmap* bitmap, const Src& src, Sink* sink) {
1486     // We can only check raster outputs.
1487     // (Non-raster outputs like .pdf, .skp, .svg may differ but still draw identically.)
1488     if (FLAGS_check && bitmap) {
1489         SkBitmap reference;
1490         SkString log;
1491         SkDynamicMemoryWStream wStream;
1492         Error err = sink->draw(src, &reference, &wStream, &log);
1493         // If we can draw into this Sink via some pipeline, we should be able to draw directly.
1494         SkASSERT(err.isEmpty());
1495         if (!err.isEmpty()) {
1496             return err;
1497         }
1498         // The dimensions are a property of the Src only, and so should be identical.
1499         SkASSERT(reference.getSize() == bitmap->getSize());
1500         if (reference.getSize() != bitmap->getSize()) {
1501             return "Dimensions don't match reference";
1502         }
1503         // All SkBitmaps in DM are pre-locked and tight, so this comparison is easy.
1504         if (0 != memcmp(reference.getPixels(), bitmap->getPixels(), reference.getSize())) {
1505             return "Pixels don't match reference";
1506         }
1507     }
1508     return "";
1509 }
1510 
1511 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1512 
auto_compute_translate(SkMatrix * matrix,int srcW,int srcH)1513 static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) {
1514     SkRect bounds = SkRect::MakeIWH(srcW, srcH);
1515     matrix->mapRect(&bounds);
1516     matrix->postTranslate(-bounds.x(), -bounds.y());
1517     return SkISize::Make(SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height()));
1518 }
1519 
ViaMatrix(SkMatrix matrix,Sink * sink)1520 ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
1521 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1522 Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1523     SkMatrix matrix = fMatrix;
1524     SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height());
1525     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) {
1526         canvas->concat(matrix);
1527         return src.draw(canvas);
1528     });
1529 }
1530 
1531 // Undoes any flip or 90 degree rotate without changing the scale of the bitmap.
1532 // This should be pixel-preserving.
ViaUpright(SkMatrix matrix,Sink * sink)1533 ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
1534 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1535 Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1536     Error err = fSink->draw(src, bitmap, stream, log);
1537     if (!err.isEmpty()) {
1538         return err;
1539     }
1540 
1541     SkMatrix inverse;
1542     if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) {
1543         return "Cannot upright --matrix.";
1544     }
1545     SkMatrix upright = SkMatrix::I();
1546     upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX()));
1547     upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY()));
1548     upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX()));
1549     upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY()));
1550 
1551     SkBitmap uprighted;
1552     SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height());
1553     uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height()));
1554 
1555     SkCanvas canvas(uprighted);
1556     canvas.concat(upright);
1557     SkPaint paint;
1558     paint.setBlendMode(SkBlendMode::kSrc);
1559     canvas.drawBitmap(*bitmap, 0, 0, &paint);
1560 
1561     *bitmap = uprighted;
1562     bitmap->lockPixels();
1563     return "";
1564 }
1565 
1566 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1567 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1568 Error ViaSerialization::draw(
1569         const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1570     // Record our Src into a picture.
1571     auto size = src.size();
1572     SkPictureRecorder recorder;
1573     Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1574                                                  SkIntToScalar(size.height())));
1575     if (!err.isEmpty()) {
1576         return err;
1577     }
1578     sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture());
1579 
1580     // Serialize it and then deserialize it.
1581     sk_sp<SkPicture> deserialized(SkPicture::MakeFromData(pic->serialize().get()));
1582 
1583     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) {
1584         canvas->drawPicture(deserialized);
1585         return check_against_reference(bitmap, src, fSink.get());
1586     });
1587 }
1588 
1589 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1590 
ViaTiles(int w,int h,SkBBHFactory * factory,Sink * sink)1591 ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink)
1592     : Via(sink)
1593     , fW(w)
1594     , fH(h)
1595     , fFactory(factory) {}
1596 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1597 Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1598     auto size = src.size();
1599     SkPictureRecorder recorder;
1600     Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1601                                                  SkIntToScalar(size.height()),
1602                                                  fFactory.get()));
1603     if (!err.isEmpty()) {
1604         return err;
1605     }
1606     sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture());
1607 
1608     return draw_to_canvas(fSink.get(), bitmap, stream, log, src.size(), [&](SkCanvas* canvas) {
1609         const int xTiles = (size.width()  + fW - 1) / fW,
1610                   yTiles = (size.height() + fH - 1) / fH;
1611         SkMultiPictureDraw mpd(xTiles*yTiles);
1612         SkTArray<sk_sp<SkSurface>> surfaces;
1613 //        surfaces.setReserve(xTiles*yTiles);
1614 
1615         SkImageInfo info = canvas->imageInfo().makeWH(fW, fH);
1616         for (int j = 0; j < yTiles; j++) {
1617             for (int i = 0; i < xTiles; i++) {
1618                 // This lets our ultimate Sink determine the best kind of surface.
1619                 // E.g., if it's a GpuSink, the surfaces and images are textures.
1620                 auto s = canvas->makeSurface(info);
1621                 if (!s) {
1622                     s = SkSurface::MakeRaster(info);  // Some canvases can't create surfaces.
1623                 }
1624                 surfaces.push_back(s);
1625                 SkCanvas* c = s->getCanvas();
1626                 c->translate(SkIntToScalar(-i * fW),
1627                              SkIntToScalar(-j * fH));  // Line up the canvas with this tile.
1628                 mpd.add(c, pic.get());
1629             }
1630         }
1631         mpd.draw();
1632         for (int j = 0; j < yTiles; j++) {
1633             for (int i = 0; i < xTiles; i++) {
1634                 sk_sp<SkImage> image(surfaces[i+xTiles*j]->makeImageSnapshot());
1635                 canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH));
1636             }
1637         }
1638         return "";
1639     });
1640 }
1641 
1642 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1643 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1644 Error ViaPicture::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1645     auto size = src.size();
1646     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1647         SkPictureRecorder recorder;
1648         sk_sp<SkPicture> pic;
1649         Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1650                                                      SkIntToScalar(size.height())));
1651         if (!err.isEmpty()) {
1652             return err;
1653         }
1654         pic = recorder.finishRecordingAsPicture();
1655         canvas->drawPicture(pic);
1656         return check_against_reference(bitmap, src, fSink.get());
1657     });
1658 }
1659 
1660 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1661 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1662 Error ViaDefer::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1663     auto size = src.size();
1664     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1665         SkDeferredCanvas deferred(canvas, SkDeferredCanvas::kEager);
1666         return src.draw(&deferred);
1667     });
1668 }
1669 
1670 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1671 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1672 Error ViaPipe::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1673     auto size = src.size();
1674     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1675         SkDynamicMemoryWStream tmpStream;
1676         Error err = src.draw(SkPipeSerializer().beginWrite(SkRect::Make(size), &tmpStream));
1677         if (!err.isEmpty()) {
1678             return err;
1679         }
1680         sk_sp<SkData> data = tmpStream.detachAsData();
1681         SkPipeDeserializer().playback(data->data(), data->size(), canvas);
1682         return check_against_reference(bitmap, src, fSink.get());
1683     });
1684 }
1685 
1686 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1687 
1688 // Draw the Src into two pictures, then draw the second picture into the wrapped Sink.
1689 // This tests that any shortcuts we may take while recording that second picture are legal.
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1690 Error ViaSecondPicture::draw(
1691         const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1692     auto size = src.size();
1693     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1694         SkPictureRecorder recorder;
1695         sk_sp<SkPicture> pic;
1696         for (int i = 0; i < 2; i++) {
1697             Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1698                                                          SkIntToScalar(size.height())));
1699             if (!err.isEmpty()) {
1700                 return err;
1701             }
1702             pic = recorder.finishRecordingAsPicture();
1703         }
1704         canvas->drawPicture(pic);
1705         return check_against_reference(bitmap, src, fSink.get());
1706     });
1707 }
1708 
1709 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1710 
1711 // Draw the Src twice.  This can help exercise caching.
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1712 Error ViaTwice::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1713     return draw_to_canvas(fSink.get(), bitmap, stream, log, src.size(), [&](SkCanvas* canvas) -> Error {
1714         for (int i = 0; i < 2; i++) {
1715             SkAutoCanvasRestore acr(canvas, true/*save now*/);
1716             canvas->clear(SK_ColorTRANSPARENT);
1717             Error err = src.draw(canvas);
1718             if (err.isEmpty()) {
1719                 return err;
1720             }
1721         }
1722         return check_against_reference(bitmap, src, fSink.get());
1723     });
1724 }
1725 
1726 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1727 
1728 #ifdef TEST_VIA_SVG
1729 #include "SkXMLWriter.h"
1730 #include "SkSVGCanvas.h"
1731 #include "SkSVGDOM.h"
1732 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1733 Error ViaSVG::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1734     auto size = src.size();
1735     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1736         SkDynamicMemoryWStream wstream;
1737         SkXMLStreamWriter writer(&wstream);
1738         Error err = src.draw(SkSVGCanvas::Make(SkRect::Make(size), &writer).get());
1739         if (!err.isEmpty()) {
1740             return err;
1741         }
1742         std::unique_ptr<SkStream> rstream(wstream.detachAsStream());
1743         auto dom = SkSVGDOM::MakeFromStream(*rstream);
1744         if (dom) {
1745             dom->setContainerSize(SkSize::Make(size));
1746             dom->render(canvas);
1747         }
1748         return "";
1749     });
1750 }
1751 #endif
1752 
1753 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1754 
1755 // This is like SkRecords::Draw, in that it plays back SkRecords ops into a Canvas.
1756 // Unlike SkRecords::Draw, it builds a single-op sub-picture out of each Draw-type op.
1757 // This is an only-slightly-exaggerated simluation of Blink's Slimming Paint pictures.
1758 struct DrawsAsSingletonPictures {
1759     SkCanvas* fCanvas;
1760     const SkDrawableList& fDrawables;
1761     SkRect fBounds;
1762 
1763     template <typename T>
drawDM::DrawsAsSingletonPictures1764     void draw(const T& op, SkCanvas* canvas) {
1765         // We must pass SkMatrix::I() as our initial matrix.
1766         // By default SkRecords::Draw() uses the canvas' matrix as its initial matrix,
1767         // which would have the funky effect of applying transforms over and over.
1768         SkRecords::Draw d(canvas, nullptr, fDrawables.begin(), fDrawables.count(), &SkMatrix::I());
1769         d(op);
1770     }
1771 
1772     // Draws get their own picture.
1773     template <typename T>
SK_WHENDM::DrawsAsSingletonPictures1774     SK_WHEN(T::kTags & SkRecords::kDraw_Tag, void) operator()(const T& op) {
1775         SkPictureRecorder rec;
1776         this->draw(op, rec.beginRecording(fBounds));
1777         sk_sp<SkPicture> pic(rec.finishRecordingAsPicture());
1778         fCanvas->drawPicture(pic);
1779     }
1780 
1781     // We'll just issue non-draws directly.
1782     template <typename T>
operator ()DM::DrawsAsSingletonPictures1783     skstd::enable_if_t<!(T::kTags & SkRecords::kDraw_Tag), void> operator()(const T& op) {
1784         this->draw(op, fCanvas);
1785     }
1786 };
1787 
1788 // Record Src into a picture, then record it into a macro picture with a sub-picture for each draw.
1789 // Then play back that macro picture into our wrapped sink.
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1790 Error ViaSingletonPictures::draw(
1791         const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1792     auto size = src.size();
1793     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1794         // Use low-level (Skia-private) recording APIs so we can read the SkRecord.
1795         SkRecord skr;
1796         SkRecorder recorder(&skr, size.width(), size.height());
1797         Error err = src.draw(&recorder);
1798         if (!err.isEmpty()) {
1799             return err;
1800         }
1801 
1802         // Record our macro-picture, with each draw op as its own sub-picture.
1803         SkPictureRecorder macroRec;
1804         SkCanvas* macroCanvas = macroRec.beginRecording(SkIntToScalar(size.width()),
1805                                                         SkIntToScalar(size.height()));
1806 
1807         std::unique_ptr<SkDrawableList> drawables(recorder.detachDrawableList());
1808         const SkDrawableList empty;
1809 
1810         DrawsAsSingletonPictures drawsAsSingletonPictures = {
1811             macroCanvas,
1812             drawables ? *drawables : empty,
1813             SkRect::MakeWH((SkScalar)size.width(), (SkScalar)size.height()),
1814         };
1815         for (int i = 0; i < skr.count(); i++) {
1816             skr.visit(i, drawsAsSingletonPictures);
1817         }
1818         sk_sp<SkPicture> macroPic(macroRec.finishRecordingAsPicture());
1819 
1820         canvas->drawPicture(macroPic);
1821         return check_against_reference(bitmap, src, fSink.get());
1822     });
1823 }
1824 
1825 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1826 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1827 Error ViaLite::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1828     auto size = src.size();
1829     SkIRect bounds = {0,0, size.width(), size.height()};
1830     return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1831         SkLiteDL dl;
1832         SkLiteRecorder rec;
1833         rec.reset(&dl, bounds);
1834 
1835         Error err = src.draw(&rec);
1836         if (!err.isEmpty()) {
1837             return err;
1838         }
1839         dl.draw(canvas);
1840         return check_against_reference(bitmap, src, fSink.get());
1841     });
1842 }
1843 
1844 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1845 
ViaCSXform(Sink * sink,sk_sp<SkColorSpace> cs,bool colorSpin)1846 ViaCSXform::ViaCSXform(Sink* sink, sk_sp<SkColorSpace> cs, bool colorSpin)
1847     : Via(sink)
1848     , fCS(std::move(cs))
1849     , fColorSpin(colorSpin) {}
1850 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1851 Error ViaCSXform::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1852     return draw_to_canvas(fSink.get(), bitmap, stream, log, src.size(),
1853                           [&](SkCanvas* canvas) -> Error {
1854         auto proxy = SkCreateColorSpaceXformCanvas(canvas, fCS);
1855         Error err = src.draw(proxy.get());
1856         if (!err.isEmpty()) {
1857             return err;
1858         }
1859 
1860         // Undo the color spin, so we can look at the pixels in Gold.
1861         if (fColorSpin) {
1862             SkBitmap pixels;
1863             pixels.allocPixels(canvas->imageInfo());
1864             canvas->readPixels(&pixels, 0, 0);
1865             for (int y = 0; y < pixels.height(); y++) {
1866                 for (int x = 0; x < pixels.width(); x++) {
1867                     uint32_t pixel = *pixels.getAddr32(x, y);
1868                     uint8_t r = SkGetPackedR32(pixel);
1869                     uint8_t g = SkGetPackedG32(pixel);
1870                     uint8_t b = SkGetPackedB32(pixel);
1871                     uint8_t a = SkGetPackedA32(pixel);
1872                     *pixels.getAddr32(x, y) =
1873                             SkSwizzle_RGBA_to_PMColor(b << 0 | r << 8 | g << 16 | a << 24);
1874                 }
1875             }
1876 
1877             canvas->writePixels(pixels, 0, 0);
1878         }
1879 
1880         return "";
1881     });
1882 }
1883 
1884 }  // namespace DM
1885