diff options
author | msarett <msarett@google.com> | 2015-12-04 05:43:09 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-12-04 05:43:09 -0800 |
commit | 1603e9310f62cf0dd543cdb09dea06aa78373f13 (patch) | |
tree | 5ef44b26dbdec877f35834a79c0e6408e7518d9e /src/codec/SkBmpStandardCodec.cpp | |
parent | bbf2ce4b06bce1d5b70529b2fe08c159c1a93704 (diff) |
Make SkAndroidCodec support ico
BUG=skia:
Review URL: https://codereview.chromium.org/1472933002
Diffstat (limited to 'src/codec/SkBmpStandardCodec.cpp')
-rw-r--r-- | src/codec/SkBmpStandardCodec.cpp | 81 |
1 files changed, 61 insertions, 20 deletions
diff --git a/src/codec/SkBmpStandardCodec.cpp b/src/codec/SkBmpStandardCodec.cpp index fd4d6d18bc..9e90f3c630 100644 --- a/src/codec/SkBmpStandardCodec.cpp +++ b/src/codec/SkBmpStandardCodec.cpp @@ -27,6 +27,7 @@ SkBmpStandardCodec::SkBmpStandardCodec(const SkImageInfo& info, SkStream* stream , fSrcRowBytes(SkAlign4(compute_row_bytes(this->getInfo().width(), this->bitsPerPixel()))) , fSrcBuffer(new uint8_t [fSrcRowBytes]) , fInIco(inIco) + , fAndMaskRowBytes(fInIco ? SkAlign4(compute_row_bytes(this->getInfo().width(), 1)) : 0) {} /* @@ -60,9 +61,6 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, *rowsDecoded = rows; return kIncompleteInput; } - if (fInIco) { - return this->decodeIcoMask(dstInfo, dst, dstRowBytes); - } return kSuccess; } @@ -227,9 +225,8 @@ SkCodec::Result SkBmpStandardCodec::prepareToDecode(const SkImageInfo& dstInfo, /* * Performs the bitmap decoding for standard input format */ -int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, - void* dst, size_t dstRowBytes, - const Options& opts) { +int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, + const Options& opts) { // Iterate over rows of the image const int height = dstInfo.height(); for (int y = 0; y < height; y++) { @@ -246,29 +243,75 @@ int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, fSwizzler->swizzle(dstRow, fSrcBuffer.get()); } - // Finished decoding the entire image + if (fInIco) { + const int startScanline = this->currScanline(); + if (startScanline < 0) { + // We are not performing a scanline decode. + // Just decode the entire ICO mask and return. + decodeIcoMask(this->stream(), dstInfo, dst, dstRowBytes); + return height; + } + + // In order to perform a scanline ICO decode, we must be able + // to skip ahead in the stream in order to apply the AND mask + // to the requested scanlines. + // We will do this by taking advantage of the fact that + // SkIcoCodec always uses a SkMemoryStream as its underlying + // representation of the stream. + const void* memoryBase = this->stream()->getMemoryBase(); + SkASSERT(nullptr != memoryBase); + SkASSERT(this->stream()->hasLength()); + SkASSERT(this->stream()->hasPosition()); + + const size_t length = this->stream()->getLength(); + const size_t currPosition = this->stream()->getPosition(); + + // 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 + + startScanline * fAndMaskRowBytes; + const size_t subStreamStartPosition = currPosition + bytesToSkip; + if (subStreamStartPosition >= length) { + // FIXME: How can we indicate that this decode was actually incomplete? + return height; + } + + // Create a subStream to pass to decodeIcoMask(). It is useful to encapsulate + // the memory base into a stream in order to safely handle incomplete images + // without reading out of bounds memory. + const void* subStreamMemoryBase = SkTAddOffset<const void>(memoryBase, + subStreamStartPosition); + const size_t subStreamLength = length - subStreamStartPosition; + // This call does not transfer ownership of the subStreamMemoryBase. + SkMemoryStream subStream(subStreamMemoryBase, subStreamLength, false); + + // FIXME: If decodeIcoMask does not succeed, is there a way that we can + // indicate the decode was incomplete? + decodeIcoMask(&subStream, dstInfo, dst, dstRowBytes); + } + return height; } -// TODO (msarett): This function will need to be modified in order to perform row by row decodes -// when the Ico scanline decoder is implemented. -SkCodec::Result SkBmpStandardCodec::decodeIcoMask(const SkImageInfo& dstInfo, +void SkBmpStandardCodec::decodeIcoMask(SkStream* stream, const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes) { // BMP in ICO have transparency, so this cannot be 565, and this mask // prevents us from using kIndex8. The below code depends on the output // being an SkPMColor. SkASSERT(dstInfo.colorType() == kN32_SkColorType); - // The AND mask is always 1 bit per pixel - const int width = this->getInfo().width(); - const size_t rowBytes = SkAlign4(compute_row_bytes(width, 1)); + // If we are sampling, make sure that we only mask the sampled pixels. + // We do not need to worry about sampling in the y-dimension because that + // should be handled by SkSampledCodec. + int sampleX = fSwizzler->sampleX(); + int startX = get_start_coord(sampleX); SkPMColor* dstPtr = (SkPMColor*) dst; for (int y = 0; y < dstInfo.height(); y++) { // The srcBuffer will at least be large enough - if (stream()->read(fSrcBuffer.get(), rowBytes) != rowBytes) { + if (stream->read(fSrcBuffer.get(), fAndMaskRowBytes) != fAndMaskRowBytes) { SkCodecPrintf("Warning: incomplete AND mask for bmp-in-ico.\n"); - return kIncompleteInput; + return; } int row = this->getDstRow(y, dstInfo.height()); @@ -276,17 +319,15 @@ SkCodec::Result SkBmpStandardCodec::decodeIcoMask(const SkImageInfo& dstInfo, SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dstPtr, row * dstRowBytes); - for (int x = 0; x < width; x++) { + for (int x = startX; x < this->getInfo().width(); x += sampleX) { int quotient; int modulus; SkTDivMod(x, 8, "ient, &modulus); uint32_t shift = 7 - modulus; - uint32_t alphaBit = - (fSrcBuffer.get()[quotient] >> shift) & 0x1; - dstRow[x] &= alphaBit - 1; + uint32_t alphaBit = (fSrcBuffer.get()[quotient] >> shift) & 0x1; + dstRow[get_dst_coord(x, sampleX)] &= alphaBit - 1; } } - return kSuccess; } uint32_t SkBmpStandardCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType) const { |