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 "SkAndroidCodec.h"
10 #include "SkCodec.h"
11 #include "SkCodecImageGenerator.h"
12 #include "SkCommonFlags.h"
13 #include "SkData.h"
14 #include "SkDocument.h"
15 #include "SkError.h"
16 #include "SkImageGenerator.h"
17 #include "SkMallocPixelRef.h"
18 #include "SkMultiPictureDraw.h"
19 #include "SkNullCanvas.h"
20 #include "SkOSFile.h"
21 #include "SkOpts.h"
22 #include "SkPictureData.h"
23 #include "SkPictureRecorder.h"
24 #include "SkRandom.h"
25 #include "SkRecordDraw.h"
26 #include "SkRecorder.h"
27 #include "SkRemote.h"
28 #include "SkSVGCanvas.h"
29 #include "SkStream.h"
30 #include "SkTLogic.h"
31 #include "SkXMLWriter.h"
32 #include "SkSwizzler.h"
33 #include <functional>
34 
35 #ifdef SK_MOJO
36     #include "SkMojo.mojom.h"
37 #endif
38 
39 DEFINE_bool(multiPage, false, "For document-type backends, render the source"
40             " into multiple pages");
41 DEFINE_bool(RAW_threading, true, "Allow RAW decodes to run on multiple threads?");
42 
43 namespace DM {
44 
GMSrc(skiagm::GMRegistry::Factory factory)45 GMSrc::GMSrc(skiagm::GMRegistry::Factory factory) : fFactory(factory) {}
46 
draw(SkCanvas * canvas) const47 Error GMSrc::draw(SkCanvas* canvas) const {
48     SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr));
49     canvas->concat(gm->getInitialTransform());
50     gm->draw(canvas);
51     return "";
52 }
53 
size() const54 SkISize GMSrc::size() const {
55     SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr));
56     return gm->getISize();
57 }
58 
name() const59 Name GMSrc::name() const {
60     SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr));
61     return gm->getName();
62 }
63 
modifyGrContextOptions(GrContextOptions * options) const64 void GMSrc::modifyGrContextOptions(GrContextOptions* options) const {
65     SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr));
66     gm->modifyGrContextOptions(options);
67 }
68 
69 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
70 
BRDSrc(Path path,SkBitmapRegionDecoder::Strategy strategy,Mode mode,CodecSrc::DstColorType dstColorType,uint32_t sampleSize)71 BRDSrc::BRDSrc(Path path, SkBitmapRegionDecoder::Strategy strategy, Mode mode,
72         CodecSrc::DstColorType dstColorType, uint32_t sampleSize)
73     : fPath(path)
74     , fStrategy(strategy)
75     , fMode(mode)
76     , fDstColorType(dstColorType)
77     , fSampleSize(sampleSize)
78 {}
79 
veto(SinkFlags flags) const80 bool BRDSrc::veto(SinkFlags flags) const {
81     // No need to test to non-raster or indirect backends.
82     return flags.type != SinkFlags::kRaster
83         || flags.approach != SinkFlags::kDirect;
84 }
85 
create_brd(Path path,SkBitmapRegionDecoder::Strategy strategy)86 static SkBitmapRegionDecoder* create_brd(Path path,
87         SkBitmapRegionDecoder::Strategy strategy) {
88     SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str()));
89     if (!encoded) {
90         return NULL;
91     }
92     return SkBitmapRegionDecoder::Create(encoded, strategy);
93 }
94 
draw(SkCanvas * canvas) const95 Error BRDSrc::draw(SkCanvas* canvas) const {
96     SkColorType colorType = canvas->imageInfo().colorType();
97     if (kRGB_565_SkColorType == colorType &&
98             CodecSrc::kGetFromCanvas_DstColorType != fDstColorType) {
99         return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
100     }
101     switch (fDstColorType) {
102         case CodecSrc::kGetFromCanvas_DstColorType:
103             break;
104         case CodecSrc::kIndex8_Always_DstColorType:
105             colorType = kIndex_8_SkColorType;
106             break;
107         case CodecSrc::kGrayscale_Always_DstColorType:
108             colorType = kGray_8_SkColorType;
109             break;
110     }
111 
112     SkAutoTDelete<SkBitmapRegionDecoder> brd(create_brd(fPath, fStrategy));
113     if (nullptr == brd.get()) {
114         return Error::Nonfatal(SkStringPrintf("Could not create brd for %s.", fPath.c_str()));
115     }
116 
117     if (!brd->conversionSupported(colorType)) {
118         return Error::Nonfatal("Cannot convert to color type.");
119     }
120 
121     const uint32_t width = brd->width();
122     const uint32_t height = brd->height();
123     // Visually inspecting very small output images is not necessary.
124     if ((width / fSampleSize <= 10 || height / fSampleSize <= 10) && 1 != fSampleSize) {
125         return Error::Nonfatal("Scaling very small images is uninteresting.");
126     }
127     switch (fMode) {
128         case kFullImage_Mode: {
129             SkBitmap bitmap;
130             if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(0, 0, width, height),
131                     fSampleSize, colorType, false)) {
132                 return "Cannot decode (full) region.";
133             }
134             if (colorType != bitmap.colorType()) {
135                 return Error::Nonfatal("Cannot convert to color type.");
136             }
137             canvas->drawBitmap(bitmap, 0, 0);
138             return "";
139         }
140         case kDivisor_Mode: {
141             const uint32_t divisor = 2;
142             if (width < divisor || height < divisor) {
143                 return Error::Nonfatal("Divisor is larger than image dimension.");
144             }
145 
146             // Use a border to test subsets that extend outside the image.
147             // We will not allow the border to be larger than the image dimensions.  Allowing
148             // these large borders causes off by one errors that indicate a problem with the
149             // test suite, not a problem with the implementation.
150             const uint32_t maxBorder = SkTMin(width, height) / (fSampleSize * divisor);
151             const uint32_t scaledBorder = SkTMin(5u, maxBorder);
152             const uint32_t unscaledBorder = scaledBorder * fSampleSize;
153 
154             // We may need to clear the canvas to avoid uninitialized memory.
155             // Assume we are scaling a 780x780 image with sampleSize = 8.
156             // The output image should be 97x97.
157             // Each subset will be 390x390.
158             // Each scaled subset be 48x48.
159             // Four scaled subsets will only fill a 96x96 image.
160             // The bottom row and last column will not be touched.
161             // This is an unfortunate result of our rounding rules when scaling.
162             // Maybe we need to consider testing scaled subsets without trying to
163             // combine them to match the full scaled image?  Or maybe this is the
164             // best we can do?
165             canvas->clear(0);
166 
167             for (uint32_t x = 0; x < divisor; x++) {
168                 for (uint32_t y = 0; y < divisor; y++) {
169                     // Calculate the subset dimensions
170                     uint32_t subsetWidth = width / divisor;
171                     uint32_t subsetHeight = height / divisor;
172                     const int left = x * subsetWidth;
173                     const int top = y * subsetHeight;
174 
175                     // Increase the size of the last subset in each row or column, when the
176                     // divisor does not divide evenly into the image dimensions
177                     subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0;
178                     subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0;
179 
180                     // Increase the size of the subset in order to have a border on each side
181                     const int decodeLeft = left - unscaledBorder;
182                     const int decodeTop = top - unscaledBorder;
183                     const uint32_t decodeWidth = subsetWidth + unscaledBorder * 2;
184                     const uint32_t decodeHeight = subsetHeight + unscaledBorder * 2;
185                     SkBitmap bitmap;
186                     if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(decodeLeft,
187                             decodeTop, decodeWidth, decodeHeight), fSampleSize, colorType, false)) {
188                         return "Cannot decode region.";
189                     }
190                     if (colorType != bitmap.colorType()) {
191                         return Error::Nonfatal("Cannot convert to color type.");
192                     }
193 
194                     canvas->drawBitmapRect(bitmap,
195                             SkRect::MakeXYWH((SkScalar) scaledBorder, (SkScalar) scaledBorder,
196                                     (SkScalar) (subsetWidth / fSampleSize),
197                                     (SkScalar) (subsetHeight / fSampleSize)),
198                             SkRect::MakeXYWH((SkScalar) (left / fSampleSize),
199                                     (SkScalar) (top / fSampleSize),
200                                     (SkScalar) (subsetWidth / fSampleSize),
201                                     (SkScalar) (subsetHeight / fSampleSize)),
202                             nullptr);
203                 }
204             }
205             return "";
206         }
207         default:
208             SkASSERT(false);
209             return "Error: Should not be reached.";
210     }
211 }
212 
size() const213 SkISize BRDSrc::size() const {
214     SkAutoTDelete<SkBitmapRegionDecoder> brd(create_brd(fPath, fStrategy));
215     if (brd) {
216         return SkISize::Make(SkTMax(1, brd->width() / (int) fSampleSize),
217                 SkTMax(1, brd->height() / (int) fSampleSize));
218     }
219     return SkISize::Make(0, 0);
220 }
221 
get_scaled_name(const Path & path,float scale)222 static SkString get_scaled_name(const Path& path, float scale) {
223     return SkStringPrintf("%s_%.3f", SkOSPath::Basename(path.c_str()).c_str(), scale);
224 }
225 
name() const226 Name BRDSrc::name() const {
227     // We will replicate the names used by CodecSrc so that images can
228     // be compared in Gold.
229     if (1 == fSampleSize) {
230         return SkOSPath::Basename(fPath.c_str());
231     }
232     return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
233 }
234 
235 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
236 
serial_from_path_name(const SkString & path)237 static bool serial_from_path_name(const SkString& path) {
238     if (!FLAGS_RAW_threading) {
239         static const char* const exts[] = {
240             "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw",
241             "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW",
242         };
243         const char* actualExt = strrchr(path.c_str(), '.');
244         if (actualExt) {
245             actualExt++;
246             for (auto* ext : exts) {
247                 if (0 == strcmp(ext, actualExt)) {
248                     return true;
249                 }
250             }
251         }
252     }
253     return false;
254 }
255 
CodecSrc(Path path,Mode mode,DstColorType dstColorType,SkAlphaType dstAlphaType,float scale)256 CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, SkAlphaType dstAlphaType,
257                    float scale)
258     : fPath(path)
259     , fMode(mode)
260     , fDstColorType(dstColorType)
261     , fDstAlphaType(dstAlphaType)
262     , fScale(scale)
263     , fRunSerially(serial_from_path_name(path))
264 {}
265 
veto(SinkFlags flags) const266 bool CodecSrc::veto(SinkFlags flags) const {
267     // Test CodecImageGenerator on 8888, 565, and gpu
268     if (kGen_Mode == fMode) {
269         // For image generator, we want to test kDirect approaches for kRaster and kGPU,
270         // while skipping everything else.
271         return (flags.type != SinkFlags::kRaster && flags.type != SinkFlags::kGPU) ||
272                 flags.approach != SinkFlags::kDirect;
273     }
274 
275     // Test all other modes to direct raster backends (8888 and 565).
276     return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
277 }
278 
279 // FIXME: Currently we cannot draw unpremultiplied sources. skbug.com/3338 and skbug.com/3339.
280 // This allows us to still test unpremultiplied decodes.
premultiply_if_necessary(SkBitmap & bitmap)281 void premultiply_if_necessary(SkBitmap& bitmap) {
282     if (kUnpremul_SkAlphaType != bitmap.alphaType()) {
283         return;
284     }
285 
286     switch (bitmap.colorType()) {
287         case kN32_SkColorType:
288             for (int y = 0; y < bitmap.height(); y++) {
289                 uint32_t* row = (uint32_t*) bitmap.getAddr(0, y);
290                 SkOpts::RGBA_to_rgbA(row, row, bitmap.width());
291             }
292             break;
293         case kIndex_8_SkColorType: {
294             SkColorTable* colorTable = bitmap.getColorTable();
295             SkPMColor* colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
296             SkOpts::RGBA_to_rgbA(colorPtr, colorPtr, colorTable->count());
297             break;
298         }
299         default:
300             // No need to premultiply kGray or k565 outputs.
301             break;
302     }
303 
304     // In the kIndex_8 case, the canvas won't even try to draw unless we mark the
305     // bitmap as kPremul.
306     bitmap.setAlphaType(kPremul_SkAlphaType);
307 }
308 
get_decode_info(SkImageInfo * decodeInfo,SkColorType canvasColorType,CodecSrc::DstColorType dstColorType)309 bool get_decode_info(SkImageInfo* decodeInfo, SkColorType canvasColorType,
310                      CodecSrc::DstColorType dstColorType) {
311     switch (dstColorType) {
312         case CodecSrc::kIndex8_Always_DstColorType:
313             if (kRGB_565_SkColorType == canvasColorType) {
314                 return false;
315             }
316             *decodeInfo = decodeInfo->makeColorType(kIndex_8_SkColorType);
317             break;
318         case CodecSrc::kGrayscale_Always_DstColorType:
319             if (kRGB_565_SkColorType == canvasColorType ||
320                     kOpaque_SkAlphaType != decodeInfo->alphaType()) {
321                 return false;
322             }
323             *decodeInfo = decodeInfo->makeColorType(kGray_8_SkColorType);
324             break;
325         default:
326             if (kRGB_565_SkColorType == canvasColorType &&
327                     kOpaque_SkAlphaType != decodeInfo->alphaType()) {
328                 return false;
329             }
330             *decodeInfo = decodeInfo->makeColorType(canvasColorType);
331             break;
332     }
333 
334     return true;
335 }
336 
test_gen(SkCanvas * canvas,SkData * data)337 Error test_gen(SkCanvas* canvas, SkData* data) {
338     SkAutoTDelete<SkImageGenerator> gen = SkCodecImageGenerator::NewFromEncodedCodec(data);
339     if (!gen) {
340         return "Could not create image generator.";
341     }
342 
343     // FIXME: The gpu backend does not draw kGray sources correctly. (skbug.com/4822)
344     // Currently, we will avoid creating a CodecSrc for this case (see DM.cpp).
345     SkASSERT(kGray_8_SkColorType != gen->getInfo().colorType());
346 
347     if (kOpaque_SkAlphaType != gen->getInfo().alphaType() &&
348             kRGB_565_SkColorType == canvas->imageInfo().colorType()) {
349         return Error::Nonfatal("Skip testing non-opaque images to 565.");
350     }
351 
352     SkAutoTDelete<SkImage> image(SkImage::NewFromGenerator(gen.detach(), nullptr));
353     if (!image) {
354         return "Could not create image from codec image generator.";
355     }
356 
357     canvas->drawImage(image, 0, 0);
358     return "";
359 }
360 
draw(SkCanvas * canvas) const361 Error CodecSrc::draw(SkCanvas* canvas) const {
362     SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
363     if (!encoded) {
364         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
365     }
366 
367     // The CodecImageGenerator test does not share much code with the other tests,
368     // so we will handle it in its own function.
369     if (kGen_Mode == fMode) {
370         return test_gen(canvas, encoded);
371     }
372 
373     SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
374     if (nullptr == codec.get()) {
375         return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
376     }
377 
378     SkImageInfo decodeInfo = codec->getInfo().makeAlphaType(fDstAlphaType);
379     if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType)) {
380         return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
381     }
382 
383     // Try to scale the image if it is desired
384     SkISize size = codec->getScaledDimensions(fScale);
385     if (size == decodeInfo.dimensions() && 1.0f != fScale) {
386         return Error::Nonfatal("Test without scaling is uninteresting.");
387     }
388 
389     // Visually inspecting very small output images is not necessary.  We will
390     // cover these cases in unit testing.
391     if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) {
392         return Error::Nonfatal("Scaling very small images is uninteresting.");
393     }
394     decodeInfo = decodeInfo.makeWH(size.width(), size.height());
395 
396     // Construct a color table for the decode if necessary
397     SkAutoTUnref<SkColorTable> colorTable(nullptr);
398     SkPMColor* colorPtr = nullptr;
399     int* colorCountPtr = nullptr;
400     int maxColors = 256;
401     if (kIndex_8_SkColorType == decodeInfo.colorType()) {
402         SkPMColor colors[256];
403         colorTable.reset(new SkColorTable(colors, maxColors));
404         colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
405         colorCountPtr = &maxColors;
406     }
407 
408     SkBitmap bitmap;
409     SkPixelRefFactory* factory = nullptr;
410     SkMallocPixelRef::ZeroedPRFactory zeroFactory;
411     SkCodec::Options options;
412     if (kCodecZeroInit_Mode == fMode) {
413         factory = &zeroFactory;
414         options.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
415     }
416     if (!bitmap.tryAllocPixels(decodeInfo, factory, colorTable.get())) {
417         return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(),
418                               decodeInfo.width(), decodeInfo.height());
419     }
420 
421     switch (fMode) {
422         case kCodecZeroInit_Mode:
423         case kCodec_Mode: {
424             switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(), &options,
425                     colorPtr, colorCountPtr)) {
426                 case SkCodec::kSuccess:
427                     // We consider incomplete to be valid, since we should still decode what is
428                     // available.
429                 case SkCodec::kIncompleteInput:
430                     break;
431                 default:
432                     // Everything else is considered a failure.
433                     return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
434             }
435             premultiply_if_necessary(bitmap);
436             canvas->drawBitmap(bitmap, 0, 0);
437             break;
438         }
439         case kScanline_Mode: {
440             if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr,
441                                                                 colorCountPtr)) {
442                 return "Could not start scanline decoder";
443             }
444 
445             void* dst = bitmap.getAddr(0, 0);
446             size_t rowBytes = bitmap.rowBytes();
447             uint32_t height = decodeInfo.height();
448             switch (codec->getScanlineOrder()) {
449                 case SkCodec::kTopDown_SkScanlineOrder:
450                 case SkCodec::kBottomUp_SkScanlineOrder:
451                 case SkCodec::kNone_SkScanlineOrder:
452                     // We do not need to check the return value.  On an incomplete
453                     // image, memory will be filled with a default value.
454                     codec->getScanlines(dst, height, rowBytes);
455                     break;
456                 case SkCodec::kOutOfOrder_SkScanlineOrder: {
457                     for (int y = 0; y < decodeInfo.height(); y++) {
458                         int dstY = codec->outputScanline(y);
459                         void* dstPtr = bitmap.getAddr(0, dstY);
460                         // We complete the loop, even if this call begins to fail
461                         // due to an incomplete image.  This ensures any uninitialized
462                         // memory will be filled with the proper value.
463                         codec->getScanlines(dstPtr, 1, bitmap.rowBytes());
464                     }
465                     break;
466                 }
467             }
468 
469             premultiply_if_necessary(bitmap);
470             canvas->drawBitmap(bitmap, 0, 0);
471             break;
472         }
473         case kStripe_Mode: {
474             const int height = decodeInfo.height();
475             // This value is chosen arbitrarily.  We exercise more cases by choosing a value that
476             // does not align with image blocks.
477             const int stripeHeight = 37;
478             const int numStripes = (height + stripeHeight - 1) / stripeHeight;
479 
480             // Decode odd stripes
481             if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr,
482                                                                 colorCountPtr)) {
483                 return "Could not start scanline decoder";
484             }
485 
486             // This mode was designed to test the new skip scanlines API in libjpeg-turbo.
487             // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting
488             // to run this test for image types that do not have this scanline ordering.
489             if (SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOrder()) {
490                 return Error::Nonfatal("kStripe test is only interesting for kTopDown codecs.");
491             }
492 
493             for (int i = 0; i < numStripes; i += 2) {
494                 // Skip a stripe
495                 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight);
496                 codec->skipScanlines(linesToSkip);
497 
498                 // Read a stripe
499                 const int startY = (i + 1) * stripeHeight;
500                 const int linesToRead = SkTMin(stripeHeight, height - startY);
501                 if (linesToRead > 0) {
502                     codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes());
503                 }
504             }
505 
506             // Decode even stripes
507             const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo, nullptr,
508                     colorPtr, colorCountPtr);
509             if (SkCodec::kSuccess != startResult) {
510                 return "Failed to restart scanline decoder with same parameters.";
511             }
512             for (int i = 0; i < numStripes; i += 2) {
513                 // Read a stripe
514                 const int startY = i * stripeHeight;
515                 const int linesToRead = SkTMin(stripeHeight, height - startY);
516                 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes());
517 
518                 // Skip a stripe
519                 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight);
520                 if (linesToSkip > 0) {
521                     codec->skipScanlines(linesToSkip);
522                 }
523             }
524             premultiply_if_necessary(bitmap);
525             canvas->drawBitmap(bitmap, 0, 0);
526             break;
527         }
528         case kCroppedScanline_Mode: {
529             const int width = decodeInfo.width();
530             const int height = decodeInfo.height();
531             // This value is chosen because, as we move across the image, it will sometimes
532             // align with the jpeg block sizes and it will sometimes not.  This allows us
533             // to test interestingly different code paths in the implementation.
534             const int tileSize = 36;
535 
536             SkCodec::Options opts;
537             SkIRect subset;
538             for (int x = 0; x < width; x += tileSize) {
539                 subset = SkIRect::MakeXYWH(x, 0, SkTMin(tileSize, width - x), height);
540                 opts.fSubset = &subset;
541                 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &opts,
542                         colorPtr, colorCountPtr)) {
543                     return "Could not start scanline decoder.";
544                 }
545 
546                 codec->getScanlines(bitmap.getAddr(x, 0), height, bitmap.rowBytes());
547             }
548 
549             premultiply_if_necessary(bitmap);
550             canvas->drawBitmap(bitmap, 0, 0);
551             break;
552         }
553         case kSubset_Mode: {
554             // Arbitrarily choose a divisor.
555             int divisor = 2;
556             // Total width/height of the image.
557             const int W = codec->getInfo().width();
558             const int H = codec->getInfo().height();
559             if (divisor > W || divisor > H) {
560                 return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divisor %d is too big "
561                                                       "for %s with dimensions (%d x %d)", divisor,
562                                                       fPath.c_str(), W, H));
563             }
564             // subset dimensions
565             // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
566             const int w = SkAlign2(W / divisor);
567             const int h = SkAlign2(H / divisor);
568             SkIRect subset;
569             SkCodec::Options opts;
570             opts.fSubset = &subset;
571             SkBitmap subsetBm;
572             // We will reuse pixel memory from bitmap.
573             void* pixels = bitmap.getPixels();
574             // Keep track of left and top (for drawing subsetBm into canvas). We could use
575             // fScale * x and fScale * y, but we want integers such that the next subset will start
576             // where the last one ended. So we'll add decodeInfo.width() and height().
577             int left = 0;
578             for (int x = 0; x < W; x += w) {
579                 int top = 0;
580                 for (int y = 0; y < H; y+= h) {
581                     // Do not make the subset go off the edge of the image.
582                     const int preScaleW = SkTMin(w, W - x);
583                     const int preScaleH = SkTMin(h, H - y);
584                     subset.setXYWH(x, y, preScaleW, preScaleH);
585                     // And scale
586                     // FIXME: Should we have a version of getScaledDimensions that takes a subset
587                     // into account?
588                     decodeInfo = decodeInfo.makeWH(
589                             SkTMax(1, SkScalarRoundToInt(preScaleW * fScale)),
590                             SkTMax(1, SkScalarRoundToInt(preScaleH * fScale)));
591                     size_t rowBytes = decodeInfo.minRowBytes();
592                     if (!subsetBm.installPixels(decodeInfo, pixels, rowBytes, colorTable.get(),
593                                                 nullptr, nullptr)) {
594                         return SkStringPrintf("could not install pixels for %s.", fPath.c_str());
595                     }
596                     const SkCodec::Result result = codec->getPixels(decodeInfo, pixels, rowBytes,
597                             &opts, colorPtr, colorCountPtr);
598                     switch (result) {
599                         case SkCodec::kSuccess:
600                         case SkCodec::kIncompleteInput:
601                             break;
602                         default:
603                             return SkStringPrintf("subset codec failed to decode (%d, %d, %d, %d) "
604                                                   "from %s with dimensions (%d x %d)\t error %d",
605                                                   x, y, decodeInfo.width(), decodeInfo.height(),
606                                                   fPath.c_str(), W, H, result);
607                     }
608                     premultiply_if_necessary(subsetBm);
609                     canvas->drawBitmap(subsetBm, SkIntToScalar(left), SkIntToScalar(top));
610                     // translate by the scaled height.
611                     top += decodeInfo.height();
612                 }
613                 // translate by the scaled width.
614                 left += decodeInfo.width();
615             }
616             return "";
617         }
618         default:
619             SkASSERT(false);
620             return "Invalid fMode";
621     }
622     return "";
623 }
624 
size() const625 SkISize CodecSrc::size() const {
626     SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
627     SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
628     if (nullptr == codec) {
629         return SkISize::Make(0, 0);
630     }
631     return codec->getScaledDimensions(fScale);
632 }
633 
name() const634 Name CodecSrc::name() const {
635     if (1.0f == fScale) {
636         return SkOSPath::Basename(fPath.c_str());
637     }
638     return get_scaled_name(fPath, fScale);
639 }
640 
641 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
642 
AndroidCodecSrc(Path path,Mode mode,CodecSrc::DstColorType dstColorType,SkAlphaType dstAlphaType,int sampleSize)643 AndroidCodecSrc::AndroidCodecSrc(Path path, Mode mode, CodecSrc::DstColorType dstColorType,
644         SkAlphaType dstAlphaType, int sampleSize)
645     : fPath(path)
646     , fMode(mode)
647     , fDstColorType(dstColorType)
648     , fDstAlphaType(dstAlphaType)
649     , fSampleSize(sampleSize)
650     , fRunSerially(serial_from_path_name(path))
651 {}
652 
veto(SinkFlags flags) const653 bool AndroidCodecSrc::veto(SinkFlags flags) const {
654     // No need to test decoding to non-raster or indirect backend.
655     return flags.type != SinkFlags::kRaster
656         || flags.approach != SinkFlags::kDirect;
657 }
658 
draw(SkCanvas * canvas) const659 Error AndroidCodecSrc::draw(SkCanvas* canvas) const {
660     SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
661     if (!encoded) {
662         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
663     }
664     SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded));
665     if (nullptr == codec.get()) {
666         return SkStringPrintf("Couldn't create android codec for %s.", fPath.c_str());
667     }
668 
669     SkImageInfo decodeInfo = codec->getInfo().makeAlphaType(fDstAlphaType);
670     if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType)) {
671         return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
672     }
673 
674     // Scale the image if it is desired.
675     SkISize size = codec->getSampledDimensions(fSampleSize);
676 
677     // Visually inspecting very small output images is not necessary.  We will
678     // cover these cases in unit testing.
679     if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) {
680         return Error::Nonfatal("Scaling very small images is uninteresting.");
681     }
682     decodeInfo = decodeInfo.makeWH(size.width(), size.height());
683 
684     // Construct a color table for the decode if necessary
685     SkAutoTUnref<SkColorTable> colorTable(nullptr);
686     SkPMColor* colorPtr = nullptr;
687     int* colorCountPtr = nullptr;
688     int maxColors = 256;
689     if (kIndex_8_SkColorType == decodeInfo.colorType()) {
690         SkPMColor colors[256];
691         colorTable.reset(new SkColorTable(colors, maxColors));
692         colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
693         colorCountPtr = &maxColors;
694     }
695 
696     SkBitmap bitmap;
697     if (!bitmap.tryAllocPixels(decodeInfo, nullptr, colorTable.get())) {
698         return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(),
699                               decodeInfo.width(), decodeInfo.height());
700     }
701 
702     // Create options for the codec.
703     SkAndroidCodec::AndroidOptions options;
704     options.fColorPtr = colorPtr;
705     options.fColorCount = colorCountPtr;
706     options.fSampleSize = fSampleSize;
707 
708     switch (fMode) {
709         case kFullImage_Mode: {
710             switch (codec->getAndroidPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(),
711                     &options)) {
712                 case SkCodec::kSuccess:
713                 case SkCodec::kIncompleteInput:
714                     break;
715                 default:
716                     return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
717             }
718             premultiply_if_necessary(bitmap);
719             canvas->drawBitmap(bitmap, 0, 0);
720             return "";
721         }
722         case kDivisor_Mode: {
723             const int width = codec->getInfo().width();
724             const int height = codec->getInfo().height();
725             const int divisor = 2;
726             if (width < divisor || height < divisor) {
727                 return Error::Nonfatal("Divisor is larger than image dimension.");
728             }
729 
730             // Keep track of the final decoded dimensions.
731             int finalScaledWidth = 0;
732             int finalScaledHeight = 0;
733             for (int x = 0; x < divisor; x++) {
734                 for (int y = 0; y < divisor; y++) {
735                     // Calculate the subset dimensions
736                     int subsetWidth = width / divisor;
737                     int subsetHeight = height / divisor;
738                     const int left = x * subsetWidth;
739                     const int top = y * subsetHeight;
740 
741                     // Increase the size of the last subset in each row or column, when the
742                     // divisor does not divide evenly into the image dimensions
743                     subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0;
744                     subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0;
745                     SkIRect subset = SkIRect::MakeXYWH(left, top, subsetWidth, subsetHeight);
746                     if (!codec->getSupportedSubset(&subset)) {
747                         return "Could not get supported subset to decode.";
748                     }
749                     options.fSubset = &subset;
750                     const int scaledWidthOffset = subset.left() / fSampleSize;
751                     const int scaledHeightOffset = subset.top() / fSampleSize;
752                     void* pixels = bitmap.getAddr(scaledWidthOffset, scaledHeightOffset);
753                     SkISize scaledSubsetSize = codec->getSampledSubsetDimensions(fSampleSize,
754                             subset);
755                     SkImageInfo subsetDecodeInfo = decodeInfo.makeWH(scaledSubsetSize.width(),
756                             scaledSubsetSize.height());
757 
758                     if (x + 1 == divisor && y + 1 == divisor) {
759                         finalScaledWidth = scaledWidthOffset + scaledSubsetSize.width();
760                         finalScaledHeight = scaledHeightOffset + scaledSubsetSize.height();
761                     }
762 
763                     switch (codec->getAndroidPixels(subsetDecodeInfo, pixels, bitmap.rowBytes(),
764                             &options)) {
765                         case SkCodec::kSuccess:
766                         case SkCodec::kIncompleteInput:
767                             break;
768                         default:
769                             return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
770                     }
771                 }
772             }
773 
774             SkRect rect = SkRect::MakeXYWH(0, 0, (SkScalar) finalScaledWidth,
775                     (SkScalar) finalScaledHeight);
776             premultiply_if_necessary(bitmap);
777             canvas->drawBitmapRect(bitmap, rect, rect, nullptr);
778             return "";
779         }
780         default:
781             SkASSERT(false);
782             return "Error: Should not be reached.";
783     }
784 }
785 
size() const786 SkISize AndroidCodecSrc::size() const {
787     SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
788     SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded));
789     if (nullptr == codec) {
790         return SkISize::Make(0, 0);
791     }
792     return codec->getSampledDimensions(fSampleSize);
793 }
794 
name() const795 Name AndroidCodecSrc::name() const {
796     // We will replicate the names used by CodecSrc so that images can
797     // be compared in Gold.
798     if (1 == fSampleSize) {
799         return SkOSPath::Basename(fPath.c_str());
800     }
801     return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
802 }
803 
804 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
805 
806 static const SkRect kSKPViewport = {0,0, 1000,1000};
807 
SKPSrc(Path path)808 SKPSrc::SKPSrc(Path path) : fPath(path) {}
809 
draw(SkCanvas * canvas) const810 Error SKPSrc::draw(SkCanvas* canvas) const {
811     SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str()));
812     if (!stream) {
813         return SkStringPrintf("Couldn't read %s.", fPath.c_str());
814     }
815     SkAutoTUnref<SkPicture> pic(SkPicture::CreateFromStream(stream));
816     if (!pic) {
817         return SkStringPrintf("Couldn't decode %s as a picture.", fPath.c_str());
818     }
819     stream.reset((SkStream*)nullptr);  // Might as well drop this when we're done with it.
820 
821     canvas->clipRect(kSKPViewport);
822     canvas->drawPicture(pic);
823     return "";
824 }
825 
size() const826 SkISize SKPSrc::size() const {
827     SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str()));
828     if (!stream) {
829         return SkISize::Make(0,0);
830     }
831     SkPictInfo info;
832     if (!SkPicture::InternalOnly_StreamIsSKP(stream, &info)) {
833         return SkISize::Make(0,0);
834     }
835     SkRect viewport = kSKPViewport;
836     if (!viewport.intersect(info.fCullRect)) {
837         return SkISize::Make(0,0);
838     }
839     return viewport.roundOut().size();
840 }
841 
name() const842 Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
843 
844 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
845 
draw(const Src & src,SkBitmap *,SkWStream *,SkString *) const846 Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const {
847     SkAutoTDelete<SkCanvas> canvas(SkCreateNullCanvas());
848     return src.draw(canvas);
849 }
850 
851 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
852 
853 DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?");
854 
GPUSink(GrContextFactory::GLContextType ct,GrContextFactory::GLContextOptions options,int samples,bool diText,bool threaded)855 GPUSink::GPUSink(GrContextFactory::GLContextType ct,
856                  GrContextFactory::GLContextOptions options,
857                  int samples,
858                  bool diText,
859                  bool threaded)
860     : fContextType(ct)
861     , fContextOptions(options)
862     , fSampleCount(samples)
863     , fUseDIText(diText)
864     , fThreaded(threaded) {}
865 
PreAbandonGpuContextErrorHandler(SkError,void *)866 void PreAbandonGpuContextErrorHandler(SkError, void*) {}
867 
868 DEFINE_bool(imm, false, "Run gpu configs in immediate mode.");
869 DEFINE_bool(batchClip, false, "Clip each GrBatch to its device bounds for testing.");
870 DEFINE_bool(batchBounds, false, "Draw a wireframe bounds of each GrBatch.");
871 DEFINE_int32(batchLookback, -1, "Maximum GrBatch lookback for combining, negative means default.");
872 
draw(const Src & src,SkBitmap * dst,SkWStream *,SkString * log) const873 Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const {
874     GrContextOptions grOptions;
875     grOptions.fImmediateMode = FLAGS_imm;
876     grOptions.fClipBatchToBounds = FLAGS_batchClip;
877     grOptions.fDrawBatchBounds = FLAGS_batchBounds;
878     grOptions.fMaxBatchLookback = FLAGS_batchLookback;
879 
880     src.modifyGrContextOptions(&grOptions);
881 
882     GrContextFactory factory(grOptions);
883     const SkISize size = src.size();
884     const SkImageInfo info =
885         SkImageInfo::Make(size.width(), size.height(), kN32_SkColorType, kPremul_SkAlphaType);
886 #if SK_SUPPORT_GPU
887     const int maxDimension = factory.getContextInfo(fContextType, fContextOptions).
888             fGrContext->caps()->maxTextureSize();
889     if (maxDimension < SkTMax(size.width(), size.height())) {
890         return Error::Nonfatal("Src too large to create a texture.\n");
891     }
892 #endif
893 
894     SkAutoTUnref<SkSurface> surface(
895             NewGpuSurface(&factory, fContextType, fContextOptions, info, fSampleCount, fUseDIText));
896     if (!surface) {
897         return "Could not create a surface.";
898     }
899     if (FLAGS_preAbandonGpuContext) {
900         SkSetErrorCallback(&PreAbandonGpuContextErrorHandler, nullptr);
901         factory.abandonContexts();
902     }
903     SkCanvas* canvas = surface->getCanvas();
904     Error err = src.draw(canvas);
905     if (!err.isEmpty()) {
906         return err;
907     }
908     canvas->flush();
909     if (FLAGS_gpuStats) {
910         canvas->getGrContext()->dumpCacheStats(log);
911         canvas->getGrContext()->dumpGpuStats(log);
912     }
913     dst->allocPixels(info);
914     canvas->readPixels(dst, 0, 0);
915     if (FLAGS_abandonGpuContext) {
916         factory.abandonContexts();
917     }
918     return "";
919 }
920 
921 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
922 
draw_skdocument(const Src & src,SkDocument * doc,SkWStream * dst)923 static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) {
924     // Print the given DM:Src to a document, breaking on 8.5x11 pages.
925     SkASSERT(doc);
926     int width  = src.size().width(),
927         height = src.size().height();
928 
929     if (FLAGS_multiPage) {
930         const int kLetterWidth = 612,  // 8.5 * 72
931                 kLetterHeight = 792;   // 11 * 72
932         const SkRect letter = SkRect::MakeWH(SkIntToScalar(kLetterWidth),
933                                              SkIntToScalar(kLetterHeight));
934 
935         int xPages = ((width - 1) / kLetterWidth) + 1;
936         int yPages = ((height - 1) / kLetterHeight) + 1;
937 
938         for (int y = 0; y < yPages; ++y) {
939             for (int x = 0; x < xPages; ++x) {
940                 int w = SkTMin(kLetterWidth, width - (x * kLetterWidth));
941                 int h = SkTMin(kLetterHeight, height - (y * kLetterHeight));
942                 SkCanvas* canvas =
943                         doc->beginPage(SkIntToScalar(w), SkIntToScalar(h));
944                 if (!canvas) {
945                     return "SkDocument::beginPage(w,h) returned nullptr";
946                 }
947                 canvas->clipRect(letter);
948                 canvas->translate(-letter.width() * x, -letter.height() * y);
949                 Error err = src.draw(canvas);
950                 if (!err.isEmpty()) {
951                     return err;
952                 }
953                 doc->endPage();
954             }
955         }
956     } else {
957         SkCanvas* canvas =
958                 doc->beginPage(SkIntToScalar(width), SkIntToScalar(height));
959         if (!canvas) {
960             return "SkDocument::beginPage(w,h) returned nullptr";
961         }
962         Error err = src.draw(canvas);
963         if (!err.isEmpty()) {
964             return err;
965         }
966         doc->endPage();
967     }
968     if (!doc->close()) {
969         return "SkDocument::close() returned false";
970     }
971     dst->flush();
972     return "";
973 }
974 
PDFSink(const char * rasterizer)975 PDFSink::PDFSink(const char* rasterizer) : fRasterizer(rasterizer) {}
976 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const977 Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
978     SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(dst));
979     if (!doc) {
980         return "SkDocument::CreatePDF() returned nullptr";
981     }
982     SkTArray<SkDocument::Attribute> info;
983     info.emplace_back(SkString("Title"), src.name());
984     info.emplace_back(SkString("Subject"),
985                       SkString("rendering correctness test"));
986     info.emplace_back(SkString("Creator"), SkString("Skia/DM"));
987 
988     info.emplace_back(SkString("Keywords"),
989                       SkStringPrintf("Rasterizer:%s;", fRasterizer));
990     doc->setMetadata(&info[0], info.count(), nullptr, nullptr);
991     return draw_skdocument(src, doc.get(), dst);
992 }
993 
994 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
995 
XPSSink()996 XPSSink::XPSSink() {}
997 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const998 Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
999     SkAutoTUnref<SkDocument> doc(SkDocument::CreateXPS(dst));
1000     if (!doc) {
1001         return "SkDocument::CreateXPS() returned nullptr";
1002     }
1003     return draw_skdocument(src, doc.get(), dst);
1004 }
1005 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1006 
SKPSink()1007 SKPSink::SKPSink() {}
1008 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1009 Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1010     SkSize size;
1011     size = src.size();
1012     SkPictureRecorder recorder;
1013     Error err = src.draw(recorder.beginRecording(size.width(), size.height()));
1014     if (!err.isEmpty()) {
1015         return err;
1016     }
1017     SkAutoTUnref<SkPicture> pic(recorder.endRecording());
1018     pic->serialize(dst);
1019     return "";
1020 }
1021 
1022 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1023 
SVGSink()1024 SVGSink::SVGSink() {}
1025 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1026 Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1027     SkAutoTDelete<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(dst));
1028     SkAutoTUnref<SkCanvas> canvas(SkSVGCanvas::Create(
1029         SkRect::MakeWH(SkIntToScalar(src.size().width()), SkIntToScalar(src.size().height())),
1030         xmlWriter));
1031     return src.draw(canvas);
1032 }
1033 
1034 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1035 
RasterSink(SkColorType colorType)1036 RasterSink::RasterSink(SkColorType colorType) : fColorType(colorType) {}
1037 
draw(const Src & src,SkBitmap * dst,SkWStream *,SkString *) const1038 Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
1039     const SkISize size = src.size();
1040     // If there's an appropriate alpha type for this color type, use it, otherwise use premul.
1041     SkAlphaType alphaType = kPremul_SkAlphaType;
1042     (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType);
1043 
1044     SkMallocPixelRef::ZeroedPRFactory factory;
1045     dst->allocPixels(SkImageInfo::Make(size.width(), size.height(), fColorType, alphaType),
1046                      &factory,
1047                      nullptr/*colortable*/);
1048     SkCanvas canvas(*dst);
1049     return src.draw(&canvas);
1050 }
1051 
1052 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1053 
1054 // Handy for front-patching a Src.  Do whatever up-front work you need, then call draw_to_canvas(),
1055 // passing the Sink draw() arguments, a size, and a function draws into an SkCanvas.
1056 // Several examples below.
1057 
1058 template <typename Fn>
draw_to_canvas(Sink * sink,SkBitmap * bitmap,SkWStream * stream,SkString * log,SkISize size,const Fn & draw)1059 static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log,
1060                             SkISize size, const Fn& draw) {
1061     class ProxySrc : public Src {
1062     public:
1063         ProxySrc(SkISize size, const Fn& draw) : fSize(size), fDraw(draw) {}
1064         Error   draw(SkCanvas* canvas) const override { return fDraw(canvas); }
1065         Name                    name() const override { sk_throw(); return ""; } // Won't be called.
1066         SkISize                 size() const override { return fSize; }
1067     private:
1068         SkISize   fSize;
1069         const Fn& fDraw;
1070     };
1071     return sink->draw(ProxySrc(size, draw), bitmap, stream, log);
1072 }
1073 
1074 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1075 
1076 DEFINE_bool(check, true, "If true, have most Via- modes fail if they affect the output.");
1077 
1078 // Is *bitmap identical to what you get drawing src into sink?
check_against_reference(const SkBitmap * bitmap,const Src & src,Sink * sink)1079 static Error check_against_reference(const SkBitmap* bitmap, const Src& src, Sink* sink) {
1080     // We can only check raster outputs.
1081     // (Non-raster outputs like .pdf, .skp, .svg may differ but still draw identically.)
1082     if (FLAGS_check && bitmap) {
1083         SkBitmap reference;
1084         SkString log;
1085         Error err = sink->draw(src, &reference, nullptr, &log);
1086         // If we can draw into this Sink via some pipeline, we should be able to draw directly.
1087         SkASSERT(err.isEmpty());
1088         if (!err.isEmpty()) {
1089             return err;
1090         }
1091         // The dimensions are a property of the Src only, and so should be identical.
1092         SkASSERT(reference.getSize() == bitmap->getSize());
1093         if (reference.getSize() != bitmap->getSize()) {
1094             return "Dimensions don't match reference";
1095         }
1096         // All SkBitmaps in DM are pre-locked and tight, so this comparison is easy.
1097         if (0 != memcmp(reference.getPixels(), bitmap->getPixels(), reference.getSize())) {
1098             return "Pixels don't match reference";
1099         }
1100     }
1101     return "";
1102 }
1103 
1104 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1105 
auto_compute_translate(SkMatrix * matrix,int srcW,int srcH)1106 static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) {
1107     SkRect bounds = SkRect::MakeIWH(srcW, srcH);
1108     matrix->mapRect(&bounds);
1109     matrix->postTranslate(-bounds.x(), -bounds.y());
1110     return SkISize::Make(SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height()));
1111 }
1112 
ViaMatrix(SkMatrix matrix,Sink * sink)1113 ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
1114 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1115 Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1116     SkMatrix matrix = fMatrix;
1117     SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height());
1118     return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
1119         canvas->concat(matrix);
1120         return src.draw(canvas);
1121     });
1122 }
1123 
1124 // Undoes any flip or 90 degree rotate without changing the scale of the bitmap.
1125 // This should be pixel-preserving.
ViaUpright(SkMatrix matrix,Sink * sink)1126 ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
1127 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1128 Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1129     Error err = fSink->draw(src, bitmap, stream, log);
1130     if (!err.isEmpty()) {
1131         return err;
1132     }
1133 
1134     SkMatrix inverse;
1135     if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) {
1136         return "Cannot upright --matrix.";
1137     }
1138     SkMatrix upright = SkMatrix::I();
1139     upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX()));
1140     upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY()));
1141     upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX()));
1142     upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY()));
1143 
1144     SkBitmap uprighted;
1145     SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height());
1146     uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height()));
1147 
1148     SkCanvas canvas(uprighted);
1149     canvas.concat(upright);
1150     SkPaint paint;
1151     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
1152     canvas.drawBitmap(*bitmap, 0, 0, &paint);
1153 
1154     *bitmap = uprighted;
1155     bitmap->lockPixels();
1156     return "";
1157 }
1158 
1159 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1160 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1161 Error ViaRemote::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1162     return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* target) {
1163         SkAutoTDelete<SkRemote::Encoder> decoder(SkRemote::NewDecoder(target));
1164         SkAutoTDelete<SkRemote::Encoder>   cache(fCache ? SkRemote::NewCachingEncoder(decoder)
1165                                                         : nullptr);
1166         SkAutoTDelete<SkCanvas> canvas(SkRemote::NewCanvas(cache ? cache : decoder));
1167         return src.draw(canvas);
1168     });
1169 }
1170 
1171 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1172 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1173 Error ViaSerialization::draw(
1174         const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1175     // Record our Src into a picture.
1176     auto size = src.size();
1177     SkPictureRecorder recorder;
1178     Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1179                                                  SkIntToScalar(size.height())));
1180     if (!err.isEmpty()) {
1181         return err;
1182     }
1183     SkAutoTUnref<SkPicture> pic(recorder.endRecording());
1184 
1185     // Serialize it and then deserialize it.
1186     SkDynamicMemoryWStream wStream;
1187     pic->serialize(&wStream);
1188     SkAutoTDelete<SkStream> rStream(wStream.detachAsStream());
1189     SkAutoTUnref<SkPicture> deserialized(SkPicture::CreateFromStream(rStream));
1190 
1191     return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
1192         canvas->drawPicture(deserialized);
1193         return check_against_reference(bitmap, src, fSink);
1194     });
1195 }
1196 
1197 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1198 
ViaTiles(int w,int h,SkBBHFactory * factory,Sink * sink)1199 ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink)
1200     : Via(sink)
1201     , fW(w)
1202     , fH(h)
1203     , fFactory(factory) {}
1204 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1205 Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1206     auto size = src.size();
1207     SkPictureRecorder recorder;
1208     Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1209                                                  SkIntToScalar(size.height()),
1210                                                  fFactory.get()));
1211     if (!err.isEmpty()) {
1212         return err;
1213     }
1214     SkAutoTUnref<SkPicture> pic(recorder.endRecordingAsPicture());
1215 
1216     return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) {
1217         const int xTiles = (size.width()  + fW - 1) / fW,
1218                   yTiles = (size.height() + fH - 1) / fH;
1219         SkMultiPictureDraw mpd(xTiles*yTiles);
1220         SkTDArray<SkSurface*> surfaces;
1221         surfaces.setReserve(xTiles*yTiles);
1222 
1223         SkImageInfo info = canvas->imageInfo().makeWH(fW, fH);
1224         for (int j = 0; j < yTiles; j++) {
1225             for (int i = 0; i < xTiles; i++) {
1226                 // This lets our ultimate Sink determine the best kind of surface.
1227                 // E.g., if it's a GpuSink, the surfaces and images are textures.
1228                 SkSurface* s = canvas->newSurface(info);
1229                 if (!s) {
1230                     s = SkSurface::NewRaster(info);  // Some canvases can't create surfaces.
1231                 }
1232                 surfaces.push(s);
1233                 SkCanvas* c = s->getCanvas();
1234                 c->translate(SkIntToScalar(-i * fW),
1235                              SkIntToScalar(-j * fH));  // Line up the canvas with this tile.
1236                 mpd.add(c, pic);
1237             }
1238         }
1239         mpd.draw();
1240         for (int j = 0; j < yTiles; j++) {
1241             for (int i = 0; i < xTiles; i++) {
1242                 SkAutoTUnref<SkImage> image(surfaces[i+xTiles*j]->newImageSnapshot());
1243                 canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH));
1244             }
1245         }
1246         surfaces.unrefAll();
1247         return "";
1248     });
1249 }
1250 
1251 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1252 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1253 Error ViaPicture::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1254     auto size = src.size();
1255     return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1256         SkPictureRecorder recorder;
1257         SkAutoTUnref<SkPicture> pic;
1258         Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1259                                                      SkIntToScalar(size.height())));
1260         if (!err.isEmpty()) {
1261             return err;
1262         }
1263         pic.reset(recorder.endRecordingAsPicture());
1264         canvas->drawPicture(pic);
1265         return check_against_reference(bitmap, src, fSink);
1266     });
1267 }
1268 
1269 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1270 
1271 // Draw the Src into two pictures, then draw the second picture into the wrapped Sink.
1272 // 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) const1273 Error ViaSecondPicture::draw(
1274         const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1275     auto size = src.size();
1276     return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1277         SkPictureRecorder recorder;
1278         SkAutoTUnref<SkPicture> pic;
1279         for (int i = 0; i < 2; i++) {
1280             Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1281                                                          SkIntToScalar(size.height())));
1282             if (!err.isEmpty()) {
1283                 return err;
1284             }
1285             pic.reset(recorder.endRecordingAsPicture());
1286         }
1287         canvas->drawPicture(pic);
1288         return check_against_reference(bitmap, src, fSink);
1289     });
1290 }
1291 
1292 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1293 
1294 // Draw the Src twice.  This can help exercise caching.
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1295 Error ViaTwice::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1296     return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) -> Error {
1297         for (int i = 0; i < 2; i++) {
1298             SkAutoCanvasRestore acr(canvas, true/*save now*/);
1299             canvas->clear(SK_ColorTRANSPARENT);
1300             Error err = src.draw(canvas);
1301             if (err.isEmpty()) {
1302                 return err;
1303             }
1304         }
1305         return check_against_reference(bitmap, src, fSink);
1306     });
1307 }
1308 
1309 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1310 
1311 #ifdef SK_MOJO
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1312     Error ViaMojo::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1313         SkPictureRecorder recorder;
1314         SkRect size = SkRect::Make(SkIRect::MakeSize(src.size()));
1315         Error err = src.draw(recorder.beginRecording(size));
1316         if (!err.isEmpty()) {
1317             return err;
1318         }
1319         SkAutoTUnref<SkPicture> skPicture(recorder.endRecording());
1320 
1321         SkASSERT(skPicture);
1322         SkDynamicMemoryWStream buffer;
1323         skPicture->serialize(&buffer);
1324         skPicture.reset();
1325         SkMojo::FlattenedPicturePtr mojoPicture = SkMojo::FlattenedPicture::New();
1326         mojoPicture->data.resize(buffer.bytesWritten());
1327         buffer.copyTo(mojoPicture->data.data());
1328         buffer.reset();
1329         SkASSERT(mojoPicture.get() && mojoPicture->data);
1330 
1331         size_t flatSize = mojoPicture->GetSerializedSize();
1332         SkAutoMalloc storage(flatSize);
1333         if (!mojoPicture->Serialize(storage.get(), flatSize)) {
1334             return "SkMojo::FlattenedPicture::Serialize failed";
1335         }
1336         mojoPicture = SkMojo::FlattenedPicture::New();
1337         mojoPicture->Deserialize(storage.get());
1338         storage.free();
1339         if (!mojoPicture) {
1340             return "SkMojo::FlattenedPicture::Deserialize failed";
1341         }
1342         SkMemoryStream tmpStream(mojoPicture->data.data(),
1343                                  mojoPicture->data.size());
1344         skPicture.reset(SkPicture::CreateFromStream(&tmpStream));
1345         mojoPicture.reset();
1346         auto fn = [&](SkCanvas* canvas) -> Error {
1347             canvas->drawPicture(skPicture.get());
1348             return check_against_reference(bitmap, src, fSink);
1349         };
1350         return draw_to_canvas(fSink, bitmap, stream, log, src.size(), fn);
1351     }
1352 #else // not SK_MOJO
draw(const Src &,SkBitmap *,SkWStream *,SkString *) const1353     Error ViaMojo::draw(const Src&, SkBitmap*, SkWStream*, SkString*) const {
1354         return "Mojo is missing!";
1355     }
1356 #endif
1357 
1358 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1359 
1360 // This is like SkRecords::Draw, in that it plays back SkRecords ops into a Canvas.
1361 // Unlike SkRecords::Draw, it builds a single-op sub-picture out of each Draw-type op.
1362 // This is an only-slightly-exaggerated simluation of Blink's Slimming Paint pictures.
1363 struct DrawsAsSingletonPictures {
1364     SkCanvas* fCanvas;
1365     const SkDrawableList& fDrawables;
1366 
1367     template <typename T>
drawDM::DrawsAsSingletonPictures1368     void draw(const T& op, SkCanvas* canvas) {
1369         // We must pass SkMatrix::I() as our initial matrix.
1370         // By default SkRecords::Draw() uses the canvas' matrix as its initial matrix,
1371         // which would have the funky effect of applying transforms over and over.
1372         SkRecords::Draw d(canvas, nullptr, fDrawables.begin(), fDrawables.count(), &SkMatrix::I());
1373         d(op);
1374     }
1375 
1376     // Draws get their own picture.
1377     template <typename T>
SK_WHENDM::DrawsAsSingletonPictures1378     SK_WHEN(T::kTags & SkRecords::kDraw_Tag, void) operator()(const T& op) {
1379         SkPictureRecorder rec;
1380         this->draw(op, rec.beginRecording(SkRect::MakeLargest()));
1381         SkAutoTUnref<SkPicture> pic(rec.endRecordingAsPicture());
1382         fCanvas->drawPicture(pic);
1383     }
1384 
1385     // We'll just issue non-draws directly.
1386     template <typename T>
operator ()DM::DrawsAsSingletonPictures1387     skstd::enable_if_t<!(T::kTags & SkRecords::kDraw_Tag), void> operator()(const T& op) {
1388         this->draw(op, fCanvas);
1389     }
1390 };
1391 
1392 // Record Src into a picture, then record it into a macro picture with a sub-picture for each draw.
1393 // Then play back that macro picture into our wrapped sink.
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const1394 Error ViaSingletonPictures::draw(
1395         const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1396     auto size = src.size();
1397     return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1398         // Use low-level (Skia-private) recording APIs so we can read the SkRecord.
1399         SkRecord skr;
1400         SkRecorder recorder(&skr, size.width(), size.height());
1401         Error err = src.draw(&recorder);
1402         if (!err.isEmpty()) {
1403             return err;
1404         }
1405 
1406         // Record our macro-picture, with each draw op as its own sub-picture.
1407         SkPictureRecorder macroRec;
1408         SkCanvas* macroCanvas = macroRec.beginRecording(SkIntToScalar(size.width()),
1409                                                         SkIntToScalar(size.height()));
1410 
1411         SkAutoTDelete<SkDrawableList> drawables(recorder.detachDrawableList());
1412         const SkDrawableList empty;
1413 
1414         DrawsAsSingletonPictures drawsAsSingletonPictures = {
1415             macroCanvas,
1416             drawables ? *drawables : empty,
1417         };
1418         for (int i = 0; i < skr.count(); i++) {
1419             skr.visit<void>(i, drawsAsSingletonPictures);
1420         }
1421         SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture());
1422 
1423         canvas->drawPicture(macroPic);
1424         return check_against_reference(bitmap, src, fSink);
1425     });
1426 }
1427 
1428 }  // namespace DM
1429