blob: d7cfb3749708f04e4f3d2adba765c82205dce4f3 [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"
msarett1a464672016-01-07 13:17:19 -080011#include "SkData.h"
12#include "SkGifCodec.h"
13#include "SkIcoCodec.h"
msarette16b04a2015-04-15 07:32:19 -070014#include "SkJpegCodec.h"
msarett39b2d5a2016-02-17 08:26:31 -080015#ifdef SK_CODEC_DECODES_PNG
msarettbe1d5552016-01-21 09:05:23 -080016#include "SkPngCodec.h"
yujieqin916de9f2016-01-25 08:26:16 -080017#endif
msarett39b2d5a2016-02-17 08:26:31 -080018#include "SkRawCodec.h"
scroggof24f2242015-03-03 08:59:20 -080019#include "SkStream.h"
msarett1a464672016-01-07 13:17:19 -080020#include "SkWbmpCodec.h"
scroggo6f5e6192015-06-18 12:53:43 -070021#include "SkWebpCodec.h"
scroggof24f2242015-03-03 08:59:20 -080022
msarett74114382015-03-16 11:55:18 -070023struct DecoderProc {
scroggodb30be22015-12-08 18:54:13 -080024 bool (*IsFormat)(const void*, size_t);
msarett74114382015-03-16 11:55:18 -070025 SkCodec* (*NewFromStream)(SkStream*);
26};
27
28static const DecoderProc gDecoderProcs[] = {
msarett39b2d5a2016-02-17 08:26:31 -080029#ifdef SK_CODEC_DECODES_JPEG
msarette16b04a2015-04-15 07:32:19 -070030 { SkJpegCodec::IsJpeg, SkJpegCodec::NewFromStream },
msarett39b2d5a2016-02-17 08:26:31 -080031#endif
32#ifdef SK_CODEC_DECODES_WEBP
scroggo6f5e6192015-06-18 12:53:43 -070033 { SkWebpCodec::IsWebp, SkWebpCodec::NewFromStream },
msarett39b2d5a2016-02-17 08:26:31 -080034#endif
35#ifdef SK_CODEC_DECODES_GIF
msarett8c8f22a2015-04-01 06:58:48 -070036 { SkGifCodec::IsGif, SkGifCodec::NewFromStream },
msarett39b2d5a2016-02-17 08:26:31 -080037#endif
38#ifdef SK_CODEC_DECODES_PNG
msarett9bde9182015-03-25 05:27:48 -070039 { SkIcoCodec::IsIco, SkIcoCodec::NewFromStream },
msarett39b2d5a2016-02-17 08:26:31 -080040#endif
halcanarya096d7a2015-03-27 12:16:53 -070041 { SkBmpCodec::IsBmp, SkBmpCodec::NewFromStream },
42 { SkWbmpCodec::IsWbmp, SkWbmpCodec::NewFromStream }
msarett74114382015-03-16 11:55:18 -070043};
44
scroggodb30be22015-12-08 18:54:13 -080045size_t SkCodec::MinBufferedBytesNeeded() {
46 return WEBP_VP8_HEADER_SIZE;
47}
48
scroggocf98fa92015-11-23 08:14:40 -080049SkCodec* SkCodec::NewFromStream(SkStream* stream,
50 SkPngChunkReader* chunkReader) {
scroggof24f2242015-03-03 08:59:20 -080051 if (!stream) {
halcanary96fcdcc2015-08-27 07:41:13 -070052 return nullptr;
scroggof24f2242015-03-03 08:59:20 -080053 }
scroggo0a7e69c2015-04-03 07:22:22 -070054
55 SkAutoTDelete<SkStream> streamDeleter(stream);
scroggodb30be22015-12-08 18:54:13 -080056
57 // 14 is enough to read all of the supported types.
58 const size_t bytesToRead = 14;
59 SkASSERT(bytesToRead <= MinBufferedBytesNeeded());
60
61 char buffer[bytesToRead];
62 size_t bytesRead = stream->peek(buffer, bytesToRead);
63
64 // It is also possible to have a complete image less than bytesToRead bytes
65 // (e.g. a 1 x 1 wbmp), meaning peek() would return less than bytesToRead.
66 // Assume that if bytesRead < bytesToRead, but > 0, the stream is shorter
67 // than bytesToRead, so pass that directly to the decoder.
68 // It also is possible the stream uses too small a buffer for peeking, but
69 // we trust the caller to use a large enough buffer.
70
71 if (0 == bytesRead) {
scroggo3ab9f2e2016-01-06 09:53:34 -080072 // TODO: After implementing peek in CreateJavaOutputStreamAdaptor.cpp, this
73 // printf could be useful to notice failures.
74 // SkCodecPrintf("Encoded image data failed to peek!\n");
75
scroggodb30be22015-12-08 18:54:13 -080076 // It is possible the stream does not support peeking, but does support
77 // rewinding.
78 // Attempt to read() and pass the actual amount read to the decoder.
79 bytesRead = stream->read(buffer, bytesToRead);
80 if (!stream->rewind()) {
scroggo3ab9f2e2016-01-06 09:53:34 -080081 SkCodecPrintf("Encoded image data could not peek or rewind to determine format!\n");
scroggodb30be22015-12-08 18:54:13 -080082 return nullptr;
83 }
84 }
85
scroggocf98fa92015-11-23 08:14:40 -080086 // PNG is special, since we want to be able to supply an SkPngChunkReader.
87 // But this code follows the same pattern as the loop.
msarett39b2d5a2016-02-17 08:26:31 -080088#ifdef SK_CODEC_DECODES_PNG
scroggodb30be22015-12-08 18:54:13 -080089 if (SkPngCodec::IsPng(buffer, bytesRead)) {
msarettf44631b2016-01-13 10:54:20 -080090 return SkPngCodec::NewFromStream(streamDeleter.detach(), chunkReader);
msarett39b2d5a2016-02-17 08:26:31 -080091 } else
92#endif
93 {
scroggocf98fa92015-11-23 08:14:40 -080094 for (DecoderProc proc : gDecoderProcs) {
scroggodb30be22015-12-08 18:54:13 -080095 if (proc.IsFormat(buffer, bytesRead)) {
msarettf44631b2016-01-13 10:54:20 -080096 return proc.NewFromStream(streamDeleter.detach());
scroggocf98fa92015-11-23 08:14:40 -080097 }
msarett74114382015-03-16 11:55:18 -070098 }
yujieqin916de9f2016-01-25 08:26:16 -080099
100#ifdef SK_CODEC_DECODES_RAW
101 // Try to treat the input as RAW if all the other checks failed.
102 return SkRawCodec::NewFromStream(streamDeleter.detach());
103#endif
scroggof24f2242015-03-03 08:59:20 -0800104 }
msarett8c8f22a2015-04-01 06:58:48 -0700105
msarettf44631b2016-01-13 10:54:20 -0800106 return nullptr;
scroggof24f2242015-03-03 08:59:20 -0800107}
108
scroggocf98fa92015-11-23 08:14:40 -0800109SkCodec* SkCodec::NewFromData(SkData* data, SkPngChunkReader* reader) {
scroggof24f2242015-03-03 08:59:20 -0800110 if (!data) {
halcanary96fcdcc2015-08-27 07:41:13 -0700111 return nullptr;
scroggof24f2242015-03-03 08:59:20 -0800112 }
scroggocf98fa92015-11-23 08:14:40 -0800113 return NewFromStream(new SkMemoryStream(data), reader);
scroggof24f2242015-03-03 08:59:20 -0800114}
115
116SkCodec::SkCodec(const SkImageInfo& info, SkStream* stream)
scroggo46c57472015-09-30 08:57:13 -0700117 : fSrcInfo(info)
scroggof24f2242015-03-03 08:59:20 -0800118 , fStream(stream)
119 , fNeedsRewind(false)
scroggo46c57472015-09-30 08:57:13 -0700120 , fDstInfo()
121 , fOptions()
122 , fCurrScanline(-1)
scroggof24f2242015-03-03 08:59:20 -0800123{}
124
scroggo9b2cdbf42015-07-10 12:07:02 -0700125SkCodec::~SkCodec() {}
scroggoeb602a52015-07-09 08:16:03 -0700126
scroggob427db12015-08-12 07:24:13 -0700127bool SkCodec::rewindIfNeeded() {
scroggo3a7701c2015-09-30 09:15:14 -0700128 if (!fStream) {
129 // Some codecs do not have a stream, but they hold others that do. They
130 // must handle rewinding themselves.
131 return true;
132 }
133
scroggof24f2242015-03-03 08:59:20 -0800134 // Store the value of fNeedsRewind so we can update it. Next read will
135 // require a rewind.
halcanarya096d7a2015-03-27 12:16:53 -0700136 const bool needsRewind = fNeedsRewind;
scroggof24f2242015-03-03 08:59:20 -0800137 fNeedsRewind = true;
halcanarya096d7a2015-03-27 12:16:53 -0700138 if (!needsRewind) {
scroggob427db12015-08-12 07:24:13 -0700139 return true;
halcanarya096d7a2015-03-27 12:16:53 -0700140 }
scroggob427db12015-08-12 07:24:13 -0700141
scroggo46c57472015-09-30 08:57:13 -0700142 // startScanlineDecode will need to be called before decoding scanlines.
143 fCurrScanline = -1;
144
scroggob427db12015-08-12 07:24:13 -0700145 if (!fStream->rewind()) {
146 return false;
147 }
148
149 return this->onRewind();
scroggof24f2242015-03-03 08:59:20 -0800150}
scroggo05245902015-03-25 11:11:52 -0700151
scroggoeb602a52015-07-09 08:16:03 -0700152SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
153 const Options* options, SkPMColor ctable[], int* ctableCount) {
154 if (kUnknown_SkColorType == info.colorType()) {
155 return kInvalidConversion;
156 }
halcanary96fcdcc2015-08-27 07:41:13 -0700157 if (nullptr == pixels) {
scroggoeb602a52015-07-09 08:16:03 -0700158 return kInvalidParameters;
159 }
160 if (rowBytes < info.minRowBytes()) {
161 return kInvalidParameters;
162 }
163
164 if (kIndex_8_SkColorType == info.colorType()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700165 if (nullptr == ctable || nullptr == ctableCount) {
scroggoeb602a52015-07-09 08:16:03 -0700166 return kInvalidParameters;
167 }
168 } else {
169 if (ctableCount) {
170 *ctableCount = 0;
171 }
halcanary96fcdcc2015-08-27 07:41:13 -0700172 ctableCount = nullptr;
173 ctable = nullptr;
scroggoeb602a52015-07-09 08:16:03 -0700174 }
175
scroggo3a7701c2015-09-30 09:15:14 -0700176 if (!this->rewindIfNeeded()) {
177 return kCouldNotRewind;
178 }
179
scroggoeb602a52015-07-09 08:16:03 -0700180 // Default options.
181 Options optsStorage;
halcanary96fcdcc2015-08-27 07:41:13 -0700182 if (nullptr == options) {
scroggoeb602a52015-07-09 08:16:03 -0700183 options = &optsStorage;
scroggoe7fc14b2015-10-02 13:14:46 -0700184 } else if (options->fSubset) {
185 SkIRect subset(*options->fSubset);
186 if (!this->onGetValidSubset(&subset) || subset != *options->fSubset) {
187 // FIXME: How to differentiate between not supporting subset at all
188 // and not supporting this particular subset?
189 return kUnimplemented;
190 }
scroggoeb602a52015-07-09 08:16:03 -0700191 }
scroggoe7fc14b2015-10-02 13:14:46 -0700192
193 // FIXME: Support subsets somehow? Note that this works for SkWebpCodec
194 // because it supports arbitrary scaling/subset combinations.
195 if (!this->dimensionsSupported(info.dimensions())) {
196 return kInvalidScale;
197 }
198
msarette6dd0042015-10-09 11:07:34 -0700199 // On an incomplete decode, the subclass will specify the number of scanlines that it decoded
200 // successfully.
201 int rowsDecoded = 0;
202 const Result result = this->onGetPixels(info, pixels, rowBytes, *options, ctable, ctableCount,
203 &rowsDecoded);
scroggoeb602a52015-07-09 08:16:03 -0700204
205 if ((kIncompleteInput == result || kSuccess == result) && ctableCount) {
206 SkASSERT(*ctableCount >= 0 && *ctableCount <= 256);
207 }
msarette6dd0042015-10-09 11:07:34 -0700208
209 // A return value of kIncompleteInput indicates a truncated image stream.
210 // In this case, we will fill any uninitialized memory with a default value.
211 // Some subclasses will take care of filling any uninitialized memory on
212 // their own. They indicate that all of the memory has been filled by
213 // setting rowsDecoded equal to the height.
214 if (kIncompleteInput == result && rowsDecoded != info.height()) {
215 this->fillIncompleteImage(info, pixels, rowBytes, options->fZeroInitialized, info.height(),
216 rowsDecoded);
217 }
218
scroggoeb602a52015-07-09 08:16:03 -0700219 return result;
220}
221
222SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) {
halcanary96fcdcc2015-08-27 07:41:13 -0700223 return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr);
scroggoeb602a52015-07-09 08:16:03 -0700224}
scroggo46c57472015-09-30 08:57:13 -0700225
226SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo,
227 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) {
228 // Reset fCurrScanline in case of failure.
229 fCurrScanline = -1;
230 // Ensure that valid color ptrs are passed in for kIndex8 color type
231 if (kIndex_8_SkColorType == dstInfo.colorType()) {
232 if (nullptr == ctable || nullptr == ctableCount) {
233 return SkCodec::kInvalidParameters;
234 }
235 } else {
236 if (ctableCount) {
237 *ctableCount = 0;
238 }
239 ctableCount = nullptr;
240 ctable = nullptr;
241 }
242
scroggo3a7701c2015-09-30 09:15:14 -0700243 if (!this->rewindIfNeeded()) {
244 return kCouldNotRewind;
245 }
246
scroggo46c57472015-09-30 08:57:13 -0700247 // Set options.
248 Options optsStorage;
249 if (nullptr == options) {
250 options = &optsStorage;
scroggoe7fc14b2015-10-02 13:14:46 -0700251 } else if (options->fSubset) {
msarettfdb47572015-10-13 12:50:14 -0700252 SkIRect size = SkIRect::MakeSize(dstInfo.dimensions());
253 if (!size.contains(*options->fSubset)) {
254 return kInvalidInput;
255 }
256
257 // We only support subsetting in the x-dimension for scanline decoder.
258 // Subsetting in the y-dimension can be accomplished using skipScanlines().
259 if (options->fSubset->top() != 0 || options->fSubset->height() != dstInfo.height()) {
260 return kInvalidInput;
scroggoe7fc14b2015-10-02 13:14:46 -0700261 }
262 }
263
264 // FIXME: Support subsets somehow?
265 if (!this->dimensionsSupported(dstInfo.dimensions())) {
266 return kInvalidScale;
scroggo46c57472015-09-30 08:57:13 -0700267 }
268
269 const Result result = this->onStartScanlineDecode(dstInfo, *options, ctable, ctableCount);
270 if (result != SkCodec::kSuccess) {
271 return result;
272 }
273
274 fCurrScanline = 0;
275 fDstInfo = dstInfo;
276 fOptions = *options;
277 return kSuccess;
278}
279
280SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo) {
281 return this->startScanlineDecode(dstInfo, nullptr, nullptr, nullptr);
282}
283
msarette6dd0042015-10-09 11:07:34 -0700284int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) {
scroggo46c57472015-09-30 08:57:13 -0700285 if (fCurrScanline < 0) {
msarette6dd0042015-10-09 11:07:34 -0700286 return 0;
scroggo46c57472015-09-30 08:57:13 -0700287 }
288
289 SkASSERT(!fDstInfo.isEmpty());
scroggoe7fc14b2015-10-02 13:14:46 -0700290 if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) {
msarette6dd0042015-10-09 11:07:34 -0700291 return 0;
scroggo46c57472015-09-30 08:57:13 -0700292 }
293
msarette6dd0042015-10-09 11:07:34 -0700294 const int linesDecoded = this->onGetScanlines(dst, countLines, rowBytes);
295 if (linesDecoded < countLines) {
296 this->fillIncompleteImage(this->dstInfo(), dst, rowBytes, this->options().fZeroInitialized,
297 countLines, linesDecoded);
298 }
299 fCurrScanline += countLines;
300 return linesDecoded;
301}
302
303bool SkCodec::skipScanlines(int countLines) {
304 if (fCurrScanline < 0) {
305 return false;
306 }
307
308 SkASSERT(!fDstInfo.isEmpty());
309 if (countLines < 0 || fCurrScanline + countLines > fDstInfo.height()) {
310 // Arguably, we could just skip the scanlines which are remaining,
311 // and return true. We choose to return false so the client
312 // can catch their bug.
313 return false;
314 }
315
316 bool result = this->onSkipScanlines(countLines);
scroggo46c57472015-09-30 08:57:13 -0700317 fCurrScanline += countLines;
318 return result;
319}
320
msarette6dd0042015-10-09 11:07:34 -0700321int SkCodec::outputScanline(int inputScanline) const {
322 SkASSERT(0 <= inputScanline && inputScanline < this->getInfo().height());
323 return this->onOutputScanline(inputScanline);
324}
scroggo46c57472015-09-30 08:57:13 -0700325
msarette6dd0042015-10-09 11:07:34 -0700326int SkCodec::onOutputScanline(int inputScanline) const {
327 switch (this->getScanlineOrder()) {
328 case kTopDown_SkScanlineOrder:
329 case kNone_SkScanlineOrder:
330 return inputScanline;
331 case kBottomUp_SkScanlineOrder:
332 return this->getInfo().height() - inputScanline - 1;
333 default:
334 // This case indicates an interlaced gif and is implemented by SkGifCodec.
335 SkASSERT(false);
336 return 0;
scroggo46c57472015-09-30 08:57:13 -0700337 }
msarette6dd0042015-10-09 11:07:34 -0700338}
scroggo46c57472015-09-30 08:57:13 -0700339
msarette6dd0042015-10-09 11:07:34 -0700340static void fill_proc(const SkImageInfo& info, void* dst, size_t rowBytes,
341 uint32_t colorOrIndex, SkCodec::ZeroInitialized zeroInit, SkSampler* sampler) {
342 if (sampler) {
343 sampler->fill(info, dst, rowBytes, colorOrIndex, zeroInit);
344 } else {
345 SkSampler::Fill(info, dst, rowBytes, colorOrIndex, zeroInit);
346 }
347}
348
349void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t rowBytes,
350 ZeroInitialized zeroInit, int linesRequested, int linesDecoded) {
351
352 void* fillDst;
scroggoc5560be2016-02-03 09:42:42 -0800353 const uint32_t fillValue = this->getFillValue(info.colorType());
msarette6dd0042015-10-09 11:07:34 -0700354 const int linesRemaining = linesRequested - linesDecoded;
355 SkSampler* sampler = this->getSampler(false);
356
msarett91c22b22016-02-22 12:27:46 -0800357 int fillWidth = info.width();
358 if (fOptions.fSubset) {
359 fillWidth = fOptions.fSubset->width();
360 }
361
msarette6dd0042015-10-09 11:07:34 -0700362 switch (this->getScanlineOrder()) {
363 case kTopDown_SkScanlineOrder:
364 case kNone_SkScanlineOrder: {
msarett91c22b22016-02-22 12:27:46 -0800365 const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining);
msarette6dd0042015-10-09 11:07:34 -0700366 fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes);
367 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler);
368 break;
369 }
370 case kBottomUp_SkScanlineOrder: {
371 fillDst = dst;
msarett91c22b22016-02-22 12:27:46 -0800372 const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining);
msarette6dd0042015-10-09 11:07:34 -0700373 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler);
374 break;
375 }
376 case kOutOfOrder_SkScanlineOrder: {
377 SkASSERT(1 == linesRequested || this->getInfo().height() == linesRequested);
msarett91c22b22016-02-22 12:27:46 -0800378 const SkImageInfo fillInfo = info.makeWH(fillWidth, 1);
msarette6dd0042015-10-09 11:07:34 -0700379 for (int srcY = linesDecoded; srcY < linesRequested; srcY++) {
380 fillDst = SkTAddOffset<void>(dst, this->outputScanline(srcY) * rowBytes);
381 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler);
382 }
383 break;
384 }
385 }
scroggo46c57472015-09-30 08:57:13 -0700386}