blob: 8598de781c9bd48b16a716d006be24015ad4161d [file] [log] [blame]
scroggo478652e2015-03-25 07:11:02 -07001/*
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
mtklein748ca3b2015-01-15 10:56:12 -08008#include "DMSrcSink.h"
msarett3d9d7a72015-10-21 10:27:10 -07009#include "SkAndroidCodec.h"
scroggof24f2242015-03-03 08:59:20 -080010#include "SkCodec.h"
msarettb714fb02016-01-22 14:46:42 -080011#include "SkCodecImageGenerator.h"
mtkleina16e69e2015-05-05 11:38:45 -070012#include "SkCommonFlags.h"
mtkleinb3e5e4d2015-03-25 13:13:43 -070013#include "SkData.h"
mtklein748ca3b2015-01-15 10:56:12 -080014#include "SkDocument.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080015#include "SkError.h"
mtkleinb3e5e4d2015-03-25 13:13:43 -070016#include "SkImageGenerator.h"
mtkleinc8be09a2016-01-04 18:56:57 -080017#include "SkMallocPixelRef.h"
mtklein748ca3b2015-01-15 10:56:12 -080018#include "SkMultiPictureDraw.h"
mtkleinad66f9b2015-02-13 15:11:10 -080019#include "SkNullCanvas.h"
mtklein748ca3b2015-01-15 10:56:12 -080020#include "SkOSFile.h"
mtkleinffa901a2015-03-16 10:38:07 -070021#include "SkPictureData.h"
mtklein748ca3b2015-01-15 10:56:12 -080022#include "SkPictureRecorder.h"
23#include "SkRandom.h"
mtkleind31c13d2015-05-05 12:59:56 -070024#include "SkRecordDraw.h"
25#include "SkRecorder.h"
mtklein2e2ea382015-10-16 10:29:41 -070026#include "SkRemote.h"
fmalita2aafe6f2015-02-06 12:51:10 -080027#include "SkSVGCanvas.h"
scroggoa1193e42015-01-21 12:09:53 -080028#include "SkStream.h"
mtklein449d9b72015-09-28 10:33:02 -070029#include "SkTLogic.h"
fmalita2aafe6f2015-02-06 12:51:10 -080030#include "SkXMLWriter.h"
msarette6dd0042015-10-09 11:07:34 -070031#include "SkSwizzler.h"
mtklein64593522015-11-12 10:41:05 -080032#include <functional>
mtklein748ca3b2015-01-15 10:56:12 -080033
halcanary7e798182015-04-14 14:06:18 -070034DEFINE_bool(multiPage, false, "For document-type backends, render the source"
35 " into multiple pages");
36
mtkleinb3e5e4d2015-03-25 13:13:43 -070037static bool lazy_decode_bitmap(const void* src, size_t size, SkBitmap* dst) {
38 SkAutoTUnref<SkData> encoded(SkData::NewWithCopy(src, size));
reedd1146452015-09-25 06:56:57 -070039 return encoded && SkDEPRECATED_InstallDiscardablePixelRef(encoded, dst);
mtkleinb3e5e4d2015-03-25 13:13:43 -070040}
41
mtklein748ca3b2015-01-15 10:56:12 -080042namespace DM {
43
mtklein748ca3b2015-01-15 10:56:12 -080044GMSrc::GMSrc(skiagm::GMRegistry::Factory factory) : fFactory(factory) {}
45
46Error GMSrc::draw(SkCanvas* canvas) const {
halcanary96fcdcc2015-08-27 07:41:13 -070047 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr));
mtklein748ca3b2015-01-15 10:56:12 -080048 canvas->concat(gm->getInitialTransform());
49 gm->draw(canvas);
50 return "";
51}
52
53SkISize GMSrc::size() const {
halcanary96fcdcc2015-08-27 07:41:13 -070054 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr));
mtklein748ca3b2015-01-15 10:56:12 -080055 return gm->getISize();
56}
57
58Name GMSrc::name() const {
halcanary96fcdcc2015-08-27 07:41:13 -070059 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr));
mtklein748ca3b2015-01-15 10:56:12 -080060 return gm->getName();
61}
62
bsalomon4ee6bd82015-05-27 13:23:23 -070063void GMSrc::modifyGrContextOptions(GrContextOptions* options) const {
halcanary96fcdcc2015-08-27 07:41:13 -070064 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr));
bsalomon4ee6bd82015-05-27 13:23:23 -070065 gm->modifyGrContextOptions(options);
66}
67
mtklein748ca3b2015-01-15 10:56:12 -080068/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
69
msarett5cb48852015-11-06 08:56:32 -080070BRDSrc::BRDSrc(Path path, SkBitmapRegionDecoder::Strategy strategy, Mode mode,
msaretta5783ae2015-09-08 15:35:32 -070071 CodecSrc::DstColorType dstColorType, uint32_t sampleSize)
72 : fPath(path)
73 , fStrategy(strategy)
74 , fMode(mode)
75 , fDstColorType(dstColorType)
76 , fSampleSize(sampleSize)
77{}
78
79bool BRDSrc::veto(SinkFlags flags) const {
80 // No need to test to non-raster or indirect backends.
81 return flags.type != SinkFlags::kRaster
82 || flags.approach != SinkFlags::kDirect;
83}
84
msarett5cb48852015-11-06 08:56:32 -080085static SkBitmapRegionDecoder* create_brd(Path path,
86 SkBitmapRegionDecoder::Strategy strategy) {
msaretta5783ae2015-09-08 15:35:32 -070087 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str()));
88 if (!encoded) {
89 return NULL;
90 }
msarett5cb48852015-11-06 08:56:32 -080091 return SkBitmapRegionDecoder::Create(encoded, strategy);
msaretta5783ae2015-09-08 15:35:32 -070092}
93
94Error BRDSrc::draw(SkCanvas* canvas) const {
95 SkColorType colorType = canvas->imageInfo().colorType();
96 if (kRGB_565_SkColorType == colorType &&
97 CodecSrc::kGetFromCanvas_DstColorType != fDstColorType) {
98 return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
99 }
100 switch (fDstColorType) {
101 case CodecSrc::kGetFromCanvas_DstColorType:
102 break;
103 case CodecSrc::kIndex8_Always_DstColorType:
104 colorType = kIndex_8_SkColorType;
105 break;
106 case CodecSrc::kGrayscale_Always_DstColorType:
107 colorType = kGray_8_SkColorType;
108 break;
109 }
110
msarett5cb48852015-11-06 08:56:32 -0800111 SkAutoTDelete<SkBitmapRegionDecoder> brd(create_brd(fPath, fStrategy));
msaretta5783ae2015-09-08 15:35:32 -0700112 if (nullptr == brd.get()) {
113 return Error::Nonfatal(SkStringPrintf("Could not create brd for %s.", fPath.c_str()));
114 }
115
msarett04965c62015-10-12 10:24:38 -0700116 if (!brd->conversionSupported(colorType)) {
mtklein9b439152015-12-09 13:02:26 -0800117 return Error::Nonfatal("Cannot convert to color type.");
msarett04965c62015-10-12 10:24:38 -0700118 }
119
msaretta5783ae2015-09-08 15:35:32 -0700120 const uint32_t width = brd->width();
121 const uint32_t height = brd->height();
122 // Visually inspecting very small output images is not necessary.
123 if ((width / fSampleSize <= 10 || height / fSampleSize <= 10) && 1 != fSampleSize) {
124 return Error::Nonfatal("Scaling very small images is uninteresting.");
125 }
126 switch (fMode) {
127 case kFullImage_Mode: {
msarett35e5d1b2015-10-27 12:50:25 -0700128 SkBitmap bitmap;
129 if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(0, 0, width, height),
130 fSampleSize, colorType, false)) {
mtklein9b439152015-12-09 13:02:26 -0800131 return "Cannot decode (full) region.";
msarett35e5d1b2015-10-27 12:50:25 -0700132 }
133 if (colorType != bitmap.colorType()) {
mtklein9b439152015-12-09 13:02:26 -0800134 return Error::Nonfatal("Cannot convert to color type.");
msaretta5783ae2015-09-08 15:35:32 -0700135 }
msarett35e5d1b2015-10-27 12:50:25 -0700136 canvas->drawBitmap(bitmap, 0, 0);
msaretta5783ae2015-09-08 15:35:32 -0700137 return "";
138 }
139 case kDivisor_Mode: {
140 const uint32_t divisor = 2;
141 if (width < divisor || height < divisor) {
mtklein9b439152015-12-09 13:02:26 -0800142 return Error::Nonfatal("Divisor is larger than image dimension.");
msaretta5783ae2015-09-08 15:35:32 -0700143 }
144
145 // Use a border to test subsets that extend outside the image.
146 // We will not allow the border to be larger than the image dimensions. Allowing
147 // these large borders causes off by one errors that indicate a problem with the
148 // test suite, not a problem with the implementation.
149 const uint32_t maxBorder = SkTMin(width, height) / (fSampleSize * divisor);
150 const uint32_t scaledBorder = SkTMin(5u, maxBorder);
151 const uint32_t unscaledBorder = scaledBorder * fSampleSize;
152
153 // We may need to clear the canvas to avoid uninitialized memory.
154 // Assume we are scaling a 780x780 image with sampleSize = 8.
155 // The output image should be 97x97.
156 // Each subset will be 390x390.
157 // Each scaled subset be 48x48.
158 // Four scaled subsets will only fill a 96x96 image.
159 // The bottom row and last column will not be touched.
160 // This is an unfortunate result of our rounding rules when scaling.
161 // Maybe we need to consider testing scaled subsets without trying to
162 // combine them to match the full scaled image? Or maybe this is the
163 // best we can do?
164 canvas->clear(0);
165
166 for (uint32_t x = 0; x < divisor; x++) {
167 for (uint32_t y = 0; y < divisor; y++) {
168 // Calculate the subset dimensions
169 uint32_t subsetWidth = width / divisor;
170 uint32_t subsetHeight = height / divisor;
171 const int left = x * subsetWidth;
172 const int top = y * subsetHeight;
173
174 // Increase the size of the last subset in each row or column, when the
175 // divisor does not divide evenly into the image dimensions
176 subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0;
177 subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0;
178
179 // Increase the size of the subset in order to have a border on each side
180 const int decodeLeft = left - unscaledBorder;
181 const int decodeTop = top - unscaledBorder;
182 const uint32_t decodeWidth = subsetWidth + unscaledBorder * 2;
183 const uint32_t decodeHeight = subsetHeight + unscaledBorder * 2;
msarett35e5d1b2015-10-27 12:50:25 -0700184 SkBitmap bitmap;
185 if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(decodeLeft,
186 decodeTop, decodeWidth, decodeHeight), fSampleSize, colorType, false)) {
mtklein9b439152015-12-09 13:02:26 -0800187 return "Cannot decode region.";
msarett35e5d1b2015-10-27 12:50:25 -0700188 }
189 if (colorType != bitmap.colorType()) {
mtklein9b439152015-12-09 13:02:26 -0800190 return Error::Nonfatal("Cannot convert to color type.");
msaretta5783ae2015-09-08 15:35:32 -0700191 }
192
msarett35e5d1b2015-10-27 12:50:25 -0700193 canvas->drawBitmapRect(bitmap,
msaretta5783ae2015-09-08 15:35:32 -0700194 SkRect::MakeXYWH((SkScalar) scaledBorder, (SkScalar) scaledBorder,
195 (SkScalar) (subsetWidth / fSampleSize),
196 (SkScalar) (subsetHeight / fSampleSize)),
197 SkRect::MakeXYWH((SkScalar) (left / fSampleSize),
198 (SkScalar) (top / fSampleSize),
199 (SkScalar) (subsetWidth / fSampleSize),
200 (SkScalar) (subsetHeight / fSampleSize)),
201 nullptr);
202 }
203 }
204 return "";
205 }
206 default:
207 SkASSERT(false);
mtklein9b439152015-12-09 13:02:26 -0800208 return "Error: Should not be reached.";
msaretta5783ae2015-09-08 15:35:32 -0700209 }
210}
211
212SkISize BRDSrc::size() const {
msarett5cb48852015-11-06 08:56:32 -0800213 SkAutoTDelete<SkBitmapRegionDecoder> brd(create_brd(fPath, fStrategy));
msaretta5783ae2015-09-08 15:35:32 -0700214 if (brd) {
215 return SkISize::Make(SkTMax(1, brd->width() / (int) fSampleSize),
216 SkTMax(1, brd->height() / (int) fSampleSize));
217 }
218 return SkISize::Make(0, 0);
219}
220
221static SkString get_scaled_name(const Path& path, float scale) {
222 return SkStringPrintf("%s_%.3f", SkOSPath::Basename(path.c_str()).c_str(), scale);
223}
224
225Name BRDSrc::name() const {
226 // We will replicate the names used by CodecSrc so that images can
227 // be compared in Gold.
228 if (1 == fSampleSize) {
229 return SkOSPath::Basename(fPath.c_str());
230 }
msarett4b0778e2015-11-13 09:59:11 -0800231 return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
msaretta5783ae2015-09-08 15:35:32 -0700232}
233
234/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
235
msarett0a242972015-06-11 14:27:27 -0700236CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, float scale)
msarett438b2ad2015-04-09 12:43:10 -0700237 : fPath(path)
238 , fMode(mode)
239 , fDstColorType(dstColorType)
msarett0a242972015-06-11 14:27:27 -0700240 , fScale(scale)
msarett438b2ad2015-04-09 12:43:10 -0700241{}
mtklein748ca3b2015-01-15 10:56:12 -0800242
mtklein99cab4e2015-07-31 06:43:04 -0700243bool CodecSrc::veto(SinkFlags flags) const {
msarettb714fb02016-01-22 14:46:42 -0800244 // Test CodecImageGenerator on 8888, 565, and gpu
245 if (kGen_Mode == fMode) {
246 return (flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect) &&
247 flags.type != SinkFlags::kGPU;
248 }
249
250 // Test all other modes to direct raster backends (8888 and 565).
251 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
mtkleine0effd62015-07-29 06:37:28 -0700252}
scroggo9b77ddd2015-03-19 06:03:39 -0700253
msarett3d9d7a72015-10-21 10:27:10 -0700254bool get_decode_info(SkImageInfo* decodeInfo, const SkImageInfo& defaultInfo,
255 SkColorType canvasColorType, CodecSrc::DstColorType dstColorType) {
256 switch (dstColorType) {
257 case CodecSrc::kIndex8_Always_DstColorType:
258 if (kRGB_565_SkColorType == canvasColorType) {
259 return false;
260 }
261 *decodeInfo = defaultInfo.makeColorType(kIndex_8_SkColorType);
262 break;
263 case CodecSrc::kGrayscale_Always_DstColorType:
264 if (kRGB_565_SkColorType == canvasColorType) {
265 return false;
266 }
267 *decodeInfo = defaultInfo.makeColorType(kGray_8_SkColorType);
268 break;
269 default:
270 *decodeInfo = defaultInfo.makeColorType(canvasColorType);
271 break;
272 }
273
274 // FIXME: Currently we cannot draw unpremultiplied sources.
275 if (decodeInfo->alphaType() == kUnpremul_SkAlphaType) {
msarett90978142015-10-27 07:12:24 -0700276 *decodeInfo = decodeInfo->makeAlphaType(kPremul_SkAlphaType);
msarett3d9d7a72015-10-21 10:27:10 -0700277 }
278 return true;
279}
280
msarettb714fb02016-01-22 14:46:42 -0800281Error test_gen(SkCanvas* canvas, SkData* data) {
282 SkImageGenerator* gen = SkCodecImageGenerator::NewFromEncodedCodec(data);
283 if (!gen) {
284 return "Could not create image generator.";
285 }
286
287 // FIXME: The gpu backend does not draw kGray sources correctly. (skbug.com/4822)
288 // Currently, we will avoid creating a CodecSrc for this case (see DM.cpp).
289 SkASSERT(kGray_8_SkColorType != gen->getInfo().colorType());
290
291 SkAutoTDelete<SkImage> image(SkImage::NewFromGenerator(gen, nullptr));
292 if (!image) {
293 return "Could not create image from codec image generator.";
294 }
295
296 canvas->drawImage(image, 0, 0);
297 return "";
298}
299
mtkleine0effd62015-07-29 06:37:28 -0700300Error CodecSrc::draw(SkCanvas* canvas) const {
mtklein75d98fd2015-01-18 07:05:01 -0800301 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
mtklein748ca3b2015-01-15 10:56:12 -0800302 if (!encoded) {
303 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
304 }
msarettb714fb02016-01-22 14:46:42 -0800305
306 // The CodecImageGenerator test does not share much code with the other tests,
307 // so we will handle it in its own function.
308 if (kGen_Mode == fMode) {
309 return test_gen(canvas, encoded);
310 }
311
msarett3d9d7a72015-10-21 10:27:10 -0700312 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
msarett9e707a02015-09-01 14:57:57 -0700313 if (nullptr == codec.get()) {
314 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
scroggo9b77ddd2015-03-19 06:03:39 -0700315 }
316
msarett3d9d7a72015-10-21 10:27:10 -0700317 SkImageInfo decodeInfo;
318 if (!get_decode_info(&decodeInfo, codec->getInfo(), canvas->imageInfo().colorType(),
319 fDstColorType)) {
320 return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
msarett438b2ad2015-04-09 12:43:10 -0700321 }
322
msarett0a242972015-06-11 14:27:27 -0700323 // Try to scale the image if it is desired
324 SkISize size = codec->getScaledDimensions(fScale);
325 if (size == decodeInfo.dimensions() && 1.0f != fScale) {
326 return Error::Nonfatal("Test without scaling is uninteresting.");
327 }
msarettb32758a2015-08-18 13:22:46 -0700328
329 // Visually inspecting very small output images is not necessary. We will
330 // cover these cases in unit testing.
331 if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) {
332 return Error::Nonfatal("Scaling very small images is uninteresting.");
333 }
msarett0a242972015-06-11 14:27:27 -0700334 decodeInfo = decodeInfo.makeWH(size.width(), size.height());
335
msarett438b2ad2015-04-09 12:43:10 -0700336 // Construct a color table for the decode if necessary
halcanary96fcdcc2015-08-27 07:41:13 -0700337 SkAutoTUnref<SkColorTable> colorTable(nullptr);
338 SkPMColor* colorPtr = nullptr;
339 int* colorCountPtr = nullptr;
msarett438b2ad2015-04-09 12:43:10 -0700340 int maxColors = 256;
341 if (kIndex_8_SkColorType == decodeInfo.colorType()) {
342 SkPMColor colors[256];
halcanary385fe4d2015-08-26 13:07:48 -0700343 colorTable.reset(new SkColorTable(colors, maxColors));
msarett438b2ad2015-04-09 12:43:10 -0700344 colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
345 colorCountPtr = &maxColors;
346 }
347
scroggo9b77ddd2015-03-19 06:03:39 -0700348 SkBitmap bitmap;
msarettbb25b532016-01-13 09:31:39 -0800349 SkPixelRefFactory* factory = nullptr;
350 SkMallocPixelRef::ZeroedPRFactory zeroFactory;
351 SkCodec::Options options;
352 if (kCodecZeroInit_Mode == fMode) {
353 factory = &zeroFactory;
354 options.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
355 }
356 if (!bitmap.tryAllocPixels(decodeInfo, factory, colorTable.get())) {
mtklein9b439152015-12-09 13:02:26 -0800357 return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(),
scroggo9b77ddd2015-03-19 06:03:39 -0700358 decodeInfo.width(), decodeInfo.height());
359 }
360
scroggo9c59ebc2015-03-25 13:48:49 -0700361 switch (fMode) {
msarettbb25b532016-01-13 09:31:39 -0800362 case kCodecZeroInit_Mode:
msarett9e707a02015-09-01 14:57:57 -0700363 case kCodec_Mode: {
msarettbb25b532016-01-13 09:31:39 -0800364 switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(), &options,
msarett438b2ad2015-04-09 12:43:10 -0700365 colorPtr, colorCountPtr)) {
scroggoeb602a52015-07-09 08:16:03 -0700366 case SkCodec::kSuccess:
scroggo9c59ebc2015-03-25 13:48:49 -0700367 // We consider incomplete to be valid, since we should still decode what is
368 // available.
scroggoeb602a52015-07-09 08:16:03 -0700369 case SkCodec::kIncompleteInput:
scroggo9c59ebc2015-03-25 13:48:49 -0700370 break;
scroggoeb602a52015-07-09 08:16:03 -0700371 case SkCodec::kInvalidConversion:
scroggo9c59ebc2015-03-25 13:48:49 -0700372 return Error::Nonfatal("Incompatible colortype conversion");
373 default:
374 // Everything else is considered a failure.
375 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
376 }
emmaleer97002062015-05-27 12:36:10 -0700377 canvas->drawBitmap(bitmap, 0, 0);
scroggo9c59ebc2015-03-25 13:48:49 -0700378 break;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700379 }
scroggo9c59ebc2015-03-25 13:48:49 -0700380 case kScanline_Mode: {
scroggo46c57472015-09-30 08:57:13 -0700381 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr,
382 colorCountPtr)) {
msarett9e707a02015-09-01 14:57:57 -0700383 return Error::Nonfatal("Could not start scanline decoder");
scroggo9c59ebc2015-03-25 13:48:49 -0700384 }
scroggo1c005e42015-08-04 09:24:45 -0700385
msarette6dd0042015-10-09 11:07:34 -0700386 void* dst = bitmap.getAddr(0, 0);
387 size_t rowBytes = bitmap.rowBytes();
388 uint32_t height = decodeInfo.height();
scroggo46c57472015-09-30 08:57:13 -0700389 switch (codec->getScanlineOrder()) {
390 case SkCodec::kTopDown_SkScanlineOrder:
391 case SkCodec::kBottomUp_SkScanlineOrder:
392 case SkCodec::kNone_SkScanlineOrder:
msarette6dd0042015-10-09 11:07:34 -0700393 // We do not need to check the return value. On an incomplete
394 // image, memory will be filled with a default value.
395 codec->getScanlines(dst, height, rowBytes);
msarett10522ff2015-09-07 08:54:01 -0700396 break;
scroggo46c57472015-09-30 08:57:13 -0700397 case SkCodec::kOutOfOrder_SkScanlineOrder: {
msarett10522ff2015-09-07 08:54:01 -0700398 for (int y = 0; y < decodeInfo.height(); y++) {
msarette6dd0042015-10-09 11:07:34 -0700399 int dstY = codec->outputScanline(y);
msarett10522ff2015-09-07 08:54:01 -0700400 void* dstPtr = bitmap.getAddr(0, dstY);
msarette6dd0042015-10-09 11:07:34 -0700401 // We complete the loop, even if this call begins to fail
402 // due to an incomplete image. This ensures any uninitialized
403 // memory will be filled with the proper value.
404 codec->getScanlines(dstPtr, 1, bitmap.rowBytes());
msarett10522ff2015-09-07 08:54:01 -0700405 }
406 break;
407 }
408 }
409
emmaleer97002062015-05-27 12:36:10 -0700410 canvas->drawBitmap(bitmap, 0, 0);
411 break;
412 }
msarett0a242972015-06-11 14:27:27 -0700413 case kStripe_Mode: {
414 const int height = decodeInfo.height();
415 // This value is chosen arbitrarily. We exercise more cases by choosing a value that
416 // does not align with image blocks.
417 const int stripeHeight = 37;
418 const int numStripes = (height + stripeHeight - 1) / stripeHeight;
419
420 // Decode odd stripes
scroggo46c57472015-09-30 08:57:13 -0700421 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr,
422 colorCountPtr)
423 || SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOrder()) {
msarett9e707a02015-09-01 14:57:57 -0700424 // This mode was designed to test the new skip scanlines API in libjpeg-turbo.
425 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting
426 // to run this test for image types that do not have this scanline ordering.
msarett5406d6f2015-08-31 06:55:13 -0700427 return Error::Nonfatal("Could not start top-down scanline decoder");
msarett0a242972015-06-11 14:27:27 -0700428 }
msarette6dd0042015-10-09 11:07:34 -0700429
msarett0a242972015-06-11 14:27:27 -0700430 for (int i = 0; i < numStripes; i += 2) {
431 // Skip a stripe
432 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight);
msarette6dd0042015-10-09 11:07:34 -0700433 codec->skipScanlines(linesToSkip);
msarett0a242972015-06-11 14:27:27 -0700434
435 // Read a stripe
436 const int startY = (i + 1) * stripeHeight;
437 const int linesToRead = SkTMin(stripeHeight, height - startY);
438 if (linesToRead > 0) {
msarette6dd0042015-10-09 11:07:34 -0700439 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes());
msarett0a242972015-06-11 14:27:27 -0700440 }
441 }
442
443 // Decode even stripes
scroggo46c57472015-09-30 08:57:13 -0700444 const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo, nullptr,
445 colorPtr, colorCountPtr);
scroggo1c005e42015-08-04 09:24:45 -0700446 if (SkCodec::kSuccess != startResult) {
447 return "Failed to restart scanline decoder with same parameters.";
msarett0a242972015-06-11 14:27:27 -0700448 }
449 for (int i = 0; i < numStripes; i += 2) {
450 // Read a stripe
451 const int startY = i * stripeHeight;
452 const int linesToRead = SkTMin(stripeHeight, height - startY);
msarette6dd0042015-10-09 11:07:34 -0700453 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes());
msarett0a242972015-06-11 14:27:27 -0700454
455 // Skip a stripe
msarettf6db27e2015-06-12 09:34:04 -0700456 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight);
457 if (linesToSkip > 0) {
msarette6dd0042015-10-09 11:07:34 -0700458 codec->skipScanlines(linesToSkip);
msarett0a242972015-06-11 14:27:27 -0700459 }
460 }
461 canvas->drawBitmap(bitmap, 0, 0);
emmaleer0a4c3cb2015-06-22 10:40:21 -0700462 break;
msarett0a242972015-06-11 14:27:27 -0700463 }
scroggob636b452015-07-22 07:16:20 -0700464 case kSubset_Mode: {
465 // Arbitrarily choose a divisor.
466 int divisor = 2;
467 // Total width/height of the image.
468 const int W = codec->getInfo().width();
469 const int H = codec->getInfo().height();
470 if (divisor > W || divisor > H) {
471 return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divisor %d is too big "
472 "for %s with dimensions (%d x %d)", divisor,
473 fPath.c_str(), W, H));
474 }
475 // subset dimensions
476 // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
477 const int w = SkAlign2(W / divisor);
478 const int h = SkAlign2(H / divisor);
479 SkIRect subset;
480 SkCodec::Options opts;
481 opts.fSubset = &subset;
482 SkBitmap subsetBm;
483 // We will reuse pixel memory from bitmap.
484 void* pixels = bitmap.getPixels();
485 // Keep track of left and top (for drawing subsetBm into canvas). We could use
486 // fScale * x and fScale * y, but we want integers such that the next subset will start
487 // where the last one ended. So we'll add decodeInfo.width() and height().
488 int left = 0;
489 for (int x = 0; x < W; x += w) {
490 int top = 0;
491 for (int y = 0; y < H; y+= h) {
492 // Do not make the subset go off the edge of the image.
493 const int preScaleW = SkTMin(w, W - x);
494 const int preScaleH = SkTMin(h, H - y);
495 subset.setXYWH(x, y, preScaleW, preScaleH);
496 // And scale
497 // FIXME: Should we have a version of getScaledDimensions that takes a subset
498 // into account?
msarette6dd0042015-10-09 11:07:34 -0700499 decodeInfo = decodeInfo.makeWH(
500 SkTMax(1, SkScalarRoundToInt(preScaleW * fScale)),
501 SkTMax(1, SkScalarRoundToInt(preScaleH * fScale)));
scroggob636b452015-07-22 07:16:20 -0700502 size_t rowBytes = decodeInfo.minRowBytes();
503 if (!subsetBm.installPixels(decodeInfo, pixels, rowBytes, colorTable.get(),
halcanary96fcdcc2015-08-27 07:41:13 -0700504 nullptr, nullptr)) {
scroggob636b452015-07-22 07:16:20 -0700505 return SkStringPrintf("could not install pixels for %s.", fPath.c_str());
506 }
507 const SkCodec::Result result = codec->getPixels(decodeInfo, pixels, rowBytes,
508 &opts, colorPtr, colorCountPtr);
509 switch (result) {
510 case SkCodec::kSuccess:
511 case SkCodec::kIncompleteInput:
512 break;
513 case SkCodec::kInvalidConversion:
514 if (0 == (x|y)) {
515 // First subset is okay to return unimplemented.
516 return Error::Nonfatal("Incompatible colortype conversion");
517 }
518 // If the first subset succeeded, a later one should not fail.
519 // fall through to failure
520 case SkCodec::kUnimplemented:
521 if (0 == (x|y)) {
522 // First subset is okay to return unimplemented.
523 return Error::Nonfatal("subset codec not supported");
524 }
525 // If the first subset succeeded, why would a later one fail?
526 // fall through to failure
527 default:
528 return SkStringPrintf("subset codec failed to decode (%d, %d, %d, %d) "
529 "from %s with dimensions (%d x %d)\t error %d",
530 x, y, decodeInfo.width(), decodeInfo.height(),
531 fPath.c_str(), W, H, result);
532 }
533 canvas->drawBitmap(subsetBm, SkIntToScalar(left), SkIntToScalar(top));
534 // translate by the scaled height.
535 top += decodeInfo.height();
536 }
537 // translate by the scaled width.
538 left += decodeInfo.width();
539 }
540 return "";
541 }
msarettb714fb02016-01-22 14:46:42 -0800542 default:
543 SkASSERT(false);
544 return "Invalid fMode";
scroggo9b77ddd2015-03-19 06:03:39 -0700545 }
scroggo9c59ebc2015-03-25 13:48:49 -0700546 return "";
scroggo9b77ddd2015-03-19 06:03:39 -0700547}
548
549SkISize CodecSrc::size() const {
550 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
msarett3d9d7a72015-10-21 10:27:10 -0700551 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
scroggo7fac5af2015-09-30 11:33:12 -0700552 if (nullptr == codec) {
553 return SkISize::Make(0, 0);
554 }
555 return codec->getScaledDimensions(fScale);
scroggo9b77ddd2015-03-19 06:03:39 -0700556}
557
558Name CodecSrc::name() const {
msarett0a242972015-06-11 14:27:27 -0700559 if (1.0f == fScale) {
560 return SkOSPath::Basename(fPath.c_str());
msarett0a242972015-06-11 14:27:27 -0700561 }
msaretta5783ae2015-09-08 15:35:32 -0700562 return get_scaled_name(fPath, fScale);
scroggo9b77ddd2015-03-19 06:03:39 -0700563}
564
565/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
566
msarett3d9d7a72015-10-21 10:27:10 -0700567AndroidCodecSrc::AndroidCodecSrc(Path path, Mode mode, CodecSrc::DstColorType dstColorType,
568 int sampleSize)
569 : fPath(path)
570 , fMode(mode)
571 , fDstColorType(dstColorType)
572 , fSampleSize(sampleSize)
573{}
574
575bool AndroidCodecSrc::veto(SinkFlags flags) const {
576 // No need to test decoding to non-raster or indirect backend.
msarett3d9d7a72015-10-21 10:27:10 -0700577 return flags.type != SinkFlags::kRaster
578 || flags.approach != SinkFlags::kDirect;
579}
580
581Error AndroidCodecSrc::draw(SkCanvas* canvas) const {
582 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
583 if (!encoded) {
584 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
585 }
586 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded));
587 if (nullptr == codec.get()) {
588 return SkStringPrintf("Couldn't create android codec for %s.", fPath.c_str());
589 }
590
591 SkImageInfo decodeInfo;
592 if (!get_decode_info(&decodeInfo, codec->getInfo(), canvas->imageInfo().colorType(),
593 fDstColorType)) {
594 return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
595 }
596
597 // Scale the image if it is desired.
598 SkISize size = codec->getSampledDimensions(fSampleSize);
599
600 // Visually inspecting very small output images is not necessary. We will
601 // cover these cases in unit testing.
602 if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) {
603 return Error::Nonfatal("Scaling very small images is uninteresting.");
604 }
605 decodeInfo = decodeInfo.makeWH(size.width(), size.height());
606
607 // Construct a color table for the decode if necessary
608 SkAutoTUnref<SkColorTable> colorTable(nullptr);
609 SkPMColor* colorPtr = nullptr;
610 int* colorCountPtr = nullptr;
611 int maxColors = 256;
612 if (kIndex_8_SkColorType == decodeInfo.colorType()) {
613 SkPMColor colors[256];
614 colorTable.reset(new SkColorTable(colors, maxColors));
615 colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
616 colorCountPtr = &maxColors;
617 }
618
619 SkBitmap bitmap;
620 if (!bitmap.tryAllocPixels(decodeInfo, nullptr, colorTable.get())) {
mtklein9b439152015-12-09 13:02:26 -0800621 return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(),
msarett3d9d7a72015-10-21 10:27:10 -0700622 decodeInfo.width(), decodeInfo.height());
623 }
624
625 // Create options for the codec.
626 SkAndroidCodec::AndroidOptions options;
627 options.fColorPtr = colorPtr;
628 options.fColorCount = colorCountPtr;
629 options.fSampleSize = fSampleSize;
630
631 switch (fMode) {
632 case kFullImage_Mode: {
633 switch (codec->getAndroidPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(),
634 &options)) {
635 case SkCodec::kSuccess:
636 case SkCodec::kIncompleteInput:
637 break;
638 case SkCodec::kInvalidConversion:
mtklein9b439152015-12-09 13:02:26 -0800639 return Error::Nonfatal("Cannot convert to requested color type.");
msarett3d9d7a72015-10-21 10:27:10 -0700640 default:
641 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
642 }
643 canvas->drawBitmap(bitmap, 0, 0);
644 return "";
645 }
646 case kDivisor_Mode: {
647 const int width = codec->getInfo().width();
648 const int height = codec->getInfo().height();
649 const int divisor = 2;
650 if (width < divisor || height < divisor) {
mtklein9b439152015-12-09 13:02:26 -0800651 return Error::Nonfatal("Divisor is larger than image dimension.");
msarett3d9d7a72015-10-21 10:27:10 -0700652 }
653
msarettfa23a9e2015-10-21 13:26:59 -0700654 // Keep track of the final decoded dimensions.
655 int finalScaledWidth = 0;
656 int finalScaledHeight = 0;
msarett3d9d7a72015-10-21 10:27:10 -0700657 for (int x = 0; x < divisor; x++) {
658 for (int y = 0; y < divisor; y++) {
659 // Calculate the subset dimensions
660 int subsetWidth = width / divisor;
661 int subsetHeight = height / divisor;
662 const int left = x * subsetWidth;
663 const int top = y * subsetHeight;
664
665 // Increase the size of the last subset in each row or column, when the
666 // divisor does not divide evenly into the image dimensions
667 subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0;
668 subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0;
669 SkIRect subset = SkIRect::MakeXYWH(left, top, subsetWidth, subsetHeight);
670 if (!codec->getSupportedSubset(&subset)) {
mtklein9b439152015-12-09 13:02:26 -0800671 return "Could not get supported subset to decode.";
msarett3d9d7a72015-10-21 10:27:10 -0700672 }
673 options.fSubset = &subset;
msarettfa23a9e2015-10-21 13:26:59 -0700674 const int scaledWidthOffset = subset.left() / fSampleSize;
675 const int scaledHeightOffset = subset.top() / fSampleSize;
676 void* pixels = bitmap.getAddr(scaledWidthOffset, scaledHeightOffset);
msarett3d9d7a72015-10-21 10:27:10 -0700677 SkISize scaledSubsetSize = codec->getSampledSubsetDimensions(fSampleSize,
678 subset);
679 SkImageInfo subsetDecodeInfo = decodeInfo.makeWH(scaledSubsetSize.width(),
680 scaledSubsetSize.height());
681
msarettfa23a9e2015-10-21 13:26:59 -0700682 if (x + 1 == divisor && y + 1 == divisor) {
683 finalScaledWidth = scaledWidthOffset + scaledSubsetSize.width();
684 finalScaledHeight = scaledHeightOffset + scaledSubsetSize.height();
685 }
686
msarett3d9d7a72015-10-21 10:27:10 -0700687 switch (codec->getAndroidPixels(subsetDecodeInfo, pixels, bitmap.rowBytes(),
688 &options)) {
689 case SkCodec::kSuccess:
690 case SkCodec::kIncompleteInput:
691 break;
692 case SkCodec::kInvalidConversion:
mtklein9b439152015-12-09 13:02:26 -0800693 return Error::Nonfatal("Cannot convert to requested color type.");
msarett3d9d7a72015-10-21 10:27:10 -0700694 default:
695 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
696 }
697 }
698 }
msarettfa23a9e2015-10-21 13:26:59 -0700699
700 SkRect rect = SkRect::MakeXYWH(0, 0, (SkScalar) finalScaledWidth,
701 (SkScalar) finalScaledHeight);
702 canvas->drawBitmapRect(bitmap, rect, rect, nullptr);
msarett3d9d7a72015-10-21 10:27:10 -0700703 return "";
704 }
705 default:
706 SkASSERT(false);
mtklein9b439152015-12-09 13:02:26 -0800707 return "Error: Should not be reached.";
msarett3d9d7a72015-10-21 10:27:10 -0700708 }
709}
710
711SkISize AndroidCodecSrc::size() const {
712 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
713 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded));
714 if (nullptr == codec) {
715 return SkISize::Make(0, 0);
716 }
717 return codec->getSampledDimensions(fSampleSize);
718}
719
720Name AndroidCodecSrc::name() const {
721 // We will replicate the names used by CodecSrc so that images can
722 // be compared in Gold.
723 if (1 == fSampleSize) {
724 return SkOSPath::Basename(fPath.c_str());
725 }
msarett4b0778e2015-11-13 09:59:11 -0800726 return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
msarett3d9d7a72015-10-21 10:27:10 -0700727}
728
729/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
730
msarett164d3022015-11-10 15:09:03 -0800731ImageSrc::ImageSrc(Path path) : fPath(path) {}
scroggo9b77ddd2015-03-19 06:03:39 -0700732
mtklein99cab4e2015-07-31 06:43:04 -0700733bool ImageSrc::veto(SinkFlags flags) const {
734 // No need to test decoding to non-raster or indirect backend.
mtkleine0effd62015-07-29 06:37:28 -0700735 // TODO: Instead, use lazy decoding to allow the GPU to handle cases like YUV.
mtklein99cab4e2015-07-31 06:43:04 -0700736 return flags.type != SinkFlags::kRaster
737 || flags.approach != SinkFlags::kDirect;
mtkleine0effd62015-07-29 06:37:28 -0700738}
scroggo9b77ddd2015-03-19 06:03:39 -0700739
mtkleine0effd62015-07-29 06:37:28 -0700740Error ImageSrc::draw(SkCanvas* canvas) const {
scroggo9b77ddd2015-03-19 06:03:39 -0700741 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
742 if (!encoded) {
743 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
744 }
mtkleine0effd62015-07-29 06:37:28 -0700745 const SkColorType dstColorType = canvas->imageInfo().colorType();
mtkleinedc93bc2015-01-30 13:22:23 -0800746
msarett164d3022015-11-10 15:09:03 -0800747 // Decode the full image.
748 SkBitmap bitmap;
749 if (!SkImageDecoder::DecodeMemory(encoded->data(), encoded->size(), &bitmap,
750 dstColorType, SkImageDecoder::kDecodePixels_Mode)) {
751 return SkStringPrintf("Couldn't decode %s.", fPath.c_str());
mtkleinedc93bc2015-01-30 13:22:23 -0800752 }
msarett164d3022015-11-10 15:09:03 -0800753 if (kRGB_565_SkColorType == dstColorType && !bitmap.isOpaque()) {
754 // Do not draw a bitmap with alpha to a destination without alpha.
755 return Error::Nonfatal("Uninteresting to decode image with alpha into 565.");
mtklein748ca3b2015-01-15 10:56:12 -0800756 }
msarett164d3022015-11-10 15:09:03 -0800757 encoded.reset((SkData*)nullptr); // Might as well drop this when we're done with it.
758 canvas->drawBitmap(bitmap, 0,0);
mtklein748ca3b2015-01-15 10:56:12 -0800759 return "";
760}
761
762SkISize ImageSrc::size() const {
mtklein75d98fd2015-01-18 07:05:01 -0800763 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
scroggo9b77ddd2015-03-19 06:03:39 -0700764 SkBitmap bitmap;
765 if (!encoded || !SkImageDecoder::DecodeMemory(encoded->data(),
766 encoded->size(),
767 &bitmap,
768 kUnknown_SkColorType,
769 SkImageDecoder::kDecodeBounds_Mode)) {
770 return SkISize::Make(0,0);
mtklein748ca3b2015-01-15 10:56:12 -0800771 }
scroggo9b77ddd2015-03-19 06:03:39 -0700772 return bitmap.dimensions();
mtklein748ca3b2015-01-15 10:56:12 -0800773}
774
mtklein9264a952015-01-20 10:11:53 -0800775Name ImageSrc::name() const {
mtkleinedc93bc2015-01-30 13:22:23 -0800776 return SkOSPath::Basename(fPath.c_str());
mtklein9264a952015-01-20 10:11:53 -0800777}
mtklein748ca3b2015-01-15 10:56:12 -0800778
779/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
780
mtkleinf4ba3212015-01-28 15:32:24 -0800781static const SkRect kSKPViewport = {0,0, 1000,1000};
782
mtklein8d17a132015-01-30 11:42:31 -0800783SKPSrc::SKPSrc(Path path) : fPath(path) {}
mtklein748ca3b2015-01-15 10:56:12 -0800784
785Error SKPSrc::draw(SkCanvas* canvas) const {
scroggoa1193e42015-01-21 12:09:53 -0800786 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str()));
mtklein75d98fd2015-01-18 07:05:01 -0800787 if (!stream) {
mtklein748ca3b2015-01-15 10:56:12 -0800788 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
789 }
mtkleinb3e5e4d2015-03-25 13:13:43 -0700790 SkAutoTUnref<SkPicture> pic(SkPicture::CreateFromStream(stream, &lazy_decode_bitmap));
mtklein75d98fd2015-01-18 07:05:01 -0800791 if (!pic) {
792 return SkStringPrintf("Couldn't decode %s as a picture.", fPath.c_str());
793 }
halcanary96fcdcc2015-08-27 07:41:13 -0700794 stream.reset((SkStream*)nullptr); // Might as well drop this when we're done with it.
joshualitt7c3a2f82015-03-31 13:32:05 -0700795
mtkleinf4ba3212015-01-28 15:32:24 -0800796 canvas->clipRect(kSKPViewport);
mtklein748ca3b2015-01-15 10:56:12 -0800797 canvas->drawPicture(pic);
798 return "";
799}
800
801SkISize SKPSrc::size() const {
mtkleinffa901a2015-03-16 10:38:07 -0700802 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str()));
803 if (!stream) {
804 return SkISize::Make(0,0);
805 }
806 SkPictInfo info;
807 if (!SkPicture::InternalOnly_StreamIsSKP(stream, &info)) {
808 return SkISize::Make(0,0);
809 }
810 SkRect viewport = kSKPViewport;
811 if (!viewport.intersect(info.fCullRect)) {
812 return SkISize::Make(0,0);
813 }
814 return viewport.roundOut().size();
mtklein748ca3b2015-01-15 10:56:12 -0800815}
816
817Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
818
819/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
820
mtkleinad66f9b2015-02-13 15:11:10 -0800821Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const {
822 SkAutoTDelete<SkCanvas> canvas(SkCreateNullCanvas());
823 return src.draw(canvas);
824}
825
826/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
827
mtkleinb9eb4ac2015-02-02 18:26:03 -0800828DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?");
829
mtklein82d28432015-01-15 12:46:02 -0800830GPUSink::GPUSink(GrContextFactory::GLContextType ct,
kkinnunen5219fd92015-12-10 06:28:13 -0800831 GrContextFactory::GLContextOptions options,
mtklein82d28432015-01-15 12:46:02 -0800832 int samples,
bsalomonafcd7cd2015-08-31 12:39:41 -0700833 bool diText,
mtklein82d28432015-01-15 12:46:02 -0800834 bool threaded)
mtklein748ca3b2015-01-15 10:56:12 -0800835 : fContextType(ct)
kkinnunen5219fd92015-12-10 06:28:13 -0800836 , fContextOptions(options)
mtklein748ca3b2015-01-15 10:56:12 -0800837 , fSampleCount(samples)
bsalomonafcd7cd2015-08-31 12:39:41 -0700838 , fUseDIText(diText)
mtklein82d28432015-01-15 12:46:02 -0800839 , fThreaded(threaded) {}
mtklein748ca3b2015-01-15 10:56:12 -0800840
841int GPUSink::enclave() const {
mtklein55e88b22015-01-21 15:50:13 -0800842 return fThreaded ? kAnyThread_Enclave : kGPU_Enclave;
mtklein748ca3b2015-01-15 10:56:12 -0800843}
844
joshualitt5f5a8d72015-02-25 14:09:45 -0800845void PreAbandonGpuContextErrorHandler(SkError, void*) {}
846
bsalomon648c6962015-10-23 09:06:59 -0700847DEFINE_bool(imm, false, "Run gpu configs in immediate mode.");
bsalomon69cfe952015-11-30 13:27:47 -0800848DEFINE_bool(batchClip, false, "Clip each GrBatch to its device bounds for testing.");
bsalomon6dea83f2015-12-03 12:58:06 -0800849DEFINE_bool(batchBounds, false, "Draw a wireframe bounds of each GrBatch.");
bsalomon489147c2015-12-14 12:13:09 -0800850DEFINE_int32(batchLookback, -1, "Maximum GrBatch lookback for combining, negative means default.");
bsalomon648c6962015-10-23 09:06:59 -0700851
mtkleinb9eb4ac2015-02-02 18:26:03 -0800852Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const {
kkinnunen5219fd92015-12-10 06:28:13 -0800853 GrContextOptions grOptions;
bsalomon489147c2015-12-14 12:13:09 -0800854 grOptions.fImmediateMode = FLAGS_imm;
855 grOptions.fClipBatchToBounds = FLAGS_batchClip;
856 grOptions.fDrawBatchBounds = FLAGS_batchBounds;
857 grOptions.fMaxBatchLookback = FLAGS_batchLookback;
kkinnunen64492c42015-12-08 01:24:40 -0800858
kkinnunen5219fd92015-12-10 06:28:13 -0800859 src.modifyGrContextOptions(&grOptions);
860
861 GrContextFactory factory(grOptions);
mtkleinf4ba3212015-01-28 15:32:24 -0800862 const SkISize size = src.size();
mtklein748ca3b2015-01-15 10:56:12 -0800863 const SkImageInfo info =
864 SkImageInfo::Make(size.width(), size.height(), kN32_SkColorType, kPremul_SkAlphaType);
865 SkAutoTUnref<SkSurface> surface(
kkinnunen3e980c32015-12-23 01:33:00 -0800866 NewGpuSurface(&factory, fContextType, fContextOptions, info, fSampleCount, fUseDIText));
mtklein748ca3b2015-01-15 10:56:12 -0800867 if (!surface) {
868 return "Could not create a surface.";
869 }
joshualitt5f5a8d72015-02-25 14:09:45 -0800870 if (FLAGS_preAbandonGpuContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700871 SkSetErrorCallback(&PreAbandonGpuContextErrorHandler, nullptr);
joshualitt5f5a8d72015-02-25 14:09:45 -0800872 factory.abandonContexts();
873 }
mtklein748ca3b2015-01-15 10:56:12 -0800874 SkCanvas* canvas = surface->getCanvas();
875 Error err = src.draw(canvas);
876 if (!err.isEmpty()) {
877 return err;
878 }
879 canvas->flush();
mtkleinb9eb4ac2015-02-02 18:26:03 -0800880 if (FLAGS_gpuStats) {
881 canvas->getGrContext()->dumpCacheStats(log);
882 canvas->getGrContext()->dumpGpuStats(log);
883 }
mtklein748ca3b2015-01-15 10:56:12 -0800884 dst->allocPixels(info);
joshualitt5f5a8d72015-02-25 14:09:45 -0800885 canvas->readPixels(dst, 0, 0);
mtklein55e88b22015-01-21 15:50:13 -0800886 if (FLAGS_abandonGpuContext) {
887 factory.abandonContexts();
888 }
mtklein748ca3b2015-01-15 10:56:12 -0800889 return "";
890}
891
892/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
893
halcanary47ef4d52015-03-03 09:13:09 -0800894static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) {
895 // Print the given DM:Src to a document, breaking on 8.5x11 pages.
896 SkASSERT(doc);
halcanaryfd4a9932015-01-28 11:45:58 -0800897 int width = src.size().width(),
898 height = src.size().height();
899
halcanary7e798182015-04-14 14:06:18 -0700900 if (FLAGS_multiPage) {
901 const int kLetterWidth = 612, // 8.5 * 72
902 kLetterHeight = 792; // 11 * 72
903 const SkRect letter = SkRect::MakeWH(SkIntToScalar(kLetterWidth),
904 SkIntToScalar(kLetterHeight));
halcanaryfd4a9932015-01-28 11:45:58 -0800905
halcanary7e798182015-04-14 14:06:18 -0700906 int xPages = ((width - 1) / kLetterWidth) + 1;
907 int yPages = ((height - 1) / kLetterHeight) + 1;
halcanaryfd4a9932015-01-28 11:45:58 -0800908
halcanary7e798182015-04-14 14:06:18 -0700909 for (int y = 0; y < yPages; ++y) {
910 for (int x = 0; x < xPages; ++x) {
911 int w = SkTMin(kLetterWidth, width - (x * kLetterWidth));
912 int h = SkTMin(kLetterHeight, height - (y * kLetterHeight));
913 SkCanvas* canvas =
914 doc->beginPage(SkIntToScalar(w), SkIntToScalar(h));
915 if (!canvas) {
halcanary96fcdcc2015-08-27 07:41:13 -0700916 return "SkDocument::beginPage(w,h) returned nullptr";
halcanary7e798182015-04-14 14:06:18 -0700917 }
918 canvas->clipRect(letter);
919 canvas->translate(-letter.width() * x, -letter.height() * y);
920 Error err = src.draw(canvas);
921 if (!err.isEmpty()) {
922 return err;
923 }
924 doc->endPage();
djsollen2ab90002015-04-03 06:38:31 -0700925 }
halcanaryfd4a9932015-01-28 11:45:58 -0800926 }
halcanary7e798182015-04-14 14:06:18 -0700927 } else {
928 SkCanvas* canvas =
929 doc->beginPage(SkIntToScalar(width), SkIntToScalar(height));
930 if (!canvas) {
halcanary96fcdcc2015-08-27 07:41:13 -0700931 return "SkDocument::beginPage(w,h) returned nullptr";
halcanary7e798182015-04-14 14:06:18 -0700932 }
933 Error err = src.draw(canvas);
934 if (!err.isEmpty()) {
935 return err;
936 }
937 doc->endPage();
mtklein748ca3b2015-01-15 10:56:12 -0800938 }
halcanary7e798182015-04-14 14:06:18 -0700939 if (!doc->close()) {
940 return "SkDocument::close() returned false";
941 }
halcanaryfd4a9932015-01-28 11:45:58 -0800942 dst->flush();
mtklein748ca3b2015-01-15 10:56:12 -0800943 return "";
944}
945
halcanaryc11c62f2015-09-28 11:51:54 -0700946PDFSink::PDFSink(const char* rasterizer) : fRasterizer(rasterizer) {}
halcanary47ef4d52015-03-03 09:13:09 -0800947
948Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
949 SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(dst));
950 if (!doc) {
halcanary96fcdcc2015-08-27 07:41:13 -0700951 return "SkDocument::CreatePDF() returned nullptr";
halcanary47ef4d52015-03-03 09:13:09 -0800952 }
halcanaryf12a1672015-09-23 12:45:49 -0700953 SkTArray<SkDocument::Attribute> info;
954 info.emplace_back(SkString("Title"), src.name());
955 info.emplace_back(SkString("Subject"),
956 SkString("rendering correctness test"));
957 info.emplace_back(SkString("Creator"), SkString("Skia/DM"));
halcanaryc11c62f2015-09-28 11:51:54 -0700958
959 info.emplace_back(SkString("Keywords"),
960 SkStringPrintf("Rasterizer:%s;", fRasterizer));
halcanaryf12a1672015-09-23 12:45:49 -0700961 doc->setMetadata(info, nullptr, nullptr);
halcanary47ef4d52015-03-03 09:13:09 -0800962 return draw_skdocument(src, doc.get(), dst);
963}
964
965/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
966
967XPSSink::XPSSink() {}
968
969Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
970 SkAutoTUnref<SkDocument> doc(SkDocument::CreateXPS(dst));
971 if (!doc) {
halcanary96fcdcc2015-08-27 07:41:13 -0700972 return "SkDocument::CreateXPS() returned nullptr";
halcanary47ef4d52015-03-03 09:13:09 -0800973 }
974 return draw_skdocument(src, doc.get(), dst);
975}
mtklein748ca3b2015-01-15 10:56:12 -0800976/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
977
mtklein9c3f17d2015-01-28 11:35:18 -0800978SKPSink::SKPSink() {}
979
mtkleinb9eb4ac2015-02-02 18:26:03 -0800980Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
mtklein9c3f17d2015-01-28 11:35:18 -0800981 SkSize size;
982 size = src.size();
983 SkPictureRecorder recorder;
984 Error err = src.draw(recorder.beginRecording(size.width(), size.height()));
985 if (!err.isEmpty()) {
986 return err;
987 }
988 SkAutoTUnref<SkPicture> pic(recorder.endRecording());
989 pic->serialize(dst);
990 return "";
991}
992
993/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
994
mtklein8a4527e2015-01-31 20:00:58 -0800995SVGSink::SVGSink() {}
996
mtkleinb9eb4ac2015-02-02 18:26:03 -0800997Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
halcanary385fe4d2015-08-26 13:07:48 -0700998 SkAutoTDelete<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(dst));
fmalita2aafe6f2015-02-06 12:51:10 -0800999 SkAutoTUnref<SkCanvas> canvas(SkSVGCanvas::Create(
1000 SkRect::MakeWH(SkIntToScalar(src.size().width()), SkIntToScalar(src.size().height())),
1001 xmlWriter));
1002 return src.draw(canvas);
mtklein8a4527e2015-01-31 20:00:58 -08001003}
1004
1005/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1006
mtklein748ca3b2015-01-15 10:56:12 -08001007RasterSink::RasterSink(SkColorType colorType) : fColorType(colorType) {}
1008
mtkleinb9eb4ac2015-02-02 18:26:03 -08001009Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
mtkleinf4ba3212015-01-28 15:32:24 -08001010 const SkISize size = src.size();
mtklein748ca3b2015-01-15 10:56:12 -08001011 // If there's an appropriate alpha type for this color type, use it, otherwise use premul.
1012 SkAlphaType alphaType = kPremul_SkAlphaType;
1013 (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType);
1014
mtkleinc8be09a2016-01-04 18:56:57 -08001015 SkMallocPixelRef::ZeroedPRFactory factory;
1016 dst->allocPixels(SkImageInfo::Make(size.width(), size.height(), fColorType, alphaType),
1017 &factory,
1018 nullptr/*colortable*/);
mtklein748ca3b2015-01-15 10:56:12 -08001019 SkCanvas canvas(*dst);
1020 return src.draw(&canvas);
1021}
1022
1023/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1024
mtkleina16e69e2015-05-05 11:38:45 -07001025// Handy for front-patching a Src. Do whatever up-front work you need, then call draw_to_canvas(),
mtkleine44b5082015-05-07 10:53:34 -07001026// passing the Sink draw() arguments, a size, and a function draws into an SkCanvas.
mtkleina16e69e2015-05-05 11:38:45 -07001027// Several examples below.
1028
msarett62d3b102015-12-10 15:14:27 -08001029static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log,
mtklein64593522015-11-12 10:41:05 -08001030 SkISize size, std::function<Error(SkCanvas*)> draw) {
mtkleina16e69e2015-05-05 11:38:45 -07001031 class ProxySrc : public Src {
1032 public:
msarett62d3b102015-12-10 15:14:27 -08001033 ProxySrc(SkISize size, std::function<Error(SkCanvas*)> draw) : fSize(size), fDraw(draw) {}
mtkleina16e69e2015-05-05 11:38:45 -07001034 Error draw(SkCanvas* canvas) const override { return fDraw(canvas); }
msarett62d3b102015-12-10 15:14:27 -08001035 Name name() const override { sk_throw(); return ""; } // Won't be called.
mtkleina16e69e2015-05-05 11:38:45 -07001036 SkISize size() const override { return fSize; }
1037 private:
mtklein64593522015-11-12 10:41:05 -08001038 SkISize fSize;
1039 std::function<Error(SkCanvas*)> fDraw;
mtkleina16e69e2015-05-05 11:38:45 -07001040 };
msarett62d3b102015-12-10 15:14:27 -08001041 return sink->draw(ProxySrc(size, draw), bitmap, stream, log);
mtkleina16e69e2015-05-05 11:38:45 -07001042}
1043
1044/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1045
mtklein4a34ecb2016-01-08 10:19:35 -08001046DEFINE_bool(check, true, "If true, have most Via- modes fail if they affect the output.");
1047
1048// Is *bitmap identical to what you get drawing src into sink?
1049static Error check_against_reference(const SkBitmap* bitmap, const Src& src, Sink* sink) {
1050 // We can only check raster outputs.
1051 // (Non-raster outputs like .pdf, .skp, .svg may differ but still draw identically.)
1052 if (FLAGS_check && bitmap) {
1053 SkBitmap reference;
1054 SkString log;
1055 Error err = sink->draw(src, &reference, nullptr, &log);
1056 // If we can draw into this Sink via some pipeline, we should be able to draw directly.
1057 SkASSERT(err.isEmpty());
1058 if (!err.isEmpty()) {
1059 return err;
1060 }
1061 // The dimensions are a property of the Src only, and so should be identical.
1062 SkASSERT(reference.getSize() == bitmap->getSize());
1063 if (reference.getSize() != bitmap->getSize()) {
1064 return "Dimensions don't match reference";
1065 }
1066 // All SkBitmaps in DM are pre-locked and tight, so this comparison is easy.
1067 if (0 != memcmp(reference.getPixels(), bitmap->getPixels(), reference.getSize())) {
1068 return "Pixels don't match reference";
1069 }
1070 }
1071 return "";
1072}
1073
1074/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1075
mtkleind603b222015-02-17 11:13:33 -08001076static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) {
1077 SkRect bounds = SkRect::MakeIWH(srcW, srcH);
1078 matrix->mapRect(&bounds);
1079 matrix->postTranslate(-bounds.x(), -bounds.y());
1080 return SkISize::Make(SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height()));
1081}
1082
msarett62d3b102015-12-10 15:14:27 -08001083ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
mtklein748ca3b2015-01-15 10:56:12 -08001084
mtkleinb9eb4ac2015-02-02 18:26:03 -08001085Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtkleina16e69e2015-05-05 11:38:45 -07001086 SkMatrix matrix = fMatrix;
1087 SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height());
msarett62d3b102015-12-10 15:14:27 -08001088 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
mtkleina16e69e2015-05-05 11:38:45 -07001089 canvas->concat(matrix);
1090 return src.draw(canvas);
1091 });
mtklein748ca3b2015-01-15 10:56:12 -08001092}
1093
mtkleind603b222015-02-17 11:13:33 -08001094// Undoes any flip or 90 degree rotate without changing the scale of the bitmap.
1095// This should be pixel-preserving.
msarett62d3b102015-12-10 15:14:27 -08001096ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
mtkleind603b222015-02-17 11:13:33 -08001097
1098Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1099 Error err = fSink->draw(src, bitmap, stream, log);
1100 if (!err.isEmpty()) {
1101 return err;
1102 }
1103
1104 SkMatrix inverse;
1105 if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) {
1106 return "Cannot upright --matrix.";
1107 }
1108 SkMatrix upright = SkMatrix::I();
1109 upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX()));
1110 upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY()));
1111 upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX()));
1112 upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY()));
1113
1114 SkBitmap uprighted;
1115 SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height());
1116 uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height()));
1117
1118 SkCanvas canvas(uprighted);
1119 canvas.concat(upright);
1120 SkPaint paint;
1121 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
1122 canvas.drawBitmap(*bitmap, 0, 0, &paint);
1123
1124 *bitmap = uprighted;
1125 bitmap->lockPixels();
1126 return "";
1127}
1128
mtklein748ca3b2015-01-15 10:56:12 -08001129/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1130
mtklein2e2ea382015-10-16 10:29:41 -07001131Error ViaRemote::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
msarett62d3b102015-12-10 15:14:27 -08001132 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* target) {
mtklein479fe772015-10-21 12:34:01 -07001133 SkAutoTDelete<SkRemote::Encoder> decoder(SkRemote::NewDecoder(target));
1134 SkAutoTDelete<SkRemote::Encoder> cache(fCache ? SkRemote::NewCachingEncoder(decoder)
1135 : nullptr);
1136 SkAutoTDelete<SkCanvas> canvas(SkRemote::NewCanvas(cache ? cache : decoder));
1137 return src.draw(canvas);
mtklein2e2ea382015-10-16 10:29:41 -07001138 });
1139}
1140
mtklein748ca3b2015-01-15 10:56:12 -08001141/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
mtkleina16e69e2015-05-05 11:38:45 -07001142
mtkleina16e69e2015-05-05 11:38:45 -07001143Error ViaSerialization::draw(
1144 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtklein748ca3b2015-01-15 10:56:12 -08001145 // Record our Src into a picture.
mtkleina16e69e2015-05-05 11:38:45 -07001146 auto size = src.size();
mtklein748ca3b2015-01-15 10:56:12 -08001147 SkPictureRecorder recorder;
mtkleina16e69e2015-05-05 11:38:45 -07001148 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1149 SkIntToScalar(size.height())));
mtklein748ca3b2015-01-15 10:56:12 -08001150 if (!err.isEmpty()) {
1151 return err;
1152 }
1153 SkAutoTUnref<SkPicture> pic(recorder.endRecording());
1154
1155 // Serialize it and then deserialize it.
1156 SkDynamicMemoryWStream wStream;
1157 pic->serialize(&wStream);
scroggoa1193e42015-01-21 12:09:53 -08001158 SkAutoTDelete<SkStream> rStream(wStream.detachAsStream());
mtkleinb3e5e4d2015-03-25 13:13:43 -07001159 SkAutoTUnref<SkPicture> deserialized(SkPicture::CreateFromStream(rStream, &lazy_decode_bitmap));
mtklein748ca3b2015-01-15 10:56:12 -08001160
msarett62d3b102015-12-10 15:14:27 -08001161 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
mtkleina16e69e2015-05-05 11:38:45 -07001162 canvas->drawPicture(deserialized);
mtklein4a34ecb2016-01-08 10:19:35 -08001163 return check_against_reference(bitmap, src, fSink);
mtkleina16e69e2015-05-05 11:38:45 -07001164 });
mtklein748ca3b2015-01-15 10:56:12 -08001165}
1166
1167/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1168
msarett62d3b102015-12-10 15:14:27 -08001169ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink)
1170 : Via(sink)
mtklein78829242015-05-06 07:54:07 -07001171 , fW(w)
mtklein748ca3b2015-01-15 10:56:12 -08001172 , fH(h)
mtklein78829242015-05-06 07:54:07 -07001173 , fFactory(factory) {}
mtklein748ca3b2015-01-15 10:56:12 -08001174
mtkleinb9eb4ac2015-02-02 18:26:03 -08001175Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtkleina16e69e2015-05-05 11:38:45 -07001176 auto size = src.size();
mtklein748ca3b2015-01-15 10:56:12 -08001177 SkPictureRecorder recorder;
mtkleina16e69e2015-05-05 11:38:45 -07001178 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1179 SkIntToScalar(size.height()),
1180 fFactory.get()));
mtklein748ca3b2015-01-15 10:56:12 -08001181 if (!err.isEmpty()) {
1182 return err;
1183 }
mtkleinb7e8d692015-04-07 08:30:32 -07001184 SkAutoTUnref<SkPicture> pic(recorder.endRecordingAsPicture());
mtklein748ca3b2015-01-15 10:56:12 -08001185
msarett62d3b102015-12-10 15:14:27 -08001186 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) {
mtkleina16e69e2015-05-05 11:38:45 -07001187 const int xTiles = (size.width() + fW - 1) / fW,
1188 yTiles = (size.height() + fH - 1) / fH;
1189 SkMultiPictureDraw mpd(xTiles*yTiles);
1190 SkTDArray<SkSurface*> surfaces;
1191 surfaces.setReserve(xTiles*yTiles);
mtklein748ca3b2015-01-15 10:56:12 -08001192
mtkleina16e69e2015-05-05 11:38:45 -07001193 SkImageInfo info = canvas->imageInfo().makeWH(fW, fH);
1194 for (int j = 0; j < yTiles; j++) {
1195 for (int i = 0; i < xTiles; i++) {
1196 // This lets our ultimate Sink determine the best kind of surface.
1197 // E.g., if it's a GpuSink, the surfaces and images are textures.
1198 SkSurface* s = canvas->newSurface(info);
1199 if (!s) {
1200 s = SkSurface::NewRaster(info); // Some canvases can't create surfaces.
mtklein748ca3b2015-01-15 10:56:12 -08001201 }
mtkleina16e69e2015-05-05 11:38:45 -07001202 surfaces.push(s);
1203 SkCanvas* c = s->getCanvas();
1204 c->translate(SkIntToScalar(-i * fW),
1205 SkIntToScalar(-j * fH)); // Line up the canvas with this tile.
1206 mpd.add(c, pic);
mtklein748ca3b2015-01-15 10:56:12 -08001207 }
mtklein748ca3b2015-01-15 10:56:12 -08001208 }
mtkleina16e69e2015-05-05 11:38:45 -07001209 mpd.draw();
1210 for (int j = 0; j < yTiles; j++) {
1211 for (int i = 0; i < xTiles; i++) {
1212 SkAutoTUnref<SkImage> image(surfaces[i+xTiles*j]->newImageSnapshot());
1213 canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH));
1214 }
1215 }
1216 surfaces.unrefAll();
1217 return "";
1218 });
mtklein748ca3b2015-01-15 10:56:12 -08001219}
1220
mtkleinb7e8d692015-04-07 08:30:32 -07001221/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1222
mtklein4a34ecb2016-01-08 10:19:35 -08001223Error ViaPicture::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1224 auto size = src.size();
1225 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1226 SkPictureRecorder recorder;
1227 SkAutoTUnref<SkPicture> pic;
1228 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1229 SkIntToScalar(size.height())));
1230 if (!err.isEmpty()) {
1231 return err;
1232 }
1233 pic.reset(recorder.endRecordingAsPicture());
1234 canvas->drawPicture(pic);
1235 return check_against_reference(bitmap, src, fSink);
1236 });
1237}
1238
1239/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1240
mtkleinb7e8d692015-04-07 08:30:32 -07001241// Draw the Src into two pictures, then draw the second picture into the wrapped Sink.
1242// This tests that any shortcuts we may take while recording that second picture are legal.
1243Error ViaSecondPicture::draw(
1244 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtkleina16e69e2015-05-05 11:38:45 -07001245 auto size = src.size();
msarett62d3b102015-12-10 15:14:27 -08001246 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
mtkleina16e69e2015-05-05 11:38:45 -07001247 SkPictureRecorder recorder;
1248 SkAutoTUnref<SkPicture> pic;
1249 for (int i = 0; i < 2; i++) {
1250 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1251 SkIntToScalar(size.height())));
1252 if (!err.isEmpty()) {
1253 return err;
mtkleinb7e8d692015-04-07 08:30:32 -07001254 }
mtkleina16e69e2015-05-05 11:38:45 -07001255 pic.reset(recorder.endRecordingAsPicture());
mtkleinb7e8d692015-04-07 08:30:32 -07001256 }
mtkleina16e69e2015-05-05 11:38:45 -07001257 canvas->drawPicture(pic);
mtklein4a34ecb2016-01-08 10:19:35 -08001258 return check_against_reference(bitmap, src, fSink);
mtkleina16e69e2015-05-05 11:38:45 -07001259 });
mtkleinb7e8d692015-04-07 08:30:32 -07001260}
1261
mtkleind31c13d2015-05-05 12:59:56 -07001262/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1263
mtklein6fbf4b32015-05-06 11:35:40 -07001264// Draw the Src twice. This can help exercise caching.
1265Error ViaTwice::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
msarett62d3b102015-12-10 15:14:27 -08001266 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) -> Error {
mtklein6fbf4b32015-05-06 11:35:40 -07001267 for (int i = 0; i < 2; i++) {
1268 SkAutoCanvasRestore acr(canvas, true/*save now*/);
1269 canvas->clear(SK_ColorTRANSPARENT);
1270 Error err = src.draw(canvas);
1271 if (err.isEmpty()) {
1272 return err;
1273 }
1274 }
mtklein4a34ecb2016-01-08 10:19:35 -08001275 return check_against_reference(bitmap, src, fSink);
mtklein6fbf4b32015-05-06 11:35:40 -07001276 });
1277}
1278
1279/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1280
mtkleind31c13d2015-05-05 12:59:56 -07001281// This is like SkRecords::Draw, in that it plays back SkRecords ops into a Canvas.
1282// Unlike SkRecords::Draw, it builds a single-op sub-picture out of each Draw-type op.
1283// This is an only-slightly-exaggerated simluation of Blink's Slimming Paint pictures.
1284struct DrawsAsSingletonPictures {
1285 SkCanvas* fCanvas;
mtkleind2baa902015-07-07 09:43:28 -07001286 const SkDrawableList& fDrawables;
mtkleind31c13d2015-05-05 12:59:56 -07001287
mtkleind31c13d2015-05-05 12:59:56 -07001288 template <typename T>
1289 void draw(const T& op, SkCanvas* canvas) {
1290 // We must pass SkMatrix::I() as our initial matrix.
1291 // By default SkRecords::Draw() uses the canvas' matrix as its initial matrix,
1292 // which would have the funky effect of applying transforms over and over.
mtkleind2baa902015-07-07 09:43:28 -07001293 SkRecords::Draw d(canvas, nullptr, fDrawables.begin(), fDrawables.count(), &SkMatrix::I());
1294 d(op);
mtkleind31c13d2015-05-05 12:59:56 -07001295 }
1296
mtklein449d9b72015-09-28 10:33:02 -07001297 // Draws get their own picture.
mtkleind31c13d2015-05-05 12:59:56 -07001298 template <typename T>
mtklein449d9b72015-09-28 10:33:02 -07001299 SK_WHEN(T::kTags & SkRecords::kDraw_Tag, void) operator()(const T& op) {
mtkleind31c13d2015-05-05 12:59:56 -07001300 SkPictureRecorder rec;
1301 this->draw(op, rec.beginRecording(SkRect::MakeLargest()));
1302 SkAutoTUnref<SkPicture> pic(rec.endRecordingAsPicture());
1303 fCanvas->drawPicture(pic);
1304 }
1305
mtklein449d9b72015-09-28 10:33:02 -07001306 // We'll just issue non-draws directly.
mtkleind31c13d2015-05-05 12:59:56 -07001307 template <typename T>
mtklein449d9b72015-09-28 10:33:02 -07001308 skstd::enable_if_t<!(T::kTags & SkRecords::kDraw_Tag), void> operator()(const T& op) {
1309 this->draw(op, fCanvas);
1310 }
mtkleind31c13d2015-05-05 12:59:56 -07001311};
1312
mtkleind31c13d2015-05-05 12:59:56 -07001313// Record Src into a picture, then record it into a macro picture with a sub-picture for each draw.
1314// Then play back that macro picture into our wrapped sink.
1315Error ViaSingletonPictures::draw(
1316 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1317 auto size = src.size();
msarett62d3b102015-12-10 15:14:27 -08001318 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
mtkleind31c13d2015-05-05 12:59:56 -07001319 // Use low-level (Skia-private) recording APIs so we can read the SkRecord.
1320 SkRecord skr;
1321 SkRecorder recorder(&skr, size.width(), size.height());
1322 Error err = src.draw(&recorder);
1323 if (!err.isEmpty()) {
1324 return err;
1325 }
1326
1327 // Record our macro-picture, with each draw op as its own sub-picture.
1328 SkPictureRecorder macroRec;
1329 SkCanvas* macroCanvas = macroRec.beginRecording(SkIntToScalar(size.width()),
1330 SkIntToScalar(size.height()));
mtkleind2baa902015-07-07 09:43:28 -07001331
1332 SkAutoTDelete<SkDrawableList> drawables(recorder.detachDrawableList());
1333 const SkDrawableList empty;
1334
1335 DrawsAsSingletonPictures drawsAsSingletonPictures = {
1336 macroCanvas,
1337 drawables ? *drawables : empty,
1338 };
mtkleinc6ad06a2015-08-19 09:51:00 -07001339 for (int i = 0; i < skr.count(); i++) {
mtkleind31c13d2015-05-05 12:59:56 -07001340 skr.visit<void>(i, drawsAsSingletonPictures);
1341 }
1342 SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture());
1343
1344 canvas->drawPicture(macroPic);
mtklein4a34ecb2016-01-08 10:19:35 -08001345 return check_against_reference(bitmap, src, fSink);
mtkleind31c13d2015-05-05 12:59:56 -07001346 });
1347}
1348
mtklein748ca3b2015-01-15 10:56:12 -08001349} // namespace DM