michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsIconDecoder.h" michael@0: #include "nsIInputStream.h" michael@0: #include "RasterImage.h" michael@0: #include "nspr.h" michael@0: #include "nsRect.h" michael@0: michael@0: #include "nsError.h" michael@0: #include michael@0: michael@0: namespace mozilla { michael@0: namespace image { michael@0: michael@0: nsIconDecoder::nsIconDecoder(RasterImage &aImage) michael@0: : Decoder(aImage), michael@0: mWidth(-1), michael@0: mHeight(-1), michael@0: mPixBytesRead(0), michael@0: mState(iconStateStart) michael@0: { michael@0: // Nothing to do michael@0: } michael@0: michael@0: nsIconDecoder::~nsIconDecoder() michael@0: { } michael@0: michael@0: void michael@0: nsIconDecoder::WriteInternal(const char *aBuffer, uint32_t aCount, DecodeStrategy) michael@0: { michael@0: NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!"); michael@0: michael@0: // We put this here to avoid errors about crossing initialization with case michael@0: // jumps on linux. michael@0: uint32_t bytesToRead = 0; michael@0: michael@0: // Loop until the input data is gone michael@0: while (aCount > 0) { michael@0: switch (mState) { michael@0: case iconStateStart: michael@0: michael@0: // Grab the width michael@0: mWidth = (uint8_t)*aBuffer; michael@0: michael@0: // Book Keeping michael@0: aBuffer++; michael@0: aCount--; michael@0: mState = iconStateHaveHeight; michael@0: break; michael@0: michael@0: case iconStateHaveHeight: michael@0: michael@0: // Grab the Height michael@0: mHeight = (uint8_t)*aBuffer; michael@0: michael@0: // Post our size to the superclass michael@0: PostSize(mWidth, mHeight); michael@0: if (HasError()) { michael@0: // Setting the size led to an error. michael@0: mState = iconStateFinished; michael@0: return; michael@0: } michael@0: michael@0: // If We're doing a size decode, we're done michael@0: if (IsSizeDecode()) { michael@0: mState = iconStateFinished; michael@0: break; michael@0: } michael@0: michael@0: if (!mImageData) { michael@0: PostDecoderError(NS_ERROR_OUT_OF_MEMORY); michael@0: return; michael@0: } michael@0: michael@0: // Book Keeping michael@0: aBuffer++; michael@0: aCount--; michael@0: mState = iconStateReadPixels; michael@0: break; michael@0: michael@0: case iconStateReadPixels: michael@0: { michael@0: michael@0: // How many bytes are we reading? michael@0: bytesToRead = std::min(aCount, mImageDataLength - mPixBytesRead); michael@0: michael@0: // Copy the bytes michael@0: memcpy(mImageData + mPixBytesRead, aBuffer, bytesToRead); michael@0: michael@0: // Performance isn't critical here, so our update rectangle is michael@0: // always the full icon michael@0: nsIntRect r(0, 0, mWidth, mHeight); michael@0: michael@0: // Invalidate michael@0: PostInvalidation(r); michael@0: michael@0: // Book Keeping michael@0: aBuffer += bytesToRead; michael@0: aCount -= bytesToRead; michael@0: mPixBytesRead += bytesToRead; michael@0: michael@0: // If we've got all the pixel bytes, we're finished michael@0: if (mPixBytesRead == mImageDataLength) { michael@0: PostFrameStop(); michael@0: PostDecodeDone(); michael@0: mState = iconStateFinished; michael@0: } michael@0: break; michael@0: } michael@0: michael@0: case iconStateFinished: michael@0: michael@0: // Consume all excess data silently michael@0: aCount = 0; michael@0: michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: } // namespace image michael@0: } // namespace mozilla