зеркало из https://github.com/mozilla/pjs.git
Bug 600556 - Support Vista-style PNG ICO files. r=joe
This commit is contained in:
Родитель
c6dbea4d8c
Коммит
e8392a91ce
|
@ -22,6 +22,7 @@
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Neil Rashbrook <neil@parkwaycc.co.uk>
|
* Neil Rashbrook <neil@parkwaycc.co.uk>
|
||||||
* Bobby Holley <bobbyholley@gmail.com>
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
|
* Brian R. Bondy <netzen@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* 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
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -70,13 +71,73 @@ nsBMPDecoder::nsBMPDecoder()
|
||||||
mState = eRLEStateInitial;
|
mState = eRLEStateInitial;
|
||||||
mStateData = 0;
|
mStateData = 0;
|
||||||
mLOH = WIN_HEADER_LENGTH;
|
mLOH = WIN_HEADER_LENGTH;
|
||||||
|
mUseAlphaData = PR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsBMPDecoder::~nsBMPDecoder()
|
nsBMPDecoder::~nsBMPDecoder()
|
||||||
{
|
{
|
||||||
delete[] mColors;
|
delete[] mColors;
|
||||||
if (mRow)
|
if (mRow) {
|
||||||
free(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
|
void
|
||||||
|
@ -90,6 +151,11 @@ nsBMPDecoder::FinishInternal()
|
||||||
|
|
||||||
// Send notifications if appropriate
|
// Send notifications if appropriate
|
||||||
if (!IsSizeDecode() && (GetFrameCount() == 1)) {
|
if (!IsSizeDecode() && (GetFrameCount() == 1)) {
|
||||||
|
|
||||||
|
// Invalidate
|
||||||
|
nsIntRect r(0, 0, mBIH.width, mBIH.height);
|
||||||
|
PostInvalidation(r);
|
||||||
|
|
||||||
PostFrameStop();
|
PostFrameStop();
|
||||||
PostDecodeDone();
|
PostDecodeDone();
|
||||||
}
|
}
|
||||||
|
@ -145,8 +211,8 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
if (mPos < BFH_LENGTH) { /* In BITMAPFILEHEADER */
|
if (mPos < BFH_INTERNAL_LENGTH) { /* In BITMAPFILEHEADER */
|
||||||
PRUint32 toCopy = BFH_LENGTH - mPos;
|
PRUint32 toCopy = BFH_INTERNAL_LENGTH - mPos;
|
||||||
if (toCopy > aCount)
|
if (toCopy > aCount)
|
||||||
toCopy = aCount;
|
toCopy = aCount;
|
||||||
memcpy(mRawBuf + mPos, aBuffer, toCopy);
|
memcpy(mRawBuf + mPos, aBuffer, toCopy);
|
||||||
|
@ -154,7 +220,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
|
||||||
aCount -= toCopy;
|
aCount -= toCopy;
|
||||||
aBuffer += toCopy;
|
aBuffer += toCopy;
|
||||||
}
|
}
|
||||||
if (mPos == BFH_LENGTH) {
|
if (mPos == BFH_INTERNAL_LENGTH) {
|
||||||
ProcessFileHeader();
|
ProcessFileHeader();
|
||||||
if (mBFH.signature[0] != 'B' || mBFH.signature[1] != 'M') {
|
if (mBFH.signature[0] != 'B' || mBFH.signature[1] != 'M') {
|
||||||
PostDataError();
|
PostDataError();
|
||||||
|
@ -163,19 +229,23 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
|
||||||
if (mBFH.bihsize == OS2_BIH_LENGTH)
|
if (mBFH.bihsize == OS2_BIH_LENGTH)
|
||||||
mLOH = OS2_HEADER_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;
|
PRUint32 toCopy = mLOH - mPos;
|
||||||
if (toCopy > aCount)
|
if (toCopy > aCount)
|
||||||
toCopy = aCount;
|
toCopy = aCount;
|
||||||
memcpy(mRawBuf + (mPos - BFH_LENGTH), aBuffer, toCopy);
|
memcpy(mRawBuf + (mPos - BFH_INTERNAL_LENGTH), aBuffer, toCopy);
|
||||||
mPos += toCopy;
|
mPos += toCopy;
|
||||||
aCount -= toCopy;
|
aCount -= toCopy;
|
||||||
aBuffer += 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();
|
ProcessInfoHeader();
|
||||||
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP image is %lix%lix%lu. compression=%lu\n",
|
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP is %lix%lix%lu. compression=%lu\n",
|
||||||
mBIH.width, mBIH.height, mBIH.bpp, mBIH.compression));
|
mBIH.width, mBIH.height, mBIH.bpp, mBIH.compression));
|
||||||
// Verify we support this bit depth
|
// Verify we support this bit depth
|
||||||
if (mBIH.bpp != 1 && mBIH.bpp != 4 && mBIH.bpp != 8 &&
|
if (mBIH.bpp != 1 && mBIH.bpp != 4 && mBIH.bpp != 8 &&
|
||||||
mBIH.bpp != 16 && mBIH.bpp != 24 && mBIH.bpp != 32) {
|
mBIH.bpp != 16 && mBIH.bpp != 24 && mBIH.bpp != 32) {
|
||||||
|
@ -226,36 +296,70 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
|
||||||
CalcBitShift();
|
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;
|
PRUint32 imageLength;
|
||||||
if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
|
if (mBIH.compression == BI_RLE8 || mBIH.compression == BI_RLE4 ||
|
||||||
rv = mImage->EnsureFrame(0, 0, 0, mBIH.width, real_height, gfxASurface::ImageFormatARGB32,
|
mBIH.compression == BI_ALPHABITFIELDS) {
|
||||||
|
rv = mImage->EnsureFrame(0, 0, 0, mBIH.width, real_height,
|
||||||
|
gfxASurface::ImageFormatARGB32,
|
||||||
(PRUint8**)&mImageData, &imageLength);
|
(PRUint8**)&mImageData, &imageLength);
|
||||||
} else {
|
} else {
|
||||||
// mRow is not used for RLE encoded images
|
// mRow is not used for RLE encoded images
|
||||||
mRow = (PRUint8*)moz_malloc((mBIH.width * mBIH.bpp)/8 + 4);
|
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
|
// + 4 because the line is padded to a 4 bit boundary, but I don't want
|
||||||
// to make exact calculations here, that's unnecessary.
|
// to make exact calculations here, that's unnecessary.
|
||||||
// Also, it compensates rounding error.
|
// Also, it compensates rounding error.
|
||||||
if (!mRow) {
|
if (!mRow) {
|
||||||
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
|
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
|
||||||
return;
|
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) {
|
if (NS_FAILED(rv) || !mImageData) {
|
||||||
PostDecoderError(NS_ERROR_FAILURE);
|
PostDecoderError(NS_ERROR_FAILURE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare for transparancy
|
// Prepare for transparency
|
||||||
if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
|
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
|
// Clear the image, as the RLE may jump over areas
|
||||||
memset(mImageData, 0, imageLength);
|
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
|
// Need to increment mPos, else we might get to mPos==mLOH again
|
||||||
// From now on, mPos is irrelevant
|
// From now on, mPos is irrelevant
|
||||||
if (!mBIH.compression || mBIH.compression == BI_BITFIELDS) {
|
if (!mBIH.compression || mBIH.compression == BI_BITFIELDS) {
|
||||||
PRUint32 rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // +7 to round up
|
PRUint32 rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // + 7 to round up
|
||||||
if (rowSize % 4)
|
if (rowSize % 4) {
|
||||||
rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
|
rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
|
||||||
|
}
|
||||||
PRUint32 toCopy;
|
PRUint32 toCopy;
|
||||||
do {
|
do {
|
||||||
toCopy = rowSize - mRowBytes;
|
toCopy = rowSize - mRowBytes;
|
||||||
|
@ -370,35 +475,44 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
|
||||||
p+=2;
|
p+=2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 32:
|
|
||||||
case 24:
|
case 24:
|
||||||
while (lpos > 0) {
|
while (lpos > 0) {
|
||||||
SetPixel(d, p[2], p[1], p[0]);
|
SetPixel(d, p[2], p[1], p[0]);
|
||||||
p += 2;
|
p += 2;
|
||||||
--lpos;
|
--lpos;
|
||||||
if (mBIH.bpp == 32)
|
|
||||||
p++; // Padding byte
|
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
NS_NOTREACHED("Unsupported color depth, but earlier check didn't catch it");
|
NS_NOTREACHED("Unsupported color depth, but earlier check didn't catch it");
|
||||||
}
|
}
|
||||||
mCurLine --;
|
mCurLine --;
|
||||||
if (mCurLine == 0) { // Finished last line
|
if (mCurLine == 0) { // Finished last line
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mRowBytes = 0;
|
mRowBytes = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
} while (aCount > 0);
|
} while (aCount > 0);
|
||||||
}
|
}
|
||||||
else if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
|
else if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
|
||||||
if (((mBIH.compression == BI_RLE8) && (mBIH.bpp != 8))
|
if (((mBIH.compression == BI_RLE8) && (mBIH.bpp != 8)) ||
|
||||||
|| ((mBIH.compression == BI_RLE4) && (mBIH.bpp != 4) && (mBIH.bpp != 1))) {
|
((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"));
|
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP RLE8/RLE4 compression only supports 8/4 bits per pixel\n"));
|
||||||
PostDataError();
|
PostDataError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (aCount > 0) {
|
while (aCount > 0) {
|
||||||
|
@ -562,7 +676,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const PRUint32 rows = mOldLine - mCurLine;
|
const PRUint32 rows = mOldLine - mCurLine;
|
||||||
if (rows) {
|
if (rows) {
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Bobby Holley <bobbyholley@gmail.com>
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
|
* Brian R. Bondy <netzen@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* 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
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -56,11 +57,16 @@ struct BMPFILEHEADER {
|
||||||
|
|
||||||
PRUint32 bihsize;
|
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_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 OS2_HEADER_LENGTH (BFH_INTERNAL_LENGTH + 8)
|
||||||
#define WIN_HEADER_LENGTH (BFH_LENGTH + 36)
|
#define WIN_HEADER_LENGTH (BFH_INTERNAL_LENGTH + 36)
|
||||||
|
|
||||||
struct BMPINFOHEADER {
|
struct BMPINFOHEADER {
|
||||||
PRInt32 width; // Uint16 in OS/2 BMPs
|
PRInt32 width; // Uint16 in OS/2 BMPs
|
||||||
|
@ -106,17 +112,34 @@ struct bitFields {
|
||||||
(((((PRUint32) x) >> 8) & 0xFF) << 16) | \
|
(((((PRUint32) x) >> 8) & 0xFF) << 16) | \
|
||||||
(((((PRUint32) x) >> 16) & 0xFF) << 8) | \
|
(((((PRUint32) x) >> 16) & 0xFF) << 8) | \
|
||||||
(((PRUint32) x) >> 24))
|
(((PRUint32) x) >> 24))
|
||||||
|
|
||||||
|
#define NATIVE32_TO_LITTLE LITTLE_TO_NATIVE32
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define LITTLE_TO_NATIVE16(x) x
|
#define LITTLE_TO_NATIVE16(x) x
|
||||||
#define LITTLE_TO_NATIVE32(x) x
|
#define LITTLE_TO_NATIVE32(x) x
|
||||||
|
#define NATIVE32_TO_LITTLE(x) x
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define USE_RGB
|
#define USE_RGB
|
||||||
|
|
||||||
// BMPINFOHEADER.compression defines
|
// BMPINFOHEADER.compression defines
|
||||||
|
#ifndef BI_RGB
|
||||||
|
#define BI_RGB 0
|
||||||
|
#endif
|
||||||
|
#ifndef BI_RLE8
|
||||||
#define BI_RLE8 1
|
#define BI_RLE8 1
|
||||||
|
#endif
|
||||||
|
#ifndef BI_RLE4
|
||||||
#define BI_RLE4 2
|
#define BI_RLE4 2
|
||||||
|
#endif
|
||||||
|
#ifndef BI_BITFIELDS
|
||||||
#define BI_BITFIELDS 3
|
#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
|
// RLE Escape codes
|
||||||
#define RLE_ESCAPE 0
|
#define RLE_ESCAPE 0
|
||||||
|
@ -146,6 +169,21 @@ public:
|
||||||
nsBMPDecoder();
|
nsBMPDecoder();
|
||||||
~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 WriteInternal(const char* aBuffer, PRUint32 aCount);
|
||||||
virtual void FinishInternal();
|
virtual void FinishInternal();
|
||||||
|
|
||||||
|
@ -184,6 +222,16 @@ private:
|
||||||
/** Set mBIH from the raw data in mRawBuf, converting from little-endian
|
/** Set mBIH from the raw data in mRawBuf, converting from little-endian
|
||||||
* data to native data as necessary */
|
* data to native data as necessary */
|
||||||
void ProcessInfoHeader();
|
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.
|
/** Sets the pixel data in aDecoded to the given values.
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
* David Hyatt <hyatt@netscape.com> (Original Author)
|
* David Hyatt <hyatt@netscape.com> (Original Author)
|
||||||
* Christian Biesinger <cbiesinger@web.de>
|
* Christian Biesinger <cbiesinger@web.de>
|
||||||
* Bobby Holley <bobbyholley@gmail.com>
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
|
* Brian R. Bondy <netzen@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* 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
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -65,39 +66,51 @@ namespace imagelib {
|
||||||
// Actual Data Processing
|
// Actual Data Processing
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
|
||||||
PRUint32 nsICODecoder::CalcAlphaRowSize()
|
PRUint32
|
||||||
|
nsICODecoder::CalcAlphaRowSize()
|
||||||
{
|
{
|
||||||
// Calculate rowsize in DWORD's and then return in # of bytes
|
// Calculate rowsize in DWORD's and then return in # of bytes
|
||||||
PRUint32 rowSize = (mDirEntry.mWidth + 31) / 32; // +31 to round up
|
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()
|
nsICODecoder::nsICODecoder()
|
||||||
{
|
{
|
||||||
mPos = mNumColors = mRowBytes = mImageOffset = mCurrIcon = mNumIcons = 0;
|
mPos = mImageOffset = mCurrIcon = mNumIcons = mBPP = mRowBytes = 0;
|
||||||
mCurLine = 1; // Otherwise decoder will never start
|
mIsPNG = PR_FALSE;
|
||||||
mColors = nsnull;
|
|
||||||
mRow = nsnull;
|
mRow = nsnull;
|
||||||
mHaveAlphaData = mDecodingAndMask = PR_FALSE;
|
mOldLine = mCurLine = 1; // Otherwise decoder will never start
|
||||||
}
|
}
|
||||||
|
|
||||||
nsICODecoder::~nsICODecoder()
|
nsICODecoder::~nsICODecoder()
|
||||||
{
|
{
|
||||||
mPos = 0;
|
|
||||||
|
|
||||||
delete[] mColors;
|
|
||||||
|
|
||||||
mCurLine = 0;
|
|
||||||
mRowBytes = 0;
|
|
||||||
mImageOffset = 0;
|
|
||||||
mCurrIcon = 0;
|
|
||||||
mNumIcons = 0;
|
|
||||||
|
|
||||||
if (mRow) {
|
if (mRow) {
|
||||||
free(mRow);
|
moz_free(mRow);
|
||||||
mRow = nsnull;
|
|
||||||
}
|
}
|
||||||
mDecodingAndMask = PR_FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -106,18 +119,87 @@ nsICODecoder::FinishInternal()
|
||||||
// We shouldn't be called in error cases
|
// We shouldn't be called in error cases
|
||||||
NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call FinishInternal after error!");
|
NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call FinishInternal after error!");
|
||||||
|
|
||||||
// We should never make multiple frames
|
// Finish the internally used decoder as well
|
||||||
NS_ABORT_IF_FALSE(GetFrameCount() <= 1, "Multiple ICO frames?");
|
if (mContainedDecoder) {
|
||||||
|
mContainedDecoder->FinishSharedDecoder();
|
||||||
|
mDecodeDone = mContainedDecoder->GetDecodeDone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Send notifications if appropriate
|
// Returns a buffer filled with the bitmap file header in little endian:
|
||||||
if (!IsSizeDecode() && (GetFrameCount() == 1)) {
|
// 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
|
// The color table is present only if BPP is <= 8
|
||||||
nsIntRect r(0, 0, mDirEntry.mWidth, mDirEntry.mHeight);
|
if (mDirEntry.mBitCount <= 8) {
|
||||||
PostInvalidation(r);
|
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();
|
fileSize = NATIVE32_TO_LITTLE(fileSize);
|
||||||
PostDecodeDone();
|
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.
|
return; // Nothing to do.
|
||||||
|
|
||||||
PRUint16 colorDepth = 0;
|
PRUint16 colorDepth = 0;
|
||||||
while (mCurrIcon < mNumIcons) {
|
// Loop through each entry's dir entry
|
||||||
if (mPos >= DIRENTRYOFFSET + (mCurrIcon*sizeof(mDirEntryArray)) &&
|
while (mCurrIcon < mNumIcons) {
|
||||||
mPos < DIRENTRYOFFSET + ((mCurrIcon+1)*sizeof(mDirEntryArray))) {
|
if (mPos >= DIRENTRYOFFSET + (mCurrIcon * sizeof(mDirEntryArray)) &&
|
||||||
PRUint32 toCopy = sizeof(mDirEntryArray) - (mPos - DIRENTRYOFFSET - mCurrIcon*sizeof(mDirEntryArray));
|
mPos < DIRENTRYOFFSET + ((mCurrIcon + 1) * sizeof(mDirEntryArray))) {
|
||||||
if (toCopy > aCount)
|
PRUint32 toCopy = sizeof(mDirEntryArray) -
|
||||||
|
(mPos - DIRENTRYOFFSET - mCurrIcon * sizeof(mDirEntryArray));
|
||||||
|
if (toCopy > aCount) {
|
||||||
toCopy = aCount;
|
toCopy = aCount;
|
||||||
|
}
|
||||||
memcpy(mDirEntryArray + sizeof(mDirEntryArray) - toCopy, aBuffer, toCopy);
|
memcpy(mDirEntryArray + sizeof(mDirEntryArray) - toCopy, aBuffer, toCopy);
|
||||||
mPos += toCopy;
|
mPos += toCopy;
|
||||||
aCount -= toCopy;
|
aCount -= toCopy;
|
||||||
|
@ -166,15 +251,18 @@ nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
|
||||||
return; // Need more data
|
return; // Need more data
|
||||||
|
|
||||||
IconDirEntry e;
|
IconDirEntry e;
|
||||||
if (mPos == 22+mCurrIcon*sizeof(mDirEntryArray)) {
|
if (mPos == (DIRENTRYOFFSET + ICODIRENTRYSIZE) +
|
||||||
|
(mCurrIcon * sizeof(mDirEntryArray))) {
|
||||||
mCurrIcon++;
|
mCurrIcon++;
|
||||||
ProcessDirEntry(e);
|
ProcessDirEntry(e);
|
||||||
if ((e.mWidth == PREFICONSIZE && e.mHeight == PREFICONSIZE && e.mBitCount >= colorDepth)
|
if ((e.mWidth == PREFICONSIZE && e.mHeight == PREFICONSIZE &&
|
||||||
|| (mCurrIcon == mNumIcons && mImageOffset == 0)) {
|
e.mBitCount >= colorDepth) ||
|
||||||
|
(mCurrIcon == mNumIcons && mImageOffset == 0)) {
|
||||||
mImageOffset = e.mImageOffset;
|
mImageOffset = e.mImageOffset;
|
||||||
|
|
||||||
// ensure mImageOffset is >= the size of the direntry headers (bug #245631)
|
// ensure mImageOffset is >= size of the direntry headers (bug #245631)
|
||||||
PRUint32 minImageOffset = DIRENTRYOFFSET + mNumIcons*sizeof(mDirEntryArray);
|
PRUint32 minImageOffset = DIRENTRYOFFSET +
|
||||||
|
mNumIcons * sizeof(mDirEntryArray);
|
||||||
if (mImageOffset < minImageOffset) {
|
if (mImageOffset < minImageOffset) {
|
||||||
PostDataError();
|
PostDataError();
|
||||||
return;
|
return;
|
||||||
|
@ -197,7 +285,67 @@ nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
|
||||||
aCount -= toSkip;
|
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.
|
// We've found the icon.
|
||||||
PRUint32 toCopy = sizeof(mBIHraw) - (mPos - mImageOffset);
|
PRUint32 toCopy = sizeof(mBIHraw) - (mPos - mImageOffset);
|
||||||
if (toCopy > aCount)
|
if (toCopy > aCount)
|
||||||
|
@ -209,257 +357,154 @@ nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
|
||||||
aBuffer += toCopy;
|
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) {
|
// 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
|
||||||
ProcessInfoHeader();
|
// generate this header ourselves and feed it to the BMP decoder.
|
||||||
PostSize(mDirEntry.mWidth, mDirEntry.mHeight);
|
PRInt8 bfhBuffer[BMPFILEHEADERSIZE];
|
||||||
if (IsSizeDecode())
|
if (!FillBitmapFileHeaderBuffer(bfhBuffer)) {
|
||||||
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) {
|
|
||||||
PostDataError();
|
PostDataError();
|
||||||
return;
|
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
|
// Setup the cursor hot spot if one is present
|
||||||
if (rowSize % 4)
|
SetHotSpotIfCursor();
|
||||||
rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
|
|
||||||
PRUint32 toCopy;
|
// Fix the height on the BMP resource
|
||||||
do {
|
FillBitmapInformationBufferHeight((PRInt8*)mBIHraw);
|
||||||
toCopy = rowSize - mRowBytes;
|
|
||||||
if (toCopy) {
|
// Write out the BMP's bitmap info header
|
||||||
if (toCopy > aCount)
|
mContainedDecoder->Write(mBIHraw, sizeof(mBIHraw));
|
||||||
toCopy = aCount;
|
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);
|
memcpy(mRow + mRowBytes, aBuffer, toCopy);
|
||||||
aCount -= toCopy;
|
aCount -= toCopy;
|
||||||
aBuffer += toCopy;
|
aBuffer += toCopy;
|
||||||
mRowBytes += toCopy;
|
mRowBytes += toCopy;
|
||||||
}
|
}
|
||||||
if (rowSize == mRowBytes) {
|
if (rowSize == mRowBytes) {
|
||||||
mCurLine--;
|
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;
|
mRowBytes = 0;
|
||||||
}
|
|
||||||
} while (!mDecodingAndMask && aCount > 0);
|
|
||||||
|
|
||||||
}
|
PRUint32* imageData = static_cast<nsBMPDecoder*>(mContainedDecoder.get())->GetImageData();
|
||||||
|
PRUint32* decoded = imageData + mCurLine * mDirEntry.mWidth;
|
||||||
if (mDecodingAndMask && !mHaveAlphaData) {
|
PRUint32* decoded_end = decoded + mDirEntry.mWidth;
|
||||||
PRUint32 rowSize = CalcAlphaRowSize();
|
PRUint8* p = mRow, *p_end = mRow + rowSize;
|
||||||
|
while (p < p_end) {
|
||||||
if (mPos == (1 + mImageOffset + BITMAPINFOSIZE + mNumColors*4)) {
|
PRUint8 idx = *p++;
|
||||||
mPos++;
|
for (PRUint8 bit = 0x80; bit && decoded<decoded_end; bit >>= 1) {
|
||||||
mRowBytes = 0;
|
// Clear pixel completely for transparency.
|
||||||
mCurLine = mDirEntry.mHeight;
|
if (idx & bit) {
|
||||||
mRow = (PRUint8*)realloc(mRow, rowSize);
|
*decoded = 0;
|
||||||
if (!mRow) {
|
}
|
||||||
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
|
decoded++;
|
||||||
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 ++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -467,51 +512,19 @@ nsICODecoder::ProcessDirEntry(IconDirEntry& aTarget)
|
||||||
{
|
{
|
||||||
memset(&aTarget, 0, sizeof(aTarget));
|
memset(&aTarget, 0, sizeof(aTarget));
|
||||||
memcpy(&aTarget.mWidth, mDirEntryArray, sizeof(aTarget.mWidth));
|
memcpy(&aTarget.mWidth, mDirEntryArray, sizeof(aTarget.mWidth));
|
||||||
memcpy(&aTarget.mHeight, mDirEntryArray+1, sizeof(aTarget.mHeight));
|
memcpy(&aTarget.mHeight, mDirEntryArray + 1, sizeof(aTarget.mHeight));
|
||||||
memcpy(&aTarget.mColorCount, mDirEntryArray+2, sizeof(aTarget.mColorCount));
|
memcpy(&aTarget.mColorCount, mDirEntryArray + 2, sizeof(aTarget.mColorCount));
|
||||||
memcpy(&aTarget.mReserved, mDirEntryArray+3, sizeof(aTarget.mReserved));
|
memcpy(&aTarget.mReserved, mDirEntryArray + 3, sizeof(aTarget.mReserved));
|
||||||
|
memcpy(&aTarget.mPlanes, mDirEntryArray + 4, sizeof(aTarget.mPlanes));
|
||||||
memcpy(&aTarget.mPlanes, mDirEntryArray+4, sizeof(aTarget.mPlanes));
|
|
||||||
aTarget.mPlanes = LITTLE_TO_NATIVE16(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);
|
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);
|
aTarget.mBytesInRes = LITTLE_TO_NATIVE32(aTarget.mBytesInRes);
|
||||||
|
memcpy(&aTarget.mImageOffset, mDirEntryArray + 12,
|
||||||
memcpy(&aTarget.mImageOffset, mDirEntryArray+12, sizeof(aTarget.mImageOffset));
|
sizeof(aTarget.mImageOffset));
|
||||||
aTarget.mImageOffset = LITTLE_TO_NATIVE32(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 imagelib
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* David Hyatt <hyatt@netscape.com> (Original Author)
|
* David Hyatt <hyatt@netscape.com> (Original Author)
|
||||||
* Bobby Holley <bobbyholley@gmail.com>
|
* Bobby Holley <bobbyholley@gmail.com>
|
||||||
|
* Brian R. Bondy <netzen@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* 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
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -45,10 +46,15 @@
|
||||||
#include "Decoder.h"
|
#include "Decoder.h"
|
||||||
#include "imgIDecoderObserver.h"
|
#include "imgIDecoderObserver.h"
|
||||||
#include "nsBMPDecoder.h"
|
#include "nsBMPDecoder.h"
|
||||||
|
#include "nsPNGDecoder.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace imagelib {
|
namespace imagelib {
|
||||||
|
|
||||||
|
#define ICODIRENTRYSIZE 16
|
||||||
|
#define PNGSIGNATURESIZE 8
|
||||||
|
#define BMPFILEHEADERSIZE 14
|
||||||
|
|
||||||
class RasterImage;
|
class RasterImage;
|
||||||
|
|
||||||
struct IconDirEntry
|
struct IconDirEntry
|
||||||
|
@ -80,37 +86,42 @@ public:
|
||||||
virtual void FinishInternal();
|
virtual void FinishInternal();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Private helper methods
|
// Processes a single dir entry of the icon resource
|
||||||
void ProcessDirEntry(IconDirEntry& aTarget);
|
void ProcessDirEntry(IconDirEntry& aTarget);
|
||||||
void ProcessInfoHeader();
|
// Sets the hotspot property of if we have a cursor
|
||||||
|
void SetHotSpotIfCursor();
|
||||||
nsresult SetImageData();
|
// 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();
|
PRUint32 CalcAlphaRowSize();
|
||||||
|
// Obtains the number of colors from the BPP, mBPP must be filled in
|
||||||
|
PRUint16 GetNumColors();
|
||||||
|
|
||||||
PRUint32 mPos;
|
PRUint16 mBPP; // Stores the images BPP
|
||||||
PRUint16 mNumIcons;
|
PRUint32 mPos; // Keeps track of the position we have decoded up until
|
||||||
PRUint16 mCurrIcon;
|
PRUint16 mNumIcons; // Stores the number of icons in the ICO file
|
||||||
PRUint32 mImageOffset;
|
PRUint16 mCurrIcon; // Stores the current dir entry index we are processing
|
||||||
|
PRUint32 mImageOffset; // Stores the offset of the image data we want
|
||||||
char mDirEntryArray[16];
|
PRUint8 *mRow; // Holds one raw line of the image
|
||||||
IconDirEntry mDirEntry;
|
PRInt32 mCurLine; // Line index of the image that's currently being decoded
|
||||||
|
|
||||||
char mBIHraw[40];
|
|
||||||
BMPINFOHEADER mBIH;
|
|
||||||
|
|
||||||
PRUint32 mNumColors;
|
|
||||||
colorTable* mColors;
|
|
||||||
|
|
||||||
PRUint8* mRow; // Holds one raw line of the image
|
|
||||||
PRUint32 mRowBytes; // How many bytes of the row were already received
|
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;
|
char mDirEntryArray[ICODIRENTRYSIZE]; // Holds the current dir entry buffer
|
||||||
|
IconDirEntry mDirEntry; // Holds a decoded dir entry
|
||||||
PRPackedBool mHaveAlphaData;
|
// 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 mIsCursor;
|
||||||
PRPackedBool mDecodingAndMask;
|
// Stores whether or not the contained resource is a PNG
|
||||||
|
PRPackedBool mIsPNG;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace imagelib
|
} // namespace imagelib
|
||||||
|
|
|
@ -77,10 +77,9 @@ static PRLogModuleInfo *gPNGDecoderAccountingLog =
|
||||||
#define HEIGHT_OFFSET (WIDTH_OFFSET + 4)
|
#define HEIGHT_OFFSET (WIDTH_OFFSET + 4)
|
||||||
#define BYTES_NEEDED_FOR_DIMENSIONS (HEIGHT_OFFSET + 4)
|
#define BYTES_NEEDED_FOR_DIMENSIONS (HEIGHT_OFFSET + 4)
|
||||||
|
|
||||||
// This is defined in the PNG spec as an invariant. We use it to
|
// First 8 bytes of a PNG file
|
||||||
// do manual validation without libpng.
|
const PRUint8
|
||||||
static const PRUint8 pngSignatureBytes[] =
|
nsPNGDecoder::pngSignatureBytes[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
|
||||||
{ 137, 80, 78, 71, 13, 10, 26, 10 };
|
|
||||||
|
|
||||||
nsPNGDecoder::nsPNGDecoder() :
|
nsPNGDecoder::nsPNGDecoder() :
|
||||||
mPNG(nsnull), mInfo(nsnull),
|
mPNG(nsnull), mInfo(nsnull),
|
||||||
|
@ -317,7 +316,8 @@ nsPNGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
|
||||||
if (mHeaderBytesRead == BYTES_NEEDED_FOR_DIMENSIONS) {
|
if (mHeaderBytesRead == BYTES_NEEDED_FOR_DIMENSIONS) {
|
||||||
|
|
||||||
// Check that the signature bytes are right
|
// Check that the signature bytes are right
|
||||||
if (memcmp(mHeaderBuf, pngSignatureBytes, sizeof(pngSignatureBytes))) {
|
if (memcmp(mHeaderBuf, nsPNGDecoder::pngSignatureBytes,
|
||||||
|
sizeof(pngSignatureBytes))) {
|
||||||
PostDataError();
|
PostDataError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,21 @@ public:
|
||||||
|
|
||||||
void EndImageFrame();
|
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:
|
public:
|
||||||
png_structp mPNG;
|
png_structp mPNG;
|
||||||
png_infop mInfo;
|
png_infop mInfo;
|
||||||
|
@ -113,6 +128,10 @@ public:
|
||||||
png_const_charp error_msg);
|
png_const_charp error_msg);
|
||||||
static void PNGAPI warning_callback(png_structp png_ptr,
|
static void PNGAPI warning_callback(png_structp png_ptr,
|
||||||
png_const_charp warning_msg);
|
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
|
} // namespace imagelib
|
||||||
|
|
|
@ -88,6 +88,26 @@ Decoder::Init(RasterImage* aImage, imgIDecoderObserver* aObserver)
|
||||||
mInitialized = true;
|
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
|
void
|
||||||
Decoder::Write(const char* aBuffer, PRUint32 aCount)
|
Decoder::Write(const char* aBuffer, PRUint32 aCount)
|
||||||
{
|
{
|
||||||
|
@ -155,6 +175,14 @@ Decoder::Finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Decoder::FinishSharedDecoder()
|
||||||
|
{
|
||||||
|
if (!HasError()) {
|
||||||
|
FinishInternal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Decoder::FlushInvalidations()
|
Decoder::FlushInvalidations()
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,6 +63,18 @@ public:
|
||||||
*/
|
*/
|
||||||
void Init(RasterImage* aImage, imgIDecoderObserver* aObserver);
|
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.
|
* Writes data to the decoder.
|
||||||
*
|
*
|
||||||
|
@ -82,6 +94,14 @@ public:
|
||||||
*/
|
*/
|
||||||
void Finish();
|
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
|
* Tells the decoder to flush any pending invalidations. This informs the image
|
||||||
* frame of its decoded region, and sends the appropriate OnDataAvailable call
|
* frame of its decoded region, and sends the appropriate OnDataAvailable call
|
||||||
|
@ -122,6 +142,9 @@ public:
|
||||||
bool HasDecoderError() { return NS_FAILED(mFailCode); };
|
bool HasDecoderError() { return NS_FAILED(mFailCode); };
|
||||||
nsresult GetDecoderError() { return mFailCode; };
|
nsresult GetDecoderError() { return mFailCode; };
|
||||||
void PostResizeError() { PostDataError(); }
|
void PostResizeError() { PostDataError(); }
|
||||||
|
bool GetDecodeDone() const {
|
||||||
|
return mDecodeDone;
|
||||||
|
}
|
||||||
|
|
||||||
// flags. Keep these in sync with imgIContainer.idl.
|
// flags. Keep these in sync with imgIContainer.idl.
|
||||||
// SetDecodeFlags must be called before Init(), otherwise
|
// SetDecodeFlags must be called before Init(), otherwise
|
||||||
|
@ -176,12 +199,13 @@ protected:
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
nsRefPtr<RasterImage> mImage;
|
nsRefPtr<RasterImage> mImage;
|
||||||
|
|
||||||
PRUint32 mDecodeFlags;
|
|
||||||
|
|
||||||
private:
|
|
||||||
nsCOMPtr<imgIDecoderObserver> mObserver;
|
nsCOMPtr<imgIDecoderObserver> mObserver;
|
||||||
|
|
||||||
|
PRUint32 mDecodeFlags;
|
||||||
|
bool mDecodeDone;
|
||||||
|
bool mDataError;
|
||||||
|
|
||||||
|
private:
|
||||||
PRUint32 mFrameCount; // Number of frames, including anything in-progress
|
PRUint32 mFrameCount; // Number of frames, including anything in-progress
|
||||||
|
|
||||||
nsIntRect mInvalidRect; // Tracks an invalidation region in the current frame.
|
nsIntRect mInvalidRect; // Tracks an invalidation region in the current frame.
|
||||||
|
@ -191,8 +215,6 @@ private:
|
||||||
bool mInitialized;
|
bool mInitialized;
|
||||||
bool mSizeDecode;
|
bool mSizeDecode;
|
||||||
bool mInFrame;
|
bool mInFrame;
|
||||||
bool mDecodeDone;
|
|
||||||
bool mDataError;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace imagelib
|
} // namespace imagelib
|
||||||
|
|
Загрузка…
Ссылка в новой задаче