Files
palemoon27/image/decoders/nsICODecoder.cpp
T
roytam1 cbc917768b import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1266578 - OOM crash if malloc fails in ProcessIncomingMessages(). r=billm (5eca51be20)
- Bug 1261340: Don't refer to |ScopedFreePtrTraits| in |RawDBusConnection|, r=shuang (61996db57c)
- Bug 1246931: Move |DBusWatcher| into its own files, r=shuang (a7fc4a68c3)
- Bug 1246931: Add support for |RefPtr<DBusConnection>| and convert callers, r=shuang (6c07d3e8d3)
- Bug 1246931: Add support for |RefPtr<DBusMessage>|, r=shuang (c0ed14cc2b)
- Bug 1246931: Add support for |RefPtr<DBusPendingCall>|, r=shuang (a007a15699)
- Bug 1246931: Use |DBusConnection| in |DBusWatcher|, r=shuang (11b5eaf535)
- Bug 1246931: Add DBus I/O helpers, r=shuang (be249fa65b)
- Bug 1264398 - Avoid extra assign() on windows in IPC code (r=jld) (0f31b798a3)
- Bug 1261231: Fix shutdown leak in imgLoader::GetInstance. r=gabor (96e5143c41)
- Bug 1256999 - Use nsIDocument for ImageCacheKey. r=bz r=seth (cd4765ce34)
- Bug 1257101. imgFrame::IsImageComplete says whether we've had pixels decoded to the whole image rect, but it's used to check if the frame is finished decoding. These are different things when the image has more than one progress pass. r=seth (06d619410f)
- Bug 1222596. If RasterImage::LookupFrame does (some) sync decoding and encouters an error we don't want to return the surface with an error. r=seth (c4dbc8e0d5)
- Bug 763784 - Make VectorImage::GetAnimated check for CSS animations. r=dholbert (4d0e5b88eb)
- Bug 1210745 - Update CheckProgressConsistency() to match current ImageLib behavior. r=tn (2317b24fcc)
- Bug 1249576. Add crashtest. (485f03120b)
- Bug 1251091. Add crashtest. (7e1682a1e6)
- Bug 1253362. SVGDocumentWrapper::IsAnimated can be called after SVGDocumentWrapper::DestroyViewer so null check mViewer. r=dholbert (2b4a1c4619)
- Bug 1210745. Change image progress asserts to allow transparency to be posted after the size is posted. r=seth (699f3c5496)
- Bug 1209780. Use the DrawResult return value of imgIContainer::Draw in the cocoa code. r=seth (abaea789e3)
- No Bug - Remove some unnecessary SVGImageContext.h includes and add comments. r=sparky (8232661a23)
- cleanup style (de33e4bfa8)
- Bug 860857, support custom datatransfer types using a special type, r=smaug,jmathies,mstange (cf7e19deb6)
- Bug 1248459 - Don't query out-of-bounds selection; r=masayuki (86c127f143)
- Bug 1261671 - ContentEventHandler::ConvertToRootRelativeOffset() should return the root-relative result in the frame's own appUnits, not the root's appUnits in the case when they're different. r=masayuki (2cd72b5ebc)
- Bug 1266702 - Clean up formatting in dom/events/DataTransfer.* and mark some methods const, r=jwatt (bd439cdad5)
2024-07-26 21:49:43 +08:00

659 lines
22 KiB
C++

/* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* This is a Cross-Platform ICO Decoder, which should work everywhere, including
* Big-Endian machines like the PowerPC. */
#include <stdlib.h>
#include "mozilla/Endian.h"
#include "mozilla/Move.h"
#include "nsICODecoder.h"
#include "RasterImage.h"
using namespace mozilla::gfx;
namespace mozilla {
namespace image {
// Constants.
static const uint32_t ICOHEADERSIZE = 6;
static const uint32_t BITMAPINFOSIZE = bmp::InfoHeaderLength::WIN_ICO;
// ----------------------------------------
// Actual Data Processing
// ----------------------------------------
// Obtains the number of colors from the bits per pixel
uint16_t
nsICODecoder::GetNumColors()
{
uint16_t numColors = 0;
if (mBPP <= 8) {
switch (mBPP) {
case 1:
numColors = 2;
break;
case 4:
numColors = 16;
break;
case 8:
numColors = 256;
break;
default:
numColors = (uint16_t)-1;
}
}
return numColors;
}
nsICODecoder::nsICODecoder(RasterImage* aImage)
: Decoder(aImage)
, mLexer(Transition::To(ICOState::HEADER, ICOHEADERSIZE))
, mBiggestResourceColorDepth(0)
, mBestResourceDelta(INT_MIN)
, mBestResourceColorDepth(0)
, mNumIcons(0)
, mCurrIcon(0)
, mBPP(0)
, mMaskRowSize(0)
, mCurrMaskLine(0)
, mIsCursor(false)
, mHasMaskAlpha(false)
{ }
void
nsICODecoder::FinishInternal()
{
// We shouldn't be called in error cases
MOZ_ASSERT(!HasError(), "Shouldn't call FinishInternal after error!");
GetFinalStateFromContainedDecoder();
}
void
nsICODecoder::FinishWithErrorInternal()
{
GetFinalStateFromContainedDecoder();
}
void
nsICODecoder::GetFinalStateFromContainedDecoder()
{
if (!mContainedDecoder) {
return;
}
// Finish the internally used decoder.
mContainedDecoder->CompleteDecode();
mDecodeDone = mContainedDecoder->GetDecodeDone();
mDataError = mDataError || mContainedDecoder->HasDataError();
mFailCode = NS_SUCCEEDED(mFailCode) ? mContainedDecoder->GetDecoderError()
: mFailCode;
mDecodeAborted = mContainedDecoder->WasAborted();
mProgress |= mContainedDecoder->TakeProgress();
mInvalidRect.UnionRect(mInvalidRect, mContainedDecoder->TakeInvalidRect());
mCurrentFrame = mContainedDecoder->GetCurrentFrameRef();
MOZ_ASSERT(HasError() || !mCurrentFrame || mCurrentFrame->IsFinished());
}
bool
nsICODecoder::CheckAndFixBitmapSize(int8_t* bih)
{
// Get the width from the BMP file information header. This is
// (unintuitively) a signed integer; see the documentation at:
//
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx
//
// However, we reject negative widths since they aren't meaningful.
int32_t width;
memcpy(&width, bih + 4, sizeof(width));
NativeEndian::swapFromLittleEndianInPlace(&width, 1);
if (width <= 0 || width > 256) {
return false;
}
// Verify that the BMP width matches the width we got from the ICO directory
// entry. If not, decoding fails, because if we were to allow it to continue
// the intrinsic size of the image wouldn't match the size of the decoded
// surface.
if (width != int32_t(GetRealWidth())) {
return false;
}
// Get the height from the BMP file information header. This is also signed,
// but in this case negative values are meaningful; see below.
int32_t height;
memcpy(&height, bih + 8, sizeof(height));
NativeEndian::swapFromLittleEndianInPlace(&height, 1);
if (height == 0) {
return false;
}
// BMPs can be stored inverted by having a negative height.
// XXX(seth): Should we really be writing the absolute value into the BIH
// below? Seems like this could be problematic for inverted BMPs.
height = abs(height);
// The height field is double the actual height of the image to account for
// the AND mask. This is true even if the AND mask is not present.
height /= 2;
if (height > 256) {
return false;
}
// Verify that the BMP height matches the height we got from the ICO directory
// entry. If not, again, decoding fails.
if (height != int32_t(GetRealHeight())) {
return false;
}
// Fix the BMP height in the BIH so that the BMP decoder, which does not know
// about the AND mask that may follow the actual bitmap, can work properly.
NativeEndian::swapToLittleEndianInPlace(&height, 1);
memcpy(bih + 8, &height, sizeof(height));
return true;
}
LexerTransition<ICOState>
nsICODecoder::ReadHeader(const char* aData)
{
// If the third byte is 1, this is an icon. If 2, a cursor.
if ((aData[2] != 1) && (aData[2] != 2)) {
return Transition::TerminateFailure();
}
mIsCursor = (aData[2] == 2);
// The fifth and sixth bytes specify the number of resources in the file.
mNumIcons = LittleEndian::readUint16(aData + 4);
if (mNumIcons == 0) {
return Transition::TerminateSuccess(); // Nothing to do.
}
// Downscale-during-decode can end up decoding different resources in the ICO
// file depending on the target size. Since the resources are not necessarily
// scaled versions of the same image, some may be transparent and some may not
// be. We could be precise about transparency if we decoded the metadata of
// every resource, but for now we don't and it's safest to assume that
// transparency could be present.
PostHasTransparency();
return Transition::To(ICOState::DIR_ENTRY, ICODIRENTRYSIZE);
}
size_t
nsICODecoder::FirstResourceOffset() const
{
MOZ_ASSERT(mNumIcons > 0,
"Calling FirstResourceOffset before processing header");
// The first resource starts right after the directory, which starts right
// after the ICO header.
return ICOHEADERSIZE + mNumIcons * ICODIRENTRYSIZE;
}
LexerTransition<ICOState>
nsICODecoder::ReadDirEntry(const char* aData)
{
mCurrIcon++;
// Read the directory entry.
IconDirEntry e;
e.mWidth = aData[0];
e.mHeight = aData[1];
e.mColorCount = aData[2];
e.mReserved = aData[3];
e.mPlanes = LittleEndian::readUint16(aData + 4);
e.mBitCount = LittleEndian::readUint16(aData + 6);
e.mBytesInRes = LittleEndian::readUint32(aData + 8);
e.mImageOffset = LittleEndian::readUint32(aData + 12);
// Determine if this is the biggest resource we've seen so far. We always use
// the biggest resource for the intrinsic size, and if we're not downscaling,
// we select it as the best resource as well.
IntSize entrySize(GetRealWidth(e), GetRealHeight(e));
if (e.mBitCount >= mBiggestResourceColorDepth &&
entrySize.width * entrySize.height >=
mBiggestResourceSize.width * mBiggestResourceSize.height) {
mBiggestResourceSize = entrySize;
mBiggestResourceColorDepth = e.mBitCount;
mBiggestResourceHotSpot = IntSize(e.mXHotspot, e.mYHotspot);
if (!mDownscaler) {
mDirEntry = e;
}
}
if (mDownscaler) {
// Calculate the delta between this resource's size and the desired size, so
// we can see if it is better than our current-best option. In the case of
// several equally-good resources, we use the last one. "Better" in this
// case is determined by |delta|, a measure of the difference in size
// between the entry we've found and the downscaler's target size. We will
// choose the smallest resource that is >= the target size (i.e. we assume
// it's better to downscale a larger icon than to upscale a smaller one).
IntSize desiredSize = mDownscaler->TargetSize();
int32_t delta = std::min(entrySize.width - desiredSize.width,
entrySize.height - desiredSize.height);
if (e.mBitCount >= mBestResourceColorDepth &&
((mBestResourceDelta < 0 && delta >= mBestResourceDelta) ||
(delta >= 0 && delta <= mBestResourceDelta))) {
mBestResourceDelta = delta;
mBestResourceColorDepth = e.mBitCount;
mDirEntry = e;
}
}
if (mCurrIcon == mNumIcons) {
// Ensure the resource we selected has an offset past the ICO headers.
if (mDirEntry.mImageOffset < FirstResourceOffset()) {
return Transition::TerminateFailure();
}
// If this is a cursor, set the hotspot. We use the hotspot from the biggest
// resource since we also use that resource for the intrinsic size.
if (mIsCursor) {
mImageMetadata.SetHotspot(mBiggestResourceHotSpot.width,
mBiggestResourceHotSpot.height);
}
// We always report the biggest resource's size as the intrinsic size; this
// is necessary for downscale-during-decode to work since we won't even
// attempt to *upscale* while decoding.
PostSize(mBiggestResourceSize.width, mBiggestResourceSize.height);
if (IsMetadataDecode()) {
return Transition::TerminateSuccess();
}
// If the resource we selected matches the downscaler's target size
// perfectly, we don't need to do any downscaling.
if (mDownscaler && GetRealSize() == mDownscaler->TargetSize()) {
mDownscaler.reset();
}
size_t offsetToResource = mDirEntry.mImageOffset - FirstResourceOffset();
return Transition::ToUnbuffered(ICOState::FOUND_RESOURCE,
ICOState::SKIP_TO_RESOURCE,
offsetToResource);
}
return Transition::To(ICOState::DIR_ENTRY, ICODIRENTRYSIZE);
}
LexerTransition<ICOState>
nsICODecoder::SniffResource(const char* aData)
{
// We use the first PNGSIGNATURESIZE bytes to determine whether this resource
// is a PNG or a BMP.
bool isPNG = !memcmp(aData, nsPNGDecoder::pngSignatureBytes,
PNGSIGNATURESIZE);
if (isPNG) {
// Create a PNG decoder which will do the rest of the work for us.
mContainedDecoder = new nsPNGDecoder(mImage);
mContainedDecoder->SetMetadataDecode(IsMetadataDecode());
mContainedDecoder->SetDecoderFlags(GetDecoderFlags());
mContainedDecoder->SetSurfaceFlags(GetSurfaceFlags());
if (mDownscaler) {
mContainedDecoder->SetTargetSize(mDownscaler->TargetSize());
}
mContainedDecoder->Init();
if (!WriteToContainedDecoder(aData, PNGSIGNATURESIZE)) {
return Transition::TerminateFailure();
}
if (mDirEntry.mBytesInRes <= PNGSIGNATURESIZE) {
return Transition::TerminateFailure();
}
// Read in the rest of the PNG unbuffered.
size_t toRead = mDirEntry.mBytesInRes - PNGSIGNATURESIZE;
return Transition::ToUnbuffered(ICOState::FINISHED_RESOURCE,
ICOState::READ_PNG,
toRead);
} else {
// Make sure we have a sane size for the bitmap information header.
int32_t bihSize = LittleEndian::readUint32(aData);
if (bihSize != static_cast<int32_t>(BITMAPINFOSIZE)) {
return Transition::TerminateFailure();
}
// Buffer the first part of the bitmap information header.
memcpy(mBIHraw, aData, PNGSIGNATURESIZE);
// Read in the rest of the bitmap information header.
return Transition::To(ICOState::READ_BIH,
BITMAPINFOSIZE - PNGSIGNATURESIZE);
}
}
LexerTransition<ICOState>
nsICODecoder::ReadPNG(const char* aData, uint32_t aLen)
{
if (!WriteToContainedDecoder(aData, aLen)) {
return Transition::TerminateFailure();
}
// Raymond Chen says that 32bpp only are valid PNG ICOs
// http://blogs.msdn.com/b/oldnewthing/archive/2010/10/22/10079192.aspx
if (!static_cast<nsPNGDecoder*>(mContainedDecoder.get())->IsValidICO()) {
return Transition::TerminateFailure();
}
return Transition::ContinueUnbuffered(ICOState::READ_PNG);
}
LexerTransition<ICOState>
nsICODecoder::ReadBIH(const char* aData)
{
// Buffer the rest of the bitmap information header.
memcpy(mBIHraw + PNGSIGNATURESIZE, aData, BITMAPINFOSIZE - PNGSIGNATURESIZE);
// Extract the BPP from the BIH header; it should be trusted over the one
// we have from the ICO header which is usually set to 0.
mBPP = LittleEndian::readUint16(mBIHraw + 14);
// The ICO format when containing a BMP does not include the 14 byte
// bitmap file header. So we create the BMP decoder via the constructor that
// tells it to skip this, and pass in the required data (dataOffset) that
// would have been present in the header.
uint32_t dataOffset = bmp::FILE_HEADER_LENGTH + BITMAPINFOSIZE;
if (mDirEntry.mBitCount <= 8) {
// The color table is present only if BPP is <= 8.
uint16_t numColors = GetNumColors();
if (numColors == (uint16_t)-1) {
return Transition::TerminateFailure();
}
dataOffset += 4 * numColors;
}
// Create a BMP decoder which will do most of the work for us; the exception
// is the AND mask, which isn't present in standalone BMPs.
RefPtr<nsBMPDecoder> bmpDecoder = new nsBMPDecoder(mImage, dataOffset);
mContainedDecoder = bmpDecoder;
mContainedDecoder->SetMetadataDecode(IsMetadataDecode());
mContainedDecoder->SetDecoderFlags(GetDecoderFlags());
mContainedDecoder->SetSurfaceFlags(GetSurfaceFlags());
if (mDownscaler) {
mContainedDecoder->SetTargetSize(mDownscaler->TargetSize());
}
mContainedDecoder->Init();
// Verify that the BIH width and height values match the ICO directory entry,
// and fix the BIH height value to compensate for the fact that the underlying
// BMP decoder doesn't know about AND masks.
if (!CheckAndFixBitmapSize(reinterpret_cast<int8_t*>(mBIHraw))) {
return Transition::TerminateFailure();
}
// Write out the BMP's bitmap info header.
if (!WriteToContainedDecoder(mBIHraw, sizeof(mBIHraw))) {
return Transition::TerminateFailure();
}
// Check to make sure we have valid color settings.
uint16_t numColors = GetNumColors();
if (numColors == uint16_t(-1)) {
return Transition::TerminateFailure();
}
// Do we have an AND mask on this BMP? If so, we need to read it after we read
// the BMP data itself.
uint32_t bmpDataLength = bmpDecoder->GetCompressedImageSize() + 4 * numColors;
bool hasANDMask = (BITMAPINFOSIZE + bmpDataLength) < mDirEntry.mBytesInRes;
ICOState afterBMPState = hasANDMask ? ICOState::PREPARE_FOR_MASK
: ICOState::FINISHED_RESOURCE;
// Read in the rest of the BMP unbuffered.
return Transition::ToUnbuffered(afterBMPState,
ICOState::READ_BMP,
bmpDataLength);
}
LexerTransition<ICOState>
nsICODecoder::ReadBMP(const char* aData, uint32_t aLen)
{
if (!WriteToContainedDecoder(aData, aLen)) {
return Transition::TerminateFailure();
}
return Transition::ContinueUnbuffered(ICOState::READ_BMP);
}
LexerTransition<ICOState>
nsICODecoder::PrepareForMask()
{
RefPtr<nsBMPDecoder> bmpDecoder =
static_cast<nsBMPDecoder*>(mContainedDecoder.get());
uint16_t numColors = GetNumColors();
MOZ_ASSERT(numColors != uint16_t(-1));
// Determine the length of the AND mask.
uint32_t bmpLengthWithHeader =
BITMAPINFOSIZE + bmpDecoder->GetCompressedImageSize() + 4 * numColors;
MOZ_ASSERT(bmpLengthWithHeader < mDirEntry.mBytesInRes);
uint32_t maskLength = mDirEntry.mBytesInRes - bmpLengthWithHeader;
// If the BMP provides its own transparency, we ignore the AND mask. We can
// also obviously ignore it if the image has zero width or zero height.
if (bmpDecoder->HasTransparency() ||
GetRealWidth() == 0 || GetRealHeight() == 0) {
return Transition::ToUnbuffered(ICOState::FINISHED_RESOURCE,
ICOState::SKIP_MASK,
maskLength);
}
// Compute the row size for the mask.
mMaskRowSize = ((GetRealWidth() + 31) / 32) * 4; // + 31 to round up
// If the expected size of the AND mask is larger than its actual size, then
// we must have a truncated (and therefore corrupt) AND mask.
uint32_t expectedLength = mMaskRowSize * GetRealHeight();
if (maskLength < expectedLength) {
return Transition::TerminateFailure();
}
// If we're downscaling, the mask is the wrong size for the surface we've
// produced, so we need to downscale the mask into a temporary buffer and then
// combine the mask's alpha values with the color values from the image.
if (mDownscaler) {
MOZ_ASSERT(bmpDecoder->GetImageDataLength() ==
mDownscaler->TargetSize().width *
mDownscaler->TargetSize().height *
sizeof(uint32_t));
mMaskBuffer = MakeUnique<uint8_t[]>(bmpDecoder->GetImageDataLength());
nsresult rv = mDownscaler->BeginFrame(GetRealSize(), Nothing(),
mMaskBuffer.get(),
/* aHasAlpha = */ true,
/* aFlipVertically = */ true);
if (NS_FAILED(rv)) {
return Transition::TerminateFailure();
}
}
mCurrMaskLine = GetRealHeight();
return Transition::To(ICOState::READ_MASK_ROW, mMaskRowSize);
}
LexerTransition<ICOState>
nsICODecoder::ReadMaskRow(const char* aData)
{
mCurrMaskLine--;
uint8_t sawTransparency = 0;
// Get the mask row we're reading.
const uint8_t* mask = reinterpret_cast<const uint8_t*>(aData);
const uint8_t* maskRowEnd = mask + mMaskRowSize;
// Get the corresponding row of the mask buffer (if we're downscaling) or the
// decoded image data (if we're not).
uint32_t* decoded = nullptr;
if (mDownscaler) {
// Initialize the row to all white and fully opaque.
memset(mDownscaler->RowBuffer(), 0xFF, GetRealWidth() * sizeof(uint32_t));
decoded = reinterpret_cast<uint32_t*>(mDownscaler->RowBuffer());
} else {
RefPtr<nsBMPDecoder> bmpDecoder =
static_cast<nsBMPDecoder*>(mContainedDecoder.get());
uint32_t* imageData = bmpDecoder->GetImageData();
if (!imageData) {
return Transition::TerminateFailure();
}
decoded = imageData + mCurrMaskLine * GetRealWidth();
}
MOZ_ASSERT(decoded);
uint32_t* decodedRowEnd = decoded + GetRealWidth();
// Iterate simultaneously through the AND mask and the image data.
while (mask < maskRowEnd) {
uint8_t idx = *mask++;
sawTransparency |= idx;
for (uint8_t bit = 0x80; bit && decoded < decodedRowEnd; bit >>= 1) {
// Clear pixel completely for transparency.
if (idx & bit) {
*decoded = 0;
}
decoded++;
}
}
if (mDownscaler) {
mDownscaler->CommitRow();
}
// If any bits are set in sawTransparency, then we know at least one pixel was
// transparent.
if (sawTransparency) {
mHasMaskAlpha = true;
}
if (mCurrMaskLine == 0) {
return Transition::To(ICOState::FINISH_MASK, 0);
}
return Transition::To(ICOState::READ_MASK_ROW, mMaskRowSize);
}
LexerTransition<ICOState>
nsICODecoder::FinishMask()
{
// If we're downscaling, we now have the appropriate alpha values in
// mMaskBuffer. We just need to transfer them to the image.
if (mDownscaler) {
// Retrieve the image data.
RefPtr<nsBMPDecoder> bmpDecoder =
static_cast<nsBMPDecoder*>(mContainedDecoder.get());
uint8_t* imageData = reinterpret_cast<uint8_t*>(bmpDecoder->GetImageData());
if (!imageData) {
return Transition::TerminateFailure();
}
// Iterate through the alpha values, copying from mask to image.
MOZ_ASSERT(mMaskBuffer);
MOZ_ASSERT(bmpDecoder->GetImageDataLength() > 0);
for (size_t i = 3 ; i < bmpDecoder->GetImageDataLength() ; i += 4) {
imageData[i] = mMaskBuffer[i];
}
}
// If the mask contained any transparent pixels, record that fact.
if (mHasMaskAlpha) {
PostHasTransparency();
RefPtr<nsBMPDecoder> bmpDecoder =
static_cast<nsBMPDecoder*>(mContainedDecoder.get());
bmpDecoder->SetHasTransparency();
}
return Transition::To(ICOState::FINISHED_RESOURCE, 0);
}
LexerTransition<ICOState>
nsICODecoder::FinishResource()
{
// Make sure the actual size of the resource matches the size in the directory
// entry. If not, we consider the image corrupt.
if (mContainedDecoder->HasSize() &&
mContainedDecoder->GetSize() != GetRealSize()) {
return Transition::TerminateFailure();
}
return Transition::TerminateSuccess();
}
void
nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
{
MOZ_ASSERT(!HasError(), "Shouldn't call WriteInternal after error!");
MOZ_ASSERT(aBuffer);
MOZ_ASSERT(aCount > 0);
Maybe<TerminalState> terminalState =
mLexer.Lex(aBuffer, aCount,
[=](ICOState aState, const char* aData, size_t aLength) {
switch (aState) {
case ICOState::HEADER:
return ReadHeader(aData);
case ICOState::DIR_ENTRY:
return ReadDirEntry(aData);
case ICOState::SKIP_TO_RESOURCE:
return Transition::ContinueUnbuffered(ICOState::SKIP_TO_RESOURCE);
case ICOState::FOUND_RESOURCE:
return Transition::To(ICOState::SNIFF_RESOURCE, PNGSIGNATURESIZE);
case ICOState::SNIFF_RESOURCE:
return SniffResource(aData);
case ICOState::READ_PNG:
return ReadPNG(aData, aLength);
case ICOState::READ_BIH:
return ReadBIH(aData);
case ICOState::READ_BMP:
return ReadBMP(aData, aLength);
case ICOState::PREPARE_FOR_MASK:
return PrepareForMask();
case ICOState::READ_MASK_ROW:
return ReadMaskRow(aData);
case ICOState::FINISH_MASK:
return FinishMask();
case ICOState::SKIP_MASK:
return Transition::ContinueUnbuffered(ICOState::SKIP_MASK);
case ICOState::FINISHED_RESOURCE:
return FinishResource();
default:
MOZ_CRASH("Unknown ICOState");
}
});
if (terminalState == Some(TerminalState::FAILURE)) {
PostDataError();
}
}
bool
nsICODecoder::WriteToContainedDecoder(const char* aBuffer, uint32_t aCount)
{
mContainedDecoder->Write(aBuffer, aCount);
mProgress |= mContainedDecoder->TakeProgress();
mInvalidRect.UnionRect(mInvalidRect, mContainedDecoder->TakeInvalidRect());
if (mContainedDecoder->HasDataError()) {
PostDataError();
}
if (mContainedDecoder->HasDecoderError()) {
PostDecoderError(mContainedDecoder->GetDecoderError());
}
return !HasError();
}
} // namespace image
} // namespace mozilla