blob: c3c8a7bc6e9b6a4bfd5c2298fc626c7cce25153f [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"
msarett9876ac52016-06-01 14:47:18 -07009#include "Resources.h"
msarett3d9d7a72015-10-21 10:27:10 -070010#include "SkAndroidCodec.h"
scroggof24f2242015-03-03 08:59:20 -080011#include "SkCodec.h"
msarettb714fb02016-01-22 14:46:42 -080012#include "SkCodecImageGenerator.h"
msarett888dc162016-05-23 10:21:17 -070013#include "SkColorSpace.h"
14#include "SkColorSpace_Base.h"
msarett9876ac52016-06-01 14:47:18 -070015#include "SkColorSpaceXform.h"
mtkleina16e69e2015-05-05 11:38:45 -070016#include "SkCommonFlags.h"
mtkleinb3e5e4d2015-03-25 13:13:43 -070017#include "SkData.h"
reedbabc3de2016-07-08 08:43:27 -070018#include "SkDeferredCanvas.h"
mtklein748ca3b2015-01-15 10:56:12 -080019#include "SkDocument.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080020#include "SkError.h"
mtkleinb3e5e4d2015-03-25 13:13:43 -070021#include "SkImageGenerator.h"
msarett18976312016-03-09 14:20:58 -080022#include "SkImageGeneratorCG.h"
msarettfc0b6d12016-03-17 13:50:17 -070023#include "SkImageGeneratorWIC.h"
mtklein8bbbb692016-08-15 12:56:00 -070024#include "SkLiteDL.h"
25#include "SkLiteRecorder.h"
mtkleinc8be09a2016-01-04 18:56:57 -080026#include "SkMallocPixelRef.h"
mtklein748ca3b2015-01-15 10:56:12 -080027#include "SkMultiPictureDraw.h"
mtkleinad66f9b2015-02-13 15:11:10 -080028#include "SkNullCanvas.h"
mtklein748ca3b2015-01-15 10:56:12 -080029#include "SkOSFile.h"
msarett9e9444c2016-02-03 12:39:10 -080030#include "SkOpts.h"
mtkleinffa901a2015-03-16 10:38:07 -070031#include "SkPictureData.h"
mtklein748ca3b2015-01-15 10:56:12 -080032#include "SkPictureRecorder.h"
33#include "SkRandom.h"
mtkleind31c13d2015-05-05 12:59:56 -070034#include "SkRecordDraw.h"
35#include "SkRecorder.h"
fmalita2aafe6f2015-02-06 12:51:10 -080036#include "SkSVGCanvas.h"
scroggoa1193e42015-01-21 12:09:53 -080037#include "SkStream.h"
mtklein449d9b72015-09-28 10:33:02 -070038#include "SkTLogic.h"
msarette6dd0042015-10-09 11:07:34 -070039#include "SkSwizzler.h"
mtklein64593522015-11-12 10:41:05 -080040#include <functional>
mtklein748ca3b2015-01-15 10:56:12 -080041
msarettfc0b6d12016-03-17 13:50:17 -070042#if defined(SK_BUILD_FOR_WIN)
43 #include "SkAutoCoInitialize.h"
44#endif
45
msarett469f1c52016-06-06 08:20:37 -070046#if defined(SK_TEST_QCMS)
msarett9876ac52016-06-01 14:47:18 -070047 #include "qcms.h"
48#endif
49
fmalita718df0a2016-07-15 10:33:29 -070050#if defined(SK_XML)
fmalitaa48f0e32016-08-04 06:26:05 -070051 #include "SkSVGDOM.h"
fmalita718df0a2016-07-15 10:33:29 -070052 #include "SkXMLWriter.h"
53#endif
54
halcanary7e798182015-04-14 14:06:18 -070055DEFINE_bool(multiPage, false, "For document-type backends, render the source"
56 " into multiple pages");
scroggo3ac66e92016-02-08 15:09:48 -080057DEFINE_bool(RAW_threading, true, "Allow RAW decodes to run on multiple threads?");
halcanary7e798182015-04-14 14:06:18 -070058
bsalomon3724e572016-03-30 18:56:19 -070059using sk_gpu_test::GrContextFactory;
60
mtklein748ca3b2015-01-15 10:56:12 -080061namespace DM {
62
mtklein748ca3b2015-01-15 10:56:12 -080063GMSrc::GMSrc(skiagm::GMRegistry::Factory factory) : fFactory(factory) {}
64
65Error GMSrc::draw(SkCanvas* canvas) const {
halcanary96fcdcc2015-08-27 07:41:13 -070066 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr));
mtklein748ca3b2015-01-15 10:56:12 -080067 canvas->concat(gm->getInitialTransform());
68 gm->draw(canvas);
69 return "";
70}
71
72SkISize GMSrc::size() const {
halcanary96fcdcc2015-08-27 07:41:13 -070073 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr));
mtklein748ca3b2015-01-15 10:56:12 -080074 return gm->getISize();
75}
76
77Name GMSrc::name() const {
halcanary96fcdcc2015-08-27 07:41:13 -070078 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr));
mtklein748ca3b2015-01-15 10:56:12 -080079 return gm->getName();
80}
81
bsalomon4ee6bd82015-05-27 13:23:23 -070082void GMSrc::modifyGrContextOptions(GrContextOptions* options) const {
halcanary96fcdcc2015-08-27 07:41:13 -070083 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr));
bsalomon4ee6bd82015-05-27 13:23:23 -070084 gm->modifyGrContextOptions(options);
85}
86
mtklein748ca3b2015-01-15 10:56:12 -080087/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
88
msarettd1227a72016-05-18 06:23:57 -070089BRDSrc::BRDSrc(Path path, Mode mode, CodecSrc::DstColorType dstColorType, uint32_t sampleSize)
msaretta5783ae2015-09-08 15:35:32 -070090 : fPath(path)
msaretta5783ae2015-09-08 15:35:32 -070091 , fMode(mode)
92 , fDstColorType(dstColorType)
93 , fSampleSize(sampleSize)
94{}
95
96bool BRDSrc::veto(SinkFlags flags) const {
97 // No need to test to non-raster or indirect backends.
98 return flags.type != SinkFlags::kRaster
99 || flags.approach != SinkFlags::kDirect;
100}
101
msarettd1227a72016-05-18 06:23:57 -0700102static SkBitmapRegionDecoder* create_brd(Path path) {
bungeman38d909e2016-08-02 14:40:46 -0700103 sk_sp<SkData> encoded(SkData::MakeFromFileName(path.c_str()));
msaretta5783ae2015-09-08 15:35:32 -0700104 if (!encoded) {
105 return NULL;
106 }
reed42943c82016-09-12 12:01:44 -0700107 return SkBitmapRegionDecoder::Create(encoded, SkBitmapRegionDecoder::kAndroidCodec_Strategy);
msaretta5783ae2015-09-08 15:35:32 -0700108}
109
110Error BRDSrc::draw(SkCanvas* canvas) const {
111 SkColorType colorType = canvas->imageInfo().colorType();
112 if (kRGB_565_SkColorType == colorType &&
113 CodecSrc::kGetFromCanvas_DstColorType != fDstColorType) {
114 return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
115 }
116 switch (fDstColorType) {
117 case CodecSrc::kGetFromCanvas_DstColorType:
118 break;
119 case CodecSrc::kIndex8_Always_DstColorType:
120 colorType = kIndex_8_SkColorType;
121 break;
122 case CodecSrc::kGrayscale_Always_DstColorType:
123 colorType = kGray_8_SkColorType;
124 break;
msarett34e0ec42016-04-22 16:27:24 -0700125 default:
126 SkASSERT(false);
127 break;
msaretta5783ae2015-09-08 15:35:32 -0700128 }
129
msarettd1227a72016-05-18 06:23:57 -0700130 SkAutoTDelete<SkBitmapRegionDecoder> brd(create_brd(fPath));
msaretta5783ae2015-09-08 15:35:32 -0700131 if (nullptr == brd.get()) {
132 return Error::Nonfatal(SkStringPrintf("Could not create brd for %s.", fPath.c_str()));
133 }
134
msarett04965c62015-10-12 10:24:38 -0700135 if (!brd->conversionSupported(colorType)) {
mtklein9b439152015-12-09 13:02:26 -0800136 return Error::Nonfatal("Cannot convert to color type.");
msarett04965c62015-10-12 10:24:38 -0700137 }
138
msaretta5783ae2015-09-08 15:35:32 -0700139 const uint32_t width = brd->width();
140 const uint32_t height = brd->height();
141 // Visually inspecting very small output images is not necessary.
142 if ((width / fSampleSize <= 10 || height / fSampleSize <= 10) && 1 != fSampleSize) {
143 return Error::Nonfatal("Scaling very small images is uninteresting.");
144 }
145 switch (fMode) {
146 case kFullImage_Mode: {
msarett35e5d1b2015-10-27 12:50:25 -0700147 SkBitmap bitmap;
148 if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(0, 0, width, height),
149 fSampleSize, colorType, false)) {
mtklein9b439152015-12-09 13:02:26 -0800150 return "Cannot decode (full) region.";
msarett35e5d1b2015-10-27 12:50:25 -0700151 }
152 if (colorType != bitmap.colorType()) {
mtklein9b439152015-12-09 13:02:26 -0800153 return Error::Nonfatal("Cannot convert to color type.");
msaretta5783ae2015-09-08 15:35:32 -0700154 }
msarett35e5d1b2015-10-27 12:50:25 -0700155 canvas->drawBitmap(bitmap, 0, 0);
msaretta5783ae2015-09-08 15:35:32 -0700156 return "";
157 }
158 case kDivisor_Mode: {
159 const uint32_t divisor = 2;
160 if (width < divisor || height < divisor) {
mtklein9b439152015-12-09 13:02:26 -0800161 return Error::Nonfatal("Divisor is larger than image dimension.");
msaretta5783ae2015-09-08 15:35:32 -0700162 }
163
164 // Use a border to test subsets that extend outside the image.
165 // We will not allow the border to be larger than the image dimensions. Allowing
166 // these large borders causes off by one errors that indicate a problem with the
167 // test suite, not a problem with the implementation.
168 const uint32_t maxBorder = SkTMin(width, height) / (fSampleSize * divisor);
169 const uint32_t scaledBorder = SkTMin(5u, maxBorder);
170 const uint32_t unscaledBorder = scaledBorder * fSampleSize;
171
172 // We may need to clear the canvas to avoid uninitialized memory.
173 // Assume we are scaling a 780x780 image with sampleSize = 8.
174 // The output image should be 97x97.
175 // Each subset will be 390x390.
176 // Each scaled subset be 48x48.
177 // Four scaled subsets will only fill a 96x96 image.
178 // The bottom row and last column will not be touched.
179 // This is an unfortunate result of our rounding rules when scaling.
180 // Maybe we need to consider testing scaled subsets without trying to
181 // combine them to match the full scaled image? Or maybe this is the
182 // best we can do?
183 canvas->clear(0);
184
185 for (uint32_t x = 0; x < divisor; x++) {
186 for (uint32_t y = 0; y < divisor; y++) {
187 // Calculate the subset dimensions
188 uint32_t subsetWidth = width / divisor;
189 uint32_t subsetHeight = height / divisor;
190 const int left = x * subsetWidth;
191 const int top = y * subsetHeight;
192
193 // Increase the size of the last subset in each row or column, when the
194 // divisor does not divide evenly into the image dimensions
195 subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0;
196 subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0;
197
198 // Increase the size of the subset in order to have a border on each side
199 const int decodeLeft = left - unscaledBorder;
200 const int decodeTop = top - unscaledBorder;
201 const uint32_t decodeWidth = subsetWidth + unscaledBorder * 2;
202 const uint32_t decodeHeight = subsetHeight + unscaledBorder * 2;
msarett35e5d1b2015-10-27 12:50:25 -0700203 SkBitmap bitmap;
204 if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(decodeLeft,
205 decodeTop, decodeWidth, decodeHeight), fSampleSize, colorType, false)) {
mtklein9b439152015-12-09 13:02:26 -0800206 return "Cannot decode region.";
msarett35e5d1b2015-10-27 12:50:25 -0700207 }
208 if (colorType != bitmap.colorType()) {
mtklein9b439152015-12-09 13:02:26 -0800209 return Error::Nonfatal("Cannot convert to color type.");
msaretta5783ae2015-09-08 15:35:32 -0700210 }
211
msarett35e5d1b2015-10-27 12:50:25 -0700212 canvas->drawBitmapRect(bitmap,
msaretta5783ae2015-09-08 15:35:32 -0700213 SkRect::MakeXYWH((SkScalar) scaledBorder, (SkScalar) scaledBorder,
214 (SkScalar) (subsetWidth / fSampleSize),
215 (SkScalar) (subsetHeight / fSampleSize)),
216 SkRect::MakeXYWH((SkScalar) (left / fSampleSize),
217 (SkScalar) (top / fSampleSize),
218 (SkScalar) (subsetWidth / fSampleSize),
219 (SkScalar) (subsetHeight / fSampleSize)),
220 nullptr);
221 }
222 }
223 return "";
224 }
225 default:
226 SkASSERT(false);
mtklein9b439152015-12-09 13:02:26 -0800227 return "Error: Should not be reached.";
msaretta5783ae2015-09-08 15:35:32 -0700228 }
229}
230
231SkISize BRDSrc::size() const {
msarettd1227a72016-05-18 06:23:57 -0700232 SkAutoTDelete<SkBitmapRegionDecoder> brd(create_brd(fPath));
msaretta5783ae2015-09-08 15:35:32 -0700233 if (brd) {
234 return SkISize::Make(SkTMax(1, brd->width() / (int) fSampleSize),
235 SkTMax(1, brd->height() / (int) fSampleSize));
236 }
237 return SkISize::Make(0, 0);
238}
239
240static SkString get_scaled_name(const Path& path, float scale) {
241 return SkStringPrintf("%s_%.3f", SkOSPath::Basename(path.c_str()).c_str(), scale);
242}
243
244Name BRDSrc::name() const {
245 // We will replicate the names used by CodecSrc so that images can
246 // be compared in Gold.
247 if (1 == fSampleSize) {
248 return SkOSPath::Basename(fPath.c_str());
249 }
msarett4b0778e2015-11-13 09:59:11 -0800250 return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
msaretta5783ae2015-09-08 15:35:32 -0700251}
252
253/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
254
scroggo3ac66e92016-02-08 15:09:48 -0800255static bool serial_from_path_name(const SkString& path) {
256 if (!FLAGS_RAW_threading) {
257 static const char* const exts[] = {
258 "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw",
259 "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW",
260 };
261 const char* actualExt = strrchr(path.c_str(), '.');
262 if (actualExt) {
263 actualExt++;
264 for (auto* ext : exts) {
265 if (0 == strcmp(ext, actualExt)) {
266 return true;
267 }
268 }
269 }
270 }
271 return false;
272}
273
scroggoc5560be2016-02-03 09:42:42 -0800274CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, SkAlphaType dstAlphaType,
275 float scale)
msarett438b2ad2015-04-09 12:43:10 -0700276 : fPath(path)
277 , fMode(mode)
278 , fDstColorType(dstColorType)
scroggoc5560be2016-02-03 09:42:42 -0800279 , fDstAlphaType(dstAlphaType)
msarett0a242972015-06-11 14:27:27 -0700280 , fScale(scale)
scroggo3ac66e92016-02-08 15:09:48 -0800281 , fRunSerially(serial_from_path_name(path))
msarett438b2ad2015-04-09 12:43:10 -0700282{}
mtklein748ca3b2015-01-15 10:56:12 -0800283
mtklein99cab4e2015-07-31 06:43:04 -0700284bool CodecSrc::veto(SinkFlags flags) const {
msarett18976312016-03-09 14:20:58 -0800285 // Test to direct raster backends (8888 and 565).
msarettb714fb02016-01-22 14:46:42 -0800286 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
mtkleine0effd62015-07-29 06:37:28 -0700287}
scroggo9b77ddd2015-03-19 06:03:39 -0700288
msarett34e0ec42016-04-22 16:27:24 -0700289// Allows us to test decodes to non-native 8888.
msarettb1be46b2016-05-17 08:52:11 -0700290static void swap_rb_if_necessary(SkBitmap& bitmap, CodecSrc::DstColorType dstColorType) {
msarett34e0ec42016-04-22 16:27:24 -0700291 if (CodecSrc::kNonNative8888_Always_DstColorType != dstColorType) {
292 return;
293 }
294
295 for (int y = 0; y < bitmap.height(); y++) {
296 uint32_t* row = (uint32_t*) bitmap.getAddr(0, y);
297 SkOpts::RGBA_to_BGRA(row, row, bitmap.width());
298 }
299}
300
msarett9e9444c2016-02-03 12:39:10 -0800301// FIXME: Currently we cannot draw unpremultiplied sources. skbug.com/3338 and skbug.com/3339.
302// This allows us to still test unpremultiplied decodes.
msarettb1be46b2016-05-17 08:52:11 -0700303static void premultiply_if_necessary(SkBitmap& bitmap) {
msarett9e9444c2016-02-03 12:39:10 -0800304 if (kUnpremul_SkAlphaType != bitmap.alphaType()) {
305 return;
306 }
307
308 switch (bitmap.colorType()) {
309 case kN32_SkColorType:
310 for (int y = 0; y < bitmap.height(); y++) {
311 uint32_t* row = (uint32_t*) bitmap.getAddr(0, y);
312 SkOpts::RGBA_to_rgbA(row, row, bitmap.width());
313 }
314 break;
315 case kIndex_8_SkColorType: {
316 SkColorTable* colorTable = bitmap.getColorTable();
317 SkPMColor* colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
318 SkOpts::RGBA_to_rgbA(colorPtr, colorPtr, colorTable->count());
319 break;
320 }
321 default:
322 // No need to premultiply kGray or k565 outputs.
323 break;
324 }
msarette1daa482016-02-03 15:31:18 -0800325
326 // In the kIndex_8 case, the canvas won't even try to draw unless we mark the
327 // bitmap as kPremul.
328 bitmap.setAlphaType(kPremul_SkAlphaType);
msarett9e9444c2016-02-03 12:39:10 -0800329}
330
msarettb1be46b2016-05-17 08:52:11 -0700331static bool get_decode_info(SkImageInfo* decodeInfo, SkColorType canvasColorType,
scroggoba584892016-05-20 13:56:13 -0700332 CodecSrc::DstColorType dstColorType, SkAlphaType dstAlphaType) {
msarett3d9d7a72015-10-21 10:27:10 -0700333 switch (dstColorType) {
334 case CodecSrc::kIndex8_Always_DstColorType:
335 if (kRGB_565_SkColorType == canvasColorType) {
336 return false;
337 }
scroggoc5560be2016-02-03 09:42:42 -0800338 *decodeInfo = decodeInfo->makeColorType(kIndex_8_SkColorType);
msarett3d9d7a72015-10-21 10:27:10 -0700339 break;
340 case CodecSrc::kGrayscale_Always_DstColorType:
scroggo1a361922016-05-20 14:27:16 -0700341 if (kRGB_565_SkColorType == canvasColorType) {
msarett3d9d7a72015-10-21 10:27:10 -0700342 return false;
343 }
scroggoc5560be2016-02-03 09:42:42 -0800344 *decodeInfo = decodeInfo->makeColorType(kGray_8_SkColorType);
msarett3d9d7a72015-10-21 10:27:10 -0700345 break;
msarett34e0ec42016-04-22 16:27:24 -0700346 case CodecSrc::kNonNative8888_Always_DstColorType:
347 if (kRGB_565_SkColorType == canvasColorType) {
348 return false;
349 }
350#ifdef SK_PMCOLOR_IS_RGBA
351 *decodeInfo = decodeInfo->makeColorType(kBGRA_8888_SkColorType);
352#else
353 *decodeInfo = decodeInfo->makeColorType(kRGBA_8888_SkColorType);
354#endif
355 break;
msarett3d9d7a72015-10-21 10:27:10 -0700356 default:
msarett55f7bdd2016-02-16 13:24:54 -0800357 if (kRGB_565_SkColorType == canvasColorType &&
358 kOpaque_SkAlphaType != decodeInfo->alphaType()) {
359 return false;
360 }
scroggoc5560be2016-02-03 09:42:42 -0800361 *decodeInfo = decodeInfo->makeColorType(canvasColorType);
msarett3d9d7a72015-10-21 10:27:10 -0700362 break;
363 }
364
scroggoba584892016-05-20 13:56:13 -0700365 *decodeInfo = decodeInfo->makeAlphaType(dstAlphaType);
msarett3d9d7a72015-10-21 10:27:10 -0700366 return true;
367}
368
msarettb1be46b2016-05-17 08:52:11 -0700369static void draw_to_canvas(SkCanvas* canvas, const SkImageInfo& info, void* pixels, size_t rowBytes,
370 SkPMColor* colorPtr, int colorCount, CodecSrc::DstColorType dstColorType,
371 SkScalar left = 0, SkScalar top = 0) {
372 SkAutoTUnref<SkColorTable> colorTable(new SkColorTable(colorPtr, colorCount));
373 SkBitmap bitmap;
374 bitmap.installPixels(info, pixels, rowBytes, colorTable.get(), nullptr, nullptr);
375 premultiply_if_necessary(bitmap);
376 swap_rb_if_necessary(bitmap, dstColorType);
377 canvas->drawBitmap(bitmap, left, top);
378}
379
mtkleine0effd62015-07-29 06:37:28 -0700380Error CodecSrc::draw(SkCanvas* canvas) const {
bungeman38d909e2016-08-02 14:40:46 -0700381 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
mtklein748ca3b2015-01-15 10:56:12 -0800382 if (!encoded) {
383 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
384 }
msarettb714fb02016-01-22 14:46:42 -0800385
reed42943c82016-09-12 12:01:44 -0700386 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
msarett9e707a02015-09-01 14:57:57 -0700387 if (nullptr == codec.get()) {
388 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
scroggo9b77ddd2015-03-19 06:03:39 -0700389 }
390
scroggoba584892016-05-20 13:56:13 -0700391 SkImageInfo decodeInfo = codec->getInfo();
392 if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType,
393 fDstAlphaType)) {
msarett3d9d7a72015-10-21 10:27:10 -0700394 return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
msarett438b2ad2015-04-09 12:43:10 -0700395 }
396
msarett0a242972015-06-11 14:27:27 -0700397 // Try to scale the image if it is desired
398 SkISize size = codec->getScaledDimensions(fScale);
399 if (size == decodeInfo.dimensions() && 1.0f != fScale) {
400 return Error::Nonfatal("Test without scaling is uninteresting.");
401 }
msarettb32758a2015-08-18 13:22:46 -0700402
403 // Visually inspecting very small output images is not necessary. We will
404 // cover these cases in unit testing.
405 if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) {
406 return Error::Nonfatal("Scaling very small images is uninteresting.");
407 }
msarett0a242972015-06-11 14:27:27 -0700408 decodeInfo = decodeInfo.makeWH(size.width(), size.height());
409
msarettb1be46b2016-05-17 08:52:11 -0700410 const int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType());
411 const size_t rowBytes = size.width() * bpp;
412 SkAutoMalloc pixels(decodeInfo.getSafeSize(rowBytes));
413 SkPMColor colorPtr[256];
414 int colorCount = 256;
msarett438b2ad2015-04-09 12:43:10 -0700415
msarettbb25b532016-01-13 09:31:39 -0800416 SkCodec::Options options;
417 if (kCodecZeroInit_Mode == fMode) {
msarettb1be46b2016-05-17 08:52:11 -0700418 memset(pixels.get(), 0, size.height() * rowBytes);
msarettbb25b532016-01-13 09:31:39 -0800419 options.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
420 }
msarett34e0ec42016-04-22 16:27:24 -0700421
422 SkImageInfo bitmapInfo = decodeInfo;
423 if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
424 kBGRA_8888_SkColorType == decodeInfo.colorType()) {
425 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
426 }
scroggo9b77ddd2015-03-19 06:03:39 -0700427
scroggo9c59ebc2015-03-25 13:48:49 -0700428 switch (fMode) {
msarettbb25b532016-01-13 09:31:39 -0800429 case kCodecZeroInit_Mode:
msarett9e707a02015-09-01 14:57:57 -0700430 case kCodec_Mode: {
msarettb1be46b2016-05-17 08:52:11 -0700431 switch (codec->getPixels(decodeInfo, pixels.get(), rowBytes, &options,
432 colorPtr, &colorCount)) {
scroggoeb602a52015-07-09 08:16:03 -0700433 case SkCodec::kSuccess:
scroggo9c59ebc2015-03-25 13:48:49 -0700434 // We consider incomplete to be valid, since we should still decode what is
435 // available.
scroggoeb602a52015-07-09 08:16:03 -0700436 case SkCodec::kIncompleteInput:
scroggo9c59ebc2015-03-25 13:48:49 -0700437 break;
scroggo9c59ebc2015-03-25 13:48:49 -0700438 default:
439 // Everything else is considered a failure.
440 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
441 }
msarettb1be46b2016-05-17 08:52:11 -0700442
443 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr, colorCount,
444 fDstColorType);
scroggo9c59ebc2015-03-25 13:48:49 -0700445 break;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700446 }
scroggo9c59ebc2015-03-25 13:48:49 -0700447 case kScanline_Mode: {
scroggod8d68552016-06-06 11:26:17 -0700448 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr,
449 &colorCount)) {
450 return "Could not start scanline decoder";
scroggo6fb23912016-06-02 14:16:43 -0700451 }
452
scroggod8d68552016-06-06 11:26:17 -0700453 void* dst = pixels.get();
454 uint32_t height = decodeInfo.height();
455 switch (codec->getScanlineOrder()) {
456 case SkCodec::kTopDown_SkScanlineOrder:
457 case SkCodec::kBottomUp_SkScanlineOrder:
458 case SkCodec::kNone_SkScanlineOrder:
459 // We do not need to check the return value. On an incomplete
460 // image, memory will be filled with a default value.
461 codec->getScanlines(dst, height, rowBytes);
462 break;
463 case SkCodec::kOutOfOrder_SkScanlineOrder: {
464 for (int y = 0; y < decodeInfo.height(); y++) {
465 int dstY = codec->outputScanline(y);
466 void* dstPtr = SkTAddOffset<void>(dst, rowBytes * dstY);
467 // We complete the loop, even if this call begins to fail
468 // due to an incomplete image. This ensures any uninitialized
469 // memory will be filled with the proper value.
470 codec->getScanlines(dstPtr, 1, rowBytes);
scroggo6fb23912016-06-02 14:16:43 -0700471 }
scroggod8d68552016-06-06 11:26:17 -0700472 break;
msarett10522ff2015-09-07 08:54:01 -0700473 }
474 }
475
msarettb1be46b2016-05-17 08:52:11 -0700476 draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, colorPtr, colorCount, fDstColorType);
emmaleer97002062015-05-27 12:36:10 -0700477 break;
478 }
msarett0a242972015-06-11 14:27:27 -0700479 case kStripe_Mode: {
480 const int height = decodeInfo.height();
481 // This value is chosen arbitrarily. We exercise more cases by choosing a value that
482 // does not align with image blocks.
483 const int stripeHeight = 37;
484 const int numStripes = (height + stripeHeight - 1) / stripeHeight;
msarettb1be46b2016-05-17 08:52:11 -0700485 void* dst = pixels.get();
msarett0a242972015-06-11 14:27:27 -0700486
487 // Decode odd stripes
msarettb1be46b2016-05-17 08:52:11 -0700488 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, nullptr, colorPtr,
489 &colorCount)) {
msarettb65e6042016-02-23 05:37:25 -0800490 return "Could not start scanline decoder";
491 }
492
493 // This mode was designed to test the new skip scanlines API in libjpeg-turbo.
494 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting
495 // to run this test for image types that do not have this scanline ordering.
scroggo12e2f502016-05-16 09:04:18 -0700496 // We only run this on Jpeg, which is always kTopDown.
497 SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder());
msarette6dd0042015-10-09 11:07:34 -0700498
msarett0a242972015-06-11 14:27:27 -0700499 for (int i = 0; i < numStripes; i += 2) {
500 // Skip a stripe
501 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight);
msarette6dd0042015-10-09 11:07:34 -0700502 codec->skipScanlines(linesToSkip);
msarett0a242972015-06-11 14:27:27 -0700503
504 // Read a stripe
505 const int startY = (i + 1) * stripeHeight;
506 const int linesToRead = SkTMin(stripeHeight, height - startY);
507 if (linesToRead > 0) {
msarettb1be46b2016-05-17 08:52:11 -0700508 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead,
509 rowBytes);
msarett0a242972015-06-11 14:27:27 -0700510 }
511 }
512
513 // Decode even stripes
scroggo46c57472015-09-30 08:57:13 -0700514 const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo, nullptr,
msarettb1be46b2016-05-17 08:52:11 -0700515 colorPtr, &colorCount);
scroggo1c005e42015-08-04 09:24:45 -0700516 if (SkCodec::kSuccess != startResult) {
517 return "Failed to restart scanline decoder with same parameters.";
msarett0a242972015-06-11 14:27:27 -0700518 }
519 for (int i = 0; i < numStripes; i += 2) {
520 // Read a stripe
521 const int startY = i * stripeHeight;
522 const int linesToRead = SkTMin(stripeHeight, height - startY);
msarettb1be46b2016-05-17 08:52:11 -0700523 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead,
524 rowBytes);
msarett0a242972015-06-11 14:27:27 -0700525
526 // Skip a stripe
msarettf6db27e2015-06-12 09:34:04 -0700527 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight);
528 if (linesToSkip > 0) {
msarette6dd0042015-10-09 11:07:34 -0700529 codec->skipScanlines(linesToSkip);
msarett0a242972015-06-11 14:27:27 -0700530 }
531 }
msarettb1be46b2016-05-17 08:52:11 -0700532
533 draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, colorPtr, colorCount, fDstColorType);
emmaleer0a4c3cb2015-06-22 10:40:21 -0700534 break;
msarett0a242972015-06-11 14:27:27 -0700535 }
msarett91c22b22016-02-22 12:27:46 -0800536 case kCroppedScanline_Mode: {
537 const int width = decodeInfo.width();
538 const int height = decodeInfo.height();
539 // This value is chosen because, as we move across the image, it will sometimes
540 // align with the jpeg block sizes and it will sometimes not. This allows us
541 // to test interestingly different code paths in the implementation.
542 const int tileSize = 36;
543
544 SkCodec::Options opts;
545 SkIRect subset;
546 for (int x = 0; x < width; x += tileSize) {
547 subset = SkIRect::MakeXYWH(x, 0, SkTMin(tileSize, width - x), height);
548 opts.fSubset = &subset;
549 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &opts,
msarettb1be46b2016-05-17 08:52:11 -0700550 colorPtr, &colorCount)) {
msarett91c22b22016-02-22 12:27:46 -0800551 return "Could not start scanline decoder.";
552 }
553
msarettb1be46b2016-05-17 08:52:11 -0700554 codec->getScanlines(SkTAddOffset<void>(pixels.get(), x * bpp), height, rowBytes);
msarett91c22b22016-02-22 12:27:46 -0800555 }
556
msarettb1be46b2016-05-17 08:52:11 -0700557 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr, colorCount,
558 fDstColorType);
msarett91c22b22016-02-22 12:27:46 -0800559 break;
560 }
scroggob636b452015-07-22 07:16:20 -0700561 case kSubset_Mode: {
562 // Arbitrarily choose a divisor.
563 int divisor = 2;
564 // Total width/height of the image.
565 const int W = codec->getInfo().width();
566 const int H = codec->getInfo().height();
567 if (divisor > W || divisor > H) {
568 return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divisor %d is too big "
569 "for %s with dimensions (%d x %d)", divisor,
570 fPath.c_str(), W, H));
571 }
572 // subset dimensions
573 // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
574 const int w = SkAlign2(W / divisor);
575 const int h = SkAlign2(H / divisor);
576 SkIRect subset;
577 SkCodec::Options opts;
578 opts.fSubset = &subset;
579 SkBitmap subsetBm;
580 // We will reuse pixel memory from bitmap.
msarettb1be46b2016-05-17 08:52:11 -0700581 void* dst = pixels.get();
scroggob636b452015-07-22 07:16:20 -0700582 // Keep track of left and top (for drawing subsetBm into canvas). We could use
583 // fScale * x and fScale * y, but we want integers such that the next subset will start
584 // where the last one ended. So we'll add decodeInfo.width() and height().
585 int left = 0;
586 for (int x = 0; x < W; x += w) {
587 int top = 0;
588 for (int y = 0; y < H; y+= h) {
589 // Do not make the subset go off the edge of the image.
590 const int preScaleW = SkTMin(w, W - x);
591 const int preScaleH = SkTMin(h, H - y);
592 subset.setXYWH(x, y, preScaleW, preScaleH);
593 // And scale
594 // FIXME: Should we have a version of getScaledDimensions that takes a subset
595 // into account?
msarettc7eb4902016-04-25 07:04:58 -0700596 const int scaledW = SkTMax(1, SkScalarRoundToInt(preScaleW * fScale));
597 const int scaledH = SkTMax(1, SkScalarRoundToInt(preScaleH * fScale));
598 decodeInfo = decodeInfo.makeWH(scaledW, scaledH);
599 SkImageInfo subsetBitmapInfo = bitmapInfo.makeWH(scaledW, scaledH);
msarettb1be46b2016-05-17 08:52:11 -0700600 size_t subsetRowBytes = subsetBitmapInfo.minRowBytes();
601 const SkCodec::Result result = codec->getPixels(decodeInfo, dst, subsetRowBytes,
602 &opts, colorPtr, &colorCount);
scroggob636b452015-07-22 07:16:20 -0700603 switch (result) {
604 case SkCodec::kSuccess:
605 case SkCodec::kIncompleteInput:
606 break;
scroggob636b452015-07-22 07:16:20 -0700607 default:
608 return SkStringPrintf("subset codec failed to decode (%d, %d, %d, %d) "
609 "from %s with dimensions (%d x %d)\t error %d",
610 x, y, decodeInfo.width(), decodeInfo.height(),
611 fPath.c_str(), W, H, result);
612 }
msarettb1be46b2016-05-17 08:52:11 -0700613 draw_to_canvas(canvas, subsetBitmapInfo, dst, subsetRowBytes, colorPtr,
614 colorCount, fDstColorType, SkIntToScalar(left),
615 SkIntToScalar(top));
616
scroggob636b452015-07-22 07:16:20 -0700617 // translate by the scaled height.
618 top += decodeInfo.height();
619 }
620 // translate by the scaled width.
621 left += decodeInfo.width();
622 }
623 return "";
624 }
msarettb714fb02016-01-22 14:46:42 -0800625 default:
626 SkASSERT(false);
627 return "Invalid fMode";
scroggo9b77ddd2015-03-19 06:03:39 -0700628 }
scroggo9c59ebc2015-03-25 13:48:49 -0700629 return "";
scroggo9b77ddd2015-03-19 06:03:39 -0700630}
631
632SkISize CodecSrc::size() const {
bungeman38d909e2016-08-02 14:40:46 -0700633 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
reed42943c82016-09-12 12:01:44 -0700634 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
scroggo7fac5af2015-09-30 11:33:12 -0700635 if (nullptr == codec) {
636 return SkISize::Make(0, 0);
637 }
638 return codec->getScaledDimensions(fScale);
scroggo9b77ddd2015-03-19 06:03:39 -0700639}
640
641Name CodecSrc::name() const {
msarett0a242972015-06-11 14:27:27 -0700642 if (1.0f == fScale) {
643 return SkOSPath::Basename(fPath.c_str());
msarett0a242972015-06-11 14:27:27 -0700644 }
msaretta5783ae2015-09-08 15:35:32 -0700645 return get_scaled_name(fPath, fScale);
scroggo9b77ddd2015-03-19 06:03:39 -0700646}
647
648/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
649
scroggof8dc9df2016-05-16 09:04:13 -0700650AndroidCodecSrc::AndroidCodecSrc(Path path, CodecSrc::DstColorType dstColorType,
scroggoc5560be2016-02-03 09:42:42 -0800651 SkAlphaType dstAlphaType, int sampleSize)
msarett3d9d7a72015-10-21 10:27:10 -0700652 : fPath(path)
msarett3d9d7a72015-10-21 10:27:10 -0700653 , fDstColorType(dstColorType)
scroggoc5560be2016-02-03 09:42:42 -0800654 , fDstAlphaType(dstAlphaType)
msarett3d9d7a72015-10-21 10:27:10 -0700655 , fSampleSize(sampleSize)
scroggo3ac66e92016-02-08 15:09:48 -0800656 , fRunSerially(serial_from_path_name(path))
msarett3d9d7a72015-10-21 10:27:10 -0700657{}
658
659bool AndroidCodecSrc::veto(SinkFlags flags) const {
660 // No need to test decoding to non-raster or indirect backend.
msarett3d9d7a72015-10-21 10:27:10 -0700661 return flags.type != SinkFlags::kRaster
662 || flags.approach != SinkFlags::kDirect;
663}
664
665Error AndroidCodecSrc::draw(SkCanvas* canvas) const {
bungeman38d909e2016-08-02 14:40:46 -0700666 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
msarett3d9d7a72015-10-21 10:27:10 -0700667 if (!encoded) {
668 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
669 }
reed42943c82016-09-12 12:01:44 -0700670 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded));
msarett3d9d7a72015-10-21 10:27:10 -0700671 if (nullptr == codec.get()) {
672 return SkStringPrintf("Couldn't create android codec for %s.", fPath.c_str());
673 }
674
scroggoba584892016-05-20 13:56:13 -0700675 SkImageInfo decodeInfo = codec->getInfo();
676 if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType,
677 fDstAlphaType)) {
msarett3d9d7a72015-10-21 10:27:10 -0700678 return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
679 }
680
681 // Scale the image if it is desired.
682 SkISize size = codec->getSampledDimensions(fSampleSize);
683
684 // Visually inspecting very small output images is not necessary. We will
685 // cover these cases in unit testing.
686 if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) {
687 return Error::Nonfatal("Scaling very small images is uninteresting.");
688 }
689 decodeInfo = decodeInfo.makeWH(size.width(), size.height());
690
msarettb1be46b2016-05-17 08:52:11 -0700691 int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType());
692 size_t rowBytes = size.width() * bpp;
693 SkAutoMalloc pixels(size.height() * rowBytes);
694 SkPMColor colorPtr[256];
695 int colorCount = 256;
msarett3d9d7a72015-10-21 10:27:10 -0700696
697 SkBitmap bitmap;
msarett34e0ec42016-04-22 16:27:24 -0700698 SkImageInfo bitmapInfo = decodeInfo;
699 if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
700 kBGRA_8888_SkColorType == decodeInfo.colorType()) {
701 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
702 }
msarett3d9d7a72015-10-21 10:27:10 -0700703
704 // Create options for the codec.
705 SkAndroidCodec::AndroidOptions options;
706 options.fColorPtr = colorPtr;
msarettb1be46b2016-05-17 08:52:11 -0700707 options.fColorCount = &colorCount;
msarett3d9d7a72015-10-21 10:27:10 -0700708 options.fSampleSize = fSampleSize;
709
msarettb1be46b2016-05-17 08:52:11 -0700710 switch (codec->getAndroidPixels(decodeInfo, pixels.get(), rowBytes, &options)) {
scroggof8dc9df2016-05-16 09:04:13 -0700711 case SkCodec::kSuccess:
712 case SkCodec::kIncompleteInput:
713 break;
msarett3d9d7a72015-10-21 10:27:10 -0700714 default:
scroggof8dc9df2016-05-16 09:04:13 -0700715 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
msarett3d9d7a72015-10-21 10:27:10 -0700716 }
msarettb1be46b2016-05-17 08:52:11 -0700717 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr, colorCount, fDstColorType);
scroggof8dc9df2016-05-16 09:04:13 -0700718 return "";
msarett3d9d7a72015-10-21 10:27:10 -0700719}
720
721SkISize AndroidCodecSrc::size() const {
bungeman38d909e2016-08-02 14:40:46 -0700722 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
reed42943c82016-09-12 12:01:44 -0700723 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded));
msarett3d9d7a72015-10-21 10:27:10 -0700724 if (nullptr == codec) {
725 return SkISize::Make(0, 0);
726 }
727 return codec->getSampledDimensions(fSampleSize);
728}
729
730Name AndroidCodecSrc::name() const {
731 // We will replicate the names used by CodecSrc so that images can
732 // be compared in Gold.
733 if (1 == fSampleSize) {
734 return SkOSPath::Basename(fPath.c_str());
735 }
msarett4b0778e2015-11-13 09:59:11 -0800736 return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
msarett3d9d7a72015-10-21 10:27:10 -0700737}
738
739/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
740
msarett18976312016-03-09 14:20:58 -0800741ImageGenSrc::ImageGenSrc(Path path, Mode mode, SkAlphaType alphaType, bool isGpu)
742 : fPath(path)
743 , fMode(mode)
744 , fDstAlphaType(alphaType)
745 , fIsGpu(isGpu)
746 , fRunSerially(serial_from_path_name(path))
747{}
748
749bool ImageGenSrc::veto(SinkFlags flags) const {
750 if (fIsGpu) {
751 return flags.type != SinkFlags::kGPU || flags.approach != SinkFlags::kDirect;
752 }
753
754 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
755}
756
757Error ImageGenSrc::draw(SkCanvas* canvas) const {
758 if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) {
759 return Error::Nonfatal("Uninteresting to test image generator to 565.");
760 }
761
bungeman38d909e2016-08-02 14:40:46 -0700762 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
msarett18976312016-03-09 14:20:58 -0800763 if (!encoded) {
764 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
765 }
766
msarettfc0b6d12016-03-17 13:50:17 -0700767#if defined(SK_BUILD_FOR_WIN)
768 // Initialize COM in order to test with WIC.
769 SkAutoCoInitialize com;
770 if (!com.succeeded()) {
771 return "Could not initialize COM.";
772 }
773#endif
774
msarett18976312016-03-09 14:20:58 -0800775 SkAutoTDelete<SkImageGenerator> gen(nullptr);
776 switch (fMode) {
777 case kCodec_Mode:
bungeman38d909e2016-08-02 14:40:46 -0700778 gen.reset(SkCodecImageGenerator::NewFromEncodedCodec(encoded.get()));
msarett18976312016-03-09 14:20:58 -0800779 if (!gen) {
780 return "Could not create codec image generator.";
781 }
782 break;
msarettfc0b6d12016-03-17 13:50:17 -0700783 case kPlatform_Mode: {
msarett18976312016-03-09 14:20:58 -0800784#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
bungeman38d909e2016-08-02 14:40:46 -0700785 gen.reset(SkImageGeneratorCG::NewFromEncodedCG(encoded.get()));
msarettfc0b6d12016-03-17 13:50:17 -0700786#elif defined(SK_BUILD_FOR_WIN)
bungeman38d909e2016-08-02 14:40:46 -0700787 gen.reset(SkImageGeneratorWIC::NewFromEncodedWIC(encoded.get()));
msarettfc0b6d12016-03-17 13:50:17 -0700788#endif
789
msarett18976312016-03-09 14:20:58 -0800790 if (!gen) {
msarettfc0b6d12016-03-17 13:50:17 -0700791 return "Could not create platform image generator.";
msarett18976312016-03-09 14:20:58 -0800792 }
793 break;
msarettfc0b6d12016-03-17 13:50:17 -0700794 }
msarett18976312016-03-09 14:20:58 -0800795 default:
796 SkASSERT(false);
797 return "Invalid image generator mode";
798 }
799
800 // Test deferred decoding path on GPU
801 if (fIsGpu) {
reed9ce9d672016-03-17 10:51:11 -0700802 sk_sp<SkImage> image(SkImage::MakeFromGenerator(gen.release(), nullptr));
msarett18976312016-03-09 14:20:58 -0800803 if (!image) {
804 return "Could not create image from codec image generator.";
805 }
806 canvas->drawImage(image, 0, 0);
807 return "";
808 }
mtklein343a63d2016-03-22 11:46:53 -0700809
msarett18976312016-03-09 14:20:58 -0800810 // Test various color and alpha types on CPU
811 SkImageInfo decodeInfo = gen->getInfo().makeAlphaType(fDstAlphaType);
mtklein343a63d2016-03-22 11:46:53 -0700812
msarettb1be46b2016-05-17 08:52:11 -0700813 int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType());
814 size_t rowBytes = decodeInfo.width() * bpp;
815 SkAutoMalloc pixels(decodeInfo.height() * rowBytes);
816 SkPMColor colorPtr[256];
817 int colorCount = 256;
msarett18976312016-03-09 14:20:58 -0800818
msarettb1be46b2016-05-17 08:52:11 -0700819 if (!gen->getPixels(decodeInfo, pixels.get(), rowBytes, colorPtr, &colorCount)) {
msarett18976312016-03-09 14:20:58 -0800820 return SkStringPrintf("Image generator could not getPixels() for %s\n", fPath.c_str());
821 }
822
msarettb1be46b2016-05-17 08:52:11 -0700823 draw_to_canvas(canvas, decodeInfo, pixels.get(), rowBytes, colorPtr, colorCount,
824 CodecSrc::kGetFromCanvas_DstColorType);
msarett18976312016-03-09 14:20:58 -0800825 return "";
826}
827
828SkISize ImageGenSrc::size() const {
bungeman38d909e2016-08-02 14:40:46 -0700829 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
reed42943c82016-09-12 12:01:44 -0700830 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
msarett18976312016-03-09 14:20:58 -0800831 if (nullptr == codec) {
832 return SkISize::Make(0, 0);
833 }
834 return codec->getInfo().dimensions();
835}
836
837Name ImageGenSrc::name() const {
838 return SkOSPath::Basename(fPath.c_str());
839}
840
841/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
842
msarett9ce3a542016-07-15 13:54:38 -0700843ColorCodecSrc::ColorCodecSrc(Path path, Mode mode, SkColorType colorType)
msarett69deca82016-04-29 09:38:40 -0700844 : fPath(path)
845 , fMode(mode)
msarett9ce3a542016-07-15 13:54:38 -0700846 , fColorType(colorType)
msarett69deca82016-04-29 09:38:40 -0700847{}
848
849bool ColorCodecSrc::veto(SinkFlags flags) const {
850 // Test to direct raster backends (8888 and 565).
851 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
852}
853
854Error ColorCodecSrc::draw(SkCanvas* canvas) const {
855 if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) {
856 return Error::Nonfatal("No need to test color correction to 565 backend.");
857 }
858
msarettd1ec89b2016-08-03 12:59:27 -0700859 bool runInLegacyMode = kBaseline_Mode == fMode;
860#if defined(SK_TEST_QCMS)
861 runInLegacyMode = runInLegacyMode || kQCMS_HPZR30w_Mode == fMode;
862#endif
863
864 if (runInLegacyMode && canvas->imageInfo().colorSpace()) {
865 return Error::Nonfatal("Skipping tests that are only interesting in legacy mode.");
866 } else if (!runInLegacyMode && !canvas->imageInfo().colorSpace()) {
867 return Error::Nonfatal("Skipping tests that are only interesting in srgb mode.");
msarett9ce3a542016-07-15 13:54:38 -0700868 }
869
bungeman38d909e2016-08-02 14:40:46 -0700870 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
msarett69deca82016-04-29 09:38:40 -0700871 if (!encoded) {
872 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
873 }
874
reed42943c82016-09-12 12:01:44 -0700875 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
msarett69deca82016-04-29 09:38:40 -0700876 if (nullptr == codec.get()) {
877 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
878 }
879
msarett9876ac52016-06-01 14:47:18 -0700880 // Load the dst ICC profile. This particular dst is fairly similar to Adobe RGB.
881 sk_sp<SkData> dstData = SkData::MakeFromFileName(
msaretta714bc32016-07-29 08:58:33 -0700882 GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str());
msarett9876ac52016-06-01 14:47:18 -0700883 if (!dstData) {
884 return "Cannot read monitor profile. Is the resource path set correctly?";
885 }
886
msarett50ce1f22016-07-29 06:23:33 -0700887 sk_sp<SkColorSpace> dstSpace = nullptr;
888 if (kDst_sRGB_Mode == fMode) {
889 dstSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
890 } else if (kDst_HPZR30w_Mode == fMode) {
891 dstSpace = SkColorSpace::NewICC(dstData->data(), dstData->size());
892 }
893
894 SkImageInfo decodeInfo = codec->getInfo().makeColorType(fColorType).makeColorSpace(dstSpace);
msarettd1ec89b2016-08-03 12:59:27 -0700895 if (kUnpremul_SkAlphaType == decodeInfo.alphaType()) {
896 decodeInfo = decodeInfo.makeAlphaType(kPremul_SkAlphaType);
897 }
msarett2ecc35f2016-09-08 11:55:16 -0700898 if (kRGBA_F16_SkColorType == fColorType) {
899 decodeInfo = decodeInfo.makeColorSpace(decodeInfo.colorSpace()->makeLinearGamma());
900 }
msarettd1ec89b2016-08-03 12:59:27 -0700901
msarett50ce1f22016-07-29 06:23:33 -0700902 SkImageInfo bitmapInfo = decodeInfo;
903 if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
904 kBGRA_8888_SkColorType == decodeInfo.colorType())
905 {
906 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
907 }
908
909 SkBitmap bitmap;
910 if (!bitmap.tryAllocPixels(bitmapInfo)) {
911 return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(),
912 bitmapInfo.width(), bitmapInfo.height());
913 }
914
915 size_t rowBytes = bitmap.rowBytes();
916 SkCodec::Result r = codec->getPixels(decodeInfo, bitmap.getPixels(), rowBytes);
917 if (SkCodec::kSuccess != r) {
918 return SkStringPrintf("Couldn't getPixels %s. Error code %d", fPath.c_str(), r);
919 }
920
msarett69deca82016-04-29 09:38:40 -0700921 switch (fMode) {
922 case kBaseline_Mode:
msarett39979d82016-07-28 17:11:18 -0700923 case kDst_sRGB_Mode:
msarett50ce1f22016-07-29 06:23:33 -0700924 case kDst_HPZR30w_Mode:
msarett39979d82016-07-28 17:11:18 -0700925 canvas->drawBitmap(bitmap, 0, 0);
926 break;
msarett469f1c52016-06-06 08:20:37 -0700927#if defined(SK_TEST_QCMS)
msarett9876ac52016-06-01 14:47:18 -0700928 case kQCMS_HPZR30w_Mode: {
929 sk_sp<SkData> srcData = codec->getICCData();
msarettd1ec89b2016-08-03 12:59:27 -0700930 if (!srcData) {
931 return Error::Nonfatal("No ICC profile data. Cannot test with QCMS.\n");
932 }
933
msarett9876ac52016-06-01 14:47:18 -0700934 SkAutoTCallVProc<qcms_profile, qcms_profile_release>
935 srcSpace(qcms_profile_from_memory(srcData->data(), srcData->size()));
936 if (!srcSpace) {
937 return Error::Nonfatal(SkStringPrintf("QCMS cannot create profile for %s.\n",
938 fPath.c_str()));
939 }
940
941 SkAutoTCallVProc<qcms_profile, qcms_profile_release>
942 dstSpace(qcms_profile_from_memory(dstData->data(), dstData->size()));
943 SkASSERT(dstSpace);
msarette8bd9ab2016-06-08 10:02:32 -0700944
945 // Optimizes conversion by precomputing the inverse transformation to dst. Also
946 // causes QCMS to use a completely different codepath. This is how Chrome uses QCMS.
947 qcms_profile_precache_output_transform(dstSpace);
msarett9876ac52016-06-01 14:47:18 -0700948 SkAutoTCallVProc<qcms_transform, qcms_transform_release>
949 transform (qcms_transform_create(srcSpace, QCMS_DATA_RGBA_8, dstSpace,
950 QCMS_DATA_RGBA_8, QCMS_INTENT_PERCEPTUAL));
951 if (!transform) {
952 return SkStringPrintf("QCMS cannot create transform for %s.\n", fPath.c_str());
953 }
954
955#ifdef SK_PMCOLOR_IS_RGBA
956 qcms_output_type outType = QCMS_OUTPUT_RGBX;
957#else
958 qcms_output_type outType = QCMS_OUTPUT_BGRX;
959#endif
960
961 // Perform color correction.
msarett50ce1f22016-07-29 06:23:33 -0700962 uint32_t* row = (uint32_t*) bitmap.getPixels();
963 for (int y = 0; y < decodeInfo.height(); y++) {
964 qcms_transform_data_type(transform, row, row, decodeInfo.width(), outType);
965 row = SkTAddOffset<uint32_t>(row, rowBytes);
msarett9876ac52016-06-01 14:47:18 -0700966 }
967
968 canvas->drawBitmap(bitmap, 0, 0);
969 break;
970 }
971#endif
msarett69deca82016-04-29 09:38:40 -0700972 default:
973 SkASSERT(false);
974 return "Invalid fMode";
975 }
976 return "";
977}
978
979SkISize ColorCodecSrc::size() const {
bungeman38d909e2016-08-02 14:40:46 -0700980 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
reed42943c82016-09-12 12:01:44 -0700981 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
msarett69deca82016-04-29 09:38:40 -0700982 if (nullptr == codec) {
983 return SkISize::Make(0, 0);
984 }
985 return SkISize::Make(codec->getInfo().width(), codec->getInfo().height());
986}
987
988Name ColorCodecSrc::name() const {
989 return SkOSPath::Basename(fPath.c_str());
990}
991
992/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
993
mtkleinf4ba3212015-01-28 15:32:24 -0800994static const SkRect kSKPViewport = {0,0, 1000,1000};
995
mtklein8d17a132015-01-30 11:42:31 -0800996SKPSrc::SKPSrc(Path path) : fPath(path) {}
mtklein748ca3b2015-01-15 10:56:12 -0800997
998Error SKPSrc::draw(SkCanvas* canvas) const {
scroggoa1193e42015-01-21 12:09:53 -0800999 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str()));
mtklein75d98fd2015-01-18 07:05:01 -08001000 if (!stream) {
mtklein748ca3b2015-01-15 10:56:12 -08001001 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
1002 }
reedca2622b2016-03-18 07:25:55 -07001003 sk_sp<SkPicture> pic(SkPicture::MakeFromStream(stream));
mtklein75d98fd2015-01-18 07:05:01 -08001004 if (!pic) {
1005 return SkStringPrintf("Couldn't decode %s as a picture.", fPath.c_str());
1006 }
halcanary96fcdcc2015-08-27 07:41:13 -07001007 stream.reset((SkStream*)nullptr); // Might as well drop this when we're done with it.
joshualitt7c3a2f82015-03-31 13:32:05 -07001008
mtkleinf4ba3212015-01-28 15:32:24 -08001009 canvas->clipRect(kSKPViewport);
mtklein748ca3b2015-01-15 10:56:12 -08001010 canvas->drawPicture(pic);
1011 return "";
1012}
1013
1014SkISize SKPSrc::size() const {
mtkleinffa901a2015-03-16 10:38:07 -07001015 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str()));
1016 if (!stream) {
1017 return SkISize::Make(0,0);
1018 }
1019 SkPictInfo info;
1020 if (!SkPicture::InternalOnly_StreamIsSKP(stream, &info)) {
1021 return SkISize::Make(0,0);
1022 }
1023 SkRect viewport = kSKPViewport;
1024 if (!viewport.intersect(info.fCullRect)) {
1025 return SkISize::Make(0,0);
1026 }
1027 return viewport.roundOut().size();
mtklein748ca3b2015-01-15 10:56:12 -08001028}
1029
1030Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
1031
1032/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
fmalitaa2b9fdf2016-08-03 19:53:36 -07001033#if defined(SK_XML)
1034// Should we try to use the SVG intrinsic size instead?
1035static const SkSize kSVGSize = SkSize::Make(1000, 1000);
1036
1037SVGSrc::SVGSrc(Path path) : fPath(path) {}
1038
1039Error SVGSrc::draw(SkCanvas* canvas) const {
1040 SkFILEStream stream(fPath.c_str());
1041 if (!stream.isValid()) {
1042 return SkStringPrintf("Unable to open file: %s", fPath.c_str());
1043 }
1044
1045 sk_sp<SkSVGDOM> dom = SkSVGDOM::MakeFromStream(stream, kSVGSize);
1046 if (!dom) {
1047 return SkStringPrintf("Unable to parse file: %s", fPath.c_str());
1048 }
1049
1050 dom->render(canvas);
1051
1052 return "";
1053}
1054
1055SkISize SVGSrc::size() const {
1056 return kSVGSize.toRound();
1057}
1058
1059Name SVGSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
1060
fmalita179d8852016-08-16 14:23:29 -07001061bool SVGSrc::veto(SinkFlags flags) const {
1062 // No need to test to non-(raster||gpu) or indirect backends.
1063 bool type_ok = flags.type == SinkFlags::kRaster
1064 || flags.type == SinkFlags::kGPU;
1065
1066 return !type_ok || flags.approach != SinkFlags::kDirect;
1067}
1068
fmalitaa2b9fdf2016-08-03 19:53:36 -07001069#endif // defined(SK_XML)
1070/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
mtklein748ca3b2015-01-15 10:56:12 -08001071
halcanary45420a92016-06-02 12:41:14 -07001072MSKPSrc::MSKPSrc(Path path) : fPath(path) {
1073 std::unique_ptr<SkStreamAsset> stream(SkStream::NewFromFile(fPath.c_str()));
1074 (void)fReader.init(stream.get());
1075}
1076
1077int MSKPSrc::pageCount() const { return fReader.pageCount(); }
1078
1079SkISize MSKPSrc::size() const { return this->size(0); }
1080SkISize MSKPSrc::size(int i) const { return fReader.pageSize(i).toCeil(); }
1081
1082Error MSKPSrc::draw(SkCanvas* c) const { return this->draw(0, c); }
1083Error MSKPSrc::draw(int i, SkCanvas* canvas) const {
1084 std::unique_ptr<SkStreamAsset> stream(SkStream::NewFromFile(fPath.c_str()));
1085 if (!stream) {
1086 return SkStringPrintf("Unable to open file: %s", fPath.c_str());
1087 }
1088 if (fReader.pageCount() == 0) {
1089 return SkStringPrintf("Unable to parse MultiPictureDocument file: %s", fPath.c_str());
1090 }
1091 if (i >= fReader.pageCount()) {
1092 return SkStringPrintf("MultiPictureDocument page number out of range: %d", i);
1093 }
1094 sk_sp<SkPicture> page = fReader.readPage(stream.get(), i);
1095 if (!page) {
1096 return SkStringPrintf("SkMultiPictureDocumentReader failed on page %d: %s",
1097 i, fPath.c_str());
1098 }
1099 canvas->drawPicture(page);
1100 return "";
1101}
1102
1103Name MSKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
1104
1105/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1106
mtkleinad66f9b2015-02-13 15:11:10 -08001107Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const {
1108 SkAutoTDelete<SkCanvas> canvas(SkCreateNullCanvas());
1109 return src.draw(canvas);
1110}
1111
1112/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1113
mtkleinb9eb4ac2015-02-02 18:26:03 -08001114DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?");
1115
bsalomon85b4b532016-04-05 11:06:27 -07001116GPUSink::GPUSink(GrContextFactory::ContextType ct,
1117 GrContextFactory::ContextOptions options,
mtklein82d28432015-01-15 12:46:02 -08001118 int samples,
bsalomonafcd7cd2015-08-31 12:39:41 -07001119 bool diText,
brianosmand93c1202016-03-10 07:49:08 -08001120 SkColorType colorType,
brianosmanb109b8c2016-06-16 13:03:24 -07001121 sk_sp<SkColorSpace> colorSpace,
mtklein82d28432015-01-15 12:46:02 -08001122 bool threaded)
mtklein748ca3b2015-01-15 10:56:12 -08001123 : fContextType(ct)
kkinnunen5219fd92015-12-10 06:28:13 -08001124 , fContextOptions(options)
mtklein748ca3b2015-01-15 10:56:12 -08001125 , fSampleCount(samples)
bsalomonafcd7cd2015-08-31 12:39:41 -07001126 , fUseDIText(diText)
brianosmand93c1202016-03-10 07:49:08 -08001127 , fColorType(colorType)
brianosmanb109b8c2016-06-16 13:03:24 -07001128 , fColorSpace(std::move(colorSpace))
mtklein82d28432015-01-15 12:46:02 -08001129 , fThreaded(threaded) {}
mtklein748ca3b2015-01-15 10:56:12 -08001130
joshualitt5f5a8d72015-02-25 14:09:45 -08001131void PreAbandonGpuContextErrorHandler(SkError, void*) {}
1132
bsalomon648c6962015-10-23 09:06:59 -07001133DEFINE_bool(imm, false, "Run gpu configs in immediate mode.");
bsalomon69cfe952015-11-30 13:27:47 -08001134DEFINE_bool(batchClip, false, "Clip each GrBatch to its device bounds for testing.");
bsalomon6dea83f2015-12-03 12:58:06 -08001135DEFINE_bool(batchBounds, false, "Draw a wireframe bounds of each GrBatch.");
bsalomon489147c2015-12-14 12:13:09 -08001136DEFINE_int32(batchLookback, -1, "Maximum GrBatch lookback for combining, negative means default.");
bsalomonaecc0182016-03-07 11:50:44 -08001137DEFINE_int32(batchLookahead, -1, "Maximum GrBatch lookahead for combining, negative means "
1138 "default.");
bsalomon648c6962015-10-23 09:06:59 -07001139
mtkleinb9eb4ac2015-02-02 18:26:03 -08001140Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const {
kkinnunen5219fd92015-12-10 06:28:13 -08001141 GrContextOptions grOptions;
bsalomon489147c2015-12-14 12:13:09 -08001142 grOptions.fImmediateMode = FLAGS_imm;
1143 grOptions.fClipBatchToBounds = FLAGS_batchClip;
1144 grOptions.fDrawBatchBounds = FLAGS_batchBounds;
1145 grOptions.fMaxBatchLookback = FLAGS_batchLookback;
bsalomonaecc0182016-03-07 11:50:44 -08001146 grOptions.fMaxBatchLookahead = FLAGS_batchLookahead;
kkinnunen64492c42015-12-08 01:24:40 -08001147
kkinnunen5219fd92015-12-10 06:28:13 -08001148 src.modifyGrContextOptions(&grOptions);
1149
1150 GrContextFactory factory(grOptions);
mtkleinf4ba3212015-01-28 15:32:24 -08001151 const SkISize size = src.size();
mtklein748ca3b2015-01-15 10:56:12 -08001152 const SkImageInfo info =
brianosmand93c1202016-03-10 07:49:08 -08001153 SkImageInfo::Make(size.width(), size.height(), fColorType,
brianosmanb109b8c2016-06-16 13:03:24 -07001154 kPremul_SkAlphaType, fColorSpace);
msarett13a036b2016-02-08 09:10:47 -08001155#if SK_SUPPORT_GPU
bsalomon8b7451a2016-05-11 06:33:06 -07001156 GrContext* context = factory.getContextInfo(fContextType, fContextOptions).grContext();
1157 const int maxDimension = context->caps()->maxTextureSize();
msarett13a036b2016-02-08 09:10:47 -08001158 if (maxDimension < SkTMax(size.width(), size.height())) {
1159 return Error::Nonfatal("Src too large to create a texture.\n");
1160 }
1161#endif
1162
reede8f30622016-03-23 18:59:25 -07001163 auto surface(
kkinnunen3e980c32015-12-23 01:33:00 -08001164 NewGpuSurface(&factory, fContextType, fContextOptions, info, fSampleCount, fUseDIText));
mtklein748ca3b2015-01-15 10:56:12 -08001165 if (!surface) {
1166 return "Could not create a surface.";
1167 }
joshualitt5f5a8d72015-02-25 14:09:45 -08001168 if (FLAGS_preAbandonGpuContext) {
halcanary96fcdcc2015-08-27 07:41:13 -07001169 SkSetErrorCallback(&PreAbandonGpuContextErrorHandler, nullptr);
joshualitt5f5a8d72015-02-25 14:09:45 -08001170 factory.abandonContexts();
1171 }
mtklein748ca3b2015-01-15 10:56:12 -08001172 SkCanvas* canvas = surface->getCanvas();
1173 Error err = src.draw(canvas);
1174 if (!err.isEmpty()) {
1175 return err;
1176 }
1177 canvas->flush();
mtkleinb9eb4ac2015-02-02 18:26:03 -08001178 if (FLAGS_gpuStats) {
1179 canvas->getGrContext()->dumpCacheStats(log);
1180 canvas->getGrContext()->dumpGpuStats(log);
1181 }
mtklein748ca3b2015-01-15 10:56:12 -08001182 dst->allocPixels(info);
joshualitt5f5a8d72015-02-25 14:09:45 -08001183 canvas->readPixels(dst, 0, 0);
mtklein55e88b22015-01-21 15:50:13 -08001184 if (FLAGS_abandonGpuContext) {
1185 factory.abandonContexts();
bsalomon6e2aad42016-04-01 11:54:31 -07001186 } else if (FLAGS_releaseAndAbandonGpuContext) {
1187 factory.releaseResourcesAndAbandonContexts();
mtklein55e88b22015-01-21 15:50:13 -08001188 }
mtklein748ca3b2015-01-15 10:56:12 -08001189 return "";
1190}
1191
1192/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1193
halcanary47ef4d52015-03-03 09:13:09 -08001194static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) {
halcanary4ba051c2016-03-10 10:31:53 -08001195 if (src.size().isEmpty()) {
1196 return "Source has empty dimensions";
1197 }
halcanary47ef4d52015-03-03 09:13:09 -08001198 SkASSERT(doc);
halcanary45420a92016-06-02 12:41:14 -07001199 int pageCount = src.pageCount();
1200 for (int i = 0; i < pageCount; ++i) {
1201 int width = src.size(i).width(), height = src.size(i).height();
halcanary7e798182015-04-14 14:06:18 -07001202 SkCanvas* canvas =
1203 doc->beginPage(SkIntToScalar(width), SkIntToScalar(height));
1204 if (!canvas) {
halcanary96fcdcc2015-08-27 07:41:13 -07001205 return "SkDocument::beginPage(w,h) returned nullptr";
halcanary7e798182015-04-14 14:06:18 -07001206 }
halcanary45420a92016-06-02 12:41:14 -07001207 Error err = src.draw(i, canvas);
halcanary7e798182015-04-14 14:06:18 -07001208 if (!err.isEmpty()) {
1209 return err;
1210 }
1211 doc->endPage();
mtklein748ca3b2015-01-15 10:56:12 -08001212 }
halcanary7e798182015-04-14 14:06:18 -07001213 if (!doc->close()) {
1214 return "SkDocument::close() returned false";
1215 }
halcanaryfd4a9932015-01-28 11:45:58 -08001216 dst->flush();
mtklein748ca3b2015-01-15 10:56:12 -08001217 return "";
1218}
1219
halcanary47ef4d52015-03-03 09:13:09 -08001220Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
halcanary4b656662016-04-27 07:45:18 -07001221 SkDocument::PDFMetadata metadata;
1222 metadata.fTitle = src.name();
1223 metadata.fSubject = "rendering correctness test";
1224 metadata.fCreator = "Skia/DM";
1225 sk_sp<SkDocument> doc = SkDocument::MakePDF(dst, SK_ScalarDefaultRasterDPI,
1226 metadata, nullptr, fPDFA);
halcanary47ef4d52015-03-03 09:13:09 -08001227 if (!doc) {
halcanary4b656662016-04-27 07:45:18 -07001228 return "SkDocument::MakePDF() returned nullptr";
halcanary47ef4d52015-03-03 09:13:09 -08001229 }
1230 return draw_skdocument(src, doc.get(), dst);
1231}
1232
1233/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1234
1235XPSSink::XPSSink() {}
1236
1237Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
halcanary4b656662016-04-27 07:45:18 -07001238 sk_sp<SkDocument> doc(SkDocument::MakeXPS(dst));
halcanary47ef4d52015-03-03 09:13:09 -08001239 if (!doc) {
halcanary4b656662016-04-27 07:45:18 -07001240 return "SkDocument::MakeXPS() returned nullptr";
halcanary47ef4d52015-03-03 09:13:09 -08001241 }
1242 return draw_skdocument(src, doc.get(), dst);
1243}
mtklein748ca3b2015-01-15 10:56:12 -08001244/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1245
mtklein9c3f17d2015-01-28 11:35:18 -08001246SKPSink::SKPSink() {}
1247
mtkleinb9eb4ac2015-02-02 18:26:03 -08001248Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
mtklein9c3f17d2015-01-28 11:35:18 -08001249 SkSize size;
1250 size = src.size();
1251 SkPictureRecorder recorder;
1252 Error err = src.draw(recorder.beginRecording(size.width(), size.height()));
1253 if (!err.isEmpty()) {
1254 return err;
1255 }
reedca2622b2016-03-18 07:25:55 -07001256 recorder.finishRecordingAsPicture()->serialize(dst);
mtklein9c3f17d2015-01-28 11:35:18 -08001257 return "";
1258}
1259
1260/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1261
mtklein8a4527e2015-01-31 20:00:58 -08001262SVGSink::SVGSink() {}
1263
mtkleinb9eb4ac2015-02-02 18:26:03 -08001264Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
fmalita718df0a2016-07-15 10:33:29 -07001265#if defined(SK_XML)
halcanary385fe4d2015-08-26 13:07:48 -07001266 SkAutoTDelete<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(dst));
fmalita2aafe6f2015-02-06 12:51:10 -08001267 SkAutoTUnref<SkCanvas> canvas(SkSVGCanvas::Create(
1268 SkRect::MakeWH(SkIntToScalar(src.size().width()), SkIntToScalar(src.size().height())),
1269 xmlWriter));
1270 return src.draw(canvas);
fmalita718df0a2016-07-15 10:33:29 -07001271#else
1272 return Error("SVG sink is disabled.");
1273#endif // SK_XML
mtklein8a4527e2015-01-31 20:00:58 -08001274}
1275
1276/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1277
brianosmanb109b8c2016-06-16 13:03:24 -07001278RasterSink::RasterSink(SkColorType colorType, sk_sp<SkColorSpace> colorSpace)
mtklein27c3fdd2016-02-26 14:43:21 -08001279 : fColorType(colorType)
brianosmanb109b8c2016-06-16 13:03:24 -07001280 , fColorSpace(std::move(colorSpace)) {}
mtklein748ca3b2015-01-15 10:56:12 -08001281
mtkleinb9eb4ac2015-02-02 18:26:03 -08001282Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
mtkleinf4ba3212015-01-28 15:32:24 -08001283 const SkISize size = src.size();
mtklein748ca3b2015-01-15 10:56:12 -08001284 // If there's an appropriate alpha type for this color type, use it, otherwise use premul.
1285 SkAlphaType alphaType = kPremul_SkAlphaType;
1286 (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType);
1287
mtkleinc8be09a2016-01-04 18:56:57 -08001288 SkMallocPixelRef::ZeroedPRFactory factory;
mtklein27c3fdd2016-02-26 14:43:21 -08001289 dst->allocPixels(SkImageInfo::Make(size.width(), size.height(),
brianosmanb109b8c2016-06-16 13:03:24 -07001290 fColorType, alphaType, fColorSpace),
mtkleinc8be09a2016-01-04 18:56:57 -08001291 &factory,
1292 nullptr/*colortable*/);
mtklein748ca3b2015-01-15 10:56:12 -08001293 SkCanvas canvas(*dst);
1294 return src.draw(&canvas);
1295}
1296
1297/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1298
mtkleina16e69e2015-05-05 11:38:45 -07001299// Handy for front-patching a Src. Do whatever up-front work you need, then call draw_to_canvas(),
mtkleine44b5082015-05-07 10:53:34 -07001300// passing the Sink draw() arguments, a size, and a function draws into an SkCanvas.
mtkleina16e69e2015-05-05 11:38:45 -07001301// Several examples below.
1302
mtkleincbf89782016-02-19 14:27:14 -08001303template <typename Fn>
msarett62d3b102015-12-10 15:14:27 -08001304static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log,
mtkleincbf89782016-02-19 14:27:14 -08001305 SkISize size, const Fn& draw) {
mtkleina16e69e2015-05-05 11:38:45 -07001306 class ProxySrc : public Src {
1307 public:
mtkleincbf89782016-02-19 14:27:14 -08001308 ProxySrc(SkISize size, const Fn& draw) : fSize(size), fDraw(draw) {}
mtkleina16e69e2015-05-05 11:38:45 -07001309 Error draw(SkCanvas* canvas) const override { return fDraw(canvas); }
halcanaryb4a7f142016-03-30 08:31:27 -07001310 Name name() const override { return "ProxySrc"; }
1311 SkISize size() const override { return fSize; }
mtkleina16e69e2015-05-05 11:38:45 -07001312 private:
mtkleincbf89782016-02-19 14:27:14 -08001313 SkISize fSize;
1314 const Fn& fDraw;
mtkleina16e69e2015-05-05 11:38:45 -07001315 };
msarett62d3b102015-12-10 15:14:27 -08001316 return sink->draw(ProxySrc(size, draw), bitmap, stream, log);
mtkleina16e69e2015-05-05 11:38:45 -07001317}
1318
1319/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1320
mtklein4a34ecb2016-01-08 10:19:35 -08001321DEFINE_bool(check, true, "If true, have most Via- modes fail if they affect the output.");
1322
1323// Is *bitmap identical to what you get drawing src into sink?
1324static Error check_against_reference(const SkBitmap* bitmap, const Src& src, Sink* sink) {
1325 // We can only check raster outputs.
1326 // (Non-raster outputs like .pdf, .skp, .svg may differ but still draw identically.)
1327 if (FLAGS_check && bitmap) {
1328 SkBitmap reference;
1329 SkString log;
halcanaryb4a7f142016-03-30 08:31:27 -07001330 SkDynamicMemoryWStream wStream;
1331 Error err = sink->draw(src, &reference, &wStream, &log);
mtklein4a34ecb2016-01-08 10:19:35 -08001332 // If we can draw into this Sink via some pipeline, we should be able to draw directly.
1333 SkASSERT(err.isEmpty());
1334 if (!err.isEmpty()) {
1335 return err;
1336 }
1337 // The dimensions are a property of the Src only, and so should be identical.
1338 SkASSERT(reference.getSize() == bitmap->getSize());
1339 if (reference.getSize() != bitmap->getSize()) {
1340 return "Dimensions don't match reference";
1341 }
1342 // All SkBitmaps in DM are pre-locked and tight, so this comparison is easy.
1343 if (0 != memcmp(reference.getPixels(), bitmap->getPixels(), reference.getSize())) {
1344 return "Pixels don't match reference";
1345 }
1346 }
1347 return "";
1348}
1349
1350/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1351
mtkleind603b222015-02-17 11:13:33 -08001352static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) {
1353 SkRect bounds = SkRect::MakeIWH(srcW, srcH);
1354 matrix->mapRect(&bounds);
1355 matrix->postTranslate(-bounds.x(), -bounds.y());
1356 return SkISize::Make(SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height()));
1357}
1358
msarett62d3b102015-12-10 15:14:27 -08001359ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
mtklein748ca3b2015-01-15 10:56:12 -08001360
mtkleinb9eb4ac2015-02-02 18:26:03 -08001361Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtkleina16e69e2015-05-05 11:38:45 -07001362 SkMatrix matrix = fMatrix;
1363 SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height());
msarett62d3b102015-12-10 15:14:27 -08001364 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
mtkleina16e69e2015-05-05 11:38:45 -07001365 canvas->concat(matrix);
1366 return src.draw(canvas);
1367 });
mtklein748ca3b2015-01-15 10:56:12 -08001368}
1369
mtkleind603b222015-02-17 11:13:33 -08001370// Undoes any flip or 90 degree rotate without changing the scale of the bitmap.
1371// This should be pixel-preserving.
msarett62d3b102015-12-10 15:14:27 -08001372ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
mtkleind603b222015-02-17 11:13:33 -08001373
1374Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1375 Error err = fSink->draw(src, bitmap, stream, log);
1376 if (!err.isEmpty()) {
1377 return err;
1378 }
1379
1380 SkMatrix inverse;
1381 if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) {
1382 return "Cannot upright --matrix.";
1383 }
1384 SkMatrix upright = SkMatrix::I();
1385 upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX()));
1386 upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY()));
1387 upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX()));
1388 upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY()));
1389
1390 SkBitmap uprighted;
1391 SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height());
1392 uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height()));
1393
1394 SkCanvas canvas(uprighted);
1395 canvas.concat(upright);
1396 SkPaint paint;
1397 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
1398 canvas.drawBitmap(*bitmap, 0, 0, &paint);
1399
1400 *bitmap = uprighted;
1401 bitmap->lockPixels();
1402 return "";
1403}
1404
mtklein748ca3b2015-01-15 10:56:12 -08001405/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1406
mtkleina16e69e2015-05-05 11:38:45 -07001407Error ViaSerialization::draw(
1408 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtklein748ca3b2015-01-15 10:56:12 -08001409 // Record our Src into a picture.
mtkleina16e69e2015-05-05 11:38:45 -07001410 auto size = src.size();
mtklein748ca3b2015-01-15 10:56:12 -08001411 SkPictureRecorder recorder;
mtkleina16e69e2015-05-05 11:38:45 -07001412 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1413 SkIntToScalar(size.height())));
mtklein748ca3b2015-01-15 10:56:12 -08001414 if (!err.isEmpty()) {
1415 return err;
1416 }
reedca2622b2016-03-18 07:25:55 -07001417 sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture());
mtklein748ca3b2015-01-15 10:56:12 -08001418
1419 // Serialize it and then deserialize it.
1420 SkDynamicMemoryWStream wStream;
1421 pic->serialize(&wStream);
scroggoa1193e42015-01-21 12:09:53 -08001422 SkAutoTDelete<SkStream> rStream(wStream.detachAsStream());
reedca2622b2016-03-18 07:25:55 -07001423 sk_sp<SkPicture> deserialized(SkPicture::MakeFromStream(rStream));
mtklein748ca3b2015-01-15 10:56:12 -08001424
msarett62d3b102015-12-10 15:14:27 -08001425 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
mtkleina16e69e2015-05-05 11:38:45 -07001426 canvas->drawPicture(deserialized);
mtklein4a34ecb2016-01-08 10:19:35 -08001427 return check_against_reference(bitmap, src, fSink);
mtkleina16e69e2015-05-05 11:38:45 -07001428 });
mtklein748ca3b2015-01-15 10:56:12 -08001429}
1430
1431/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1432
msarett62d3b102015-12-10 15:14:27 -08001433ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink)
1434 : Via(sink)
mtklein78829242015-05-06 07:54:07 -07001435 , fW(w)
mtklein748ca3b2015-01-15 10:56:12 -08001436 , fH(h)
mtklein78829242015-05-06 07:54:07 -07001437 , fFactory(factory) {}
mtklein748ca3b2015-01-15 10:56:12 -08001438
mtkleinb9eb4ac2015-02-02 18:26:03 -08001439Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtkleina16e69e2015-05-05 11:38:45 -07001440 auto size = src.size();
mtklein748ca3b2015-01-15 10:56:12 -08001441 SkPictureRecorder recorder;
mtkleina16e69e2015-05-05 11:38:45 -07001442 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1443 SkIntToScalar(size.height()),
1444 fFactory.get()));
mtklein748ca3b2015-01-15 10:56:12 -08001445 if (!err.isEmpty()) {
1446 return err;
1447 }
reedca2622b2016-03-18 07:25:55 -07001448 sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture());
mtklein748ca3b2015-01-15 10:56:12 -08001449
msarett62d3b102015-12-10 15:14:27 -08001450 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) {
mtkleina16e69e2015-05-05 11:38:45 -07001451 const int xTiles = (size.width() + fW - 1) / fW,
1452 yTiles = (size.height() + fH - 1) / fH;
1453 SkMultiPictureDraw mpd(xTiles*yTiles);
reede8f30622016-03-23 18:59:25 -07001454 SkTArray<sk_sp<SkSurface>> surfaces;
1455// surfaces.setReserve(xTiles*yTiles);
mtklein748ca3b2015-01-15 10:56:12 -08001456
mtkleina16e69e2015-05-05 11:38:45 -07001457 SkImageInfo info = canvas->imageInfo().makeWH(fW, fH);
1458 for (int j = 0; j < yTiles; j++) {
1459 for (int i = 0; i < xTiles; i++) {
1460 // This lets our ultimate Sink determine the best kind of surface.
1461 // E.g., if it's a GpuSink, the surfaces and images are textures.
reede8f30622016-03-23 18:59:25 -07001462 auto s = canvas->makeSurface(info);
mtkleina16e69e2015-05-05 11:38:45 -07001463 if (!s) {
reede8f30622016-03-23 18:59:25 -07001464 s = SkSurface::MakeRaster(info); // Some canvases can't create surfaces.
mtklein748ca3b2015-01-15 10:56:12 -08001465 }
reede8f30622016-03-23 18:59:25 -07001466 surfaces.push_back(s);
mtkleina16e69e2015-05-05 11:38:45 -07001467 SkCanvas* c = s->getCanvas();
1468 c->translate(SkIntToScalar(-i * fW),
1469 SkIntToScalar(-j * fH)); // Line up the canvas with this tile.
reedca2622b2016-03-18 07:25:55 -07001470 mpd.add(c, pic.get());
mtklein748ca3b2015-01-15 10:56:12 -08001471 }
mtklein748ca3b2015-01-15 10:56:12 -08001472 }
mtkleina16e69e2015-05-05 11:38:45 -07001473 mpd.draw();
1474 for (int j = 0; j < yTiles; j++) {
1475 for (int i = 0; i < xTiles; i++) {
reed9ce9d672016-03-17 10:51:11 -07001476 sk_sp<SkImage> image(surfaces[i+xTiles*j]->makeImageSnapshot());
mtkleina16e69e2015-05-05 11:38:45 -07001477 canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH));
1478 }
1479 }
mtkleina16e69e2015-05-05 11:38:45 -07001480 return "";
1481 });
mtklein748ca3b2015-01-15 10:56:12 -08001482}
1483
mtkleinb7e8d692015-04-07 08:30:32 -07001484/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1485
mtklein4a34ecb2016-01-08 10:19:35 -08001486Error ViaPicture::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1487 auto size = src.size();
1488 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1489 SkPictureRecorder recorder;
reedca2622b2016-03-18 07:25:55 -07001490 sk_sp<SkPicture> pic;
mtklein4a34ecb2016-01-08 10:19:35 -08001491 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1492 SkIntToScalar(size.height())));
1493 if (!err.isEmpty()) {
1494 return err;
1495 }
reedca2622b2016-03-18 07:25:55 -07001496 pic = recorder.finishRecordingAsPicture();
mtklein4a34ecb2016-01-08 10:19:35 -08001497 canvas->drawPicture(pic);
1498 return check_against_reference(bitmap, src, fSink);
1499 });
1500}
1501
1502/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1503
reedbabc3de2016-07-08 08:43:27 -07001504Error ViaDefer::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1505 auto size = src.size();
1506 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1507 SkDeferredCanvas deferred(canvas);
1508 return src.draw(&deferred);
1509 });
1510}
1511
1512/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1513
mtkleinb7e8d692015-04-07 08:30:32 -07001514// Draw the Src into two pictures, then draw the second picture into the wrapped Sink.
1515// This tests that any shortcuts we may take while recording that second picture are legal.
1516Error ViaSecondPicture::draw(
1517 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtkleina16e69e2015-05-05 11:38:45 -07001518 auto size = src.size();
msarett62d3b102015-12-10 15:14:27 -08001519 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
mtkleina16e69e2015-05-05 11:38:45 -07001520 SkPictureRecorder recorder;
reedca2622b2016-03-18 07:25:55 -07001521 sk_sp<SkPicture> pic;
mtkleina16e69e2015-05-05 11:38:45 -07001522 for (int i = 0; i < 2; i++) {
1523 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1524 SkIntToScalar(size.height())));
1525 if (!err.isEmpty()) {
1526 return err;
mtkleinb7e8d692015-04-07 08:30:32 -07001527 }
reedca2622b2016-03-18 07:25:55 -07001528 pic = recorder.finishRecordingAsPicture();
mtkleinb7e8d692015-04-07 08:30:32 -07001529 }
mtkleina16e69e2015-05-05 11:38:45 -07001530 canvas->drawPicture(pic);
mtklein4a34ecb2016-01-08 10:19:35 -08001531 return check_against_reference(bitmap, src, fSink);
mtkleina16e69e2015-05-05 11:38:45 -07001532 });
mtkleinb7e8d692015-04-07 08:30:32 -07001533}
1534
mtkleind31c13d2015-05-05 12:59:56 -07001535/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1536
mtklein6fbf4b32015-05-06 11:35:40 -07001537// Draw the Src twice. This can help exercise caching.
1538Error ViaTwice::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
msarett62d3b102015-12-10 15:14:27 -08001539 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) -> Error {
mtklein6fbf4b32015-05-06 11:35:40 -07001540 for (int i = 0; i < 2; i++) {
1541 SkAutoCanvasRestore acr(canvas, true/*save now*/);
1542 canvas->clear(SK_ColorTRANSPARENT);
1543 Error err = src.draw(canvas);
1544 if (err.isEmpty()) {
1545 return err;
1546 }
1547 }
mtklein4a34ecb2016-01-08 10:19:35 -08001548 return check_against_reference(bitmap, src, fSink);
mtklein6fbf4b32015-05-06 11:35:40 -07001549 });
1550}
1551
1552/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1553
mtkleind31c13d2015-05-05 12:59:56 -07001554// This is like SkRecords::Draw, in that it plays back SkRecords ops into a Canvas.
1555// Unlike SkRecords::Draw, it builds a single-op sub-picture out of each Draw-type op.
1556// This is an only-slightly-exaggerated simluation of Blink's Slimming Paint pictures.
1557struct DrawsAsSingletonPictures {
1558 SkCanvas* fCanvas;
mtkleind2baa902015-07-07 09:43:28 -07001559 const SkDrawableList& fDrawables;
mtklein11064df2016-04-06 15:01:57 -07001560 SkRect fBounds;
mtkleind31c13d2015-05-05 12:59:56 -07001561
mtkleind31c13d2015-05-05 12:59:56 -07001562 template <typename T>
1563 void draw(const T& op, SkCanvas* canvas) {
1564 // We must pass SkMatrix::I() as our initial matrix.
1565 // By default SkRecords::Draw() uses the canvas' matrix as its initial matrix,
1566 // which would have the funky effect of applying transforms over and over.
mtkleind2baa902015-07-07 09:43:28 -07001567 SkRecords::Draw d(canvas, nullptr, fDrawables.begin(), fDrawables.count(), &SkMatrix::I());
1568 d(op);
mtkleind31c13d2015-05-05 12:59:56 -07001569 }
1570
mtklein449d9b72015-09-28 10:33:02 -07001571 // Draws get their own picture.
mtkleind31c13d2015-05-05 12:59:56 -07001572 template <typename T>
mtklein449d9b72015-09-28 10:33:02 -07001573 SK_WHEN(T::kTags & SkRecords::kDraw_Tag, void) operator()(const T& op) {
mtkleind31c13d2015-05-05 12:59:56 -07001574 SkPictureRecorder rec;
mtklein11064df2016-04-06 15:01:57 -07001575 this->draw(op, rec.beginRecording(fBounds));
reedca2622b2016-03-18 07:25:55 -07001576 sk_sp<SkPicture> pic(rec.finishRecordingAsPicture());
mtkleind31c13d2015-05-05 12:59:56 -07001577 fCanvas->drawPicture(pic);
1578 }
1579
mtklein449d9b72015-09-28 10:33:02 -07001580 // We'll just issue non-draws directly.
mtkleind31c13d2015-05-05 12:59:56 -07001581 template <typename T>
mtklein449d9b72015-09-28 10:33:02 -07001582 skstd::enable_if_t<!(T::kTags & SkRecords::kDraw_Tag), void> operator()(const T& op) {
1583 this->draw(op, fCanvas);
1584 }
mtkleind31c13d2015-05-05 12:59:56 -07001585};
1586
mtkleind31c13d2015-05-05 12:59:56 -07001587// Record Src into a picture, then record it into a macro picture with a sub-picture for each draw.
1588// Then play back that macro picture into our wrapped sink.
1589Error ViaSingletonPictures::draw(
1590 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1591 auto size = src.size();
msarett62d3b102015-12-10 15:14:27 -08001592 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
mtkleind31c13d2015-05-05 12:59:56 -07001593 // Use low-level (Skia-private) recording APIs so we can read the SkRecord.
1594 SkRecord skr;
1595 SkRecorder recorder(&skr, size.width(), size.height());
1596 Error err = src.draw(&recorder);
1597 if (!err.isEmpty()) {
1598 return err;
1599 }
1600
1601 // Record our macro-picture, with each draw op as its own sub-picture.
1602 SkPictureRecorder macroRec;
1603 SkCanvas* macroCanvas = macroRec.beginRecording(SkIntToScalar(size.width()),
1604 SkIntToScalar(size.height()));
mtkleind2baa902015-07-07 09:43:28 -07001605
1606 SkAutoTDelete<SkDrawableList> drawables(recorder.detachDrawableList());
1607 const SkDrawableList empty;
1608
1609 DrawsAsSingletonPictures drawsAsSingletonPictures = {
1610 macroCanvas,
1611 drawables ? *drawables : empty,
mtklein11064df2016-04-06 15:01:57 -07001612 SkRect::MakeWH((SkScalar)size.width(), (SkScalar)size.height()),
mtkleind2baa902015-07-07 09:43:28 -07001613 };
mtkleinc6ad06a2015-08-19 09:51:00 -07001614 for (int i = 0; i < skr.count(); i++) {
mtklein343a63d2016-03-22 11:46:53 -07001615 skr.visit(i, drawsAsSingletonPictures);
mtkleind31c13d2015-05-05 12:59:56 -07001616 }
reedca2622b2016-03-18 07:25:55 -07001617 sk_sp<SkPicture> macroPic(macroRec.finishRecordingAsPicture());
mtkleind31c13d2015-05-05 12:59:56 -07001618
1619 canvas->drawPicture(macroPic);
mtklein4a34ecb2016-01-08 10:19:35 -08001620 return check_against_reference(bitmap, src, fSink);
mtkleind31c13d2015-05-05 12:59:56 -07001621 });
1622}
1623
mtklein9c5052f2016-08-06 12:51:51 -07001624/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1625
1626Error ViaLite::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1627 auto size = src.size();
mtklein8bbbb692016-08-15 12:56:00 -07001628 SkRect bounds = {0,0, (SkScalar)size.width(), (SkScalar)size.height()};
mtklein9c5052f2016-08-06 12:51:51 -07001629 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
mtklein8bbbb692016-08-15 12:56:00 -07001630 sk_sp<SkLiteDL> dl = SkLiteDL::New(bounds);
1631
1632 SkLiteRecorder rec;
1633 rec.reset(dl.get());
1634
1635 Error err = src.draw(&rec);
mtklein9c5052f2016-08-06 12:51:51 -07001636 if (!err.isEmpty()) {
1637 return err;
1638 }
mtklein8bbbb692016-08-15 12:56:00 -07001639 dl->draw(canvas);
mtklein03591a72016-08-07 13:35:46 -07001640 return check_against_reference(bitmap, src, fSink);
mtklein9c5052f2016-08-06 12:51:51 -07001641 });
1642}
1643
mtklein748ca3b2015-01-15 10:56:12 -08001644} // namespace DM