diff --git a/include/codec/SkCodec.h b/include/codec/SkCodec.h index edc8ec38fa..c3a5873d7f 100644 --- a/include/codec/SkCodec.h +++ b/include/codec/SkCodec.h @@ -657,18 +657,7 @@ private: return kUnimplemented; } - // Naive default version just calls onGetScanlines on temp memory. - virtual bool onSkipScanlines(int countLines) { - // FIXME (msarett): Make this a pure virtual and always override this. - SkAutoMalloc storage(fDstInfo.minRowBytes()); - - // Note that we pass 0 to rowBytes so we continue to use the same memory. - // Also note that while getScanlines checks that rowBytes is big enough, - // onGetScanlines bypasses that check. - // Calling the virtual method also means we do not double count - // countLines. - return countLines == this->onGetScanlines(storage.get(), countLines, 0); - } + virtual bool onSkipScanlines(int /*countLines*/) { return false; } virtual int onGetScanlines(void* /*dst*/, int /*countLines*/, size_t /*rowBytes*/) { return 0; } diff --git a/src/codec/SkBmpCodec.cpp b/src/codec/SkBmpCodec.cpp index cbba28c172..babb17d32e 100644 --- a/src/codec/SkBmpCodec.cpp +++ b/src/codec/SkBmpCodec.cpp @@ -546,6 +546,7 @@ SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream, : INHERITED(info, stream) , fBitsPerPixel(bitsPerPixel) , fRowOrder(rowOrder) + , fSrcRowBytes(SkAlign4(compute_row_bytes(info.width(), fBitsPerPixel))) {} bool SkBmpCodec::onRewind() { @@ -577,3 +578,12 @@ int SkBmpCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { // Decode the requested rows return this->decodeRows(rowInfo, dst, rowBytes, this->options()); } + +bool SkBmpCodec::skipRows(int count) { + const size_t bytesToSkip = count * fSrcRowBytes; + return this->stream()->skip(bytesToSkip) == bytesToSkip; +} + +bool SkBmpCodec::onSkipScanlines(int count) { + return this->skipRows(count); +} diff --git a/src/codec/SkBmpCodec.h b/src/codec/SkBmpCodec.h index 5d77ca3fc8..a54734f431 100644 --- a/src/codec/SkBmpCodec.h +++ b/src/codec/SkBmpCodec.h @@ -81,6 +81,7 @@ protected: */ uint16_t bitsPerPixel() const { return fBitsPerPixel; } SkScanlineOrder onGetScanlineOrder() const override { return fRowOrder; } + size_t srcRowBytes() const { return fSrcRowBytes; } /* * To be overriden by bmp subclasses, which provide unique implementations. @@ -127,15 +128,18 @@ private: virtual int decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts) = 0; + virtual bool skipRows(int count); + Result onStartScanlineDecode(const SkImageInfo& dstInfo, const SkCodec::Options&, SkPMColor inputColorPtr[], int* inputColorCount) override; int onGetScanlines(void* dst, int count, size_t rowBytes) override; - // TODO(msarett): Override default skipping with something more clever. + bool onSkipScanlines(int count) override; const uint16_t fBitsPerPixel; const SkScanlineOrder fRowOrder; + const size_t fSrcRowBytes; typedef SkCodec INHERITED; }; diff --git a/src/codec/SkBmpMaskCodec.cpp b/src/codec/SkBmpMaskCodec.cpp index b173317c10..b603de9a03 100644 --- a/src/codec/SkBmpMaskCodec.cpp +++ b/src/codec/SkBmpMaskCodec.cpp @@ -18,8 +18,7 @@ SkBmpMaskCodec::SkBmpMaskCodec(const SkImageInfo& info, SkStream* stream, : INHERITED(info, stream, bitsPerPixel, rowOrder) , fMasks(masks) , fMaskSwizzler(nullptr) - , fSrcRowBytes(SkAlign4(compute_row_bytes(this->getInfo().width(), this->bitsPerPixel()))) - , fSrcBuffer(new uint8_t [fSrcRowBytes]) + , fSrcBuffer(new uint8_t [this->srcRowBytes()]) {} /* @@ -92,7 +91,7 @@ int SkBmpMaskCodec::decodeRows(const SkImageInfo& dstInfo, const int height = dstInfo.height(); for (int y = 0; y < height; y++) { // Read a row of the input - if (this->stream()->read(srcRow, fSrcRowBytes) != fSrcRowBytes) { + if (this->stream()->read(srcRow, this->srcRowBytes()) != this->srcRowBytes()) { SkCodecPrintf("Warning: incomplete input stream.\n"); return y; } diff --git a/src/codec/SkBmpMaskCodec.h b/src/codec/SkBmpMaskCodec.h index 4ec868db0e..73a8b3799d 100644 --- a/src/codec/SkBmpMaskCodec.h +++ b/src/codec/SkBmpMaskCodec.h @@ -55,7 +55,6 @@ private: SkAutoTDelete fMasks; // owned SkAutoTDelete fMaskSwizzler; - const size_t fSrcRowBytes; SkAutoTDeleteArray fSrcBuffer; typedef SkBmpCodec INHERITED; diff --git a/src/codec/SkBmpRLECodec.cpp b/src/codec/SkBmpRLECodec.cpp index 05691cc079..1b95acc830 100644 --- a/src/codec/SkBmpRLECodec.cpp +++ b/src/codec/SkBmpRLECodec.cpp @@ -201,7 +201,7 @@ size_t SkBmpRLECodec::checkForMoreData() { void SkBmpRLECodec::setPixel(void* dst, size_t dstRowBytes, const SkImageInfo& dstInfo, uint32_t x, uint32_t y, uint8_t index) { - if (is_coord_necessary(x, fSampleX, dstInfo.width())) { + if (dst && is_coord_necessary(x, fSampleX, dstInfo.width())) { // Set the row uint32_t row = this->getDstRow(y, dstInfo.height()); @@ -234,7 +234,7 @@ void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes, const SkImageInfo& dstInfo, uint32_t x, uint32_t y, uint8_t red, uint8_t green, uint8_t blue) { - if (is_coord_necessary(x, fSampleX, dstInfo.width())) { + if (dst && is_coord_necessary(x, fSampleX, dstInfo.width())) { // Set the row uint32_t row = this->getDstRow(y, dstInfo.height()); @@ -316,7 +316,9 @@ int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB // Because of the need for transparent pixels, kN32 is the only color // type that makes sense for the destination format. SkASSERT(kN32_SkColorType == dstInfo.colorType()); - SkSampler::Fill(dstInfo, dst, dstRowBytes, SK_ColorTRANSPARENT, opts.fZeroInitialized); + if (dst) { + SkSampler::Fill(dstInfo, dst, dstRowBytes, SK_ColorTRANSPARENT, opts.fZeroInitialized); + } // Adjust the height and the dst if the previous call to decodeRows() left us // with lines that need to be skipped. @@ -500,6 +502,13 @@ int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB } } +bool SkBmpRLECodec::skipRows(int count) { + const SkImageInfo rowInfo = SkImageInfo::Make(this->getInfo().width(), count, kN32_SkColorType, + kUnpremul_SkAlphaType); + + return count == this->decodeRows(rowInfo, nullptr, 0, this->options()); +} + // FIXME: Make SkBmpRLECodec have no knowledge of sampling. // Or it should do all sampling natively. // It currently is a hybrid that needs to know what SkScaledCodec is doing. diff --git a/src/codec/SkBmpRLECodec.h b/src/codec/SkBmpRLECodec.h index e319a71052..2ddf8d8b90 100644 --- a/src/codec/SkBmpRLECodec.h +++ b/src/codec/SkBmpRLECodec.h @@ -84,9 +84,14 @@ private: const SkImageInfo& dstInfo, uint32_t x, uint32_t y, uint8_t red, uint8_t green, uint8_t blue); + /* + * If dst is NULL, this is a signal to skip the rows. + */ int decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts) override; + bool skipRows(int count) override; + SkSampler* getSampler(bool createIfNecessary) override; SkAutoTUnref fColorTable; // owned diff --git a/src/codec/SkBmpStandardCodec.cpp b/src/codec/SkBmpStandardCodec.cpp index 66a8c9a12a..47b10701d3 100644 --- a/src/codec/SkBmpStandardCodec.cpp +++ b/src/codec/SkBmpStandardCodec.cpp @@ -25,8 +25,7 @@ SkBmpStandardCodec::SkBmpStandardCodec(const SkImageInfo& info, SkStream* stream , fBytesPerColor(bytesPerColor) , fOffset(offset) , fSwizzler(nullptr) - , fSrcRowBytes(SkAlign4(compute_row_bytes(this->getInfo().width(), this->bitsPerPixel()))) - , fSrcBuffer(new uint8_t [fSrcRowBytes]) + , fSrcBuffer(new uint8_t [this->srcRowBytes()]) , fIsOpaque(isOpaque) , fInIco(inIco) , fAndMaskRowBytes(fInIco ? SkAlign4(compute_row_bytes(this->getInfo().width(), 1)) : 0) @@ -225,7 +224,7 @@ int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t const int height = dstInfo.height(); for (int y = 0; y < height; y++) { // Read a row of the input - if (this->stream()->read(fSrcBuffer.get(), fSrcRowBytes) != fSrcRowBytes) { + if (this->stream()->read(fSrcBuffer.get(), this->srcRowBytes()) != this->srcRowBytes()) { SkCodecPrintf("Warning: incomplete input stream.\n"); return y; } @@ -262,7 +261,7 @@ int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t // Calculate how many bytes we must skip to reach the AND mask. const int remainingScanlines = this->getInfo().height() - startScanline - height; - const size_t bytesToSkip = remainingScanlines * fSrcRowBytes + + const size_t bytesToSkip = remainingScanlines * this->srcRowBytes() + startScanline * fAndMaskRowBytes; const size_t subStreamStartPosition = currPosition + bytesToSkip; if (subStreamStartPosition >= length) { diff --git a/src/codec/SkBmpStandardCodec.h b/src/codec/SkBmpStandardCodec.h index 725b7bb68f..d3e2ed3e4f 100644 --- a/src/codec/SkBmpStandardCodec.h +++ b/src/codec/SkBmpStandardCodec.h @@ -90,7 +90,6 @@ private: const uint32_t fBytesPerColor; const uint32_t fOffset; SkAutoTDelete fSwizzler; - const size_t fSrcRowBytes; SkAutoTDeleteArray fSrcBuffer; const bool fIsOpaque; const bool fInIco; diff --git a/src/codec/SkWbmpCodec.cpp b/src/codec/SkWbmpCodec.cpp index 4dd0f2544d..af1ab46f73 100644 --- a/src/codec/SkWbmpCodec.cpp +++ b/src/codec/SkWbmpCodec.cpp @@ -181,6 +181,11 @@ int SkWbmpCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) { return count; } +bool SkWbmpCodec::onSkipScanlines(int count) { + const size_t bytesToSkip = count * fSrcRowBytes; + return this->stream()->skip(bytesToSkip) == bytesToSkip; +} + SkCodec::Result SkWbmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options, SkPMColor inputColorTable[], int* inputColorCount) { if (options.fSubset) { diff --git a/src/codec/SkWbmpCodec.h b/src/codec/SkWbmpCodec.h index fb062c94d5..ceeadd4cc8 100644 --- a/src/codec/SkWbmpCodec.h +++ b/src/codec/SkWbmpCodec.h @@ -52,8 +52,8 @@ private: SkAutoTUnref fColorTable; SkAutoTMalloc fSrcBuffer; - // FIXME: Override onSkipScanlines to avoid swizzling. int onGetScanlines(void* dst, int count, size_t dstRowBytes) override; + bool onSkipScanlines(int count) override; Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options, SkPMColor inputColorTable[], int* inputColorCount) override;