--- a/modules/libpr0n/build/Makefile.in
+++ b/modules/libpr0n/build/Makefile.in
@@ -49,16 +49,17 @@ IS_COMPONENT = 1
MODULE_NAME = nsImageLib2Module
GRE_MODULE = 1
LIBXUL_LIBRARY = 1
PACKAGE_FILE = imglib2.pkg
REQUIRES = xpcom \
string \
+ thebes \
necko \
nkcache \
gfx \
$(JPEG_REQUIRES) \
$(PNG_REQUIRES) \
$(ZLIB_REQUIRES) \
$(NULL)
--- a/modules/libpr0n/decoders/bmp/Makefile.in
+++ b/modules/libpr0n/decoders/bmp/Makefile.in
@@ -45,15 +45,17 @@ include $(DEPTH)/config/autoconf.mk
MODULE = imgbmp
LIBRARY_NAME = imgbmp_s
FORCE_STATIC_LIB = 1
MODULE_NAME = nsBMPModule
LIBXUL_LIBRARY = 1
REQUIRES = xpcom \
+ string \
gfx \
+ thebes \
imglib2 \
$(NULL)
CPPSRCS = nsBMPDecoder.cpp nsICODecoder.cpp
include $(topsrcdir)/config/rules.mk
--- a/modules/libpr0n/decoders/bmp/nsBMPDecoder.cpp
+++ b/modules/libpr0n/decoders/bmp/nsBMPDecoder.cpp
@@ -42,47 +42,50 @@
#include <stdlib.h>
#include "nsBMPDecoder.h"
#include "nsIInputStream.h"
#include "nsIComponentManager.h"
#include "imgIContainerObserver.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIInterfaceRequestorUtils.h"
#include "imgILoad.h"
+#include "nsIImage.h"
#include "prlog.h"
#ifdef PR_LOGGING
PRLogModuleInfo *gBMPLog = PR_NewLogModule("BMPDecoder");
#endif
+// Convert from row (1..height) to absolute line (0..height-1)
+#define LINE(row) ((mBIH.height < 0) ? (-mBIH.height - (row)) : ((row) - 1))
+#define PIXEL_OFFSET(row, col) (LINE(row) * mBIH.width + col)
+
NS_IMPL_ISUPPORTS1(nsBMPDecoder, imgIDecoder)
nsBMPDecoder::nsBMPDecoder()
{
mColors = nsnull;
mRow = nsnull;
- mPos = mNumColors = mRowBytes = 0;
- mCurLine = 1; // Otherwise decoder will never start
+ mCurPos = mPos = mNumColors = mRowBytes = 0;
+ mOldLine = mCurLine = 1; // Otherwise decoder will never start
mState = eRLEStateInitial;
mStateData = 0;
- mAlpha = mAlphaPtr = mDecoded = mDecoding = nsnull;
mLOH = WIN_HEADER_LENGTH;
}
nsBMPDecoder::~nsBMPDecoder()
{
delete[] mColors;
- free(mRow);
- if (mAlpha)
- free(mAlpha);
- if (mDecoded)
- free(mDecoded);
+ if (mRow)
+ free(mRow);
}
NS_IMETHODIMP nsBMPDecoder::Init(imgILoad *aLoad)
{
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("nsBMPDecoder::Init(%p)\n", aLoad));
mObserver = do_QueryInterface(aLoad);
nsresult rv;
@@ -96,16 +99,17 @@ NS_IMETHODIMP nsBMPDecoder::Init(imgILoa
return aLoad->SetImage(mImage);
}
NS_IMETHODIMP nsBMPDecoder::Close()
{
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("nsBMPDecoder::Close()\n"));
if (mObserver) {
+ mObserver->OnStopFrame(nsnull, mFrame);
mObserver->OnStopContainer(nsnull, mImage);
mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
mObserver = nsnull;
}
mImage = nsnull;
mFrame = nsnull;
return NS_OK;
}
@@ -130,69 +134,16 @@ NS_IMETHODIMP nsBMPDecoder::WriteFrom(ns
return aInStr->ReadSegments(ReadSegCb, this, aCount, aRetval);
}
// ----------------------------------------
// Actual Data Processing
// ----------------------------------------
-nsresult nsBMPDecoder::SetData()
-{
- PRInt32 line = (mBIH.height < 0) ? (-mBIH.height - mCurLine--) : --mCurLine;
- nsresult rv = mFrame->SetImageData(mDecoded, mBpr, line * mBpr);
- NS_ENSURE_SUCCESS(rv, rv);
-
- nsIntRect r(0, line, mBIH.width, 1);
- return mObserver->OnDataAvailable(nsnull, mFrame, &r);
-}
-
-nsresult nsBMPDecoder::WriteRLERows(PRUint32 rows)
-{
- PRUint32 cnt, line;
-
- PRUint32 abpr;
- PRUint8 bit;
- PRUint8* pos = mAlpha;
- // First pack the alpha data
- nsresult rv = mFrame->GetAlphaBytesPerRow(&abpr);
- NS_ENSURE_SUCCESS(rv, rv);
-
- gfx_format format;
- mFrame->GetFormat(&format);
- if (format == RLE_GFXFORMAT_ALPHA)
- abpr >>= 2;
-
- for (cnt = 0; cnt < abpr; cnt++) {
- PRUint8 byte = 0;
- for (bit = 128; bit; bit >>= 1)
- byte |= *pos++ & bit;
- mAlpha[cnt] = byte;
-#ifdef IS_LITTLE_ENDIAN
- mDecoded[(cnt << 2) + 3] = byte ? 0 : 255;
-#else
- mDecoded[(cnt << 2)] = byte ? 0 : 255;
-#endif
- }
-
- for (cnt = 0; cnt < rows; cnt++) {
- line = (mBIH.height < 0) ? (-mBIH.height - mCurLine--) : --mCurLine;
- rv = mFrame->SetImageData(mDecoded, mBpr, line * mBpr);
- NS_ENSURE_SUCCESS(rv, rv);
- if (cnt == 0) {
- memset(mAlpha, 0, mBIH.width);
- memset(mDecoded, 0, mBpr);
- }
- }
-
- line = (mBIH.height < 0) ? (-mBIH.height - mCurLine - rows) : mCurLine;
- nsIntRect r(0, line, mBIH.width, rows);
- return mObserver->OnDataAvailable(nsnull, mFrame, &r);
-}
-
static void calcBitmask(PRUint32 aMask, PRUint8& aBegin, PRUint8& aLength)
{
// find the rightmost 1
PRUint8 pos;
PRBool started = PR_FALSE;
aBegin = aLength = 0;
for (pos = 0; pos <= 31; pos++) {
if (!started && (aMask & (1 << pos))) {
@@ -289,37 +240,53 @@ NS_METHOD nsBMPDecoder::ProcessData(cons
if (mBIH.width < 0 || mBIH.width > k64KWidth)
return NS_ERROR_FAILURE;
PRUint32 real_height = (mBIH.height > 0) ? mBIH.height : -mBIH.height;
rv = mImage->Init(mBIH.width, real_height, mObserver);
NS_ENSURE_SUCCESS(rv, rv);
rv = mObserver->OnStartContainer(nsnull, mImage);
NS_ENSURE_SUCCESS(rv, rv);
- mCurLine = real_height;
+ mOldLine = mCurLine = real_height;
- mRow = (PRUint8*)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) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
rv = mFrame->Init(0, 0, mBIH.width, real_height, RLE_GFXFORMAT_ALPHA, 24);
} else {
+ // mRow is not used for RLE encoded images
+ mRow = (PRUint8*)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) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
rv = mFrame->Init(0, 0, mBIH.width, real_height, BMP_GFXFORMAT, 24);
}
NS_ENSURE_SUCCESS(rv, rv);
+
+ PRUint32 imageLength;
+ mFrame->GetImageData((PRUint8**)&mImageData, &imageLength);
+ if (!mImageData)
+ return NS_ERROR_FAILURE;
+
+ // Prepare for transparancy
+ 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"));
+ return NS_ERROR_FAILURE;
+ }
+ // Clear the image, as the RLE may jump over areas
+ memset(mImageData, 0, imageLength);
+ }
+
rv = mImage->AppendFrame(mFrame);
NS_ENSURE_SUCCESS(rv, rv);
mObserver->OnStartFrame(nsnull, mFrame);
NS_ENSURE_SUCCESS(rv, rv);
- rv = mFrame->GetImageBytesPerRow(&mBpr);
- NS_ENSURE_SUCCESS(rv, rv);
}
PRUint8 bpc; // bytes per color
bpc = (mBFH.bihsize == OS2_BIH_LENGTH) ? 3 : 4; // OS/2 Bitmaps have no padding byte
if (mColors && (mPos >= mLOH && (mPos < (mLOH + mNumColors * bpc)))) {
// We will receive (mNumColors * bpc) bytes of color data
PRUint32 colorBytes = mPos - mLOH; // Number of bytes already received
PRUint8 colorNum = colorBytes / bpc; // Color which is currently received
PRUint8 at = colorBytes % bpc;
@@ -376,25 +343,20 @@ NS_METHOD nsBMPDecoder::ProcessData(cons
if (toCopy) {
if (toCopy > aCount)
toCopy = aCount;
memcpy(mRow + mRowBytes, aBuffer, toCopy);
aCount -= toCopy;
aBuffer += toCopy;
mRowBytes += toCopy;
}
- if ((rowSize - mRowBytes) == 0) {
- if (!mDecoded) {
- mDecoded = (PRUint8*)malloc(mBpr);
- if (!mDecoded)
- return NS_ERROR_OUT_OF_MEMORY;
- }
-
+ if (rowSize == mRowBytes) {
+ // Collected a whole row into mRow, process it
PRUint8* p = mRow;
- PRUint8* d = mDecoded;
+ PRUint32* d = mImageData + PIXEL_OFFSET(mCurLine, 0);
PRUint32 lpos = mBIH.width;
switch (mBIH.bpp) {
case 1:
while (lpos > 0) {
PRInt8 bit;
PRUint8 idx;
for (bit = 7; bit >= 0 && lpos > 0; bit--) {
idx = (*p >> bit) & 1;
@@ -437,53 +399,32 @@ NS_METHOD nsBMPDecoder::ProcessData(cons
if (mBIH.bpp == 32)
p++; // Padding byte
++p;
}
break;
default:
NS_NOTREACHED("Unsupported color depth, but earlier check didn't catch it");
}
-
- nsresult rv = SetData();
- NS_ENSURE_SUCCESS(rv, rv);
-
+ mCurLine --;
if (mCurLine == 0) { // Finished last line
- return mObserver->OnStopFrame(nsnull, mFrame);
+ 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"));
return NS_ERROR_FAILURE;
}
- if (!mAlpha) {
- PRUint32 alpha;
- rv = mFrame->GetAlphaBytesPerRow(&alpha);
- NS_ENSURE_SUCCESS(rv, rv);
- // Allocate an unpacked buffer
- mAlpha = (PRUint8*)calloc(alpha, 8);
- if (!mAlpha)
- return NS_ERROR_OUT_OF_MEMORY;
- mAlphaPtr = mAlpha;
- }
-
- if (!mDecoded) {
- mDecoded = (PRUint8*)calloc(mBpr, 1);
- if (!mDecoded)
- return NS_ERROR_OUT_OF_MEMORY;
- mDecoding = mDecoded;
- }
-
while (aCount > 0) {
PRUint8 byte;
switch(mState) {
case eRLEStateInitial:
mStateData = (PRUint8)*aBuffer++;
aCount--;
@@ -495,68 +436,61 @@ NS_METHOD nsBMPDecoder::ProcessData(cons
aCount--;
if (mStateData != RLE_ESCAPE) { // encoded mode
// Encoded mode consists of two bytes:
// the first byte (mStateData) specifies the
// number of consecutive pixels to be drawn
// using the color index contained in
// the second byte
// Work around bitmaps that specify too many pixels
- if (mAlphaPtr + mStateData > mAlpha + mBIH.width)
- mStateData = (PRUint32)(mAlpha + mBIH.width - mAlphaPtr);
- memset(mAlphaPtr, 0xFF, mStateData);
- mAlphaPtr += mStateData;
- if (mBIH.compression == BI_RLE8) {
- while (mStateData > 0) {
- SetPixel(mDecoding, byte, mColors);
- mStateData--;
- }
- } else {
- while (mStateData > 0) {
- Set4BitPixel(mDecoding, byte, mStateData, mColors);
+ mState = eRLEStateInitial;
+ PRUint32 pixelsNeeded = PR_MIN((PRUint32)(mBIH.width - mCurPos), mStateData);
+ if (pixelsNeeded) {
+ PRUint32* d = mImageData + PIXEL_OFFSET(mCurLine, mCurPos);
+ mCurPos += pixelsNeeded;
+ if (mBIH.compression == BI_RLE8) {
+ do {
+ SetPixel(d, byte, mColors);
+ pixelsNeeded --;
+ } while (pixelsNeeded);
+ } else {
+ do {
+ Set4BitPixel(d, byte, pixelsNeeded, mColors);
+ } while (pixelsNeeded);
}
}
-
- mState = eRLEStateInitial;
continue;
}
switch(byte) {
case RLE_ESCAPE_EOL:
- // End of Line: Write out current row
- // and reset our row buffer
- rv = WriteRLERows(1);
- NS_ENSURE_SUCCESS(rv, rv);
- mAlphaPtr = mAlpha;
- mDecoding = mDecoded;
-
+ // End of Line: Go to next row
+ mCurLine --;
+ mCurPos = 0;
mState = eRLEStateInitial;
break;
case RLE_ESCAPE_EOF: // EndOfFile
- rv = WriteRLERows(mCurLine);
- NS_ENSURE_SUCCESS(rv, rv);
+ mCurPos = mCurLine = 0;
break;
case RLE_ESCAPE_DELTA:
mState = eRLEStateNeedXDelta;
continue;
default : // absolute mode
// Save the number of pixels to read
mStateData = byte;
- if (mAlphaPtr + mStateData > mAlpha + mBIH.width) {
+ if (mCurPos + mStateData > (PRUint32)mBIH.width) {
// We can work around bitmaps that specify one
// pixel too many, but only if their width is odd.
mStateData -= mBIH.width & 1;
- if (mAlphaPtr + mStateData > mAlpha + mBIH.width)
+ if (mCurPos + mStateData > (PRUint32)mBIH.width)
return NS_ERROR_FAILURE;
}
- memset(mAlphaPtr, 0xFF, mStateData);
- mAlphaPtr += mStateData;
// See if we will need to skip a byte
// to word align the pixel data
// mStateData is a number of pixels
// so allow for the RLE compression type
// Pixels RLE8=1 RLE4=2
// 1 Pad Pad
// 2 No Pad
@@ -569,55 +503,55 @@ NS_METHOD nsBMPDecoder::ProcessData(cons
continue;
}
break;
case eRLEStateNeedXDelta:
// Handle the XDelta and proceed to get Y Delta
byte = *aBuffer++;
aCount--;
- mAlphaPtr += byte;
- if (mAlphaPtr > mAlpha + mBIH.width)
- mAlphaPtr = mAlpha + mBIH.width;
- mDecoding += byte * GFXBYTESPERPIXEL;
+ mCurPos += byte;
+ if (mCurPos > mBIH.width)
+ mCurPos = mBIH.width;
mState = eRLEStateNeedYDelta;
continue;
case eRLEStateNeedYDelta:
// Get the Y Delta and then "handle" the move
byte = *aBuffer++;
aCount--;
mState = eRLEStateInitial;
- if (byte == 0)
- continue; // Nothing more to do
-
- rv = WriteRLERows(PR_MIN(byte, mCurLine));
- NS_ENSURE_SUCCESS(rv, rv);
+ mCurLine -= PR_MIN(byte, mCurLine);
break;
case eRLEStateAbsoluteMode: // Absolute Mode
case eRLEStateAbsoluteModePadded:
- // In absolute mode, the second byte (mStateData)
- // represents the number of pixels
- // that follow, each of which contains
- // the color index of a single pixel.
- if (mBIH.compression == BI_RLE8) {
- while (aCount > 0 && mStateData > 0) {
- byte = *aBuffer++;
- aCount--;
- SetPixel(mDecoding, byte, mColors);
- mStateData--;
+ if (mStateData) {
+ // In absolute mode, the second byte (mStateData)
+ // represents the number of pixels
+ // that follow, each of which contains
+ // the color index of a single pixel.
+ PRUint32* d = mImageData + PIXEL_OFFSET(mCurLine, mCurPos);
+ PRUint32* oldPos = d;
+ if (mBIH.compression == BI_RLE8) {
+ while (aCount > 0 && mStateData > 0) {
+ byte = *aBuffer++;
+ aCount--;
+ SetPixel(d, byte, mColors);
+ mStateData--;
+ }
+ } else {
+ while (aCount > 0 && mStateData > 0) {
+ byte = *aBuffer++;
+ aCount--;
+ Set4BitPixel(d, byte, mStateData, mColors);
+ }
}
- } else {
- while (aCount > 0 && mStateData > 0) {
- byte = *aBuffer++;
- aCount--;
- Set4BitPixel(mDecoding, byte, mStateData, mColors);
- }
+ mCurPos += d - oldPos;
}
if (mStateData == 0) {
// In absolute mode, each run must
// be aligned on a word boundary
if (mState == eRLEStateAbsoluteMode) { // Word Aligned
mState = eRLEStateInitial;
@@ -634,22 +568,36 @@ NS_METHOD nsBMPDecoder::ProcessData(cons
default :
NS_NOTREACHED("BMP RLE decompression: unknown state!");
return NS_ERROR_FAILURE;
}
// Because of the use of the continue statement
// we only get here for eol, eof or y delta
if (mCurLine == 0) { // Finished last line
- return mObserver->OnStopFrame(nsnull, mFrame);
+ break;
}
}
}
}
+ const PRUint32 rows = mOldLine - mCurLine;
+ if (rows) {
+ nsIntRect r(0, LINE(mCurLine), mBIH.width, rows);
+
+ // Tell the image that it's data has been updated
+ nsCOMPtr<nsIImage> img(do_GetInterface(mFrame));
+ if (!img)
+ return PR_FALSE;
+ img->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r);
+
+ mObserver->OnDataAvailable(nsnull, mFrame, &r);
+ mOldLine = mCurLine;
+ }
+
return NS_OK;
}
void nsBMPDecoder::ProcessFileHeader()
{
memset(&mBFH, 0, sizeof(mBFH));
memcpy(&mBFH.signature, mRawBuf, sizeof(mBFH.signature));
memcpy(&mBFH.filesize, mRawBuf + 2, sizeof(mBFH.filesize));
--- a/modules/libpr0n/decoders/bmp/nsBMPDecoder.h
+++ b/modules/libpr0n/decoders/bmp/nsBMPDecoder.h
@@ -39,16 +39,17 @@
#ifndef _nsBMPDecoder_h
#define _nsBMPDecoder_h
#include "nsCOMPtr.h"
#include "imgIDecoder.h"
#include "imgIContainer.h"
#include "imgIDecoderObserver.h"
#include "gfxIImageFrame.h"
+#include "gfxColor.h"
#define NS_BMPDECODER_CID \
{ /* {78c61626-4d1f-4843-9364-4652d98ff6e1} */ \
0x78c61626, \
0x4d1f, \
0x4843, \
{ 0x93, 0x64, 0x46, 0x52, 0xd9, 0x8f, 0xf6, 0xe1 } \
}
@@ -164,26 +165,16 @@ private:
* @param aBuffer Data to process.
* @oaram count Number of bytes in mBuffer */
NS_METHOD ProcessData(const char* aBuffer, PRUint32 aCount);
/** Calculates the red-, green- and blueshift in mBitFields using
* the bitmasks from mBitFields */
NS_METHOD CalcBitShift();
- /** Sets the image data. mCurLine is used to get the row,
- * mDecoded is used to get the data */
- nsresult SetData();
-
- /** Sets the rle data. mCurLine is used to get the row,
- * mDecoded is used to get the data for the first row,
- * all subsequent rows are blank.
- * @param rows Number of rows of data to set */
- nsresult WriteRLERows(PRUint32 rows);
-
nsCOMPtr<imgIDecoderObserver> mObserver;
nsCOMPtr<imgIContainer> mImage;
nsCOMPtr<gfxIImageFrame> mFrame;
PRUint32 mPos;
BMPFILEHEADER mBFH;
@@ -192,56 +183,54 @@ private:
PRUint32 mLOH; ///< Length of the header
PRUint32 mNumColors; ///< The number of used colors, i.e. the number of entries in mColors
colorTable *mColors;
bitFields mBitFields;
+ PRUint32 *mImageData; ///< Pointer to the image data for the frame
PRUint8 *mRow; ///< Holds one raw line of the image
PRUint32 mRowBytes; ///< How many bytes of the row were already received
PRInt32 mCurLine; ///< Index of the line of the image that's currently being decoded
- PRUint8 *mAlpha; ///< Holds one line of unpacked alpha data
- PRUint8 *mAlphaPtr; ///< Pointer within unpacked alpha data
- PRUint8 *mDecoded; ///< Holds one line of color image data
- PRUint8 *mDecoding; ///< Pointer within image data
+ PRInt32 mOldLine; ///< Previous index of the line
+ PRInt32 mCurPos; ///< Index in the current line of the image
ERLEState mState; ///< Maintains the current state of the RLE decoding
PRUint32 mStateData;///< Decoding information that is needed depending on mState
- PRUint32 mBpr; ///< Cached image bytes per row
-
/** Set mBFH from the raw data in mRawBuf, converting from little-endian
* data to native data as necessary */
void ProcessFileHeader();
/** Set mBIH from the raw data in mRawBuf, converting from little-endian
* data to native data as necessary */
void ProcessInfoHeader();
};
/** Sets the pixel data in aDecoded to the given values.
- * The variable passed in as aDecoded will be moved on 3 or 4 bytes! */
-inline void SetPixel(PRUint8*& aDecoded, PRUint8 aRed, PRUint8 aGreen, PRUint8 aBlue, PRUint8 aAlpha = 0xFF)
+ * @param aDecoded pointer to pixel to be set, will be incremented to point to the next pixel.
+ */
+static inline void SetPixel(PRUint32*& aDecoded, PRUint8 aRed, PRUint8 aGreen, PRUint8 aBlue, PRUint8 aAlpha = 0xFF)
{
- *(PRUint32*)aDecoded = (aAlpha << 24) | (aRed << 16) | (aGreen << 8) | aBlue;
- aDecoded += 4;
+ *aDecoded++ = GFX_PACKED_PIXEL(aAlpha, aRed, aGreen, aBlue);
}
-inline void SetPixel(PRUint8*& aDecoded, PRUint8 idx, colorTable* aColors)
+static inline void SetPixel(PRUint32*& aDecoded, PRUint8 idx, colorTable* aColors)
{
SetPixel(aDecoded, aColors[idx].red, aColors[idx].green, aColors[idx].blue);
}
/** Sets two (or one if aCount = 1) pixels
- * @param aDecoded where the data is stored. Will be moved 3 or 6 bytes,
+ * @param aDecoded where the data is stored. Will be moved 4 resp 8 bytes
* depending on whether one or two pixels are written.
* @param aData The values for the two pixels
- * @param aCount Current count. Is decremented by one or two. */
-inline void Set4BitPixel(PRUint8*& aDecoded, PRUint8 aData,
+ * @param aCount Current count. Is decremented by one or two.
+ */
+inline void Set4BitPixel(PRUint32*& aDecoded, PRUint8 aData,
PRUint32& aCount, colorTable* aColors)
{
PRUint8 idx = aData >> 4;
SetPixel(aDecoded, idx, aColors);
if (--aCount > 0) {
idx = aData & 0xF;
SetPixel(aDecoded, idx, aColors);
--aCount;
--- a/modules/libpr0n/decoders/bmp/nsICODecoder.cpp
+++ b/modules/libpr0n/decoders/bmp/nsICODecoder.cpp
@@ -44,16 +44,19 @@
#include "nsICODecoder.h"
#include "nsIInputStream.h"
#include "nsIComponentManager.h"
#include "imgIContainerObserver.h"
#include "imgILoad.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsIImage.h"
#include "nsIProperties.h"
#include "nsISupportsPrimitives.h"
#include "nsAutoPtr.h"
NS_IMPL_ISUPPORTS1(nsICODecoder, imgIDecoder)
@@ -61,70 +64,30 @@ NS_IMPL_ISUPPORTS1(nsICODecoder, imgIDec
#define DIRENTRYOFFSET 6
#define BITMAPINFOSIZE 40
#define PREFICONSIZE 16
// ----------------------------------------
// Actual Data Processing
// ----------------------------------------
-static PRUint32 premultiply(PRUint32 x)
-{
- PRUint32 a = x >> 24;
- PRUint32 t = (x & 0xff00ff) * a + 0x800080;
- t = (t + ((t >> 8) & 0xff00ff)) >> 8;
- t &= 0xff00ff;
-
- x = ((x >> 8) & 0xff) * a + 0x80;
- x = (x + ((x >> 8) & 0xff));
- x &= 0xff00;
- x |= t | (a << 24);
- return x;
-}
-
-nsresult nsICODecoder::SetImageData()
-{
- if (mHaveAlphaData) {
- // We have premultiply the pixels when we have alpha transparency
- PRUint32* p = (PRUint32*)mDecodedBuffer;
- for (PRUint32 c = mDirEntry.mWidth * mDirEntry.mHeight; c > 0; --c) {
- *p = premultiply(*p);
- p++;
- }
- }
- // In Cairo we can set the whole image in one go
- PRUint32 dataLen = mDirEntry.mHeight * mDirEntry.mWidth * 4;
- mFrame->SetImageData(mDecodedBuffer, dataLen, 0);
-
- nsIntRect r(0, 0, 0, 0);
- mFrame->GetWidth(&r.width);
- mFrame->GetHeight(&r.height);
- mObserver->OnDataAvailable(nsnull, mFrame, &r);
-
- return NS_OK;
-}
-
PRUint32 nsICODecoder::CalcAlphaRowSize()
{
- PRUint32 rowSize = (mDirEntry.mWidth + 7) / 8; // +7 to round up
- if (rowSize % 4)
- rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
- return rowSize;
+ // 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
}
nsICODecoder::nsICODecoder()
{
mPos = mNumColors = mRowBytes = mImageOffset = mCurrIcon = mNumIcons = 0;
mCurLine = 1; // Otherwise decoder will never start
- mStatus = NS_OK;
mColors = nsnull;
mRow = nsnull;
- mHaveAlphaData = 0;
- mDecodingAndMask = PR_FALSE;
- mDecodedBuffer = nsnull;
+ mHaveAlphaData = mDecodingAndMask = PR_FALSE;
}
nsICODecoder::~nsICODecoder()
{
}
NS_IMETHODIMP nsICODecoder::Init(imgILoad *aLoad)
{
@@ -138,17 +101,26 @@ NS_IMETHODIMP nsICODecoder::Init(imgILoa
if (!mFrame)
return NS_ERROR_OUT_OF_MEMORY;
return aLoad->SetImage(mImage);
}
NS_IMETHODIMP nsICODecoder::Close()
{
+ // Tell the image that it's data has been updated
+ // This should be a mFrame function, so that we don't have to query for interface...
+ nsIntRect r(0, 0, mDirEntry.mWidth, mDirEntry.mHeight);
+ nsCOMPtr<nsIImage> img(do_GetInterface(mFrame));
+ if (img)
+ img->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r);
+
if (mObserver) {
+ mObserver->OnDataAvailable(nsnull, mFrame, &r);
+ mObserver->OnStopFrame(nsnull, mFrame);
mObserver->OnStopContainer(nsnull, mImage);
mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
mObserver = nsnull;
}
mImage = nsnull;
mFrame = nsnull;
@@ -158,51 +130,42 @@ NS_IMETHODIMP nsICODecoder::Close()
mColors = nsnull;
mCurLine = 0;
mRowBytes = 0;
mImageOffset = 0;
mCurrIcon = 0;
mNumIcons = 0;
- free(mRow);
- mRow = nsnull;
-
+ if (mRow) {
+ free(mRow);
+ mRow = nsnull;
+ }
mDecodingAndMask = PR_FALSE;
- free(mDecodedBuffer);
return NS_OK;
}
NS_IMETHODIMP nsICODecoder::Flush()
{
- // Set Data here because some ICOs don't have a complete AND Mask
- // see bug 115357
- if (mDecodingAndMask) {
- SetImageData();
- mObserver->OnStopFrame(nsnull, mFrame);
- }
return NS_OK;
}
NS_METHOD nsICODecoder::ReadSegCb(nsIInputStream* aIn, void* aClosure,
const char* aFromRawSegment, PRUint32 aToOffset,
PRUint32 aCount, PRUint32 *aWriteCount) {
nsICODecoder *decoder = reinterpret_cast<nsICODecoder*>(aClosure);
*aWriteCount = aCount;
- decoder->mStatus = decoder->ProcessData(aFromRawSegment, aCount);
- return decoder->mStatus;
+ return decoder->ProcessData(aFromRawSegment, aCount);
}
NS_IMETHODIMP nsICODecoder::WriteFrom(nsIInputStream *aInStr, PRUint32 aCount, PRUint32 *aRetval)
{
- nsresult rv = aInStr->ReadSegments(ReadSegCb, this, aCount, aRetval);
- NS_ENSURE_SUCCESS(rv, rv);
- return mStatus;
+ return aInStr->ReadSegments(ReadSegCb, this, aCount, aRetval);
}
nsresult nsICODecoder::ProcessData(const char* aBuffer, PRUint32 aCount) {
if (!aCount) // aCount=0 means EOF
return NS_OK;
while (aCount && (mPos < ICONCOUNTOFFSET)) { // Skip to the # of icons.
if (mPos == 2) { // if the third byte is 1: This is an icon, 2: a cursor
@@ -332,16 +295,19 @@ nsresult nsICODecoder::ProcessData(const
return NS_ERROR_OUT_OF_MEMORY;
rv = mFrame->Init(0, 0, mDirEntry.mWidth, mDirEntry.mHeight, GFXFORMATALPHA8, 24);
NS_ENSURE_SUCCESS(rv, rv);
rv = mImage->AppendFrame(mFrame);
NS_ENSURE_SUCCESS(rv, rv);
mObserver->OnStartFrame(nsnull, mFrame);
NS_ENSURE_SUCCESS(rv, rv);
+
+ PRUint32 imageLength;
+ mFrame->GetImageData((PRUint8**)&mImageData, &imageLength);
}
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;
@@ -364,26 +330,23 @@ nsresult nsICODecoder::ProcessData(const
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++;
- mDecodedBuffer = (PRUint8*)malloc(mDirEntry.mHeight*mDirEntry.mWidth*4);
- if (!mDecodedBuffer)
- return NS_ERROR_OUT_OF_MEMORY;
}
// Ensure memory has been allocated before decoding. If we get this far
// without allocated memory, the file is most likely invalid.
NS_ASSERTION(mRow, "mRow is null");
- NS_ASSERTION(mDecodedBuffer, "mDecodedBuffer is null");
- if (!mRow || !mDecodedBuffer)
+ NS_ASSERTION(mImageData, "mImageData is null");
+ if (!mRow || !mImageData)
return NS_ERROR_FAILURE;
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;
@@ -392,17 +355,17 @@ nsresult nsICODecoder::ProcessData(const
toCopy = aCount;
memcpy(mRow + mRowBytes, aBuffer, toCopy);
aCount -= toCopy;
aBuffer += toCopy;
mRowBytes += toCopy;
}
if (rowSize == mRowBytes) {
mCurLine--;
- PRUint8* d = mDecodedBuffer + (mCurLine * mDirEntry.mWidth * GFXBYTESPERPIXEL);
+ 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--) {
@@ -440,19 +403,28 @@ nsresult nsICODecoder::ProcessData(const
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) {
- SetPixel(d, p[2], p[1], p[0], p[3]);
- mHaveAlphaData |= p[3]; // Alpha value
+ 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...
return NS_ERROR_FAILURE;
}
@@ -468,66 +440,52 @@ nsresult nsICODecoder::ProcessData(const
if (mDecodingAndMask && !mHaveAlphaData) {
PRUint32 rowSize = CalcAlphaRowSize();
if (mPos == (1 + mImageOffset + BITMAPINFOSIZE + mNumColors*4)) {
mPos++;
mRowBytes = 0;
mCurLine = mDirEntry.mHeight;
- free(mRow);
- mRow = (PRUint8*)malloc(rowSize);
+ mRow = (PRUint8*)realloc(mRow, rowSize);
if (!mRow)
return NS_ERROR_OUT_OF_MEMORY;
}
// Ensure memory has been allocated before decoding.
NS_ASSERTION(mRow, "mRow is null");
- NS_ASSERTION(mDecodedBuffer, "mDecodedBuffer is null");
- if (!mRow || !mDecodedBuffer)
+ NS_ASSERTION(mImageData, "mImageData is null");
+ if (!mRow || !mImageData)
return NS_ERROR_FAILURE;
- PRUint32 toCopy;
- do {
- if (mCurLine == 0) {
- return NS_OK;
- }
-
- toCopy = rowSize - mRowBytes;
- if (toCopy) {
- if (toCopy > aCount)
- toCopy = aCount;
- memcpy(mRow + mRowBytes, aBuffer, toCopy);
- aCount -= toCopy;
- aBuffer += toCopy;
- mRowBytes += toCopy;
- }
- if ((rowSize - mRowBytes) == 0) {
- mCurLine--;
+ while (mCurLine > 0 && aCount > 0) {
+ PRUint32 toCopy = PR_MIN(rowSize - mRowBytes, aCount);
+ if (toCopy) {
+ memcpy(mRow + mRowBytes, aBuffer, toCopy);
+ aCount -= toCopy;
+ aBuffer += toCopy;
+ mRowBytes += toCopy;
+ }
+ if (rowSize == mRowBytes) {
+ mCurLine--;
+ mRowBytes = 0;
- PRUint8* decoded =
- mDecodedBuffer + (mCurLine * mDirEntry.mWidth * GFXBYTESPERPIXEL);
-#ifdef IS_LITTLE_ENDIAN
- decoded += 3;
-#endif
- PRUint8* decoded_end =
- decoded + mDirEntry.mWidth * GFXBYTESPERPIXEL;
- for (PRUint8* p = mRow, *p_end = mRow + rowSize; p < p_end; ++p) {
- PRUint8 idx = *p;
- for (PRUint8 bit = 0x80; bit && decoded<decoded_end; bit >>= 1) {
- // We complement the value, since our method of storing
- // transparency is opposite what Win32 uses in its masks.
- *decoded = (idx & bit) ? 0x00 : 0xff;
- decoded += GFXBYTESPERPIXEL;
- }
- }
-
- 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 ++;
+ }
}
- } while (aCount > 0);
+ }
+ }
}
return NS_OK;
}
void
nsICODecoder::ProcessDirEntry(IconDirEntry& aTarget)
{
--- a/modules/libpr0n/decoders/bmp/nsICODecoder.h
+++ b/modules/libpr0n/decoders/bmp/nsICODecoder.h
@@ -118,19 +118,17 @@ private:
PRUint32 mNumColors;
colorTable* mColors;
PRUint8* mRow; // Holds one raw line of the image
PRUint32 mRowBytes; // How many bytes of the row were already received
PRInt32 mCurLine;
- nsresult mStatus;
+ PRUint32* mImageData;
- PRUint8* mDecodedBuffer;
-
- PRUint8 mHaveAlphaData;
+ PRPackedBool mHaveAlphaData;
PRPackedBool mIsCursor;
PRPackedBool mDecodingAndMask;
};
#endif