Bug 600556 - Support Vista-style PNG ICO files. r=joe

This commit is contained in:
Brian R. Bondy 2011-08-25 16:09:01 -04:00
Родитель 6fe02cb278
Коммит 86960fd5c7
8 изменённых файлов: 643 добавлений и 388 удалений

Просмотреть файл

@ -22,6 +22,7 @@
* Contributor(s):
* Neil Rashbrook <neil@parkwaycc.co.uk>
* Bobby Holley <bobbyholley@gmail.com>
* Brian R. Bondy <netzen@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -70,13 +71,73 @@ nsBMPDecoder::nsBMPDecoder()
mState = eRLEStateInitial;
mStateData = 0;
mLOH = WIN_HEADER_LENGTH;
mUseAlphaData = PR_FALSE;
}
nsBMPDecoder::~nsBMPDecoder()
{
delete[] mColors;
if (mRow)
free(mRow);
if (mRow) {
moz_free(mRow);
}
}
// Sets whether or not the BMP will use alpha data
void
nsBMPDecoder::SetUseAlphaData(PRBool useAlphaData)
{
mUseAlphaData = useAlphaData;
}
// Obtains the bits per pixel from the internal BIH header
PRInt32
nsBMPDecoder::GetBitsPerPixel() const
{
return mBIH.bpp;
}
// Obtains the width from the internal BIH header
PRInt32
nsBMPDecoder::GetWidth() const
{
return mBIH.width;
}
// Obtains the height from the internal BIH header
PRInt32
nsBMPDecoder::GetHeight() const
{
return mBIH.height;
}
// Obtains the internal output image buffer
PRUint32*
nsBMPDecoder::GetImageData()
{
return mImageData;
}
// Obtains the size of the compressed image resource
PRInt32
nsBMPDecoder::GetCompressedImageSize() const
{
// For everything except BI_RGB the header field must be defined
if (mBIH.compression != BI_RGB) {
return mBIH.image_size;
}
// mBIH.image_size isn't always filled for BI_RGB so calculate it manually
// The pixel array size is calculated based on extra 4 byte boundary padding
PRUint32 rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // + 7 to round up
// Pad to DWORD Boundary
if (rowSize % 4) {
rowSize += (4 - (rowSize % 4));
}
// The height should be the absolute value of what the height is in the BIH.
// If positive the bitmap is stored bottom to top, otherwise top to bottom
PRInt32 pixelArraySize = rowSize * abs(mBIH.height);
return pixelArraySize;
}
void
@ -90,6 +151,11 @@ nsBMPDecoder::FinishInternal()
// Send notifications if appropriate
if (!IsSizeDecode() && (GetFrameCount() == 1)) {
// Invalidate
nsIntRect r(0, 0, mBIH.width, mBIH.height);
PostInvalidation(r);
PostFrameStop();
PostDecodeDone();
}
@ -145,8 +211,8 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
return;
nsresult rv;
if (mPos < BFH_LENGTH) { /* In BITMAPFILEHEADER */
PRUint32 toCopy = BFH_LENGTH - mPos;
if (mPos < BFH_INTERNAL_LENGTH) { /* In BITMAPFILEHEADER */
PRUint32 toCopy = BFH_INTERNAL_LENGTH - mPos;
if (toCopy > aCount)
toCopy = aCount;
memcpy(mRawBuf + mPos, aBuffer, toCopy);
@ -154,7 +220,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
aCount -= toCopy;
aBuffer += toCopy;
}
if (mPos == BFH_LENGTH) {
if (mPos == BFH_INTERNAL_LENGTH) {
ProcessFileHeader();
if (mBFH.signature[0] != 'B' || mBFH.signature[1] != 'M') {
PostDataError();
@ -163,19 +229,23 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
if (mBFH.bihsize == OS2_BIH_LENGTH)
mLOH = OS2_HEADER_LENGTH;
}
if (mPos >= BFH_LENGTH && mPos < mLOH) { /* In BITMAPINFOHEADER */
if (mPos >= BFH_INTERNAL_LENGTH && mPos < mLOH) { /* In BITMAPINFOHEADER */
PRUint32 toCopy = mLOH - mPos;
if (toCopy > aCount)
toCopy = aCount;
memcpy(mRawBuf + (mPos - BFH_LENGTH), aBuffer, toCopy);
memcpy(mRawBuf + (mPos - BFH_INTERNAL_LENGTH), aBuffer, toCopy);
mPos += toCopy;
aCount -= toCopy;
aBuffer += toCopy;
}
if (mPos == mLOH) {
// GetNumFrames is called to ensure that if at this point mPos == mLOH but
// we have no data left to process, the next time WriteInternal is called
// we won't enter this condition again.
if (mPos == mLOH && GetFrameCount() == 0) {
ProcessInfoHeader();
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP image is %lix%lix%lu. compression=%lu\n",
mBIH.width, mBIH.height, mBIH.bpp, mBIH.compression));
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP is %lix%lix%lu. compression=%lu\n",
mBIH.width, mBIH.height, mBIH.bpp, mBIH.compression));
// Verify we support this bit depth
if (mBIH.bpp != 1 && mBIH.bpp != 4 && mBIH.bpp != 8 &&
mBIH.bpp != 16 && mBIH.bpp != 24 && mBIH.bpp != 32) {
@ -226,36 +296,70 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
CalcBitShift();
}
// Make sure we have a valid value for our supported compression modes
// before adding the frame
if (mBIH.compression != BI_RGB && mBIH.compression != BI_RLE8 &&
mBIH.compression != BI_RLE4 && mBIH.compression != BI_BITFIELDS) {
PostDataError();
return;
}
// If we have RLE4 or RLE8 or BI_ALPHABITFIELDS, then ensure we
// have valid BPP values before adding the frame
if (mBIH.compression == BI_RLE8 && mBIH.bpp != 8) {
PR_LOG(gBMPLog, PR_LOG_DEBUG,
("BMP RLE8 compression only supports 8 bits per pixel\n"));
PostDataError();
return;
}
if (mBIH.compression == BI_RLE4 && mBIH.bpp != 4) {
PR_LOG(gBMPLog, PR_LOG_DEBUG,
("BMP RLE4 compression only supports 4 bits per pixel\n"));
PostDataError();
return;
}
if (mBIH.compression == BI_ALPHABITFIELDS &&
mBIH.bpp != 16 && mBIH.bpp != 32) {
PR_LOG(gBMPLog, PR_LOG_DEBUG,
("BMP ALPHABITFIELDS only supports 16 or 32 bits per pixel\n"));
PostDataError();
return;
}
PRUint32 imageLength;
if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
rv = mImage->EnsureFrame(0, 0, 0, mBIH.width, real_height, gfxASurface::ImageFormatARGB32,
if (mBIH.compression == BI_RLE8 || mBIH.compression == BI_RLE4 ||
mBIH.compression == BI_ALPHABITFIELDS) {
rv = mImage->EnsureFrame(0, 0, 0, mBIH.width, real_height,
gfxASurface::ImageFormatARGB32,
(PRUint8**)&mImageData, &imageLength);
} else {
// mRow is not used for RLE encoded images
mRow = (PRUint8*)moz_malloc((mBIH.width * mBIH.bpp)/8 + 4);
// +4 because the line is padded to a 4 bit boundary, but I don't want
mRow = (PRUint8*)moz_malloc((mBIH.width * mBIH.bpp) / 8 + 4);
// + 4 because the line is padded to a 4 bit boundary, but I don't want
// to make exact calculations here, that's unnecessary.
// Also, it compensates rounding error.
if (!mRow) {
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
return;
}
rv = mImage->EnsureFrame(0, 0, 0, mBIH.width, real_height, gfxASurface::ImageFormatRGB24,
(PRUint8**)&mImageData, &imageLength);
if (mUseAlphaData) {
rv = mImage->EnsureFrame(0, 0, 0, mBIH.width, real_height,
gfxASurface::ImageFormatARGB32,
(PRUint8**)&mImageData, &imageLength);
} else {
rv = mImage->EnsureFrame(0, 0, 0, mBIH.width, real_height,
gfxASurface::ImageFormatRGB24,
(PRUint8**)&mImageData, &imageLength);
}
}
if (NS_FAILED(rv) || !mImageData) {
PostDecoderError(NS_ERROR_FAILURE);
return;
}
// Prepare for transparancy
// Prepare for transparency
if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
if (((mBIH.compression == BI_RLE8) && (mBIH.bpp != 8))
|| ((mBIH.compression == BI_RLE4) && (mBIH.bpp != 4) && (mBIH.bpp != 1))) {
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP RLE8/RLE4 compression only supports 8/4 bits per pixel\n"));
PostDataError();
return;
}
// Clear the image, as the RLE may jump over areas
memset(mImageData, 0, imageLength);
}
@ -314,9 +418,10 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
// Need to increment mPos, else we might get to mPos==mLOH again
// From now on, mPos is irrelevant
if (!mBIH.compression || mBIH.compression == BI_BITFIELDS) {
PRUint32 rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // +7 to round up
if (rowSize % 4)
PRUint32 rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // + 7 to round up
if (rowSize % 4) {
rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
}
PRUint32 toCopy;
do {
toCopy = rowSize - mRowBytes;
@ -370,35 +475,44 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
p+=2;
}
break;
case 32:
case 24:
while (lpos > 0) {
SetPixel(d, p[2], p[1], p[0]);
p += 2;
--lpos;
if (mBIH.bpp == 32)
p++; // Padding byte
++p;
}
break;
case 32:
while (lpos > 0) {
if (mUseAlphaData) {
SetPixel(d, p[2], p[1], p[0], p[3]);
}
else {
SetPixel(d, p[2], p[1], p[0]);
}
p += 4;
--lpos;
}
break;
default:
NS_NOTREACHED("Unsupported color depth, but earlier check didn't catch it");
}
mCurLine --;
if (mCurLine == 0) { // Finished last line
break;
break;
}
mRowBytes = 0;
}
} while (aCount > 0);
}
}
else if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
if (((mBIH.compression == BI_RLE8) && (mBIH.bpp != 8))
|| ((mBIH.compression == BI_RLE4) && (mBIH.bpp != 4) && (mBIH.bpp != 1))) {
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP RLE8/RLE4 compression only supports 8/4 bits per pixel\n"));
PostDataError();
return;
if (((mBIH.compression == BI_RLE8) && (mBIH.bpp != 8)) ||
((mBIH.compression == BI_RLE4) && (mBIH.bpp != 4) && (mBIH.bpp != 1))) {
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP RLE8/RLE4 compression only supports 8/4 bits per pixel\n"));
PostDataError();
return;
}
while (aCount > 0) {
@ -562,7 +676,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
}
}
}
const PRUint32 rows = mOldLine - mCurLine;
if (rows) {

Просмотреть файл

@ -21,6 +21,7 @@
*
* Contributor(s):
* Bobby Holley <bobbyholley@gmail.com>
* Brian R. Bondy <netzen@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -56,11 +57,16 @@ struct BMPFILEHEADER {
PRUint32 bihsize;
};
#define BFH_LENGTH 18 // Note: For our purposes, we include bihsize in the BFH
// The length of the bitmap file header as defined in the BMP spec.
#define BFH_LENGTH 14
// Internally we store the bitmap file header with an additional 4 bytes which
// is used to store the bitmap information header size.
#define BFH_INTERNAL_LENGTH 18
#define OS2_BIH_LENGTH 12 // This is the real BIH size (as contained in the bihsize field of BMPFILEHEADER)
#define OS2_HEADER_LENGTH (BFH_LENGTH + 8)
#define WIN_HEADER_LENGTH (BFH_LENGTH + 36)
#define OS2_HEADER_LENGTH (BFH_INTERNAL_LENGTH + 8)
#define WIN_HEADER_LENGTH (BFH_INTERNAL_LENGTH + 36)
struct BMPINFOHEADER {
PRInt32 width; // Uint16 in OS/2 BMPs
@ -106,17 +112,34 @@ struct bitFields {
(((((PRUint32) x) >> 8) & 0xFF) << 16) | \
(((((PRUint32) x) >> 16) & 0xFF) << 8) | \
(((PRUint32) x) >> 24))
#define NATIVE32_TO_LITTLE LITTLE_TO_NATIVE32
#else
#define LITTLE_TO_NATIVE16(x) x
#define LITTLE_TO_NATIVE32(x) x
#define NATIVE32_TO_LITTLE(x) x
#endif
#define USE_RGB
// BMPINFOHEADER.compression defines
#ifndef BI_RGB
#define BI_RGB 0
#endif
#ifndef BI_RLE8
#define BI_RLE8 1
#endif
#ifndef BI_RLE4
#define BI_RLE4 2
#endif
#ifndef BI_BITFIELDS
#define BI_BITFIELDS 3
#endif
// BI_ALPHABITFIELDS means no compression and specifies alpha bits
// valid only for 32bpp and 16bpp
#define BI_ALPHABITFIELDS 4
// RLE Escape codes
#define RLE_ESCAPE 0
@ -146,6 +169,21 @@ public:
nsBMPDecoder();
~nsBMPDecoder();
// Specifies whether or not the BMP file will contain alpha data
// If set to true and the BMP is 32BPP, the alpha data will be
// retrieved from the 4th byte of image data per pixel
void SetUseAlphaData(PRBool useAlphaData);
// Obtains the bits per pixel from the internal BIH header
PRInt32 GetBitsPerPixel() const;
// Obtains the width from the internal BIH header
PRInt32 GetWidth() const;
// Obtains the height from the internal BIH header
PRInt32 GetHeight() const;
// Obtains the internal output image buffer
PRUint32* GetImageData();
// Obtains the size of the compressed image resource
PRInt32 GetCompressedImageSize() const;
virtual void WriteInternal(const char* aBuffer, PRUint32 aCount);
virtual void FinishInternal();
@ -184,6 +222,16 @@ private:
/** Set mBIH from the raw data in mRawBuf, converting from little-endian
* data to native data as necessary */
void ProcessInfoHeader();
// Stores whether the image data stores alpha data, or if
// the alpha data is unspecified and filled with a
// padding byte of 0.
// When a 32BPP bitmap is stored in an ICO or CUR file, its 4th byte
// is used for alpha transparency. When it is stored in a BMP, its
// 4th byte is reserved and is always 0.
// Reference:
// http://en.wikipedia.org/wiki/ICO_(file_format)#cite_note-9
PRPackedBool mUseAlphaData;
};
/** Sets the pixel data in aDecoded to the given values.

Просмотреть файл

@ -23,6 +23,7 @@
* David Hyatt <hyatt@netscape.com> (Original Author)
* Christian Biesinger <cbiesinger@web.de>
* Bobby Holley <bobbyholley@gmail.com>
* Brian R. Bondy <netzen@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -65,39 +66,51 @@ namespace imagelib {
// Actual Data Processing
// ----------------------------------------
PRUint32 nsICODecoder::CalcAlphaRowSize()
PRUint32
nsICODecoder::CalcAlphaRowSize()
{
// Calculate rowsize in DWORD's and then return in # of bytes
PRUint32 rowSize = (mDirEntry.mWidth + 31) / 32; // +31 to round up
return rowSize * 4; // Return rowSize in bytes
return rowSize * 4; // Return rowSize in bytes
}
// Obtains the number of colors from the bits per pixel
PRUint16
nsICODecoder::GetNumColors()
{
PRUint16 numColors = 0;
if (mBPP <= 8) {
switch (mBPP) {
case 1:
numColors = 2;
break;
case 4:
numColors = 16;
break;
case 8:
numColors = 256;
break;
default:
numColors = (PRUint16)-1;
}
}
return numColors;
}
nsICODecoder::nsICODecoder()
{
mPos = mNumColors = mRowBytes = mImageOffset = mCurrIcon = mNumIcons = 0;
mCurLine = 1; // Otherwise decoder will never start
mColors = nsnull;
mPos = mImageOffset = mCurrIcon = mNumIcons = mBPP = mRowBytes = 0;
mIsPNG = PR_FALSE;
mRow = nsnull;
mHaveAlphaData = mDecodingAndMask = PR_FALSE;
mOldLine = mCurLine = 1; // Otherwise decoder will never start
}
nsICODecoder::~nsICODecoder()
{
mPos = 0;
delete[] mColors;
mCurLine = 0;
mRowBytes = 0;
mImageOffset = 0;
mCurrIcon = 0;
mNumIcons = 0;
if (mRow) {
free(mRow);
mRow = nsnull;
moz_free(mRow);
}
mDecodingAndMask = PR_FALSE;
}
void
@ -106,18 +119,87 @@ nsICODecoder::FinishInternal()
// We shouldn't be called in error cases
NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call FinishInternal after error!");
// We should never make multiple frames
NS_ABORT_IF_FALSE(GetFrameCount() <= 1, "Multiple ICO frames?");
// Finish the internally used decoder as well
if (mContainedDecoder) {
mContainedDecoder->FinishSharedDecoder();
mDecodeDone = mContainedDecoder->GetDecodeDone();
}
}
// Send notifications if appropriate
if (!IsSizeDecode() && (GetFrameCount() == 1)) {
// Returns a buffer filled with the bitmap file header in little endian:
// Signature 2 bytes 'BM'
// FileSize 4 bytes File size in bytes
// reserved 4 bytes unused (=0)
// DataOffset 4 bytes File offset to Raster Data
// Returns PR_TRUE if successful
PRBool nsICODecoder::FillBitmapFileHeaderBuffer(PRInt8 *bfh)
{
memset(bfh, 0, 14);
bfh[0] = 'B';
bfh[1] = 'M';
PRInt32 dataOffset = 0;
PRInt32 fileSize = 0;
dataOffset = BFH_LENGTH + BITMAPINFOSIZE;
// Invalidate
nsIntRect r(0, 0, mDirEntry.mWidth, mDirEntry.mHeight);
PostInvalidation(r);
// The color table is present only if BPP is <= 8
if (mDirEntry.mBitCount <= 8) {
PRUint16 numColors = GetNumColors();
if (numColors == (PRUint16)-1) {
return PR_FALSE;
}
dataOffset += 4 * numColors;
fileSize = dataOffset + mDirEntry.mWidth * mDirEntry.mHeight;
} else {
fileSize = dataOffset + (mDirEntry.mBitCount * mDirEntry.mWidth *
mDirEntry.mHeight) / 8;
}
PostFrameStop();
PostDecodeDone();
fileSize = NATIVE32_TO_LITTLE(fileSize);
memcpy(bfh + 2, &fileSize, sizeof(fileSize));
dataOffset = NATIVE32_TO_LITTLE(dataOffset);
memcpy(bfh + 10, &dataOffset, sizeof(dataOffset));
return PR_TRUE;
}
// A BMP inside of an ICO has *2 height because of the AND mask
// that follows the actual bitmap. The BMP shouldn't know about
// this difference though.
void
nsICODecoder::FillBitmapInformationBufferHeight(PRInt8 *bih)
{
PRInt32 height = mDirEntry.mHeight;
height = NATIVE32_TO_LITTLE(height);
memcpy(bih + 8, &height, sizeof(height));
}
// The BMP information header's bits per pixel should be trusted
// more than what we have. Usually the ICO's BPP is set to 0
PRInt32
nsICODecoder::ExtractBPPFromBitmap(PRInt8 *bih)
{
PRInt32 bitsPerPixel;
memcpy(&bitsPerPixel, bih + 14, sizeof(bitsPerPixel));
bitsPerPixel = LITTLE_TO_NATIVE32(bitsPerPixel);
return bitsPerPixel;
}
void
nsICODecoder::SetHotSpotIfCursor() {
if (!mIsCursor) {
return;
}
nsCOMPtr<nsISupportsPRUint32> intwrapx =
do_CreateInstance("@mozilla.org/supports-PRUint32;1");
nsCOMPtr<nsISupportsPRUint32> intwrapy =
do_CreateInstance("@mozilla.org/supports-PRUint32;1");
if (intwrapx && intwrapy) {
intwrapx->SetData(mDirEntry.mXHotspot);
intwrapy->SetData(mDirEntry.mYHotspot);
mImage->Set("hotspotX", intwrapx);
mImage->Set("hotspotY", intwrapy);
}
}
@ -151,12 +233,15 @@ nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
return; // Nothing to do.
PRUint16 colorDepth = 0;
while (mCurrIcon < mNumIcons) {
if (mPos >= DIRENTRYOFFSET + (mCurrIcon*sizeof(mDirEntryArray)) &&
mPos < DIRENTRYOFFSET + ((mCurrIcon+1)*sizeof(mDirEntryArray))) {
PRUint32 toCopy = sizeof(mDirEntryArray) - (mPos - DIRENTRYOFFSET - mCurrIcon*sizeof(mDirEntryArray));
if (toCopy > aCount)
// Loop through each entry's dir entry
while (mCurrIcon < mNumIcons) {
if (mPos >= DIRENTRYOFFSET + (mCurrIcon * sizeof(mDirEntryArray)) &&
mPos < DIRENTRYOFFSET + ((mCurrIcon + 1) * sizeof(mDirEntryArray))) {
PRUint32 toCopy = sizeof(mDirEntryArray) -
(mPos - DIRENTRYOFFSET - mCurrIcon * sizeof(mDirEntryArray));
if (toCopy > aCount) {
toCopy = aCount;
}
memcpy(mDirEntryArray + sizeof(mDirEntryArray) - toCopy, aBuffer, toCopy);
mPos += toCopy;
aCount -= toCopy;
@ -166,15 +251,18 @@ nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
return; // Need more data
IconDirEntry e;
if (mPos == 22+mCurrIcon*sizeof(mDirEntryArray)) {
if (mPos == (DIRENTRYOFFSET + ICODIRENTRYSIZE) +
(mCurrIcon * sizeof(mDirEntryArray))) {
mCurrIcon++;
ProcessDirEntry(e);
if ((e.mWidth == PREFICONSIZE && e.mHeight == PREFICONSIZE && e.mBitCount >= colorDepth)
|| (mCurrIcon == mNumIcons && mImageOffset == 0)) {
if ((e.mWidth == PREFICONSIZE && e.mHeight == PREFICONSIZE &&
e.mBitCount >= colorDepth) ||
(mCurrIcon == mNumIcons && mImageOffset == 0)) {
mImageOffset = e.mImageOffset;
// ensure mImageOffset is >= the size of the direntry headers (bug #245631)
PRUint32 minImageOffset = DIRENTRYOFFSET + mNumIcons*sizeof(mDirEntryArray);
// ensure mImageOffset is >= size of the direntry headers (bug #245631)
PRUint32 minImageOffset = DIRENTRYOFFSET +
mNumIcons * sizeof(mDirEntryArray);
if (mImageOffset < minImageOffset) {
PostDataError();
return;
@ -197,7 +285,67 @@ nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
aCount -= toSkip;
}
if (mCurrIcon == mNumIcons && mPos >= mImageOffset && mPos < mImageOffset + BITMAPINFOSIZE) {
// If we are within the first PNGSIGNATURESIZE bytes of the image data,
// then we have either a BMP or a PNG. We use the first PNGSIGNATURESIZE
// bytes to determine which one we have.
if (mCurrIcon == mNumIcons && mPos >= mImageOffset &&
mPos < mImageOffset + PNGSIGNATURESIZE)
{
PRUint32 toCopy = PNGSIGNATURESIZE - (mPos - mImageOffset);
if (toCopy > aCount) {
toCopy = aCount;
}
memcpy(mSignature + (mPos - mImageOffset), aBuffer, toCopy);
mPos += toCopy;
aCount -= toCopy;
aBuffer += toCopy;
mIsPNG = !memcmp(mSignature, nsPNGDecoder::pngSignatureBytes,
PNGSIGNATURESIZE);
if (mIsPNG) {
mContainedDecoder = new nsPNGDecoder();
mContainedDecoder->InitSharedDecoder(mImage, mObserver);
mContainedDecoder->Write(mSignature, PNGSIGNATURESIZE);
mDataError = mContainedDecoder->HasDataError();
if (mContainedDecoder->HasDataError()) {
return;
}
}
}
// If we have a PNG, let the PNG decoder do all of the rest of the work
if (mIsPNG && mContainedDecoder && mPos >= mImageOffset + PNGSIGNATURESIZE) {
mContainedDecoder->Write(aBuffer, aCount);
mDataError = mContainedDecoder->HasDataError();
if (mContainedDecoder->HasDataError()) {
return;
}
mPos += aCount;
aBuffer += aCount;
aCount = 0;
// 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())->HasValidInfo() &&
static_cast<nsPNGDecoder*>(mContainedDecoder.get())->GetPixelDepth() != 32) {
PostDataError();
}
return;
}
// We've processed all of the icon dir entries and are within the
// bitmap info size
if (!mIsPNG && mCurrIcon == mNumIcons && mPos >= mImageOffset &&
mPos >= mImageOffset + PNGSIGNATURESIZE &&
mPos < mImageOffset + BITMAPINFOSIZE) {
// As we were decoding, we did not know if we had a PNG signature or the
// start of a bitmap information header. At this point we know we had
// a bitmap information header and not a PNG signature, so fill the bitmap
// information header with the data it should already have.
memcpy(mBIHraw, mSignature, PNGSIGNATURESIZE);
// We've found the icon.
PRUint32 toCopy = sizeof(mBIHraw) - (mPos - mImageOffset);
if (toCopy > aCount)
@ -209,257 +357,154 @@ nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
aBuffer += toCopy;
}
nsresult rv;
// If we have a BMP inside the ICO and we have read the BIH header
if (!mIsPNG && mPos == mImageOffset + BITMAPINFOSIZE) {
// We are extracting the BPP from the BIH header as it should be trusted
// over the one we have from the icon header
mBPP = ExtractBPPFromBitmap((PRInt8*)mBIHraw);
// Init the bitmap decoder which will do most of the work for us
// It will do everything except the AND mask which isn't present in bitmaps
// bmpDecoder is for local scope ease, it will be freed by mContainedDecoder
nsBMPDecoder *bmpDecoder = new nsBMPDecoder();
mContainedDecoder = bmpDecoder;
bmpDecoder->SetUseAlphaData(PR_TRUE);
mContainedDecoder->SetSizeDecode(IsSizeDecode());
mContainedDecoder->InitSharedDecoder(mImage, mObserver);
if (mPos == mImageOffset + BITMAPINFOSIZE) {
ProcessInfoHeader();
PostSize(mDirEntry.mWidth, mDirEntry.mHeight);
if (IsSizeDecode())
return;
if (mBIH.bpp <= 8) {
switch (mBIH.bpp) {
case 1:
mNumColors = 2;
break;
case 4:
mNumColors = 16;
break;
case 8:
mNumColors = 256;
break;
default:
PostDataError();
return;
}
mColors = new colorTable[mNumColors];
}
if (mIsCursor) {
nsCOMPtr<nsISupportsPRUint32> intwrapx = do_CreateInstance("@mozilla.org/supports-PRUint32;1");
nsCOMPtr<nsISupportsPRUint32> intwrapy = do_CreateInstance("@mozilla.org/supports-PRUint32;1");
if (intwrapx && intwrapy) {
intwrapx->SetData(mDirEntry.mXHotspot);
intwrapy->SetData(mDirEntry.mYHotspot);
mImage->Set("hotspotX", intwrapx);
mImage->Set("hotspotY", intwrapy);
}
}
mCurLine = mDirEntry.mHeight;
mRow = (PRUint8*)moz_malloc((mDirEntry.mWidth * mBIH.bpp)/8 + 4);
// +4 because the line is padded to a 4 bit boundary, but I don't want
// to make exact calculations here, that's unnecessary.
// Also, it compensates rounding error.
if (!mRow) {
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
return;
}
PRUint32 imageLength;
rv = mImage->EnsureFrame(0, 0, 0, mDirEntry.mWidth, mDirEntry.mHeight,
gfxASurface::ImageFormatARGB32, (PRUint8**)&mImageData, &imageLength);
if (NS_FAILED(rv)) {
PostDecoderError(rv);
return;
}
// Tell the superclass we're starting a frame
PostFrameStart();
}
if (mColors && (mPos >= mImageOffset + BITMAPINFOSIZE) &&
(mPos < (mImageOffset + BITMAPINFOSIZE + mNumColors * 4))) {
// We will receive (mNumColors * 4) bytes of color data
PRUint32 colorBytes = mPos - (mImageOffset + 40); // Number of bytes already received
PRUint8 colorNum = colorBytes / 4; // Color which is currently received
PRUint8 at = colorBytes % 4;
while (aCount && (mPos < (mImageOffset + BITMAPINFOSIZE + mNumColors * 4))) {
switch (at) {
case 0:
mColors[colorNum].blue = *aBuffer;
break;
case 1:
mColors[colorNum].green = *aBuffer;
break;
case 2:
mColors[colorNum].red = *aBuffer;
break;
case 3:
colorNum++; // This is a padding byte
break;
}
mPos++; aBuffer++; aCount--;
at = (at + 1) % 4;
}
}
if (!mDecodingAndMask && (mPos >= (mImageOffset + BITMAPINFOSIZE + mNumColors*4))) {
if (mPos == (mImageOffset + BITMAPINFOSIZE + mNumColors*4)) {
// Increment mPos to avoid reprocessing the info header.
mPos++;
}
// Ensure memory has been allocated before decoding. If we get this far
// without allocated memory, the file is most likely invalid.
// XXXbholley - If null values can be triggered by bad input, why are we
// asserting here?
NS_ASSERTION(mRow, "mRow is null");
NS_ASSERTION(mImageData, "mImageData is null");
if (!mRow || !mImageData) {
// The ICO format when containing a BMP does not include the 14 byte
// bitmap file header. To use the code of the BMP decoder we need to
// generate this header ourselves and feed it to the BMP decoder.
PRInt8 bfhBuffer[BMPFILEHEADERSIZE];
if (!FillBitmapFileHeaderBuffer(bfhBuffer)) {
PostDataError();
return;
}
mContainedDecoder->Write((const char*)bfhBuffer, sizeof(bfhBuffer));
mDataError = mContainedDecoder->HasDataError();
if (mContainedDecoder->HasDataError()) {
return;
}
PRUint32 rowSize = (mBIH.bpp * mDirEntry.mWidth + 7) / 8; // +7 to round up
if (rowSize % 4)
rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
PRUint32 toCopy;
do {
toCopy = rowSize - mRowBytes;
if (toCopy) {
if (toCopy > aCount)
toCopy = aCount;
// Setup the cursor hot spot if one is present
SetHotSpotIfCursor();
// Fix the height on the BMP resource
FillBitmapInformationBufferHeight((PRInt8*)mBIHraw);
// Write out the BMP's bitmap info header
mContainedDecoder->Write(mBIHraw, sizeof(mBIHraw));
mDataError = mContainedDecoder->HasDataError();
if (mContainedDecoder->HasDataError()) {
return;
}
// Sometimes the ICO BPP header field is not filled out
// so we should trust the contained resource over our own
// information.
mBPP = bmpDecoder->GetBitsPerPixel();
// Check to make sure we have valid color settings
PRUint16 numColors = GetNumColors();
if (numColors == (PRUint16)-1) {
PostDataError();
return;
}
}
// If we have a BMP
if (!mIsPNG && mContainedDecoder && mPos >= mImageOffset + BITMAPINFOSIZE) {
PRUint16 numColors = GetNumColors();
if (numColors == (PRUint16)-1) {
PostDataError();
return;
}
// Feed the actual image data (not including headers) into the BMP decoder
PRInt32 bmpDataOffset = mDirEntry.mImageOffset + BITMAPINFOSIZE;
PRInt32 bmpDataEnd = mDirEntry.mImageOffset + BITMAPINFOSIZE +
static_cast<nsBMPDecoder*>(mContainedDecoder.get())->GetCompressedImageSize() +
4 * numColors;
// If we are feeding in the core image data, but we have not yet
// reached the ICO's 'AND buffer mask'
if (mPos >= bmpDataOffset && mPos < bmpDataEnd) {
// Figure out how much data the BMP decoder wants
PRUint32 toFeed = bmpDataEnd - mPos;
if (toFeed > aCount) {
toFeed = aCount;
}
mContainedDecoder->Write(aBuffer, toFeed);
mDataError = mContainedDecoder->HasDataError();
if (mContainedDecoder->HasDataError()) {
return;
}
mPos += toFeed;
aCount -= toFeed;
aBuffer += toFeed;
}
// If the bitmap is fully processed, treat any left over data as the ICO's
// 'AND buffer mask' which appears after the bitmap resource.
if (!mIsPNG && mPos >= bmpDataEnd) {
// There may be an optional AND bit mask after the data. This is
// only used if the alpha data is not already set. The alpha data
// is used for 32bpp bitmaps as per the comment in ICODecoder.h
// The alpha mask should be checked in all other cases.
if (static_cast<nsBMPDecoder*>(mContainedDecoder.get())->GetBitsPerPixel() != 32) {
PRUint32 rowSize = ((mDirEntry.mWidth + 31) / 32) * 4; // + 31 to round up
if (mPos == bmpDataEnd) {
mPos++;
mRowBytes = 0;
mCurLine = mDirEntry.mHeight;
mRow = (PRUint8*)moz_realloc(mRow, rowSize);
if (!mRow) {
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
return;
}
}
// Ensure memory has been allocated before decoding.
NS_ABORT_IF_FALSE(mRow, "mRow is null");
NS_ABORT_IF_FALSE(mImage, "mImage is null");
if (!mRow || !mImage) {
PostDataError();
return;
}
while (mCurLine > 0 && aCount > 0) {
PRUint32 toCopy = NS_MIN(rowSize - mRowBytes, aCount);
if (toCopy) {
memcpy(mRow + mRowBytes, aBuffer, toCopy);
aCount -= toCopy;
aBuffer += toCopy;
mRowBytes += toCopy;
}
if (rowSize == mRowBytes) {
}
if (rowSize == mRowBytes) {
mCurLine--;
PRUint32* d = mImageData + (mCurLine * mDirEntry.mWidth);
PRUint8* p = mRow;
PRUint32 lpos = mDirEntry.mWidth;
switch (mBIH.bpp) {
case 1:
while (lpos > 0) {
PRInt8 bit;
PRUint8 idx;
for (bit = 7; bit >= 0 && lpos > 0; bit--) {
idx = (*p >> bit) & 1;
SetPixel(d, idx, mColors);
--lpos;
}
++p;
}
break;
case 4:
while (lpos > 0) {
Set4BitPixel(d, *p, lpos, mColors);
++p;
}
break;
case 8:
while (lpos > 0) {
SetPixel(d, *p, mColors);
--lpos;
++p;
}
break;
case 16:
while (lpos > 0) {
SetPixel(d,
(p[1] & 124) << 1,
((p[1] & 3) << 6) | ((p[0] & 224) >> 2),
(p[0] & 31) << 3);
--lpos;
p+=2;
}
break;
case 24:
while (lpos > 0) {
SetPixel(d, p[2], p[1], p[0]);
p += 3;
--lpos;
}
break;
case 32:
// We assume that 32bit doesn't have alpha data until we
// find a non-zero alpha byte. If we find such a byte,
// it means that all previous pixels are really clear (alphabyte=0).
// This working assumption prevents us having to premultiply afterwards.
while (lpos > 0) {
if (!mHaveAlphaData && p[3]) {
// Non-zero alpha byte detected! Clear previous pixels from current row to end
memset(mImageData + mCurLine * mDirEntry.mWidth, 0,
(mDirEntry.mHeight - mCurLine) * mDirEntry.mWidth * sizeof(PRUint32));
mHaveAlphaData = PR_TRUE;
}
SetPixel(d, p[2], p[1], p[0], mHaveAlphaData ? p[3] : 0xFF);
p += 4;
--lpos;
}
break;
default:
// This is probably the wrong place to check this...
PostDataError();
return;
}
if (mCurLine == 0)
mDecodingAndMask = PR_TRUE;
mRowBytes = 0;
}
} while (!mDecodingAndMask && aCount > 0);
}
if (mDecodingAndMask && !mHaveAlphaData) {
PRUint32 rowSize = CalcAlphaRowSize();
if (mPos == (1 + mImageOffset + BITMAPINFOSIZE + mNumColors*4)) {
mPos++;
mRowBytes = 0;
mCurLine = mDirEntry.mHeight;
mRow = (PRUint8*)realloc(mRow, rowSize);
if (!mRow) {
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
return;
}
}
// Ensure memory has been allocated before decoding.
NS_ASSERTION(mRow, "mRow is null");
NS_ASSERTION(mImageData, "mImageData is null");
if (!mRow || !mImageData) {
PostDataError();
return;
}
while (mCurLine > 0 && aCount > 0) {
PRUint32 toCopy = NS_MIN(rowSize - mRowBytes, aCount);
if (toCopy) {
memcpy(mRow + mRowBytes, aBuffer, toCopy);
aCount -= toCopy;
aBuffer += toCopy;
mRowBytes += toCopy;
}
if (rowSize == mRowBytes) {
mCurLine--;
mRowBytes = 0;
PRUint32* decoded = mImageData + mCurLine * mDirEntry.mWidth;
PRUint32* decoded_end = decoded + mDirEntry.mWidth;
PRUint8* p = mRow, *p_end = mRow + rowSize;
while (p < p_end) {
PRUint8 idx = *p++;
for (PRUint8 bit = 0x80; bit && decoded<decoded_end; bit >>= 1) {
// Clear pixel completely for transparency.
if (idx & bit) *decoded = 0;
decoded ++;
PRUint32* imageData = static_cast<nsBMPDecoder*>(mContainedDecoder.get())->GetImageData();
PRUint32* decoded = imageData + mCurLine * mDirEntry.mWidth;
PRUint32* decoded_end = decoded + mDirEntry.mWidth;
PRUint8* p = mRow, *p_end = mRow + rowSize;
while (p < p_end) {
PRUint8 idx = *p++;
for (PRUint8 bit = 0x80; bit && decoded<decoded_end; bit >>= 1) {
// Clear pixel completely for transparency.
if (idx & bit) {
*decoded = 0;
}
decoded++;
}
}
}
}
}
}
}
return;
}
void
@ -467,51 +512,19 @@ nsICODecoder::ProcessDirEntry(IconDirEntry& aTarget)
{
memset(&aTarget, 0, sizeof(aTarget));
memcpy(&aTarget.mWidth, mDirEntryArray, sizeof(aTarget.mWidth));
memcpy(&aTarget.mHeight, mDirEntryArray+1, sizeof(aTarget.mHeight));
memcpy(&aTarget.mColorCount, mDirEntryArray+2, sizeof(aTarget.mColorCount));
memcpy(&aTarget.mReserved, mDirEntryArray+3, sizeof(aTarget.mReserved));
memcpy(&aTarget.mPlanes, mDirEntryArray+4, sizeof(aTarget.mPlanes));
memcpy(&aTarget.mHeight, mDirEntryArray + 1, sizeof(aTarget.mHeight));
memcpy(&aTarget.mColorCount, mDirEntryArray + 2, sizeof(aTarget.mColorCount));
memcpy(&aTarget.mReserved, mDirEntryArray + 3, sizeof(aTarget.mReserved));
memcpy(&aTarget.mPlanes, mDirEntryArray + 4, sizeof(aTarget.mPlanes));
aTarget.mPlanes = LITTLE_TO_NATIVE16(aTarget.mPlanes);
memcpy(&aTarget.mBitCount, mDirEntryArray+6, sizeof(aTarget.mBitCount));
memcpy(&aTarget.mBitCount, mDirEntryArray + 6, sizeof(aTarget.mBitCount));
aTarget.mBitCount = LITTLE_TO_NATIVE16(aTarget.mBitCount);
memcpy(&aTarget.mBytesInRes, mDirEntryArray+8, sizeof(aTarget.mBytesInRes));
memcpy(&aTarget.mBytesInRes, mDirEntryArray + 8, sizeof(aTarget.mBytesInRes));
aTarget.mBytesInRes = LITTLE_TO_NATIVE32(aTarget.mBytesInRes);
memcpy(&aTarget.mImageOffset, mDirEntryArray+12, sizeof(aTarget.mImageOffset));
memcpy(&aTarget.mImageOffset, mDirEntryArray + 12,
sizeof(aTarget.mImageOffset));
aTarget.mImageOffset = LITTLE_TO_NATIVE32(aTarget.mImageOffset);
}
void nsICODecoder::ProcessInfoHeader() {
memset(&mBIH, 0, sizeof(mBIH));
// Ignoring the size; it should always be 40 for icons, anyway
memcpy(&mBIH.width, mBIHraw + 4, sizeof(mBIH.width));
memcpy(&mBIH.height, mBIHraw + 8, sizeof(mBIH.height));
memcpy(&mBIH.planes, mBIHraw + 12, sizeof(mBIH.planes));
memcpy(&mBIH.bpp, mBIHraw + 14, sizeof(mBIH.bpp));
memcpy(&mBIH.compression, mBIHraw + 16, sizeof(mBIH.compression));
memcpy(&mBIH.image_size, mBIHraw + 20, sizeof(mBIH.image_size));
memcpy(&mBIH.xppm, mBIHraw + 24, sizeof(mBIH.xppm));
memcpy(&mBIH.yppm, mBIHraw + 28, sizeof(mBIH.yppm));
memcpy(&mBIH.colors, mBIHraw + 32, sizeof(mBIH.colors));
memcpy(&mBIH.important_colors, mBIHraw + 36, sizeof(mBIH.important_colors));
// Convert endianness
mBIH.width = LITTLE_TO_NATIVE32(mBIH.width);
mBIH.height = LITTLE_TO_NATIVE32(mBIH.height);
mBIH.planes = LITTLE_TO_NATIVE16(mBIH.planes);
mBIH.bpp = LITTLE_TO_NATIVE16(mBIH.bpp);
mBIH.compression = LITTLE_TO_NATIVE32(mBIH.compression);
mBIH.image_size = LITTLE_TO_NATIVE32(mBIH.image_size);
mBIH.xppm = LITTLE_TO_NATIVE32(mBIH.xppm);
mBIH.yppm = LITTLE_TO_NATIVE32(mBIH.yppm);
mBIH.colors = LITTLE_TO_NATIVE32(mBIH.colors);
mBIH.important_colors = LITTLE_TO_NATIVE32(mBIH.important_colors);
}
} // namespace imagelib
} // namespace mozilla

Просмотреть файл

@ -22,6 +22,7 @@
* Contributor(s):
* David Hyatt <hyatt@netscape.com> (Original Author)
* Bobby Holley <bobbyholley@gmail.com>
* Brian R. Bondy <netzen@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -45,10 +46,15 @@
#include "Decoder.h"
#include "imgIDecoderObserver.h"
#include "nsBMPDecoder.h"
#include "nsPNGDecoder.h"
namespace mozilla {
namespace imagelib {
#define ICODIRENTRYSIZE 16
#define PNGSIGNATURESIZE 8
#define BMPFILEHEADERSIZE 14
class RasterImage;
struct IconDirEntry
@ -80,37 +86,42 @@ public:
virtual void FinishInternal();
private:
// Private helper methods
// Processes a single dir entry of the icon resource
void ProcessDirEntry(IconDirEntry& aTarget);
void ProcessInfoHeader();
nsresult SetImageData();
// Sets the hotspot property of if we have a cursor
void SetHotSpotIfCursor();
// Creates a bitmap file header buffer, returns PR_TRUE if successful
PRBool FillBitmapFileHeaderBuffer(PRInt8 *bfh);
// Fixes the height of a BMP information header field
void FillBitmapInformationBufferHeight(PRInt8 *bih);
// Extract bit count from BMP information header
PRInt32 ExtractBPPFromBitmap(PRInt8 *bih);
// Calculates the row size in bytes for the AND mask table
PRUint32 CalcAlphaRowSize();
// Obtains the number of colors from the BPP, mBPP must be filled in
PRUint16 GetNumColors();
PRUint32 mPos;
PRUint16 mNumIcons;
PRUint16 mCurrIcon;
PRUint32 mImageOffset;
char mDirEntryArray[16];
IconDirEntry mDirEntry;
char mBIHraw[40];
BMPINFOHEADER mBIH;
PRUint32 mNumColors;
colorTable* mColors;
PRUint8* mRow; // Holds one raw line of the image
PRUint16 mBPP; // Stores the images BPP
PRUint32 mPos; // Keeps track of the position we have decoded up until
PRUint16 mNumIcons; // Stores the number of icons in the ICO file
PRUint16 mCurrIcon; // Stores the current dir entry index we are processing
PRUint32 mImageOffset; // Stores the offset of the image data we want
PRUint8 *mRow; // Holds one raw line of the image
PRInt32 mCurLine; // Line index of the image that's currently being decoded
PRUint32 mRowBytes; // How many bytes of the row were already received
PRInt32 mCurLine;
PRInt32 mOldLine; // Previous index of the line
nsAutoPtr<Decoder> mContainedDecoder; // Contains either a BMP or PNG resource
PRUint32* mImageData;
PRPackedBool mHaveAlphaData;
char mDirEntryArray[ICODIRENTRYSIZE]; // Holds the current dir entry buffer
IconDirEntry mDirEntry; // Holds a decoded dir entry
// Holds the potential bytes that can be a PNG signature
char mSignature[PNGSIGNATURESIZE];
// Holds the potential bytes for a bitmap information header
char mBIHraw[40];
// Stores whether or not the icon file we are processing has type 1 (icon)
PRPackedBool mIsCursor;
PRPackedBool mDecodingAndMask;
// Stores whether or not the contained resource is a PNG
PRPackedBool mIsPNG;
};
} // namespace imagelib

Просмотреть файл

@ -77,10 +77,9 @@ static PRLogModuleInfo *gPNGDecoderAccountingLog =
#define HEIGHT_OFFSET (WIDTH_OFFSET + 4)
#define BYTES_NEEDED_FOR_DIMENSIONS (HEIGHT_OFFSET + 4)
// This is defined in the PNG spec as an invariant. We use it to
// do manual validation without libpng.
static const PRUint8 pngSignatureBytes[] =
{ 137, 80, 78, 71, 13, 10, 26, 10 };
// First 8 bytes of a PNG file
const PRUint8
nsPNGDecoder::pngSignatureBytes[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
nsPNGDecoder::nsPNGDecoder() :
mPNG(nsnull), mInfo(nsnull),
@ -317,7 +316,8 @@ nsPNGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
if (mHeaderBytesRead == BYTES_NEEDED_FOR_DIMENSIONS) {
// Check that the signature bytes are right
if (memcmp(mHeaderBuf, pngSignatureBytes, sizeof(pngSignatureBytes))) {
if (memcmp(mHeaderBuf, nsPNGDecoder::pngSignatureBytes,
sizeof(pngSignatureBytes))) {
PostDataError();
return;
}

Просмотреть файл

@ -72,6 +72,21 @@ public:
void EndImageFrame();
// Checks if the info header contains valid information
bool HasValidInfo() const
{
return mInfo && mInfo->valid;
}
// Obtain the pixel depth if available or 0 otherwise
PRInt32 GetPixelDepth() const
{
if (!mInfo) {
return 0;
}
return mInfo->pixel_depth;
}
public:
png_structp mPNG;
png_infop mInfo;
@ -113,6 +128,10 @@ public:
png_const_charp error_msg);
static void PNGAPI warning_callback(png_structp png_ptr,
png_const_charp warning_msg);
// This is defined in the PNG spec as an invariant. We use it to
// do manual validation without libpng.
static const PRUint8 pngSignatureBytes[];
};
} // namespace imagelib

Просмотреть файл

@ -88,6 +88,26 @@ Decoder::Init(RasterImage* aImage, imgIDecoderObserver* aObserver)
mInitialized = true;
}
// Initializes a decoder whose aImage and aObserver is already being used by a
// parent decoder
void
Decoder::InitSharedDecoder(RasterImage* aImage, imgIDecoderObserver* aObserver)
{
// We should always have an image
NS_ABORT_IF_FALSE(aImage, "Can't initialize decoder without an image!");
// No re-initializing
NS_ABORT_IF_FALSE(mImage == nsnull, "Can't re-initialize a decoder!");
// Save our parameters
mImage = aImage;
mObserver = aObserver;
// Implementation-specific initialization
InitInternal();
mInitialized = true;
}
void
Decoder::Write(const char* aBuffer, PRUint32 aCount)
{
@ -155,6 +175,14 @@ Decoder::Finish()
}
}
void
Decoder::FinishSharedDecoder()
{
if (!HasError()) {
FinishInternal();
}
}
void
Decoder::FlushInvalidations()
{

Просмотреть файл

@ -63,6 +63,18 @@ public:
*/
void Init(RasterImage* aImage, imgIDecoderObserver* aObserver);
/**
* Initializes a decoder whose aImage and aObserver is already being used by a
* parent decoder. Decoders may not be re-initialized.
*
* @param aContainer The image container to decode to.
* @param aObserver The observer for decode notification events.
*
* Notifications Sent: TODO
*/
void InitSharedDecoder(RasterImage* aImage, imgIDecoderObserver* aObserver);
/**
* Writes data to the decoder.
*
@ -82,6 +94,14 @@ public:
*/
void Finish();
/**
* Informs the shared decoder that all the data has been written.
* Should only be used if InitSharedDecoder was useed
*
* Notifications Sent: TODO
*/
void FinishSharedDecoder();
/**
* Tells the decoder to flush any pending invalidations. This informs the image
* frame of its decoded region, and sends the appropriate OnDataAvailable call
@ -122,6 +142,9 @@ public:
bool HasDecoderError() { return NS_FAILED(mFailCode); };
nsresult GetDecoderError() { return mFailCode; };
void PostResizeError() { PostDataError(); }
bool GetDecodeDone() const {
return mDecodeDone;
}
// flags. Keep these in sync with imgIContainer.idl.
// SetDecodeFlags must be called before Init(), otherwise
@ -176,12 +199,13 @@ protected:
*
*/
nsRefPtr<RasterImage> mImage;
PRUint32 mDecodeFlags;
private:
nsCOMPtr<imgIDecoderObserver> mObserver;
PRUint32 mDecodeFlags;
bool mDecodeDone;
bool mDataError;
private:
PRUint32 mFrameCount; // Number of frames, including anything in-progress
nsIntRect mInvalidRect; // Tracks an invalidation region in the current frame.
@ -191,8 +215,6 @@ private:
bool mInitialized;
bool mSizeDecode;
bool mInFrame;
bool mDecodeDone;
bool mDataError;
};
} // namespace imagelib