Chromium Code Reviews| Index: src/codec/SkBmpStandardCodec.cpp |
| diff --git a/src/codec/SkBmpStandardCodec.cpp b/src/codec/SkBmpStandardCodec.cpp |
| index fd4d6d18bc2d3df2ea6366554dc3bf56ec72700e..00164c604a09f5b5f224617a69d2369fc009973a 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,74 @@ 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); |
| + const size_t length = this->stream()->getLength(); |
| + SkASSERT(this->stream()->hasLength()); |
|
scroggo
2015/12/03 19:39:25
I think this belongs above the call to getLength
msarett
2015/12/03 19:54:15
Done.
|
| + const size_t currPosition = this->stream()->getPosition(); |
| + SkASSERT(this->stream()->hasPosition()); |
|
scroggo
2015/12/03 19:39:24
Same here. Maybe put all the SkASSERTs together? I
msarett
2015/12/03 19:54:15
sgtm
|
| + |
| + // 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 +318,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 { |