blob: 26b31ae11f44071ac5f839d98460a146db58898a [file] [log] [blame]
scroggof24f2242015-03-03 08:59:20 -08001/*
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
msarettb46e5e22015-07-30 11:36:40 -07008#include "SkBmpCodec.h"
scroggof24f2242015-03-03 08:59:20 -08009#include "SkCodec.h"
msarett8c8f22a2015-04-01 06:58:48 -070010#include "SkCodecPriv.h"
msarettad8bcfe2016-03-07 07:09:03 -080011#include "SkColorSpace.h"
Matt Sarettcf3f2342017-03-23 15:32:25 -040012#include "SkColorSpaceXform_Base.h"
msarett1a464672016-01-07 13:17:19 -080013#include "SkData.h"
Leon Scroggins III1f6af6b2017-06-12 16:41:09 -040014#include "SkFrameHolder.h"
msarett1a464672016-01-07 13:17:19 -080015#include "SkGifCodec.h"
msarettf7eb6fc2016-09-13 09:04:11 -070016#include "SkHalf.h"
msarett1a464672016-01-07 13:17:19 -080017#include "SkIcoCodec.h"
msarette16b04a2015-04-15 07:32:19 -070018#include "SkJpegCodec.h"
msarettad3a5c62016-05-06 07:21:26 -070019#ifdef SK_HAS_PNG_LIBRARY
msarettbe1d5552016-01-21 09:05:23 -080020#include "SkPngCodec.h"
yujieqin916de9f2016-01-25 08:26:16 -080021#endif
msarett39b2d5a2016-02-17 08:26:31 -080022#include "SkRawCodec.h"
scroggof24f2242015-03-03 08:59:20 -080023#include "SkStream.h"
msarett1a464672016-01-07 13:17:19 -080024#include "SkWbmpCodec.h"
scroggo6f5e6192015-06-18 12:53:43 -070025#include "SkWebpCodec.h"
scroggof24f2242015-03-03 08:59:20 -080026
msarett74114382015-03-16 11:55:18 -070027struct DecoderProc {
scroggodb30be22015-12-08 18:54:13 -080028 bool (*IsFormat)(const void*, size_t);
msarett74114382015-03-16 11:55:18 -070029 SkCodec* (*NewFromStream)(SkStream*);
30};
31
32static const DecoderProc gDecoderProcs[] = {
msarettad3a5c62016-05-06 07:21:26 -070033#ifdef SK_HAS_JPEG_LIBRARY
msarette16b04a2015-04-15 07:32:19 -070034 { SkJpegCodec::IsJpeg, SkJpegCodec::NewFromStream },
msarett39b2d5a2016-02-17 08:26:31 -080035#endif
msarettad3a5c62016-05-06 07:21:26 -070036#ifdef SK_HAS_WEBP_LIBRARY
scroggo6f5e6192015-06-18 12:53:43 -070037 { SkWebpCodec::IsWebp, SkWebpCodec::NewFromStream },
msarett39b2d5a2016-02-17 08:26:31 -080038#endif
msarett8c8f22a2015-04-01 06:58:48 -070039 { SkGifCodec::IsGif, SkGifCodec::NewFromStream },
msarettad3a5c62016-05-06 07:21:26 -070040#ifdef SK_HAS_PNG_LIBRARY
msarett9bde9182015-03-25 05:27:48 -070041 { SkIcoCodec::IsIco, SkIcoCodec::NewFromStream },
msarett39b2d5a2016-02-17 08:26:31 -080042#endif
halcanarya096d7a2015-03-27 12:16:53 -070043 { SkBmpCodec::IsBmp, SkBmpCodec::NewFromStream },
44 { SkWbmpCodec::IsWbmp, SkWbmpCodec::NewFromStream }
msarett74114382015-03-16 11:55:18 -070045};
46
scroggodb30be22015-12-08 18:54:13 -080047size_t SkCodec::MinBufferedBytesNeeded() {
48 return WEBP_VP8_HEADER_SIZE;
49}
50
scroggocf98fa92015-11-23 08:14:40 -080051SkCodec* SkCodec::NewFromStream(SkStream* stream,
52 SkPngChunkReader* chunkReader) {
scroggof24f2242015-03-03 08:59:20 -080053 if (!stream) {
halcanary96fcdcc2015-08-27 07:41:13 -070054 return nullptr;
scroggof24f2242015-03-03 08:59:20 -080055 }
scroggo0a7e69c2015-04-03 07:22:22 -070056
Ben Wagner145dbcd2016-11-03 14:40:50 -040057 std::unique_ptr<SkStream> streamDeleter(stream);
scroggodb30be22015-12-08 18:54:13 -080058
59 // 14 is enough to read all of the supported types.
60 const size_t bytesToRead = 14;
61 SkASSERT(bytesToRead <= MinBufferedBytesNeeded());
62
63 char buffer[bytesToRead];
64 size_t bytesRead = stream->peek(buffer, bytesToRead);
65
66 // It is also possible to have a complete image less than bytesToRead bytes
67 // (e.g. a 1 x 1 wbmp), meaning peek() would return less than bytesToRead.
68 // Assume that if bytesRead < bytesToRead, but > 0, the stream is shorter
69 // than bytesToRead, so pass that directly to the decoder.
70 // It also is possible the stream uses too small a buffer for peeking, but
71 // we trust the caller to use a large enough buffer.
72
73 if (0 == bytesRead) {
scroggo3ab9f2e2016-01-06 09:53:34 -080074 // TODO: After implementing peek in CreateJavaOutputStreamAdaptor.cpp, this
75 // printf could be useful to notice failures.
76 // SkCodecPrintf("Encoded image data failed to peek!\n");
77
scroggodb30be22015-12-08 18:54:13 -080078 // It is possible the stream does not support peeking, but does support
79 // rewinding.
80 // Attempt to read() and pass the actual amount read to the decoder.
81 bytesRead = stream->read(buffer, bytesToRead);
82 if (!stream->rewind()) {
scroggo3ab9f2e2016-01-06 09:53:34 -080083 SkCodecPrintf("Encoded image data could not peek or rewind to determine format!\n");
scroggodb30be22015-12-08 18:54:13 -080084 return nullptr;
85 }
86 }
87
scroggocf98fa92015-11-23 08:14:40 -080088 // PNG is special, since we want to be able to supply an SkPngChunkReader.
89 // But this code follows the same pattern as the loop.
msarettad3a5c62016-05-06 07:21:26 -070090#ifdef SK_HAS_PNG_LIBRARY
scroggodb30be22015-12-08 18:54:13 -080091 if (SkPngCodec::IsPng(buffer, bytesRead)) {
mtklein18300a32016-03-16 13:53:35 -070092 return SkPngCodec::NewFromStream(streamDeleter.release(), chunkReader);
msarett39b2d5a2016-02-17 08:26:31 -080093 } else
94#endif
95 {
scroggocf98fa92015-11-23 08:14:40 -080096 for (DecoderProc proc : gDecoderProcs) {
scroggodb30be22015-12-08 18:54:13 -080097 if (proc.IsFormat(buffer, bytesRead)) {
mtklein18300a32016-03-16 13:53:35 -070098 return proc.NewFromStream(streamDeleter.release());
scroggocf98fa92015-11-23 08:14:40 -080099 }
msarett74114382015-03-16 11:55:18 -0700100 }
yujieqin916de9f2016-01-25 08:26:16 -0800101
102#ifdef SK_CODEC_DECODES_RAW
103 // Try to treat the input as RAW if all the other checks failed.
mtklein18300a32016-03-16 13:53:35 -0700104 return SkRawCodec::NewFromStream(streamDeleter.release());
yujieqin916de9f2016-01-25 08:26:16 -0800105#endif
scroggof24f2242015-03-03 08:59:20 -0800106 }
msarett8c8f22a2015-04-01 06:58:48 -0700107
msarettf44631b2016-01-13 10:54:20 -0800108 return nullptr;
scroggof24f2242015-03-03 08:59:20 -0800109}
110
reed42943c82016-09-12 12:01:44 -0700111SkCodec* SkCodec::NewFromData(sk_sp<SkData> data, SkPngChunkReader* reader) {
scroggof24f2242015-03-03 08:59:20 -0800112 if (!data) {
halcanary96fcdcc2015-08-27 07:41:13 -0700113 return nullptr;
scroggof24f2242015-03-03 08:59:20 -0800114 }
scroggocf98fa92015-11-23 08:14:40 -0800115 return NewFromStream(new SkMemoryStream(data), reader);
scroggof24f2242015-03-03 08:59:20 -0800116}
117
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400118SkCodec::SkCodec(int width, int height, const SkEncodedInfo& info,
119 XformFormat srcFormat, SkStream* stream,
msarettc30c4182016-04-20 11:53:35 -0700120 sk_sp<SkColorSpace> colorSpace, Origin origin)
121 : fEncodedInfo(info)
msarett530c8442016-07-21 11:57:49 -0700122 , fSrcInfo(info.makeImageInfo(width, height, std::move(colorSpace)))
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400123 , fSrcXformFormat(srcFormat)
scroggof24f2242015-03-03 08:59:20 -0800124 , fStream(stream)
125 , fNeedsRewind(false)
msarett0e6274f2016-03-21 08:04:40 -0700126 , fOrigin(origin)
scroggo46c57472015-09-30 08:57:13 -0700127 , fDstInfo()
128 , fOptions()
129 , fCurrScanline(-1)
scroggof24f2242015-03-03 08:59:20 -0800130{}
131
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400132SkCodec::SkCodec(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
133 XformFormat srcFormat, SkStream* stream, Origin origin)
msarett549ca322016-08-17 08:54:08 -0700134 : fEncodedInfo(info)
135 , fSrcInfo(imageInfo)
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400136 , fSrcXformFormat(srcFormat)
msarett549ca322016-08-17 08:54:08 -0700137 , fStream(stream)
138 , fNeedsRewind(false)
139 , fOrigin(origin)
140 , fDstInfo()
141 , fOptions()
142 , fCurrScanline(-1)
143{}
144
scroggo9b2cdbf42015-07-10 12:07:02 -0700145SkCodec::~SkCodec() {}
scroggoeb602a52015-07-09 08:16:03 -0700146
scroggob427db12015-08-12 07:24:13 -0700147bool SkCodec::rewindIfNeeded() {
scroggof24f2242015-03-03 08:59:20 -0800148 // Store the value of fNeedsRewind so we can update it. Next read will
149 // require a rewind.
halcanarya096d7a2015-03-27 12:16:53 -0700150 const bool needsRewind = fNeedsRewind;
scroggof24f2242015-03-03 08:59:20 -0800151 fNeedsRewind = true;
halcanarya096d7a2015-03-27 12:16:53 -0700152 if (!needsRewind) {
scroggob427db12015-08-12 07:24:13 -0700153 return true;
halcanarya096d7a2015-03-27 12:16:53 -0700154 }
scroggob427db12015-08-12 07:24:13 -0700155
scroggo46c57472015-09-30 08:57:13 -0700156 // startScanlineDecode will need to be called before decoding scanlines.
157 fCurrScanline = -1;
scroggo8e6c7ad2016-09-16 08:20:38 -0700158 // startIncrementalDecode will need to be called before incrementalDecode.
159 fStartedIncrementalDecode = false;
scroggo46c57472015-09-30 08:57:13 -0700160
scroggo19b91532016-10-24 09:03:26 -0700161 // Some codecs do not have a stream. They may hold onto their own data or another codec.
162 // They must handle rewinding themselves.
163 if (fStream && !fStream->rewind()) {
scroggob427db12015-08-12 07:24:13 -0700164 return false;
165 }
166
167 return this->onRewind();
scroggof24f2242015-03-03 08:59:20 -0800168}
scroggo05245902015-03-25 11:11:52 -0700169
Leon Scroggins8321f752017-07-10 19:51:46 +0000170#define CHECK_COLOR_TABLE \
171 if (kIndex_8_SkColorType == info.colorType()) { \
172 if (nullptr == ctable || nullptr == ctableCount) { \
173 return SkCodec::kInvalidParameters; \
174 } \
175 } else { \
176 if (ctableCount) { \
177 *ctableCount = 0; \
178 } \
179 ctableCount = nullptr; \
180 ctable = nullptr; \
181 }
182
Leon Scroggins III1f6af6b2017-06-12 16:41:09 -0400183static void zero_rect(const SkImageInfo& dstInfo, void* pixels, size_t rowBytes,
184 SkIRect frameRect) {
185 if (!frameRect.intersect(dstInfo.bounds())) {
186 return;
187 }
188 const auto info = dstInfo.makeWH(frameRect.width(), frameRect.height());
189 const size_t bpp = SkColorTypeBytesPerPixel(dstInfo.colorType());
190 const size_t offset = frameRect.x() * bpp + frameRect.y() * rowBytes;
191 auto* eraseDst = SkTAddOffset<void>(pixels, offset);
192 SkSampler::Fill(info, eraseDst, rowBytes, 0, SkCodec::kNo_ZeroInitialized);
193}
194
195SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels, size_t rowBytes,
196 const Options& options) {
197 const int index = options.fFrameIndex;
198 if (0 == index) {
199 return kSuccess;
200 }
201
202 if (options.fSubset || info.dimensions() != fSrcInfo.dimensions()) {
203 // If we add support for these, we need to update the code that zeroes
204 // a kRestoreBGColor frame.
205 return kInvalidParameters;
206 }
207
Leon Scroggins8321f752017-07-10 19:51:46 +0000208 // index 8 is not supported beyond the first frame.
209 if (index < 0 || info.colorType() == kIndex_8_SkColorType) {
210 return kInvalidParameters;
211 }
212
Leon Scroggins III1f6af6b2017-06-12 16:41:09 -0400213 if (index >= this->onGetFrameCount()) {
214 return kIncompleteInput;
215 }
216
217 const auto* frameHolder = this->getFrameHolder();
218 SkASSERT(frameHolder);
219
220 const auto* frame = frameHolder->getFrame(index);
221 SkASSERT(frame);
222
223 const int requiredFrame = frame->getRequiredFrame();
224 if (requiredFrame == kNone) {
225 return kSuccess;
226 }
227
228 if (options.fPriorFrame != kNone) {
229 // Check for a valid frame as a starting point. Alternatively, we could
230 // treat an invalid frame as not providing one, but rejecting it will
231 // make it easier to catch the mistake.
232 if (options.fPriorFrame < requiredFrame || options.fPriorFrame >= index) {
233 return kInvalidParameters;
234 }
235 const auto* prevFrame = frameHolder->getFrame(options.fPriorFrame);
236 switch (prevFrame->getDisposalMethod()) {
237 case SkCodecAnimation::DisposalMethod::kRestorePrevious:
238 return kInvalidParameters;
239 case SkCodecAnimation::DisposalMethod::kRestoreBGColor:
240 // If a frame after the required frame is provided, there is no
241 // need to clear, since it must be covered by the desired frame.
242 if (options.fPriorFrame == requiredFrame) {
243 zero_rect(info, pixels, rowBytes, prevFrame->frameRect());
244 }
245 break;
246 default:
247 break;
248 }
249 return kSuccess;
250 }
251
252 Options prevFrameOptions(options);
253 prevFrameOptions.fFrameIndex = requiredFrame;
254 prevFrameOptions.fZeroInitialized = kNo_ZeroInitialized;
Leon Scroggins8321f752017-07-10 19:51:46 +0000255 const Result result = this->getPixels(info, pixels, rowBytes, &prevFrameOptions,
256 nullptr, nullptr);
Leon Scroggins III1f6af6b2017-06-12 16:41:09 -0400257 if (result == kSuccess) {
258 const auto* prevFrame = frameHolder->getFrame(requiredFrame);
259 const auto disposalMethod = prevFrame->getDisposalMethod();
260 if (disposalMethod == SkCodecAnimation::DisposalMethod::kRestoreBGColor) {
261 zero_rect(info, pixels, rowBytes, prevFrame->frameRect());
262 }
263 }
264
265 return result;
266}
scroggo8e6c7ad2016-09-16 08:20:38 -0700267
scroggoeb602a52015-07-09 08:16:03 -0700268SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
Leon Scroggins8321f752017-07-10 19:51:46 +0000269 const Options* options, SkPMColor ctable[], int* ctableCount) {
scroggoeb602a52015-07-09 08:16:03 -0700270 if (kUnknown_SkColorType == info.colorType()) {
271 return kInvalidConversion;
272 }
halcanary96fcdcc2015-08-27 07:41:13 -0700273 if (nullptr == pixels) {
scroggoeb602a52015-07-09 08:16:03 -0700274 return kInvalidParameters;
275 }
276 if (rowBytes < info.minRowBytes()) {
277 return kInvalidParameters;
278 }
279
Leon Scroggins8321f752017-07-10 19:51:46 +0000280 CHECK_COLOR_TABLE;
281
scroggo3a7701c2015-09-30 09:15:14 -0700282 if (!this->rewindIfNeeded()) {
283 return kCouldNotRewind;
284 }
285
scroggoeb602a52015-07-09 08:16:03 -0700286 // Default options.
287 Options optsStorage;
halcanary96fcdcc2015-08-27 07:41:13 -0700288 if (nullptr == options) {
scroggoeb602a52015-07-09 08:16:03 -0700289 options = &optsStorage;
Leon Scroggins III1f6af6b2017-06-12 16:41:09 -0400290 } else {
291 const Result frameIndexResult = this->handleFrameIndex(info, pixels, rowBytes, *options);
292 if (frameIndexResult != kSuccess) {
293 return frameIndexResult;
294 }
295 if (options->fSubset) {
296 SkIRect subset(*options->fSubset);
297 if (!this->onGetValidSubset(&subset) || subset != *options->fSubset) {
298 // FIXME: How to differentiate between not supporting subset at all
299 // and not supporting this particular subset?
300 return kUnimplemented;
301 }
scroggoe7fc14b2015-10-02 13:14:46 -0700302 }
scroggoeb602a52015-07-09 08:16:03 -0700303 }
scroggoe7fc14b2015-10-02 13:14:46 -0700304
305 // FIXME: Support subsets somehow? Note that this works for SkWebpCodec
306 // because it supports arbitrary scaling/subset combinations.
307 if (!this->dimensionsSupported(info.dimensions())) {
308 return kInvalidScale;
309 }
310
scroggo8e6c7ad2016-09-16 08:20:38 -0700311 fDstInfo = info;
Leon Scroggins III42886572017-01-27 13:16:28 -0500312 fOptions = *options;
scroggo8e6c7ad2016-09-16 08:20:38 -0700313
msarette6dd0042015-10-09 11:07:34 -0700314 // On an incomplete decode, the subclass will specify the number of scanlines that it decoded
315 // successfully.
316 int rowsDecoded = 0;
Leon Scroggins8321f752017-07-10 19:51:46 +0000317 const Result result = this->onGetPixels(info, pixels, rowBytes, *options, ctable, ctableCount,
318 &rowsDecoded);
319
320 if (ctableCount) {
321 if (kIncompleteInput == result || kSuccess == result || kErrorInInput == result) {
322 SkASSERT(*ctableCount >= 0 && *ctableCount <= 256);
323 }
324 }
msarette6dd0042015-10-09 11:07:34 -0700325
326 // A return value of kIncompleteInput indicates a truncated image stream.
327 // In this case, we will fill any uninitialized memory with a default value.
328 // Some subclasses will take care of filling any uninitialized memory on
329 // their own. They indicate that all of the memory has been filled by
330 // setting rowsDecoded equal to the height.
Leon Scroggins III674a1842017-07-06 12:26:09 -0400331 if ((kIncompleteInput == result || kErrorInInput == result) && rowsDecoded != info.height()) {
Leon Scroggins III42886572017-01-27 13:16:28 -0500332 // FIXME: (skbug.com/5772) fillIncompleteImage will fill using the swizzler's width, unless
333 // there is a subset. In that case, it will use the width of the subset. From here, the
334 // subset will only be non-null in the case of SkWebpCodec, but it treats the subset
335 // differenty from the other codecs, and it needs to use the width specified by the info.
336 // Set the subset to null so SkWebpCodec uses the correct width.
337 fOptions.fSubset = nullptr;
msarette6dd0042015-10-09 11:07:34 -0700338 this->fillIncompleteImage(info, pixels, rowBytes, options->fZeroInitialized, info.height(),
339 rowsDecoded);
340 }
341
scroggoeb602a52015-07-09 08:16:03 -0700342 return result;
343}
344
Leon Scroggins8321f752017-07-10 19:51:46 +0000345SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) {
346 return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr);
347}
348
scroggo8e6c7ad2016-09-16 08:20:38 -0700349SkCodec::Result SkCodec::startIncrementalDecode(const SkImageInfo& info, void* pixels,
Leon Scroggins8321f752017-07-10 19:51:46 +0000350 size_t rowBytes, const SkCodec::Options* options, SkPMColor* ctable, int* ctableCount) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700351 fStartedIncrementalDecode = false;
352
353 if (kUnknown_SkColorType == info.colorType()) {
354 return kInvalidConversion;
355 }
356 if (nullptr == pixels) {
357 return kInvalidParameters;
358 }
359
Leon Scroggins8321f752017-07-10 19:51:46 +0000360 // Ensure that valid color ptrs are passed in for kIndex8 color type
361 CHECK_COLOR_TABLE;
362
scroggo8e6c7ad2016-09-16 08:20:38 -0700363 // FIXME: If the rows come after the rows of a previous incremental decode,
364 // we might be able to skip the rewind, but only the implementation knows
365 // that. (e.g. PNG will always need to rewind, since we called longjmp, but
366 // a bottom-up BMP could skip rewinding if the new rows are above the old
367 // rows.)
368 if (!this->rewindIfNeeded()) {
369 return kCouldNotRewind;
370 }
371
372 // Set options.
373 Options optsStorage;
374 if (nullptr == options) {
375 options = &optsStorage;
Leon Scroggins III1f6af6b2017-06-12 16:41:09 -0400376 } else {
377 const Result frameIndexResult = this->handleFrameIndex(info, pixels, rowBytes, *options);
378 if (frameIndexResult != kSuccess) {
379 return frameIndexResult;
scroggo8e6c7ad2016-09-16 08:20:38 -0700380 }
Leon Scroggins III1f6af6b2017-06-12 16:41:09 -0400381 if (options->fSubset) {
382 SkIRect size = SkIRect::MakeSize(info.dimensions());
383 if (!size.contains(*options->fSubset)) {
384 return kInvalidParameters;
385 }
scroggo8e6c7ad2016-09-16 08:20:38 -0700386
Leon Scroggins III1f6af6b2017-06-12 16:41:09 -0400387 const int top = options->fSubset->top();
388 const int bottom = options->fSubset->bottom();
389 if (top < 0 || top >= info.height() || top >= bottom || bottom > info.height()) {
390 return kInvalidParameters;
391 }
scroggo8e6c7ad2016-09-16 08:20:38 -0700392 }
393 }
394
395 if (!this->dimensionsSupported(info.dimensions())) {
396 return kInvalidScale;
397 }
398
399 fDstInfo = info;
400 fOptions = *options;
401
Leon Scroggins8321f752017-07-10 19:51:46 +0000402 const Result result = this->onStartIncrementalDecode(info, pixels, rowBytes,
403 fOptions, ctable, ctableCount);
scroggo8e6c7ad2016-09-16 08:20:38 -0700404 if (kSuccess == result) {
405 fStartedIncrementalDecode = true;
406 } else if (kUnimplemented == result) {
407 // FIXME: This is temporarily necessary, until we transition SkCodec
408 // implementations from scanline decoding to incremental decoding.
409 // SkAndroidCodec will first attempt to use incremental decoding, but
410 // will fall back to scanline decoding if incremental returns
411 // kUnimplemented. rewindIfNeeded(), above, set fNeedsRewind to true
412 // (after potentially rewinding), but we do not want the next call to
413 // startScanlineDecode() to do a rewind.
414 fNeedsRewind = false;
415 }
416 return result;
417}
418
419
420SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info,
Leon Scroggins8321f752017-07-10 19:51:46 +0000421 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) {
scroggo46c57472015-09-30 08:57:13 -0700422 // Reset fCurrScanline in case of failure.
423 fCurrScanline = -1;
Leon Scroggins8321f752017-07-10 19:51:46 +0000424 // Ensure that valid color ptrs are passed in for kIndex8 color type
425 CHECK_COLOR_TABLE;
scroggo46c57472015-09-30 08:57:13 -0700426
scroggo3a7701c2015-09-30 09:15:14 -0700427 if (!this->rewindIfNeeded()) {
428 return kCouldNotRewind;
429 }
430
scroggo46c57472015-09-30 08:57:13 -0700431 // Set options.
432 Options optsStorage;
433 if (nullptr == options) {
434 options = &optsStorage;
scroggoe7fc14b2015-10-02 13:14:46 -0700435 } else if (options->fSubset) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700436 SkIRect size = SkIRect::MakeSize(info.dimensions());
msarettfdb47572015-10-13 12:50:14 -0700437 if (!size.contains(*options->fSubset)) {
438 return kInvalidInput;
439 }
440
441 // We only support subsetting in the x-dimension for scanline decoder.
442 // Subsetting in the y-dimension can be accomplished using skipScanlines().
scroggo8e6c7ad2016-09-16 08:20:38 -0700443 if (options->fSubset->top() != 0 || options->fSubset->height() != info.height()) {
msarettfdb47572015-10-13 12:50:14 -0700444 return kInvalidInput;
scroggoe7fc14b2015-10-02 13:14:46 -0700445 }
446 }
447
448 // FIXME: Support subsets somehow?
scroggo8e6c7ad2016-09-16 08:20:38 -0700449 if (!this->dimensionsSupported(info.dimensions())) {
scroggoe7fc14b2015-10-02 13:14:46 -0700450 return kInvalidScale;
scroggo46c57472015-09-30 08:57:13 -0700451 }
452
Leon Scroggins8321f752017-07-10 19:51:46 +0000453 const Result result = this->onStartScanlineDecode(info, *options, ctable, ctableCount);
scroggo46c57472015-09-30 08:57:13 -0700454 if (result != SkCodec::kSuccess) {
455 return result;
456 }
457
458 fCurrScanline = 0;
scroggo8e6c7ad2016-09-16 08:20:38 -0700459 fDstInfo = info;
scroggo46c57472015-09-30 08:57:13 -0700460 fOptions = *options;
461 return kSuccess;
462}
463
Leon Scroggins8321f752017-07-10 19:51:46 +0000464#undef CHECK_COLOR_TABLE
465
466SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info) {
467 return this->startScanlineDecode(info, nullptr, nullptr, nullptr);
468}
469
msarette6dd0042015-10-09 11:07:34 -0700470int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) {
scroggo46c57472015-09-30 08:57:13 -0700471 if (fCurrScanline < 0) {
msarette6dd0042015-10-09 11:07:34 -0700472 return 0;
scroggo46c57472015-09-30 08:57:13 -0700473 }
474
475 SkASSERT(!fDstInfo.isEmpty());
scroggoe7fc14b2015-10-02 13:14:46 -0700476 if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) {
msarette6dd0042015-10-09 11:07:34 -0700477 return 0;
scroggo46c57472015-09-30 08:57:13 -0700478 }
479
msarette6dd0042015-10-09 11:07:34 -0700480 const int linesDecoded = this->onGetScanlines(dst, countLines, rowBytes);
481 if (linesDecoded < countLines) {
482 this->fillIncompleteImage(this->dstInfo(), dst, rowBytes, this->options().fZeroInitialized,
483 countLines, linesDecoded);
484 }
485 fCurrScanline += countLines;
486 return linesDecoded;
487}
488
489bool SkCodec::skipScanlines(int countLines) {
490 if (fCurrScanline < 0) {
491 return false;
492 }
493
494 SkASSERT(!fDstInfo.isEmpty());
495 if (countLines < 0 || fCurrScanline + countLines > fDstInfo.height()) {
496 // Arguably, we could just skip the scanlines which are remaining,
497 // and return true. We choose to return false so the client
498 // can catch their bug.
499 return false;
500 }
501
502 bool result = this->onSkipScanlines(countLines);
scroggo46c57472015-09-30 08:57:13 -0700503 fCurrScanline += countLines;
504 return result;
505}
506
msarette6dd0042015-10-09 11:07:34 -0700507int SkCodec::outputScanline(int inputScanline) const {
508 SkASSERT(0 <= inputScanline && inputScanline < this->getInfo().height());
509 return this->onOutputScanline(inputScanline);
510}
scroggo46c57472015-09-30 08:57:13 -0700511
msarette6dd0042015-10-09 11:07:34 -0700512int SkCodec::onOutputScanline(int inputScanline) const {
513 switch (this->getScanlineOrder()) {
514 case kTopDown_SkScanlineOrder:
msarette6dd0042015-10-09 11:07:34 -0700515 return inputScanline;
516 case kBottomUp_SkScanlineOrder:
517 return this->getInfo().height() - inputScanline - 1;
518 default:
519 // This case indicates an interlaced gif and is implemented by SkGifCodec.
520 SkASSERT(false);
521 return 0;
scroggo46c57472015-09-30 08:57:13 -0700522 }
msarette6dd0042015-10-09 11:07:34 -0700523}
scroggo46c57472015-09-30 08:57:13 -0700524
msarettf7eb6fc2016-09-13 09:04:11 -0700525uint64_t SkCodec::onGetFillValue(const SkImageInfo& dstInfo) const {
526 switch (dstInfo.colorType()) {
527 case kRGBA_F16_SkColorType: {
528 static constexpr uint64_t transparentColor = 0;
529 static constexpr uint64_t opaqueColor = ((uint64_t) SK_Half1) << 48;
530 return (kOpaque_SkAlphaType == fSrcInfo.alphaType()) ? opaqueColor : transparentColor;
531 }
532 default: {
Leon Scroggins8321f752017-07-10 19:51:46 +0000533 // This not only handles the kN32 case, but also k565, kGray8, kIndex8, since
msarettf7eb6fc2016-09-13 09:04:11 -0700534 // the low bits are zeros.
535 return (kOpaque_SkAlphaType == fSrcInfo.alphaType()) ?
536 SK_ColorBLACK : SK_ColorTRANSPARENT;
537 }
538 }
539}
540
msarette6dd0042015-10-09 11:07:34 -0700541static void fill_proc(const SkImageInfo& info, void* dst, size_t rowBytes,
msarettf7eb6fc2016-09-13 09:04:11 -0700542 uint64_t colorOrIndex, SkCodec::ZeroInitialized zeroInit, SkSampler* sampler) {
msarette6dd0042015-10-09 11:07:34 -0700543 if (sampler) {
544 sampler->fill(info, dst, rowBytes, colorOrIndex, zeroInit);
545 } else {
546 SkSampler::Fill(info, dst, rowBytes, colorOrIndex, zeroInit);
547 }
548}
549
550void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t rowBytes,
551 ZeroInitialized zeroInit, int linesRequested, int linesDecoded) {
552
553 void* fillDst;
msarettf7eb6fc2016-09-13 09:04:11 -0700554 const uint64_t fillValue = this->getFillValue(info);
msarette6dd0042015-10-09 11:07:34 -0700555 const int linesRemaining = linesRequested - linesDecoded;
556 SkSampler* sampler = this->getSampler(false);
557
msarett91c22b22016-02-22 12:27:46 -0800558 int fillWidth = info.width();
559 if (fOptions.fSubset) {
560 fillWidth = fOptions.fSubset->width();
561 }
562
msarette6dd0042015-10-09 11:07:34 -0700563 switch (this->getScanlineOrder()) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700564 case kTopDown_SkScanlineOrder: {
msarett91c22b22016-02-22 12:27:46 -0800565 const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining);
msarette6dd0042015-10-09 11:07:34 -0700566 fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes);
567 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler);
568 break;
569 }
570 case kBottomUp_SkScanlineOrder: {
571 fillDst = dst;
msarett91c22b22016-02-22 12:27:46 -0800572 const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining);
msarette6dd0042015-10-09 11:07:34 -0700573 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler);
574 break;
575 }
msarette6dd0042015-10-09 11:07:34 -0700576 }
scroggo46c57472015-09-30 08:57:13 -0700577}
Matt Sarett313c4632016-10-20 12:35:23 -0400578
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400579static inline SkColorSpaceXform::ColorFormat select_xform_format_ct(SkColorType colorType) {
580 switch (colorType) {
581 case kRGBA_8888_SkColorType:
582 return SkColorSpaceXform::kRGBA_8888_ColorFormat;
583 case kBGRA_8888_SkColorType:
584 return SkColorSpaceXform::kBGRA_8888_ColorFormat;
585 case kRGB_565_SkColorType:
Leon Scroggins8321f752017-07-10 19:51:46 +0000586 case kIndex_8_SkColorType:
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400587#ifdef SK_PMCOLOR_IS_RGBA
588 return SkColorSpaceXform::kRGBA_8888_ColorFormat;
589#else
590 return SkColorSpaceXform::kBGRA_8888_ColorFormat;
591#endif
592 default:
593 SkASSERT(false);
594 return SkColorSpaceXform::kRGBA_8888_ColorFormat;
595 }
596}
597
Matt Sarettcf3f2342017-03-23 15:32:25 -0400598bool SkCodec::initializeColorXform(const SkImageInfo& dstInfo,
599 SkTransferFunctionBehavior premulBehavior) {
Matt Sarett313c4632016-10-20 12:35:23 -0400600 fColorXform = nullptr;
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400601 fXformOnDecode = false;
Matt Sarettcf3f2342017-03-23 15:32:25 -0400602 bool needsColorCorrectPremul = needs_premul(dstInfo, fEncodedInfo) &&
603 SkTransferFunctionBehavior::kRespect == premulBehavior;
604 if (needs_color_xform(dstInfo, fSrcInfo, needsColorCorrectPremul)) {
605 fColorXform = SkColorSpaceXform_Base::New(fSrcInfo.colorSpace(), dstInfo.colorSpace(),
606 premulBehavior);
Matt Sarett313c4632016-10-20 12:35:23 -0400607 if (!fColorXform) {
608 return false;
609 }
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400610
611 // We will apply the color xform when reading the color table unless F16 is requested.
612 fXformOnDecode = SkEncodedInfo::kPalette_Color != fEncodedInfo.color()
613 || kRGBA_F16_SkColorType == dstInfo.colorType();
614 if (fXformOnDecode) {
615 fDstXformFormat = select_xform_format(dstInfo.colorType());
616 } else {
617 fDstXformFormat = select_xform_format_ct(dstInfo.colorType());
618 }
Matt Sarett313c4632016-10-20 12:35:23 -0400619 }
620
621 return true;
622}
Leon Scroggins IIIe132e7b2017-04-12 10:49:52 -0400623
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400624void SkCodec::applyColorXform(void* dst, const void* src, int count, SkAlphaType at) const {
625 SkASSERT(fColorXform);
626 SkAssertResult(fColorXform->apply(fDstXformFormat, dst,
627 fSrcXformFormat, src,
628 count, at));
629}
630
631void SkCodec::applyColorXform(void* dst, const void* src, int count) const {
632 auto alphaType = select_xform_alpha(fDstInfo.alphaType(), fSrcInfo.alphaType());
633 this->applyColorXform(dst, src, count, alphaType);
634}
635
Leon Scroggins IIIe132e7b2017-04-12 10:49:52 -0400636std::vector<SkCodec::FrameInfo> SkCodec::getFrameInfo() {
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400637 const int frameCount = this->getFrameCount();
638 SkASSERT(frameCount >= 0);
639 if (frameCount <= 0) {
640 return std::vector<FrameInfo>{};
Leon Scroggins IIIe132e7b2017-04-12 10:49:52 -0400641 }
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400642
643 if (frameCount == 1 && !this->onGetFrameInfo(0, nullptr)) {
644 // Not animated.
645 return std::vector<FrameInfo>{};
646 }
647
648 std::vector<FrameInfo> result(frameCount);
649 for (int i = 0; i < frameCount; ++i) {
650 SkAssertResult(this->onGetFrameInfo(i, &result[i]));
651 }
652 return result;
Leon Scroggins IIIe132e7b2017-04-12 10:49:52 -0400653}