b=391583, DoesARGBImageDataHaveAlpha is slow, r=stuart,a=me
authorvladimir@pobox.com
Fri, 17 Aug 2007 12:54:58 -0700
changeset 4753 2e3e92e4ab6f49bbfe3963090c560580101c61cd
parent 4752 7771b50b8b8e5face3e2f48fe771af9a42855191
child 4754 ebead0992db48c852e30ff15225879832ecb44d5
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersstuart, me
bugs391583
milestone1.9a8pre
b=391583, DoesARGBImageDataHaveAlpha is slow, r=stuart,a=me
gfx/public/nsIImage.h
gfx/src/shared/gfxImageFrame.cpp
gfx/src/thebes/nsThebesImage.cpp
gfx/src/thebes/nsThebesImage.h
gfx/thebes/public/gfxPlatform.h
gfx/thebes/src/gfxPlatform.cpp
gfx/thebes/src/gfxWindowsSurface.cpp
modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp
modules/libpr0n/decoders/gif/nsGIFDecoder2.h
modules/libpr0n/decoders/png/nsPNGDecoder.cpp
modules/libpr0n/decoders/png/nsPNGDecoder.h
modules/libpr0n/decoders/xbm/Makefile.in
modules/libpr0n/decoders/xbm/nsXBMDecoder.cpp
modules/libpr0n/decoders/xbm/nsXBMDecoder.h
--- a/gfx/public/nsIImage.h
+++ b/gfx/public/nsIImage.h
@@ -253,16 +253,29 @@ public:
    *
    * aMaskPixels = PR_TRUE for the mask, PR_FALSE for the image
    *
    * @update - sfraser 10/18/99
    * @return error result
    */
   NS_IMETHOD UnlockImagePixels(PRBool aMaskPixels) = 0;
 
-#ifdef MOZ_CAIRO_GFX
+  /**
+   * GetSurface
+   * Return the Thebes gfxASurface in aSurface.
+   *
+   * aSurface will be AddRef'd (as with most getters), so
+   * getter_AddRefs should be used.
+   */
   NS_IMETHOD GetSurface(gfxASurface **aSurface) = 0;
-#endif
+
+  /**
+   * SetHasNoAlpha
+   *
+   * Hint to the image that all the pixels are fully opaque, even if
+   * the original format requested a 1-bit or 8-bit alpha mask
+   */
+  virtual void SetHasNoAlpha() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIImage, NS_IIMAGE_IID)
 
 #endif
--- a/gfx/src/shared/gfxImageFrame.cpp
+++ b/gfx/src/shared/gfxImageFrame.cpp
@@ -546,9 +546,8 @@ NS_IMETHODIMP gfxImageFrame::GetInterfac
 
   if (NS_SUCCEEDED(QueryInterface(aIID, result)))
     return NS_OK;
   if (mImage && aIID.Equals(NS_GET_IID(nsIImage)))
     return mImage->QueryInterface(aIID, result);
 
   return NS_NOINTERFACE;
 }
- 
--- a/gfx/src/thebes/nsThebesImage.cpp
+++ b/gfx/src/thebes/nsThebesImage.cpp
@@ -601,8 +601,21 @@ nsThebesImage::ShouldUseImageSurfaces()
         // or we hit our high water mark; disable
         // image allocations for a bit.
         return PR_TRUE;
     }
 #endif
 
     return PR_FALSE;
 }
+
+// A hint from the image decoders that this image has no alpha, even
+// though we created is ARGB32.  This changes our format to RGB24,
+// which in turn will cause us to Optimize() to RGB24.  Has no effect
+// after Optimize() is called, though in all cases it will be just a
+// performance win -- the pixels are still correct and have the A byte
+// set to 0xff.
+void
+nsThebesImage::SetHasNoAlpha()
+{
+    if (mFormat == gfxASurface::ImageFormatARGB32)
+        mFormat = gfxASurface::ImageFormatRGB24;
+}
--- a/gfx/src/thebes/nsThebesImage.h
+++ b/gfx/src/thebes/nsThebesImage.h
@@ -98,16 +98,18 @@ public:
 
     gfxASurface* ThebesSurface() {
         if (mOptSurface)
             return mOptSurface;
 
         return mImageSurface;
     }
 
+    void SetHasNoAlpha();
+
 protected:
     static PRBool AllowedImageSize(PRInt32 aWidth, PRInt32 aHeight) {
         NS_ASSERTION(aWidth > 0, "invalid image width");
         NS_ASSERTION(aHeight > 0, "invalid image height");
 
         // reject over-wide or over-tall images
         const PRInt32 k64KLimit = 0x0000FFFF;
         if (NS_UNLIKELY(aWidth > k64KLimit || aHeight > k64KLimit )) {
--- a/gfx/thebes/public/gfxPlatform.h
+++ b/gfx/thebes/public/gfxPlatform.h
@@ -129,22 +129,16 @@ public:
                                      PRBool& aAborted) = 0;
 
     /**
      * Create the appropriate platform font group
      */
     virtual gfxFontGroup *CreateFontGroup(const nsAString& aFamilies,
                                           const gfxFontStyle *aStyle) = 0;
 
-    /* Returns PR_TRUE if the given block of ARGB32 data really has alpha, otherwise PR_FALSE */
-    static PRBool DoesARGBImageDataHaveAlpha(PRUint8* data,
-                                             PRUint32 width,
-                                             PRUint32 height,
-                                             PRUint32 stride);
-
     void GetPrefFonts(const char *aLangGroup, nsString& array, PRBool aAppendUnicode = PR_TRUE);
 
     /**
      * Are we going to try color management?
      */
     static PRBool IsCMSEnabled();
 
     /**
--- a/gfx/thebes/src/gfxPlatform.cpp
+++ b/gfx/thebes/src/gfxPlatform.cpp
@@ -176,54 +176,23 @@ gfxPlatform::UseGlitz()
 }
 
 void
 gfxPlatform::SetUseGlitz(PRBool use)
 {
     gGlitzState = (use ? 1 : 0);
 }
 
-PRBool
-gfxPlatform::DoesARGBImageDataHaveAlpha(PRUint8* data,
-                                        PRUint32 width,
-                                        PRUint32 height,
-                                        PRUint32 stride)
-{
-    PRUint32 *r;
-
-    for (PRUint32 j = 0; j < height; j++) {
-        r = (PRUint32*) (data + stride*j);
-        for (PRUint32 i = 0; i < width; i++) {
-            if ((*r++ & 0xff000000) != 0xff000000) {
-                return PR_TRUE;
-            }
-        }
-    }
-
-    return PR_FALSE;    
-}
-
 already_AddRefed<gfxASurface>
 gfxPlatform::OptimizeImage(gfxImageSurface *aSurface)
 {
     const gfxIntSize& surfaceSize = aSurface->GetSize();
 
     gfxASurface::gfxImageFormat realFormat = aSurface->Format();
 
-    if (realFormat == gfxASurface::ImageFormatARGB32) {
-        // this might not really need alpha; figure that out
-        if (!DoesARGBImageDataHaveAlpha(aSurface->Data(),
-                                        surfaceSize.width,
-                                        surfaceSize.height,
-                                        aSurface->Stride()))
-        {
-            realFormat = gfxASurface::ImageFormatRGB24;
-        }
-    }
-
     nsRefPtr<gfxASurface> optSurface = CreateOffscreenSurface(surfaceSize, realFormat);
 
     if (!optSurface)
         return nsnull;
 
     nsRefPtr<gfxContext> tmpCtx(new gfxContext(optSurface));
     tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
     tmpCtx->SetSource(aSurface);
--- a/gfx/thebes/src/gfxWindowsSurface.cpp
+++ b/gfx/thebes/src/gfxWindowsSurface.cpp
@@ -114,26 +114,16 @@ gfxWindowsSurface::GetImageSurface()
     NS_ADDREF(imgsurf);
     return imgsurf;
 }
 
 already_AddRefed<gfxWindowsSurface>
 gfxWindowsSurface::OptimizeToDDB(HDC dc, const gfxIntSize& size, gfxImageFormat format)
 {
     gfxImageFormat realFormat = format;
-    if (realFormat == ImageFormatARGB32) {
-        cairo_surface_t *isurf = cairo_win32_surface_get_image(CairoSurface());
-        if (isurf && !gfxPlatform::DoesARGBImageDataHaveAlpha(cairo_image_surface_get_data(isurf),
-                                                              cairo_image_surface_get_width(isurf),
-                                                              cairo_image_surface_get_height(isurf),
-                                                              cairo_image_surface_get_stride(isurf)))
-        {
-            realFormat = ImageFormatRGB24;
-        }
-    }
 
     if (realFormat != ImageFormatRGB24)
         return nsnull;
 
     nsRefPtr<gfxWindowsSurface> wsurf = new gfxWindowsSurface(dc, size, realFormat);
 
     nsRefPtr<gfxContext> tmpCtx(new gfxContext(wsurf));
     tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
--- a/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp
+++ b/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp
@@ -72,16 +72,19 @@ mailing address.
 */
 
 #include <stddef.h>
 #include "prtypes.h"
 #include "prmem.h"
 #include "prlog.h"
 #include "GIF2.h"
 
+#include "nsIImage.h"
+#include "nsIInterfaceRequestorUtils.h"
+
 #include "nsGIFDecoder2.h"
 #include "nsIInputStream.h"
 #include "nsIComponentManager.h"
 #include "imgIContainerObserver.h"
 
 #include "imgILoad.h"
 
 #include "imgContainer.h"
@@ -315,16 +318,17 @@ void nsGIFDecoder2::EndGIF()
 
   mGIFOpen = PR_FALSE;
 }
 
 //******************************************************************************
 void nsGIFDecoder2::BeginImageFrame()
 {
   mImageFrame = nsnull; // clear out our current frame reference
+  mFrameHasNoAlpha = PR_TRUE;
 
   if (!mGIFStruct.images_decoded) {
     // Send a onetime OnDataAvailable (Display Refresh) for the first frame
     // if it has a y-axis offset.  Otherwise, the area may never be refreshed
     // and the placeholder will remain on the screen. (Bug 37589)
     if (mGIFStruct.y_offset > 0) {
       PRInt32 imgWidth;
       mImageContainer->GetWidth(&imgWidth);
@@ -345,16 +349,21 @@ void nsGIFDecoder2::EndImageFrame()
   if (!mImageFrame) {
     HaveDecodedRow(nsnull,0,0,0);
   } else {
     // We actually have the timeout information before we get the lzw encoded 
     // image data, at least according to the spec, but we delay in setting the 
     // timeout for the image until here to help ensure that we have the whole 
     // image frame decoded before we go off and try to display another frame.
     mImageFrame->SetTimeout(mGIFStruct.delay_time);
+
+    if (mFrameHasNoAlpha) {
+      nsCOMPtr<nsIImage> img(do_GetInterface(mImageFrame));
+      img->SetHasNoAlpha();
+    }
   }
   mImageContainer->EndFrameDecode(mGIFStruct.images_decoded, mGIFStruct.delay_time);
 
   if (mObserver && mImageFrame) {
     FlushImageData();
 
     if (mGIFStruct.images_decoded == 1) {
       // If the first frame is smaller in height than the entire image, send a
@@ -437,36 +446,40 @@ void nsGIFDecoder2::HaveDecodedRow(
     }
 
     if (!cmap) { // cmap could have null value if the global color table flag is 0
       nsIntRect r(0, aRowNumber, mGIFStruct.width, aDuplicateCount);
       imgContainer::ClearFrame(mImageFrame, r);
     } else {
       PRUint8* rowBufIndex = aRowBufPtr;
       PRUint32* rgbRowIndex = (PRUint32*)mRGBLine;
+      PRBool rowHasNoAlpha = PR_TRUE;
 
       const PRInt32 tpixel = 
         mGIFStruct.is_transparent ? mGIFStruct.tpixel : -1;
 
       while (rowBufIndex != mGIFStruct.rowend) {
         if (*rowBufIndex >= cmapsize || *rowBufIndex == tpixel) {
+          rowHasNoAlpha = PR_FALSE;
           *rgbRowIndex++ = 0x00000000;
           ++rowBufIndex;
           continue;
         }
 
         PRUint32 colorIndex = *rowBufIndex * 3;
         *rgbRowIndex++ = (0xFF << 24) |
           (cmap[colorIndex] << 16) |
           (cmap[colorIndex+1] << 8) |
           (cmap[colorIndex+2]);
         ++rowBufIndex;
       }
       for (int i=0; i<aDuplicateCount; i++)
         mImageFrame->SetImageData(mRGBLine, bpr, (aRowNumber+i)*bpr);
+      if (!rowHasNoAlpha)
+        mFrameHasNoAlpha = PR_FALSE;
     }
 
     mCurrentRow = aRowNumber + aDuplicateCount - 1;
     mCurrentPass = aInterlacePass;
     if (aInterlacePass == 1)
       mLastFlushedPass = aInterlacePass;   // interlaced starts at 1
   }
 }
--- a/modules/libpr0n/decoders/gif/nsGIFDecoder2.h
+++ b/modules/libpr0n/decoders/gif/nsGIFDecoder2.h
@@ -97,13 +97,14 @@ private:
   PRInt32 mCurrentRow;
   PRInt32 mLastFlushedRow;
 
   PRUint8 *mRGBLine;
   PRUint32 mRGBLineMaxSize;
   PRUint8 mCurrentPass;
   PRUint8 mLastFlushedPass;
   PRPackedBool mGIFOpen;
+  PRPackedBool mFrameHasNoAlpha;
 
   gif_struct mGIFStruct;
 };
 
 #endif
--- a/modules/libpr0n/decoders/png/nsPNGDecoder.cpp
+++ b/modules/libpr0n/decoders/png/nsPNGDecoder.cpp
@@ -114,16 +114,18 @@ void nsPNGDecoder::CreateFrame(png_uint_
 
   if (png_get_valid(mPNG, mInfo, PNG_INFO_acTL))
     SetAnimFrameInfo();
   
   mImage->AppendFrame(mFrame);
   
   if (mObserver)
     mObserver->OnStartFrame(nsnull, mFrame);
+
+  mFrameHasNoAlpha = PR_TRUE;
 }
 
 // set timeout and frame disposal method for the current frame
 void nsPNGDecoder::SetAnimFrameInfo()
 {
   png_uint_16 delay_num, delay_den; /* in seconds */
   png_byte dispose_op;
   PRInt32 timeout; /* in milliseconds */
@@ -643,16 +645,17 @@ row_callback(png_structp png_ptr, png_by
     gfx_format format;
     decoder->mFrame->GetFormat(&format);
 
     // we're thebes. we can write stuff directly to the data
     PRUint8 *imageData;
     PRUint32 imageDataLength, bpr = width * sizeof(PRUint32);
     decoder->mFrame->GetImageData(&imageData, &imageDataLength);
     PRUint32 *cptr32 = (PRUint32*)(imageData + (row_num*bpr));
+    PRBool rowHasNoAlpha = PR_TRUE;
 
     if (decoder->mTransform) {
       if (decoder->mCMSLine) {
         cmsDoTransform(decoder->mTransform, line, decoder->mCMSLine, iwidth);
         /* copy alpha over */
         PRUint32 channels = decoder->mChannels;
         if (channels == 2 || channels == 4) {
           for (PRUint32 i = 0; i < iwidth; i++)
@@ -674,31 +677,38 @@ row_callback(png_structp png_ptr, png_by
         }
       }
       break;
     case gfxIFormats::RGB_A1:
     case gfxIFormats::BGR_A1:
       {
         for (PRUint32 x=iwidth; x>0; --x) {
           *cptr32++ = GFX_PACKED_PIXEL(line[3]?0xFF:0x00, line[0], line[1], line[2]);
+          if (line[3] == 0)
+            rowHasNoAlpha = PR_FALSE;
           line += 4;
         }
       }
       break;
     case gfxIFormats::RGB_A8:
     case gfxIFormats::BGR_A8:
       {
         for (PRUint32 x=width; x>0; --x) {
           *cptr32++ = GFX_PACKED_PIXEL(line[3], line[0], line[1], line[2]);
+          if (line[3] != 0xff)
+            rowHasNoAlpha = PR_FALSE;
           line += 4;
         }
       }
       break;
     }
 
+    if (!rowHasNoAlpha)
+      decoder->mFrameHasNoAlpha = PR_FALSE;
+
     nsIntRect r(0, row_num, width, 1);
     nsCOMPtr<nsIImage> img(do_GetInterface(decoder->mFrame));
     img->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r);
     decoder->mObserver->OnDataAvailable(nsnull, decoder->mFrame, &r);
   }
 }
 
 // got the header of a new frame that's coming
@@ -709,16 +719,20 @@ frame_info_callback(png_structp png_ptr,
   PRInt32 width, height;
   
   nsPNGDecoder *decoder = static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
   
   // old frame is done
   if (!(decoder->apngFlags & FRAME_HIDDEN)) {
     PRInt32 timeout;
     decoder->mFrame->GetTimeout(&timeout);
+    if (decoder->mFrameHasNoAlpha) {
+      nsCOMPtr<nsIImage> img(do_GetInterface(decoder->mFrame));
+      img->SetHasNoAlpha();
+    }
     decoder->mImage->EndFrameDecode(frame_num, timeout);
     decoder->mObserver->OnStopFrame(nsnull, decoder->mFrame);
   }
   
   decoder->apngFlags &= ~FRAME_HIDDEN;
   
   x_offset = png_get_next_frame_x_offset(png_ptr, decoder->mInfo);
   y_offset = png_get_next_frame_y_offset(png_ptr, decoder->mInfo);
@@ -748,16 +762,20 @@ end_callback(png_structp png_ptr, png_in
   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL)) {
     PRInt32 num_plays = png_get_num_plays(png_ptr, info_ptr);
     decoder->mImage->SetLoopCount(num_plays - 1);
   }
   
   if (!(decoder->apngFlags & FRAME_HIDDEN)) {
     PRInt32 timeout;
     decoder->mFrame->GetTimeout(&timeout);
+    if (decoder->mFrameHasNoAlpha) {
+      nsCOMPtr<nsIImage> img(do_GetInterface(decoder->mFrame));
+      img->SetHasNoAlpha();
+    }
     decoder->mImage->EndFrameDecode(decoder->mPNG->num_frames_read, timeout);
   }
   
   decoder->mImage->DecodingComplete();
   
   if (decoder->mObserver) {
     if (!(decoder->apngFlags & FRAME_HIDDEN))
       decoder->mObserver->OnStopFrame(nsnull, decoder->mFrame);
--- a/modules/libpr0n/decoders/png/nsPNGDecoder.h
+++ b/modules/libpr0n/decoders/png/nsPNGDecoder.h
@@ -88,11 +88,12 @@ public:
   cmsHPROFILE mInProfile;
   cmsHTRANSFORM mTransform;
 
   PRUint32 ibpr;
   gfx_format format;
   PRUint8 apngFlags;
   PRUint8 mChannels;
   PRPackedBool mError;
+  PRPackedBool mFrameHasNoAlpha;
 };
 
 #endif // nsPNGDecoder_h__
--- a/modules/libpr0n/decoders/xbm/Makefile.in
+++ b/modules/libpr0n/decoders/xbm/Makefile.in
@@ -47,13 +47,14 @@ MODULE          = imgxbm
 LIBRARY_NAME    = imgxbm_s
 FORCE_STATIC_LIB = 1
 MODULE_NAME     = nsXBMModule
 LIBXUL_LIBRARY  = 1
 
 REQUIRES	= xpcom \
 		  gfx \
 		  imglib2 \
+		  thebes \
 		  $(NULL)
 
 CPPSRCS        = nsXBMDecoder.cpp
 
 include $(topsrcdir)/config/rules.mk
--- a/modules/libpr0n/decoders/xbm/nsXBMDecoder.cpp
+++ b/modules/libpr0n/decoders/xbm/nsXBMDecoder.cpp
@@ -42,29 +42,24 @@
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>
 
 #include "nsXBMDecoder.h"
 
 #include "nsIInputStream.h"
 #include "nsIComponentManager.h"
+#include "nsIImage.h"
+#include "nsIInterfaceRequestorUtils.h"
 
 #include "imgILoad.h"
 
 #include "nsIProperties.h"
 #include "nsISupportsPrimitives.h"
 
-#if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
-#define GFXFORMAT gfxIFormats::BGR_A1
-#else
-#define USE_RGB
-#define GFXFORMAT gfxIFormats::RGB_A1
-#endif
-
 NS_IMPL_ISUPPORTS1(nsXBMDecoder, imgIDecoder)
 
 nsXBMDecoder::nsXBMDecoder() : mBuf(nsnull), mPos(nsnull), mAlphaRow(nsnull)
 {
 }
 
 nsXBMDecoder::~nsXBMDecoder()
 {
@@ -87,22 +82,28 @@ NS_IMETHODIMP nsXBMDecoder::Init(imgILoa
     mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2", &rv);
     if (NS_FAILED(rv))
         return rv;
 
     aLoad->SetImage(mImage);
 
     mCurRow = mBufSize = mWidth = mHeight = 0;
     mState = RECV_HEADER;
+    mHasNoAlpha = PR_TRUE;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP nsXBMDecoder::Close()
 {
+    if (mHasNoAlpha) {
+        nsCOMPtr<nsIImage> img(do_GetInterface(mFrame));
+        img->SetHasNoAlpha();
+    }
+
     mObserver->OnStopContainer(nsnull, mImage);
     mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
     mObserver = nsnull;
     mImage = nsnull;
     mFrame = nsnull;
 
     if (mAlphaRow) {
         free(mAlphaRow);
@@ -180,17 +181,17 @@ nsresult nsXBMDecoder::ProcessData(const
             mIsX10 = PR_TRUE;
         else
             // Neither identifier found.  Return for now, waiting for more data.
             return NS_OK;
 
         mImage->Init(mWidth, mHeight, mObserver);
         mObserver->OnStartContainer(nsnull, mImage);
 
-        nsresult rv = mFrame->Init(0, 0, mWidth, mHeight, GFXFORMAT, 24);
+        nsresult rv = mFrame->Init(0, 0, mWidth, mHeight, gfxIFormats::RGB_A1, 24);
         if (NS_FAILED(rv))
             return rv;
 
         if (mIsCursor) {
             nsCOMPtr<nsIProperties> props(do_QueryInterface(mImage));
             if (props) {
                 nsCOMPtr<nsISupportsPRUint32> intwrapx = do_CreateInstance("@mozilla.org/supports-PRUint32;1");
                 nsCOMPtr<nsISupportsPRUint32> intwrapy = do_CreateInstance("@mozilla.org/supports-PRUint32;1");
@@ -235,16 +236,17 @@ nsresult nsXBMDecoder::ProcessData(const
         }
     }
     if (mState == RECV_DATA) {
         PRUint32 bpr;
         mFrame->GetImageBytesPerRow(&bpr);
         PRUint32 abpr;
         mFrame->GetAlphaBytesPerRow(&abpr);
         PRBool hiByte = PR_TRUE;
+        PRBool chunkHasNoAlpha = PR_TRUE;
 
         do {
             PRUint32 pixel = strtoul(mPos, &endPtr, 0);
             if (endPtr == mPos)
                 return NS_OK;   // no number to be found - need more data
             if (!*endPtr)
                 return NS_OK;   // number at the end - might be missing a digit
             if (pixel == 0 && *endPtr == 'x')
@@ -268,16 +270,18 @@ nsresult nsXBMDecoder::ProcessData(const
                 hiByte = !hiByte;
             }
 
             PRUint32 *ar = ((PRUint32*)mAlphaRow) + mCurCol;
             const int alphas = PR_MIN(8, mWidth - mCurCol);
             for (int i = 0; i < alphas; i++) {
                 const PRUint8 val = ((pixel & (1 << i)) >> i) ? 255 : 0;
                 *ar++ = (val << 24) | 0;
+                if (val == 0)
+                    chunkHasNoAlpha = PR_FALSE;
             }
 
             mCurCol = PR_MIN(mCurCol + 8, mWidth);
             if (mCurCol == mWidth || mState == RECV_DONE) {
                 mFrame->SetImageData(mAlphaRow, abpr, mCurRow * abpr);
 
                 nsIntRect r(0, mCurRow, mWidth, 1);
                 mObserver->OnDataAvailable(nsnull, mFrame, &r);
@@ -292,14 +296,17 @@ nsresult nsXBMDecoder::ProcessData(const
 
             // Skip the comma
             NS_ASSERTION(mState != RECV_DATA || *mPos == ',' ||
                          (mIsX10 && hiByte),
                          "Must be a comma");
             if (*mPos == ',')
                 mPos++;
         } while ((mState == RECV_DATA) && *mPos);
+
+        if (!chunkHasNoAlpha)
+            mHasNoAlpha = PR_FALSE;
     }
 
     return NS_OK;
 }
 
 
--- a/modules/libpr0n/decoders/xbm/nsXBMDecoder.h
+++ b/modules/libpr0n/decoders/xbm/nsXBMDecoder.h
@@ -85,16 +85,17 @@ private:
     PRUint32 mHeight;
     PRUint32 mXHotspot;
     PRUint32 mYHotspot;
 
     PRUint8* mAlphaRow; // alpha data for the row
 
     PRPackedBool mIsCursor;
     PRPackedBool mIsX10; // X10 flavor XBM?
+    PRPackedBool mHasNoAlpha;
 
     enum {
         RECV_HEADER,
         RECV_SEEK,
         RECV_DATA,
         RECV_DONE
     } mState;
 };