Backing out bug 296818 to see if it fixes the Tp regression
authordtownsend@oxymoronical.com
Tue, 16 Oct 2007 08:45:31 -0700
changeset 6990 12910a9796941fe1f282d1644f5cbdc80d9fe5d5
parent 6989 845f4ac941bae9c2af1904689eccacbf1f838b61
child 6991 bd21f9038cb2127484bdbf92f695edaec3e593d7
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
bugs296818
milestone1.9a9pre
Backing out bug 296818 to see if it fixes the Tp regression
modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp
modules/libpr0n/decoders/jpeg/nsJPEGDecoder.h
modules/libpr0n/decoders/png/nsPNGDecoder.cpp
modules/libpr0n/public/imgIContainer.idl
modules/libpr0n/src/imgContainer.cpp
modules/libpr0n/src/imgContainer.h
--- a/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp
+++ b/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp
@@ -17,17 +17,16 @@
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 2001
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Stuart Parmenter <stuart@mozilla.com>
- *   Federico Mena-Quintero <federico@novell.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -59,20 +58,18 @@
 extern "C" {
 #include "iccjpeg.h"
 }
 
 NS_IMPL_ISUPPORTS1(nsJPEGDecoder, imgIDecoder)
 
 #if defined(PR_LOGGING)
 PRLogModuleInfo *gJPEGlog = PR_NewLogModule("JPEGDecoder");
-static PRLogModuleInfo *gJPEGDecoderAccountingLog = PR_NewLogModule("JPEGDecoderAccounting");
 #else
 #define gJPEGlog
-#define gJPEGDecoderAccountingLog
 #endif
 
 
 METHODDEF(void) init_source (j_decompress_ptr jd);
 METHODDEF(boolean) fill_input_buffer (j_decompress_ptr jd);
 METHODDEF(void) skip_input_data (j_decompress_ptr jd, long num_bytes);
 METHODDEF(void) term_source (j_decompress_ptr jd);
 METHODDEF(void) my_error_exit (j_common_ptr cinfo);
@@ -94,34 +91,26 @@ nsJPEGDecoder::nsJPEGDecoder()
   mBuffer = nsnull;
   mBufferLen = mBufferSize = 0;
 
   mBackBuffer = nsnull;
   mBackBufferLen = mBackBufferSize = mBackBufferUnreadLen = 0;
 
   mInProfile = nsnull;
   mTransform = nsnull;
-
-  PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-         ("nsJPEGDecoder::nsJPEGDecoder: Creating JPEG decoder %p",
-          this));
 }
 
 nsJPEGDecoder::~nsJPEGDecoder()
 {
   PR_FREEIF(mBuffer);
   PR_FREEIF(mBackBuffer);
   if (mTransform)
     cmsDeleteTransform(mTransform);
   if (mInProfile)
     cmsCloseProfile(mInProfile);
-
-  PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-         ("nsJPEGDecoder::~nsJPEGDecoder: Destroying JPEG decoder %p",
-          this));
 }
 
 
 /** imgIDecoder methods **/
 
 /* void init (in imgILoad aLoad); */
 NS_IMETHODIMP nsJPEGDecoder::Init(imgILoad *aLoad)
 {
@@ -153,44 +142,16 @@ NS_IMETHODIMP nsJPEGDecoder::Init(imgILo
   mSourceMgr.skip_input_data = skip_input_data;
   mSourceMgr.resync_to_restart = jpeg_resync_to_restart;
   mSourceMgr.term_source = term_source;
 
   /* Record app markers for ICC data */
   for (PRUint32 m = 0; m < 16; m++)
     jpeg_save_markers(&mInfo, JPEG_APP0 + m, 0xFFFF);
 
-
-
-  /* Check if the request already has an image container.
-   * this is the case when multipart/x-mixed-replace is being downloaded
-   * if we already have one and it has the same width and height, reuse it.
-   * This is also the case when an existing container is reloading itself from
-   * us.
-   *
-   * If we have a mismatch in width/height for the container later on we will
-   * generate an error.
-   */
-  mImageLoad->GetImage(getter_AddRefs(mImage));
-
-  if (!mImage) {
-    mImage = do_CreateInstance("@mozilla.org/image/container;1");
-    if (!mImage)
-      return NS_ERROR_OUT_OF_MEMORY;
-      
-    mImageLoad->SetImage(mImage);
-    nsresult result = mImage->SetDiscardable("image/jpeg");
-    if (NS_FAILED(result)) {
-      mState = JPEG_ERROR;
-      PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-             (" (could not set image container to discardable)"));
-      return result;
-    }
-  }
-
   return NS_OK;
 }
 
 
 /* void close (); */
 NS_IMETHODIMP nsJPEGDecoder::Close()
 {
   PR_LOG(gJPEGlog, PR_LOG_DEBUG,
@@ -219,106 +180,68 @@ NS_IMETHODIMP nsJPEGDecoder::Flush()
   return NS_OK;
 }
 
 /* unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count); */
 NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
 {
   LOG_SCOPE_WITH_PARAM(gJPEGlog, "nsJPEGDecoder::WriteFrom", "count", count);
 
-  PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-         ("nsJPEGDecoder::WriteFrom(decoder = %p) {\n"
-          "        image container %s; %u bytes to be added",
-          this,
-          mImage ? "exists" : "does not exist",
-          count));
-
   if (inStr) {
     if (!mBuffer) {
       mBuffer = (JOCTET *)PR_Malloc(count);
       if (!mBuffer) {
         mState = JPEG_ERROR;
-        PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-               ("} (out of memory allocating buffer)"));
         return NS_ERROR_OUT_OF_MEMORY;
       }
       mBufferSize = count;
     } else if (count > mBufferSize) {
       JOCTET *buf = (JOCTET *)PR_Realloc(mBuffer, count);
       if (!buf) {
         mState = JPEG_ERROR;
-        PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-               ("} (out of memory resizing buffer)"));
         return NS_ERROR_OUT_OF_MEMORY;
       }
       mBuffer = buf;
       mBufferSize = count;
     }
 
     nsresult rv = inStr->Read((char*)mBuffer, count, &mBufferLen);
-    NS_ASSERTION(NS_SUCCEEDED(rv), "nsJPEGDecoder::WriteFrom -- inStr->Read failed");
-
-    PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-           ("nsJPEGDecoder::WriteFrom(): decoder %p got %u bytes, read %u from the stream (buffer size %u)",
-            this,
-            count,
-            mBufferLen,
-            mBufferSize));
-    
     *_retval = mBufferLen;
 
-    nsresult result = mImage->AddRestoreData((char *) mBuffer, count);
-
-    if (NS_FAILED(result)) {
-      mState = JPEG_ERROR;
-      PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-             ("} (could not add restore data)"));
-      return result;
-    }
-
-    PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-           ("        added %u bytes to restore data",
-            count));
+    NS_ASSERTION(NS_SUCCEEDED(rv), "nsJPEGDecoder::WriteFrom -- inStr->Read failed");
   }
   // else no input stream.. Flush() ?
 
   /* Return here if there is a fatal error. */
   nsresult error_code;
   if ((error_code = setjmp(mErr.setjmp_buffer)) != 0) {
     mState = JPEG_SINK_NON_JPEG_TRAILER;
     if (error_code == NS_ERROR_FAILURE) {
       /* Error due to corrupt stream - return NS_OK so that libpr0n
          doesn't throw away a partial image load */
-      PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-             ("} (setjmp returned NS_ERROR_FAILURE)"));
       return NS_OK;
     } else {
       /* Error due to reasons external to the stream (probably out of
          memory) - let libpr0n attempt to clean up, even though
          mozilla is seconds away from falling flat on its face. */
-      PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-             ("} (setjmp returned an error)"));
       return error_code;
     }
   }
 
   PR_LOG(gJPEGlog, PR_LOG_DEBUG,
          ("[this=%p] nsJPEGDecoder::WriteFrom -- processing JPEG data\n", this));
 
   switch (mState) {
   case JPEG_HEADER:
   {
     LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::WriteFrom -- entering JPEG_HEADER case");
 
     /* Step 3: read file parameters with jpeg_read_header() */
-    if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED) {
-      PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-             ("} (JPEG_SUSPENDED)"));
+    if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED)
       return NS_OK; /* I/O suspension */
-    }
 
     JOCTET  *profile;
     PRUint32 profileLength;
 
     if (gfxPlatform::IsCMSEnabled() &&
         read_icc_profile(&mInfo, &profile, &profileLength) &&
         (mInProfile = cmsOpenProfileFromMem(profile, profileLength)) != NULL) {
       free(profile);
@@ -350,18 +273,16 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(n
       case JCS_YCCK:
         if (profileSpace == icSigCmykData)
           mInfo.out_color_space = JCS_CMYK;
         else
           mismatch = PR_TRUE;
         break;
       default:
         mState = JPEG_ERROR;
-        PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-               ("} (unknown colorpsace (1))"));
         return NS_ERROR_UNEXPECTED;
       }
 
       if (!mismatch) {
         PRUint32 space, channels;
         switch (mInfo.out_color_space) {
         case JCS_GRAYSCALE:
           space = PT_GRAY;
@@ -375,18 +296,16 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(n
           space = PT_YCbCr;
           channels = 3;
         case JCS_CMYK:
           space = PT_CMYK;
           channels = 4;
           break;
         default:
           mState = JPEG_ERROR;
-          PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-                 ("} (unknown colorpsace (2))"));
           return NS_ERROR_UNEXPECTED;
         }
 
         PRUint32 type =
           COLORSPACE_SH(space) |
           CHANNELS_SH(channels) |
           BYTES_SH(1);
 
@@ -412,49 +331,56 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(n
       switch (mInfo.jpeg_color_space) {
       case JCS_GRAYSCALE:
       case JCS_RGB:
       case JCS_YCbCr:
         mInfo.out_color_space = JCS_RGB;
         break;
       default:
         mState = JPEG_ERROR;
-        PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-               ("} (unknown colorpsace (3))"));
         return NS_ERROR_UNEXPECTED;
         break;
       }
     }
 
     /*
      * Don't allocate a giant and superfluous memory buffer
      * when the image is a sequential JPEG.
      */
     mInfo.buffered_image = jpeg_has_multiple_scans(&mInfo);
 
     /* Used to set up image size so arrays can be allocated */
     jpeg_calc_output_dimensions(&mInfo);
 
     mObserver->OnStartDecode(nsnull);
 
-    /* verify that the width and height of the image are the same as
-     * the container we're about to put things in to.
-     * XXX it might not matter maybe we should just resize the image.
+    /* Check if the request already has an image container.
+       this is the case when multipart/x-mixed-replace is being downloaded
+       if we already have one and it has the same width and height, reuse it.
      */
-    PRInt32 width, height;
-    mImage->GetWidth(&width);
-    mImage->GetHeight(&height);
-    if (width == 0 && height == 0) {
-      mImage->Init(mInfo.image_width, mInfo.image_height, mObserver);
-    } else if ((width != (PRInt32)mInfo.image_width) || (height != (PRInt32)mInfo.image_height)) {
-      mState = JPEG_ERROR;
-      return NS_ERROR_UNEXPECTED;
+    mImageLoad->GetImage(getter_AddRefs(mImage));
+    if (mImage) {
+      PRInt32 width, height;
+      mImage->GetWidth(&width);
+      mImage->GetHeight(&height);
+      if ((width != (PRInt32)mInfo.image_width) ||
+          (height != (PRInt32)mInfo.image_height)) {
+        mImage = nsnull;
+      }
     }
 
-    mImage->Init(mInfo.image_width, mInfo.image_height, mObserver);
+    if (!mImage) {
+      mImage = do_CreateInstance("@mozilla.org/image/container;1");
+      if (!mImage) {
+        mState = JPEG_ERROR;
+        return NS_ERROR_OUT_OF_MEMORY;
+      }
+      mImageLoad->SetImage(mImage);
+      mImage->Init(mInfo.image_width, mInfo.image_height, mObserver);
+    }
 
     mObserver->OnStartContainer(nsnull, mImage);
 
     mImage->GetFrameAt(0, getter_AddRefs(mFrame));
 
     PRBool createNewFrame = PR_TRUE;
 
     if (mFrame) {
@@ -469,39 +395,31 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(n
         mImage->Clear();
       }
     }
 
     if (createNewFrame) {
       mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
       if (!mFrame) {
         mState = JPEG_ERROR;
-        PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-               ("} (could not create image frame)"));
         return NS_ERROR_OUT_OF_MEMORY;
       }
 
       gfx_format format = gfxIFormats::RGB;
 #if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS)
       format = gfxIFormats::BGR;
 #endif
 
       if (NS_FAILED(mFrame->Init(0, 0, mInfo.image_width, mInfo.image_height, format, 24))) {
         mState = JPEG_ERROR;
-        PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-               ("} (could not initialize image frame)"));
         return NS_ERROR_OUT_OF_MEMORY;
       }
 
       mImage->AppendFrame(mFrame);
-
-      PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-             ("        JPEGDecoderAccounting: nsJPEGDecoder::WriteFrom -- created image frame with %ux%u pixels",
-              mInfo.image_width, mInfo.image_height));
-    }
+    }      
 
     mObserver->OnStartFrame(nsnull, mFrame);
     mState = JPEG_START_DECOMPRESS;
   }
 
   case JPEG_START_DECOMPRESS:
   {
     LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::WriteFrom -- entering JPEG_START_DECOMPRESS case");
@@ -512,41 +430,35 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(n
      */
     mInfo.dct_method =  JDCT_ISLOW;
     mInfo.dither_mode = JDITHER_FS;
     mInfo.do_fancy_upsampling = TRUE;
     mInfo.enable_2pass_quant = FALSE;
     mInfo.do_block_smoothing = TRUE;
 
     /* Step 5: Start decompressor */
-    if (jpeg_start_decompress(&mInfo) == FALSE) {
-      PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-             ("} (I/O suspension after jpeg_start_decompress())"));
+    if (jpeg_start_decompress(&mInfo) == FALSE)
       return NS_OK; /* I/O suspension */
-    }
 
     /* If this is a progressive JPEG ... */
     if (mInfo.buffered_image) {
       mState = JPEG_DECOMPRESS_PROGRESSIVE;
     } else {
       mState = JPEG_DECOMPRESS_SEQUENTIAL;
     }
   }
 
   case JPEG_DECOMPRESS_SEQUENTIAL:
   {
     if (mState == JPEG_DECOMPRESS_SEQUENTIAL)
     {
       LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::WriteFrom -- JPEG_DECOMPRESS_SEQUENTIAL case");
       
-      if (!OutputScanlines()) {
-        PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-               ("} (I/O suspension after OutputScanlines() - SEQUENTIAL)"));
+      if (!OutputScanlines())
         return NS_OK; /* I/O suspension */
-      }
       
       /* If we've completed image output ... */
       NS_ASSERTION(mInfo.output_scanline == mInfo.output_height, "We didn't process all of the data!");
       mState = JPEG_DONE;
     }
   }
 
   case JPEG_DECOMPRESS_PROGRESSIVE:
@@ -568,99 +480,76 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(n
           /* if we haven't displayed anything yet (output_scan_number==0)
              and we have enough data for a complete scan, force output
              of the last full scan */
           if ((mInfo.output_scan_number == 0) &&
               (scan > 1) &&
               (status != JPEG_REACHED_EOI))
             scan--;
 
-          if (!jpeg_start_output(&mInfo, scan)) {
-            PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-                   ("} (I/O suspension after jpeg_start_output() - PROGRESSIVE)"));
+          if (!jpeg_start_output(&mInfo, scan))
             return NS_OK; /* I/O suspension */
-          }
         }
 
         if (mInfo.output_scanline == 0xffffff)
           mInfo.output_scanline = 0;
 
         if (!OutputScanlines()) {
           if (mInfo.output_scanline == 0) {
             /* didn't manage to read any lines - flag so we don't call
                jpeg_start_output() multiple times for the same scan */
             mInfo.output_scanline = 0xffffff;
           }
-          PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-                 ("} (I/O suspension after OutputScanlines() - PROGRESSIVE)"));
           return NS_OK; /* I/O suspension */
         }
 
         if (mInfo.output_scanline == mInfo.output_height)
         {
-          if (!jpeg_finish_output(&mInfo)) {
-            PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-                   ("} (I/O suspension after jpeg_finish_output() - PROGRESSIVE)"));
+          if (!jpeg_finish_output(&mInfo))
             return NS_OK; /* I/O suspension */
-          }
 
           if (jpeg_input_complete(&mInfo) &&
               (mInfo.input_scan_number == mInfo.output_scan_number))
             break;
 
           mInfo.output_scanline = 0;
         }
       }
 
       mState = JPEG_DONE;
     }
   }
 
   case JPEG_DONE:
   {
-    nsresult result;
-
     LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::WriteFrom -- entering JPEG_DONE case");
 
     /* Step 7: Finish decompression */
 
-    if (jpeg_finish_decompress(&mInfo) == FALSE) {
-      PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-             ("} (I/O suspension after jpeg_finish_decompress() - DONE)"));
+    if (jpeg_finish_decompress(&mInfo) == FALSE)
       return NS_OK; /* I/O suspension */
-    }
 
     mState = JPEG_SINK_NON_JPEG_TRAILER;
 
-    result = mImage->RestoreDataDone();
-    if (NS_FAILED (result)) {
-      mState = JPEG_ERROR;
-      PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-             ("} (could not mark image container with RestoreDataDone)"));
-      return result;
-    }
-
     /* we're done dude */
     break;
   }
   case JPEG_SINK_NON_JPEG_TRAILER:
     PR_LOG(gJPEGlog, PR_LOG_DEBUG,
            ("[this=%p] nsJPEGDecoder::WriteFrom -- entering JPEG_SINK_NON_JPEG_TRAILER case\n", this));
 
     break;
 
   case JPEG_ERROR:
     PR_LOG(gJPEGlog, PR_LOG_DEBUG,
            ("[this=%p] nsJPEGDecoder::WriteFrom -- entering JPEG_ERROR case\n", this));
 
     break;
   }
 
-  PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
-         ("} (end of function)"));
   return NS_OK;
 }
 
 
 PRBool
 nsJPEGDecoder::OutputScanlines()
 {
   const PRUint32 top = mInfo.output_scanline;
--- a/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.h
+++ b/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.h
@@ -119,15 +119,11 @@ public:
 
   JOCTET  *mProfile;
   PRUint32 mProfileLength;
 
   cmsHPROFILE mInProfile;
   cmsHTRANSFORM mTransform;
 
   PRPackedBool mReading;
-
-private:
-
-  nsresult AddToTmpAccumulateBuffer(JOCTET *src, PRUint32 len);
 };
 
 #endif // nsJPEGDecoder_h__
--- a/modules/libpr0n/decoders/png/nsPNGDecoder.cpp
+++ b/modules/libpr0n/decoders/png/nsPNGDecoder.cpp
@@ -18,17 +18,16 @@
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 2001
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Stuart Parmenter <stuart@mozilla.com>
  *   Andrew Smith
- *   Federico Mena-Quintero <federico@novell.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -68,18 +67,17 @@ static void PNGAPI info_callback(png_str
 static void PNGAPI row_callback(png_structp png_ptr, png_bytep new_row,
                            png_uint_32 row_num, int pass);
 static void PNGAPI frame_info_callback(png_structp png_ptr, png_uint_32 frame_num);
 static void PNGAPI end_callback(png_structp png_ptr, png_infop info_ptr);
 static void PNGAPI error_callback(png_structp png_ptr, png_const_charp error_msg);
 static void PNGAPI warning_callback(png_structp png_ptr, png_const_charp warning_msg);
 
 #ifdef PR_LOGGING
-static PRLogModuleInfo *gPNGLog = PR_NewLogModule("PNGDecoder");
-static PRLogModuleInfo *gPNGDecoderAccountingLog = PR_NewLogModule("PNGDecoderAccounting");
+PRLogModuleInfo *gPNGLog = PR_NewLogModule("PNGDecoder");
 #endif
 
 NS_IMPL_ISUPPORTS1(nsPNGDecoder, imgIDecoder)
 
 nsPNGDecoder::nsPNGDecoder() :
   mPNG(nsnull), mInfo(nsnull),
   mCMSLine(nsnull), interlacebuf(nsnull),
   mInProfile(nsnull), mTransform(nsnull),
@@ -117,22 +115,16 @@ void nsPNGDecoder::CreateFrame(png_uint_
   if (png_get_valid(mPNG, mInfo, PNG_INFO_acTL))
     SetAnimFrameInfo();
   
   mImage->AppendFrame(mFrame);
   
   if (mObserver)
     mObserver->OnStartFrame(nsnull, mFrame);
 
- 
-  PR_LOG(gPNGDecoderAccountingLog, PR_LOG_DEBUG,
-         ("PNGDecoderAccounting: nsPNGDecoder::CreateFrame -- created image frame with %dx%d pixels in container %p",
-          width, height,
-          mImage.get ()));
-
   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;
@@ -212,66 +204,32 @@ NS_IMETHODIMP nsPNGDecoder::Init(imgILoa
   png_set_keep_unknown_chunks(mPNG, 1, unused_chunks,
      (int)sizeof(unused_chunks)/5);   
 #endif
 
   /* use this as libpng "progressive pointer" (retrieve in callbacks) */
   png_set_progressive_read_fn(mPNG, static_cast<png_voidp>(this),
                               info_callback, row_callback, end_callback);
 
-
-  /* The image container may already exist if it is reloading itself from us.
-   * Check that it has the same width/height; otherwise create a new container.
-   */
-  mImageLoad->GetImage(getter_AddRefs(mImage));
-  if (!mImage) {
-    mImage = do_CreateInstance("@mozilla.org/image/container;1");
-    if (!mImage)
-      return NS_ERROR_OUT_OF_MEMORY;
-      
-    mImageLoad->SetImage(mImage);
-    if (NS_FAILED(mImage->SetDiscardable("image/png"))) {
-      PR_LOG(gPNGDecoderAccountingLog, PR_LOG_DEBUG,
-             ("PNGDecoderAccounting: info_callback(): failed to set image container %p as discardable",
-              mImage.get()));
-      return NS_ERROR_FAILURE;
-    }
-  }
-
   return NS_OK;
 }
 
 /* void close (); */
 NS_IMETHODIMP nsPNGDecoder::Close()
 {
   if (mPNG)
     png_destroy_read_struct(&mPNG, mInfo ? &mInfo : NULL, NULL);
 
-  if (mImage) { // mImage could be null in the case of an error
-    nsresult result = mImage->RestoreDataDone();
-    if (NS_FAILED(result)) {
-        PR_LOG(gPNGDecoderAccountingLog, PR_LOG_DEBUG,
-            ("PNGDecoderAccounting: nsPNGDecoder::Close(): failure in RestoreDataDone() for image container %p",
-                mImage.get()));
-
-        mError = PR_TRUE;
-        return result;
-    }
-
-    PR_LOG(gPNGDecoderAccountingLog, PR_LOG_DEBUG,
-            ("PNGDecoderAccounting: nsPNGDecoder::Close(): image container %p is now with RestoreDataDone",
-            mImage.get()));
-  }
   return NS_OK;
 }
 
 /* void flush (); */
 NS_IMETHODIMP nsPNGDecoder::Flush()
 {
-  return NS_OK;
+    return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 
 static NS_METHOD ReadDataOut(nsIInputStream* in,
                              void* closure,
                              const char* fromRawSegment,
                              PRUint32 toOffset,
                              PRUint32 count,
@@ -287,34 +245,20 @@ static NS_METHOD ReadDataOut(nsIInputStr
   // we need to do the setjmp here otherwise bad things will happen
   if (setjmp(decoder->mPNG->jmpbuf)) {
     png_destroy_read_struct(&decoder->mPNG, &decoder->mInfo, NULL);
 
     decoder->mError = PR_TRUE;
     *writeCount = 0;
     return NS_ERROR_FAILURE;
   }
+
   png_process_data(decoder->mPNG, decoder->mInfo,
                    reinterpret_cast<unsigned char *>(const_cast<char *>(fromRawSegment)), count);
 
-  nsresult result = decoder->mImage->AddRestoreData((char *) fromRawSegment, count);
-  if (NS_FAILED (result)) {
-    PR_LOG(gPNGDecoderAccountingLog, PR_LOG_DEBUG,
-           ("PNGDecoderAccounting: ReadDataOut(): failed to add restore data to image container %p",
-            decoder->mImage.get()));
-
-    decoder->mError = PR_TRUE;
-    *writeCount = 0;
-    return result;
-  }
-
-  PR_LOG(gPNGDecoderAccountingLog, PR_LOG_DEBUG,
-         ("PNGDecoderAccounting: ReadDataOut(): Added restore data to image container %p",
-          decoder->mImage.get()));
-
   *writeCount = count;
   return NS_OK;
 }
 
 
 /* unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count); */
 NS_IMETHODIMP nsPNGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
 {
@@ -564,28 +508,23 @@ info_callback(png_structp png_ptr, png_i
     } else {
       alpha_bits = 8;
     }
   }
 
   if (decoder->mObserver)
     decoder->mObserver->OnStartDecode(nsnull);
 
-  /* The image container may already exist if it is reloading itself from us.
-   * Check that it has the same width/height; otherwise create a new container.
-   */
-  PRInt32 containerWidth, containerHeight;
-  decoder->mImage->GetWidth(&containerWidth);
-  decoder->mImage->GetHeight(&containerHeight);
-  if (containerWidth == 0 && containerHeight == 0) {
-    // the image hasn't been inited yet
-    decoder->mImage->Init(width, height, decoder->mObserver);
-  } else if (containerWidth != width || containerHeight != height) {
-    longjmp(decoder->mPNG->jmpbuf, 5); // NS_ERROR_UNEXPECTED
-  }
+  decoder->mImage = do_CreateInstance("@mozilla.org/image/container;1");
+  if (!decoder->mImage)
+    longjmp(decoder->mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
+
+  decoder->mImageLoad->SetImage(decoder->mImage);
+
+  decoder->mImage->Init(width, height, decoder->mObserver);
 
   if (decoder->mObserver)
     decoder->mObserver->OnStartContainer(nsnull, decoder->mImage);
 
   if (channels == 1 || channels == 3) {
     decoder->format = gfxIFormats::RGB;
   } else if (channels == 2 || channels == 4) {
     if (alpha_bits == 8) {
@@ -817,17 +756,17 @@ end_callback(png_structp png_ptr, png_in
     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);
     decoder->mObserver->OnStopContainer(nsnull, decoder->mImage);
     decoder->mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
   }
 }
 
--- a/modules/libpr0n/public/imgIContainer.idl
+++ b/modules/libpr0n/public/imgIContainer.idl
@@ -17,17 +17,16 @@
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 2001
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Stuart Parmenter <pavlov@netscape.com>
- *   Federico Mena-Quintero <federico@novell.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -140,15 +139,9 @@ interface imgIContainer : nsISupports
 
   void resetAnimation();
 
   /**
    * number of times to loop the image.
    * @note -1 means forever.
    */
   attribute long loopCount;
-
-  /* Methods to discard uncompressed images and restore them again */
-  [noscript] void setDiscardable(in string aMimeType);
-  [noscript] void addRestoreData([array, size_is(aCount), const] in char data,
-                                 in unsigned long aCount);
-  [noscript] void restoreDataDone();
 };
--- a/modules/libpr0n/src/imgContainer.cpp
+++ b/modules/libpr0n/src/imgContainer.cpp
@@ -20,17 +20,16 @@
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Stuart Parmenter <pavlov@netscape.com>
  *   Chris Saari <saari@netscape.com>
  *   Asko Tontti <atontti@cc.hut.fi>
  *   Arron Mogge <paper@animecity.nu>
  *   Andrew Smith
- *   Federico Mena-Quintero <federico@novell.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -38,82 +37,41 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsComponentManagerUtils.h"
 #include "imgIContainerObserver.h"
-#include "ImageErrors.h"
 #include "nsIImage.h"
-#include "imgILoad.h"
-#include "imgIDecoder.h"
-#include "imgIDecoderObserver.h"
 #include "imgContainer.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsAutoPtr.h"
-#include "nsStringStream.h"
-#include "prmem.h"
-#include "prlog.h"
-#include "prenv.h"
 
 #include "gfxContext.h"
 
-/* Accounting for compressed data */
-#if defined(PR_LOGGING)
-static PRLogModuleInfo *gCompressedImageAccountingLog = PR_NewLogModule ("CompressedImageAccounting");
-#else
-#define gCompressedImageAccountingLog
-#endif
-
-static int num_containers_with_discardable_data;
-static PRInt64 num_compressed_image_bytes;
-
-
 NS_IMPL_ISUPPORTS3(imgContainer, imgIContainer, nsITimerCallback, nsIProperties)
 
 //******************************************************************************
 imgContainer::imgContainer() :
   mSize(0,0),
-  mNumFrames(0),
   mAnim(nsnull),
   mAnimationMode(kNormalAnimMode),
   mLoopCount(-1),
-  mObserver(nsnull),
-  mDiscardable(PR_FALSE),
-  mDiscarded(PR_FALSE),
-  mRestoreDataDone(PR_FALSE),
-  mDiscardTimer(nsnull)
+  mObserver(nsnull)
 {
 }
 
 //******************************************************************************
 imgContainer::~imgContainer()
 {
   if (mAnim)
     delete mAnim;
-
-  if (!mRestoreData.IsEmpty()) {
-    num_containers_with_discardable_data--;
-    num_compressed_image_bytes -= mRestoreData.Length();
-
-    PR_LOG (gCompressedImageAccountingLog, PR_LOG_DEBUG,
-            ("CompressedImageAccounting: destroying imgContainer %p.  "
-             "Compressed containers: %d, Compressed data bytes: %lld",
-             this,
-             num_containers_with_discardable_data,
-             num_compressed_image_bytes));
-  }
-
-  if (mDiscardTimer) {
-    mDiscardTimer->Cancel ();
-    mDiscardTimer = nsnull;
-  }
 }
 
 //******************************************************************************
 /* void init (in PRInt32 aWidth, in PRInt32 aHeight, 
               in imgIContainerObserver aObserver); */
 NS_IMETHODIMP imgContainer::Init(PRInt32 aWidth, PRInt32 aHeight,
                                  imgIContainerObserver *aObserver)
 {
@@ -161,132 +119,85 @@ NS_IMETHODIMP imgContainer::GetHeight(PR
   NS_ASSERTION(aHeight, "imgContainer::GetHeight; Invalid Arg");
   if (!aHeight)
     return NS_ERROR_INVALID_ARG;
 
   *aHeight = mSize.height;
   return NS_OK;
 }
 
-nsresult imgContainer::GetCurrentFrameNoRef(gfxIImageFrame **aFrame)
-{
-  nsresult result;
-
-  result = RestoreDiscardedData();
-  if (NS_FAILED (result)) {
-    PR_LOG (gCompressedImageAccountingLog, PR_LOG_DEBUG,
-            ("CompressedImageAccounting: imgContainer::GetCurrentFrameNoRef(): error %d in RestoreDiscardedData(); "
-             "returning a null frame from imgContainer %p",
-             result,
-             this));
-
-    *aFrame = nsnull;
-    return result;
-  }
-
-  if (!mAnim)
-    *aFrame = mFrames.SafeObjectAt(0);
-  else if (mAnim->lastCompositedFrameIndex == mAnim->currentAnimationFrameIndex)
-    *aFrame = mAnim->compositingFrame;
-  else
-    *aFrame = mFrames.SafeObjectAt(mAnim->currentAnimationFrameIndex);
-
-  if (!*aFrame)
-    PR_LOG (gCompressedImageAccountingLog, PR_LOG_DEBUG,
-            ("CompressedImageAccounting: imgContainer::GetCurrentFrameNoRef(): returning null frame from imgContainer %p "
-             "(no errors when restoring data)",
-              this));
-
-  return NS_OK;
-}
-
 //******************************************************************************
 /* readonly attribute gfxIImageFrame currentFrame; */
 NS_IMETHODIMP imgContainer::GetCurrentFrame(gfxIImageFrame **aCurrentFrame)
 {
-  nsresult result;
-
   NS_ASSERTION(aCurrentFrame, "imgContainer::GetCurrentFrame; Invalid Arg");
   if (!aCurrentFrame)
     return NS_ERROR_INVALID_POINTER;
   
-  result = GetCurrentFrameNoRef (aCurrentFrame);
-  if (NS_FAILED (result))
-    return result;
-
-  if (!*aCurrentFrame)
+  if (!(*aCurrentFrame = inlinedGetCurrentFrame()))
     return NS_ERROR_FAILURE;
 
   NS_ADDREF(*aCurrentFrame);
   
   return NS_OK;
 }
 
 //******************************************************************************
 /* readonly attribute unsigned long numFrames; */
 NS_IMETHODIMP imgContainer::GetNumFrames(PRUint32 *aNumFrames)
 {
   NS_ASSERTION(aNumFrames, "imgContainer::GetNumFrames; Invalid Arg");
   if (!aNumFrames)
     return NS_ERROR_INVALID_ARG;
 
-  *aNumFrames = mNumFrames;
+  *aNumFrames = mFrames.Count();
   
   return NS_OK;
 }
 
 //******************************************************************************
 /* gfxIImageFrame getFrameAt (in unsigned long index); */
 NS_IMETHODIMP imgContainer::GetFrameAt(PRUint32 index, gfxIImageFrame **_retval)
 {
-  nsresult result;
-
   NS_ASSERTION(_retval, "imgContainer::GetFrameAt; Invalid Arg");
   if (!_retval)
     return NS_ERROR_INVALID_POINTER;
 
-  if (mNumFrames == 0) {
+  if (!mFrames.Count()) {
     *_retval = nsnull;
     return NS_OK;
   }
 
-  NS_ENSURE_ARG((int) index < mNumFrames);
-
-  result = RestoreDiscardedData ();
-  if (NS_FAILED (result)) {
-    *_retval = nsnull;
-    return result;
-  }
+  NS_ENSURE_ARG(index < static_cast<PRUint32>(mFrames.Count()));
   
   if (!(*_retval = mFrames[index]))
     return NS_ERROR_FAILURE;
 
   NS_ADDREF(*_retval);
   
   return NS_OK;
 }
 
 //******************************************************************************
 /* void appendFrame (in gfxIImageFrame item); */
 NS_IMETHODIMP imgContainer::AppendFrame(gfxIImageFrame *item)
 {
   NS_ASSERTION(item, "imgContainer::AppendFrame; Invalid Arg");
   if (!item)
     return NS_ERROR_INVALID_ARG;
-
-  if (mFrames.Count () == 0) {
+  
+  PRInt32 numFrames = mFrames.Count();
+  
+  if (numFrames == 0) {
     // This may not be an animated image, don't do all the animation stuff.
     mFrames.AppendObject(item);
-
-    mNumFrames++;
-
     return NS_OK;
   }
   
-  if (mFrames.Count () == 1) {
+  if (numFrames == 1) {
     // Now that we got a second frame, initialize animation stuff.
     if (!ensureAnimExists())
       return NS_ERROR_OUT_OF_MEMORY;
     
     // If we dispose of the first frame by clearing it, then the
     // First Frame's refresh area is all of itself.
     // RESTORE_PREVIOUS is invalid (assumed to be DISPOSE_CLEAR)
     PRInt32 frameDisposalMethod;
@@ -300,33 +211,30 @@ NS_IMETHODIMP imgContainer::AppendFrame(
   // Some gifs are huge but only have a small area that they animate
   // We only need to refresh that small area when Frame 0 comes around again
   nsIntRect itemRect;
   item->GetRect(itemRect);
   mAnim->firstFrameRefreshArea.UnionRect(mAnim->firstFrameRefreshArea, 
                                          itemRect);
   
   mFrames.AppendObject(item);
-
-  mNumFrames++;
   
   // If this is our second frame, start the animation.
   // Must be called after AppendObject because StartAnimation checks for > 1
   // frame
-  if (mFrames.Count () == 1)
+  if (numFrames == 1)
     StartAnimation();
   
   return NS_OK;
 }
 
 //******************************************************************************
 /* void removeFrame (in gfxIImageFrame item); */
 NS_IMETHODIMP imgContainer::RemoveFrame(gfxIImageFrame *item)
 {
-  /* Remember to decrement mNumFrames if you implement this */
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 //******************************************************************************
 /* void endFrameDecode (in unsigned long framenumber, in unsigned long timeout); */
 NS_IMETHODIMP imgContainer::EndFrameDecode(PRUint32 aFrameNum, PRUint32 aTimeout)
 {
   // Assume there's another frame.
@@ -340,17 +248,17 @@ NS_IMETHODIMP imgContainer::EndFrameDeco
 //******************************************************************************
 /* void decodingComplete (); */
 NS_IMETHODIMP imgContainer::DecodingComplete(void)
 {
   if (mAnim)
     mAnim->doneDecoding = PR_TRUE;
   // If there's only 1 frame, optimize it.
   // Optimizing animated images is not supported
-  if (mNumFrames == 1)
+  if (mFrames.Count() == 1)
     mFrames[0]->SetMutable(PR_FALSE);
   return NS_OK;
 }
 
 //******************************************************************************
 /* void clear (); */
 NS_IMETHODIMP imgContainer::Clear()
 {
@@ -379,48 +287,42 @@ NS_IMETHODIMP imgContainer::SetAnimation
                "Wrong Animation Mode is being set!");
   
   switch (mAnimationMode = aAnimationMode) {
     case kDontAnimMode:
       StopAnimation();
       break;
     case kNormalAnimMode:
       if (mLoopCount != 0 || 
-          (mAnim && (mAnim->currentAnimationFrameIndex + 1 < mNumFrames)))
+          (mAnim && (mAnim->currentAnimationFrameIndex + 1 < mFrames.Count())))
         StartAnimation();
       break;
     case kLoopOnceAnimMode:
-      if (mAnim && (mAnim->currentAnimationFrameIndex + 1 < mNumFrames))
+      if (mAnim && (mAnim->currentAnimationFrameIndex + 1 < mFrames.Count()))
         StartAnimation();
       break;
   }
   
   return NS_OK;
 }
 
 //******************************************************************************
 /* void startAnimation () */
 NS_IMETHODIMP imgContainer::StartAnimation()
 {
   if (mAnimationMode == kDontAnimMode || 
       (mAnim && (mAnim->timer || mAnim->animating)))
     return NS_OK;
   
-  if (mNumFrames > 1) {
+  if (mFrames.Count() > 1) {
     if (!ensureAnimExists())
       return NS_ERROR_OUT_OF_MEMORY;
     
     PRInt32 timeout;
-    nsresult result;
-    gfxIImageFrame *currentFrame;
-
-    result = GetCurrentFrameNoRef (&currentFrame);
-    if (NS_FAILED (result))
-      return result;
-
+    gfxIImageFrame *currentFrame = inlinedGetCurrentFrame();
     if (currentFrame) {
       currentFrame->GetTimeout(&timeout);
       if (timeout <= 0) // -1 means display this frame forever
         return NS_OK;
     } else
       timeout = 100; // XXX hack.. the timer notify code will do the right
                      //     thing, so just get that started
     
@@ -469,25 +371,18 @@ NS_IMETHODIMP imgContainer::ResetAnimati
     if (NS_FAILED(rv))
       return rv;
   }
 
   mAnim->lastCompositedFrameIndex = -1;
   mAnim->currentAnimationFrameIndex = 0;
   // Update display
   nsCOMPtr<imgIContainerObserver> observer(do_QueryReferent(mObserver));
-  if (observer) {
-    nsresult result;
-
-    result = RestoreDiscardedData ();
-    if (NS_FAILED (result))
-      return result;
-
+  if (observer)
     observer->FrameChanged(this, mFrames[0], &(mAnim->firstFrameRefreshArea));
-  }
 
   if (oldAnimating)
     return StartAnimation();
   else
     return NS_OK;
 }
 
 //******************************************************************************
@@ -511,160 +406,20 @@ NS_IMETHODIMP imgContainer::SetLoopCount
   //  0  no looping, one iteration
   //  1  one loop, two iterations
   //  ...
   mLoopCount = aLoopCount;
 
   return NS_OK;
 }
 
-static PRBool
-DiscardingEnabled(void)
-{
-  static PRBool inited;
-  static PRBool enabled;
-
-  if (!inited) {
-    inited = PR_TRUE;
-
-    enabled = (PR_GetEnv("MOZ_DISABLE_IMAGE_DISCARD") == nsnull);
-  }
-
-  return enabled;
-}
-
-//******************************************************************************
-/* void setDiscardable(in string mime_type); */
-NS_IMETHODIMP imgContainer::SetDiscardable(const char* aMimeType)
-{
-  NS_ASSERTION(aMimeType, "imgContainer::SetDiscardable() called with null aMimeType");
-
-  if (!DiscardingEnabled())
-    return NS_OK;
-
-  if (mDiscardable) {
-    NS_WARNING ("imgContainer::SetDiscardable(): cannot change an imgContainer which is already discardable");
-    return NS_ERROR_FAILURE;
-  }
-
-  mDiscardableMimeType.Assign(aMimeType);
-  mDiscardable = PR_TRUE;
-
-  num_containers_with_discardable_data++;
-  PR_LOG (gCompressedImageAccountingLog, PR_LOG_DEBUG,
-          ("CompressedImageAccounting: Making imgContainer %p (%s) discardable.  "
-           "Compressed containers: %d, Compressed data bytes: %lld",
-           this,
-           aMimeType,
-           num_containers_with_discardable_data,
-           num_compressed_image_bytes));
-
-  return NS_OK;
-}
-
-//******************************************************************************
-/* void addRestoreData(in nsIInputStream aInputStream, in unsigned long aCount); */
-NS_IMETHODIMP imgContainer::AddRestoreData(const char *aBuffer, PRUint32 aCount)
-{
-  NS_ASSERTION(aBuffer, "imgContainer::AddRestoreData() called with null aBuffer");
-
-  if (!DiscardingEnabled ())
-    return NS_OK;
-
-  if (!mDiscardable) {
-    NS_WARNING ("imgContainer::AddRestoreData() can only be called if SetDiscardable is called first");
-    return NS_ERROR_FAILURE;
-  }
-
-  if (mRestoreDataDone) {
-    /* We are being called from the decoder while the data is being restored
-     * (i.e. we were fully loaded once, then we discarded the image data, then
-     * we are being restored).  We don't want to save the compressed data again,
-     * since we already have it.
-     */
-    return NS_OK;
-  }
-
-  if (!mRestoreData.AppendElements(aBuffer, aCount))
-    return NS_ERROR_OUT_OF_MEMORY;
-
-  num_compressed_image_bytes += aCount;
-
-  PR_LOG (gCompressedImageAccountingLog, PR_LOG_DEBUG,
-          ("CompressedImageAccounting: Added compressed data to imgContainer %p (%s).  "
-           "Compressed containers: %d, Compressed data bytes: %lld",
-           this,
-           mDiscardableMimeType.get(),
-           num_containers_with_discardable_data,
-           num_compressed_image_bytes));
-
-  return NS_OK;
-}
-
-/* Note!  buf must be declared as char buf[9]; */
-// just used for logging and hashing the header
-static void
-get_header_str (char *buf, char *data, PRSize data_len)
-{
-  int i;
-  int n;
-  static char hex[] = "0123456789abcdef";
-
-  n = data_len < 4 ? data_len : 4;
-
-  for (i = 0; i < n; i++) {
-    buf[i * 2]     = hex[(data[i] >> 4) & 0x0f];
-    buf[i * 2 + 1] = hex[data[i] & 0x0f];
-  }
-
-  buf[i * 2] = 0;
-}
-
-//******************************************************************************
-/* void restoreDataDone(); */
-NS_IMETHODIMP imgContainer::RestoreDataDone (void)
-{
-
-  if (!DiscardingEnabled ())
-    return NS_OK;
-
-  if (mRestoreDataDone)
-    return NS_OK;
-
-  mRestoreData.Compact();
-
-  mRestoreDataDone = PR_TRUE;
-
-  if (PR_LOG_TEST(gCompressedImageAccountingLog, PR_LOG_DEBUG)) {
-    char buf[9];
-    get_header_str(buf, mRestoreData.Elements(), mRestoreData.Length());
-    PR_LOG (gCompressedImageAccountingLog, PR_LOG_DEBUG,
-            ("CompressedImageAccounting: imgContainer::RestoreDataDone() - data is done for container %p (%s), %d real frames (cached as %d frames) - header %p is 0x%s (length %d)",
-             this,
-             mDiscardableMimeType.get(),
-             mFrames.Count (),
-             mNumFrames,
-             mRestoreData.Elements(),
-             buf,
-             mRestoreData.Length()));
-  }
-
-  return ResetDiscardTimer();
-}
-
 //******************************************************************************
 /* void notify(in nsITimer timer); */
 NS_IMETHODIMP imgContainer::Notify(nsITimer *timer)
 {
-  nsresult result;
-
-  result = RestoreDiscardedData();
-  if (NS_FAILED (result))
-    return result;
-
   // This should never happen since the timer is only set up in StartAnimation()
   // after mAnim is checked to exist.
   NS_ASSERTION(mAnim, "imgContainer::Notify() called but mAnim is null");
   if (!mAnim)
     return NS_ERROR_UNEXPECTED;
   NS_ASSERTION(mAnim->timer == timer,
                "imgContainer::Notify() called with incorrect timer");
 
@@ -673,31 +428,32 @@ NS_IMETHODIMP imgContainer::Notify(nsITi
 
   nsCOMPtr<imgIContainerObserver> observer(do_QueryReferent(mObserver));
   if (!observer) {
     // the imgRequest that owns us is dead, we should die now too.
     StopAnimation();
     return NS_OK;
   }
 
-  if (mNumFrames == 0)
+  PRInt32 numFrames = mFrames.Count();
+  if (!numFrames)
     return NS_OK;
   
   gfxIImageFrame *nextFrame = nsnull;
   PRInt32 previousFrameIndex = mAnim->currentAnimationFrameIndex;
   PRInt32 nextFrameIndex = mAnim->currentAnimationFrameIndex + 1;
   PRInt32 timeout = 0;
 
   // If we're done decoding the next frame, go ahead and display it now and
   // reinit the timer with the next frame's delay time.
   // currentDecodingFrameIndex is not set until the second frame has
   // finished decoding (see EndFrameDecode)
   if (mAnim->doneDecoding || 
       (nextFrameIndex < mAnim->currentDecodingFrameIndex)) {
-    if (mNumFrames == nextFrameIndex) {
+    if (numFrames == nextFrameIndex) {
       // End of Animation
 
       // If animation mode is "loop once", it's time to stop animating
       if (mAnimationMode == kLoopOnceAnimMode || mLoopCount == 0) {
         StopAnimation();
         return NS_OK;
       } else {
         // We may have used compositingFrame to build a frame, and then copied
@@ -1145,313 +901,8 @@ NS_IMETHODIMP imgContainer::GetKeys(PRUi
 {
   if (!mProperties) {
     *count = 0;
     *keys = nsnull;
     return NS_OK;
   }
   return mProperties->GetKeys(count, keys);
 }
-
-static int
-get_discard_timer_ms (void)
-{
-  /* FIXME: don't hardcode this */
-  return 45000; /* 45 seconds */
-}
-
-void
-imgContainer::sDiscardTimerCallback(nsITimer *aTimer, void *aClosure)
-{
-  imgContainer *self = (imgContainer *) aClosure;
-  int old_frame_count;
-
-  NS_ASSERTION(aTimer == self->mDiscardTimer,
-               "imgContainer::DiscardTimerCallback() got a callback for an unknown timer");
-
-  self->mDiscardTimer = nsnull;
-
-  old_frame_count = self->mFrames.Count();
-
-  if (self->mAnim) {
-    delete self->mAnim;
-    self->mAnim = nsnull;
-  }
-
-  self->mFrames.Clear();
-
-  self->mDiscarded = PR_TRUE;
-
-  PR_LOG(gCompressedImageAccountingLog, PR_LOG_DEBUG,
-         ("CompressedImageAccounting: discarded uncompressed image data from imgContainer %p (%s) - %d frames (cached count: %d); "
-          "Compressed containers: %d, Compressed data bytes: %lld",
-          self,
-          self->mDiscardableMimeType.get(),
-          old_frame_count,
-          self->mNumFrames,
-          num_containers_with_discardable_data,
-          num_compressed_image_bytes));
-}
-
-nsresult
-imgContainer::ResetDiscardTimer (void)
-{
-  if (!DiscardingEnabled())
-    return NS_OK;
-
-  if (!mDiscardTimer) {
-    mDiscardTimer = do_CreateInstance("@mozilla.org/timer;1");
-
-    if (!mDiscardTimer)
-      return NS_ERROR_OUT_OF_MEMORY;
-  } else {
-    if (NS_FAILED(mDiscardTimer->Cancel()))
-      return NS_ERROR_FAILURE;
-  }
-
-  return mDiscardTimer->InitWithFuncCallback(sDiscardTimerCallback,
-                                             (void *) this,
-                                             get_discard_timer_ms (),
-                                             nsITimer::TYPE_ONE_SHOT);
-}
-
-nsresult
-imgContainer::RestoreDiscardedData(void)
-{
-  nsresult result;
-  int num_expected_frames;
-
-  if (!mDiscardable)
-    return NS_OK;
-
-  result = ResetDiscardTimer();
-  if (NS_FAILED (result))
-    return result;
-
-  if (!mDiscarded)
-    return NS_OK;
-
-  num_expected_frames = mNumFrames;
-
-  result = ReloadImages ();
-  if (NS_FAILED (result)) {
-    PR_LOG (gCompressedImageAccountingLog, PR_LOG_DEBUG,
-            ("CompressedImageAccounting: imgContainer::RestoreDiscardedData() for container %p failed to ReloadImages()",
-             this));
-    return result;
-  }
-
-  mDiscarded = PR_FALSE;
-
-  NS_ASSERTION (mNumFrames == mFrames.Count(),
-                "number of restored image frames doesn't match");
-  NS_ASSERTION (num_expected_frames == mNumFrames,
-                "number of restored image frames doesn't match the original number of frames!");
-  
-  PR_LOG (gCompressedImageAccountingLog, PR_LOG_DEBUG,
-          ("CompressedImageAccounting: imgContainer::RestoreDiscardedData() restored discarded data "
-           "for imgContainer %p (%s) - %d image frames.  "
-           "Compressed containers: %d, Compressed data bytes: %lld",
-           this,
-           mDiscardableMimeType.get(),
-           mNumFrames,
-           num_containers_with_discardable_data,
-           num_compressed_image_bytes));
-
-  return NS_OK;
-}
-
-class ContainerLoader : public imgILoad,
-                        public imgIDecoderObserver,
-                        public nsSupportsWeakReference
-{
-public:
-
-  NS_DECL_ISUPPORTS
-  NS_DECL_IMGILOAD
-  NS_DECL_IMGIDECODEROBSERVER
-  NS_DECL_IMGICONTAINEROBSERVER
-
-  ContainerLoader(void);
-
-private:
-
-  imgIContainer *mContainer;
-};
-
-NS_IMPL_ISUPPORTS4 (ContainerLoader, imgILoad, imgIDecoderObserver, imgIContainerObserver, nsISupportsWeakReference)
-
-ContainerLoader::ContainerLoader (void)
-{
-}
-
-/* Implement imgILoad::image getter */
-NS_IMETHODIMP
-ContainerLoader::GetImage(imgIContainer **aImage)
-{
-  *aImage = mContainer;
-  NS_IF_ADDREF (*aImage);
-  return NS_OK;
-}
-
-/* Implement imgILoad::image setter */
-NS_IMETHODIMP
-ContainerLoader::SetImage(imgIContainer *aImage)
-{
-  mContainer = aImage;
-  return NS_OK;
-}
-
-/* Implement imgILoad::isMultiPartChannel getter */
-NS_IMETHODIMP
-ContainerLoader::GetIsMultiPartChannel(PRBool *aIsMultiPartChannel)
-{
-  *aIsMultiPartChannel = PR_FALSE; /* FIXME: is this always right? */
-  return NS_OK;
-}
-
-/* Implement imgIDecoderObserver::onStartRequest() */
-NS_IMETHODIMP
-ContainerLoader::OnStartRequest(imgIRequest *aRequest)
-{
-  return NS_OK;
-}
-
-/* Implement imgIDecoderObserver::onStartDecode() */
-NS_IMETHODIMP
-ContainerLoader::OnStartDecode(imgIRequest *aRequest)
-{
-  return NS_OK;
-}
-
-/* Implement imgIDecoderObserver::onStartContainer() */
-NS_IMETHODIMP
-ContainerLoader::OnStartContainer(imgIRequest *aRequest, imgIContainer *aContainer)
-{
-  return NS_OK;
-}
-
-/* Implement imgIDecoderObserver::onStartFrame() */
-NS_IMETHODIMP
-ContainerLoader::OnStartFrame(imgIRequest *aRequest, gfxIImageFrame *aFrame)
-{
-  return NS_OK;
-}
-
-/* Implement imgIDecoderObserver::onDataAvailable() */
-NS_IMETHODIMP
-ContainerLoader::OnDataAvailable(imgIRequest *aRequest, gfxIImageFrame *aFrame, const nsIntRect * aRect)
-{
-  return NS_OK;
-}
-
-/* Implement imgIDecoderObserver::onStopFrame() */
-NS_IMETHODIMP
-ContainerLoader::OnStopFrame(imgIRequest *aRequest, gfxIImageFrame *aFrame)
-{
-  return NS_OK;
-}
-
-/* Implement imgIDecoderObserver::onStopContainer() */
-NS_IMETHODIMP
-ContainerLoader::OnStopContainer(imgIRequest *aRequest, imgIContainer *aContainer)
-{
-  return NS_OK;
-}
-
-/* Implement imgIDecoderObserver::onStopDecode() */
-NS_IMETHODIMP
-ContainerLoader::OnStopDecode(imgIRequest *aRequest, nsresult status, const PRUnichar *statusArg)
-{
-  return NS_OK;
-}
-
-/* Implement imgIDecoderObserver::onStopRequest() */
-NS_IMETHODIMP
-ContainerLoader::OnStopRequest(imgIRequest *aRequest, PRBool aIsLastPart)
-{
-  return NS_OK;
-}
-
-/* implement imgIContainerObserver::frameChanged() */
-NS_IMETHODIMP
-ContainerLoader::FrameChanged(imgIContainer *aContainer, gfxIImageFrame *aFrame, nsIntRect * aDirtyRect)
-{
-  return NS_OK;
-}
-
-nsresult
-imgContainer::ReloadImages(void)
-{
-  nsresult result = NS_ERROR_FAILURE;
-  nsCOMPtr<nsIInputStream> stream;
-
-  NS_ASSERTION(!mRestoreData.IsEmpty(),
-               "imgContainer::ReloadImages(): mRestoreData should not be empty");
-  NS_ASSERTION(mRestoreDataDone,
-               "imgContainer::ReloadImages(): mRestoreDataDone shoudl be true!");
-
-  mNumFrames = 0;
-  NS_ASSERTION(mFrames.Count() == 0,
-               "imgContainer::ReloadImages(): mFrames should be empty");
-
-  nsCAutoString decoderCID(NS_LITERAL_CSTRING("@mozilla.org/image/decoder;2?type=") + mDiscardableMimeType);
-
-  nsCOMPtr<imgIDecoder> decoder = do_CreateInstance(decoderCID.get());
-  if (!decoder) {
-    PR_LOG(gCompressedImageAccountingLog, PR_LOG_WARNING,
-           ("CompressedImageAccounting: imgContainer::ReloadImages() could not create decoder for %s",
-            mDiscardableMimeType.get()));
-    return NS_IMAGELIB_ERROR_NO_DECODER;
-  }
-
-  nsCOMPtr<imgILoad> loader = new ContainerLoader();
-  if (!loader) {
-    PR_LOG(gCompressedImageAccountingLog, PR_LOG_WARNING,
-           ("CompressedImageAccounting: imgContainer::ReloadImages() could not allocate ContainerLoader "
-            "when reloading the images for container %p",
-            this));
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  loader->SetImage(this);
-
-  result = decoder->Init(loader);
-  if (NS_FAILED(result)) {
-    PR_LOG(gCompressedImageAccountingLog, PR_LOG_WARNING,
-           ("CompressedImageAccounting: imgContainer::ReloadImages() image container %p "
-            "failed to initialize the decoder (%s)",
-            this,
-            mDiscardableMimeType.get()));
-    return result;
-  }
-
-  result = NS_NewByteInputStream(getter_AddRefs(stream), mRestoreData.Elements(), mRestoreData.Length(), NS_ASSIGNMENT_DEPEND);
-  NS_ENSURE_SUCCESS(result, result);
-
-  if (PR_LOG_TEST(gCompressedImageAccountingLog, PR_LOG_DEBUG)) {
-    char buf[9];
-    get_header_str(buf, mRestoreData.Elements(), mRestoreData.Length());
-    PR_LOG(gCompressedImageAccountingLog, PR_LOG_WARNING,
-           ("CompressedImageAccounting: imgContainer::ReloadImages() starting to restore images for container %p (%s) - "
-            "header %p is 0x%s (length %d)",
-            this,
-            mDiscardableMimeType.get(),
-            mRestoreData.Elements(),
-            buf,
-            mRestoreData.Length()));
-  }
-
-  PRUint32 written;
-  result = decoder->WriteFrom(stream, mRestoreData.Length(), &written);
-  NS_ENSURE_SUCCESS(result, result);
-
-  if (NS_FAILED(decoder->Flush()))
-    return result;
-
-  result = decoder->Close();
-  NS_ENSURE_SUCCESS(result, result);
-
-  NS_ASSERTION(mFrames.Count() == mNumFrames,
-               "imgContainer::ReloadImages(): the restored mFrames.Count() doesn't match mNumFrames!");
-
-  return result;
-}
--- a/modules/libpr0n/src/imgContainer.h
+++ b/modules/libpr0n/src/imgContainer.h
@@ -18,17 +18,16 @@
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 2001
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Stuart Parmenter <pavlov@netscape.com>
  *   Chris Saari <saari@netscape.com>
- *   Federico Mena-Quintero <federico@novell.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -54,17 +53,16 @@
 
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
 #include "imgIContainer.h"
 #include "gfxIImageFrame.h"
 #include "nsIProperties.h"
 #include "nsITimer.h"
 #include "nsWeakReference.h"
-#include "nsTArray.h"
 
 #define NS_IMGCONTAINER_CID \
 { /* 27f0682c-ff64-4dd2-ae7a-668e59f2fd38 */         \
      0x27f0682c,                                     \
      0xff64,                                         \
      0x4dd2,                                         \
     {0xae, 0x7a, 0x66, 0x8e, 0x59, 0xf2, 0xfd, 0x38} \
 }
@@ -189,18 +187,24 @@ private:
       ;
     }
     ~Anim()
     {
       if (timer)
         timer->Cancel();
     }
   };
-
-  nsresult GetCurrentFrameNoRef(gfxIImageFrame** aFrame);
+  
+  inline gfxIImageFrame* inlinedGetCurrentFrame() {
+    if (!mAnim)
+      return mFrames.SafeObjectAt(0);
+    if (mAnim->lastCompositedFrameIndex == mAnim->currentAnimationFrameIndex)
+      return mAnim->compositingFrame;
+    return mFrames.SafeObjectAt(mAnim->currentAnimationFrameIndex);
+  }
   
   inline Anim* ensureAnimExists() {
     if (!mAnim)
       mAnim = new Anim();
     return mAnim;
   }
   
   /** Function for doing the frame compositing of animations
@@ -274,43 +278,25 @@ private:
    */
   static nsresult DrawFrameTo(gfxIImageFrame *aSrcFrame,
                               gfxIImageFrame *aDstFrame,
                               nsIntRect& aRect);
 
   nsIntSize                  mSize;
   
   //! All the <gfxIImageFrame>s of the PNG
-  // *** IMPORTANT: if you use mFrames in a method, call RestoreDiscardedData() first to ensure
-  //     that the frames actually exist (they may have been discarded to save memory).
   nsCOMArray<gfxIImageFrame> mFrames;
-  int                        mNumFrames; /* stored separately from mFrames.Count() to support discarded images */
   
   nsCOMPtr<nsIProperties>    mProperties;
-
-  // *** IMPORTANT: if you use mAnim in a method, call RestoreDiscardedData() first to ensure
-  //     that the frames actually exist (they may have been discarded to save memory).
+  
   imgContainer::Anim*        mAnim;
   
   //! See imgIContainer for mode constants
   PRUint16                   mAnimationMode;
   
   //! # loops remaining before animation stops (-1 no stop)
   PRInt32                    mLoopCount;
   
   //! imgIContainerObserver
   nsWeakPtr                  mObserver;
-
-  PRBool                     mDiscardable;
-  PRBool                     mDiscarded;
-  nsCString                  mDiscardableMimeType;
-
-  nsTArray<char>             mRestoreData;
-  PRBool                     mRestoreDataDone;
-  nsCOMPtr<nsITimer>         mDiscardTimer;
-
-  nsresult ResetDiscardTimer (void);
-  nsresult RestoreDiscardedData (void);
-  nsresult ReloadImages (void);
-  static void sDiscardTimerCallback (nsITimer *aTimer, void *aClosure);
 };
 
 #endif /* __imgContainer_h__ */