blob: cf9a6a2a2c8d840e5ad8c733821e3623a0672047 [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"
9#include "SamplePipeControllers.h"
msarett3d9d7a72015-10-21 10:27:10 -070010#include "SkAndroidCodec.h"
scroggof24f2242015-03-03 08:59:20 -080011#include "SkCodec.h"
msarett7f691442015-09-22 11:56:16 -070012#include "SkCodecTools.h"
mtkleina16e69e2015-05-05 11:38:45 -070013#include "SkCommonFlags.h"
mtkleinb3e5e4d2015-03-25 13:13:43 -070014#include "SkData.h"
mtklein748ca3b2015-01-15 10:56:12 -080015#include "SkDocument.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080016#include "SkError.h"
mtkleine44b5082015-05-07 10:53:34 -070017#include "SkFunction.h"
mtkleinb3e5e4d2015-03-25 13:13:43 -070018#include "SkImageGenerator.h"
mtklein748ca3b2015-01-15 10:56:12 -080019#include "SkMultiPictureDraw.h"
mtkleinad66f9b2015-02-13 15:11:10 -080020#include "SkNullCanvas.h"
mtklein748ca3b2015-01-15 10:56:12 -080021#include "SkOSFile.h"
mtkleinffa901a2015-03-16 10:38:07 -070022#include "SkPictureData.h"
mtklein748ca3b2015-01-15 10:56:12 -080023#include "SkPictureRecorder.h"
24#include "SkRandom.h"
mtkleind31c13d2015-05-05 12:59:56 -070025#include "SkRecordDraw.h"
26#include "SkRecorder.h"
mtklein2e2ea382015-10-16 10:29:41 -070027#include "SkRemote.h"
fmalita2aafe6f2015-02-06 12:51:10 -080028#include "SkSVGCanvas.h"
scroggoa1193e42015-01-21 12:09:53 -080029#include "SkStream.h"
mtklein449d9b72015-09-28 10:33:02 -070030#include "SkTLogic.h"
fmalita2aafe6f2015-02-06 12:51:10 -080031#include "SkXMLWriter.h"
msarette6dd0042015-10-09 11:07:34 -070032#include "SkSwizzler.h"
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
msaretta5783ae2015-09-08 15:35:32 -070070BRDSrc::BRDSrc(Path path, SkBitmapRegionDecoderInterface::Strategy strategy, Mode mode,
71 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
85static SkBitmapRegionDecoderInterface* create_brd(Path path,
86 SkBitmapRegionDecoderInterface::Strategy strategy) {
87 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str()));
88 if (!encoded) {
89 return NULL;
90 }
msarett26ad17b2015-10-22 07:29:19 -070091 return SkBitmapRegionDecoderInterface::CreateBitmapRegionDecoder(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
111 SkAutoTDelete<SkBitmapRegionDecoderInterface> brd(create_brd(fPath, fStrategy));
112 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)) {
117 return Error::Nonfatal("Cannot convert to color type.\n");
118 }
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: {
128 SkAutoTDelete<SkBitmap> bitmap(brd->decodeRegion(0, 0, width, height, fSampleSize,
129 colorType));
130 if (nullptr == bitmap.get() || colorType != bitmap->colorType()) {
131 return Error::Nonfatal("Cannot convert to color type.\n");
132 }
133 canvas->drawBitmap(*bitmap, 0, 0);
134 return "";
135 }
136 case kDivisor_Mode: {
137 const uint32_t divisor = 2;
138 if (width < divisor || height < divisor) {
139 return Error::Nonfatal("Divisor is larger than image dimension.\n");
140 }
141
142 // Use a border to test subsets that extend outside the image.
143 // We will not allow the border to be larger than the image dimensions. Allowing
144 // these large borders causes off by one errors that indicate a problem with the
145 // test suite, not a problem with the implementation.
146 const uint32_t maxBorder = SkTMin(width, height) / (fSampleSize * divisor);
147 const uint32_t scaledBorder = SkTMin(5u, maxBorder);
148 const uint32_t unscaledBorder = scaledBorder * fSampleSize;
149
150 // We may need to clear the canvas to avoid uninitialized memory.
151 // Assume we are scaling a 780x780 image with sampleSize = 8.
152 // The output image should be 97x97.
153 // Each subset will be 390x390.
154 // Each scaled subset be 48x48.
155 // Four scaled subsets will only fill a 96x96 image.
156 // The bottom row and last column will not be touched.
157 // This is an unfortunate result of our rounding rules when scaling.
158 // Maybe we need to consider testing scaled subsets without trying to
159 // combine them to match the full scaled image? Or maybe this is the
160 // best we can do?
161 canvas->clear(0);
162
163 for (uint32_t x = 0; x < divisor; x++) {
164 for (uint32_t y = 0; y < divisor; y++) {
165 // Calculate the subset dimensions
166 uint32_t subsetWidth = width / divisor;
167 uint32_t subsetHeight = height / divisor;
168 const int left = x * subsetWidth;
169 const int top = y * subsetHeight;
170
171 // Increase the size of the last subset in each row or column, when the
172 // divisor does not divide evenly into the image dimensions
173 subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0;
174 subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0;
175
176 // Increase the size of the subset in order to have a border on each side
177 const int decodeLeft = left - unscaledBorder;
178 const int decodeTop = top - unscaledBorder;
179 const uint32_t decodeWidth = subsetWidth + unscaledBorder * 2;
180 const uint32_t decodeHeight = subsetHeight + unscaledBorder * 2;
181 SkAutoTDelete<SkBitmap> bitmap(brd->decodeRegion(decodeLeft,
182 decodeTop, decodeWidth, decodeHeight, fSampleSize, colorType));
183 if (nullptr == bitmap.get() || colorType != bitmap->colorType()) {
184 return Error::Nonfatal("Cannot convert to color type.\n");
185 }
186
187 canvas->drawBitmapRect(*bitmap,
188 SkRect::MakeXYWH((SkScalar) scaledBorder, (SkScalar) scaledBorder,
189 (SkScalar) (subsetWidth / fSampleSize),
190 (SkScalar) (subsetHeight / fSampleSize)),
191 SkRect::MakeXYWH((SkScalar) (left / fSampleSize),
192 (SkScalar) (top / fSampleSize),
193 (SkScalar) (subsetWidth / fSampleSize),
194 (SkScalar) (subsetHeight / fSampleSize)),
195 nullptr);
196 }
197 }
198 return "";
199 }
200 default:
201 SkASSERT(false);
202 return "Error: Should not be reached.\n";
203 }
204}
205
206SkISize BRDSrc::size() const {
207 SkAutoTDelete<SkBitmapRegionDecoderInterface> brd(create_brd(fPath, fStrategy));
208 if (brd) {
209 return SkISize::Make(SkTMax(1, brd->width() / (int) fSampleSize),
210 SkTMax(1, brd->height() / (int) fSampleSize));
211 }
212 return SkISize::Make(0, 0);
213}
214
215static SkString get_scaled_name(const Path& path, float scale) {
216 return SkStringPrintf("%s_%.3f", SkOSPath::Basename(path.c_str()).c_str(), scale);
217}
218
219Name BRDSrc::name() const {
220 // We will replicate the names used by CodecSrc so that images can
221 // be compared in Gold.
222 if (1 == fSampleSize) {
223 return SkOSPath::Basename(fPath.c_str());
224 }
msarett7f691442015-09-22 11:56:16 -0700225 return get_scaled_name(fPath, get_scale_from_sample_size(fSampleSize));
msaretta5783ae2015-09-08 15:35:32 -0700226}
227
228/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
229
msarett0a242972015-06-11 14:27:27 -0700230CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, float scale)
msarett438b2ad2015-04-09 12:43:10 -0700231 : fPath(path)
232 , fMode(mode)
233 , fDstColorType(dstColorType)
msarett0a242972015-06-11 14:27:27 -0700234 , fScale(scale)
msarett438b2ad2015-04-09 12:43:10 -0700235{}
mtklein748ca3b2015-01-15 10:56:12 -0800236
mtklein99cab4e2015-07-31 06:43:04 -0700237bool CodecSrc::veto(SinkFlags flags) const {
238 // No need to test decoding to non-raster or indirect backend.
mtkleine0effd62015-07-29 06:37:28 -0700239 // TODO: Once we implement GPU paths (e.g. JPEG YUV), we should use a deferred decode to
240 // let the GPU handle it.
mtklein99cab4e2015-07-31 06:43:04 -0700241 return flags.type != SinkFlags::kRaster
242 || flags.approach != SinkFlags::kDirect;
mtkleine0effd62015-07-29 06:37:28 -0700243}
scroggo9b77ddd2015-03-19 06:03:39 -0700244
msarett3d9d7a72015-10-21 10:27:10 -0700245bool get_decode_info(SkImageInfo* decodeInfo, const SkImageInfo& defaultInfo,
246 SkColorType canvasColorType, CodecSrc::DstColorType dstColorType) {
247 switch (dstColorType) {
248 case CodecSrc::kIndex8_Always_DstColorType:
249 if (kRGB_565_SkColorType == canvasColorType) {
250 return false;
251 }
252 *decodeInfo = defaultInfo.makeColorType(kIndex_8_SkColorType);
253 break;
254 case CodecSrc::kGrayscale_Always_DstColorType:
255 if (kRGB_565_SkColorType == canvasColorType) {
256 return false;
257 }
258 *decodeInfo = defaultInfo.makeColorType(kGray_8_SkColorType);
259 break;
260 default:
261 *decodeInfo = defaultInfo.makeColorType(canvasColorType);
262 break;
263 }
264
265 // FIXME: Currently we cannot draw unpremultiplied sources.
266 if (decodeInfo->alphaType() == kUnpremul_SkAlphaType) {
267 decodeInfo->makeAlphaType(kPremul_SkAlphaType);
268 }
269 return true;
270}
271
mtkleine0effd62015-07-29 06:37:28 -0700272Error CodecSrc::draw(SkCanvas* canvas) const {
mtklein75d98fd2015-01-18 07:05:01 -0800273 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
mtklein748ca3b2015-01-15 10:56:12 -0800274 if (!encoded) {
275 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
276 }
msarett3d9d7a72015-10-21 10:27:10 -0700277 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
msarett9e707a02015-09-01 14:57:57 -0700278 if (nullptr == codec.get()) {
279 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
scroggo9b77ddd2015-03-19 06:03:39 -0700280 }
281
msarett3d9d7a72015-10-21 10:27:10 -0700282 SkImageInfo decodeInfo;
283 if (!get_decode_info(&decodeInfo, codec->getInfo(), canvas->imageInfo().colorType(),
284 fDstColorType)) {
285 return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
msarett438b2ad2015-04-09 12:43:10 -0700286 }
287
msarett0a242972015-06-11 14:27:27 -0700288 // Try to scale the image if it is desired
289 SkISize size = codec->getScaledDimensions(fScale);
290 if (size == decodeInfo.dimensions() && 1.0f != fScale) {
291 return Error::Nonfatal("Test without scaling is uninteresting.");
292 }
msarettb32758a2015-08-18 13:22:46 -0700293
294 // Visually inspecting very small output images is not necessary. We will
295 // cover these cases in unit testing.
296 if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) {
297 return Error::Nonfatal("Scaling very small images is uninteresting.");
298 }
msarett0a242972015-06-11 14:27:27 -0700299 decodeInfo = decodeInfo.makeWH(size.width(), size.height());
300
msarett438b2ad2015-04-09 12:43:10 -0700301 // Construct a color table for the decode if necessary
halcanary96fcdcc2015-08-27 07:41:13 -0700302 SkAutoTUnref<SkColorTable> colorTable(nullptr);
303 SkPMColor* colorPtr = nullptr;
304 int* colorCountPtr = nullptr;
msarett438b2ad2015-04-09 12:43:10 -0700305 int maxColors = 256;
306 if (kIndex_8_SkColorType == decodeInfo.colorType()) {
307 SkPMColor colors[256];
halcanary385fe4d2015-08-26 13:07:48 -0700308 colorTable.reset(new SkColorTable(colors, maxColors));
msarett438b2ad2015-04-09 12:43:10 -0700309 colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
310 colorCountPtr = &maxColors;
311 }
312
scroggo9b77ddd2015-03-19 06:03:39 -0700313 SkBitmap bitmap;
halcanary96fcdcc2015-08-27 07:41:13 -0700314 if (!bitmap.tryAllocPixels(decodeInfo, nullptr, colorTable.get())) {
scroggo9b77ddd2015-03-19 06:03:39 -0700315 return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str(),
316 decodeInfo.width(), decodeInfo.height());
317 }
318
scroggo9c59ebc2015-03-25 13:48:49 -0700319 switch (fMode) {
msarett9e707a02015-09-01 14:57:57 -0700320 case kCodec_Mode: {
halcanary96fcdcc2015-08-27 07:41:13 -0700321 switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(), nullptr,
msarett438b2ad2015-04-09 12:43:10 -0700322 colorPtr, colorCountPtr)) {
scroggoeb602a52015-07-09 08:16:03 -0700323 case SkCodec::kSuccess:
scroggo9c59ebc2015-03-25 13:48:49 -0700324 // We consider incomplete to be valid, since we should still decode what is
325 // available.
scroggoeb602a52015-07-09 08:16:03 -0700326 case SkCodec::kIncompleteInput:
scroggo9c59ebc2015-03-25 13:48:49 -0700327 break;
scroggoeb602a52015-07-09 08:16:03 -0700328 case SkCodec::kInvalidConversion:
scroggo9c59ebc2015-03-25 13:48:49 -0700329 return Error::Nonfatal("Incompatible colortype conversion");
330 default:
331 // Everything else is considered a failure.
332 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
333 }
emmaleer97002062015-05-27 12:36:10 -0700334 canvas->drawBitmap(bitmap, 0, 0);
scroggo9c59ebc2015-03-25 13:48:49 -0700335 break;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700336 }
scroggo9c59ebc2015-03-25 13:48:49 -0700337 case kScanline_Mode: {
scroggo46c57472015-09-30 08:57:13 -0700338 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr,
339 colorCountPtr)) {
msarett9e707a02015-09-01 14:57:57 -0700340 return Error::Nonfatal("Could not start scanline decoder");
scroggo9c59ebc2015-03-25 13:48:49 -0700341 }
scroggo1c005e42015-08-04 09:24:45 -0700342
msarette6dd0042015-10-09 11:07:34 -0700343 void* dst = bitmap.getAddr(0, 0);
344 size_t rowBytes = bitmap.rowBytes();
345 uint32_t height = decodeInfo.height();
scroggo46c57472015-09-30 08:57:13 -0700346 switch (codec->getScanlineOrder()) {
347 case SkCodec::kTopDown_SkScanlineOrder:
348 case SkCodec::kBottomUp_SkScanlineOrder:
349 case SkCodec::kNone_SkScanlineOrder:
msarette6dd0042015-10-09 11:07:34 -0700350 // We do not need to check the return value. On an incomplete
351 // image, memory will be filled with a default value.
352 codec->getScanlines(dst, height, rowBytes);
msarett10522ff2015-09-07 08:54:01 -0700353 break;
scroggo46c57472015-09-30 08:57:13 -0700354 case SkCodec::kOutOfOrder_SkScanlineOrder: {
msarett10522ff2015-09-07 08:54:01 -0700355 for (int y = 0; y < decodeInfo.height(); y++) {
msarette6dd0042015-10-09 11:07:34 -0700356 int dstY = codec->outputScanline(y);
msarett10522ff2015-09-07 08:54:01 -0700357 void* dstPtr = bitmap.getAddr(0, dstY);
msarette6dd0042015-10-09 11:07:34 -0700358 // We complete the loop, even if this call begins to fail
359 // due to an incomplete image. This ensures any uninitialized
360 // memory will be filled with the proper value.
361 codec->getScanlines(dstPtr, 1, bitmap.rowBytes());
msarett10522ff2015-09-07 08:54:01 -0700362 }
363 break;
364 }
365 }
366
emmaleer97002062015-05-27 12:36:10 -0700367 canvas->drawBitmap(bitmap, 0, 0);
368 break;
369 }
370 case kScanline_Subset_Mode: {
371 //this mode decodes the image in divisor*divisor subsets, using a scanline decoder
372 const int divisor = 2;
373 const int w = decodeInfo.width();
374 const int h = decodeInfo.height();
emmaleer97002062015-05-27 12:36:10 -0700375 if (divisor > w || divisor > h) {
msarett70542572015-06-19 07:44:05 -0700376 return Error::Nonfatal(SkStringPrintf("Cannot decode subset: divisor %d is too big"
377 "for %s with dimensions (%d x %d)", divisor, fPath.c_str(), w, h));
emmaleer97002062015-05-27 12:36:10 -0700378 }
379 const int subsetWidth = w/divisor;
380 const int subsetHeight = h/divisor;
381 // One of our subsets will be larger to contain any pixels that do not divide evenly.
382 const int extraX = w % divisor;
383 const int extraY = h % divisor;
384 /*
385 * if w or h are not evenly divided by divisor need to adjust width and height of end
386 * subsets to cover entire image.
387 * Add extraX and extraY to largestSubsetBm's width and height to adjust width
388 * and height of end subsets.
389 * subsetBm is extracted from largestSubsetBm.
390 * subsetBm's size is determined based on the current subset and may be larger for end
391 * subsets.
392 */
msarett0a242972015-06-11 14:27:27 -0700393 SkImageInfo largestSubsetDecodeInfo =
emmaleer97002062015-05-27 12:36:10 -0700394 decodeInfo.makeWH(subsetWidth + extraX, subsetHeight + extraY);
395 SkBitmap largestSubsetBm;
msarett9e707a02015-09-01 14:57:57 -0700396 if (!largestSubsetBm.tryAllocPixels(largestSubsetDecodeInfo, nullptr,
397 colorTable.get())) {
emmaleer97002062015-05-27 12:36:10 -0700398 return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str(),
399 largestSubsetDecodeInfo.width(), largestSubsetDecodeInfo.height());
400 }
emmaleer97002062015-05-27 12:36:10 -0700401 for (int col = 0; col < divisor; col++) {
402 //currentSubsetWidth may be larger than subsetWidth for rightmost subsets
403 const int currentSubsetWidth = (col + 1 == divisor) ?
404 subsetWidth + extraX : subsetWidth;
405 const int x = col * subsetWidth;
406 for (int row = 0; row < divisor; row++) {
407 //currentSubsetHeight may be larger than subsetHeight for bottom subsets
408 const int currentSubsetHeight = (row + 1 == divisor) ?
409 subsetHeight + extraY : subsetHeight;
410 const int y = row * subsetHeight;
411 //create scanline decoder for each subset
msarettfdb47572015-10-13 12:50:14 -0700412 SkCodec::Options options;
413 SkIRect subset = SkIRect::MakeXYWH(x, 0, currentSubsetWidth, h);
414 options.fSubset = &subset;
415 // TODO (msarett): Support this mode for all scanline orderings.
416 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &options,
417 colorPtr, colorCountPtr) ||
418 SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOrder()) {
emmaleer97002062015-05-27 12:36:10 -0700419 if (x == 0 && y == 0) {
420 //first try, image may not be compatible
msarett5406d6f2015-08-31 06:55:13 -0700421 return Error::Nonfatal("Could not start top-down scanline decoder");
emmaleer97002062015-05-27 12:36:10 -0700422 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700423 return "Error scanline decoder is nullptr";
emmaleer97002062015-05-27 12:36:10 -0700424 }
425 }
msarette6dd0042015-10-09 11:07:34 -0700426 // Skip to the first line of subset. We ignore the result value here.
427 // If the skip value fails, this will indicate an incomplete image.
428 // This means that the call to getScanlines() will also fail, but it
429 // will fill the buffer with a default value, so we can still draw the
430 // image.
431 codec->skipScanlines(y);
432
emmaleer97002062015-05-27 12:36:10 -0700433 //create and set size of subsetBm
434 SkBitmap subsetBm;
scroggo6634cbb2015-09-30 13:01:55 -0700435 SkIRect bounds = SkIRect::MakeWH(currentSubsetWidth, currentSubsetHeight);
emmaleer97002062015-05-27 12:36:10 -0700436 SkAssertResult(largestSubsetBm.extractSubset(&subsetBm, bounds));
msarettfdb47572015-10-13 12:50:14 -0700437 SkAutoLockPixels autolock(subsetBm, true);
438 codec->getScanlines(subsetBm.getAddr(0, 0), currentSubsetHeight,
439 subsetBm.rowBytes());
scroggo4358f132015-07-30 11:33:04 -0700440 subsetBm.notifyPixelsChanged();
emmaleer97002062015-05-27 12:36:10 -0700441 canvas->drawBitmap(subsetBm, SkIntToScalar(x), SkIntToScalar(y));
442 }
443 }
scroggo9c59ebc2015-03-25 13:48:49 -0700444 break;
445 }
msarett0a242972015-06-11 14:27:27 -0700446 case kStripe_Mode: {
447 const int height = decodeInfo.height();
448 // This value is chosen arbitrarily. We exercise more cases by choosing a value that
449 // does not align with image blocks.
450 const int stripeHeight = 37;
451 const int numStripes = (height + stripeHeight - 1) / stripeHeight;
452
453 // Decode odd stripes
scroggo46c57472015-09-30 08:57:13 -0700454 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr,
455 colorCountPtr)
456 || SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOrder()) {
msarett9e707a02015-09-01 14:57:57 -0700457 // This mode was designed to test the new skip scanlines API in libjpeg-turbo.
458 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting
459 // to run this test for image types that do not have this scanline ordering.
msarett5406d6f2015-08-31 06:55:13 -0700460 return Error::Nonfatal("Could not start top-down scanline decoder");
msarett0a242972015-06-11 14:27:27 -0700461 }
msarette6dd0042015-10-09 11:07:34 -0700462
msarett0a242972015-06-11 14:27:27 -0700463 for (int i = 0; i < numStripes; i += 2) {
464 // Skip a stripe
465 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight);
msarette6dd0042015-10-09 11:07:34 -0700466 codec->skipScanlines(linesToSkip);
msarett0a242972015-06-11 14:27:27 -0700467
468 // Read a stripe
469 const int startY = (i + 1) * stripeHeight;
470 const int linesToRead = SkTMin(stripeHeight, height - startY);
471 if (linesToRead > 0) {
msarette6dd0042015-10-09 11:07:34 -0700472 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes());
msarett0a242972015-06-11 14:27:27 -0700473 }
474 }
475
476 // Decode even stripes
scroggo46c57472015-09-30 08:57:13 -0700477 const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo, nullptr,
478 colorPtr, colorCountPtr);
scroggo1c005e42015-08-04 09:24:45 -0700479 if (SkCodec::kSuccess != startResult) {
480 return "Failed to restart scanline decoder with same parameters.";
msarett0a242972015-06-11 14:27:27 -0700481 }
482 for (int i = 0; i < numStripes; i += 2) {
483 // Read a stripe
484 const int startY = i * stripeHeight;
485 const int linesToRead = SkTMin(stripeHeight, height - startY);
msarette6dd0042015-10-09 11:07:34 -0700486 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes());
msarett0a242972015-06-11 14:27:27 -0700487
488 // Skip a stripe
msarettf6db27e2015-06-12 09:34:04 -0700489 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight);
490 if (linesToSkip > 0) {
msarette6dd0042015-10-09 11:07:34 -0700491 codec->skipScanlines(linesToSkip);
msarett0a242972015-06-11 14:27:27 -0700492 }
493 }
494 canvas->drawBitmap(bitmap, 0, 0);
emmaleer0a4c3cb2015-06-22 10:40:21 -0700495 break;
msarett0a242972015-06-11 14:27:27 -0700496 }
scroggob636b452015-07-22 07:16:20 -0700497 case kSubset_Mode: {
498 // Arbitrarily choose a divisor.
499 int divisor = 2;
500 // Total width/height of the image.
501 const int W = codec->getInfo().width();
502 const int H = codec->getInfo().height();
503 if (divisor > W || divisor > H) {
504 return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divisor %d is too big "
505 "for %s with dimensions (%d x %d)", divisor,
506 fPath.c_str(), W, H));
507 }
508 // subset dimensions
509 // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
510 const int w = SkAlign2(W / divisor);
511 const int h = SkAlign2(H / divisor);
512 SkIRect subset;
513 SkCodec::Options opts;
514 opts.fSubset = &subset;
515 SkBitmap subsetBm;
516 // We will reuse pixel memory from bitmap.
517 void* pixels = bitmap.getPixels();
518 // Keep track of left and top (for drawing subsetBm into canvas). We could use
519 // fScale * x and fScale * y, but we want integers such that the next subset will start
520 // where the last one ended. So we'll add decodeInfo.width() and height().
521 int left = 0;
522 for (int x = 0; x < W; x += w) {
523 int top = 0;
524 for (int y = 0; y < H; y+= h) {
525 // Do not make the subset go off the edge of the image.
526 const int preScaleW = SkTMin(w, W - x);
527 const int preScaleH = SkTMin(h, H - y);
528 subset.setXYWH(x, y, preScaleW, preScaleH);
529 // And scale
530 // FIXME: Should we have a version of getScaledDimensions that takes a subset
531 // into account?
msarette6dd0042015-10-09 11:07:34 -0700532 decodeInfo = decodeInfo.makeWH(
533 SkTMax(1, SkScalarRoundToInt(preScaleW * fScale)),
534 SkTMax(1, SkScalarRoundToInt(preScaleH * fScale)));
scroggob636b452015-07-22 07:16:20 -0700535 size_t rowBytes = decodeInfo.minRowBytes();
536 if (!subsetBm.installPixels(decodeInfo, pixels, rowBytes, colorTable.get(),
halcanary96fcdcc2015-08-27 07:41:13 -0700537 nullptr, nullptr)) {
scroggob636b452015-07-22 07:16:20 -0700538 return SkStringPrintf("could not install pixels for %s.", fPath.c_str());
539 }
540 const SkCodec::Result result = codec->getPixels(decodeInfo, pixels, rowBytes,
541 &opts, colorPtr, colorCountPtr);
542 switch (result) {
543 case SkCodec::kSuccess:
544 case SkCodec::kIncompleteInput:
545 break;
546 case SkCodec::kInvalidConversion:
547 if (0 == (x|y)) {
548 // First subset is okay to return unimplemented.
549 return Error::Nonfatal("Incompatible colortype conversion");
550 }
551 // If the first subset succeeded, a later one should not fail.
552 // fall through to failure
553 case SkCodec::kUnimplemented:
554 if (0 == (x|y)) {
555 // First subset is okay to return unimplemented.
556 return Error::Nonfatal("subset codec not supported");
557 }
558 // If the first subset succeeded, why would a later one fail?
559 // fall through to failure
560 default:
561 return SkStringPrintf("subset codec failed to decode (%d, %d, %d, %d) "
562 "from %s with dimensions (%d x %d)\t error %d",
563 x, y, decodeInfo.width(), decodeInfo.height(),
564 fPath.c_str(), W, H, result);
565 }
566 canvas->drawBitmap(subsetBm, SkIntToScalar(left), SkIntToScalar(top));
567 // translate by the scaled height.
568 top += decodeInfo.height();
569 }
570 // translate by the scaled width.
571 left += decodeInfo.width();
572 }
573 return "";
574 }
scroggo9b77ddd2015-03-19 06:03:39 -0700575 }
scroggo9c59ebc2015-03-25 13:48:49 -0700576 return "";
scroggo9b77ddd2015-03-19 06:03:39 -0700577}
578
579SkISize CodecSrc::size() const {
580 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
msarett3d9d7a72015-10-21 10:27:10 -0700581 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
scroggo7fac5af2015-09-30 11:33:12 -0700582 if (nullptr == codec) {
583 return SkISize::Make(0, 0);
584 }
585 return codec->getScaledDimensions(fScale);
scroggo9b77ddd2015-03-19 06:03:39 -0700586}
587
588Name CodecSrc::name() const {
msarett0a242972015-06-11 14:27:27 -0700589 if (1.0f == fScale) {
590 return SkOSPath::Basename(fPath.c_str());
msarett0a242972015-06-11 14:27:27 -0700591 }
msaretta5783ae2015-09-08 15:35:32 -0700592 return get_scaled_name(fPath, fScale);
scroggo9b77ddd2015-03-19 06:03:39 -0700593}
594
595/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
596
msarett3d9d7a72015-10-21 10:27:10 -0700597AndroidCodecSrc::AndroidCodecSrc(Path path, Mode mode, CodecSrc::DstColorType dstColorType,
598 int sampleSize)
599 : fPath(path)
600 , fMode(mode)
601 , fDstColorType(dstColorType)
602 , fSampleSize(sampleSize)
603{}
604
605bool AndroidCodecSrc::veto(SinkFlags flags) const {
606 // No need to test decoding to non-raster or indirect backend.
607 // TODO: Once we implement GPU paths (e.g. JPEG YUV), we should use a deferred decode to
608 // let the GPU handle it.
609 return flags.type != SinkFlags::kRaster
610 || flags.approach != SinkFlags::kDirect;
611}
612
613Error AndroidCodecSrc::draw(SkCanvas* canvas) const {
614 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
615 if (!encoded) {
616 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
617 }
618 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded));
619 if (nullptr == codec.get()) {
620 return SkStringPrintf("Couldn't create android codec for %s.", fPath.c_str());
621 }
622
623 SkImageInfo decodeInfo;
624 if (!get_decode_info(&decodeInfo, codec->getInfo(), canvas->imageInfo().colorType(),
625 fDstColorType)) {
626 return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
627 }
628
629 // Scale the image if it is desired.
630 SkISize size = codec->getSampledDimensions(fSampleSize);
631
632 // Visually inspecting very small output images is not necessary. We will
633 // cover these cases in unit testing.
634 if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) {
635 return Error::Nonfatal("Scaling very small images is uninteresting.");
636 }
637 decodeInfo = decodeInfo.makeWH(size.width(), size.height());
638
639 // Construct a color table for the decode if necessary
640 SkAutoTUnref<SkColorTable> colorTable(nullptr);
641 SkPMColor* colorPtr = nullptr;
642 int* colorCountPtr = nullptr;
643 int maxColors = 256;
644 if (kIndex_8_SkColorType == decodeInfo.colorType()) {
645 SkPMColor colors[256];
646 colorTable.reset(new SkColorTable(colors, maxColors));
647 colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
648 colorCountPtr = &maxColors;
649 }
650
651 SkBitmap bitmap;
652 if (!bitmap.tryAllocPixels(decodeInfo, nullptr, colorTable.get())) {
653 return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str(),
654 decodeInfo.width(), decodeInfo.height());
655 }
656
657 // Create options for the codec.
658 SkAndroidCodec::AndroidOptions options;
659 options.fColorPtr = colorPtr;
660 options.fColorCount = colorCountPtr;
661 options.fSampleSize = fSampleSize;
662
663 switch (fMode) {
664 case kFullImage_Mode: {
665 switch (codec->getAndroidPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(),
666 &options)) {
667 case SkCodec::kSuccess:
668 case SkCodec::kIncompleteInput:
669 break;
670 case SkCodec::kInvalidConversion:
671 return Error::Nonfatal("Cannot convert to requested color type.\n");
672 default:
673 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
674 }
675 canvas->drawBitmap(bitmap, 0, 0);
676 return "";
677 }
678 case kDivisor_Mode: {
679 const int width = codec->getInfo().width();
680 const int height = codec->getInfo().height();
681 const int divisor = 2;
682 if (width < divisor || height < divisor) {
683 return Error::Nonfatal("Divisor is larger than image dimension.\n");
684 }
685
msarettfa23a9e2015-10-21 13:26:59 -0700686 // Keep track of the final decoded dimensions.
687 int finalScaledWidth = 0;
688 int finalScaledHeight = 0;
msarett3d9d7a72015-10-21 10:27:10 -0700689 for (int x = 0; x < divisor; x++) {
690 for (int y = 0; y < divisor; y++) {
691 // Calculate the subset dimensions
692 int subsetWidth = width / divisor;
693 int subsetHeight = height / divisor;
694 const int left = x * subsetWidth;
695 const int top = y * subsetHeight;
696
697 // Increase the size of the last subset in each row or column, when the
698 // divisor does not divide evenly into the image dimensions
699 subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0;
700 subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0;
701 SkIRect subset = SkIRect::MakeXYWH(left, top, subsetWidth, subsetHeight);
702 if (!codec->getSupportedSubset(&subset)) {
703 return "Could not get supported subset to decode.\n";
704 }
705 options.fSubset = &subset;
msarettfa23a9e2015-10-21 13:26:59 -0700706 const int scaledWidthOffset = subset.left() / fSampleSize;
707 const int scaledHeightOffset = subset.top() / fSampleSize;
708 void* pixels = bitmap.getAddr(scaledWidthOffset, scaledHeightOffset);
msarett3d9d7a72015-10-21 10:27:10 -0700709 SkISize scaledSubsetSize = codec->getSampledSubsetDimensions(fSampleSize,
710 subset);
711 SkImageInfo subsetDecodeInfo = decodeInfo.makeWH(scaledSubsetSize.width(),
712 scaledSubsetSize.height());
713
msarettfa23a9e2015-10-21 13:26:59 -0700714 if (x + 1 == divisor && y + 1 == divisor) {
715 finalScaledWidth = scaledWidthOffset + scaledSubsetSize.width();
716 finalScaledHeight = scaledHeightOffset + scaledSubsetSize.height();
717 }
718
msarett3d9d7a72015-10-21 10:27:10 -0700719 switch (codec->getAndroidPixels(subsetDecodeInfo, pixels, bitmap.rowBytes(),
720 &options)) {
721 case SkCodec::kSuccess:
722 case SkCodec::kIncompleteInput:
723 break;
724 case SkCodec::kInvalidConversion:
725 return Error::Nonfatal("Cannot convert to requested color type.\n");
726 default:
727 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
728 }
729 }
730 }
msarettfa23a9e2015-10-21 13:26:59 -0700731
732 SkRect rect = SkRect::MakeXYWH(0, 0, (SkScalar) finalScaledWidth,
733 (SkScalar) finalScaledHeight);
734 canvas->drawBitmapRect(bitmap, rect, rect, nullptr);
msarett3d9d7a72015-10-21 10:27:10 -0700735 return "";
736 }
737 default:
738 SkASSERT(false);
739 return "Error: Should not be reached.\n";
740 }
741}
742
743SkISize AndroidCodecSrc::size() const {
744 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
745 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded));
746 if (nullptr == codec) {
747 return SkISize::Make(0, 0);
748 }
749 return codec->getSampledDimensions(fSampleSize);
750}
751
752Name AndroidCodecSrc::name() const {
753 // We will replicate the names used by CodecSrc so that images can
754 // be compared in Gold.
755 if (1 == fSampleSize) {
756 return SkOSPath::Basename(fPath.c_str());
757 }
758 return get_scaled_name(fPath, get_scale_from_sample_size(fSampleSize));
759}
760
761/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
762
scroggo9b77ddd2015-03-19 06:03:39 -0700763ImageSrc::ImageSrc(Path path, int divisor) : fPath(path), fDivisor(divisor) {}
764
mtklein99cab4e2015-07-31 06:43:04 -0700765bool ImageSrc::veto(SinkFlags flags) const {
766 // No need to test decoding to non-raster or indirect backend.
mtkleine0effd62015-07-29 06:37:28 -0700767 // TODO: Instead, use lazy decoding to allow the GPU to handle cases like YUV.
mtklein99cab4e2015-07-31 06:43:04 -0700768 return flags.type != SinkFlags::kRaster
769 || flags.approach != SinkFlags::kDirect;
mtkleine0effd62015-07-29 06:37:28 -0700770}
scroggo9b77ddd2015-03-19 06:03:39 -0700771
mtkleine0effd62015-07-29 06:37:28 -0700772Error ImageSrc::draw(SkCanvas* canvas) const {
scroggo9b77ddd2015-03-19 06:03:39 -0700773 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
774 if (!encoded) {
775 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
776 }
mtkleine0effd62015-07-29 06:37:28 -0700777 const SkColorType dstColorType = canvas->imageInfo().colorType();
mtkleinedc93bc2015-01-30 13:22:23 -0800778 if (fDivisor == 0) {
mtklein748ca3b2015-01-15 10:56:12 -0800779 // Decode the full image.
780 SkBitmap bitmap;
scroggo9b77ddd2015-03-19 06:03:39 -0700781 if (!SkImageDecoder::DecodeMemory(encoded->data(), encoded->size(), &bitmap,
782 dstColorType, SkImageDecoder::kDecodePixels_Mode)) {
783 return SkStringPrintf("Couldn't decode %s.", fPath.c_str());
784 }
785 if (kRGB_565_SkColorType == dstColorType && !bitmap.isOpaque()) {
786 // Do not draw a bitmap with alpha to a destination without alpha.
787 return Error::Nonfatal("Uninteresting to decode image with alpha into 565.");
mtklein748ca3b2015-01-15 10:56:12 -0800788 }
halcanary96fcdcc2015-08-27 07:41:13 -0700789 encoded.reset((SkData*)nullptr); // Might as well drop this when we're done with it.
mtklein748ca3b2015-01-15 10:56:12 -0800790 canvas->drawBitmap(bitmap, 0,0);
791 return "";
792 }
mtkleinedc93bc2015-01-30 13:22:23 -0800793 // Decode subsets. This is a little involved.
scroggoa1193e42015-01-21 12:09:53 -0800794 SkAutoTDelete<SkMemoryStream> stream(new SkMemoryStream(encoded));
795 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream.get()));
mtklein748ca3b2015-01-15 10:56:12 -0800796 if (!decoder) {
797 return SkStringPrintf("Can't find a good decoder for %s.", fPath.c_str());
798 }
scroggoa1193e42015-01-21 12:09:53 -0800799 stream->rewind();
mtklein748ca3b2015-01-15 10:56:12 -0800800 int w,h;
msarett70542572015-06-19 07:44:05 -0700801 if (!decoder->buildTileIndex(stream.detach(), &w, &h)) {
mtklein4089ef72015-03-05 08:40:28 -0800802 return Error::Nonfatal("Subset decoding not supported.");
mtklein748ca3b2015-01-15 10:56:12 -0800803 }
mtkleinedc93bc2015-01-30 13:22:23 -0800804
805 // Divide the image into subsets that cover the entire image.
806 if (fDivisor > w || fDivisor > h) {
msarett70542572015-06-19 07:44:05 -0700807 return Error::Nonfatal(SkStringPrintf("Cannot decode subset: divisor %d is too big"
808 "for %s with dimensions (%d x %d)", fDivisor, fPath.c_str(), w, h));
mtkleinedc93bc2015-01-30 13:22:23 -0800809 }
810 const int subsetWidth = w / fDivisor,
811 subsetHeight = h / fDivisor;
812 for (int y = 0; y < h; y += subsetHeight) {
813 for (int x = 0; x < w; x += subsetWidth) {
814 SkBitmap subset;
815 SkIRect rect = SkIRect::MakeXYWH(x, y, subsetWidth, subsetHeight);
816 if (!decoder->decodeSubset(&subset, rect, dstColorType)) {
817 return SkStringPrintf("Could not decode subset (%d, %d, %d, %d).",
818 x, y, x+subsetWidth, y+subsetHeight);
819 }
scroggo56e25dd2015-03-05 11:46:40 -0800820 if (kRGB_565_SkColorType == dstColorType && !subset.isOpaque()) {
821 // Do not draw a bitmap with alpha to a destination without alpha.
822 // This is not an error, but there is nothing interesting to show.
823
824 // This should only happen on the first iteration through the loop.
825 SkASSERT(0 == x && 0 == y);
826
827 return Error::Nonfatal("Uninteresting to decode image with alpha into 565.");
828 }
mtkleinedc93bc2015-01-30 13:22:23 -0800829 canvas->drawBitmap(subset, SkIntToScalar(x), SkIntToScalar(y));
mtklein748ca3b2015-01-15 10:56:12 -0800830 }
mtklein748ca3b2015-01-15 10:56:12 -0800831 }
832 return "";
833}
834
835SkISize ImageSrc::size() const {
mtklein75d98fd2015-01-18 07:05:01 -0800836 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
scroggo9b77ddd2015-03-19 06:03:39 -0700837 SkBitmap bitmap;
838 if (!encoded || !SkImageDecoder::DecodeMemory(encoded->data(),
839 encoded->size(),
840 &bitmap,
841 kUnknown_SkColorType,
842 SkImageDecoder::kDecodeBounds_Mode)) {
843 return SkISize::Make(0,0);
mtklein748ca3b2015-01-15 10:56:12 -0800844 }
scroggo9b77ddd2015-03-19 06:03:39 -0700845 return bitmap.dimensions();
mtklein748ca3b2015-01-15 10:56:12 -0800846}
847
mtklein9264a952015-01-20 10:11:53 -0800848Name ImageSrc::name() const {
mtkleinedc93bc2015-01-30 13:22:23 -0800849 return SkOSPath::Basename(fPath.c_str());
mtklein9264a952015-01-20 10:11:53 -0800850}
mtklein748ca3b2015-01-15 10:56:12 -0800851
852/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
853
mtkleinf4ba3212015-01-28 15:32:24 -0800854static const SkRect kSKPViewport = {0,0, 1000,1000};
855
mtklein8d17a132015-01-30 11:42:31 -0800856SKPSrc::SKPSrc(Path path) : fPath(path) {}
mtklein748ca3b2015-01-15 10:56:12 -0800857
858Error SKPSrc::draw(SkCanvas* canvas) const {
scroggoa1193e42015-01-21 12:09:53 -0800859 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str()));
mtklein75d98fd2015-01-18 07:05:01 -0800860 if (!stream) {
mtklein748ca3b2015-01-15 10:56:12 -0800861 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
862 }
mtkleinb3e5e4d2015-03-25 13:13:43 -0700863 SkAutoTUnref<SkPicture> pic(SkPicture::CreateFromStream(stream, &lazy_decode_bitmap));
mtklein75d98fd2015-01-18 07:05:01 -0800864 if (!pic) {
865 return SkStringPrintf("Couldn't decode %s as a picture.", fPath.c_str());
866 }
halcanary96fcdcc2015-08-27 07:41:13 -0700867 stream.reset((SkStream*)nullptr); // Might as well drop this when we're done with it.
joshualitt7c3a2f82015-03-31 13:32:05 -0700868
mtkleinf4ba3212015-01-28 15:32:24 -0800869 canvas->clipRect(kSKPViewport);
mtklein748ca3b2015-01-15 10:56:12 -0800870 canvas->drawPicture(pic);
871 return "";
872}
873
874SkISize SKPSrc::size() const {
mtkleinffa901a2015-03-16 10:38:07 -0700875 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str()));
876 if (!stream) {
877 return SkISize::Make(0,0);
878 }
879 SkPictInfo info;
880 if (!SkPicture::InternalOnly_StreamIsSKP(stream, &info)) {
881 return SkISize::Make(0,0);
882 }
883 SkRect viewport = kSKPViewport;
884 if (!viewport.intersect(info.fCullRect)) {
885 return SkISize::Make(0,0);
886 }
887 return viewport.roundOut().size();
mtklein748ca3b2015-01-15 10:56:12 -0800888}
889
890Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
891
892/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
893
mtkleinad66f9b2015-02-13 15:11:10 -0800894Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const {
895 SkAutoTDelete<SkCanvas> canvas(SkCreateNullCanvas());
896 return src.draw(canvas);
897}
898
899/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
900
mtkleinb9eb4ac2015-02-02 18:26:03 -0800901DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?");
902
mtklein82d28432015-01-15 12:46:02 -0800903GPUSink::GPUSink(GrContextFactory::GLContextType ct,
904 GrGLStandard api,
905 int samples,
bsalomonafcd7cd2015-08-31 12:39:41 -0700906 bool diText,
mtklein82d28432015-01-15 12:46:02 -0800907 bool threaded)
mtklein748ca3b2015-01-15 10:56:12 -0800908 : fContextType(ct)
909 , fGpuAPI(api)
910 , fSampleCount(samples)
bsalomonafcd7cd2015-08-31 12:39:41 -0700911 , fUseDIText(diText)
mtklein82d28432015-01-15 12:46:02 -0800912 , fThreaded(threaded) {}
mtklein748ca3b2015-01-15 10:56:12 -0800913
914int GPUSink::enclave() const {
mtklein55e88b22015-01-21 15:50:13 -0800915 return fThreaded ? kAnyThread_Enclave : kGPU_Enclave;
mtklein748ca3b2015-01-15 10:56:12 -0800916}
917
joshualitt5f5a8d72015-02-25 14:09:45 -0800918void PreAbandonGpuContextErrorHandler(SkError, void*) {}
919
bsalomon648c6962015-10-23 09:06:59 -0700920DEFINE_bool(imm, false, "Run gpu configs in immediate mode.");
921
mtkleinb9eb4ac2015-02-02 18:26:03 -0800922Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const {
bsalomon4ee6bd82015-05-27 13:23:23 -0700923 GrContextOptions options;
bsalomon648c6962015-10-23 09:06:59 -0700924 if (FLAGS_imm) {
925 options.fImmediateMode = true;
926 }
bsalomon4ee6bd82015-05-27 13:23:23 -0700927 src.modifyGrContextOptions(&options);
928
929 GrContextFactory factory(options);
mtkleinf4ba3212015-01-28 15:32:24 -0800930 const SkISize size = src.size();
mtklein748ca3b2015-01-15 10:56:12 -0800931 const SkImageInfo info =
932 SkImageInfo::Make(size.width(), size.height(), kN32_SkColorType, kPremul_SkAlphaType);
933 SkAutoTUnref<SkSurface> surface(
bsalomonafcd7cd2015-08-31 12:39:41 -0700934 NewGpuSurface(&factory, fContextType, fGpuAPI, info, fSampleCount, fUseDIText));
mtklein748ca3b2015-01-15 10:56:12 -0800935 if (!surface) {
936 return "Could not create a surface.";
937 }
joshualitt5f5a8d72015-02-25 14:09:45 -0800938 if (FLAGS_preAbandonGpuContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700939 SkSetErrorCallback(&PreAbandonGpuContextErrorHandler, nullptr);
joshualitt5f5a8d72015-02-25 14:09:45 -0800940 factory.abandonContexts();
941 }
mtklein748ca3b2015-01-15 10:56:12 -0800942 SkCanvas* canvas = surface->getCanvas();
943 Error err = src.draw(canvas);
944 if (!err.isEmpty()) {
945 return err;
946 }
947 canvas->flush();
mtkleinb9eb4ac2015-02-02 18:26:03 -0800948 if (FLAGS_gpuStats) {
949 canvas->getGrContext()->dumpCacheStats(log);
950 canvas->getGrContext()->dumpGpuStats(log);
951 }
mtklein748ca3b2015-01-15 10:56:12 -0800952 dst->allocPixels(info);
joshualitt5f5a8d72015-02-25 14:09:45 -0800953 canvas->readPixels(dst, 0, 0);
mtklein55e88b22015-01-21 15:50:13 -0800954 if (FLAGS_abandonGpuContext) {
955 factory.abandonContexts();
956 }
mtklein748ca3b2015-01-15 10:56:12 -0800957 return "";
958}
959
960/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
961
halcanary47ef4d52015-03-03 09:13:09 -0800962static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) {
963 // Print the given DM:Src to a document, breaking on 8.5x11 pages.
964 SkASSERT(doc);
halcanaryfd4a9932015-01-28 11:45:58 -0800965 int width = src.size().width(),
966 height = src.size().height();
967
halcanary7e798182015-04-14 14:06:18 -0700968 if (FLAGS_multiPage) {
969 const int kLetterWidth = 612, // 8.5 * 72
970 kLetterHeight = 792; // 11 * 72
971 const SkRect letter = SkRect::MakeWH(SkIntToScalar(kLetterWidth),
972 SkIntToScalar(kLetterHeight));
halcanaryfd4a9932015-01-28 11:45:58 -0800973
halcanary7e798182015-04-14 14:06:18 -0700974 int xPages = ((width - 1) / kLetterWidth) + 1;
975 int yPages = ((height - 1) / kLetterHeight) + 1;
halcanaryfd4a9932015-01-28 11:45:58 -0800976
halcanary7e798182015-04-14 14:06:18 -0700977 for (int y = 0; y < yPages; ++y) {
978 for (int x = 0; x < xPages; ++x) {
979 int w = SkTMin(kLetterWidth, width - (x * kLetterWidth));
980 int h = SkTMin(kLetterHeight, height - (y * kLetterHeight));
981 SkCanvas* canvas =
982 doc->beginPage(SkIntToScalar(w), SkIntToScalar(h));
983 if (!canvas) {
halcanary96fcdcc2015-08-27 07:41:13 -0700984 return "SkDocument::beginPage(w,h) returned nullptr";
halcanary7e798182015-04-14 14:06:18 -0700985 }
986 canvas->clipRect(letter);
987 canvas->translate(-letter.width() * x, -letter.height() * y);
988 Error err = src.draw(canvas);
989 if (!err.isEmpty()) {
990 return err;
991 }
992 doc->endPage();
djsollen2ab90002015-04-03 06:38:31 -0700993 }
halcanaryfd4a9932015-01-28 11:45:58 -0800994 }
halcanary7e798182015-04-14 14:06:18 -0700995 } else {
996 SkCanvas* canvas =
997 doc->beginPage(SkIntToScalar(width), SkIntToScalar(height));
998 if (!canvas) {
halcanary96fcdcc2015-08-27 07:41:13 -0700999 return "SkDocument::beginPage(w,h) returned nullptr";
halcanary7e798182015-04-14 14:06:18 -07001000 }
1001 Error err = src.draw(canvas);
1002 if (!err.isEmpty()) {
1003 return err;
1004 }
1005 doc->endPage();
mtklein748ca3b2015-01-15 10:56:12 -08001006 }
halcanary7e798182015-04-14 14:06:18 -07001007 if (!doc->close()) {
1008 return "SkDocument::close() returned false";
1009 }
halcanaryfd4a9932015-01-28 11:45:58 -08001010 dst->flush();
mtklein748ca3b2015-01-15 10:56:12 -08001011 return "";
1012}
1013
halcanaryc11c62f2015-09-28 11:51:54 -07001014PDFSink::PDFSink(const char* rasterizer) : fRasterizer(rasterizer) {}
halcanary47ef4d52015-03-03 09:13:09 -08001015
1016Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1017 SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(dst));
1018 if (!doc) {
halcanary96fcdcc2015-08-27 07:41:13 -07001019 return "SkDocument::CreatePDF() returned nullptr";
halcanary47ef4d52015-03-03 09:13:09 -08001020 }
halcanaryf12a1672015-09-23 12:45:49 -07001021 SkTArray<SkDocument::Attribute> info;
1022 info.emplace_back(SkString("Title"), src.name());
1023 info.emplace_back(SkString("Subject"),
1024 SkString("rendering correctness test"));
1025 info.emplace_back(SkString("Creator"), SkString("Skia/DM"));
halcanaryc11c62f2015-09-28 11:51:54 -07001026
1027 info.emplace_back(SkString("Keywords"),
1028 SkStringPrintf("Rasterizer:%s;", fRasterizer));
halcanaryf12a1672015-09-23 12:45:49 -07001029 doc->setMetadata(info, nullptr, nullptr);
halcanary47ef4d52015-03-03 09:13:09 -08001030 return draw_skdocument(src, doc.get(), dst);
1031}
1032
1033/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1034
1035XPSSink::XPSSink() {}
1036
1037Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1038 SkAutoTUnref<SkDocument> doc(SkDocument::CreateXPS(dst));
1039 if (!doc) {
halcanary96fcdcc2015-08-27 07:41:13 -07001040 return "SkDocument::CreateXPS() returned nullptr";
halcanary47ef4d52015-03-03 09:13:09 -08001041 }
1042 return draw_skdocument(src, doc.get(), dst);
1043}
mtklein748ca3b2015-01-15 10:56:12 -08001044/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1045
mtklein9c3f17d2015-01-28 11:35:18 -08001046SKPSink::SKPSink() {}
1047
mtkleinb9eb4ac2015-02-02 18:26:03 -08001048Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
mtklein9c3f17d2015-01-28 11:35:18 -08001049 SkSize size;
1050 size = src.size();
1051 SkPictureRecorder recorder;
1052 Error err = src.draw(recorder.beginRecording(size.width(), size.height()));
1053 if (!err.isEmpty()) {
1054 return err;
1055 }
1056 SkAutoTUnref<SkPicture> pic(recorder.endRecording());
1057 pic->serialize(dst);
1058 return "";
1059}
1060
1061/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1062
mtklein8a4527e2015-01-31 20:00:58 -08001063SVGSink::SVGSink() {}
1064
mtkleinb9eb4ac2015-02-02 18:26:03 -08001065Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
halcanary385fe4d2015-08-26 13:07:48 -07001066 SkAutoTDelete<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(dst));
fmalita2aafe6f2015-02-06 12:51:10 -08001067 SkAutoTUnref<SkCanvas> canvas(SkSVGCanvas::Create(
1068 SkRect::MakeWH(SkIntToScalar(src.size().width()), SkIntToScalar(src.size().height())),
1069 xmlWriter));
1070 return src.draw(canvas);
mtklein8a4527e2015-01-31 20:00:58 -08001071}
1072
1073/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1074
mtklein748ca3b2015-01-15 10:56:12 -08001075RasterSink::RasterSink(SkColorType colorType) : fColorType(colorType) {}
1076
mtkleinb9eb4ac2015-02-02 18:26:03 -08001077Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
mtkleinf4ba3212015-01-28 15:32:24 -08001078 const SkISize size = src.size();
mtklein748ca3b2015-01-15 10:56:12 -08001079 // If there's an appropriate alpha type for this color type, use it, otherwise use premul.
1080 SkAlphaType alphaType = kPremul_SkAlphaType;
1081 (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType);
1082
1083 dst->allocPixels(SkImageInfo::Make(size.width(), size.height(), fColorType, alphaType));
1084 dst->eraseColor(SK_ColorTRANSPARENT);
1085 SkCanvas canvas(*dst);
1086 return src.draw(&canvas);
1087}
1088
1089/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1090
mtkleina16e69e2015-05-05 11:38:45 -07001091// Handy for front-patching a Src. Do whatever up-front work you need, then call draw_to_canvas(),
mtkleine44b5082015-05-07 10:53:34 -07001092// passing the Sink draw() arguments, a size, and a function draws into an SkCanvas.
mtkleina16e69e2015-05-05 11:38:45 -07001093// Several examples below.
1094
mtkleina16e69e2015-05-05 11:38:45 -07001095static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log,
mtkleine44b5082015-05-07 10:53:34 -07001096 SkISize size, SkFunction<Error(SkCanvas*)> draw) {
mtkleina16e69e2015-05-05 11:38:45 -07001097 class ProxySrc : public Src {
1098 public:
mtkleine44b5082015-05-07 10:53:34 -07001099 ProxySrc(SkISize size, SkFunction<Error(SkCanvas*)> draw) : fSize(size), fDraw(draw) {}
mtkleina16e69e2015-05-05 11:38:45 -07001100 Error draw(SkCanvas* canvas) const override { return fDraw(canvas); }
1101 Name name() const override { sk_throw(); return ""; } // Won't be called.
1102 SkISize size() const override { return fSize; }
1103 private:
mtkleine44b5082015-05-07 10:53:34 -07001104 SkISize fSize;
1105 SkFunction<Error(SkCanvas*)> fDraw;
mtkleina16e69e2015-05-05 11:38:45 -07001106 };
1107 return sink->draw(ProxySrc(size, draw), bitmap, stream, log);
1108}
1109
1110/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1111
mtkleind603b222015-02-17 11:13:33 -08001112static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) {
1113 SkRect bounds = SkRect::MakeIWH(srcW, srcH);
1114 matrix->mapRect(&bounds);
1115 matrix->postTranslate(-bounds.x(), -bounds.y());
1116 return SkISize::Make(SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height()));
1117}
1118
mtklein78829242015-05-06 07:54:07 -07001119ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
mtklein748ca3b2015-01-15 10:56:12 -08001120
mtkleinb9eb4ac2015-02-02 18:26:03 -08001121Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtkleina16e69e2015-05-05 11:38:45 -07001122 SkMatrix matrix = fMatrix;
1123 SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height());
1124 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
1125 canvas->concat(matrix);
1126 return src.draw(canvas);
1127 });
mtklein748ca3b2015-01-15 10:56:12 -08001128}
1129
mtkleind603b222015-02-17 11:13:33 -08001130// Undoes any flip or 90 degree rotate without changing the scale of the bitmap.
1131// This should be pixel-preserving.
mtklein78829242015-05-06 07:54:07 -07001132ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
mtkleind603b222015-02-17 11:13:33 -08001133
1134Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1135 Error err = fSink->draw(src, bitmap, stream, log);
1136 if (!err.isEmpty()) {
1137 return err;
1138 }
1139
1140 SkMatrix inverse;
1141 if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) {
1142 return "Cannot upright --matrix.";
1143 }
1144 SkMatrix upright = SkMatrix::I();
1145 upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX()));
1146 upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY()));
1147 upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX()));
1148 upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY()));
1149
1150 SkBitmap uprighted;
1151 SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height());
1152 uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height()));
1153
1154 SkCanvas canvas(uprighted);
1155 canvas.concat(upright);
1156 SkPaint paint;
1157 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
1158 canvas.drawBitmap(*bitmap, 0, 0, &paint);
1159
1160 *bitmap = uprighted;
1161 bitmap->lockPixels();
1162 return "";
1163}
1164
mtklein748ca3b2015-01-15 10:56:12 -08001165/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1166
mtkleinb9eb4ac2015-02-02 18:26:03 -08001167Error ViaPipe::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtkleina16e69e2015-05-05 11:38:45 -07001168 auto size = src.size();
1169 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
1170 PipeController controller(canvas, &SkImageDecoder::DecodeMemory);
1171 SkGPipeWriter pipe;
reed451af502015-08-19 08:18:04 -07001172 const uint32_t kFlags = 0;
mtkleina16e69e2015-05-05 11:38:45 -07001173 return src.draw(pipe.startRecording(&controller, kFlags, size.width(), size.height()));
1174 });
mtklein748ca3b2015-01-15 10:56:12 -08001175}
1176
mtklein2e2ea382015-10-16 10:29:41 -07001177Error ViaRemote::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtklein479fe772015-10-21 12:34:01 -07001178 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* target) {
1179 SkAutoTDelete<SkRemote::Encoder> decoder(SkRemote::NewDecoder(target));
1180 SkAutoTDelete<SkRemote::Encoder> cache(fCache ? SkRemote::NewCachingEncoder(decoder)
1181 : nullptr);
1182 SkAutoTDelete<SkCanvas> canvas(SkRemote::NewCanvas(cache ? cache : decoder));
1183 return src.draw(canvas);
mtklein2e2ea382015-10-16 10:29:41 -07001184 });
1185}
1186
mtklein748ca3b2015-01-15 10:56:12 -08001187/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
mtkleina16e69e2015-05-05 11:38:45 -07001188
mtkleina16e69e2015-05-05 11:38:45 -07001189Error ViaSerialization::draw(
1190 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtklein748ca3b2015-01-15 10:56:12 -08001191 // Record our Src into a picture.
mtkleina16e69e2015-05-05 11:38:45 -07001192 auto size = src.size();
mtklein748ca3b2015-01-15 10:56:12 -08001193 SkPictureRecorder recorder;
mtkleina16e69e2015-05-05 11:38:45 -07001194 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1195 SkIntToScalar(size.height())));
mtklein748ca3b2015-01-15 10:56:12 -08001196 if (!err.isEmpty()) {
1197 return err;
1198 }
1199 SkAutoTUnref<SkPicture> pic(recorder.endRecording());
1200
1201 // Serialize it and then deserialize it.
1202 SkDynamicMemoryWStream wStream;
1203 pic->serialize(&wStream);
scroggoa1193e42015-01-21 12:09:53 -08001204 SkAutoTDelete<SkStream> rStream(wStream.detachAsStream());
mtkleinb3e5e4d2015-03-25 13:13:43 -07001205 SkAutoTUnref<SkPicture> deserialized(SkPicture::CreateFromStream(rStream, &lazy_decode_bitmap));
mtklein748ca3b2015-01-15 10:56:12 -08001206
mtkleina16e69e2015-05-05 11:38:45 -07001207 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
1208 canvas->drawPicture(deserialized);
1209 return "";
1210 });
mtklein748ca3b2015-01-15 10:56:12 -08001211}
1212
1213/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1214
1215ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink)
mtklein78829242015-05-06 07:54:07 -07001216 : Via(sink)
1217 , fW(w)
mtklein748ca3b2015-01-15 10:56:12 -08001218 , fH(h)
mtklein78829242015-05-06 07:54:07 -07001219 , fFactory(factory) {}
mtklein748ca3b2015-01-15 10:56:12 -08001220
mtkleinb9eb4ac2015-02-02 18:26:03 -08001221Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtkleina16e69e2015-05-05 11:38:45 -07001222 auto size = src.size();
mtklein748ca3b2015-01-15 10:56:12 -08001223 SkPictureRecorder recorder;
mtkleina16e69e2015-05-05 11:38:45 -07001224 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1225 SkIntToScalar(size.height()),
1226 fFactory.get()));
mtklein748ca3b2015-01-15 10:56:12 -08001227 if (!err.isEmpty()) {
1228 return err;
1229 }
mtkleinb7e8d692015-04-07 08:30:32 -07001230 SkAutoTUnref<SkPicture> pic(recorder.endRecordingAsPicture());
mtklein748ca3b2015-01-15 10:56:12 -08001231
mtkleina16e69e2015-05-05 11:38:45 -07001232 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) {
1233 const int xTiles = (size.width() + fW - 1) / fW,
1234 yTiles = (size.height() + fH - 1) / fH;
1235 SkMultiPictureDraw mpd(xTiles*yTiles);
1236 SkTDArray<SkSurface*> surfaces;
1237 surfaces.setReserve(xTiles*yTiles);
mtklein748ca3b2015-01-15 10:56:12 -08001238
mtkleina16e69e2015-05-05 11:38:45 -07001239 SkImageInfo info = canvas->imageInfo().makeWH(fW, fH);
1240 for (int j = 0; j < yTiles; j++) {
1241 for (int i = 0; i < xTiles; i++) {
1242 // This lets our ultimate Sink determine the best kind of surface.
1243 // E.g., if it's a GpuSink, the surfaces and images are textures.
1244 SkSurface* s = canvas->newSurface(info);
1245 if (!s) {
1246 s = SkSurface::NewRaster(info); // Some canvases can't create surfaces.
mtklein748ca3b2015-01-15 10:56:12 -08001247 }
mtkleina16e69e2015-05-05 11:38:45 -07001248 surfaces.push(s);
1249 SkCanvas* c = s->getCanvas();
1250 c->translate(SkIntToScalar(-i * fW),
1251 SkIntToScalar(-j * fH)); // Line up the canvas with this tile.
1252 mpd.add(c, pic);
mtklein748ca3b2015-01-15 10:56:12 -08001253 }
mtklein748ca3b2015-01-15 10:56:12 -08001254 }
mtkleina16e69e2015-05-05 11:38:45 -07001255 mpd.draw();
1256 for (int j = 0; j < yTiles; j++) {
1257 for (int i = 0; i < xTiles; i++) {
1258 SkAutoTUnref<SkImage> image(surfaces[i+xTiles*j]->newImageSnapshot());
1259 canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH));
1260 }
1261 }
1262 surfaces.unrefAll();
1263 return "";
1264 });
mtklein748ca3b2015-01-15 10:56:12 -08001265}
1266
mtkleinb7e8d692015-04-07 08:30:32 -07001267/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1268
mtkleinb7e8d692015-04-07 08:30:32 -07001269// Draw the Src into two pictures, then draw the second picture into the wrapped Sink.
1270// This tests that any shortcuts we may take while recording that second picture are legal.
1271Error ViaSecondPicture::draw(
1272 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtkleina16e69e2015-05-05 11:38:45 -07001273 auto size = src.size();
1274 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1275 SkPictureRecorder recorder;
1276 SkAutoTUnref<SkPicture> pic;
1277 for (int i = 0; i < 2; i++) {
1278 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1279 SkIntToScalar(size.height())));
1280 if (!err.isEmpty()) {
1281 return err;
mtkleinb7e8d692015-04-07 08:30:32 -07001282 }
mtkleina16e69e2015-05-05 11:38:45 -07001283 pic.reset(recorder.endRecordingAsPicture());
mtkleinb7e8d692015-04-07 08:30:32 -07001284 }
mtkleina16e69e2015-05-05 11:38:45 -07001285 canvas->drawPicture(pic);
1286 return "";
1287 });
mtkleinb7e8d692015-04-07 08:30:32 -07001288}
1289
mtkleind31c13d2015-05-05 12:59:56 -07001290/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1291
mtklein6fbf4b32015-05-06 11:35:40 -07001292// Draw the Src twice. This can help exercise caching.
1293Error ViaTwice::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1294 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) -> Error {
1295 for (int i = 0; i < 2; i++) {
1296 SkAutoCanvasRestore acr(canvas, true/*save now*/);
1297 canvas->clear(SK_ColorTRANSPARENT);
1298 Error err = src.draw(canvas);
1299 if (err.isEmpty()) {
1300 return err;
1301 }
1302 }
1303 return "";
1304 });
1305}
1306
1307/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1308
mtkleind31c13d2015-05-05 12:59:56 -07001309// This is like SkRecords::Draw, in that it plays back SkRecords ops into a Canvas.
1310// Unlike SkRecords::Draw, it builds a single-op sub-picture out of each Draw-type op.
1311// This is an only-slightly-exaggerated simluation of Blink's Slimming Paint pictures.
1312struct DrawsAsSingletonPictures {
1313 SkCanvas* fCanvas;
mtkleind2baa902015-07-07 09:43:28 -07001314 const SkDrawableList& fDrawables;
mtkleind31c13d2015-05-05 12:59:56 -07001315
mtkleind31c13d2015-05-05 12:59:56 -07001316 template <typename T>
1317 void draw(const T& op, SkCanvas* canvas) {
1318 // We must pass SkMatrix::I() as our initial matrix.
1319 // By default SkRecords::Draw() uses the canvas' matrix as its initial matrix,
1320 // which would have the funky effect of applying transforms over and over.
mtkleind2baa902015-07-07 09:43:28 -07001321 SkRecords::Draw d(canvas, nullptr, fDrawables.begin(), fDrawables.count(), &SkMatrix::I());
1322 d(op);
mtkleind31c13d2015-05-05 12:59:56 -07001323 }
1324
mtklein449d9b72015-09-28 10:33:02 -07001325 // Draws get their own picture.
mtkleind31c13d2015-05-05 12:59:56 -07001326 template <typename T>
mtklein449d9b72015-09-28 10:33:02 -07001327 SK_WHEN(T::kTags & SkRecords::kDraw_Tag, void) operator()(const T& op) {
mtkleind31c13d2015-05-05 12:59:56 -07001328 SkPictureRecorder rec;
1329 this->draw(op, rec.beginRecording(SkRect::MakeLargest()));
1330 SkAutoTUnref<SkPicture> pic(rec.endRecordingAsPicture());
1331 fCanvas->drawPicture(pic);
1332 }
1333
mtklein449d9b72015-09-28 10:33:02 -07001334 // We'll just issue non-draws directly.
mtkleind31c13d2015-05-05 12:59:56 -07001335 template <typename T>
mtklein449d9b72015-09-28 10:33:02 -07001336 skstd::enable_if_t<!(T::kTags & SkRecords::kDraw_Tag), void> operator()(const T& op) {
1337 this->draw(op, fCanvas);
1338 }
mtkleind31c13d2015-05-05 12:59:56 -07001339};
1340
mtkleind31c13d2015-05-05 12:59:56 -07001341// Record Src into a picture, then record it into a macro picture with a sub-picture for each draw.
1342// Then play back that macro picture into our wrapped sink.
1343Error ViaSingletonPictures::draw(
1344 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1345 auto size = src.size();
1346 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
1347 // Use low-level (Skia-private) recording APIs so we can read the SkRecord.
1348 SkRecord skr;
1349 SkRecorder recorder(&skr, size.width(), size.height());
1350 Error err = src.draw(&recorder);
1351 if (!err.isEmpty()) {
1352 return err;
1353 }
1354
1355 // Record our macro-picture, with each draw op as its own sub-picture.
1356 SkPictureRecorder macroRec;
1357 SkCanvas* macroCanvas = macroRec.beginRecording(SkIntToScalar(size.width()),
1358 SkIntToScalar(size.height()));
mtkleind2baa902015-07-07 09:43:28 -07001359
1360 SkAutoTDelete<SkDrawableList> drawables(recorder.detachDrawableList());
1361 const SkDrawableList empty;
1362
1363 DrawsAsSingletonPictures drawsAsSingletonPictures = {
1364 macroCanvas,
1365 drawables ? *drawables : empty,
1366 };
mtkleinc6ad06a2015-08-19 09:51:00 -07001367 for (int i = 0; i < skr.count(); i++) {
mtkleind31c13d2015-05-05 12:59:56 -07001368 skr.visit<void>(i, drawsAsSingletonPictures);
1369 }
1370 SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture());
1371
1372 canvas->drawPicture(macroPic);
1373 return "";
1374 });
1375}
1376
mtklein748ca3b2015-01-15 10:56:12 -08001377} // namespace DM