Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
authorJoe Drew <joe@drew.ca>
Mon, 20 Jul 2009 18:50:15 -0700
changeset 30479 b94bc4be53ca18e7d33b27f5c829131423137a0d
parent 30478 43f2b453b68dcb0badba6e3e3ec420f8199c7ec0
child 30481 cb3a833096f62874bc5708cf42ca8c5de1aec512
push idunknown
push userunknown
push dateunknown
reviewersroc, josh, bz, longsonr, vlad, karlt, jimm, bsmedberg, mfinkle, peterw, peterv, vlad, roc
bugs753
milestone1.9.2a1pre
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
accessible/src/html/nsHTMLImageAccessible.cpp
browser/components/build/Makefile.in
browser/components/shell/src/nsGNOMEShellService.cpp
browser/components/shell/src/nsWindowsShellService.cpp
content/base/public/nsContentUtils.h
content/base/src/nsContentAreaDragDrop.cpp
content/base/src/nsContentAreaDragDrop.h
content/base/src/nsContentUtils.cpp
content/base/src/nsCopySupport.cpp
content/base/src/nsImageLoadingContent.cpp
content/base/src/nsStubImageDecoderObserver.cpp
content/svg/content/src/nsSVGFilters.cpp
editor/libeditor/html/nsHTMLDataTransfer.cpp
editor/libeditor/html/nsHTMLEditor.cpp
gfx/idl/Makefile.in
gfx/idl/gfxIImageFrame.idl
gfx/public/Makefile.in
gfx/public/nsIImage.h
gfx/src/Makefile.in
gfx/src/shared/Makefile.in
gfx/src/shared/gfxImageFrame.cpp
gfx/src/shared/gfxImageFrame.h
gfx/src/thebes/Makefile.in
gfx/src/thebes/nsThebesGfxFactory.cpp
gfx/src/thebes/nsThebesImage.cpp
gfx/src/thebes/nsThebesImage.h
gfx/src/thebes/nsThebesRenderingContext.cpp
gfx/src/thebes/nsThebesRenderingContext.h
layout/base/nsCSSRendering.cpp
layout/base/nsCSSRenderingBorders.cpp
layout/base/nsDisplayList.cpp
layout/base/nsImageLoader.cpp
layout/base/nsImageLoader.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/base/nsPresContext.h
layout/forms/nsHTMLButtonControlFrame.cpp
layout/forms/nsImageControlFrame.cpp
layout/generic/nsBulletFrame.cpp
layout/generic/nsBulletFrame.h
layout/generic/nsFrame.cpp
layout/generic/nsImageFrame.cpp
layout/generic/nsImageFrame.h
layout/reftests/svg/image-scaling-02.svg
layout/svg/base/src/nsSVGImageFrame.cpp
layout/xul/base/src/nsImageBoxFrame.cpp
layout/xul/base/src/nsImageBoxFrame.h
layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
layout/xul/base/src/tree/src/nsTreeImageListener.cpp
layout/xul/base/src/tree/src/nsTreeImageListener.h
modules/libpr0n/build/nsImageModule.cpp
modules/libpr0n/decoders/bmp/nsBMPDecoder.cpp
modules/libpr0n/decoders/bmp/nsBMPDecoder.h
modules/libpr0n/decoders/bmp/nsICODecoder.cpp
modules/libpr0n/decoders/bmp/nsICODecoder.h
modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp
modules/libpr0n/decoders/gif/nsGIFDecoder2.h
modules/libpr0n/decoders/icon/nsIconDecoder.cpp
modules/libpr0n/decoders/icon/nsIconDecoder.h
modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp
modules/libpr0n/decoders/jpeg/nsJPEGDecoder.h
modules/libpr0n/decoders/png/nsPNGDecoder.cpp
modules/libpr0n/decoders/png/nsPNGDecoder.h
modules/libpr0n/decoders/xbm/nsXBMDecoder.cpp
modules/libpr0n/decoders/xbm/nsXBMDecoder.h
modules/libpr0n/public/imgIContainer.idl
modules/libpr0n/public/imgIContainerObserver.idl
modules/libpr0n/public/imgIDecoderObserver.idl
modules/libpr0n/src/Makefile.in
modules/libpr0n/src/imgContainer.cpp
modules/libpr0n/src/imgContainer.h
modules/libpr0n/src/imgFrame.cpp
modules/libpr0n/src/imgFrame.h
modules/libpr0n/src/imgRequest.cpp
modules/libpr0n/src/imgRequestProxy.cpp
modules/libpr0n/src/imgRequestProxy.h
modules/libpr0n/src/imgTools.cpp
modules/libpr0n/test/unit/test_imgtools.js
toolkit/library/libxul-config.mk
toolkit/system/gnome/nsAlertsIconListener.cpp
tools/trace-malloc/rules.txt
widget/src/cocoa/nsClipboard.mm
widget/src/cocoa/nsDragService.mm
widget/src/cocoa/nsMenuItemIconX.mm
widget/src/gtk2/nsClipboard.cpp
widget/src/gtk2/nsIImageToPixbuf.h
widget/src/gtk2/nsImageToPixbuf.cpp
widget/src/gtk2/nsImageToPixbuf.h
widget/src/gtk2/nsWindow.cpp
widget/src/os2/nsWindow.cpp
widget/src/os2/nsWindow.h
widget/src/qt/nsWindow.cpp
widget/src/windows/nsClipboard.cpp
widget/src/windows/nsDataObj.cpp
widget/src/windows/nsImageClipboard.cpp
widget/src/windows/nsImageClipboard.h
widget/src/windows/nsWindow.cpp
widget/src/xpwidgets/nsBaseDragService.cpp
--- a/accessible/src/html/nsHTMLImageAccessible.cpp
+++ b/accessible/src/html/nsHTMLImageAccessible.cpp
@@ -110,19 +110,19 @@ nsHTMLImageAccessible::GetStateInternal(
     content->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
                         getter_AddRefs(imageRequest));
 
   nsCOMPtr<imgIContainer> imgContainer;
   if (imageRequest)
     imageRequest->GetImage(getter_AddRefs(imgContainer));
 
   if (imgContainer) {
-    PRUint32 numFrames;
-    imgContainer->GetNumFrames(&numFrames);
-    if (numFrames > 1)
+    PRBool animated;
+    imgContainer->GetAnimated(&animated);
+    if (animated)
       *aState |= nsIAccessibleStates::STATE_ANIMATED;
   }
 
   return NS_OK;
 }
 
 nsresult
 nsHTMLImageAccessible::GetNameInternal(nsAString& aName)
--- a/browser/components/build/Makefile.in
+++ b/browser/components/build/Makefile.in
@@ -86,9 +86,17 @@ EXTRA_DSO_LDOPTS += \
 # Mac: Need to link with CoreFoundation for Mac Migrators (PList reading code)
 # GTK2: Need to link with glib for GNOME shell service
 ifneq (,$(filter mac cocoa gtk2,$(MOZ_WIDGET_TOOLKIT)))
 EXTRA_DSO_LDOPTS += \
   $(TK_LIBS) \
   $(NULL)
 endif
 
+ifndef MOZ_ENABLE_LIBXUL
+ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
+# Doesn't work, couldn't figure out why
+#EXTRA_DSO_LIBS += thebes
+EXTRA_DSO_LDOPTS += $(LIBXUL_DIST)/lib/$(LIB_PREFIX)thebes.$(LIB_SUFFIX)
+endif
+endif
+
 include $(topsrcdir)/config/rules.mk
--- a/browser/components/shell/src/nsGNOMEShellService.cpp
+++ b/browser/components/shell/src/nsGNOMEShellService.cpp
@@ -42,25 +42,23 @@
 #include "nsIProperties.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIPrefService.h"
 #include "prenv.h"
 #include "nsStringAPI.h"
 #include "nsIGConfService.h"
 #include "nsIGnomeVFSService.h"
 #include "nsIStringBundle.h"
-#include "gfxIImageFrame.h"
 #include "nsIOutputStream.h"
 #include "nsIProcess.h"
 #include "nsNetUtil.h"
 #include "nsIDOMHTMLImageElement.h"
 #include "nsIImageLoadingContent.h"
 #include "imgIRequest.h"
 #include "imgIContainer.h"
-#include "nsIImage.h"
 #include "prprf.h"
 #ifdef MOZ_WIDGET_GTK2
 #include "nsIImageToPixbuf.h"
 #endif
 
 #include <glib.h>
 #include <glib-object.h>
 #include <gtk/gtk.h>
@@ -344,66 +342,54 @@ nsGNOMEShellService::SetShouldCheckDefau
 
   if (prefs)
     prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, aShouldCheck);
 
   return NS_OK;
 }
 
 static nsresult
-WriteImage(const nsCString& aPath, gfxIImageFrame* aImage)
+WriteImage(const nsCString& aPath, imgIContainer* aImage)
 {
-  nsCOMPtr<nsIImage> img(do_GetInterface(aImage));
-  if (!img)
-      return NS_ERROR_NOT_AVAILABLE;
-
 #ifndef MOZ_WIDGET_GTK2
   return NS_ERROR_NOT_AVAILABLE;
 #else
   nsCOMPtr<nsIImageToPixbuf> imgToPixbuf =
     do_GetService("@mozilla.org/widget/image-to-gdk-pixbuf;1");
   if (!imgToPixbuf)
       return NS_ERROR_NOT_AVAILABLE;
 
-  GdkPixbuf* pixbuf = imgToPixbuf->ConvertImageToPixbuf(img);
+  GdkPixbuf* pixbuf = imgToPixbuf->ConvertImageToPixbuf(aImage);
   if (!pixbuf)
       return NS_ERROR_NOT_AVAILABLE;
 
   gboolean res = gdk_pixbuf_save(pixbuf, aPath.get(), "png", NULL, NULL);
 
   g_object_unref(pixbuf);
   return res ? NS_OK : NS_ERROR_FAILURE;
 #endif
 }
                  
 NS_IMETHODIMP
 nsGNOMEShellService::SetDesktopBackground(nsIDOMElement* aElement, 
                                           PRInt32 aPosition)
 {
   nsresult rv;
-  nsCOMPtr<gfxIImageFrame> gfxFrame;
-
   nsCOMPtr<nsIImageLoadingContent> imageContent = do_QueryInterface(aElement, &rv);
   if (!imageContent) return rv;
 
   // get the image container
   nsCOMPtr<imgIRequest> request;
   rv = imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
                                 getter_AddRefs(request));
   if (!request) return rv;
   nsCOMPtr<imgIContainer> container;
   rv = request->GetImage(getter_AddRefs(container));
   if (!container) return rv;
 
-  // get the current frame, which holds the image data
-  container->GetCurrentFrame(getter_AddRefs(gfxFrame));
-
-  if (!gfxFrame)
-    return NS_ERROR_FAILURE;
-
   // Write the background file to the home directory.
   nsCAutoString filePath(PR_GetEnv("HOME"));
 
   // get the product brand name from localized strings
   nsString brandName;
   nsCID bundleCID = NS_STRINGBUNDLESERVICE_CID;
   nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(bundleCID));
   if (bundleService) {
@@ -418,17 +404,17 @@ nsGNOMEShellService::SetDesktopBackgroun
   }
 
   // build the file name
   filePath.Append('/');
   filePath.Append(NS_ConvertUTF16toUTF8(brandName));
   filePath.Append("_wallpaper.png");
 
   // write the image to a file in the home dir
-  rv = WriteImage(filePath, gfxFrame);
+  rv = WriteImage(filePath, container);
 
   // if the file was written successfully, set it as the system wallpaper
   nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID);
 
   nsCAutoString options;
   if (aPosition == BACKGROUND_TILE)
     options.Assign("wallpaper");
   else if (aPosition == BACKGROUND_STRETCH)
--- a/browser/components/shell/src/nsWindowsShellService.cpp
+++ b/browser/components/shell/src/nsWindowsShellService.cpp
@@ -36,17 +36,16 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * 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 "gfxIImageFrame.h"
 #include "imgIContainer.h"
 #include "imgIRequest.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMHTMLImageElement.h"
 #include "nsIImageLoadingContent.h"
 #include "nsIPrefService.h"
 #include "nsIPrefLocalizedString.h"
@@ -514,33 +513,28 @@ nsWindowsShellService::SetShouldCheckDef
     pserve->GetBranch("", getter_AddRefs(prefs));
 
   prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, aShouldCheck);
 
   return NS_OK;
 }
 
 static nsresult
-WriteBitmap(nsIFile* aFile, gfxIImageFrame* aImage)
+WriteBitmap(nsIFile* aFile, imgIContainer* aImage)
 {
-  PRInt32 width, height;
-  aImage->GetWidth(&width);
-  aImage->GetHeight(&height);
+  nsRefPtr<gfxImageSurface> image;
+  nsresult rv = aImage->CopyCurrentFrame(getter_AddRefs(image));
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  PRUint8* bits;
-  PRUint32 length;
-  aImage->LockImageData();
-  aImage->GetImageData(&bits, &length);
-  if (!bits) {
-      aImage->UnlockImageData();
-      return NS_ERROR_FAILURE;
-  }
+  PRInt32 width = image->Width();
+  PRInt32 height = image->Height();
 
-  PRUint32 bpr;
-  aImage->GetImageBytesPerRow(&bpr);
+  PRUint8* bits = image->Data();
+  PRUint32 length = image->GetDataSize();
+  PRUint32 bpr = PRUint32(image->Stride());
   PRInt32 bitCount = bpr/width;
 
   // initialize these bitmap structs which we will later
   // serialize directly to the head of the bitmap file
   BITMAPINFOHEADER bmi;
   bmi.biSize = sizeof(BITMAPINFOHEADER);
   bmi.biWidth = width;
   bmi.biHeight = height;
@@ -557,17 +551,17 @@ WriteBitmap(nsIFile* aFile, gfxIImageFra
   bf.bfType = 0x4D42; // 'BM'
   bf.bfReserved1 = 0;
   bf.bfReserved2 = 0;
   bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
   bf.bfSize = bf.bfOffBits + bmi.biSizeImage;
 
   // get a file output stream
   nsCOMPtr<nsIOutputStream> stream;
-  nsresult rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), aFile);
+  rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), aFile);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // write the bitmap headers and rgb pixel data to the file
   rv = NS_ERROR_FAILURE;
   if (stream) {
     PRUint32 written;
     stream->Write((const char*)&bf, sizeof(BITMAPFILEHEADER), &written);
     if (written == sizeof(BITMAPFILEHEADER)) {
@@ -587,56 +581,47 @@ WriteBitmap(nsIFile* aFile, gfxIImageFra
           }
         } while (i != 0);
       }
     }
 
     stream->Close();
   }
 
-  aImage->UnlockImageData();
   return rv;
 }
 
 NS_IMETHODIMP
 nsWindowsShellService::SetDesktopBackground(nsIDOMElement* aElement, 
                                             PRInt32 aPosition)
 {
   nsresult rv;
 
-  nsCOMPtr<gfxIImageFrame> gfxFrame;
-
+  nsCOMPtr<imgIContainer> container;
   nsCOMPtr<nsIDOMHTMLImageElement> imgElement(do_QueryInterface(aElement));
   if (!imgElement) {
     // XXX write background loading stuff!
   } 
   else {
     nsCOMPtr<nsIImageLoadingContent> imageContent =
       do_QueryInterface(aElement, &rv);
     if (!imageContent)
       return rv;
 
     // get the image container
     nsCOMPtr<imgIRequest> request;
     rv = imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
                                   getter_AddRefs(request));
     if (!request)
       return rv;
-    nsCOMPtr<imgIContainer> container;
     rv = request->GetImage(getter_AddRefs(container));
     if (!container)
       return NS_ERROR_FAILURE;
-
-    // get the current frame, which holds the image data
-    container->GetCurrentFrame(getter_AddRefs(gfxFrame));
   }
 
-  if (!gfxFrame)
-    return NS_ERROR_FAILURE;
-
   // get the file name from localized strings
   nsCOMPtr<nsIStringBundleService>
     bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIStringBundle> shellBundle;
   rv = bundleService->CreateBundle(SHELLSERVICE_PROPERTIES,
                                    getter_AddRefs(shellBundle));
@@ -659,17 +644,17 @@ nsWindowsShellService::SetDesktopBackgro
   rv = file->Append(fileLeafName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoString path;
   rv = file->GetPath(path);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // write the bitmap to a file in the profile directory
-  rv = WriteBitmap(file, gfxFrame);
+  rv = WriteBitmap(file, container);
 
   // if the file was written successfully, set it as the system wallpaper
   if (NS_SUCCEEDED(rv)) {
      PRBool result = PR_FALSE;
      DWORD  dwDisp = 0;
      HKEY   key;
      // Try to create/open a subkey under HKLM.
      DWORD res = ::RegCreateKeyExW(HKEY_CURRENT_USER,
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -73,22 +73,22 @@ class nsIDocument;
 class nsIDocShell;
 class nsINameSpaceManager;
 class nsIScriptSecurityManager;
 class nsIJSContextStack;
 class nsIThreadJSContextStack;
 class nsIParserService;
 class nsIIOService;
 class nsIURI;
+class imgIContainer;
 class imgIDecoderObserver;
 class imgIRequest;
 class imgILoader;
 class imgICache;
 class nsIPrefBranch;
-class nsIImage;
 class nsIImageLoadingContent;
 class nsIDOMHTMLFormElement;
 class nsIDOMDocument;
 class nsIConsoleService;
 class nsIStringBundleService;
 class nsIStringBundle;
 class nsIContentPolicy;
 class nsILineBreaker;
@@ -649,23 +649,23 @@ public:
                             imgIRequest** aRequest);
 
   /**
    * Returns whether the given URI is in the image cache.
    */
   static PRBool IsImageInCache(nsIURI* aURI);
 
   /**
-   * Method to get an nsIImage from an image loading content
+   * Method to get an imgIContainer from an image loading content
    *
    * @param aContent The image loading content.  Must not be null.
    * @param aRequest The image request [out]
-   * @return the nsIImage corresponding to the first frame of the image
+   * @return the imgIContainer corresponding to the first frame of the image
    */
-  static already_AddRefed<nsIImage> GetImageFromContent(nsIImageLoadingContent* aContent, imgIRequest **aRequest = nsnull);
+  static already_AddRefed<imgIContainer> GetImageFromContent(nsIImageLoadingContent* aContent, imgIRequest **aRequest = nsnull);
 
   /**
    * Method that decides whether a content node is draggable
    *
    * @param aContent The content node to test.
    * @return whether it's draggable
    */
   static PRBool ContentIsDraggable(nsIContent* aContent);
--- a/content/base/src/nsContentAreaDragDrop.cpp
+++ b/content/base/src/nsContentAreaDragDrop.cpp
@@ -75,29 +75,29 @@
 #include "nsIFile.h"
 #include "nsIWebNavigation.h"
 #include "nsIDocShell.h"
 #include "nsIContent.h"
 #include "nsIImageLoadingContent.h"
 #include "nsINameSpaceManager.h"
 #include "nsUnicharUtils.h"
 #include "nsIURL.h"
-#include "nsIImage.h"
 #include "nsIDocument.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIPrincipal.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIFrame.h"
 #include "nsRange.h"
 #include "nsIWebBrowserPersist.h"
 #include "nsEscape.h"
 #include "nsContentUtils.h"
 #include "nsIMIMEService.h"
+#include "imgIContainer.h"
 #include "imgIRequest.h"
 #include "nsContentCID.h"
 #include "nsDOMDataTransfer.h"
 #include "nsISelectionController.h"
 #include "nsFrameSelection.h"
 #include "nsIDOMEventTarget.h"
 #include "nsWidgetsCID.h"
 
@@ -166,17 +166,17 @@ private:
   nsString mImageDestFileName;
   nsString mTitleString;
   // will be filled automatically if you fill urlstring
   nsString mHtmlString;
   nsString mContextString;
   nsString mInfoString;
 
   PRBool mIsAnchor;
-  nsCOMPtr<nsIImage> mImage;
+  nsCOMPtr<imgIContainer> mImage;
 };
 
 
 //
 // nsContentAreaDragDrop ctor
 //
 nsContentAreaDragDrop::nsContentAreaDragDrop()
   : mNavigator(nsnull)
@@ -967,17 +967,17 @@ nsTransferableFactory::Produce(nsDOMData
 
         if (mTitleString.IsEmpty()) {
           mTitleString = mUrlString;
         }
 
         nsCOMPtr<imgIRequest> imgRequest;
 
         // grab the image data, and its request.
-        nsCOMPtr<nsIImage> img =
+        nsCOMPtr<imgIContainer> img =
           nsContentUtils::GetImageFromContent(image,
                                               getter_AddRefs(imgRequest));
 
         nsCOMPtr<nsIMIMEService> mimeService =
           do_GetService("@mozilla.org/mime;1");
 
         // Fix the file extension in the URL if necessary
         if (imgRequest && mimeService) {
--- a/content/base/src/nsContentAreaDragDrop.h
+++ b/content/base/src/nsContentAreaDragDrop.h
@@ -48,17 +48,16 @@
 #include "nsITransferable.h"
 
 class nsIDOMNode;
 class nsIDOMWindow;
 class nsIDOMDocument;
 class nsIDOMDragEvent;
 class nsISelection;
 class nsITransferable;
-class nsIImage;
 class nsIPresShell;
 class nsPresContext;
 class nsIContent;
 class nsIURI;
 class nsIFile;
 class nsISimpleEnumerator;
 class nsDOMDataTransfer;
 
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -93,18 +93,16 @@
 #include "nsIForm.h"
 #include "nsIFormControl.h"
 #include "nsGkAtoms.h"
 #include "nsISupportsPrimitives.h"
 #include "imgIDecoderObserver.h"
 #include "imgIRequest.h"
 #include "imgIContainer.h"
 #include "imgILoader.h"
-#include "nsIImage.h"
-#include "gfxIImageFrame.h"
 #include "nsIImageLoadingContent.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsILoadGroup.h"
 #include "nsContentPolicyUtils.h"
 #include "nsNodeInfoManager.h"
 #include "nsIXBLService.h"
 #include "nsCRT.h"
@@ -2441,17 +2439,17 @@ nsContentUtils::LoadImage(nsIURI* aURI, 
                                aLoadingDocument,     /* uniquification key */
                                aLoadFlags,           /* load flags */
                                nsnull,               /* cache key */
                                nsnull,               /* existing request*/
                                aRequest);
 }
 
 // static
-already_AddRefed<nsIImage>
+already_AddRefed<imgIContainer>
 nsContentUtils::GetImageFromContent(nsIImageLoadingContent* aContent,
                                     imgIRequest **aRequest)
 {
   if (aRequest) {
     *aRequest = nsnull;
   }
 
   NS_ENSURE_TRUE(aContent, nsnull);
@@ -2465,36 +2463,21 @@ nsContentUtils::GetImageFromContent(nsII
 
   nsCOMPtr<imgIContainer> imgContainer;
   imgRequest->GetImage(getter_AddRefs(imgContainer));
 
   if (!imgContainer) {
     return nsnull;
   }
 
-  nsCOMPtr<gfxIImageFrame> imgFrame;
-  imgContainer->GetFrameAt(0, getter_AddRefs(imgFrame));
-
-  if (!imgFrame) {
-    return nsnull;
-  }
-
-  nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(imgFrame);
-
-  if (!ir) {
-    return nsnull;
-  }
-
   if (aRequest) {
     imgRequest.swap(*aRequest);
   }
 
-  nsIImage* image = nsnull;
-  CallGetInterface(ir.get(), &image);
-  return image;
+  return imgContainer.forget();
 }
 
 // static
 PRBool
 nsContentUtils::ContentIsDraggable(nsIContent* aContent)
 {
   nsCOMPtr<nsIDOMNSHTMLElement> htmlElement = do_QueryInterface(aContent);
   if (htmlElement) {
--- a/content/base/src/nsCopySupport.cpp
+++ b/content/base/src/nsCopySupport.cpp
@@ -44,33 +44,33 @@
 #include "nsIComponentManager.h" 
 #include "nsIServiceManager.h"
 #include "nsIClipboard.h"
 #include "nsISelection.h"
 #include "nsWidgetsCID.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIDOMRange.h"
+#include "imgIContainer.h"
 
 #include "nsIDocShell.h"
 #include "nsIContentViewerEdit.h"
 #include "nsIClipboardDragDropHooks.h"
 #include "nsIClipboardDragDropHookList.h"
 
 #include "nsIDocument.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMDocument.h"
 #include "nsIHTMLDocument.h"
 #include "nsGkAtoms.h"
 
 // image copy stuff
 #include "nsIImageLoadingContent.h"
 #include "nsIInterfaceRequestorUtils.h"
-#include "nsIImage.h"
 #include "nsContentUtils.h"
 #include "nsContentCID.h"
 
 static NS_DEFINE_CID(kCClipboardCID,           NS_CLIPBOARD_CID);
 static NS_DEFINE_CID(kCTransferableCID,        NS_TRANSFERABLE_CID);
 static NS_DEFINE_CID(kHTMLConverterCID,        NS_HTMLFORMATCONVERTER_CID);
 
 // private clipboard data flavors for html copy, used by editor when pasting
@@ -458,17 +458,17 @@ nsCopySupport::ImageCopy(nsIImageLoading
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = AppendDOMNode(trans, node);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (aCopyFlags & nsIContentViewerEdit::COPY_IMAGE_DATA) {
     // get the image data from the element
-    nsCOMPtr<nsIImage> image =
+    nsCOMPtr<imgIContainer> image =
       nsContentUtils::GetImageFromContent(aImageElement);
     NS_ENSURE_TRUE(image, NS_ERROR_FAILURE);
 
     nsCOMPtr<nsISupportsInterfacePointer>
       imgPtr(do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = imgPtr->SetData(image);
--- a/content/base/src/nsImageLoadingContent.cpp
+++ b/content/base/src/nsImageLoadingContent.cpp
@@ -50,17 +50,16 @@
 #include "nsIDocument.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
 #include "nsContentPolicyUtils.h"
 #include "nsIURI.h"
 #include "nsILoadGroup.h"
 #include "imgIContainer.h"
-#include "gfxIImageFrame.h"
 #include "imgILoader.h"
 #include "nsThreadUtils.h"
 #include "nsNetUtil.h"
 
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsIEventStateManager.h"
 #include "nsGUIEvent.h"
@@ -153,20 +152,19 @@ nsImageLoadingContent::~nsImageLoadingCo
   PR_END_MACRO
 
 
 /*
  * imgIContainerObserver impl
  */
 NS_IMETHODIMP
 nsImageLoadingContent::FrameChanged(imgIContainer* aContainer,
-                                    gfxIImageFrame* aFrame,
                                     nsIntRect* aDirtyRect)
 {
-  LOOP_OVER_OBSERVERS(FrameChanged(aContainer, aFrame, aDirtyRect));
+  LOOP_OVER_OBSERVERS(FrameChanged(aContainer, aDirtyRect));
   return NS_OK;
 }
             
 /*
  * imgIDecoderObserver impl
  */
 NS_IMETHODIMP
 nsImageLoadingContent::OnStartRequest(imgIRequest* aRequest)
@@ -191,34 +189,34 @@ nsImageLoadingContent::OnStartContainer(
   // Have to check for state changes here, since we might have been in
   // the LOADING state before.
   UpdateImageState(PR_TRUE);
   return NS_OK;    
 }
 
 NS_IMETHODIMP
 nsImageLoadingContent::OnStartFrame(imgIRequest* aRequest,
-                                    gfxIImageFrame* aFrame)
+                                    PRUint32 aFrame)
 {
   LOOP_OVER_OBSERVERS(OnStartFrame(aRequest, aFrame));
   return NS_OK;    
 }
 
 NS_IMETHODIMP
 nsImageLoadingContent::OnDataAvailable(imgIRequest* aRequest,
-                                       gfxIImageFrame* aFrame,
+                                       PRBool aCurrentFrame,
                                        const nsIntRect* aRect)
 {
-  LOOP_OVER_OBSERVERS(OnDataAvailable(aRequest, aFrame, aRect));
+  LOOP_OVER_OBSERVERS(OnDataAvailable(aRequest, aCurrentFrame, aRect));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsImageLoadingContent::OnStopFrame(imgIRequest* aRequest,
-                                   gfxIImageFrame* aFrame)
+                                   PRUint32 aFrame)
 {
   LOOP_OVER_OBSERVERS(OnStopFrame(aRequest, aFrame));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsImageLoadingContent::OnStopContainer(imgIRequest* aRequest,
                                        imgIContainer* aContainer)
--- a/content/base/src/nsStubImageDecoderObserver.cpp
+++ b/content/base/src/nsStubImageDecoderObserver.cpp
@@ -53,32 +53,32 @@ NS_IMETHODIMP
 nsStubImageDecoderObserver::OnStartContainer(imgIRequest *aRequest,
                                              imgIContainer *aContainer)
 {
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStubImageDecoderObserver::OnStartFrame(imgIRequest *aRequest,
-                                         gfxIImageFrame *aFrame)
+                                         PRUint32 aFrame)
 {
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStubImageDecoderObserver::OnDataAvailable(imgIRequest *aRequest,
-                                            gfxIImageFrame *aFrame,
+                                            PRBool aCurrentFrame,
                                             const nsIntRect * aRect)
 {
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStubImageDecoderObserver::OnStopFrame(imgIRequest *aRequest,
-                                        gfxIImageFrame *aFrame)
+                                        PRUint32 aFrame)
 {
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStubImageDecoderObserver::OnStopContainer(imgIRequest *aRequest,
                                             imgIContainer *aContainer)
 {
@@ -97,13 +97,12 @@ NS_IMETHODIMP
 nsStubImageDecoderObserver::OnStopRequest(imgIRequest *aRequest, 
                                           PRBool aIsLastPart)
 {
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStubImageDecoderObserver::FrameChanged(imgIContainer *aContainer,
-                                         gfxIImageFrame *aFrame,
                                          nsIntRect * aDirtyRect)
 {
     return NS_OK;
 }
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -56,18 +56,16 @@
 #include "nsStyleContext.h"
 #include "nsIDocument.h"
 #include "nsIFrame.h"
 #include "gfxContext.h"
 #include "nsSVGLengthList.h"
 #include "nsIDOMSVGURIReference.h"
 #include "nsImageLoadingContent.h"
 #include "imgIContainer.h"
-#include "gfxIImageFrame.h"
-#include "nsIImage.h"
 #include "nsNetUtil.h"
 #include "nsSVGPreserveAspectRatio.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsSVGMatrix.h"
 #include "nsSVGFilterElement.h"
 #include "nsSVGString.h"
 
 #if defined(XP_WIN) 
@@ -5186,18 +5184,17 @@ public:
                               nsIContent* aBindingParent,
                               PRBool aCompileEventHandlers);
   virtual PRInt32 IntrinsicState() const;
 
   // imgIDecoderObserver
   NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult status,
                           const PRUnichar *statusArg);
   // imgIContainerObserver
-  NS_IMETHOD FrameChanged(imgIContainer *aContainer, gfxIImageFrame *newframe,
-                          nsIntRect *dirtyRect);
+  NS_IMETHOD FrameChanged(imgIContainer *aContainer, nsIntRect *dirtyRect);
   // imgIContainerObserver
   NS_IMETHOD OnStartContainer(imgIRequest *aRequest,
                               imgIContainer *aContainer);
 
   void MaybeLoadSVGImage();
 private:
   // Invalidate users of the filter containing this element.
   void Invalidate();
@@ -5373,41 +5370,37 @@ nsSVGFEImageElement::Filter(nsSVGFilterI
   nsCOMPtr<imgIRequest> currentRequest;
   GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
              getter_AddRefs(currentRequest));
 
   nsCOMPtr<imgIContainer> imageContainer;
   if (currentRequest)
     currentRequest->GetImage(getter_AddRefs(imageContainer));
 
-  nsCOMPtr<gfxIImageFrame> currentFrame;
+  nsRefPtr<gfxASurface> currentFrame;
   if (imageContainer)
     imageContainer->GetCurrentFrame(getter_AddRefs(currentFrame));
 
-  nsRefPtr<gfxPattern> thebesPattern = nsnull;
-  if (currentFrame) {
-    nsCOMPtr<nsIImage> img(do_GetInterface(currentFrame));
-
-    img->GetPattern(getter_AddRefs(thebesPattern));
-  }
+  // We need to wrap the surface in a pattern to have somewhere to set the
+  // graphics filter.
+  nsRefPtr<gfxPattern> thebesPattern;
+  if (currentFrame)
+    thebesPattern = new gfxPattern(currentFrame);
 
   if (thebesPattern) {
     thebesPattern->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(frame));
 
-    PRInt32 x, y, nativeWidth, nativeHeight;
-    currentFrame->GetX(&x);
-    currentFrame->GetY(&y);
-    currentFrame->GetWidth(&nativeWidth);
-    currentFrame->GetHeight(&nativeHeight);
+    PRInt32 nativeWidth, nativeHeight;
+    imageContainer->GetWidth(&nativeWidth);
+    imageContainer->GetHeight(&nativeHeight);
 
     nsCOMPtr<nsIDOMSVGMatrix> trans;
     const gfxRect& filterSubregion = aTarget->mFilterPrimitiveSubregion;
     trans = nsSVGUtils::GetViewBoxTransform(filterSubregion.Width(), filterSubregion.Height(),
-                                            x, y,
-                                            nativeWidth, nativeHeight,
+                                            0, 0, nativeWidth, nativeHeight,
                                             mPreserveAspectRatio);
     nsCOMPtr<nsIDOMSVGMatrix> xy, fini;
     NS_NewSVGMatrix(getter_AddRefs(xy), 1, 0, 0, 1, filterSubregion.X(), filterSubregion.Y());
     xy->Multiply(trans, getter_AddRefs(fini));
 
     gfxContext ctx(aTarget->mImage);
     nsSVGUtils::CompositePatternMatrix(&ctx, thebesPattern, fini, nativeWidth, nativeHeight, 1.0);
   }
@@ -5452,21 +5445,20 @@ nsSVGFEImageElement::OnStopDecode(imgIRe
   nsresult rv =
     nsImageLoadingContent::OnStopDecode(aRequest, status, statusArg);
   Invalidate();
   return rv;
 }
 
 NS_IMETHODIMP
 nsSVGFEImageElement::FrameChanged(imgIContainer *aContainer,
-                                  gfxIImageFrame *newframe,
                                   nsIntRect *dirtyRect)
 {
   nsresult rv =
-    nsImageLoadingContent::FrameChanged(aContainer, newframe, dirtyRect);
+    nsImageLoadingContent::FrameChanged(aContainer, dirtyRect);
   Invalidate();
   return rv;
 }
 
 NS_IMETHODIMP
 nsSVGFEImageElement::OnStartContainer(imgIRequest *aRequest,
                                       imgIContainer *aContainer)
 {
--- a/editor/libeditor/html/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/html/nsHTMLDataTransfer.cpp
@@ -80,17 +80,16 @@
 #include "nsIComponentManager.h"
 #include "nsIServiceManager.h"
 #include "nsIDocumentEncoder.h"
 #include "nsIDOMDocumentFragment.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIParser.h"
 #include "nsParserCIID.h"
-#include "nsIImage.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsLinebreakConverter.h"
 #include "nsIFragmentContentSink.h"
 #include "nsIContentSink.h"
 
 // netwerk
 #include "nsIURI.h"
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -88,17 +88,16 @@
 #include "nsContentUtils.h"
 #include "nsIURL.h"
 #include "nsIComponentManager.h"
 #include "nsIServiceManager.h"
 #include "nsIDocumentEncoder.h"
 #include "nsIDOMDocumentFragment.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
-#include "nsIImage.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "SetDocTitleTxn.h"
 #include "nsGUIEvent.h"
 #include "nsTextFragment.h"
 
 // netwerk
 #include "nsIURI.h"
--- a/gfx/idl/Makefile.in
+++ b/gfx/idl/Makefile.in
@@ -45,14 +45,13 @@ include $(DEPTH)/config/autoconf.mk
 MODULE		= gfx
 XPIDL_MODULE	= gfx
 GRE_MODULE	= 1
 
 XPIDLSRCS	= \
 		nsIFontEnumerator.idl \
 		nsIScriptableRegion.idl \
 		gfxIFormats.idl \
-		gfxIImageFrame.idl \
 		gfxidltypes.idl \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
deleted file mode 100644
--- a/gfx/idl/gfxIImageFrame.idl
+++ /dev/null
@@ -1,168 +0,0 @@
-/** -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * 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>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of 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
- * decision by deleting the provisions above and replace them with the notice
- * 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 "nsISupports.idl"
-#include "gfxidltypes.idl"
-#include "gfxIFormats.idl"
-
-%{C++
-#include "nsRect.h"
-%}
-
-native nsRectRef(nsIntRect &);
-
-/**
- * gfxIImageFrame interface
- *
- * All x, y, width, height values are in pixels.
- *
- * @author Tim Rowley <tor@cs.brown.edu>
- * @author Stuart Parmenter <pavlov@netscape.com>
- * @version 0.1
- */
-[scriptable, uuid(9c37930b-cadd-453c-89e1-9ed456715b9c)]
-interface gfxIImageFrame : nsISupports
-{
-  /**
-   * Create a new \a aWidth x \a aHeight sized image.
-   *
-   * @param aX The x-offset from the origin of the gfxIImageContainer parent.
-   * @param aY The y-offset from the origin of the gfxIImageContainer parent.
-   * @param aWidth The width of the image to create.
-   * @param aHeight The height of the image to create.
-   * @param aFormat the width of the image to create.
-   *
-   * @note The data in a new image is uninitialized.
-   */
-  void init(in PRInt32 aX,
-            in PRInt32 aY,
-            in PRInt32 aWidth,
-            in PRInt32 aHeight,
-            in gfx_format aFormat,
-            in gfx_depth aDepth);
-
-  /**
-   * TRUE by default.  When set to FALSE, you will no longer be able to make any modifications
-   * to the data of the image.  Any attempts will fail.
-   */
-  attribute boolean mutable;
-
-  /**
-   * The x-offset of the image.
-   */
-  readonly attribute PRInt32 x;
-
-  /**
-   * The y-offset of the image.
-   */
-  readonly attribute PRInt32 y;
-
-  /**
-   * The width of the image.
-   */
-  readonly attribute PRInt32 width;
-
-  /**
-   * The height of the image.
-   */
-  readonly attribute PRInt32 height;
-
-  /**
-   * The rectangle this frame ocupies.
-   * @param rect this is really an out parameter.
-   */
-  [noscript] void getRect(in nsRectRef rect);
-
-  /**
-   * The image data format the image was created with.
-   * @see gfxIFormats
-   */
-  readonly attribute gfx_format format;
-
-  /**
-   * returns whether the image requires the background to be painted
-   */
-  readonly attribute boolean needsBackground;
-
-  /* data accessors */
-  readonly attribute unsigned long imageBytesPerRow;
-
-  /**
-   * returns the number of bytes allocated for the image
-   */
-  readonly attribute unsigned long imageDataLength;
-
-  // XXX do we copy here?  lets not...
-  void getImageData([array, size_is(length)] out PRUint8 bits, out unsigned long length);
-
-  /**
-   * Get Palette data pointer
-   */
-  void getPaletteData([array, size_is(length)] out gfx_color palette, out unsigned long length);
-
-  /**
-   * Lock image pixels before addressing the data directly
-   */
-  void lockImageData();
-
-  /**
-   * Unlock image pixels
-   */
-  void unlockImageData();
-
-
-  /* GIF Specific methods.  These should be in a different class or interface. */
-
-  /**
-   * Represents the number of milliseconds until the next frame should be displayed.
-   * @note -1 means that this frame should be displayed forever.
-   */
-  attribute long timeout;
-
-  /* frame disposal method, used only by GIFs. Should probably subclass image frame
-   * and image container for GIFs special needs, but for simplicity it is here for the
-   * moment
-   */
-  attribute long frameDisposalMethod;
-
-  /* PNG specific methods */
-
-  attribute long blendMethod;
-};
--- a/gfx/public/Makefile.in
+++ b/gfx/public/Makefile.in
@@ -55,17 +55,16 @@ EXPORTS		= \
 		nsRegion.h \
 		nsPoint.h \
 		nsSize.h \
 		nsMargin.h \
 		nsTransform2D.h \
 		nsIRenderingContext.h \
 		nsIFontMetrics.h \
 		nsIDeviceContext.h \
-		nsIImage.h \
 		nsGfxCIID.h \
 		nsIRegion.h \
 		nsITheme.h \
 		nsThemeConstants.h \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
deleted file mode 100644
--- a/gfx/public/nsIImage.h
+++ /dev/null
@@ -1,307 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of 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
- * decision by deleting the provisions above and replace them with the notice
- * 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 ***** */
-
-#ifndef nsIImage_h___
-#define nsIImage_h___
-
-#include "nsISupports.h"
-#include "nsMargin.h"
-#include "nsRect.h"
-#include "gfxPattern.h"
-
-class gfxASurface;
-struct gfxMatrix;
-struct gfxRect;
-class gfxContext;
-
-class nsIDeviceContext;
-
-struct nsColorMap
-{
-  //I lifted this from the image lib. The difference is that
-  //this uses nscolor instead of NI_RGB. Multiple color pollution
-  //is a bad thing. MMP
-  PRInt32 NumColors;  // Number of colors in the colormap.
-                      // A negative value can be used to denote a
-                      // possibly non-unique set.
-  //nscolor *Map;       // Colormap colors.
-  PRUint8 *Index;     // NULL, if map is in index order, otherwise
-                      // specifies the indices of the map entries. */
-};
-
-typedef enum {
-    nsMaskRequirements_kNoMask,
-    nsMaskRequirements_kNeeds1Bit,
-    nsMaskRequirements_kNeeds8Bit
-} nsMaskRequirements;
-
-
-#define  nsImageUpdateFlags_kColorMapChanged 0x1
-#define  nsImageUpdateFlags_kBitsChanged     0x2
-
-// IID for the nsIImage interface
-// 0358ce68-b076-43b0-8f5c-36ed4592822c
-#define NS_IIMAGE_IID \
-  { 0x358ce68, 0xb076, 0x43b0, \
-    { 0x8f, 0x5c, 0x36, 0xed, 0x45, 0x92, 0x82, 0x2c } }
-
-// Interface to Images
-class nsIImage : public nsISupports
-{
-
-public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IIMAGE_IID)
-
-  /**
-   * Build and initialize the nsIImage
-   * @param aWidth The width in pixels of the desired pixelmap
-   * @param aHeight The height in pixels of the desired pixelmap
-   * @param aDepth The number of bits per pixel for the pixelmap
-   * @param aMaskRequirements A flag indicating if a alpha mask should be allocated 
-   */
-  virtual nsresult Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequirements aMaskRequirements) = 0;
-
-  /**
-   * Get the number of bytes per pixel for this image
-   * @update - dwc 2/3/99
-   * @return - the number of bytes per pixel
-   */
-  virtual PRInt32 GetBytesPix() = 0;
-
-  /**
-   * Get whether rows are organized top to bottom, or bottom to top 
-   * @update - syd 3/29/99 
-   * @return PR_TRUE if top to bottom, else PR_FALSE 
-   */
-  virtual PRBool GetIsRowOrderTopToBottom() = 0;
-
-  /**
-   * Get the width for the pixelmap
-   * @update - dwc 2/1/99
-   * @return The width in pixels for the pixelmap
-   */
-  virtual PRInt32 GetWidth() = 0;
-
-  /**
-   * Get the height for the pixelmap
-   * @update - dwc 2/1/99
-   * @return The height in pixels for the pixelmap
-   */
-  virtual PRInt32 GetHeight() = 0;
-
-  /**
-   * Get a pointer to the bits for the pixelmap, only if it is not optimized
-   * @update - dwc 2/1/99
-   * @return address of the DIB pixel array
-   */
-  virtual PRUint8 * GetBits() = 0;
-
-  /**
-   * Get the number of bytes needed to get to the next scanline for the pixelmap
-   * @update - dwc 2/1/99
-   * @return The number of bytes in each scanline
-   */
-  virtual PRInt32 GetLineStride() = 0;
-
-  /**
-   * Get whether this image has an alpha mask. Preferable to testing
-   * if GetAlphaBits() is non-null.
-   * @update - sfraser 10/19/99
-   * @return PR_TRUE if the image has an alpha mask, PR_FALSE otherwise
-   */
-  virtual PRBool GetHasAlphaMask() = 0;
-
-  /**
-   * Get a pointer to the bits for the alpha mask
-   * @update - dwc 2/1/99
-   * @return address of the alpha mask pixel array
-   */
-  virtual PRUint8 * GetAlphaBits() = 0;
-
-  /**
-   * Get the number of bytes per scanline for the alpha mask
-   * @update - dwc 2/1/99
-   * @return The number of bytes in each scanline
-   */
-  virtual PRInt32 GetAlphaLineStride() = 0;
-
-  /**
-   * Update the nsIImage color table
-   * @update - dougt 9/9/08
-   * @param aFlags Used to pass in parameters for the update
-   * @param aUpdateRect The rectangle to update
-   * @return success code. failure means stop decoding
-   */
-  virtual nsresult ImageUpdated(nsIDeviceContext *aContext, PRUint8 aFlags, nsIntRect *aUpdateRect) = 0;
-  
-  /**
-   * Get whether this image's region is completely filled with data.
-   * @return PR_TRUE if image is complete, PR_FALSE if image is not yet 
-   *         complete or broken
-   */
-  virtual PRBool GetIsImageComplete() = 0;
-
-  /**
-   * Converted this pixelmap to an optimized pixelmap for the device
-   * @update - dwc 2/1/99
-   * @param aContext The device to optimize for
-   * @return the result of the operation, if NS_OK, then the pixelmap is optimized
-   */
-  virtual nsresult Optimize(nsIDeviceContext* aContext) = 0;
-
-  /**
-   * Get the colormap for the nsIImage
-   * @update - dwc 2/1/99
-   * @return if non null, the colormap for the pixelmap,otherwise the image is not color mapped
-   */
-  virtual nsColorMap * GetColorMap() = 0;
-
-  /**
-   * BitBlit the nsIImage to a device, the source and dest can be scaled.
-   * @param aContext the destination
-   * @param aFilter the filter for the image
-   * @param aUserSpaceToImageSpace the transform that maps user-space
-   * coordinates to coordinates in (tiled, post-padding) image pixels
-   * @param aFill the area to fill with tiled images
-   * @param aPadding the padding to be added to this image before tiling,
-   * in image pixels
-   * @param aSubimage the subimage in padded+tiled image space that we're
-   * extracting the contents from. Pixels outside this rectangle must not
-   * be sampled.
-   * 
-   * So this is supposed to
-   * -- add aPadding transparent pixels around the image
-   * -- use that image to tile the plane
-   * -- replace everything outside the aSubimage region with the nearest
-   * border pixel of that region (like EXTEND_PAD)
-   * -- fill aFill with the image, using aImageSpaceToDeviceSpace as the
-   * image-space-to-device-space transform
-   */
-  virtual void Draw(gfxContext*        aContext,
-                    gfxPattern::GraphicsFilter aFilter,
-                    const gfxMatrix&   aUserSpaceToImageSpace,
-                    const gfxRect&     aFill,
-                    const nsIntMargin& aPadding,
-                    const nsIntRect&   aSubimage) = 0;
-
-  /** 
-   * Get the alpha depth for the image mask
-   * @update - lordpixel 2001/05/16
-   * @return  the alpha mask depth for the image, ie, 0, 1 or 8
-   */
-  virtual PRInt8 GetAlphaDepth() = 0;
-
-  /**
-   * Return information about the bits for this structure
-   * @update - dwc 2/1/99
-   * @return a bitmap info structure for the Device Dependent Bits
-   */
-  virtual void* GetBitInfo() = 0;
-
-
-  /**
-   * LockImagePixels
-   * Lock the image pixels so that we can access them directly,
-   * with safety. May be a noop on some platforms.
-   *
-   * If you want to be able to call GetSurface(), wrap the call in
-   * LockImagePixels()/UnlockImagePixels(). This also allows you to write to
-   * the surface returned by GetSurface().
-   *
-   * aMaskPixels = PR_TRUE for the mask, PR_FALSE for the image
-   *
-   * Must be balanced by a call to UnlockImagePixels().
-   *
-   * @update - sfraser 10/18/99
-   * @return error result
-   */
-  NS_IMETHOD LockImagePixels(PRBool aMaskPixels) = 0;
-  
-  /**
-   * UnlockImagePixels
-   * Unlock the image pixels. May be a noop on some platforms.
-   *
-   * Should balance an earlier call to LockImagePixels().
-   *
-   * 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;
-
-  /**
-   * GetSurface
-   * Return the Thebes gfxASurface in aSurface, if there is one. Should be
-   * wrapped by LockImagePixels()/UnlockImagePixels().
-   *
-   * aSurface will be AddRef'd (as with most getters), so
-   * getter_AddRefs should be used.
-   */
-  NS_IMETHOD GetSurface(gfxASurface **aSurface) = 0;
-
-  /**
-   * GetSurface
-   * Return the Thebes gfxPattern in aPattern. It is always possible to get a
-   * gfxPattern (unlike the gfxASurface from GetSurface()).
-   *
-   * aPattern will be AddRef'd (as with most getters), so
-   * getter_AddRefs should be used.
-   */
-  NS_IMETHOD GetPattern(gfxPattern **aPattern) = 0;
-
-  /**
-   * 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;
-
-  /**
-   * Extract a rectangular region of the nsIImage and return it as a new
-   * nsIImage.
-   * @param aSubimage  the region to extract
-   * @param aResult    the extracted image
-   */
-  NS_IMETHOD Extract(const nsIntRect& aSubimage,
-                     nsIImage** aResult NS_OUTPARAM) = 0;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsIImage, NS_IIMAGE_IID)
-
-#endif
--- a/gfx/src/Makefile.in
+++ b/gfx/src/Makefile.in
@@ -54,17 +54,17 @@ REQUIRES	= xpcom \
 		  locale \
 		  view \
 		  unicharutil \
 		  thebes \
 		  js \
 		  xpconnect \
 		  $(NULL)
 
-DIRS        = shared thebes
+DIRS        = thebes
 
 ifdef MOZ_ENABLE_POSTSCRIPT
 DIRS        += psshared
 endif
 
 CPPSRCS = \
         nsColor.cpp \
         nsFont.cpp \
deleted file mode 100644
--- a/gfx/src/shared/Makefile.in
+++ /dev/null
@@ -1,67 +0,0 @@
-#
-# ***** BEGIN LICENSE BLOCK *****
-# Version: MPL 1.1/GPL 2.0/LGPL 2.1
-#
-# The contents of this file are subject to the Mozilla Public License Version
-# 1.1 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-# http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS IS" basis,
-# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-# for the specific language governing rights and limitations under the
-# License.
-#
-# The Original Code is mozilla.org code.
-#
-# 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):
-#
-# Alternatively, the contents of this file may be used under the terms of
-# either of 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
-# decision by deleting the provisions above and replace them with the notice
-# 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 *****
-
-DEPTH		= ../../..
-topsrcdir	= @top_srcdir@
-srcdir		= @srcdir@
-VPATH		= @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-MODULE = gfx
-LIBRARY_NAME = gfxshared_s
-FORCE_STATIC_LIB=1
-EXPORT_LIBRARY=1
-LIBXUL_LIBRARY = 1
-
-REQUIRES= \
-		  xpcom \
-		  string \
-		  imglib2 \
-		  widget \
-		  thebes \
-		  $(NULL)
-
-CPPSRCS = \
-	gfxImageFrame.cpp \
-	$(NULL)
-
-LOCAL_INCLUDES = -I$(srcdir)/.. \
-                 $(NULL)
-
-include $(topsrcdir)/config/rules.mk
-
--- a/gfx/src/thebes/Makefile.in
+++ b/gfx/src/thebes/Makefile.in
@@ -67,17 +67,16 @@ REQUIRES =  xpcom \
             $(NULL)
 
 ifeq (,$(filter windows,$(MOZ_WIDGET_TOOLKIT)))
 REQUIRES += uconv
 endif
 
 CPPSRCS		= \
 		nsThebesDeviceContext.cpp \
-		nsThebesImage.cpp \
 		nsThebesRegion.cpp \
 		nsThebesGfxFactory.cpp \
 		nsThebesRenderingContext.cpp \
 		nsThebesFontMetrics.cpp \
 		nsThebesFontEnumerator.cpp \
 		$(NULL)
 
 
@@ -123,17 +122,16 @@ EXPORTS         += nsIThebesFontMetrics.
 
 LOCAL_INCLUDES	= \
 		-I$(srcdir)/. \
 		-I$(srcdir)/.. \
 		-I$(srcdir)/../shared \
 		$(NULL)
 
 EXTRA_DSO_LDOPTS += \
-		../shared/$(LIB_PREFIX)gfxshared_s.$(LIB_SUFFIX) \
 		$(LIBS_DIR) \
 		$(EXTRA_DSO_LIBS) \
 		$(DEPTH)/modules/libutil/src/$(LIB_PREFIX)mozutil_s.$(LIB_SUFFIX) \
 		$(MOZ_COMPONENT_LIBS) \
 		$(MOZ_UNICHARUTIL_LIBS) \
 		$(MOZ_JS_LIBS) \
 		$(TK_LIBS) \
 		$(NULL)
--- a/gfx/src/thebes/nsThebesGfxFactory.cpp
+++ b/gfx/src/thebes/nsThebesGfxFactory.cpp
@@ -37,31 +37,27 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsIGenericFactory.h"
 #include "nsIModule.h"
 #include "nsCOMPtr.h"
 #include "nsGfxCIID.h"
 
 #include "nsScriptableRegion.h"
-#include "gfxImageFrame.h"
 
 #include "nsThebesDeviceContext.h"
 #include "nsThebesRenderingContext.h"
-#include "nsThebesImage.h"
 #include "nsThebesRegion.h"
 #include "nsThebesFontMetrics.h"
 #include "nsThebesFontEnumerator.h"
 #include "gfxPlatform.h"
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsThebesFontMetrics)
-NS_GENERIC_FACTORY_CONSTRUCTOR(gfxImageFrame)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsThebesDeviceContext)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsThebesRenderingContext)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsThebesImage)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsThebesRegion)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsThebesFontEnumerator)
 
 static NS_IMETHODIMP nsScriptableRegionConstructor(nsISupports *aOuter, REFNSIID aIID, void **aResult)
 {
   nsresult rv;
 
   nsIScriptableRegion *inst = nsnull;
@@ -114,32 +110,24 @@ static const nsModuleComponentInfo compo
   { "Thebes Device Context",
     NS_DEVICE_CONTEXT_CID,
     "@mozilla.org/gfx/devicecontext;1",
     nsThebesDeviceContextConstructor },
   { "Thebes Rendering Context",
     NS_RENDERING_CONTEXT_CID,
     "@mozilla.org/gfx/renderingcontext;1",
     nsThebesRenderingContextConstructor },
-  { "Thebes nsImage",
-    NS_IMAGE_CID,
-    "@mozilla.org/gfx/image;1",
-    nsThebesImageConstructor },
   { "Thebes Region",
     NS_REGION_CID,
     "@mozilla.org/gfx/region/nsThebes;1",
     nsThebesRegionConstructor },
   { "Scriptable Region",
     NS_SCRIPTABLE_REGION_CID,
     "@mozilla.org/gfx/region;1",
     nsScriptableRegionConstructor },
-  { "image frame",
-    GFX_IMAGEFRAME_CID,
-    "@mozilla.org/gfx/image/frame;2",
-    gfxImageFrameConstructor },
 };
 
 static nsresult
 nsThebesGfxModuleCtor(nsIModule *self)
 {
     return gfxPlatform::Init();
 }
 
deleted file mode 100644
--- a/gfx/src/thebes/nsThebesImage.cpp
+++ /dev/null
@@ -1,857 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is thebes gfx
- *
- * The Initial Developer of the Original Code is
- * mozilla.org.
- * Portions created by the Initial Developer are Copyright (C) 2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Vladimir Vukicevic <vladimir@pobox.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
- * decision by deleting the provisions above and replace them with the notice
- * 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 "nsThebesImage.h"
-#include "nsThebesRenderingContext.h"
-
-#include "gfxContext.h"
-#include "gfxPattern.h"
-
-#include "gfxPlatform.h"
-
-#include "prenv.h"
-
-static PRBool gDisableOptimize = PR_FALSE;
-
-/*XXX get CAIRO_HAS_DDRAW_SURFACE */
-#include "cairo.h"
-
-#ifdef CAIRO_HAS_DDRAW_SURFACE
-#include "gfxDDrawSurface.h"
-#endif
-
-#if defined(XP_WIN) || defined(WINCE)
-#include "gfxWindowsPlatform.h"
-#endif
-
-#if defined(XP_WIN) && !defined(WINCE)
-
-/* Whether to use the windows surface; only for desktop win32 */
-#define USE_WIN_SURFACE 1
-
-static PRUint32 gTotalDDBs = 0;
-static PRUint32 gTotalDDBSize = 0;
-// only use up a maximum of 64MB in DDBs
-#define kMaxDDBSize (64*1024*1024)
-// and don't let anything in that's bigger than 4MB
-#define kMaxSingleDDBSize (4*1024*1024)
-
-#endif
-
-NS_IMPL_ISUPPORTS1(nsThebesImage, nsIImage)
-
-nsThebesImage::nsThebesImage()
-    : mFormat(gfxImageSurface::ImageFormatRGB24),
-      mWidth(0),
-      mHeight(0),
-      mDecoded(0,0,0,0),
-      mImageComplete(PR_FALSE),
-      mSinglePixel(PR_FALSE),
-      mFormatChanged(PR_FALSE),
-      mNeverUseDeviceSurface(PR_FALSE),
-      mSinglePixelColor(0),
-      mAlphaDepth(0)
-{
-    static PRBool hasCheckedOptimize = PR_FALSE;
-    if (!hasCheckedOptimize) {
-        if (PR_GetEnv("MOZ_DISABLE_IMAGE_OPTIMIZE")) {
-            gDisableOptimize = PR_TRUE;
-        }
-        hasCheckedOptimize = PR_TRUE;
-    }
-
-#ifdef USE_WIN_SURFACE
-    mIsDDBSurface = PR_FALSE;
-#endif
-}
-
-nsresult
-nsThebesImage::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequirements aMaskRequirements)
-{
-    mWidth = aWidth;
-    mHeight = aHeight;
-
-    // Reject over-wide or over-tall images.
-    if (!AllowedImageSize(aWidth, aHeight))
-        return NS_ERROR_FAILURE;
-
-    // Check to see if we are running OOM
-    nsCOMPtr<nsIMemory> mem;
-    NS_GetMemoryManager(getter_AddRefs(mem));
-    if (!mem)
-        return NS_ERROR_UNEXPECTED;
-
-    PRBool lowMemory;
-    mem->IsLowMemory(&lowMemory);
-    if (lowMemory)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    gfxImageSurface::gfxImageFormat format;
-    switch(aMaskRequirements)
-    {
-        case nsMaskRequirements_kNeeds1Bit:
-            format = gfxImageSurface::ImageFormatARGB32;
-            mAlphaDepth = 1;
-            break;
-        case nsMaskRequirements_kNeeds8Bit:
-            format = gfxImageSurface::ImageFormatARGB32;
-            mAlphaDepth = 8;
-            break;
-        default:
-            format = gfxImageSurface::ImageFormatRGB24;
-            mAlphaDepth = 0;
-            break;
-    }
-
-    mFormat = format;
-
-    // For Windows, we must create the device surface first (if we're
-    // going to) so that the image surface can wrap it.  Can't be done
-    // the other way around.
-#ifdef USE_WIN_SURFACE
-    if (!mNeverUseDeviceSurface && !ShouldUseImageSurfaces()) {
-        mWinSurface = new gfxWindowsSurface(gfxIntSize(mWidth, mHeight), format);
-        if (mWinSurface && mWinSurface->CairoStatus() == 0) {
-            // no error
-            mImageSurface = mWinSurface->GetImageSurface();
-        } else {
-            mWinSurface = nsnull;
-        }
-    }
-#endif
-
-    // For other platforms we create the image surface first and then
-    // possibly wrap it in a device surface.  This branch is also used
-    // on Windows if we're not using device surfaces or if we couldn't
-    // create one.
-    if (!mImageSurface)
-        mImageSurface = new gfxImageSurface(gfxIntSize(mWidth, mHeight), format);
-
-    if (!mImageSurface || mImageSurface->CairoStatus()) {
-        mImageSurface = nsnull;
-        // guess
-        return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-#ifdef XP_MACOSX
-    if (!mNeverUseDeviceSurface && !ShouldUseImageSurfaces()) {
-        mQuartzSurface = new gfxQuartzImageSurface(mImageSurface);
-    }
-#endif
-
-    mStride = mImageSurface->Stride();
-
-    return NS_OK;
-}
-
-nsThebesImage::~nsThebesImage()
-{
-#ifdef USE_WIN_SURFACE
-    if (mIsDDBSurface) {
-        gTotalDDBs--;
-        gTotalDDBSize -= mWidth*mHeight*4;
-    }
-#endif
-}
-
-PRInt32
-nsThebesImage::GetBytesPix()
-{
-    return 4;
-}
-
-PRBool
-nsThebesImage::GetIsRowOrderTopToBottom()
-{
-    return PR_TRUE;
-}
-
-PRInt32
-nsThebesImage::GetWidth()
-{
-    return mWidth;
-}
-
-PRInt32
-nsThebesImage::GetHeight()
-{
-    return mHeight;
-}
-
-PRUint8 *
-nsThebesImage::GetBits()
-{
-    if (mImageSurface)
-        return mImageSurface->Data();
-    return nsnull;
-}
-
-PRInt32
-nsThebesImage::GetLineStride()
-{
-    return mStride;
-}
-
-PRBool
-nsThebesImage::GetHasAlphaMask()
-{
-    return mAlphaDepth > 0;
-}
-
-PRUint8 *
-nsThebesImage::GetAlphaBits()
-{
-    return nsnull;
-}
-
-PRInt32
-nsThebesImage::GetAlphaLineStride()
-{
-    return (mAlphaDepth > 0) ? mStride : 0;
-}
-
-nsresult
-nsThebesImage::ImageUpdated(nsIDeviceContext *aContext, PRUint8 aFlags, nsIntRect *aUpdateRect)
-{
-    // Check to see if we are running OOM
-    nsCOMPtr<nsIMemory> mem;
-    NS_GetMemoryManager(getter_AddRefs(mem));
-    if (!mem)
-        return NS_ERROR_UNEXPECTED;
-
-    PRBool lowMemory;
-    mem->IsLowMemory(&lowMemory);
-    if (lowMemory)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    mDecoded.UnionRect(mDecoded, *aUpdateRect);
-
-    // clamp to bounds, in case someone sends a bogus
-    // updateRect (I'm looking at you, gif decoder)
-    nsIntRect boundsRect(0, 0, mWidth, mHeight);
-    mDecoded.IntersectRect(mDecoded, boundsRect);
-
-#ifdef XP_MACOSX
-    if (mQuartzSurface)
-        mQuartzSurface->Flush();
-#endif
-    return NS_OK;
-}
-
-PRBool
-nsThebesImage::GetIsImageComplete()
-{
-    if (!mImageComplete)
-        mImageComplete = (mDecoded == nsIntRect(0, 0, mWidth, mHeight));
-    return mImageComplete;
-}
-
-nsresult
-nsThebesImage::Optimize(nsIDeviceContext* aContext)
-{
-    if (gDisableOptimize)
-        return NS_OK;
-
-    if (mOptSurface || mSinglePixel)
-        return NS_OK;
-
-    /* Figure out if the entire image is a constant color */
-
-    // this should always be true
-    if (mStride == mWidth * 4) {
-        PRUint32 *imgData = (PRUint32*) mImageSurface->Data();
-        PRUint32 firstPixel = * (PRUint32*) imgData;
-        PRUint32 pixelCount = mWidth * mHeight + 1;
-
-        while (--pixelCount && *imgData++ == firstPixel)
-            ;
-
-        if (pixelCount == 0) {
-            // all pixels were the same
-            if (mFormat == gfxImageSurface::ImageFormatARGB32 ||
-                mFormat == gfxImageSurface::ImageFormatRGB24)
-            {
-                mSinglePixelColor = gfxRGBA
-                    (firstPixel,
-                     (mFormat == gfxImageSurface::ImageFormatRGB24 ?
-                      gfxRGBA::PACKED_XRGB :
-                      gfxRGBA::PACKED_ARGB_PREMULTIPLIED));
-
-                mSinglePixel = PR_TRUE;
-
-                // blow away the older surfaces, to release data
-
-                mImageSurface = nsnull;
-                mOptSurface = nsnull;
-#ifdef USE_WIN_SURFACE
-                mWinSurface = nsnull;
-#endif
-#ifdef XP_MACOSX
-                mQuartzSurface = nsnull;
-#endif
-                return NS_OK;
-            }
-        }
-
-        // if it's not RGB24/ARGB32, don't optimize, but we never hit this at the moment
-    }
-
-    // if we're being forced to use image surfaces due to
-    // resource constraints, don't try to optimize beyond same-pixel.
-    if (mNeverUseDeviceSurface || ShouldUseImageSurfaces())
-        return NS_OK;
-
-    mOptSurface = nsnull;
-
-#ifdef USE_WIN_SURFACE
-    // we need to special-case windows here, because windows has
-    // a distinction between DIB and DDB and we want to use DDBs as much
-    // as we can.
-    if (mWinSurface) {
-        // Don't do DDBs for large images; see bug 359147
-        // Note that we bother with DDBs at all because they are much faster
-        // on some systems; on others there isn't much of a speed difference
-        // between DIBs and DDBs.
-        //
-        // Originally this just limited to 1024x1024; but that still
-        // had us hitting overall total memory usage limits (which was
-        // around 220MB on my intel shared memory system with 2GB RAM
-        // and 16-128mb in use by the video card, so I can't make
-        // heads or tails out of this limit).
-        //
-        // So instead, we clamp the max size to 64MB (this limit shuld
-        // be made dynamic based on.. something.. as soon a we figure
-        // out that something) and also limit each individual image to
-        // be less than 4MB to keep very large images out of DDBs.
-
-        // assume (almost -- we don't quadword-align) worst-case size
-        PRUint32 ddbSize = mWidth * mHeight * 4;
-        if (ddbSize <= kMaxSingleDDBSize &&
-            ddbSize + gTotalDDBSize <= kMaxDDBSize)
-        {
-            nsRefPtr<gfxWindowsSurface> wsurf = mWinSurface->OptimizeToDDB(nsnull, gfxIntSize(mWidth, mHeight), mFormat);
-            if (wsurf) {
-                gTotalDDBs++;
-                gTotalDDBSize += ddbSize;
-                mIsDDBSurface = PR_TRUE;
-                mOptSurface = wsurf;
-            }
-        }
-        if (!mOptSurface && !mFormatChanged) {
-            // just use the DIB if the format has not changed
-            mOptSurface = mWinSurface;
-        }
-    }
-#endif
-
-#ifdef XP_MACOSX
-    if (mQuartzSurface) {
-        mQuartzSurface->Flush();
-        mOptSurface = mQuartzSurface;
-    }
-#endif
-
-    if (mOptSurface == nsnull)
-        mOptSurface = gfxPlatform::GetPlatform()->OptimizeImage(mImageSurface, mFormat);
-
-    if (mOptSurface) {
-        mImageSurface = nsnull;
-#ifdef USE_WIN_SURFACE
-        mWinSurface = nsnull;
-#endif
-#ifdef XP_MACOSX
-        mQuartzSurface = nsnull;
-#endif
-    }
-
-    return NS_OK;
-}
-
-nsColorMap *
-nsThebesImage::GetColorMap()
-{
-    return NULL;
-}
-
-PRInt8
-nsThebesImage::GetAlphaDepth()
-{
-    return mAlphaDepth;
-}
-
-void *
-nsThebesImage::GetBitInfo()
-{
-    return NULL;
-}
-
-NS_IMETHODIMP
-nsThebesImage::LockImagePixels(PRBool aMaskPixels)
-{
-    if (aMaskPixels)
-        return NS_ERROR_NOT_IMPLEMENTED;
-    if ((mOptSurface || mSinglePixel) && !mImageSurface) {
-        // Recover the pixels
-        mImageSurface = new gfxImageSurface(gfxIntSize(mWidth, mHeight),
-                                            gfxImageSurface::ImageFormatARGB32);
-        if (!mImageSurface || mImageSurface->CairoStatus())
-            return NS_ERROR_OUT_OF_MEMORY;
-        gfxContext context(mImageSurface);
-        context.SetOperator(gfxContext::OPERATOR_SOURCE);
-        if (mSinglePixel)
-            context.SetDeviceColor(mSinglePixelColor);
-        else
-            context.SetSource(mOptSurface);
-        context.Paint();
-
-#ifdef USE_WIN_SURFACE
-        mWinSurface = nsnull;
-#endif
-#ifdef XP_MACOSX
-        mQuartzSurface = nsnull;
-#endif
-    }
-
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsThebesImage::UnlockImagePixels(PRBool aMaskPixels)
-{
-    if (aMaskPixels)
-        return NS_ERROR_NOT_IMPLEMENTED;
-    mOptSurface = nsnull;
-#ifdef XP_MACOSX
-    if (mQuartzSurface)
-        mQuartzSurface->Flush();
-#endif
-    return NS_OK;
-}
-
-static PRBool
-IsSafeImageTransformComponent(gfxFloat aValue)
-{
-    return aValue >= -32768 && aValue <= 32767;
-}
-
-void
-nsThebesImage::Draw(gfxContext*        aContext,
-                    gfxPattern::GraphicsFilter aFilter,
-                    const gfxMatrix&   aUserSpaceToImageSpace,
-                    const gfxRect&     aFill,
-                    const nsIntMargin& aPadding,
-                    const nsIntRect&   aSubimage)
-{
-    NS_ASSERTION(!aFill.IsEmpty(), "zero dest size --- fix caller");
-    NS_ASSERTION(!aSubimage.IsEmpty(), "zero source size --- fix caller");
-
-    PRBool doPadding = aPadding != nsIntMargin(0,0,0,0);
-    PRBool doPartialDecode = !GetIsImageComplete();
-    gfxContext::GraphicsOperator op = aContext->CurrentOperator();
-
-    if (mSinglePixel && !doPadding && !doPartialDecode) {
-        // Single-color fast path
-        // if a == 0, it's a noop
-        if (mSinglePixelColor.a == 0.0)
-            return;
-
-        if (op == gfxContext::OPERATOR_OVER && mSinglePixelColor.a == 1.0)
-            aContext->SetOperator(gfxContext::OPERATOR_SOURCE);
-
-        aContext->SetDeviceColor(mSinglePixelColor);
-        aContext->NewPath();
-        aContext->Rectangle(aFill);
-        aContext->Fill();
-        aContext->SetOperator(op);
-        aContext->SetDeviceColor(gfxRGBA(0,0,0,0));
-        return;
-    }
-
-    gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace;
-    gfxRect sourceRect = userSpaceToImageSpace.Transform(aFill);
-    gfxRect imageRect(0, 0, mWidth + aPadding.LeftRight(), mHeight + aPadding.TopBottom());
-    gfxRect subimage(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height);
-    gfxRect fill = aFill;
-    nsRefPtr<gfxASurface> surface;
-    gfxImageSurface::gfxImageFormat format;
-
-    NS_ASSERTION(!sourceRect.Intersect(subimage).IsEmpty(),
-                 "We must be allowed to sample *some* source pixels!");
-
-    PRBool doTile = !imageRect.Contains(sourceRect);
-    if (doPadding || doPartialDecode) {
-        gfxRect available = gfxRect(mDecoded.x, mDecoded.y, mDecoded.width, mDecoded.height) +
-            gfxPoint(aPadding.left, aPadding.top);
-  
-        if (!doTile && !mSinglePixel) {
-            // Not tiling, and we have a surface, so we can account for
-            // padding and/or a partial decode just by twiddling parameters.
-            // First, update our user-space fill rect.
-            sourceRect = sourceRect.Intersect(available);
-            gfxMatrix imageSpaceToUserSpace = userSpaceToImageSpace;
-            imageSpaceToUserSpace.Invert();
-            fill = imageSpaceToUserSpace.Transform(sourceRect);
-  
-            surface = ThebesSurface();
-            format = mFormat;
-            subimage = subimage.Intersect(available) - gfxPoint(aPadding.left, aPadding.top);
-            userSpaceToImageSpace.Multiply(
-                gfxMatrix().Translate(-gfxPoint(aPadding.left, aPadding.top)));
-            sourceRect = sourceRect - gfxPoint(aPadding.left, aPadding.top);
-            imageRect = gfxRect(0, 0, mWidth, mHeight);
-        } else {
-            // Create a temporary surface
-            gfxIntSize size(PRInt32(imageRect.Width()),
-                            PRInt32(imageRect.Height()));
-            // Give this surface an alpha channel because there are
-            // transparent pixels in the padding or undecoded area
-            format = gfxASurface::ImageFormatARGB32;
-            surface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(size,
-                format);
-            if (!surface || surface->CairoStatus() != 0)
-                return;
-  
-            // Fill 'available' with whatever we've got
-            gfxContext tmpCtx(surface);
-            tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE);
-            if (mSinglePixel) {
-                tmpCtx.SetDeviceColor(mSinglePixelColor);
-            } else {
-                tmpCtx.SetSource(ThebesSurface(), gfxPoint(aPadding.left, aPadding.top));
-            }
-            tmpCtx.Rectangle(available);
-            tmpCtx.Fill();
-        }
-    } else {
-        NS_ASSERTION(!mSinglePixel, "This should already have been handled");
-        surface = ThebesSurface();
-        format = mFormat;
-    }
-    // At this point, we've taken care of mSinglePixel images, images with
-    // aPadding, and partially-decoded images.
-
-    if (!AllowedImageSize(fill.size.width + 1, fill.size.height + 1)) {
-        NS_WARNING("Destination area too large, bailing out");
-        return;
-    }
-    // Compute device-space-to-image-space transform. We need to sanity-
-    // check it to work around a pixman bug :-(
-    // XXX should we only do this for certain surface types?
-    gfxFloat deviceX, deviceY;
-    nsRefPtr<gfxASurface> currentTarget =
-        aContext->CurrentSurface(&deviceX, &deviceY);
-    gfxMatrix currentMatrix = aContext->CurrentMatrix();
-    gfxMatrix deviceToUser = currentMatrix;
-    deviceToUser.Invert();
-    deviceToUser.Translate(-gfxPoint(-deviceX, -deviceY));
-    gfxMatrix deviceToImage = deviceToUser;
-    deviceToImage.Multiply(userSpaceToImageSpace);
-  
-    PRBool pushedGroup = PR_FALSE;
-    if (currentTarget->GetType() != gfxASurface::SurfaceTypeQuartz) {
-        // BEGIN working around cairo/pixman bug (bug 364968)
-        // Quartz's limits for matrix are much larger than pixman
-
-    // Our device-space-to-image-space transform may not be acceptable to pixman.
-    if (!IsSafeImageTransformComponent(deviceToImage.xx) ||
-        !IsSafeImageTransformComponent(deviceToImage.xy) ||
-        !IsSafeImageTransformComponent(deviceToImage.yx) ||
-        !IsSafeImageTransformComponent(deviceToImage.yy)) {
-        NS_WARNING("Scaling up too much, bailing out");
-        return;
-    }
-
-    if (!IsSafeImageTransformComponent(deviceToImage.x0) ||
-        !IsSafeImageTransformComponent(deviceToImage.y0)) {
-        // We'll push a group, which will hopefully reduce our transform's
-        // translation so it's in bounds
-        aContext->Save();
-  
-        // Clip the rounded-out-to-device-pixels bounds of the
-        // transformed fill area. This is the area for the group we
-        // want to push.
-        aContext->IdentityMatrix();
-        gfxRect bounds = currentMatrix.TransformBounds(fill);
-        bounds.RoundOut();
-        aContext->Clip(bounds);
-        aContext->SetMatrix(currentMatrix);
-  
-        aContext->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
-        aContext->SetOperator(gfxContext::OPERATOR_OVER);
-        pushedGroup = PR_TRUE;
-    }
-    // END working around cairo/pixman bug (bug 364968)
-    }
-  
-    nsRefPtr<gfxPattern> pattern = new gfxPattern(surface);
-    pattern->SetMatrix(userSpaceToImageSpace);
-
-    // OK now, the hard part left is to account for the subimage sampling
-    // restriction. If all the transforms involved are just integer
-    // translations, then we assume no resampling will occur so there's
-    // nothing to do.
-    // XXX if only we had source-clipping in cairo!
-    if (!currentMatrix.HasNonIntegerTranslation() &&
-        !userSpaceToImageSpace.HasNonIntegerTranslation()) {
-        if (doTile) {
-            pattern->SetExtend(gfxPattern::EXTEND_REPEAT);
-        }
-    } else {
-        if (doTile || !subimage.Contains(imageRect)) {
-            // EXTEND_PAD won't help us here; we have to create a temporary
-            // surface to hold the subimage of pixels we're allowed to
-            // sample
-
-            gfxRect userSpaceClipExtents = aContext->GetClipExtents();
-            // This isn't optimal --- if aContext has a rotation then
-            // GetClipExtents will have to do a bounding-box computation,
-            // and TransformBounds might too, so we could get a better
-            // result if we computed image space clip extents in one go
-            // --- but it doesn't really matter and this is easier to
-            // understand.
-            gfxRect imageSpaceClipExtents =
-              userSpaceToImageSpace.TransformBounds(userSpaceClipExtents);
-            // Inflate by one pixel because bilinear filtering will sample
-            // at most one pixel beyond the computed image pixel coordinate.
-            imageSpaceClipExtents.Outset(1.0);
-
-            gfxRect needed =
-              imageSpaceClipExtents.Intersect(sourceRect).Intersect(subimage);
-            needed.RoundOut();
-            // if 'needed' is empty, nothing will be drawn since aFill
-            // must be entirely outside the clip region, so it doesn't
-            // matter what we do here, but we should avoid trying to
-            // create a zero-size surface.
-            if (!needed.IsEmpty()) {
-                gfxIntSize size(PRInt32(needed.Width()), PRInt32(needed.Height()));
-                nsRefPtr<gfxASurface> temp =
-                    gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, format);
-                if (temp && temp->CairoStatus() == 0) {
-                    gfxContext tmpCtx(temp);
-                    tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE);
-                    nsRefPtr<gfxPattern> tmpPattern = new gfxPattern(surface);
-                    if (tmpPattern) {
-                        tmpPattern->SetExtend(gfxPattern::EXTEND_REPEAT);
-                        tmpPattern->SetMatrix(gfxMatrix().Translate(needed.pos));
-                        tmpCtx.SetPattern(tmpPattern);
-                        tmpCtx.Paint();
-                        tmpPattern = new gfxPattern(temp);
-                        if (tmpPattern) {
-                            pattern.swap(tmpPattern);
-                            pattern->SetMatrix(
-                                gfxMatrix(userSpaceToImageSpace).Multiply(gfxMatrix().Translate(-needed.pos)));
-                        }
-                    }
-                }
-            }
-        }
-  
-        // In theory we can handle this using cairo's EXTEND_PAD,
-        // but implementation limitations mean we have to consult
-        // the surface type.
-        switch (currentTarget->GetType()) {
-        case gfxASurface::SurfaceTypeXlib:
-        case gfxASurface::SurfaceTypeXcb: {
-            // See bug 324698.  This is a workaround for EXTEND_PAD not being
-            // implemented correctly on linux in the X server.
-            //
-            // Set the filter to CAIRO_FILTER_FAST --- otherwise,
-            // pixman's sampling will sample transparency for the outside edges and we'll
-            // get blurry edges.  CAIRO_EXTEND_PAD would also work here, if
-            // available
-            //
-            // But don't do this for simple downscales because it's horrible.
-            // Downscaling means that device-space coordinates are
-            // scaled *up* to find the image pixel coordinates.
-            //
-            // deviceToImage is slightly stale because up above we may
-            // have adjusted the pattern's matrix ... but the adjustment
-            // is only a translation so the scale factors in deviceToImage
-            // are still valid.
-            PRBool isDownscale =
-              deviceToImage.xx >= 1.0 && deviceToImage.yy >= 1.0 &&
-              deviceToImage.xy == 0.0 && deviceToImage.yx == 0.0;
-            if (!isDownscale) {
-                pattern->SetFilter(gfxPattern::FILTER_FAST);
-            }
-            break;
-        }
-  
-        case gfxASurface::SurfaceTypeQuartz:
-        case gfxASurface::SurfaceTypeQuartzImage:
-            // Don't set EXTEND_PAD, Mac seems to be OK. Really?
-            pattern->SetFilter(aFilter);
-            break;
-
-        default:
-            // turn on EXTEND_PAD.
-            // This is what we really want for all surface types, if the
-            // implementation was universally good.
-            pattern->SetExtend(gfxPattern::EXTEND_PAD);
-            pattern->SetFilter(aFilter);
-            break;
-        }
-    }
-
-    if ((op == gfxContext::OPERATOR_OVER || pushedGroup) &&
-        format == gfxASurface::ImageFormatRGB24) {
-        aContext->SetOperator(gfxContext::OPERATOR_SOURCE);
-    }
-
-    // Phew! Now we can actually draw this image
-    aContext->NewPath();
-#ifdef MOZ_GFX_OPTIMIZE_MOBILE
-    pattern->SetFilter(gfxPattern::FILTER_FAST); 
-#endif
-    aContext->SetPattern(pattern);
-    aContext->Rectangle(fill);
-    aContext->Fill();
-  
-    aContext->SetOperator(op);
-    if (pushedGroup) {
-        aContext->PopGroupToSource();
-        aContext->Paint();
-        aContext->Restore();
-    }
-}
-
-nsresult
-nsThebesImage::Extract(const nsIntRect& aRegion,
-                       nsIImage** aResult)
-{
-    nsRefPtr<nsThebesImage> subImage(new nsThebesImage());
-    if (!subImage)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    // The scaling problems described in bug 468496 are especially
-    // likely to be visible for the sub-image, as at present the only
-    // user is the border-image code and border-images tend to get
-    // stretched a lot.  At the same time, the performance concerns
-    // that prevent us from just using Cairo's fallback scaler when
-    // accelerated graphics won't cut it are less relevant to such
-    // images, since they also tend to be small.  Thus, we forcibly
-    // disable the use of anything other than a client-side image
-    // surface for the sub-image; this ensures that the correct
-    // (albeit slower) Cairo fallback scaler will be used.
-    subImage->mNeverUseDeviceSurface = PR_TRUE;
-
-    // ->Init() is just going to convert this back, bleah.
-    nsMaskRequirements maskReq;
-    switch (mAlphaDepth) {
-    case 0: maskReq = nsMaskRequirements_kNoMask; break;
-    case 1: maskReq = nsMaskRequirements_kNeeds1Bit; break;
-    case 8: maskReq = nsMaskRequirements_kNeeds8Bit; break;
-    default:
-        NS_NOTREACHED("impossible alpha depth");
-        maskReq = nsMaskRequirements_kNeeds8Bit; // safe
-    }
-
-    nsresult rv = subImage->Init(aRegion.width, aRegion.height,
-                                 8 /* ignored */, maskReq);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    { // scope to destroy ctx
-        gfxContext ctx(subImage->ThebesSurface());
-        ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
-        if (mSinglePixel) {
-            ctx.SetDeviceColor(mSinglePixelColor);
-        } else {
-            // SetSource() places point (0,0) of its first argument at
-            // the coordinages given by its second argument.  We want
-            // (x,y) of the image to be (0,0) of source space, so we
-            // put (0,0) of the image at (-x,-y).
-            ctx.SetSource(this->ThebesSurface(),
-                          gfxPoint(-aRegion.x, -aRegion.y));
-        }
-        ctx.Rectangle(gfxRect(0, 0, aRegion.width, aRegion.height));
-        ctx.Fill();
-    }
-
-    nsIntRect filled(0, 0, aRegion.width, aRegion.height);
-    subImage->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &filled);
-    subImage->Optimize(nsnull);
-
-    NS_ADDREF(*aResult = subImage);
-    return NS_OK;
-}
-
-PRBool
-nsThebesImage::ShouldUseImageSurfaces()
-{
-#if defined(WINCE)
-    // There is no test on windows mobile to check for Gui resources.
-    // Allocate, until we run out of memory.
-    gfxWindowsPlatform::RenderMode rmode = gfxWindowsPlatform::GetPlatform()->GetRenderMode();
-    return rmode != gfxWindowsPlatform::RENDER_DDRAW &&
-        rmode != gfxWindowsPlatform::RENDER_DDRAW_GL;
-
-#elif defined(USE_WIN_SURFACE)
-    static const DWORD kGDIObjectsHighWaterMark = 7000;
-
-    // at 7000 GDI objects, stop allocating normal images to make sure
-    // we never hit the 10k hard limit.
-    // GetCurrentProcess() just returns (HANDLE)-1, it's inlined afaik
-    DWORD count = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
-    if (count == 0 ||
-        count > kGDIObjectsHighWaterMark)
-    {
-        // either something's broken (count == 0),
-        // 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;
-        mFormatChanged = PR_TRUE;
-        mAlphaDepth = 0;
-    }
-}
deleted file mode 100644
--- a/gfx/src/thebes/nsThebesImage.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is thebes gfx
- *
- * The Initial Developer of the Original Code is
- * mozilla.org.
- * Portions created by the Initial Developer are Copyright (C) 2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Vladimir Vukicevic <vladimir@pobox.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
- * decision by deleting the provisions above and replace them with the notice
- * 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 ***** */
-
-#ifndef _NSTHEBESIMAGE_H_
-#define _NSTHEBESIMAGE_H_
-
-#include "nsIImage.h"
-
-#include "gfxColor.h"
-#include "gfxASurface.h"
-#include "gfxImageSurface.h"
-#include "gfxPattern.h"
-#if defined(XP_WIN)
-#include "gfxWindowsSurface.h"
-#elif defined(XP_MACOSX)
-#include "gfxQuartzImageSurface.h"
-#endif
-
-class nsThebesImage : public nsIImage
-{
-public:
-    nsThebesImage();
-    ~nsThebesImage();
-
-    NS_DECL_ISUPPORTS
-
-    virtual nsresult Init(PRInt32 aWidth, PRInt32 aHeight,
-                          PRInt32 aDepth, nsMaskRequirements aMaskRequirements);
-    virtual PRInt32 GetBytesPix();
-    virtual PRBool GetIsRowOrderTopToBottom();
-    virtual PRInt32 GetWidth();
-    virtual PRInt32 GetHeight();
-    virtual PRUint8 *GetBits();
-    virtual PRInt32 GetLineStride();
-    virtual PRBool GetHasAlphaMask();
-    virtual PRUint8 *GetAlphaBits();
-    virtual PRInt32 GetAlphaLineStride();
-    virtual PRBool GetIsImageComplete();
-    virtual nsresult ImageUpdated(nsIDeviceContext *aContext, PRUint8 aFlags, nsIntRect *aUpdateRect);
-    virtual nsresult Optimize(nsIDeviceContext* aContext);
-    virtual nsColorMap *GetColorMap();
-
-    virtual void Draw(gfxContext*        aContext,
-                      gfxPattern::GraphicsFilter aFilter,
-                      const gfxMatrix&   aUserSpaceToImageSpace,
-                      const gfxRect&     aFill,
-                      const nsIntMargin& aPadding,
-                      const nsIntRect&   aSubimage);
-
-    virtual PRInt8 GetAlphaDepth();
-    virtual void* GetBitInfo();
-    NS_IMETHOD LockImagePixels(PRBool aMaskPixels);
-    NS_IMETHOD UnlockImagePixels(PRBool aMaskPixels);
-
-    NS_IMETHOD GetSurface(gfxASurface **aSurface) {
-        *aSurface = ThebesSurface();
-        NS_ADDREF(*aSurface);
-        return NS_OK;
-    }
-
-    NS_IMETHOD GetPattern(gfxPattern **aPattern) {
-        if (mSinglePixel)
-            *aPattern = new gfxPattern(mSinglePixelColor);
-        else
-            *aPattern = new gfxPattern(ThebesSurface());
-        NS_ADDREF(*aPattern);
-        return NS_OK;
-    }
-
-    gfxASurface* ThebesSurface() {
-        if (mOptSurface)
-            return mOptSurface;
-#if defined(XP_WIN) && !defined(WINCE)
-        if (mWinSurface)
-            return mWinSurface;
-#elif defined(XP_MACOSX)
-        if (mQuartzSurface)
-            return mQuartzSurface;
-#endif
-        return mImageSurface;
-    }
-
-    void SetHasNoAlpha();
-
-    NS_IMETHOD Extract(const nsIntRect& aSubimage,
-                       nsIImage** aResult NS_OUTPARAM);
-
-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 )) {
-            NS_WARNING("image too big");
-            return PR_FALSE;
-        }
-        
-        // protect against division by zero - this really shouldn't happen
-        // if our consumers were well behaved, but they aren't (bug 368427)
-        if (NS_UNLIKELY(aHeight == 0)) {
-            return PR_FALSE;
-        }
-
-        // check to make sure we don't overflow a 32-bit
-        PRInt32 tmp = aWidth * aHeight;
-        if (NS_UNLIKELY(tmp / aHeight != aWidth)) {
-            NS_WARNING("width or height too large");
-            return PR_FALSE;
-        }
-        tmp = tmp * 4;
-        if (NS_UNLIKELY(tmp / 4 != aWidth * aHeight)) {
-            NS_WARNING("width or height too large");
-            return PR_FALSE;
-        }
-        return PR_TRUE;
-    }
-
-    gfxImageSurface::gfxImageFormat mFormat;
-    PRInt32 mWidth;
-    PRInt32 mHeight;
-    PRInt32 mStride;
-    nsIntRect mDecoded;
-    PRPackedBool mImageComplete;
-    PRPackedBool mSinglePixel;
-    PRPackedBool mFormatChanged;
-    PRPackedBool mNeverUseDeviceSurface;
-#if defined(XP_WIN) && !defined(WINCE)
-    PRPackedBool mIsDDBSurface;
-#endif
-
-    gfxRGBA mSinglePixelColor;
-
-    nsRefPtr<gfxImageSurface> mImageSurface;
-    nsRefPtr<gfxASurface> mOptSurface;
-#if defined(XP_WIN) && !defined(WINCE)
-    nsRefPtr<gfxWindowsSurface> mWinSurface;
-#elif defined(XP_MACOSX)
-    nsRefPtr<gfxQuartzImageSurface> mQuartzSurface;
-#endif
-
-    PRUint8 mAlphaDepth;
-
-    // this function should return true if
-    // we should (temporarily) not allocate any
-    // platform native surfaces and instead use
-    // image surfaces for everything.
-    static PRBool ShouldUseImageSurfaces();
-};
-
-#endif /* _NSTHEBESIMAGE_H_ */
--- a/gfx/src/thebes/nsThebesRenderingContext.cpp
+++ b/gfx/src/thebes/nsThebesRenderingContext.cpp
@@ -41,22 +41,17 @@
 #include "nsThebesDeviceContext.h"
 
 #include "nsString.h"
 #include "nsTransform2D.h"
 #include "nsIServiceManager.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsGfxCIID.h"
 
-#include "imgIContainer.h"
-#include "gfxIImageFrame.h"
-#include "nsIImage.h"
-
 #include "nsThebesRegion.h"
-#include "nsThebesImage.h"
 
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 
 #include "gfxPlatform.h"
 
--- a/gfx/src/thebes/nsThebesRenderingContext.h
+++ b/gfx/src/thebes/nsThebesRenderingContext.h
@@ -49,18 +49,16 @@
 #include "nsSize.h"
 #include "nsColor.h"
 #include "nsRect.h"
 #include "nsIRegion.h"
 #include "nsTransform2D.h"
 #include "nsIThebesFontMetrics.h"
 #include "gfxContext.h"
 
-class nsIImage;
-
 class nsThebesRenderingContext : public nsIRenderingContext
 {
 public:
     nsThebesRenderingContext();
     virtual ~nsThebesRenderingContext();
 
     NS_DECL_ISUPPORTS
 
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -41,34 +41,32 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /* utility functions for drawing borders and backgrounds */
 
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
-#include "nsIImage.h"
 #include "nsIFrame.h"
 #include "nsPoint.h"
 #include "nsRect.h"
 #include "nsIViewManager.h"
 #include "nsIPresShell.h"
 #include "nsFrameManager.h"
 #include "nsStyleContext.h"
 #include "nsGkAtoms.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsTransform2D.h"
 #include "nsIDeviceContext.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIScrollableFrame.h"
 #include "imgIRequest.h"
 #include "imgIContainer.h"
-#include "gfxIImageFrame.h"
 #include "nsCSSRendering.h"
 #include "nsCSSColorUtils.h"
 #include "nsITheme.h"
 #include "nsThemeConstants.h"
 #include "nsIServiceManager.h"
 #include "nsIHTMLDocument.h"
 #include "nsLayoutUtils.h"
 #include "nsINameSpaceManager.h"
@@ -316,17 +314,17 @@ static void DrawBorderImage(nsPresContex
                             nsIRenderingContext& aRenderingContext,
                             nsIFrame* aForFrame,
                             const nsRect& aBorderArea,
                             const nsStyleBorder& aBorderStyle,
                             const nsRect& aDirtyRect);
 
 static void DrawBorderImageComponent(nsIRenderingContext& aRenderingContext,
                                      nsIFrame* aForFrame,
-                                     nsIImage* aImage,
+                                     imgIContainer* aImage,
                                      const nsRect& aDirtyRect,
                                      const nsRect& aFill,
                                      const nsIntRect& aSrc,
                                      PRUint8 aHFill,
                                      PRUint8 aVFill,
                                      const nsSize& aUnitSize);
 
 static nscolor MakeBevelColor(PRIntn whichSide, PRUint8 style,
@@ -1682,37 +1680,19 @@ nsCSSRendering::PaintBackgroundWithSC(ns
   // association of the style data with the frame.
   aPresContext->SetupBackgroundImageLoaders(aForFrame, &aBackground);
 
   if (bottomImage &&
       aBackground.BottomLayer().mRepeat == NS_STYLE_BG_REPEAT_XY &&
       drawBackgroundColor) {
     nsCOMPtr<imgIContainer> image;
     bottomImage->GetImage(getter_AddRefs(image));
-    // If the image is completely opaque, we may not need to paint
-    // the background color.
-    nsCOMPtr<gfxIImageFrame> gfxImgFrame;
-    image->GetCurrentFrame(getter_AddRefs(gfxImgFrame));
-    if (gfxImgFrame) {
-      gfxImgFrame->GetNeedsBackground(&drawBackgroundColor);
-      if (!drawBackgroundColor) {
-        // If the current frame is smaller than its container, we
-        // need to paint the background color even if the frame
-        // itself is opaque.
-        nsIntSize iSize;
-        image->GetWidth(&iSize.width);
-        image->GetHeight(&iSize.height);
-        nsIntRect iframeRect;
-        gfxImgFrame->GetRect(iframeRect);
-        if (iSize.width != iframeRect.width ||
-            iSize.height != iframeRect.height) {
-          drawBackgroundColor = PR_TRUE;
-        }
-      }
-    }
+    PRBool isOpaque;
+    if (NS_SUCCEEDED(image->GetCurrentFrameIsOpaque(&isOpaque)) && isOpaque)
+      drawBackgroundColor = PR_FALSE;
   }
 
   // The background color is rendered over the entire dirty area,
   // even if the image isn't.
   if (drawBackgroundColor && !isCanvasFrame) {
     if (!dirtyRectGfx.IsEmpty()) {
       ctx->NewPath();
       ctx->Rectangle(dirtyRectGfx, PR_TRUE);
@@ -1933,28 +1913,16 @@ DrawBorderImage(nsPresContext*       aPr
 
   nsCOMPtr<imgIContainer> imgContainer;
   req->GetImage(getter_AddRefs(imgContainer));
 
   nsIntSize imageSize;
   imgContainer->GetWidth(&imageSize.width);
   imgContainer->GetHeight(&imageSize.height);
 
-  nsCOMPtr<gfxIImageFrame> imgFrame;
-  imgContainer->GetCurrentFrame(getter_AddRefs(imgFrame));
-
-  nsIntRect innerRect;
-  imgFrame->GetRect(innerRect);
-
-  nsCOMPtr<nsIImage> img(do_GetInterface(imgFrame));
-  // The inner rectangle should precisely enclose the image pixels for
-  // this frame.
-  NS_ASSERTION(innerRect.width == img->GetWidth(), "img inner width off");
-  NS_ASSERTION(innerRect.height == img->GetHeight(), "img inner height off");
-
   // Convert percentages and clamp values to the image size.
   nsIntMargin split;
   NS_FOR_CSS_SIDES(s) {
     nsStyleCoord coord = aBorderStyle.mBorderImageSplit.Get(s);
     PRInt32 imgDimension = ((s == NS_SIDE_TOP || s == NS_SIDE_BOTTOM)
                             ? imageSize.height
                             : imageSize.width);
     double value;
@@ -1978,17 +1946,17 @@ DrawBorderImage(nsPresContext*       aPr
     split.side(s) = NS_lround(value);
   }
 
   nsMargin border(aBorderStyle.GetActualBorder());
 
   // These helper tables recharacterize the 'split' and 'border' margins
   // in a more convenient form: they are the x/y/width/height coords
   // required for various bands of the border, and they have been transformed
-  // to be relative to the innerRect (for 'split') or the page (for 'border').
+  // to be relative to the image (for 'split') or the page (for 'border').
   enum {
     LEFT, MIDDLE, RIGHT,
     TOP = LEFT, BOTTOM = RIGHT
   };
   const nscoord borderX[3] = {
     aBorderArea.x + 0,
     aBorderArea.x + border.left,
     aBorderArea.x + aBorderArea.width - border.right,
@@ -2005,24 +1973,24 @@ DrawBorderImage(nsPresContext*       aPr
   };
   const nscoord borderHeight[3] = {
     border.top,
     aBorderArea.height - border.top - border.bottom,
     border.bottom,
   };
 
   const PRInt32 splitX[3] = {
-    -innerRect.x + 0,
-    -innerRect.x + split.left,
-    -innerRect.x + imageSize.width - split.right,
+    0,
+    split.left,
+    imageSize.width - split.right,
   };
   const PRInt32 splitY[3] = {
-    -innerRect.y + 0,
-    -innerRect.y + split.top,
-    -innerRect.y + imageSize.height - split.bottom,
+    0,
+    split.top,
+    imageSize.height - split.bottom,
   };
   const PRInt32 splitWidth[3] = {
     split.left,
     imageSize.width - split.left - split.right,
     split.right,
   };
   const PRInt32 splitHeight[3] = {
     split.top,
@@ -2103,39 +2071,39 @@ DrawBorderImage(nsPresContext*       aPr
         // Corners are always stretched to fit the corner.
         unitSize.width = borderWidth[i];
         unitSize.height = borderHeight[j];
         fillStyleH = NS_STYLE_BORDER_IMAGE_STRETCH;
         fillStyleV = NS_STYLE_BORDER_IMAGE_STRETCH;
       }
 
       DrawBorderImageComponent(aRenderingContext, aForFrame,
-                               img, aDirtyRect,
+                               imgContainer, aDirtyRect,
                                destArea, subArea,
                                fillStyleH, fillStyleV, unitSize);
     }
   }
 }
 
 static void
 DrawBorderImageComponent(nsIRenderingContext& aRenderingContext,
                          nsIFrame*            aForFrame,
-                         nsIImage*            aImage,
+                         imgIContainer*       aImage,
                          const nsRect&        aDirtyRect,
                          const nsRect&        aFill,
                          const nsIntRect&     aSrc,
                          PRUint8              aHFill,
                          PRUint8              aVFill,
                          const nsSize&        aUnitSize)
 {
   if (aFill.IsEmpty() || aSrc.IsEmpty())
     return;
 
-  nsCOMPtr<nsIImage> subImage;
-  if (NS_FAILED(aImage->Extract(aSrc, getter_AddRefs(subImage))))
+  nsCOMPtr<imgIContainer> subImage;
+  if (NS_FAILED(aImage->ExtractCurrentFrame(aSrc, getter_AddRefs(subImage))))
     return;
 
   gfxPattern::GraphicsFilter graphicsFilter =
     nsLayoutUtils::GetGraphicsFilterForFrame(aForFrame);
 
   // If we have no tiling in either direction, we can skip the intermediate
   // scaling step.
   if ((aHFill == NS_STYLE_BORDER_IMAGE_STRETCH &&
--- a/layout/base/nsCSSRenderingBorders.cpp
+++ b/layout/base/nsCSSRenderingBorders.cpp
@@ -34,34 +34,32 @@
  * 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 "nsStyleConsts.h"
 #include "nsPresContext.h"
-#include "nsIImage.h"
 #include "nsIFrame.h"
 #include "nsPoint.h"
 #include "nsRect.h"
 #include "nsIViewManager.h"
 #include "nsIPresShell.h"
 #include "nsFrameManager.h"
 #include "nsStyleContext.h"
 #include "nsGkAtoms.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsTransform2D.h"
 #include "nsIDeviceContext.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIScrollableFrame.h"
 #include "imgIRequest.h"
 #include "imgIContainer.h"
-#include "gfxIImageFrame.h"
 #include "nsCSSRendering.h"
 #include "nsCSSColorUtils.h"
 #include "nsITheme.h"
 #include "nsThemeConstants.h"
 #include "nsIServiceManager.h"
 #include "nsIHTMLDocument.h"
 #include "nsLayoutUtils.h"
 #include "nsINameSpaceManager.h"
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -53,19 +53,17 @@
 #include "nsStyleStructInlines.h"
 #include "nsStyleTransformMatrix.h"
 #include "gfxMatrix.h"
 #ifdef MOZ_SVG
 #include "nsSVGIntegrationUtils.h"
 #endif
 
 #include "imgIContainer.h"
-#include "gfxIImageFrame.h"
 #include "nsIInterfaceRequestorUtils.h"
-#include "nsIImage.h"
 
 nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
     PRBool aIsForEvents, PRBool aBuildCaret)
     : mReferenceFrame(aReferenceFrame),
       mMovingFrame(nsnull),
       mIgnoreScrollFrame(nsnull),
       mCurrentTableItem(nsnull),
       mBuildCaret(aBuildCaret),
@@ -550,28 +548,22 @@ nsDisplayBackground::IsOpaque(nsDisplayL
       !nsCSSRendering::IsCanvasFrame(mFrame))
     return PR_TRUE;
 
   if (bottomLayer.mRepeat == NS_STYLE_BG_REPEAT_XY) {
     if (bottomLayer.mImage) {
       nsCOMPtr<imgIContainer> container;
       bottomLayer.mImage->GetImage(getter_AddRefs(container));
       if (container) {
-        PRUint32 nframes;
-        container->GetNumFrames(&nframes);
-        if (nframes == 1) {
-          nsCOMPtr<gfxIImageFrame> imgFrame;
-          container->GetCurrentFrame(getter_AddRefs(imgFrame));
-          if (imgFrame) {
-            nsCOMPtr<nsIImage> img(do_GetInterface(imgFrame));
-
-            PRBool hasMask = img->GetHasAlphaMask();
-
-            return !hasMask;
-          }
+        PRBool animated;
+        container->GetAnimated(&animated);
+        if (!animated) {
+          PRBool isOpaque;
+          if (NS_SUCCEEDED(container->GetCurrentFrameIsOpaque(&isOpaque)))
+            return isOpaque;
         }
       }
     }
   }
 
   return PR_FALSE;
 }
 
--- a/layout/base/nsImageLoader.cpp
+++ b/layout/base/nsImageLoader.cpp
@@ -149,17 +149,17 @@ NS_IMETHODIMP nsImageLoader::OnStartCont
     aImage->SetAnimationMode(mFrame->PresContext()->ImageAnimationMode());
     // Ensure the animation (if any) is started.
     aImage->StartAnimation();
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP nsImageLoader::OnStopFrame(imgIRequest *aRequest,
-                                         gfxIImageFrame *aFrame)
+                                         PRUint32 aFrame)
 {
   if (!mFrame)
     return NS_ERROR_FAILURE;
   
 #ifdef NS_DEBUG
 // Make sure the image request status's STATUS_FRAME_COMPLETE flag has been set to ensure
 // the image will be painted when invalidated
   if (aRequest) {
@@ -177,17 +177,16 @@ NS_IMETHODIMP nsImageLoader::OnStopFrame
   }
   
   // Draw the background image
   RedrawDirtyFrame(nsnull);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsImageLoader::FrameChanged(imgIContainer *aContainer,
-                                          gfxIImageFrame *newframe,
                                           nsIntRect *dirtyRect)
 {
   if (!mFrame)
     return NS_ERROR_FAILURE;
 
   if (!mRequest) {
     // We're in the middle of a paint anyway
     return NS_OK;
--- a/layout/base/nsImageLoader.h
+++ b/layout/base/nsImageLoader.h
@@ -65,26 +65,25 @@ public:
   static already_AddRefed<nsImageLoader>
     Create(nsIFrame *aFrame, imgIRequest *aRequest,
            PRBool aReflowOnLoad, nsImageLoader *aNextLoader);
 
   NS_DECL_ISUPPORTS
 
   // imgIDecoderObserver (override nsStubImageDecoderObserver)
   NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
-  NS_IMETHOD OnStopFrame(imgIRequest *aRequest, gfxIImageFrame *aFrame);
+  NS_IMETHOD OnStopFrame(imgIRequest *aRequest, PRUint32 aFrame);
   // Do not override OnDataAvailable since background images are not
   // displayed incrementally; they are displayed after the entire image
   // has been loaded.
   // Note: Images referenced by the <img> element are displayed
   // incrementally in nsImageFrame.cpp.
 
   // imgIContainerObserver (override nsStubImageDecoderObserver)
-  NS_IMETHOD FrameChanged(imgIContainer *aContainer, gfxIImageFrame *newframe,
-                          nsIntRect *dirtyRect);
+  NS_IMETHOD FrameChanged(imgIContainer *aContainer, nsIntRect *dirtyRect);
 
   void Destroy();
 
   imgIRequest *GetRequest() { return mRequest; }
   nsImageLoader *GetNextLoader() { return mNextLoader; }
 
 private:
   nsresult Load(imgIRequest *aImage);
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -56,22 +56,20 @@
 #include "nsIPrivateDOMEvent.h"
 #include "nsIDOMEvent.h"
 #include "nsGUIEvent.h"
 #include "nsDisplayList.h"
 #include "nsRegion.h"
 #include "nsFrameManager.h"
 #include "nsBlockFrame.h"
 #include "nsBidiPresUtils.h"
-#include "gfxIImageFrame.h"
 #include "imgIContainer.h"
 #include "gfxRect.h"
 #include "gfxContext.h"
 #include "gfxFont.h"
-#include "nsIImage.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsCSSRendering.h"
 #include "nsContentUtils.h"
 #include "nsThemeConstants.h"
 #include "nsPIDOMWindow.h"
 #include "nsIBaseWindow.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
@@ -2727,24 +2725,23 @@ MapToFloatUserPixels(const gfxSize& aSiz
                      const gfxRect& aDest, const gfxPoint& aPt)
 {
   return gfxPoint(aPt.x*aDest.size.width/aSize.width + aDest.pos.x,
                   aPt.y*aDest.size.height/aSize.height + aDest.pos.y);
 }
 
 static nsresult
 DrawImageInternal(nsIRenderingContext* aRenderingContext,
-                  nsIImage*            aImage,
+                  imgIContainer*       aImage,
                   gfxPattern::GraphicsFilter aGraphicsFilter,
                   const nsRect&        aDest,
                   const nsRect&        aFill,
                   const nsPoint&       aAnchor,
                   const nsRect&        aDirty,
-                  const nsIntSize&     aImageSize,
-                  const nsIntRect&     aInnerRect)
+                  const nsIntSize&     aImageSize)
 {
   if (aDest.IsEmpty() || aFill.IsEmpty())
     return NS_OK;
   if (aImageSize.width == 0 || aImageSize.height == 0)
     return NS_OK;
 
   nsCOMPtr<nsIDeviceContext> dc;
   aRenderingContext->GetDeviceContext(*getter_AddRefs(dc));
@@ -2834,32 +2831,28 @@ DrawImageInternal(nsIRenderingContext* a
   // computed for edge pixels.
   if (didSnap && !transform.HasNonIntegerTranslation()) {
     dirty.RoundOut();
     finalFillRect = fill.Intersect(dirty);
   }
   if (finalFillRect.IsEmpty())
     return NS_OK;
 
-  nsIntMargin padding(aInnerRect.x, aInnerRect.y,
-                      imageSize.width - aInnerRect.XMost(),
-                      imageSize.height - aInnerRect.YMost());
-  aImage->Draw(ctx, aGraphicsFilter, transform, finalFillRect, padding, intSubimage);
+  aImage->Draw(ctx, aGraphicsFilter, transform, finalFillRect, intSubimage);
   return NS_OK;
 }
 
 /* Workhorse for DrawSingleUnscaledImage.  */
 static nsresult
 DrawSingleUnscaledImageInternal(nsIRenderingContext* aRenderingContext,
-                                nsIImage*            aImage,
+                                imgIContainer*       aImage,
                                 const nsPoint&       aDest,
                                 const nsRect&        aDirty,
                                 const nsRect*        aSourceArea,
-                                const nsIntSize&     aImageSize,
-                                const nsIntRect&     aInnerRect)
+                                const nsIntSize&     aImageSize)
 {
   if (aImageSize.width == 0 || aImageSize.height == 0)
     return NS_OK;
 
   nscoord appUnitsPerCSSPixel = nsIDeviceContext::AppUnitsPerCSSPixel();
   nsSize size(aImageSize.width*appUnitsPerCSSPixel,
               aImageSize.height*appUnitsPerCSSPixel);
 
@@ -2872,29 +2865,28 @@ DrawSingleUnscaledImageInternal(nsIRende
 
   nsRect dest(aDest - source.TopLeft(), size);
   nsRect fill(aDest, source.Size());
   // Ensure that only a single image tile is drawn. If aSourceArea extends
   // outside the image bounds, we want to honor the aSourceArea-to-aDest
   // translation but we don't want to actually tile the image.
   fill.IntersectRect(fill, dest);
   return DrawImageInternal(aRenderingContext, aImage, gfxPattern::FILTER_NEAREST,
-                           dest, fill, aDest, aDirty, aImageSize, aInnerRect);
+                           dest, fill, aDest, aDirty, aImageSize);
 }
 
 /* Workhorse for DrawSingleImage.  */
 static nsresult
 DrawSingleImageInternal(nsIRenderingContext* aRenderingContext,
-                        nsIImage*            aImage,
+                        imgIContainer*       aImage,
                         gfxPattern::GraphicsFilter aGraphicsFilter,
                         const nsRect&        aDest,
                         const nsRect&        aDirty,
                         const nsRect*        aSourceArea,
-                        const nsIntSize&     aImageSize,
-                        const nsIntRect&     aInnerRect)
+                        const nsIntSize&     aImageSize)
 {
   if (aImageSize.width == 0 || aImageSize.height == 0)
     return NS_OK;
 
   nsRect source;
   if (aSourceArea) {
     source = *aSourceArea;
   } else {
@@ -2906,134 +2898,73 @@ DrawSingleImageInternal(nsIRenderingCont
   nsRect dest = nsLayoutUtils::GetWholeImageDestination(aImageSize, source,
                                                         aDest);
   // Ensure that only a single image tile is drawn. If aSourceArea extends
   // outside the image bounds, we want to honor the aSourceArea-to-aDest
   // transform but we don't want to actually tile the image.
   nsRect fill;
   fill.IntersectRect(aDest, dest);
   return DrawImageInternal(aRenderingContext, aImage, aGraphicsFilter, dest, fill,
-                           fill.TopLeft(), aDirty, aImageSize, aInnerRect);
+                           fill.TopLeft(), aDirty, aImageSize);
 }
 
 /* The exposed Draw*Image functions just do interface conversion and call the
    appropriate Draw*ImageInternal workhorse.  */
 
 /* static */ nsresult
 nsLayoutUtils::DrawImage(nsIRenderingContext* aRenderingContext,
                          imgIContainer*       aImage,
                          gfxPattern::GraphicsFilter aGraphicsFilter,
                          const nsRect&        aDest,
                          const nsRect&        aFill,
                          const nsPoint&       aAnchor,
                          const nsRect&        aDirty)
 {
-  nsCOMPtr<gfxIImageFrame> imgFrame;
-  aImage->GetCurrentFrame(getter_AddRefs(imgFrame));
-  if (!imgFrame) return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIImage> img(do_GetInterface(imgFrame));
-  if (!img) return NS_ERROR_FAILURE;
-
-  nsIntRect innerRect;
-  imgFrame->GetRect(innerRect);
-
   nsIntSize imageSize;
   aImage->GetWidth(&imageSize.width);
   aImage->GetHeight(&imageSize.height);
 
-  return DrawImageInternal(aRenderingContext, img, aGraphicsFilter,
-                           aDest, aFill, aAnchor, aDirty,
-                           imageSize, innerRect);
-}
-
-/* static */ nsresult
-nsLayoutUtils::DrawImage(nsIRenderingContext* aRenderingContext,
-                         nsIImage*            aImage,
-                         gfxPattern::GraphicsFilter aGraphicsFilter,
-                         const nsRect&        aDest,
-                         const nsRect&        aFill,
-                         const nsPoint&       aAnchor,
-                         const nsRect&        aDirty)
-{
-  nsIntSize imageSize(aImage->GetWidth(), aImage->GetHeight());
   return DrawImageInternal(aRenderingContext, aImage, aGraphicsFilter,
                            aDest, aFill, aAnchor, aDirty,
-                           imageSize, nsIntRect(nsIntPoint(0,0), imageSize));
+                           imageSize);
 }
 
 /* static */ nsresult
 nsLayoutUtils::DrawSingleUnscaledImage(nsIRenderingContext* aRenderingContext,
                                        imgIContainer*       aImage,
                                        const nsPoint&       aDest,
                                        const nsRect&        aDirty,
                                        const nsRect*        aSourceArea)
 {
-  nsCOMPtr<gfxIImageFrame> imgFrame;
-  aImage->GetCurrentFrame(getter_AddRefs(imgFrame));
-  if (!imgFrame) return NS_ERROR_FAILURE;
- 
-  nsCOMPtr<nsIImage> img(do_GetInterface(imgFrame));
-  if (!img) return NS_ERROR_FAILURE;
- 
-  nsIntRect innerRect;
-  imgFrame->GetRect(innerRect);
-
   nsIntSize imageSize;
   aImage->GetWidth(&imageSize.width);
   aImage->GetHeight(&imageSize.height);
 
-  return DrawSingleUnscaledImageInternal(aRenderingContext, img,
+  return DrawSingleUnscaledImageInternal(aRenderingContext, aImage,
                                          aDest, aDirty, aSourceArea,
-                                         imageSize, innerRect);
+                                         imageSize);
 }
  
 /* static */ nsresult
 nsLayoutUtils::DrawSingleImage(nsIRenderingContext* aRenderingContext,
                                imgIContainer*       aImage,
                                gfxPattern::GraphicsFilter aGraphicsFilter,
                                const nsRect&        aDest,
                                const nsRect&        aDirty,
                                const nsRect*        aSourceArea)
 {
-  nsCOMPtr<gfxIImageFrame> imgFrame;
-  aImage->GetCurrentFrame(getter_AddRefs(imgFrame));
-  if (!imgFrame) return NS_ERROR_FAILURE;
- 
-  nsCOMPtr<nsIImage> img(do_GetInterface(imgFrame));
-  if (!img) return NS_ERROR_FAILURE;
- 
-  nsIntRect innerRect;
-  imgFrame->GetRect(innerRect);
-
   nsIntSize imageSize;
   aImage->GetWidth(&imageSize.width);
   aImage->GetHeight(&imageSize.height);
 
-  return DrawSingleImageInternal(aRenderingContext, img, aGraphicsFilter,
-                                 aDest, aDirty, aSourceArea,
-                                 imageSize, innerRect);
-}
-
-/* static */ nsresult
-nsLayoutUtils::DrawSingleImage(nsIRenderingContext* aRenderingContext,
-                               nsIImage*            aImage,
-                               gfxPattern::GraphicsFilter aGraphicsFilter,
-                               const nsRect&        aDest,
-                               const nsRect&        aDirty,
-                               const nsRect*        aSourceArea)
-{
-  nsIntSize imageSize(aImage->GetWidth(), aImage->GetHeight());
   return DrawSingleImageInternal(aRenderingContext, aImage, aGraphicsFilter,
                                  aDest, aDirty, aSourceArea,
-                                 imageSize,
-                                 nsIntRect(nsIntPoint(0, 0), imageSize));
+                                 imageSize);
 }
 
-
 /* static */ nsRect
 nsLayoutUtils::GetWholeImageDestination(const nsIntSize& aWholeImageSize,
                                         const nsRect& aImageSourceArea,
                                         const nsRect& aDestArea)
 {
   double scaleX = double(aDestArea.width)/aImageSourceArea.width;
   double scaleY = double(aDestArea.height)/aImageSourceArea.height;
   nscoord destOffsetX = NSToCoordRound(aImageSourceArea.x*scaleX);
@@ -3381,17 +3312,16 @@ nsLayoutUtils::SurfaceFromElement(nsIDOM
     result.mPrincipal = principal;
     result.mIsWriteOnly = PR_FALSE;
 
     return result;
   }
 #endif
 
   // Finally, check if it's a normal image
-  nsCOMPtr<imgIContainer> imgContainer;
   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(aElement);
 
   if (!imageLoader)
     return result;
 
   nsCOMPtr<imgIRequest> imgRequest;
   rv = imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
                                getter_AddRefs(imgRequest));
@@ -3420,55 +3350,49 @@ nsLayoutUtils::SurfaceFromElement(nsIDOM
   // to null to indicate that.
   nsCOMPtr<nsIPrincipal> principal;
   if (!isDataURI) {
     rv = imgRequest->GetImagePrincipal(getter_AddRefs(principal));
     if (NS_FAILED(rv) || !principal)
       return result;
   }
 
+  nsCOMPtr<imgIContainer> imgContainer;
   rv = imgRequest->GetImage(getter_AddRefs(imgContainer));
   if (NS_FAILED(rv) || !imgContainer)
     return result;
 
-  nsCOMPtr<gfxIImageFrame> frame;
-  rv = imgContainer->GetCurrentFrame(getter_AddRefs(frame));
+  nsRefPtr<gfxASurface> framesurf;
+  rv = imgContainer->GetCurrentFrame(getter_AddRefs(framesurf));
   if (NS_FAILED(rv))
     return result;
 
-  nsCOMPtr<nsIImage> img(do_GetInterface(frame));
-  if (!img)
-    return result;
-
   PRInt32 imgWidth, imgHeight;
-  rv = frame->GetWidth(&imgWidth);
-  rv |= frame->GetHeight(&imgHeight);
+  rv = imgContainer->GetWidth(&imgWidth);
+  rv |= imgContainer->GetHeight(&imgHeight);
   if (NS_FAILED(rv))
     return result;
 
-  nsRefPtr<gfxPattern> gfxpattern;
-  img->GetPattern(getter_AddRefs(gfxpattern));
-  nsRefPtr<gfxASurface> gfxsurf = gfxpattern->GetSurface();
-
-  if (wantImageSurface && gfxsurf->GetType() != gfxASurface::SurfaceTypeImage) {
+  if (wantImageSurface && framesurf->GetType() != gfxASurface::SurfaceTypeImage) {
     forceCopy = PR_TRUE;
   }
 
-  if (forceCopy || !gfxsurf) {
+  nsRefPtr<gfxASurface> gfxsurf = framesurf;
+  if (forceCopy) {
     if (wantImageSurface) {
       gfxsurf = new gfxImageSurface (gfxIntSize(imgWidth, imgHeight), gfxASurface::ImageFormatARGB32);
     } else {
       gfxsurf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(imgWidth, imgHeight),
                                                                    gfxASurface::ImageFormatARGB32);
     }
 
     nsRefPtr<gfxContext> ctx = new gfxContext(gfxsurf);
 
     ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
-    ctx->SetPattern(gfxpattern);
+    ctx->SetSource(framesurf);
     ctx->Paint();
   }
 
   result.mSurface = gfxsurf;
   result.mSize = gfxIntSize(imgWidth, imgHeight);
   result.mPrincipal = principal;
   result.mIsWriteOnly = PR_FALSE;
 
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -857,24 +857,16 @@ public:
   static nsresult DrawImage(nsIRenderingContext* aRenderingContext,
                             imgIContainer*       aImage,
                             gfxPattern::GraphicsFilter aGraphicsFilter,
                             const nsRect&        aDest,
                             const nsRect&        aFill,
                             const nsPoint&       aAnchor,
                             const nsRect&        aDirty);
 
-  static nsresult DrawImage(nsIRenderingContext* aRenderingContext,
-                            nsIImage*            aImage,
-                            gfxPattern::GraphicsFilter aGraphicsFilter,
-                            const nsRect&        aDest,
-                            const nsRect&        aFill,
-                            const nsPoint&       aAnchor,
-                            const nsRect&        aDirty);
-
   /**
    * Draw a whole image without scaling or tiling.
    *
    *   @param aRenderingContext Where to draw the image, set up with an
    *                            appropriate scale and transform for drawing in
    *                            app units.
    *   @param aImage            The image.
    *   @param aDest             The top-left where the image should be drawn
@@ -906,23 +898,16 @@ public:
    */
   static nsresult DrawSingleImage(nsIRenderingContext* aRenderingContext,
                                   imgIContainer*       aImage,
                                   gfxPattern::GraphicsFilter aGraphicsFilter,
                                   const nsRect&        aDest,
                                   const nsRect&        aDirty,
                                   const nsRect*        aSourceArea = nsnull);
 
-  static nsresult DrawSingleImage(nsIRenderingContext* aRenderingContext,
-                                  nsIImage*            aImage,
-                                  gfxPattern::GraphicsFilter aGraphicsFilter,
-                                  const nsRect&        aDest,
-                                  const nsRect&        aDirty,
-                                  const nsRect*        aSourceArea = nsnull);
-
   /**
    * Given a source area of an image (in appunits) and a destination area
    * that we want to map that source area too, computes the area that
    * would be covered by the whole image. This is useful for passing to
    * the aDest parameter of DrawImage, when we want to draw a subimage
    * of an overall image.
    */
   static nsRect GetWholeImageDestination(const nsIntSize& aWholeImageSize,
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -79,17 +79,16 @@ class nsBidiPresUtils;
 struct nsRect;
 
 class imgIRequest;
 
 class nsIContent;
 class nsIFontMetrics;
 class nsIFrame;
 class nsFrameManager;
-class nsIImage;
 class nsILinkHandler;
 class nsStyleContext;
 class nsIAtom;
 class nsIEventStateManager;
 class nsIURI;
 class nsILookAndFeel;
 class nsICSSPseudoComparator;
 class nsIAtom;
--- a/layout/forms/nsHTMLButtonControlFrame.cpp
+++ b/layout/forms/nsHTMLButtonControlFrame.cpp
@@ -47,17 +47,16 @@
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsStyleContext.h"
 #include "nsLeafFrame.h"
 #include "nsCSSRendering.h"
 #include "nsISupports.h"
 #include "nsGkAtoms.h"
 #include "nsCSSAnonBoxes.h"
-#include "nsIImage.h"
 #include "nsStyleConsts.h"
 #include "nsIComponentManager.h"
 #include "nsIDocument.h"
 #include "nsButtonFrameRenderer.h"
 #include "nsFormControlFrame.h"
 #include "nsFrameManager.h"
 #include "nsINameSpaceManager.h"
 #include "nsIServiceManager.h"
--- a/layout/forms/nsImageControlFrame.cpp
+++ b/layout/forms/nsImageControlFrame.cpp
@@ -44,17 +44,16 @@
 #include "nsIPresShell.h"
 #include "nsStyleContext.h"
 #include "nsLeafFrame.h"
 #include "nsCSSRendering.h"
 #include "nsISupports.h"
 #include "nsGkAtoms.h"
 #include "nsIDeviceContext.h"
 #include "nsIFontMetrics.h"
-#include "nsIImage.h"
 #include "nsStyleConsts.h"
 #include "nsFormControlFrame.h"
 #include "nsGUIEvent.h"
 #include "nsIServiceManager.h"
 #include "nsContainerFrame.h"
 #include "nsLayoutUtils.h"
 #ifdef ACCESSIBILITY
 #include "nsIAccessibilityService.h"
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -66,23 +66,22 @@ class nsBulletListener : public nsStubIm
 {
 public:
   nsBulletListener();
   virtual ~nsBulletListener();
 
   NS_DECL_ISUPPORTS
   // imgIDecoderObserver (override nsStubImageDecoderObserver)
   NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
-  NS_IMETHOD OnDataAvailable(imgIRequest *aRequest, gfxIImageFrame *aFrame,
+  NS_IMETHOD OnDataAvailable(imgIRequest *aRequest, PRBool aCurrentFrame,
                              const nsIntRect *aRect);
   NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult status,
                           const PRUnichar *statusArg);
   // imgIContainerObserver (override nsStubImageDecoderObserver)
-  NS_IMETHOD FrameChanged(imgIContainer *aContainer, gfxIImageFrame *newframe,
-                          nsIntRect *dirtyRect);
+  NS_IMETHOD FrameChanged(imgIContainer *aContainer, nsIntRect *dirtyRect);
 
   void SetFrame(nsBulletFrame *frame) { mFrame = frame; }
 
 private:
   nsBulletFrame *mFrame;
 };
 
 
@@ -1453,17 +1452,17 @@ NS_IMETHODIMP nsBulletFrame::OnStartCont
   // Ensure the animation (if any) is started.
   aImage->StartAnimation();
 
   
   return NS_OK;
 }
 
 NS_IMETHODIMP nsBulletFrame::OnDataAvailable(imgIRequest *aRequest,
-                                             gfxIImageFrame *aFrame,
+                                             PRBool aCurrentFrame,
                                              const nsIntRect *aRect)
 {
   // The image has changed.
   // Invalidate the entire content area. Maybe it's not optimal but it's simple and
   // always correct, and I'll be a stunned mullet if it ever matters for performance
   Invalidate(nsRect(0, 0, mRect.width, mRect.height));
 
   return NS_OK;
@@ -1484,17 +1483,16 @@ NS_IMETHODIMP nsBulletFrame::OnStopDecod
     }
   }
 #endif
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsBulletFrame::FrameChanged(imgIContainer *aContainer,
-                                          gfxIImageFrame *aNewFrame,
                                           nsIntRect *aDirtyRect)
 {
   // Invalidate the entire content area. Maybe it's not optimal but it's simple and
   // always correct.
   Invalidate(nsRect(0, 0, mRect.width, mRect.height));
 
   return NS_OK;
 }
@@ -1542,36 +1540,35 @@ NS_IMETHODIMP nsBulletListener::OnStartC
 {
   if (!mFrame)
     return NS_ERROR_FAILURE;
 
   return mFrame->OnStartContainer(aRequest, aImage);
 }
 
 NS_IMETHODIMP nsBulletListener::OnDataAvailable(imgIRequest *aRequest,
-                                                gfxIImageFrame *aFrame,
+                                                PRBool aCurrentFrame,
                                                 const nsIntRect *aRect)
 {
   if (!mFrame)
     return NS_ERROR_FAILURE;
 
-  return mFrame->OnDataAvailable(aRequest, aFrame, aRect);
+  return mFrame->OnDataAvailable(aRequest, aCurrentFrame, aRect);
 }
 
 NS_IMETHODIMP nsBulletListener::OnStopDecode(imgIRequest *aRequest,
                                              nsresult status,
                                              const PRUnichar *statusArg)
 {
   if (!mFrame)
     return NS_ERROR_FAILURE;
   
   return mFrame->OnStopDecode(aRequest, status, statusArg);
 }
 
 NS_IMETHODIMP nsBulletListener::FrameChanged(imgIContainer *aContainer,
-                                             gfxIImageFrame *newframe,
                                              nsIntRect *dirtyRect)
 {
   if (!mFrame)
     return NS_ERROR_FAILURE;
 
-  return mFrame->FrameChanged(aContainer, newframe, dirtyRect);
+  return mFrame->FrameChanged(aContainer, dirtyRect);
 }
--- a/layout/generic/nsBulletFrame.h
+++ b/layout/generic/nsBulletFrame.h
@@ -40,17 +40,16 @@
 #ifndef nsBulletFrame_h___
 #define nsBulletFrame_h___
 
 #include "nsFrame.h"
 #include "nsStyleContext.h"
 
 #include "imgIRequest.h"
 #include "imgIDecoderObserver.h"
-class gfxIImageFrame;
 
 /**
  * A simple class that manages the layout and rendering of html bullets.
  * This class also supports the CSS list-style properties.
  */
 class nsBulletFrame : public nsFrame {
 public:
   nsBulletFrame(nsStyleContext* aContext) : nsFrame(aContext) {}
@@ -76,23 +75,22 @@ public:
   virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext);
 
   // nsBulletFrame
   PRInt32 SetListItemOrdinal(PRInt32 aNextOrdinal, PRBool* aChanged);
 
 
   NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
   NS_IMETHOD OnDataAvailable(imgIRequest *aRequest,
-                             gfxIImageFrame *aFrame,
+                             PRBool aCurrentFrame,
                              const nsIntRect *aRect);
   NS_IMETHOD OnStopDecode(imgIRequest *aRequest,
                           nsresult aStatus,
                           const PRUnichar *aStatusArg);
   NS_IMETHOD FrameChanged(imgIContainer *aContainer,
-                          gfxIImageFrame *aNewframe,
                           nsIntRect *aDirtyRect);
 
   /* get list item text, without '.' */
   static PRBool AppendCounterText(PRInt32 aListStyleType,
                                   PRInt32 aOrdinal,
                                   nsString& aResult);
 
   /* get list item text, with '.' */
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -104,17 +104,16 @@
 #ifdef IBMBIDI
 #include "nsBidiPresUtils.h"
 #endif
 
 // For triple-click pref
 #include "nsIServiceManager.h"
 #include "imgIContainer.h"
 #include "imgIRequest.h"
-#include "gfxIImageFrame.h"
 #include "nsILookAndFeel.h"
 #include "nsLayoutCID.h"
 #include "nsWidgetsCID.h"     // for NS_LOOKANDFEEL_CID
 #include "nsUnicharUtils.h"
 #include "nsLayoutErrors.h"
 #include "nsContentErrors.h"
 #include "nsHTMLContainerFrame.h"
 #include "nsBoxLayoutState.h"
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -42,17 +42,16 @@
 #include "nsCOMPtr.h"
 #include "nsImageFrame.h"
 #include "nsIImageLoadingContent.h"
 #include "nsString.h"
 #include "nsPrintfCString.h"
 #include "nsPresContext.h"
 #include "nsIRenderingContext.h"
 #include "nsIPresShell.h"
-#include "nsIImage.h"
 #include "nsGkAtoms.h"
 #include "nsIDocument.h"
 #include "nsINodeInfo.h"
 #include "nsContentUtils.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsStyleContext.h"
 #include "nsStyleConsts.h"
 #include "nsImageMap.h"
@@ -88,17 +87,16 @@
 
 #include "imgIContainer.h"
 #include "imgILoader.h"
 
 #include "nsContentPolicyUtils.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsIPrefBranch2.h"
 #include "nsIPrefService.h"
-#include "gfxIImageFrame.h"
 #include "nsIDOMRange.h"
 
 #include "nsIContentPolicy.h"
 #include "nsContentPolicyUtils.h"
 #include "nsIEventStateManager.h"
 #include "nsLayoutErrors.h"
 #include "nsBidiUtils.h"
 #include "nsBidiPresUtils.h"
@@ -518,17 +516,17 @@ nsImageFrame::OnStartContainer(imgIReque
     }
   }
 
   return NS_OK;
 }
 
 nsresult
 nsImageFrame::OnDataAvailable(imgIRequest *aRequest,
-                              gfxIImageFrame *aFrame,
+                              PRBool aCurrentFrame,
                               const nsIntRect *aRect)
 {
   // XXX do we need to make sure that the reflow from the
   // OnStartContainer has been processed before we start calling
   // invalidate?
 
   NS_ENSURE_ARG_POINTER(aRect);
 
@@ -550,26 +548,18 @@ nsImageFrame::OnDataAvailable(imgIReques
 
   if (IsPendingLoad(aRequest)) {
     // We don't care
     return NS_OK;
   }
 
   // Don't invalidate if the current visible frame isn't the one the data is
   // from
-  nsCOMPtr<imgIContainer> container;
-  aRequest->GetImage(getter_AddRefs(container));
-  if (container) {
-    nsCOMPtr<gfxIImageFrame> currentFrame;
-    container->GetCurrentFrame(getter_AddRefs(currentFrame));
-    if (aFrame != currentFrame) {
-      // just bail
-      return NS_OK;
-    }
-  }
+  if (!aCurrentFrame)
+    return NS_OK;
 
 #ifdef DEBUG_decode
   printf("Source rect (%d,%d,%d,%d) -> invalidate dest rect (%d,%d,%d,%d)\n",
          aRect->x, aRect->y, aRect->width, aRect->height,
          r.x, r.y, r.width, r.height);
 #endif
 
   Invalidate(r);
@@ -629,19 +619,17 @@ nsImageFrame::OnStopDecode(imgIRequest *
       }
     }
   }
 
   return NS_OK;
 }
 
 nsresult
-nsImageFrame::FrameChanged(imgIContainer *aContainer,
-                           gfxIImageFrame *aNewFrame,
-                           nsIntRect *aDirtyRect)
+nsImageFrame::FrameChanged(imgIContainer *aContainer, nsIntRect *aDirtyRect)
 {
   if (!GetStyleVisibility()->IsVisible()) {
     return NS_OK;
   }
 
   if (IsPendingLoad(aContainer)) {
     // We don't care about it
     return NS_OK;
@@ -1828,43 +1816,42 @@ NS_IMETHODIMP nsImageListener::OnStartCo
 {
   if (!mFrame)
     return NS_ERROR_FAILURE;
 
   return mFrame->OnStartContainer(aRequest, aImage);
 }
 
 NS_IMETHODIMP nsImageListener::OnDataAvailable(imgIRequest *aRequest,
-                                               gfxIImageFrame *aFrame,
+                                               PRBool aCurrentFrame,
                                                const nsIntRect *aRect)
 {
   if (!mFrame)
     return NS_ERROR_FAILURE;
 
-  return mFrame->OnDataAvailable(aRequest, aFrame, aRect);
+  return mFrame->OnDataAvailable(aRequest, aCurrentFrame, aRect);
 }
 
 NS_IMETHODIMP nsImageListener::OnStopDecode(imgIRequest *aRequest,
                                             nsresult status,
                                             const PRUnichar *statusArg)
 {
   if (!mFrame)
     return NS_ERROR_FAILURE;
 
   return mFrame->OnStopDecode(aRequest, status, statusArg);
 }
 
 NS_IMETHODIMP nsImageListener::FrameChanged(imgIContainer *aContainer,
-                                            gfxIImageFrame *newframe,
                                             nsIntRect * dirtyRect)
 {
   if (!mFrame)
     return NS_ERROR_FAILURE;
 
-  return mFrame->FrameChanged(aContainer, newframe, dirtyRect);
+  return mFrame->FrameChanged(aContainer, dirtyRect);
 }
 
 static PRBool
 IsInAutoWidthTableCellForQuirk(nsIFrame *aFrame)
 {
   if (eCompatibility_NavQuirks != aFrame->PresContext()->CompatibilityMode())
     return PR_FALSE;
   // Check if the parent of the closest nsBlockFrame has auto width.
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -68,23 +68,22 @@ class nsImageListener : public nsStubIma
 {
 public:
   nsImageListener(nsImageFrame *aFrame);
   virtual ~nsImageListener();
 
   NS_DECL_ISUPPORTS
   // imgIDecoderObserver (override nsStubImageDecoderObserver)
   NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
-  NS_IMETHOD OnDataAvailable(imgIRequest *aRequest, gfxIImageFrame *aFrame,
+  NS_IMETHOD OnDataAvailable(imgIRequest *aRequest, PRBool aCurrentFrame,
                              const nsIntRect *aRect);
   NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult status,
                           const PRUnichar *statusArg);
   // imgIContainerObserver (override nsStubImageDecoderObserver)
-  NS_IMETHOD FrameChanged(imgIContainer *aContainer, gfxIImageFrame *newframe,
-                          nsIntRect * dirtyRect);
+  NS_IMETHOD FrameChanged(imgIContainer *aContainer, nsIntRect * dirtyRect);
 
   void SetFrame(nsImageFrame *frame) { mFrame = frame; }
 
 private:
   nsImageFrame *mFrame;
 };
 
 #define IMAGE_SIZECONSTRAINED       0x00100000
@@ -213,25 +212,22 @@ protected:
                       const nsRect&        aRect);
 
   void PaintImage(nsIRenderingContext& aRenderingContext, nsPoint aPt,
                   const nsRect& aDirtyRect, imgIContainer* aImage);
                   
 protected:
   friend class nsImageListener;
   nsresult OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
-  nsresult OnDataAvailable(imgIRequest *aRequest,
-                           gfxIImageFrame *aFrame,
+  nsresult OnDataAvailable(imgIRequest *aRequest, PRBool aCurrentFrame,
                            const nsIntRect *rect);
   nsresult OnStopDecode(imgIRequest *aRequest,
                         nsresult aStatus,
                         const PRUnichar *aStatusArg);
-  nsresult FrameChanged(imgIContainer *aContainer,
-                        gfxIImageFrame *aNewframe,
-                        nsIntRect *aDirtyRect);
+  nsresult FrameChanged(imgIContainer *aContainer, nsIntRect *aDirtyRect);
 
 private:
   // random helpers
   inline void SpecToURI(const nsAString& aSpec, nsIIOService *aIOService,
                         nsIURI **aURI);
 
   inline void GetLoadGroup(nsPresContext *aPresContext,
                            nsILoadGroup **aLoadGroup);
--- a/layout/reftests/svg/image-scaling-02.svg
+++ b/layout/reftests/svg/image-scaling-02.svg
@@ -16,11 +16,11 @@
 -->
 
 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 
   <title> Ensure images aren't scaled too small </title>
 
   <rect width="100%" height="100%" fill="lime"/>
   <rect width="183" height="183" fill="red"/>
-  <image width="183" height="183" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAABGdBTUEAALGPC%2FxhBQAAAAxJREFUGFdjYPjPAAACAgEA0dNGRAAAAABJRU5ErkJggg%3D%3D"/>
+  <image style="image-rendering: -moz-crisp-edges" width="183" height="183" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAABGdBTUEAALGPC%2FxhBQAAAAxJREFUGFdjYPjPAAACAgEA0dNGRAAAAABJRU5ErkJggg%3D%3D"/>
 
 </svg>
--- a/layout/svg/base/src/nsSVGImageFrame.cpp
+++ b/layout/svg/base/src/nsSVGImageFrame.cpp
@@ -32,42 +32,39 @@
  * 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 "nsSVGPathGeometryFrame.h"
 #include "nsIDOMSVGMatrix.h"
 #include "imgIContainer.h"
-#include "gfxIImageFrame.h"
 #include "nsStubImageDecoderObserver.h"
 #include "nsImageLoadingContent.h"
 #include "nsIDOMSVGImageElement.h"
 #include "nsLayoutUtils.h"
 #include "nsSVGImageElement.h"
 #include "nsSVGUtils.h"
 #include "nsSVGMatrix.h"
 #include "gfxContext.h"
 #include "nsIInterfaceRequestorUtils.h"
-#include "nsIImage.h"
 
 class nsSVGImageFrame;
 
 class nsSVGImageListener : public nsStubImageDecoderObserver
 {
 public:
   nsSVGImageListener(nsSVGImageFrame *aFrame);
 
   NS_DECL_ISUPPORTS
   // imgIDecoderObserver (override nsStubImageDecoderObserver)
   NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult status,
                           const PRUnichar *statusArg);
   // imgIContainerObserver (override nsStubImageDecoderObserver)
-  NS_IMETHOD FrameChanged(imgIContainer *aContainer, gfxIImageFrame *newframe,
-                          nsRect * dirtyRect);
+  NS_IMETHOD FrameChanged(imgIContainer *aContainer, nsIntRect * dirtyRect);
   // imgIContainerObserver (override nsStubImageDecoderObserver)
   NS_IMETHOD OnStartContainer(imgIRequest *aRequest,
                               imgIContainer *aContainer);
 
   void SetFrame(nsSVGImageFrame *frame) { mFrame = frame; }
 
 private:
   nsSVGImageFrame *mFrame;
@@ -238,26 +235,25 @@ nsSVGImageFrame::PaintSVG(nsSVGRenderSta
     if (imageLoader)
       imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
                               getter_AddRefs(currentRequest));
 
     if (currentRequest)
       currentRequest->GetImage(getter_AddRefs(mImageContainer));
   }
 
-  nsCOMPtr<gfxIImageFrame> currentFrame;
+  nsRefPtr<gfxASurface> currentFrame;
   if (mImageContainer)
     mImageContainer->GetCurrentFrame(getter_AddRefs(currentFrame));
 
-  nsRefPtr<gfxPattern> thebesPattern = nsnull;
-  if (currentFrame) {
-    nsCOMPtr<nsIImage> img(do_GetInterface(currentFrame));
-
-    img->GetPattern(getter_AddRefs(thebesPattern));
-  }
+  // We need to wrap the surface in a pattern to have somewhere to set the
+  // graphics filter.
+  nsRefPtr<gfxPattern> thebesPattern;
+  if (currentFrame)
+    thebesPattern = new gfxPattern(currentFrame);
 
   if (thebesPattern) {
 
     thebesPattern->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));
 
     gfxContext *gfx = aContext->GetGfxContext();
 
     if (GetStyleDisplay()->IsScrollableOverflow()) {
@@ -274,18 +270,18 @@ nsSVGImageFrame::PaintSVG(nsSVGRenderSta
     // optimize group opacity, the opacity used for compositing the
     // image into the current canvas is just the group opacity.
     float opacity = 1.0f;
     if (nsSVGUtils::CanOptimizeOpacity(this)) {
       opacity = GetStyleDisplay()->mOpacity;
     }
 
     PRInt32 nativeWidth, nativeHeight;
-    currentFrame->GetWidth(&nativeWidth);
-    currentFrame->GetHeight(&nativeHeight);
+    mImageContainer->GetWidth(&nativeWidth);
+    mImageContainer->GetHeight(&nativeHeight);
 
     nsSVGUtils::CompositePatternMatrix(gfx, thebesPattern, fini, nativeWidth, nativeHeight, opacity);
 
     if (GetStyleDisplay()->IsScrollableOverflow())
       gfx->Restore();
   }
 
   return rv;
@@ -379,18 +375,17 @@ NS_IMETHODIMP nsSVGImageListener::OnStop
   if (!mFrame)
     return NS_ERROR_FAILURE;
 
   nsSVGUtils::UpdateGraphic(mFrame);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsSVGImageListener::FrameChanged(imgIContainer *aContainer,
-                                               gfxIImageFrame *newframe,
-                                               nsRect * dirtyRect)
+                                               nsIntRect * dirtyRect)
 {
   if (!mFrame)
     return NS_ERROR_FAILURE;
 
   nsSVGUtils::UpdateGraphic(mFrame);
   return NS_OK;
 }
 
--- a/layout/xul/base/src/nsImageBoxFrame.cpp
+++ b/layout/xul/base/src/nsImageBoxFrame.cpp
@@ -53,17 +53,16 @@
 #include "nsBoxLayoutState.h"
 
 #include "nsHTMLParts.h"
 #include "nsString.h"
 #include "nsLeafFrame.h"
 #include "nsPresContext.h"
 #include "nsIRenderingContext.h"
 #include "nsIPresShell.h"
-#include "nsIImage.h"
 #include "nsIDocument.h"
 #include "nsIHTMLDocument.h"
 #include "nsStyleConsts.h"
 #include "nsImageMap.h"
 #include "nsILinkHandler.h"
 #include "nsIURL.h"
 #include "nsILoadGroup.h"
 #include "nsHTMLContainerFrame.h"
@@ -538,17 +537,16 @@ NS_IMETHODIMP nsImageBoxFrame::OnStopDec
       FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
     FireImageDOMEvent(mContent, NS_LOAD_ERROR);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsImageBoxFrame::FrameChanged(imgIContainer *container,
-                                            gfxIImageFrame *newframe,
                                             nsIntRect *dirtyRect)
 {
   nsBoxLayoutState state(PresContext());
   this->Redraw(state);
 
   return NS_OK;
 }
 
@@ -586,17 +584,16 @@ NS_IMETHODIMP nsImageBoxListener::OnStop
 {
   if (!mFrame)
     return NS_ERROR_FAILURE;
 
   return mFrame->OnStopDecode(request, status, statusArg);
 }
 
 NS_IMETHODIMP nsImageBoxListener::FrameChanged(imgIContainer *container,
-                                               gfxIImageFrame *newframe,
                                                nsIntRect *dirtyRect)
 {
   if (!mFrame)
     return NS_ERROR_FAILURE;
 
-  return mFrame->FrameChanged(container, newframe, dirtyRect);
+  return mFrame->FrameChanged(container, dirtyRect);
 }
 
--- a/layout/xul/base/src/nsImageBoxFrame.h
+++ b/layout/xul/base/src/nsImageBoxFrame.h
@@ -54,18 +54,17 @@ public:
 
   NS_DECL_ISUPPORTS
   // imgIDecoderObserver (override nsStubImageDecoderObserver)
   NS_IMETHOD OnStartContainer(imgIRequest *request, imgIContainer *image);
   NS_IMETHOD OnStopContainer(imgIRequest *request, imgIContainer *image);
   NS_IMETHOD OnStopDecode(imgIRequest *request, nsresult status,
                           const PRUnichar *statusArg);
   // imgIContainerObserver (override nsStubImageDecoderObserver)
-  NS_IMETHOD FrameChanged(imgIContainer *container, gfxIImageFrame *newframe,
-                          nsIntRect *dirtyRect);
+  NS_IMETHOD FrameChanged(imgIContainer *container, nsIntRect *dirtyRect);
 
   void SetFrame(nsImageBoxFrame *frame) { mFrame = frame; }
 
 private:
   nsImageBoxFrame *mFrame;
 };
 
 class nsImageBoxFrame : public nsLeafBoxFrame
@@ -116,19 +115,17 @@ public:
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists);
 
   NS_IMETHOD OnStartContainer(imgIRequest *request, imgIContainer *image);
   NS_IMETHOD OnStopContainer(imgIRequest *request, imgIContainer *image);
   NS_IMETHOD OnStopDecode(imgIRequest *request,
                           nsresult status,
                           const PRUnichar *statusArg);
-  NS_IMETHOD FrameChanged(imgIContainer *container,
-                          gfxIImageFrame *newframe,
-                          nsIntRect *dirtyRect);
+  NS_IMETHOD FrameChanged(imgIContainer *container, nsIntRect *dirtyRect);
 
   virtual ~nsImageBoxFrame();
 
   void  PaintImage(nsIRenderingContext& aRenderingContext,
                    const nsRect& aDirtyRect,
                    nsPoint aPt);
 
 protected:
--- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
+++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
@@ -2168,21 +2168,21 @@ nsTreeBodyFrame::GetImage(PRInt32 aRowIn
   // Look the image up in our cache.
   nsTreeImageCacheEntry entry;
   if (mImageCache.Get(imageSrc, &entry)) {
     // Find out if the image has loaded.
     PRUint32 status;
     imgIRequest *imgReq = entry.request;
     imgReq->GetImageStatus(&status);
     imgReq->GetImage(aResult); // We hand back the image here.  The GetImage call addrefs *aResult.
-    PRUint32 numFrames = 1;
+    PRBool animated = PR_FALSE;
     if (*aResult)
-      (*aResult)->GetNumFrames(&numFrames);
-
-    if ((!(status & imgIRequest::STATUS_LOAD_COMPLETE)) || numFrames > 1) {
+      (*aResult)->GetAnimated(&animated);
+
+    if ((!(status & imgIRequest::STATUS_LOAD_COMPLETE)) || animated) {
       // We either aren't done loading, or we're animating. Add our row as a listener for invalidations.
       nsCOMPtr<imgIDecoderObserver> obs;
       imgReq->GetDecoderObserver(getter_AddRefs(obs));
       nsCOMPtr<nsITreeImageListener> listener(do_QueryInterface(obs));
       if (listener)
         listener->AddCell(aRowIndex, aCol);
       return NS_OK;
     }
--- a/layout/xul/base/src/tree/src/nsTreeImageListener.cpp
+++ b/layout/xul/base/src/tree/src/nsTreeImageListener.cpp
@@ -59,25 +59,24 @@ NS_IMETHODIMP nsTreeImageListener::OnSta
                                                     imgIContainer *aImage)
 {
   // Ensure the animation (if any) is started
   aImage->StartAnimation();                                                     
   return NS_OK;
 }
 
 NS_IMETHODIMP nsTreeImageListener::OnDataAvailable(imgIRequest *aRequest,
-                                                   gfxIImageFrame *aFrame,
+                                                   PRBool aCurrentFrame,
                                                    const nsIntRect *aRect)
 {
   Invalidate();
   return NS_OK;
 }
 
 NS_IMETHODIMP nsTreeImageListener::FrameChanged(imgIContainer *aContainer,
-                                                gfxIImageFrame *newframe,
                                                 nsIntRect *dirtyRect)
 {
   Invalidate();
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
--- a/layout/xul/base/src/tree/src/nsTreeImageListener.h
+++ b/layout/xul/base/src/tree/src/nsTreeImageListener.h
@@ -67,21 +67,20 @@ class nsTreeImageListener : public nsStu
 {
 public:
   nsTreeImageListener(nsITreeBoxObject* aTree);
   ~nsTreeImageListener();
 
   NS_DECL_ISUPPORTS
   // imgIDecoderObserver (override nsStubImageDecoderObserver)
   NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
-  NS_IMETHOD OnDataAvailable(imgIRequest *aRequest, gfxIImageFrame *aFrame,
+  NS_IMETHOD OnDataAvailable(imgIRequest *aRequest, PRBool aCurrentFrame,
                              const nsIntRect *aRect);
   // imgIContainerObserver (override nsStubImageDecoderObserver)
-  NS_IMETHOD FrameChanged(imgIContainer *aContainer, gfxIImageFrame *newframe,
-                          nsIntRect *dirtyRect);
+  NS_IMETHOD FrameChanged(imgIContainer *aContainer, nsIntRect *dirtyRect);
 
   NS_IMETHOD AddCell(PRInt32 aIndex, nsITreeColumn* aCol);
  
   friend class nsTreeBodyFrame;
 
 protected:
   void UnsuppressInvalidation() { mInvalidationSuppressed = PR_FALSE; }
   void Invalidate();
--- a/modules/libpr0n/build/nsImageModule.cpp
+++ b/modules/libpr0n/build/nsImageModule.cpp
@@ -42,16 +42,17 @@
 #ifdef XP_MAC
 #define IMG_BUILD_gif 1
 #define IMG_BUILD_bmp 1
 #define IMG_BUILD_png 1
 #define IMG_BUILD_jpeg 1
 #define IMG_BUILD_xbm 1
 #endif
 
+#include "nsIDeviceContext.h"
 #include "nsIGenericFactory.h"
 #include "nsIModule.h"
 #include "nsICategoryManager.h"
 #include "nsXPCOMCID.h"
 #include "nsServiceManagerUtils.h"
 
 #include "imgContainer.h"
 #include "imgLoader.h"
@@ -201,17 +202,17 @@ static NS_METHOD ImageUnregisterProc(nsI
 static const nsModuleComponentInfo components[] =
 {
   { "image cache",
     NS_IMGLOADER_CID,
     "@mozilla.org/image/cache;1",
     imgLoaderConstructor, },
   { "image container",
     NS_IMGCONTAINER_CID,
-    "@mozilla.org/image/container;1",
+    "@mozilla.org/image/container;2",
     imgContainerConstructor, },
   { "image loader",
     NS_IMGLOADER_CID,
     "@mozilla.org/image/loader;1",
     imgLoaderConstructor,
     ImageRegisterProc, /* register the decoder mime types here */
     ImageUnregisterProc, },
   { "image request proxy",
@@ -308,16 +309,22 @@ static const nsModuleComponentInfo compo
      "@mozilla.org/image/decoder;2?type=image/xbm",
      nsXBMDecoderConstructor, },
 #endif
 };
 
 static nsresult
 imglib_Initialize(nsIModule* aSelf)
 {
+  // Hack: We need the gfx module to be initialized because we use gfxPlatform
+  // in imgFrame. Request something from the gfx module to ensure that
+  // everything's set up for us.
+  nsCOMPtr<nsIDeviceContext> devctx = 
+    do_CreateInstance("@mozilla.org/gfx/devicecontext;1");
+
   imgLoader::InitCache();
   return NS_OK;
 }
 
 static void
 imglib_Shutdown(nsIModule* aSelf)
 {
   imgLoader::Shutdown();
--- a/modules/libpr0n/decoders/bmp/nsBMPDecoder.cpp
+++ b/modules/libpr0n/decoders/bmp/nsBMPDecoder.cpp
@@ -46,17 +46,16 @@
 
 #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)
@@ -84,40 +83,35 @@ nsBMPDecoder::~nsBMPDecoder()
 }
 
 NS_IMETHODIMP nsBMPDecoder::Init(imgILoad *aLoad)
 {
     PR_LOG(gBMPLog, PR_LOG_DEBUG, ("nsBMPDecoder::Init(%p)\n", aLoad));
     mObserver = do_QueryInterface(aLoad);
 
     nsresult rv;
-    mImage = do_CreateInstance("@mozilla.org/image/container;1", &rv);
-    if (NS_FAILED(rv))
-        return rv;
-
-    mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2", &rv);
+    mImage = do_CreateInstance("@mozilla.org/image/container;2", &rv);
     if (NS_FAILED(rv))
         return rv;
 
     return aLoad->SetImage(mImage);
 }
 
 NS_IMETHODIMP nsBMPDecoder::Close()
 {
     PR_LOG(gBMPLog, PR_LOG_DEBUG, ("nsBMPDecoder::Close()\n"));
 
     mImage->DecodingComplete();
     if (mObserver) {
-        mObserver->OnStopFrame(nsnull, mFrame);
+        mObserver->OnStopFrame(nsnull, 0);
         mObserver->OnStopContainer(nsnull, mImage);
         mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
         mObserver = nsnull;
     }
     mImage = nsnull;
-    mFrame = nsnull;
     return NS_OK;
 }
 
 NS_IMETHODIMP nsBMPDecoder::Flush()
 {
     return NS_OK;
 }
 
@@ -261,50 +255,48 @@ NS_METHOD nsBMPDecoder::ProcessData(cons
 
         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);
         mOldLine = mCurLine = real_height;
 
+        PRUint32 imageLength;
         if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
-            rv = mFrame->Init(0, 0, mBIH.width, real_height, RLE_GFXFORMAT_ALPHA, 24);
+            rv = mImage->AppendFrame(0, 0, mBIH.width, real_height, gfxASurface::ImageFormatARGB32,
+                                     (PRUint8**)&mImageData, &imageLength);
         } 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);
+            rv = mImage->AppendFrame(0, 0, mBIH.width, real_height, gfxASurface::ImageFormatRGB24,
+                                     (PRUint8**)&mImageData, &imageLength);
         }
         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);
+        mObserver->OnStartFrame(nsnull, 0);
         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
@@ -598,24 +590,21 @@ NS_METHOD nsBMPDecoder::ProcessData(cons
         }
     }
     
     const PRUint32 rows = mOldLine - mCurLine;
     if (rows) {
         nsIntRect r(0, mBIH.height < 0 ? -mBIH.height - mOldLine : mCurLine,
                     mBIH.width, rows);
 
-        // Tell the image that it's data has been updated
-        nsCOMPtr<nsIImage> img(do_GetInterface(mFrame, &rv));
+        // Tell the image that its data has been updated
+        rv = mImage->FrameUpdated(0, r); 
         NS_ENSURE_SUCCESS(rv, rv);
-        rv = img->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r);        
-        if (NS_FAILED(rv))
-          return rv;
 
-        mObserver->OnDataAvailable(nsnull, mFrame, &r);
+        mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
         mOldLine = mCurLine;
     }
 
     return NS_OK;
 }
 
 void nsBMPDecoder::ProcessFileHeader()
 {
--- a/modules/libpr0n/decoders/bmp/nsBMPDecoder.h
+++ b/modules/libpr0n/decoders/bmp/nsBMPDecoder.h
@@ -38,17 +38,16 @@
 
 #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 } \
@@ -113,19 +112,16 @@ struct bitFields {
                                (((((PRUint32) x) >> 16) & 0xFF) << 8) | \
                                (((PRUint32) x) >> 24))
 #else
 #define LITTLE_TO_NATIVE16(x) x
 #define LITTLE_TO_NATIVE32(x) x
 #endif
 
 #define USE_RGB
-#define BMP_GFXFORMAT gfxIFormats::RGB
-#define RLE_GFXFORMAT_ALPHA gfxIFormats::RGB_A1
-#define GFXBYTESPERPIXEL 4
 
 // BMPINFOHEADER.compression defines
 #define BI_RLE8 1
 #define BI_RLE4 2
 #define BI_BITFIELDS 3
 
 // RLE Escape codes
 #define RLE_ESCAPE       0
@@ -168,17 +164,16 @@ private:
 
     /** Calculates the red-, green- and blueshift in mBitFields using
      * the bitmasks from mBitFields */
     NS_METHOD CalcBitShift();
 
     nsCOMPtr<imgIDecoderObserver> mObserver;
 
     nsCOMPtr<imgIContainer> mImage;
-    nsCOMPtr<gfxIImageFrame> mFrame;
 
     PRUint32 mPos;
 
     BMPFILEHEADER mBFH;
     BMPINFOHEADER mBIH;
     char mRawBuf[36];
 
     PRUint32 mLOH; ///< Length of the header
--- a/modules/libpr0n/decoders/bmp/nsICODecoder.cpp
+++ b/modules/libpr0n/decoders/bmp/nsICODecoder.cpp
@@ -46,17 +46,16 @@
 
 #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)
 
@@ -88,49 +87,40 @@ nsICODecoder::nsICODecoder()
 nsICODecoder::~nsICODecoder()
 {
 }
 
 NS_IMETHODIMP nsICODecoder::Init(imgILoad *aLoad)
 { 
   mObserver = do_QueryInterface(aLoad);
     
-  mImage = do_CreateInstance("@mozilla.org/image/container;1");
+  mImage = do_CreateInstance("@mozilla.org/image/container;2");
   if (!mImage)
     return NS_ERROR_OUT_OF_MEMORY;
 
-  mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
-  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));
-  nsresult rv = NS_OK;
-  if (img) 
-    rv = img->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r);
+  nsresult rv = mImage->FrameUpdated(0, r);
     
   mImage->DecodingComplete();
 
   if (mObserver) {
-    mObserver->OnDataAvailable(nsnull, mFrame, &r);
-    mObserver->OnStopFrame(nsnull, mFrame);
-    mObserver->OnStopContainer(nsnull, mImage);
+    mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
+    mObserver->OnStopFrame(nsnull, 0);
+    mObserver->OnStopContainer(nsnull, 0);
     mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
     mObserver = nsnull;
   }
 
   mImage = nsnull;
-  mFrame = nsnull;
  
   mPos = 0;
 
   delete[] mColors;
   mColors = nsnull;
 
   mCurLine = 0;
   mRowBytes = 0;
@@ -299,25 +289,23 @@ nsresult nsICODecoder::ProcessData(const
     mCurLine = mDirEntry.mHeight;
     mRow = (PRUint8*)malloc((mDirEntry.mWidth * mBIH.bpp)/8 + 4);
     // +4 because the line is padded to a 4 bit boundary, but I don't want
     // to make exact calculations here, that's unnecessary.
     // Also, it compensates rounding error.
     if (!mRow)
       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);
+    PRUint32 imageLength;
+    rv = mImage->AppendFrame(0, 0, mDirEntry.mWidth, mDirEntry.mHeight,
+                             gfxASurface::ImageFormatARGB32, (PRUint8**)&mImageData, &imageLength);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    PRUint32 imageLength;
-    mFrame->GetImageData((PRUint8**)&mImageData, &imageLength);
+    mObserver->OnStartFrame(nsnull, 0);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   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;
--- a/modules/libpr0n/decoders/bmp/nsICODecoder.h
+++ b/modules/libpr0n/decoders/bmp/nsICODecoder.h
@@ -39,30 +39,22 @@
 
 #ifndef _nsICODecoder_h
 #define _nsICODecoder_h
 
 #include "nsCOMPtr.h"
 #include "imgIDecoder.h"
 #include "imgIContainer.h"
 #include "imgIDecoderObserver.h"
-#include "gfxIImageFrame.h"
 #include "nsBMPDecoder.h"
 
 // {CB3EDE1A-0FA5-4e27-AAFE-0F7801E5A1F1}
 #define NS_ICODECODER_CID \
 { 0xcb3ede1a, 0xfa5, 0x4e27, { 0xaa, 0xfe, 0xf, 0x78, 0x1, 0xe5, 0xa1, 0xf1 } }
 
-#if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
-#define GFXFORMATALPHA8 gfxIFormats::BGR_A8
-#else
-#define USE_RGBA1
-#define GFXFORMATALPHA8 gfxIFormats::RGB_A8
-#endif
-
 struct IconDirEntry
 {
   PRUint8   mWidth;
   PRUint8   mHeight;
   PRUint8   mColorCount;
   PRUint8   mReserved;
   union {
     PRUint16 mPlanes;   // ICO
@@ -98,17 +90,16 @@ private:
 
   nsresult SetImageData();
 
   PRUint32 CalcAlphaRowSize();
 
 private:
   nsCOMPtr<imgIDecoderObserver> mObserver;
   nsCOMPtr<imgIContainer> mImage;
-  nsCOMPtr<gfxIImageFrame> mFrame;
   
   PRUint32 mPos;
   PRUint16 mNumIcons;
   PRUint16 mCurrIcon;
   PRUint32 mImageOffset;
 
   char mDirEntryArray[16];
   IconDirEntry mDirEntry;
--- a/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp
+++ b/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp
@@ -69,17 +69,16 @@ CompuServe Incorporated maintains a mail
 organizations who wish to receive copies of this document when it is corrected
 or revised. This service is offered free of charge; please provide us with your
 mailing address.
 */
 
 #include <stddef.h>
 #include "prmem.h"
 
-#include "nsIImage.h"
 #include "nsIInterfaceRequestorUtils.h"
 
 #include "nsGIFDecoder2.h"
 #include "nsIInputStream.h"
 #include "nsIComponentManager.h"
 #include "imgIContainerObserver.h"
 
 #include "imgILoad.h"
@@ -137,17 +136,17 @@ nsGIFDecoder2::~nsGIFDecoder2()
 //******************************************************************************
 
 //******************************************************************************
 /* void init (in imgILoad aLoad); */
 NS_IMETHODIMP nsGIFDecoder2::Init(imgILoad *aLoad)
 {
   mObserver = do_QueryInterface(aLoad);
 
-  mImageContainer = do_CreateInstance("@mozilla.org/image/container;1");
+  mImageContainer = do_CreateInstance("@mozilla.org/image/container;2");
   aLoad->SetImage(mImageContainer);
   
   // Start with the version (GIF89a|GIF87a)
   mGIFStruct.state = gif_type;
   mGIFStruct.bytes_to_consume = 6;
 
   return NS_OK;
 }
@@ -156,18 +155,17 @@ NS_IMETHODIMP nsGIFDecoder2::Init(imgILo
 //******************************************************************************
 /** nsIOutputStream methods **/
 //******************************************************************************
 
 //******************************************************************************
 /* void close (); */
 NS_IMETHODIMP nsGIFDecoder2::Close()
 {
-  if (mImageFrame) 
-    EndImageFrame();
+  EndImageFrame();
   EndGIF();
 
   PR_FREEIF(mGIFStruct.local_colormap);
 
   return NS_OK;
 }
 
 //******************************************************************************
@@ -200,27 +198,28 @@ static NS_METHOD ReadDataOut(nsIInputStr
 // mCurrentRow/mLastFlushedRow.  Note: caller is responsible for
 // updating mlastFlushed{Row,Pass}.
 nsresult
 nsGIFDecoder2::FlushImageData(PRUint32 fromRow, PRUint32 rows)
 {
   nsIntRect r(0, fromRow, mGIFStruct.width, rows);
 
   // Update image  
-  nsCOMPtr<nsIImage> img(do_GetInterface(mImageFrame));
-  nsresult rv = img->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r);
+  nsresult rv = mImageContainer->FrameUpdated(mGIFStruct.images_decoded, r);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // Offset to the frame position
   // Only notify observer(s) for first frame
   if (!mGIFStruct.images_decoded && mObserver) {
+    PRUint32 imgCurFrame;
+    mImageContainer->GetCurrentFrameIndex(&imgCurFrame);
     r.y += mGIFStruct.y_offset;
-    mObserver->OnDataAvailable(nsnull, mImageFrame, &r);
+    mObserver->OnDataAvailable(nsnull, imgCurFrame == PRUint32(mGIFStruct.images_decoded), &r);
   }
   return NS_OK;
 }
 
 nsresult
 nsGIFDecoder2::FlushImageData()
 {
   nsresult rv = NS_OK;
@@ -246,17 +245,17 @@ nsGIFDecoder2::FlushImageData()
 nsresult nsGIFDecoder2::ProcessData(unsigned char *data, PRUint32 count, PRUint32 *_retval)
 {
   // Push the data to the GIF decoder
   
   nsresult rv = GifWrite(data, count);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Flushing is only needed for first frame
-  if (!mGIFStruct.images_decoded && mImageFrame) {
+  if (!mGIFStruct.images_decoded) {
     rv = FlushImageData();
     mLastFlushedRow = mCurrentRow;
     mLastFlushedPass = mCurrentPass;
   }
 
   *_retval = count;
 
   return rv;
@@ -319,114 +318,116 @@ void nsGIFDecoder2::EndGIF()
   mImageContainer->DecodingComplete();
 
   mGIFOpen = PR_FALSE;
 }
 
 //******************************************************************************
 void nsGIFDecoder2::BeginImageFrame(gfx_depth aDepth)
 {
-  mImageFrame = nsnull; // clear out our current frame reference
-
   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);
+      PRUint32 imgCurFrame;
+      mImageContainer->GetCurrentFrameIndex(&imgCurFrame);
       nsIntRect r(0, 0, imgWidth, mGIFStruct.y_offset);
-      mObserver->OnDataAvailable(nsnull, mImageFrame, &r);
+      mObserver->OnDataAvailable(nsnull, imgCurFrame == PRUint32(mGIFStruct.images_decoded), &r);
     }
   }
 
+  PRUint32 imageDataLength;
+  nsresult rv;
+  gfxASurface::gfxImageFormat format;
+  if (mGIFStruct.is_transparent)
+    format = gfxASurface::ImageFormatARGB32;
+  else
+    format = gfxASurface::ImageFormatRGB24;
+
   // Use correct format, RGB for first frame, PAL for following frames
   // and include transparency to allow for optimization of opaque images
-  gfx_format format;
   if (mGIFStruct.images_decoded) {
     // Image data is stored with original depth and palette
-    format = mGIFStruct.is_transparent ? gfxIFormats::PAL_A1 : gfxIFormats::PAL;
+    rv = mImageContainer->AppendPalettedFrame(mGIFStruct.x_offset, mGIFStruct.y_offset,
+                                              mGIFStruct.width, mGIFStruct.height,
+                                              format, aDepth, &mImageData, &imageDataLength,
+                                              &mColormap, &mColormapSize);
+
+
   } else {
     // Regardless of depth of input, image is decoded into 24bit RGB
-    format = mGIFStruct.is_transparent ? gfxIFormats::RGB_A1 : gfxIFormats::RGB;
-    aDepth = 24;
+    rv = mImageContainer->AppendFrame(mGIFStruct.x_offset, mGIFStruct.y_offset,
+                                      mGIFStruct.width, mGIFStruct.height,
+                                      format, &mImageData, &imageDataLength);
   }
 
-  // initialize the frame and append it to the container
-  mImageFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
-  if (!mImageFrame || NS_FAILED(mImageFrame->Init(
-        mGIFStruct.x_offset, mGIFStruct.y_offset, 
-        mGIFStruct.width, mGIFStruct.height, format, aDepth))) {
-    mImageFrame = 0;
+  if (NS_FAILED(rv))
     return;
-  }
 
-  mImageFrame->SetFrameDisposalMethod(mGIFStruct.disposal_method);
-  if (!mGIFStruct.images_decoded)
-    mImageContainer->AppendFrame(mImageFrame);
+  mImageContainer->SetFrameDisposalMethod(mGIFStruct.images_decoded,
+                                          mGIFStruct.disposal_method);
 
   if (mObserver)
-    mObserver->OnStartFrame(nsnull, mImageFrame);
-
-  PRUint32 imageDataLength;
-  mImageFrame->GetImageData(&mImageData, &imageDataLength);
+    mObserver->OnStartFrame(nsnull, mGIFStruct.images_decoded);
 }
 
 
 //******************************************************************************
 void nsGIFDecoder2::EndImageFrame()
 {
   // First flush all pending image data 
   if (!mGIFStruct.images_decoded) {
     // Only need to flush first frame
     (void) FlushImageData();
 
     // If the first frame is smaller in height than the entire image, send a
     // OnDataAvailable (Display Refresh) for the area it does not have data for.
     // This will clear the remaining bits of the placeholder. (Bug 37589)
     const PRUint32 realFrameHeight = mGIFStruct.height + mGIFStruct.y_offset;
     if (realFrameHeight < mGIFStruct.screen_height) {
+      PRUint32 imgCurFrame;
+      mImageContainer->GetCurrentFrameIndex(&imgCurFrame);
       nsIntRect r(0, realFrameHeight, 
                   mGIFStruct.screen_width, 
 				  mGIFStruct.screen_height - realFrameHeight);
-      mObserver->OnDataAvailable(nsnull, mImageFrame, &r);
+      mObserver->OnDataAvailable(nsnull, imgCurFrame == PRUint32(mGIFStruct.images_decoded), &r);
     }
     // This transparency check is only valid for first frame
     if (mGIFStruct.is_transparent && !mSawTransparency) {
-      nsCOMPtr<nsIImage> img(do_GetInterface(mImageFrame));
-      img->SetHasNoAlpha();
+      mImageContainer->SetFrameHasNoAlpha(mGIFStruct.images_decoded);
     }
   }
   mCurrentRow = mLastFlushedRow = -1;
   mCurrentPass = mLastFlushedPass = 0;
 
+  PRUint32 curframe = mGIFStruct.images_decoded;
+
   // Only add frame if we have any rows at all
   if (mGIFStruct.rows_remaining != mGIFStruct.height) {
     if (mGIFStruct.rows_remaining && mGIFStruct.images_decoded) {
       // Clear the remaining rows (only needed for the animation frames)
       PRUint8 *rowp = mImageData + ((mGIFStruct.height - mGIFStruct.rows_remaining) * mGIFStruct.width);
       memset(rowp, 0, mGIFStruct.rows_remaining * mGIFStruct.width);
     }
 
     // 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 (mGIFStruct.images_decoded)
-      mImageContainer->AppendFrame(mImageFrame);
+    mImageContainer->SetFrameTimeout(mGIFStruct.images_decoded, mGIFStruct.delay_time);
     mImageContainer->EndFrameDecode(mGIFStruct.images_decoded);
-    mGIFStruct.images_decoded++; 
+
+    mGIFStruct.images_decoded++;
   }
 
   if (mObserver)
-    mObserver->OnStopFrame(nsnull, mImageFrame);
-
-  // Release reference to this frame
-  mImageFrame = nsnull;
+    mObserver->OnStopFrame(nsnull, curframe);
 
   // Reset the transparent pixel
   if (mOldColor) {
     mColormap[mGIFStruct.tpixel] = mOldColor;
     mOldColor = 0;
   }
 }
 
@@ -492,17 +493,17 @@ PRUint32 nsGIFDecoder2::OutputRow()
         }
       }
     }
 
     // Duplicate rows
     if (drow_end > drow_start) {
       // irow is the current row filled
       for (int r = drow_start; r <= drow_end; r++) {
-        if (r != mGIFStruct.irow) {
+        if (r != int(mGIFStruct.irow)) {
           memcpy(mImageData + (r * bpr), rowp, bpr);
         }
       }
     }
   }
 
   mCurrentRow = drow_end;
   mCurrentPass = mGIFStruct.ipass;
@@ -1055,17 +1056,17 @@ nsresult nsGIFDecoder2::GifWrite(const P
       // Make sure the transparent pixel is within colormap space
       PRUint32 realDepth = depth;
       while (mGIFStruct.tpixel >= (1 << realDepth) && (realDepth < 8)) {
         realDepth++;
       } 
       BeginImageFrame(realDepth);
       
       // handle allocation error
-      if (!mImageFrame) {
+      if (!mImageData) {
         mGIFStruct.state = gif_error;
         break;
       }
 
       if (q[8] & 0x40) {
         mGIFStruct.interlaced = PR_TRUE;
         mGIFStruct.ipass = 1;
       } else {
@@ -1081,58 +1082,52 @@ nsresult nsGIFDecoder2::GifWrite(const P
       mGIFStruct.rows_remaining = mGIFStruct.height;
       mGIFStruct.rowp = mImageData;
 
       /* bits per pixel is q[8]&0x07 */
 
       if (q[8] & 0x80) /* has a local colormap? */
       {
         mGIFStruct.local_colormap_size = 1 << depth;
-        PRUint32 paletteSize;
-        if (mGIFStruct.images_decoded) {
-          // Copy directly into the palette of current frame,
-          // by pointing mColormap to that palette.
-          mImageFrame->GetPaletteData(&mColormap, &paletteSize);
-        } else {
+        if (!mGIFStruct.images_decoded) {
           // First frame has local colormap, allocate space for it
           // as the image frame doesn't have its own palette
-          paletteSize = sizeof(PRUint32) << realDepth;
+          mColormapSize = sizeof(PRUint32) << realDepth;
           if (!mGIFStruct.local_colormap) {
-            mGIFStruct.local_colormap = (PRUint32*)PR_MALLOC(paletteSize);
+            mGIFStruct.local_colormap = (PRUint32*)PR_MALLOC(mColormapSize);
             if (!mGIFStruct.local_colormap) {
               mGIFStruct.state = gif_oom;
               break;
             }
           }
           mColormap = mGIFStruct.local_colormap;
         }
         const PRUint32 size = 3 << depth;
-        if (paletteSize > size) {
+        if (mColormapSize > size) {
           // Clear the notfilled part of the colormap
-          memset(((PRUint8*)mColormap) + size, 0, paletteSize - size);
+          memset(((PRUint8*)mColormap) + size, 0, mColormapSize - size);
         }
         if (len < size) {
           // Use 'hold' pattern to get the image colormap
           GETN(size, gif_image_colormap);
           break;
         }
         // Copy everything, go to colormap state to do CMS correction
         memcpy(mColormap, buf, size);
         buf += size;
         len -= size;
         GETN(0, gif_image_colormap);
         break;
       } else {
         /* Switch back to the global palette */
-        mColormap = mGIFStruct.global_colormap;
         if (mGIFStruct.images_decoded) {
           // Copy global colormap into the palette of current frame
-          PRUint32 size;
-          mImageFrame->GetPaletteData(&mColormap, &size);
-          memcpy(mColormap, mGIFStruct.global_colormap, size);
+          memcpy(mColormap, mGIFStruct.global_colormap, mColormapSize);
+        } else {
+          mColormap = mGIFStruct.global_colormap;
         }
       }
       GETN(1, gif_lzw_start);
     }
     break;
 
     case gif_image_colormap:
       // Everything is already copied into local_colormap
--- a/modules/libpr0n/decoders/gif/nsGIFDecoder2.h
+++ b/modules/libpr0n/decoders/gif/nsGIFDecoder2.h
@@ -39,17 +39,16 @@
 
 #ifndef _nsGIFDecoder2_h
 #define _nsGIFDecoder2_h
 
 #include "nsCOMPtr.h"
 #include "imgIDecoder.h"
 #include "imgIContainer.h"
 #include "imgIDecoderObserver.h"
-#include "gfxIImageFrame.h"
 
 #include "GIF2.h"
 
 #define NS_GIFDECODER2_CID \
 { /* 797bec5a-1dd2-11b2-a7f8-ca397e0179c4 */         \
      0x797bec5a,                                     \
      0x1dd2,                                         \
      0x11b2,                                         \
@@ -83,23 +82,23 @@ private:
 
   nsresult  GifWrite(const PRUint8 * buf, PRUint32 numbytes);
   PRUint32  OutputRow();
   PRBool    DoLzw(const PRUint8 *q);
 
   inline int ClearCode() const { return 1 << mGIFStruct.datasize; }
 
   nsCOMPtr<imgIContainer> mImageContainer;
-  nsCOMPtr<gfxIImageFrame> mImageFrame;
   nsCOMPtr<imgIDecoderObserver> mObserver; // this is just qi'd from mRequest for speed
   PRInt32 mCurrentRow;
   PRInt32 mLastFlushedRow;
 
   PRUint8 *mImageData;       // Pointer to image data in either Cairo or 8bit format
   PRUint32 *mColormap;       // Current colormap to be used in Cairo format
+  PRUint32 mColormapSize;
   PRUint32 mOldColor;        // The old value of the transparent pixel
   PRUint8 mCurrentPass;
   PRUint8 mLastFlushedPass;
   PRPackedBool mGIFOpen;
   PRPackedBool mSawTransparency;
 
   gif_struct mGIFStruct;
 };
--- a/modules/libpr0n/decoders/icon/nsIconDecoder.cpp
+++ b/modules/libpr0n/decoders/icon/nsIconDecoder.cpp
@@ -42,17 +42,16 @@
 #include "imgIContainer.h"
 #include "imgIContainerObserver.h"
 #include "imgILoad.h"
 #include "nspr.h"
 #include "nsIComponentManager.h"
 #include "nsRect.h"
 #include "nsComponentManagerUtils.h"
 
-#include "nsIImage.h"
 #include "nsIInterfaceRequestorUtils.h"
 
 NS_IMPL_THREADSAFE_ADDREF(nsIconDecoder)
 NS_IMPL_THREADSAFE_RELEASE(nsIconDecoder)
 
 NS_INTERFACE_MAP_BEGIN(nsIconDecoder)
    NS_INTERFACE_MAP_ENTRY(imgIDecoder)
 NS_INTERFACE_MAP_END_THREADSAFE
@@ -66,34 +65,31 @@ nsIconDecoder::~nsIconDecoder()
 
 
 /** imgIDecoder methods **/
 
 NS_IMETHODIMP nsIconDecoder::Init(imgILoad *aLoad)
 {
   mObserver = do_QueryInterface(aLoad);  // we're holding 2 strong refs to the request.
 
-  mImage = do_CreateInstance("@mozilla.org/image/container;1");
+  mImage = do_CreateInstance("@mozilla.org/image/container;2");
   if (!mImage) return NS_ERROR_OUT_OF_MEMORY;
 
   aLoad->SetImage(mImage);                                                   
 
-  mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
-  if (!mFrame) return NS_ERROR_OUT_OF_MEMORY;
-
   return NS_OK;
 }
 
 NS_IMETHODIMP nsIconDecoder::Close()
 {
   mImage->DecodingComplete();
 
   if (mObserver) 
   {
-    mObserver->OnStopFrame(nsnull, mFrame);
+    mObserver->OnStopFrame(nsnull, 0);
     mObserver->OnStopContainer(nsnull, mImage);
     mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
   }
   
   return NS_OK;
 }
 
 NS_IMETHODIMP nsIconDecoder::Flush()
@@ -115,40 +111,37 @@ NS_IMETHODIMP nsIconDecoder::WriteFrom(n
   NS_ENSURE_TRUE(w > 0 && h > 0, NS_ERROR_UNEXPECTED);
 
   if (mObserver)
     mObserver->OnStartDecode(nsnull);
   mImage->Init(w, h, mObserver);
   if (mObserver)
     mObserver->OnStartContainer(nsnull, mImage);
 
-  rv = mFrame->Init(0, 0, w, h, gfxIFormats::BGRA, 24);
+  PRUint32 imageLen;
+  PRUint8 *imageData;
+
+  rv = mImage->AppendFrame(0, 0, w, h, gfxASurface::ImageFormatARGB32, &imageData, &imageLen);
   if (NS_FAILED(rv))
     return rv;
 
-  mImage->AppendFrame(mFrame);
   if (mObserver)
-    mObserver->OnStartFrame(nsnull, mFrame);
-
-  PRUint32 imageLen;
-  PRUint8 *imageData;
-  mFrame->GetImageData(&imageData, &imageLen);
+    mObserver->OnStartFrame(nsnull, 0);
 
   // Ensure that there enough in the inputStream
   NS_ENSURE_TRUE(count >= imageLen, NS_ERROR_UNEXPECTED);
 
   // Read the image data direct into the frame data
   rv = inStr->Read((char*)imageData, imageLen, &readLen);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(readLen == imageLen, NS_ERROR_UNEXPECTED);
 
   // Notify the image...
   nsIntRect r(0, 0, w, h);
-  nsCOMPtr<nsIImage> img(do_GetInterface(mFrame));
-  rv = img->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r);
+  rv = mImage->FrameUpdated(0, r);
   if (NS_FAILED(rv))
     return rv;
 
-  mObserver->OnDataAvailable(nsnull, mFrame, &r);
+  mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
 
   return NS_OK;
 }
 
--- a/modules/libpr0n/decoders/icon/nsIconDecoder.h
+++ b/modules/libpr0n/decoders/icon/nsIconDecoder.h
@@ -41,17 +41,16 @@
 #define nsIconDecoder_h__
 
 #include "imgIDecoder.h"
 
 #include "nsCOMPtr.h"
 
 #include "imgIContainer.h"
 #include "imgIDecoderObserver.h"
-#include "gfxIImageFrame.h"
 
 #define NS_ICONDECODER_CID                           \
 { /* FFC08380-256C-11d5-9905-001083010E9B */         \
      0xffc08380,                                     \
      0x256c,                                         \
      0x11d5,                                         \
     { 0x99, 0x5, 0x0, 0x10, 0x83, 0x1, 0xe, 0x9b }   \
 }
@@ -82,13 +81,12 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_IMGIDECODER
 
   nsIconDecoder();
   virtual ~nsIconDecoder();
 
 private:
   nsCOMPtr<imgIContainer> mImage;
-  nsCOMPtr<gfxIImageFrame> mFrame;
   nsCOMPtr<imgIDecoderObserver> mObserver; // this is just qi'd from mRequest for speed
 };
 
 #endif // nsIconDecoder_h__
--- a/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp
+++ b/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp
@@ -43,17 +43,16 @@
 #include "imgIContainerObserver.h"
 
 #include "nsIComponentManager.h"
 #include "nsIInputStream.h"
 
 #include "nspr.h"
 #include "nsCRT.h"
 #include "ImageLogging.h"
-#include "nsIImage.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "gfxColor.h"
 
 #include "jerror.h"
 
 #include "gfxPlatform.h"
 
 extern "C" {
@@ -96,16 +95,17 @@ static void cmyk_convert_rgb(JSAMPROW ro
 #define MAX_JPEG_MARKER_LENGTH  (((PRUint32)1 << 16) - 1)
 
 
 nsJPEGDecoder::nsJPEGDecoder()
 {
   mState = JPEG_HEADER;
   mReading = PR_TRUE;
   mError = NS_OK;
+  mImageData = nsnull;
 
   mBytesToSkip = 0;
   memset(&mInfo, 0, sizeof(jpeg_decompress_struct));
   memset(&mSourceMgr, 0, sizeof(mSourceMgr));
   mInfo.client_data = (void*)this;
 
   mSegment = nsnull;
   mSegmentLen = 0;
@@ -182,17 +182,17 @@ NS_IMETHODIMP nsJPEGDecoder::Init(imgILo
    * 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");
+    mImage = do_CreateInstance("@mozilla.org/image/container;2");
     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,
@@ -468,59 +468,33 @@ nsresult nsJPEGDecoder::ProcessData(cons
       mState = JPEG_ERROR;
       return NS_ERROR_UNEXPECTED;
     }
 
     mImage->Init(mInfo.image_width, mInfo.image_height, mObserver);
 
     mObserver->OnStartContainer(nsnull, mImage);
 
-    mImage->GetFrameAt(0, getter_AddRefs(mFrame));
-
-    if (mFrame) {
-      PRInt32 width, height;
-      mFrame->GetWidth(&width);
-      mFrame->GetHeight(&height);
-
-      if ((width != (PRInt32)mInfo.image_width) ||
-          (height != (PRInt32)mInfo.image_height)) {
-        // Can't reuse frame, create a new one with correct size
-        mFrame = nsnull;
-      }
+    // Use EnsureCleanFrame so we don't create a new frame if we're being
+    // reused for e.g. multipart/x-replace
+    PRUint32 imagelength;
+    if (NS_FAILED(mImage->EnsureCleanFrame(0, 0, 0, mInfo.image_width, mInfo.image_height,
+                                           gfxASurface::ImageFormatRGB24,
+                                           &mImageData, &imagelength))) {
+      mState = JPEG_ERROR;
+      PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+             ("} (could not initialize image frame)"));
+      return NS_ERROR_OUT_OF_MEMORY;
     }
 
-    if (!mFrame) {
-      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
+    PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
+           ("        JPEGDecoderAccounting: nsJPEGDecoder::ProcessData -- created image frame with %ux%u pixels",
+            mInfo.image_width, mInfo.image_height));
 
-      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::ProcessData -- created image frame with %ux%u pixels",
-              mInfo.image_width, mInfo.image_height));
-    }
-
-    mObserver->OnStartFrame(nsnull, mFrame);
+    mObserver->OnStartFrame(nsnull, 0);
     mState = JPEG_START_DECOMPRESS;
   }
 
   case JPEG_START_DECOMPRESS:
   {
     LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::ProcessData -- entering JPEG_START_DECOMPRESS case");
     /* Step 4: set parameters for decompression */
 
@@ -694,26 +668,19 @@ nsresult nsJPEGDecoder::ProcessData(cons
 nsresult
 nsJPEGDecoder::OutputScanlines(PRBool* suspend)
 {
   *suspend = PR_FALSE;
 
   const PRUint32 top = mInfo.output_scanline;
   nsresult rv = NS_OK;
 
-  mFrame->LockImageData();
-  
-  // we're thebes. we can write stuff directly to the data
-  PRUint8 *imageData;
-  PRUint32 imageDataLength;
-  mFrame->GetImageData(&imageData, &imageDataLength);
-
   while ((mInfo.output_scanline < mInfo.output_height)) {
       /* Use the Cairo image buffer as scanline buffer */
-      PRUint32 *imageRow = ((PRUint32*)imageData) +
+      PRUint32 *imageRow = ((PRUint32*)mImageData) +
                            (mInfo.output_scanline * mInfo.output_width);
 
       if (mInfo.cconvert->color_convert == ycc_rgb_convert_argb) {
         /* Special case: scanline will be directly converted into packed ARGB */
         if (jpeg_read_scanlines(&mInfo, (JSAMPARRAY)&imageRow, 1) != 1) {
           *suspend = PR_TRUE; /* suspend */
           break;
         }
@@ -786,23 +753,20 @@ nsJPEGDecoder::OutputScanlines(PRBool* s
         // 32-bit read of final pixel will exceed buffer, so read bytes
         *imageRow++ = GFX_PACKED_PIXEL(0xFF, sampleRow[0], sampleRow[1], sampleRow[2]);
         sampleRow += 3;
       }
   }
 
   if (top != mInfo.output_scanline) {
       nsIntRect r(0, top, mInfo.output_width, mInfo.output_scanline-top);
-      nsCOMPtr<nsIImage> img(do_GetInterface(mFrame));
-      rv = img->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r);
-      mObserver->OnDataAvailable(nsnull, mFrame, &r);
+      rv = mImage->FrameUpdated(0, r);
+      mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
   }
-  
-  mFrame->UnlockImageData();
-  
+
   return rv;
 }
 
 
 /* Override the standard error method in the IJG JPEG decoder code. */
 METHODDEF(void)
 my_error_exit (j_common_ptr cinfo)
 {
@@ -1008,25 +972,26 @@ fill_input_buffer (j_decompress_ptr jd)
  * jpeg_abort() or jpeg_destroy().
  */
 METHODDEF(void)
 term_source (j_decompress_ptr jd)
 {
   nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
 
   if (decoder->mObserver) {
-    decoder->mObserver->OnStopFrame(nsnull, decoder->mFrame);
+    decoder->mObserver->OnStopFrame(nsnull, 0);
     decoder->mObserver->OnStopContainer(nsnull, decoder->mImage);
     decoder->mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
   }
 
-  PRBool isMutable = PR_FALSE;
+  PRBool multipart = PR_FALSE;
   if (decoder->mImageLoad) 
-      decoder->mImageLoad->GetIsMultiPartChannel(&isMutable);
-  decoder->mFrame->SetMutable(isMutable);
+      decoder->mImageLoad->GetIsMultiPartChannel(&multipart);
+  if (!multipart)
+    decoder->mImage->DecodingComplete();
 }
 
 
 /**************** YCbCr -> Cairo's RGB24/ARGB32 conversion: most common case **************/
 
 /*
  * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
  * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
--- a/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.h
+++ b/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.h
@@ -40,17 +40,16 @@
 #ifndef nsJPEGDecoder_h__
 #define nsJPEGDecoder_h__
 
 #include "imgIDecoder.h"
 
 #include "nsCOMPtr.h"
 
 #include "imgIContainer.h"
-#include "gfxIImageFrame.h"
 #include "imgIDecoderObserver.h"
 #include "imgILoad.h"
 #include "nsIInputStream.h"
 #include "nsIPipe.h"
 #include "qcms.h"
 
 extern "C" {
 #include "jpeglib.h"
@@ -94,19 +93,19 @@ public:
   nsresult  ProcessData(const char *data, PRUint32 count, PRUint32 *writeCount);
 
 protected:
   nsresult OutputScanlines(PRBool* suspend);
 
 public:
   nsCOMPtr<imgIContainer> mImage;
   nsCOMPtr<imgILoad> mImageLoad;
-  nsCOMPtr<gfxIImageFrame> mFrame;
 
   nsCOMPtr<imgIDecoderObserver> mObserver;
+  PRUint8 *mImageData;
 
   struct jpeg_decompress_struct mInfo;
   struct jpeg_source_mgr mSourceMgr;
   decoder_error_mgr mErr;
   jstate mState;
   nsresult mError;
 
   PRUint32 mBytesToSkip;
--- a/modules/libpr0n/decoders/png/nsPNGDecoder.cpp
+++ b/modules/libpr0n/decoders/png/nsPNGDecoder.cpp
@@ -43,17 +43,16 @@
 
 #include "nsMemory.h"
 #include "nsRect.h"
 
 #include "nsIComponentManager.h"
 #include "nsIInputStream.h"
 
 #include "imgIContainerObserver.h"
-#include "nsIImage.h"
 #include "nsIInterfaceRequestorUtils.h"
 
 #include "gfxColor.h"
 #include "nsColor.h"
 
 #include "nspr.h"
 #include "png.h"
 
@@ -94,35 +93,39 @@ nsPNGDecoder::~nsPNGDecoder()
     /* mTransform belongs to us only if mInProfile is non-null */
     if (mTransform)
       qcms_transform_release(mTransform);
   }
 }
 
 // CreateFrame() is used for both simple and animated images
 void nsPNGDecoder::CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset, 
-                                PRInt32 width, PRInt32 height, gfx_format format)
+                               PRInt32 width, PRInt32 height,
+                               gfxASurface::gfxImageFormat format)
 {
-  mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
-  if (!mFrame)
-    longjmp(mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
-
-  nsresult rv = mFrame->Init(x_offset, y_offset, width, height, format, 24);
+  PRUint32 imageDataLength;
+  nsresult rv = mImage->AppendFrame(x_offset, y_offset, width, height, format,
+                                    &mImageData, &imageDataLength);
   if (NS_FAILED(rv))
     longjmp(mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
 
+  mFrameRect.x = x_offset;
+  mFrameRect.y = y_offset;
+  mFrameRect.width = width;
+  mFrameRect.height = height;
+
   if (png_get_valid(mPNG, mInfo, PNG_INFO_acTL))
     SetAnimFrameInfo();
-  
-  mImage->AppendFrame(mFrame);
-  
+
+  PRUint32 numFrames = 0;
+  mImage->GetNumFrames(&numFrames);
+
   if (mObserver)
-    mObserver->OnStartFrame(nsnull, mFrame);
+    mObserver->OnStartFrame(nsnull, numFrames - 1);
 
- 
   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;
 }
 
@@ -136,74 +139,69 @@ void nsPNGDecoder::SetAnimFrameInfo()
   PRInt32 timeout; /* in milliseconds */
   
   delay_num = png_get_next_frame_delay_num(mPNG, mInfo);
   delay_den = png_get_next_frame_delay_den(mPNG, mInfo);
   dispose_op = png_get_next_frame_dispose_op(mPNG, mInfo);
   blend_op = png_get_next_frame_blend_op(mPNG, mInfo);
 
   if (delay_num == 0) {
-    timeout = 0; // gfxImageFrame::SetTimeout() will set to a minimum
+    timeout = 0; // SetFrameTimeout() will set to a minimum
   } else {
     if (delay_den == 0)
       delay_den = 100; // so says the APNG spec
     
     // Need to cast delay_num to float to have a proper division and
     // the result to int to avoid compiler warning
     timeout = static_cast<PRInt32>
                          (static_cast<PRFloat64>(delay_num) * 1000 / delay_den);
   }
-  mFrame->SetTimeout(timeout);
+
+  PRUint32 numFrames = 0;
+  mImage->GetNumFrames(&numFrames);
+
+  mImage->SetFrameTimeout(numFrames - 1, timeout);
   
   if (dispose_op == PNG_DISPOSE_OP_PREVIOUS)
-      mFrame->SetFrameDisposalMethod(imgIContainer::kDisposeRestorePrevious);
+      mImage->SetFrameDisposalMethod(numFrames - 1, imgIContainer::kDisposeRestorePrevious);
   else if (dispose_op == PNG_DISPOSE_OP_BACKGROUND)
-      mFrame->SetFrameDisposalMethod(imgIContainer::kDisposeClear);
+      mImage->SetFrameDisposalMethod(numFrames - 1, imgIContainer::kDisposeClear);
   else
-      mFrame->SetFrameDisposalMethod(imgIContainer::kDisposeKeep);
+      mImage->SetFrameDisposalMethod(numFrames - 1, imgIContainer::kDisposeKeep);
   
   if (blend_op == PNG_BLEND_OP_SOURCE)
-      mFrame->SetBlendMethod(imgIContainer::kBlendSource);
-  /*else // 'over' is the default for a gfxImageFrame
-      mFrame->SetBlendMethod(imgIContainer::kBlendOver); */
+      mImage->SetFrameBlendMethod(numFrames - 1, imgIContainer::kBlendSource);
+  /*else // 'over' is the default
+      mImage->SetFrameBlendMethod(numFrames - 1, imgIContainer::kBlendOver); */
 }
 
 // set timeout and frame disposal method for the current frame
 void nsPNGDecoder::EndImageFrame()
 {
-  if (mFrameHasNoAlpha) {
-    nsCOMPtr<nsIImage> img(do_GetInterface(mFrame));
-    img->SetHasNoAlpha();
-  }
-
-  // First tell the container that this frame is complete
-  PRInt32 timeout = 100;
   PRUint32 numFrames = 0;
-  mFrame->GetTimeout(&timeout);
   mImage->GetNumFrames(&numFrames);
 
   // We can't use mPNG->num_frames_read as it may be one ahead.
   if (numFrames > 1) {
     // Tell the image renderer that the frame is complete
-    PRInt32 width, height;
-    mFrame->GetWidth(&width);
-    mFrame->GetHeight(&height);
+    if (mFrameHasNoAlpha)
+      mImage->SetFrameHasNoAlpha(numFrames - 1);
 
-    nsIntRect r(0, 0, width, height);
-    nsCOMPtr<nsIImage> img(do_GetInterface(mFrame));
-    if (NS_FAILED(img->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r))) {
+    if (NS_FAILED(mImage->FrameUpdated(numFrames - 1, mFrameRect))) {
       mError = PR_TRUE;
       // allow the call out to the observers.
     }
-    mObserver->OnDataAvailable(nsnull, mFrame, &r);
+    PRUint32 curFrame;
+    mImage->GetCurrentFrameIndex(&curFrame);
+    mObserver->OnDataAvailable(nsnull, curFrame == numFrames - 1, &mFrameRect);
   }
 
-  mImage->EndFrameDecode(numFrames);
+  mImage->EndFrameDecode(numFrames - 1);
   if (mObserver)
-    mObserver->OnStopFrame(nsnull, mFrame);
+    mObserver->OnStopFrame(nsnull, numFrames - 1);
 }
 
 
 /** imgIDecoder methods **/
 
 /* void init (in imgILoad aLoad); */
 NS_IMETHODIMP nsPNGDecoder::Init(imgILoad *aLoad)
 {
@@ -260,17 +258,17 @@ NS_IMETHODIMP nsPNGDecoder::Init(imgILoa
                               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");
+    mImage = do_CreateInstance("@mozilla.org/image/container;2");
     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()));
@@ -551,22 +549,21 @@ info_callback(png_structp png_ptr, png_i
 
   qcms_data_type inType;
   PRUint32 intent, pIntent;
   if (gfxPlatform::GetCMSMode() != eCMSMode_Off) {
     intent = gfxPlatform::GetRenderingIntent();
     decoder->mInProfile = PNGGetColorProfile(png_ptr, info_ptr,
                                              color_type, &inType, &pIntent);
     /* If we're not mandating an intent, use the one from the image. */
-    if (intent == -1)
+    if (intent == PRUint32(-1))
       intent = pIntent;
   }
   if (decoder->mInProfile && gfxPlatform::GetCMSOutputProfile()) {
     qcms_data_type outType;
-    PRUint32 dwFlags = 0;
 
     if (color_type & PNG_COLOR_MASK_ALPHA || num_trans)
       outType = QCMS_DATA_RGBA_8;
     else
       outType = QCMS_DATA_RGB_8;
 
     decoder->mTransform = qcms_transform_create(decoder->mInProfile,
                                              inType,
@@ -626,32 +623,27 @@ info_callback(png_structp png_ptr, png_i
    * 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) {
+  } else if (containerWidth != PRInt32(width) || containerHeight != PRInt32(height)) {
     longjmp(decoder->mPNG->jmpbuf, 5); // NS_ERROR_UNEXPECTED
   }
 
   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) {
-      decoder->format = gfxIFormats::RGB_A8;
-    } else if (alpha_bits == 1) {
-      decoder->format = gfxIFormats::RGB_A1;
-    }
-  }
+  if (channels == 1 || channels == 3)
+    decoder->format = gfxASurface::ImageFormatRGB24;
+  else if (channels == 2 || channels == 4)
+    decoder->format = gfxASurface::ImageFormatARGB32;
 
   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL))
     png_set_progressive_frame_fn(png_ptr, frame_info_callback, NULL);
   
   if (png_get_first_frame_is_hidden(png_ptr, info_ptr)) {
     decoder->mFrameIsHidden = PR_TRUE;
   } else {
     decoder->CreateFrame(0, 0, width, height, decoder->format);
@@ -669,19 +661,16 @@ info_callback(png_structp png_ptr, png_i
   if (interlace_type == PNG_INTERLACE_ADAM7) {
     if (height < PR_INT32_MAX / (width * channels))
       decoder->interlacebuf = (PRUint8 *)nsMemory::Alloc(channels * width * height);
     if (!decoder->interlacebuf) {
       longjmp(decoder->mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
     }
   }
   
-  if (png_get_first_frame_is_hidden(png_ptr, info_ptr))
-    decoder->mFrame = nsnull;
-
   /* Reject any ancillary chunk after IDAT with a bad CRC (bug #397593).
    * It would be better to show the default frame (if one has already been
    * successfully decoded) before bailing, but it's simpler to just bail
    * out with an error message.
    */
   png_set_crc_action(png_ptr, NULL, PNG_CRC_ERROR_QUIT);
   
   return;
@@ -720,31 +709,27 @@ row_callback(png_structp png_ptr, png_by
    */
   nsPNGDecoder *decoder = static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
   
   // skip this frame
   if (decoder->mFrameIsHidden)
     return;
 
   if (new_row) {
-    PRInt32 width;
-    decoder->mFrame->GetWidth(&width);
-    PRUint32 iwidth = width;
+    PRInt32 width = decoder->mFrameRect.width;
+    PRUint32 iwidth = decoder->mFrameRect.width;
 
     png_bytep line = new_row;
     if (decoder->interlacebuf) {
       line = decoder->interlacebuf + (row_num * decoder->mChannels * width);
       png_progressive_combine_row(png_ptr, line, new_row);
     }
 
-    // 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));
+    PRUint32 bpr = width * sizeof(PRUint32);
+    PRUint32 *cptr32 = (PRUint32*)(decoder->mImageData + (row_num*bpr));
     PRBool rowHasNoAlpha = PR_TRUE;
 
     if (decoder->mTransform) {
       if (decoder->mCMSLine) {
         qcms_transform_data(decoder->mTransform, line, decoder->mCMSLine, iwidth);
         /* copy alpha over */
         PRUint32 channels = decoder->mChannels;
         if (channels == 2 || channels == 4) {
@@ -753,17 +738,17 @@ row_callback(png_structp png_ptr, png_by
         }
         line = decoder->mCMSLine;
       } else {
         qcms_transform_data(decoder->mTransform, line, line, iwidth);
        }
      }
 
     switch (decoder->format) {
-    case gfxIFormats::RGB:
+      case gfxASurface::ImageFormatRGB24:
       {
         // counter for while() loops below
         PRUint32 idx = iwidth;
 
         // copy as bytes until source pointer is 32-bit-aligned
         for (; (NS_PTR_TO_UINT32(line) & 0x3) && idx; --idx) {
           *cptr32++ = GFX_PACKED_PIXEL(0xFF, line[0], line[1], line[2]);
           line += 3; 
@@ -780,52 +765,47 @@ row_callback(png_structp png_ptr, png_by
         // copy remaining pixel(s)
         while (idx--) {
           // 32-bit read of final pixel will exceed buffer, so read bytes
           *cptr32++ = GFX_PACKED_PIXEL(0xFF, line[0], line[1], line[2]);
           line += 3;
         }
       }
       break;
-    case gfxIFormats::RGB_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 gfxASurface::ImageFormatARGB32:
       {
         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;
+      default:
+        NS_ERROR("Unknown PNG format!");
+        NS_ABORT();
+        break;
     }
 
     if (!rowHasNoAlpha)
       decoder->mFrameHasNoAlpha = PR_FALSE;
 
     PRUint32 numFrames = 0;
     decoder->mImage->GetNumFrames(&numFrames);
     if (numFrames <= 1) {
       // Only do incremental image display for the first frame
       nsIntRect r(0, row_num, width, 1);
-      nsCOMPtr<nsIImage> img(do_GetInterface(decoder->mFrame));
-      if (NS_FAILED(img->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r))) {
+      if (NS_FAILED(decoder->mImage->FrameUpdated(numFrames - 1, r))) {
         decoder->mError = PR_TRUE;  /* bail */
         return;
       }
-      decoder->mObserver->OnDataAvailable(nsnull, decoder->mFrame, &r);
+      PRUint32 curFrame;
+      decoder->mImage->GetCurrentFrameIndex(&curFrame);
+      decoder->mObserver->OnDataAvailable(nsnull, curFrame == numFrames - 1, &r);
     }
   }
 }
 
 // got the header of a new frame that's coming
 void
 frame_info_callback(png_structp png_ptr, png_uint_32 frame_num)
 {
--- a/modules/libpr0n/decoders/png/nsPNGDecoder.h
+++ b/modules/libpr0n/decoders/png/nsPNGDecoder.h
@@ -39,19 +39,18 @@
 
 #ifndef nsPNGDecoder_h__
 #define nsPNGDecoder_h__
 
 #include "imgIDecoder.h"
 
 #include "imgIContainer.h"
 #include "imgIDecoderObserver.h"
-#include "gfxIImageFrame.h"
 #include "imgILoad.h"
-
+#include "gfxASurface.h"
 
 #include "nsCOMPtr.h"
 
 #include "png.h"
 
 #include "qcms.h"
 
 #define NS_PNGDECODER_CID \
@@ -67,34 +66,36 @@ class nsPNGDecoder : public imgIDecoder
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_IMGIDECODER
 
   nsPNGDecoder();
   virtual ~nsPNGDecoder();
 
   void CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset, 
-                   PRInt32 width, PRInt32 height, gfx_format format);
+                   PRInt32 width, PRInt32 height, 
+                   gfxASurface::gfxImageFormat format);
   void SetAnimFrameInfo();
   
   void EndImageFrame();
 
 public:
   nsCOMPtr<imgIContainer> mImage;
-  nsCOMPtr<gfxIImageFrame> mFrame;
   nsCOMPtr<imgILoad> mImageLoad;
   nsCOMPtr<imgIDecoderObserver> mObserver; // this is just qi'd from mRequest for speed
 
   png_structp mPNG;
   png_infop mInfo;
+  nsIntRect mFrameRect;
   PRUint8 *mCMSLine;
   PRUint8 *interlacebuf;
+  PRUint8 *mImageData;
   qcms_profile *mInProfile;
   qcms_transform *mTransform;
 
-  gfx_format format;
+  gfxASurface::gfxImageFormat format;
   PRUint8 mChannels;
   PRPackedBool mError;
   PRPackedBool mFrameHasNoAlpha;
   PRPackedBool mFrameIsHidden;
 };
 
 #endif // nsPNGDecoder_h__
--- a/modules/libpr0n/decoders/xbm/nsXBMDecoder.cpp
+++ b/modules/libpr0n/decoders/xbm/nsXBMDecoder.cpp
@@ -42,26 +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"
 
 #include "gfxColor.h"
-#include "nsIImage.h"
 #include "nsIInterfaceRequestorUtils.h"
 
 // Static colormap
 static const PRUint32 kColors[2] = {
     GFX_PACKED_PIXEL(0, 0, 0, 0),     // Transparent 
     GFX_PACKED_PIXEL(255, 0, 0, 0)    // Black
 };
 
@@ -77,21 +75,17 @@ nsXBMDecoder::~nsXBMDecoder()
         free(mBuf);
 }
 
 NS_IMETHODIMP nsXBMDecoder::Init(imgILoad *aLoad)
 {
     nsresult rv;
     mObserver = do_QueryInterface(aLoad);
 
-    mImage = do_CreateInstance("@mozilla.org/image/container;1", &rv);
-    if (NS_FAILED(rv))
-        return rv;
-
-    mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2", &rv);
+    mImage = do_CreateInstance("@mozilla.org/image/container;2", &rv);
     if (NS_FAILED(rv))
         return rv;
 
     aLoad->SetImage(mImage);
 
     mCurRow = mBufSize = mWidth = mHeight = 0;
     mState = RECV_HEADER;
 
@@ -101,17 +95,16 @@ NS_IMETHODIMP nsXBMDecoder::Init(imgILoa
 NS_IMETHODIMP nsXBMDecoder::Close()
 {
     mImage->DecodingComplete();
 
     mObserver->OnStopContainer(nsnull, mImage);
     mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
     mObserver = nsnull;
     mImage = nsnull;
-    mFrame = nsnull;
     mImageData = nsnull;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP nsXBMDecoder::Flush()
 {
     return NS_OK;
@@ -193,17 +186,19 @@ 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, gfxIFormats::RGB_A1, 24);
+        PRUint32 imageLen;
+        nsresult rv = mImage->AppendFrame(0, 0, mWidth, mHeight, gfxASurface::ImageFormatARGB32,
+                                          (PRUint8**)&mImageData, &imageLen);
         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");
@@ -213,21 +208,17 @@ nsresult nsXBMDecoder::ProcessData(const
                     intwrapy->SetData(mYHotspot);
 
                     props->Set("hotspotX", intwrapx);
                     props->Set("hotspotY", intwrapy);
                 }
             }
         }
 
-        mImage->AppendFrame(mFrame);
-        mObserver->OnStartFrame(nsnull, mFrame);
-
-        PRUint32 imageLen;
-        mFrame->GetImageData((PRUint8**)&mImageData, &imageLen);
+        mObserver->OnStartFrame(nsnull, 0);
 
         mState = RECV_SEEK;
 
         mCurRow = 0;
         mCurCol = 0;
 
     }
     if (mState == RECV_SEEK) {
@@ -235,17 +226,16 @@ nsresult nsXBMDecoder::ProcessData(const
             mPos = endPtr+1;
             mState = RECV_DATA;
         } else {
             mPos = mBuf + mBufSize;
             return NS_OK;
         }
     }
     if (mState == RECV_DATA) {
-        nsCOMPtr<nsIImage> img = do_GetInterface(mFrame);
         PRUint32 *ar = mImageData + mCurRow * mWidth + mCurCol;
 
         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
@@ -274,27 +264,27 @@ nsresult nsXBMDecoder::ProcessData(const
             numPixels = PR_MIN(numPixels, mWidth - mCurCol);
             for (PRUint32 i = numPixels; i > 0; --i) {
                 *ar++ = kColors[pixel & 1];
                 pixel >>= 1;
             }
             mCurCol += numPixels;
             if (mCurCol == mWidth || mState == RECV_DONE) {
                 nsIntRect r(0, mCurRow, mWidth, 1);
-                nsresult rv = img->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r);
+                nsresult rv = mImage->FrameUpdated(0, r);
                 if (NS_FAILED(rv)) {
                   return rv;
                 }
 
-                mObserver->OnDataAvailable(nsnull, mFrame, &r);
+                mObserver->OnDataAvailable(nsnull, PR_TRUE, &r);
 
                 mCurRow++;
                 if (mCurRow == mHeight) {
                     mState = RECV_DONE;
-                    return mObserver->OnStopFrame(nsnull, mFrame);
+                    return mObserver->OnStopFrame(nsnull, 0);
                 }
                 mCurCol = 0;
             }
         } while ((mState == RECV_DATA) && *mPos);
     }
 
     return NS_OK;
 }
--- a/modules/libpr0n/decoders/xbm/nsXBMDecoder.h
+++ b/modules/libpr0n/decoders/xbm/nsXBMDecoder.h
@@ -39,17 +39,16 @@
 
 #ifndef _nsXBMDecoder_h
 #define _nsXBMDecoder_h
 
 #include "nsCOMPtr.h"
 #include "imgIDecoder.h"
 #include "imgIContainer.h"
 #include "imgIDecoderObserver.h"
-#include "gfxIImageFrame.h"
 
 #define NS_XBMDECODER_CID \
 { /* {dbfd145d-3298-4f3c-902f-2c5e1a1494ce} */ \
   0xdbfd145d, \
   0x3298, \
   0x4f3c, \
   { 0x90, 0x2f, 0x2c, 0x5e, 0x1a, 0x14, 0x94, 0xce } \
 }
@@ -67,17 +66,16 @@ public:
 private:
     static NS_METHOD ReadSegCb(nsIInputStream* aIn, void* aClosure,
                                const char* aFromRawSegment, PRUint32 aToOffset,
                                PRUint32 aCount, PRUint32 *aWriteCount);
 
     nsCOMPtr<imgIDecoderObserver> mObserver;
 
     nsCOMPtr<imgIContainer> mImage;
-    nsCOMPtr<gfxIImageFrame> mFrame;
 
     PRUint32 mCurRow;
     PRUint32 mCurCol;
 
     char* mBuf; // Holds the received data
     char* mPos;
     PRUint32 mBufSize; // number of bytes in mBuf
 
--- a/modules/libpr0n/public/imgIContainer.idl
+++ b/modules/libpr0n/public/imgIContainer.idl
@@ -18,48 +18,140 @@
  * 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>
+ *   Joe Drew <joe@drew.ca>
  *
  * 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
  * decision by deleting the provisions above and replace them with the notice
  * 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 "nsISupports.idl"
-#include "gfxidltypes.idl"
-#include "gfxIFormats.idl"
+
+interface imgIContainerObserver;
 
-interface gfxIImageFrame;
-interface imgIContainerObserver;
+%{C++
+#include "gfxImageSurface.h"
+#include "gfxContext.h"
+#include "gfxMatrix.h"
+#include "gfxRect.h"
+#include "gfxPattern.h"
+#include "gfxASurface.h"
+#include "nsRect.h"
+%}
+
+[ptr] native gfxImageSurface(gfxImageSurface);
+[ptr] native gfxASurface(gfxASurface);
+native gfxImageFormat(gfxASurface::gfxImageFormat);
+[ptr] native gfxContext(gfxContext);
+[ref] native gfxMatrix(gfxMatrix);
+[ref] native gfxRect(gfxRect);
+native gfxGraphicsFilter(gfxPattern::GraphicsFilter);
+[ref] native nsIntRect(nsIntRect);
 
 /**
- * gfxIImageContainer interface
+ * imgIContainer is the interface that represents an image. It allows
+ * access to frames as Thebes surfaces, and permits users to extract subregions
+ * as other imgIContainers. It also allows drawing of images on to Thebes
+ * contexts.
  *
- * @author Stuart Parmenter <pavlov@netscape.com>
- * @version 0.2
- * @see "gfx2"
+ * Internally, imgIContainer also manages animation of images.
  */
-[scriptable, uuid(a4e9df32-f5d7-479f-9082-70e1fead23d5)]
+[scriptable, uuid(1bcf7a25-1356-47a8-bf80-e284989ea38f)]
 interface imgIContainer : nsISupports
 {
+  /**
+   * The width of the container rectangle.
+   */
+  readonly attribute PRInt32 width;
+
+  /**
+   * The height of the container rectangle.
+   */
+  readonly attribute PRInt32 height;
+
+  /**
+   * Whether this image is animated.
+   */
+  readonly attribute boolean animated;
+
+  /**
+   * Whether the current frame is opaque; that is, needs the background painted
+   * behind it.
+   */
+  readonly attribute boolean currentFrameIsOpaque;
+
+  /**
+   * Get a surface for the current frame. This may be a platform-native,
+   * optimized frame, so you cannot inspect its pixel data.
+   */
+  [noscript] readonly attribute gfxASurface currentFrame;
+
+  /**
+   * Create and return a new copy of the current frame that you can write to
+   * and otherwise inspect the pixels of.
+   */
+  [noscript] gfxImageSurface copyCurrentFrame();
+
+  /**
+   * Create a new imgContainer that contains only a single frame, which itself
+   * contains a subregion of the current frame.
+   *
+   * @param aRect the area of the current frame to be duplicated in the
+   *              returned imgContainer's frame.
+   */
+  [noscript] imgIContainer extractCurrentFrame([const] in nsIntRect aRect);
+
+  /**
+   * Draw the current frame on to the context specified.
+   *
+   * @param aContext The Thebex context to draw the image to.
+   * @param aFilter The filter to be used if we're scaling the image.
+   * @param aUserSpaceToImageSpace The transformation from user space (e.g.,
+   *                               appunits) to image space.
+   * @param aFill The area in the context to draw pixels to. Image will be
+   *              automatically tiled as necessary.
+   * @param @aSubimage The area of the image, in pixels, that we are allowed to
+   *                   sample from.
+   */
+  [noscript] void draw(in gfxContext aContext, in gfxGraphicsFilter aFilter,
+                       in gfxMatrix aUserSpaceToImageSpace, in gfxRect aFill,
+                       in nsIntRect aSubimage);
+
+
+  /************ Internal libpr0n use only below here. *****************/
+
+  /**
+   * Create a new \a aWidth x \a aHeight sized image container.
+   *
+   * @param aWidth The width of the container in which all the
+   *               frames will fit.
+   * @param aHeight The height of the container in which all the
+   *                frames will fit.
+   * @param aObserver Observer to send animation notifications to.
+   */
+  void init(in PRInt32 aWidth,
+            in PRInt32 aHeight,
+            in imgIContainerObserver aObserver);
+
   /** 
    * "Disposal" method indicates how the image should be handled before the
    *  subsequent image is displayed.
    *  Don't change these without looking at the implementations using them,
    *  struct gif_struct::disposal_method and gif_write() in particular.
    */
   const long kDisposeClearAll         = -1; // Clear the whole image, revealing
                                             // what was there before the gif displayed
@@ -74,70 +166,75 @@ interface imgIContainer : nsISupports
    */
   const long kBlendSource             =  0; // All color components of the frame, including alpha, 
                                             // overwrite the current contents of the frame's 
                                             // output buffer region
   const long kBlendOver               =  1; // The frame should be composited onto the output buffer 
                                             // based on its alpha, using a simple OVER operation
   
   /**
-   * Create a new \a aWidth x \a aHeight sized image container.
-   *
-   * @param aWidth The width of the container in which all the
-   *               gfxIImageFrame children will fit.
-   * @param aHeight The height of the container in which all the
-   *                gfxIImageFrame children will fit.
-   * @param aObserver Observer to send animation notifications to.
-   */
-  void init(in PRInt32 aWidth,
-            in PRInt32 aHeight,
-            in imgIContainerObserver aObserver);
-
-
-  /* this should probably be on the device context (or equiv) */
-  readonly attribute gfx_format preferredAlphaChannelFormat;
-
-  /**
-   * The width of the container rectangle.
-   */
-  readonly attribute PRInt32 width;
-
-  /**
-   * The height of the container rectangle.
-   */
-  readonly attribute PRInt32 height;
-
-
-  /**
-   * Get the current frame that would be drawn if the image was to be drawn now
-   */
-  readonly attribute gfxIImageFrame currentFrame;
-
-
-  readonly attribute unsigned long numFrames;
-
-  /**
    * Animation mode Constants
    *   0 = normal
    *   1 = don't animate
    *   2 = loop once
    */
   const short kNormalAnimMode   = 0;
   const short kDontAnimMode     = 1;
   const short kLoopOnceAnimMode = 2;
 
   attribute unsigned short animationMode;
 
-  gfxIImageFrame getFrameAt(in unsigned long index);
+  /**
+   * The rectangle defining the location and size of the currently displayed frame.
+   * Should be an attribute, but can't be because of reference/pointer
+   * conflicts with native types in xpidl.
+   */
+  [noscript] void getCurrentFrameRect(in nsIntRect aFrameRect);
+
+  /**
+   * The index of the current frame that would be drawn if the image was to be
+   * drawn now.
+   */
+  readonly attribute unsigned long currentFrameIndex;
+
+  /**
+   * The total number of frames in this image.
+   */
+  readonly attribute unsigned long numFrames;
 
   /**
-   * Adds \a item to the end of the list of frames.
-   * @param item frame to add.
+   * Get the size, in bytes, of a particular frame's image data.
    */
-  void appendFrame(in gfxIImageFrame item);
+  unsigned long getFrameImageDataLength(in unsigned long framenumber);
+
+  void getFrameColormap(in unsigned long framenumber, 
+                        [array, size_is(paletteLength)] out PRUint32 paletteData,
+                        out unsigned long paletteLength);
+
+  void setFrameDisposalMethod(in unsigned long framenumber, in PRInt32 aDisposalMethod);
+  void setFrameBlendMethod(in unsigned long framenumber, in PRInt32 aBlendMethod);
+  void setFrameTimeout(in unsigned long framenumber, in PRInt32 aTimeout);
+  void setFrameHasNoAlpha(in unsigned long framenumber);
+
+  /**
+   * Create or re-use a frame at index aFrameNum. It is an error to call this with aFrameNum not in the range [0, numFrames].
+   */
+  [noscript] void ensureCleanFrame(in unsigned long aFramenum, in PRInt32 aX, in PRInt32 aY, in PRInt32 aWidth, in PRInt32 aHeight, in gfxImageFormat aFormat,
+                                   [array, size_is(imageLength)] out PRUint8 imageData, out unsigned long imageLength);
+
+  /**
+   * Adds to the end of the list of frames.
+   */
+  [noscript] void appendFrame(in PRInt32 aX, in PRInt32 aY, in PRInt32 aWidth, in PRInt32 aHeight, in gfxImageFormat aFormat,
+                              [array, size_is(imageLength)] out PRUint8 imageData, out unsigned long imageLength);
+  [noscript] void appendPalettedFrame(in PRInt32 aX, in PRInt32 aY, in PRInt32 aWidth, in PRInt32 aHeight, in gfxImageFormat aFormat, in PRUint8 aPaletteDepth, 
+                                      [array, size_is(imageLength)] out PRUint8 imageData, out unsigned long imageLength,
+                                      [array, size_is(paletteLength)] out PRUint32 paletteData, out unsigned long paletteLength);
+
+  [noscript] void frameUpdated(in unsigned long framenum, in nsIntRect aNewRect);
 
   /* notification when the current frame is done decoding */
   void endFrameDecode(in unsigned long framenumber);
   
   /* notification that the entire image has been decoded */
   void decodingComplete();
   
   void startAnimation();
--- a/modules/libpr0n/public/imgIContainerObserver.idl
+++ b/modules/libpr0n/public/imgIContainerObserver.idl
@@ -41,23 +41,19 @@
 #include "gfxidltypes.idl"
 
 %{C++
 #include "nsRect.h"
 %}
 
 interface imgIContainer;
 
-interface gfxIImageFrame;
-
 /**
  * imgIContainerObserver interface
  *
  * @author Stuart Parmenter <pavlov@netscape.com>
  * @version 0.1
  */
-[scriptable, uuid(53102f15-0f53-4939-957e-aea353ad2700)]
+[scriptable, uuid(e214c295-4b8e-4aa9-9907-45289e57295b)]
 interface imgIContainerObserver : nsISupports
 {
-  [noscript] void frameChanged(in imgIContainer aContainer,
-                               in gfxIImageFrame aFrame,
-                               in nsIntRect aDirtyRect);
+  [noscript] void frameChanged(in imgIContainer aContainer, in nsIntRect aDirtyRect);
 };
--- a/modules/libpr0n/public/imgIDecoderObserver.idl
+++ b/modules/libpr0n/public/imgIDecoderObserver.idl
@@ -36,17 +36,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "imgIContainerObserver.idl"
 
 interface imgIRequest;
 interface imgIContainer;
-interface gfxIImageFrame;
 
 %{C++
 #include "nsRect.h"
 %}
 
 /**
  * imgIDecoderObserver interface
  *
@@ -54,17 +53,17 @@ interface gfxIImageFrame;
  * observing imgIRequest objects.  In the former case, aRequest is
  * always null.
  * XXXldb The two functions should probably be split.
  *
  * @author Stuart Parmenter <pavlov@netscape.com>
  * @version 0.1
  * @see imagelib2
  */
-[scriptable, uuid(876f14ee-f27c-41cd-b6fb-9efda3ebc7b5)]
+[scriptable, uuid(1dfc9189-6421-4281-83b2-d9c1c9ba4d1b)]
 interface imgIDecoderObserver : imgIContainerObserver
 {
   /**
    * called at the same time that nsIRequestObserver::onStartRequest would be
    * (used only for observers of imgIRequest objects, which are nsIRequests,
    * not imgIDecoder objects)
    *
    * Unlike nsIRequestObserver::onStartRequest, this can be called
@@ -80,27 +79,27 @@ interface imgIDecoderObserver : imgICont
   /**
    * called once the image has been inited and therefore has a width and height
    */
   void onStartContainer(in imgIRequest aRequest, in imgIContainer aContainer);
 
   /**
    * called when each frame is created
    */
-  void onStartFrame(in imgIRequest aRequest, in gfxIImageFrame aFrame);
+  void onStartFrame(in imgIRequest aRequest, in unsigned long aFrame);
 
   /**
    * called when some part of the frame has new data in it
    */
-  [noscript] void onDataAvailable(in imgIRequest aRequest, in gfxIImageFrame aFrame, [const] in nsIntRect aRect);
+  [noscript] void onDataAvailable(in imgIRequest aRequest, in boolean aCurrentFrame, [const] in nsIntRect aRect);
 
   /**
    * called when a frame is finished decoding
    */
-  void onStopFrame(in imgIRequest aRequest, in gfxIImageFrame aFrame);
+  void onStopFrame(in imgIRequest aRequest, in unsigned long aFrame);
 
   /**
    * probably not needed.  called right before onStopDecode
    */
   void onStopContainer(in imgIRequest aRequest, in imgIContainer aContainer);
 
   /**
    * called when the decoder is dying off
--- a/modules/libpr0n/src/Makefile.in
+++ b/modules/libpr0n/src/Makefile.in
@@ -54,19 +54,25 @@ REQUIRES	= xpcom \
 		  necko \
 		  nkcache \
 		  gfx \
 		  thebes \
 		  caps \
 		  xpconnect \
 		  js \
 		  uriloader \
+		  qcms \
 		  $(NULL)
 
 CPPSRCS		= \
 			imgContainer.cpp \
+			imgFrame.cpp \
 			imgLoader.cpp    \
 			imgRequest.cpp   \
 			imgRequestProxy.cpp \
 			imgTools.cpp
 
 include $(topsrcdir)/config/rules.mk
 
+# Because imgFrame.cpp includes "cairo.h"
+CXXFLAGS += $(MOZ_CAIRO_CFLAGS)
+
+
--- a/modules/libpr0n/src/imgContainer.cpp
+++ b/modules/libpr0n/src/imgContainer.cpp
@@ -39,17 +39,16 @@
  * 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"
@@ -88,16 +87,19 @@ imgContainer::imgContainer() :
 }
 
 //******************************************************************************
 imgContainer::~imgContainer()
 {
   if (mAnim)
     delete mAnim;
 
+  for (unsigned int i = 0; i < mFrames.Length(); ++i)
+    delete mFrames[i];
+
   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,
@@ -128,23 +130,44 @@ NS_IMETHODIMP imgContainer::Init(PRInt32
   mDiscarded = PR_FALSE;
 
   mObserver = do_GetWeakReference(aObserver);
   
   return NS_OK;
 }
 
 //******************************************************************************
-/* readonly attribute gfx_format preferredAlphaChannelFormat; */
-NS_IMETHODIMP imgContainer::GetPreferredAlphaChannelFormat(gfx_format *aFormat)
+/* [noscript] imgIContainer extractCurrentFrame([const] in nsIntRect aRegion); */
+NS_IMETHODIMP imgContainer::ExtractCurrentFrame(const nsIntRect &aRegion, imgIContainer **_retval)
 {
-  NS_ENSURE_ARG_POINTER(aFormat);
+  NS_ENSURE_ARG_POINTER(_retval);
+
+  nsRefPtr<imgContainer> img(new imgContainer());
+  NS_ENSURE_TRUE(img, NS_ERROR_OUT_OF_MEMORY);
+
+  img->Init(aRegion.width, aRegion.height, nsnull);
+
+  imgFrame *frame = GetCurrentImgFrame();
+  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
 
-  /* default.. platforms should probably overwrite this */
-  *aFormat = gfxIFormats::RGB_A8;
+  // The frame can be smaller than the image. We want to extract only the part
+  // of the frame that actually exists.
+  nsIntRect framerect = frame->GetRect();
+  framerect.IntersectRect(framerect, aRegion);
+
+  nsAutoPtr<imgFrame> subframe;
+  nsresult rv = frame->Extract(framerect, getter_Transfers(subframe));
+  if (NS_FAILED(rv))
+    return rv;
+
+  img->mFrames.AppendElement(subframe.forget());
+  img->mNumFrames++;
+
+  *_retval = img.forget().get();
+
   return NS_OK;
 }
 
 //******************************************************************************
 /* readonly attribute PRInt32 width; */
 NS_IMETHODIMP imgContainer::GetWidth(PRInt32 *aWidth)
 {
   NS_ENSURE_ARG_POINTER(aWidth);
@@ -158,124 +181,437 @@ NS_IMETHODIMP imgContainer::GetWidth(PRI
 NS_IMETHODIMP imgContainer::GetHeight(PRInt32 *aHeight)
 {
   NS_ENSURE_ARG_POINTER(aHeight);
 
   *aHeight = mSize.height;
   return NS_OK;
 }
 
-gfxIImageFrame *imgContainer::GetCurrentFrameNoRef()
+imgFrame *imgContainer::GetImgFrame(PRUint32 framenum)
 {
   nsresult rv = RestoreDiscardedData();
   NS_ENSURE_SUCCESS(rv, nsnull);
 
-  if (!mAnim)
-    return mFrames.SafeObjectAt(0);
-  if (mAnim->lastCompositedFrameIndex == mAnim->currentAnimationFrameIndex)
+  if (!mAnim) {
+    NS_ASSERTION(framenum == 0, "Don't ask for a frame > 0 if we're not animated!");
+    return mFrames.SafeElementAt(0, nsnull);
+  }
+  if (mAnim->lastCompositedFrameIndex == PRInt32(framenum))
     return mAnim->compositingFrame;
-  return mFrames.SafeObjectAt(mAnim->currentAnimationFrameIndex);
+  return mFrames.SafeElementAt(framenum, nsnull);
+}
+
+PRInt32 imgContainer::GetCurrentImgFrameIndex() const
+{
+  if (mAnim)
+    return mAnim->currentAnimationFrameIndex;
+
+  return 0;
+}
+
+imgFrame *imgContainer::GetCurrentImgFrame()
+{
+  return GetImgFrame(GetCurrentImgFrameIndex());
 }
 
 //******************************************************************************
-/* readonly attribute gfxIImageFrame currentFrame; */
-NS_IMETHODIMP imgContainer::GetCurrentFrame(gfxIImageFrame **aCurrentFrame)
+/* readonly attribute boolean currentFrameIsOpaque; */
+NS_IMETHODIMP imgContainer::GetCurrentFrameIsOpaque(PRBool *aIsOpaque)
 {
-  NS_ENSURE_ARG_POINTER(aCurrentFrame);
+  NS_ENSURE_ARG_POINTER(aIsOpaque);
+
+  imgFrame *curframe = GetCurrentImgFrame();
+  NS_ENSURE_TRUE(curframe, NS_ERROR_FAILURE);
+
+  *aIsOpaque = !curframe->GetNeedsBackground();
+
+  // We are also transparent if the current frame's size doesn't cover our
+  // entire area.
+  nsIntRect framerect = curframe->GetRect();
+  *aIsOpaque = *aIsOpaque && (framerect != nsIntRect(0, 0, mSize.width, mSize.height));
+
+  return NS_OK;
+}
+
+//******************************************************************************
+/* [noscript] void getCurrentFrameRect(nsIntRect rect); */
+NS_IMETHODIMP imgContainer::GetCurrentFrameRect(nsIntRect &aRect)
+{
+  imgFrame *curframe = GetCurrentImgFrame();
+  NS_ENSURE_TRUE(curframe, NS_ERROR_FAILURE);
+
+  aRect = curframe->GetRect();
+
+  return NS_OK;
+}
+
+//******************************************************************************
+/* readonly attribute unsigned long currentFrameIndex; */
+NS_IMETHODIMP imgContainer::GetCurrentFrameIndex(PRUint32 *aCurrentFrameIdx)
+{
+  NS_ENSURE_ARG_POINTER(aCurrentFrameIdx);
   
-  *aCurrentFrame = GetCurrentFrameNoRef();
-  NS_ENSURE_TRUE(*aCurrentFrame, NS_ERROR_FAILURE);
+  *aCurrentFrameIdx = GetCurrentImgFrameIndex();
 
-  NS_ADDREF(*aCurrentFrame);
-  
   return NS_OK;
 }
 
 //******************************************************************************
 /* readonly attribute unsigned long numFrames; */
 NS_IMETHODIMP imgContainer::GetNumFrames(PRUint32 *aNumFrames)
 {
   NS_ENSURE_ARG_POINTER(aNumFrames);
 
   *aNumFrames = mNumFrames;
   
   return NS_OK;
 }
 
 //******************************************************************************
-/* gfxIImageFrame getFrameAt (in unsigned long index); */
-NS_IMETHODIMP imgContainer::GetFrameAt(PRUint32 index, gfxIImageFrame **_retval)
+/* readonly attribute boolean animated; */
+NS_IMETHODIMP imgContainer::GetAnimated(PRBool *aAnimated)
 {
-  NS_ENSURE_ARG_POINTER(_retval);
-
-  *_retval = nsnull;
-  if (mNumFrames == 0)
-    return NS_OK;
+  NS_ENSURE_ARG_POINTER(aAnimated);
 
-  NS_ENSURE_ARG((int) index < mNumFrames);
-
-  nsresult rv = RestoreDiscardedData();
-  NS_ENSURE_SUCCESS(rv, rv);
-  
-  *_retval = mFrames[index];
-  NS_ENSURE_TRUE(*_retval, NS_ERROR_FAILURE);
-
-  NS_ADDREF(*_retval);
+  *aAnimated = (mNumFrames > 1);
   
   return NS_OK;
 }
 
+
 //******************************************************************************
-/* void appendFrame (in gfxIImageFrame item); */
-NS_IMETHODIMP imgContainer::AppendFrame(gfxIImageFrame *item)
+/* [noscript] gfxImageSurface copyCurrentFrame(); */
+NS_IMETHODIMP imgContainer::CopyCurrentFrame(gfxImageSurface **_retval)
+{
+  NS_ENSURE_ARG_POINTER(_retval);
+
+  imgFrame *frame = GetImgFrame(GetCurrentImgFrameIndex());
+  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
+
+  nsRefPtr<gfxPattern> pattern;
+  frame->GetPattern(getter_AddRefs(pattern));
+  nsIntRect intframerect = frame->GetRect();
+  gfxRect framerect(intframerect.x, intframerect.y, intframerect.width, intframerect.height);
+
+  // Create a 32-bit image surface of our size, but draw using the frame's
+  // rect, implicitly padding the frame out to the image's size.
+  nsRefPtr<gfxImageSurface> imgsurface = new gfxImageSurface(gfxIntSize(mSize.width, mSize.height),
+                                                             gfxASurface::ImageFormatARGB32);
+  gfxContext ctx(imgsurface);
+  ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
+  ctx.SetPattern(pattern);
+  ctx.Rectangle(framerect);
+  ctx.Fill();
+
+  *_retval = imgsurface.forget().get();
+  return NS_OK;
+}
+
+//******************************************************************************
+/* [noscript] readonly attribute gfxASurface currentFrame; */
+NS_IMETHODIMP imgContainer::GetCurrentFrame(gfxASurface **_retval)
 {
-  NS_ENSURE_ARG_POINTER(item);
+  imgFrame *frame = GetImgFrame(GetCurrentImgFrameIndex());
+  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
+
+  nsRefPtr<gfxASurface> framesurf;
+  nsresult rv = NS_OK;
+
+  // If this frame covers the entire image, we can just reuse its existing
+  // surface.
+  nsIntRect framerect = frame->GetRect();
+  if (framerect.x == 0 && framerect.y == 0 &&
+      framerect.width == mSize.width &&
+      framerect.height == mSize.height)
+    rv = frame->GetSurface(getter_AddRefs(framesurf));
+
+  // The image doesn't have a surface because it's been optimized away. Create
+  // one.
+  if (!framesurf) {
+    nsRefPtr<gfxImageSurface> imgsurf;
+    rv = CopyCurrentFrame(getter_AddRefs(imgsurf));
+    framesurf = imgsurf;
+  }
+
+  *_retval = framesurf.forget().get();
+
+  return rv;
+}
+
+//******************************************************************************
+/* unsigned long getFrameDataLength(in unsigned long framenum); */
+NS_IMETHODIMP imgContainer::GetFrameImageDataLength(PRUint32 framenum, PRUint32 *_retval)
+{
+  NS_ENSURE_ARG_POINTER(_retval);
+
+  if (framenum >= PRUint32(mNumFrames))
+    return NS_ERROR_INVALID_ARG;
+
+  imgFrame *frame = GetImgFrame(framenum);
+  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
 
-  if (mFrames.Count() == 0) {
-    // This may not be an animated image, don't do all the animation stuff.
-    mFrames.AppendObject(item);
+  *_retval = frame->GetImageDataLength();
+
+  return NS_OK;
+}
+
+//******************************************************************************
+/* unsigned long getFrameColormap(unsigned long framenumber, 
+ *                         [array, size_is(paletteLength)] out PRUint32 paletteData,
+ *                         out unsigned long paletteLength); */
+NS_IMETHODIMP imgContainer::GetFrameColormap(PRUint32 framenum, PRUint32 **aPaletteData,
+                                             PRUint32 *aPaletteLength)
+{
+  NS_ENSURE_ARG_POINTER(aPaletteData);
+  NS_ENSURE_ARG_POINTER(aPaletteLength);
+
+  if (framenum >= PRUint32(mNumFrames))
+    return NS_ERROR_INVALID_ARG;
+
+  imgFrame *frame = GetImgFrame(framenum);
+  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
+
+  if (!frame->GetIsPaletted())
+    return NS_ERROR_FAILURE;
+
+  frame->GetPaletteData(aPaletteData, aPaletteLength);
+
+  return NS_OK;
+}
+
+nsresult imgContainer::InternalAddFrameHelper(PRUint32 framenum, imgFrame *aFrame,
+                                              PRUint8 **imageData, PRUint32 *imageLength,
+                                              PRUint32 **paletteData, PRUint32 *paletteLength)
+{
+  if (framenum > PRUint32(mNumFrames))
+    return NS_ERROR_INVALID_ARG;
 
-    mNumFrames++;
+  nsAutoPtr<imgFrame> frame(aFrame);
+
+  if (paletteData && paletteLength)
+    frame->GetPaletteData(paletteData, paletteLength);
+
+  frame->GetImageData(imageData, imageLength);
+
+  mFrames.InsertElementAt(framenum, frame.forget());
+  mNumFrames++;
 
-    return NS_OK;
+  return NS_OK;
+}
+                                  
+nsresult imgContainer::InternalAddFrame(PRUint32 framenum,
+                                        PRInt32 aX, PRInt32 aY,
+                                        PRInt32 aWidth, PRInt32 aHeight,
+                                        gfxASurface::gfxImageFormat aFormat,
+                                        PRUint8 aPaletteDepth,
+                                        PRUint8 **imageData,
+                                        PRUint32 *imageLength,
+                                        PRUint32 **paletteData,
+                                        PRUint32 *paletteLength)
+{
+  if (framenum > PRUint32(mNumFrames))
+    return NS_ERROR_INVALID_ARG;
+
+  nsAutoPtr<imgFrame> frame(new imgFrame());
+  NS_ENSURE_TRUE(frame, NS_ERROR_OUT_OF_MEMORY);
+
+  nsresult rv = frame->Init(aX, aY, aWidth, aHeight, aFormat, aPaletteDepth);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (mFrames.Length() == 0) {
+    return InternalAddFrameHelper(framenum, frame.forget(), imageData, imageLength, 
+                                  paletteData, paletteLength);
   }
-  
-  if (mFrames.Count() == 1) {
+
+  if (mFrames.Length() == 1) {
     // Since we're about to add our 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;
-    mFrames[0]->GetFrameDisposalMethod(&frameDisposalMethod);
+    PRInt32 frameDisposalMethod = mFrames[0]->GetFrameDisposalMethod();
     if (frameDisposalMethod == imgIContainer::kDisposeClear ||
         frameDisposalMethod == imgIContainer::kDisposeRestorePrevious)
-      mFrames[0]->GetRect(mAnim->firstFrameRefreshArea);
+      mAnim->firstFrameRefreshArea = mFrames[0]->GetRect();
   }
-  
+
   // Calculate firstFrameRefreshArea
   // 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);
+  nsIntRect frameRect = frame->GetRect();
   mAnim->firstFrameRefreshArea.UnionRect(mAnim->firstFrameRefreshArea, 
-                                         itemRect);
+                                         frameRect);
   
-  mFrames.AppendObject(item);
-
-  mNumFrames++;
+  rv = InternalAddFrameHelper(framenum, frame.forget(), imageData, imageLength,
+                              paletteData, paletteLength);
   
   // If this is our second frame (We've just added our second frame above),
   // count should now be 2.  This must be called after we AppendObject 
   // because StartAnimation checks for > 1 frames
-  if (mFrames.Count() == 2)
+  if (mFrames.Length() == 2)
     StartAnimation();
   
+  return rv;
+}
+
+/* [noscript] void appendFrame (in PRInt32 aX, in PRInt32 aY, in PRInt32 aWidth, in PRInt32 aHeight, in gfxImageFormat aFormat, [array, size_is (imageLength)] out PRUint8 imageData, out unsigned long imageLength); */
+NS_IMETHODIMP imgContainer::AppendFrame(PRInt32 aX, PRInt32 aY, PRInt32 aWidth,
+                                        PRInt32 aHeight, 
+                                        gfxASurface::gfxImageFormat aFormat,
+                                        PRUint8 **imageData,
+                                        PRUint32 *imageLength)
+{
+  NS_ENSURE_ARG_POINTER(imageData);
+  NS_ENSURE_ARG_POINTER(imageLength);
+
+  return InternalAddFrame(mNumFrames, aX, aY, aWidth, aHeight, aFormat, 
+                          /* aPaletteDepth = */ 0, imageData, imageLength,
+                          /* aPaletteData = */ nsnull, 
+                          /* aPaletteLength = */ nsnull);
+}
+
+/* [noscript] void appendPalettedFrame (in PRInt32 aX, in PRInt32 aY, in PRInt32 aWidth, in PRInt32 aHeight, in gfxImageFormat aFormat, in PRUint8 aPaletteDepth, [array, size_is (imageLength)] out PRUint8 imageData, out unsigned long imageLength, [array, size_is (paletteLength)] out PRUint32 paletteData, out unsigned long paletteLength); */
+NS_IMETHODIMP imgContainer::AppendPalettedFrame(PRInt32 aX, PRInt32 aY,
+                                                PRInt32 aWidth, PRInt32 aHeight,
+                                                gfxASurface::gfxImageFormat aFormat,
+                                                PRUint8 aPaletteDepth,
+                                                PRUint8 **imageData,
+                                                PRUint32 *imageLength,
+                                                PRUint32 **paletteData,
+                                                PRUint32 *paletteLength)
+{
+  NS_ENSURE_ARG_POINTER(imageData);
+  NS_ENSURE_ARG_POINTER(imageLength);
+  NS_ENSURE_ARG_POINTER(paletteData);
+  NS_ENSURE_ARG_POINTER(paletteLength);
+
+  return InternalAddFrame(mNumFrames, aX, aY, aWidth, aHeight, aFormat, 
+                          aPaletteDepth, imageData, imageLength,
+                          paletteData, paletteLength);
+}
+
+/*  [noscript] void ensureCleanFrame(in unsigned long aFramenum, in PRInt32 aX, in PRInt32 aY, in PRInt32 aWidth, in PRInt32 aHeight, in gfxImageFormat aFormat, [array, size_is(imageLength)] out PRUint8 imageData, out unsigned long imageLength); */
+NS_IMETHODIMP imgContainer::EnsureCleanFrame(PRUint32 aFrameNum, PRInt32 aX, PRInt32 aY,
+                                             PRInt32 aWidth, PRInt32 aHeight, 
+                                             gfxASurface::gfxImageFormat aFormat,
+                                             PRUint8 **imageData, PRUint32 *imageLength)
+{
+  NS_ENSURE_ARG_POINTER(imageData);
+  NS_ENSURE_ARG_POINTER(imageLength);
+  if (aFrameNum > PRUint32(mNumFrames))
+    return NS_ERROR_INVALID_ARG;
+
+  // Adding a frame that doesn't already exist.
+  if (aFrameNum == PRUint32(mNumFrames))
+    return InternalAddFrame(aFrameNum, aX, aY, aWidth, aHeight, aFormat, 
+                            /* aPaletteDepth = */ 0, imageData, imageLength,
+                            /* aPaletteData = */ nsnull, 
+                            /* aPaletteLength = */ nsnull);
+
+  imgFrame *frame = GetImgFrame(aFrameNum);
+  if (!frame)
+    return InternalAddFrame(aFrameNum, aX, aY, aWidth, aHeight, aFormat, 
+                            /* aPaletteDepth = */ 0, imageData, imageLength,
+                            /* aPaletteData = */ nsnull, 
+                            /* aPaletteLength = */ nsnull);
+
+  // See if we can re-use the frame that already exists.
+  nsIntRect rect = frame->GetRect();
+  if (rect.x != aX || rect.y != aY || rect.width != aWidth || rect.height != aHeight ||
+      frame->GetFormat() != aFormat) {
+    delete frame;
+    return InternalAddFrame(aFrameNum, aX, aY, aWidth, aHeight, aFormat, 
+                            /* aPaletteDepth = */ 0, imageData, imageLength,
+                            /* aPaletteData = */ nsnull, 
+                            /* aPaletteLength = */ nsnull);
+  }
+
+  // We can re-use the frame.
+  frame->GetImageData(imageData, imageLength);
+
+  return NS_OK;
+}
+
+
+//******************************************************************************
+/* void frameUpdated (in unsigned long framenumber, in nsIntRect rect); */
+NS_IMETHODIMP imgContainer::FrameUpdated(PRUint32 aFrameNum, nsIntRect &aUpdatedRect)
+{
+  if (aFrameNum >= PRUint32(mNumFrames))
+    return NS_ERROR_INVALID_ARG;
+
+  imgFrame *frame = GetImgFrame(aFrameNum);
+  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
+
+  frame->ImageUpdated(aUpdatedRect);
+
+  return NS_OK;
+}
+
+//******************************************************************************
+/* void setFrameDisposalMethod (in unsigned long framenumber, in PRInt32 aDisposalMethod); */
+NS_IMETHODIMP imgContainer::SetFrameDisposalMethod(PRUint32 aFrameNum, PRInt32 aDisposalMethod)
+{
+  if (aFrameNum >= PRUint32(mNumFrames))
+    return NS_ERROR_INVALID_ARG;
+
+  imgFrame *frame = GetImgFrame(aFrameNum);
+  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
+
+  frame->SetFrameDisposalMethod(aDisposalMethod);
+
+  return NS_OK;
+}
+
+//******************************************************************************
+/* void setFrameTimeout (in unsigned long framenumber, in PRInt32 aTimeout); */
+NS_IMETHODIMP imgContainer::SetFrameTimeout(PRUint32 aFrameNum, PRInt32 aTimeout)
+{
+  if (aFrameNum >= PRUint32(mNumFrames))
+    return NS_ERROR_INVALID_ARG;
+
+  imgFrame *frame = GetImgFrame(aFrameNum);
+  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
+
+  frame->SetTimeout(aTimeout);
+
+  return NS_OK;
+}
+
+//******************************************************************************
+/* void setFrameBlendMethod (in unsigned long framenumber, in PRInt32 aBlendMethod); */
+NS_IMETHODIMP imgContainer::SetFrameBlendMethod(PRUint32 aFrameNum, PRInt32 aBlendMethod)
+{
+  if (aFrameNum >= PRUint32(mNumFrames))
+    return NS_ERROR_INVALID_ARG;
+
+  imgFrame *frame = GetImgFrame(aFrameNum);
+  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
+
+  frame->SetBlendMethod(aBlendMethod);
+
+  return NS_OK;
+}
+
+
+//******************************************************************************
+/* void setFrameHasNoAlpha (in unsigned long framenumber); */
+NS_IMETHODIMP imgContainer::SetFrameHasNoAlpha(PRUint32 aFrameNum)
+{
+  if (aFrameNum >= PRUint32(mNumFrames))
+    return NS_ERROR_INVALID_ARG;
+
+  imgFrame *frame = GetImgFrame(aFrameNum);
+  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
+
+  frame->SetHasNoAlpha();
+
   return NS_OK;
 }
 
 //******************************************************************************
 /* void endFrameDecode (in unsigned long framenumber); */
 NS_IMETHODIMP imgContainer::EndFrameDecode(PRUint32 aFrameNum)
 {
   // Assume there's another frame.
@@ -287,20 +623,22 @@ 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
+  // Optimizing animated images is not supported.
   if (mNumFrames == 1)
-    mFrames[0]->SetMutable(PR_FALSE);
+    return mFrames[0]->Optimize();
+
   return NS_OK;
 }
 
 //******************************************************************************
 /* attribute unsigned short animationMode; */
 NS_IMETHODIMP imgContainer::GetAnimationMode(PRUint16 *aAnimationMode)
 {
   NS_ENSURE_ARG_POINTER(aAnimationMode);
@@ -346,19 +684,19 @@ NS_IMETHODIMP imgContainer::StartAnimati
   
   if (mNumFrames > 1) {
     if (!ensureAnimExists())
       return NS_ERROR_OUT_OF_MEMORY;
     
     // Default timeout to 100: the timer notify code will do the right
     // thing, so just get that started.
     PRInt32 timeout = 100;
-    gfxIImageFrame *currentFrame = GetCurrentFrameNoRef();
+    imgFrame *currentFrame = GetCurrentImgFrame();
     if (currentFrame) {
-      currentFrame->GetTimeout(&timeout);
+      timeout = currentFrame->GetTimeout();
       if (timeout <= 0) // -1 means display this frame forever
         return NS_OK;
     }
     
     mAnim->timer = do_CreateInstance("@mozilla.org/timer;1");
     NS_ENSURE_TRUE(mAnim->timer, NS_ERROR_OUT_OF_MEMORY);
     
     // The only way animating becomes true is if the timer is created
@@ -404,17 +742,17 @@ NS_IMETHODIMP imgContainer::ResetAnimati
 
   mAnim->lastCompositedFrameIndex = -1;
   mAnim->currentAnimationFrameIndex = 0;
   // Update display
   nsCOMPtr<imgIContainerObserver> observer(do_QueryReferent(mObserver));
   if (observer) {
     nsresult rv = RestoreDiscardedData();
     NS_ENSURE_SUCCESS(rv, rv);
-    observer->FrameChanged(this, mFrames[0], &(mAnim->firstFrameRefreshArea));
+    observer->FrameChanged(this, &(mAnim->firstFrameRefreshArea));
   }
 
   if (oldAnimating)
     return StartAnimation();
   return NS_OK;
 }
 
 //******************************************************************************
@@ -555,17 +893,17 @@ NS_IMETHODIMP imgContainer::RestoreDataD
 
   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 (),
+             mFrames.Length (),
              mNumFrames,
              mRestoreData.Elements(),
              buf,
              mRestoreData.Length()));
   }
 
   return ResetDiscardTimer();
 }
@@ -593,17 +931,17 @@ NS_IMETHODIMP imgContainer::Notify(nsITi
     // the imgRequest that owns us is dead, we should die now too.
     StopAnimation();
     return NS_OK;
   }
 
   if (mNumFrames == 0)
     return NS_OK;
   
-  gfxIImageFrame *nextFrame = nsnull;
+  imgFrame *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)
@@ -629,17 +967,17 @@ NS_IMETHODIMP imgContainer::Notify(nsITi
     }
 
     if (!(nextFrame = mFrames[nextFrameIndex])) {
       // something wrong with the next frame, skip it
       mAnim->currentAnimationFrameIndex = nextFrameIndex;
       mAnim->timer->SetDelay(100);
       return NS_OK;
     }
-    nextFrame->GetTimeout(&timeout);
+    timeout = nextFrame->GetTimeout();
 
   } else if (nextFrameIndex == mAnim->currentDecodingFrameIndex) {
     // Uh oh, the frame we want to show is currently being decoded (partial)
     // Wait a bit and try again
     mAnim->timer->SetDelay(100);
     return NS_OK;
   } else { //  (nextFrameIndex > currentDecodingFrameIndex)
     // We shouldn't get here. However, if we are requesting a frame
@@ -647,108 +985,102 @@ NS_IMETHODIMP imgContainer::Notify(nsITi
     NS_WARNING("imgContainer::Notify()  Frame is passed decoded frame");
     nextFrameIndex = mAnim->currentDecodingFrameIndex;
     if (!(nextFrame = mFrames[nextFrameIndex])) {
       // something wrong with the next frame, skip it
       mAnim->currentAnimationFrameIndex = nextFrameIndex;
       mAnim->timer->SetDelay(100);
       return NS_OK;
     }
-    nextFrame->GetTimeout(&timeout);
+    timeout = nextFrame->GetTimeout();
   }
 
   if (timeout > 0)
     mAnim->timer->SetDelay(timeout);
   else
     StopAnimation();
 
   nsIntRect dirtyRect;
-  gfxIImageFrame *frameToUse = nsnull;
+  imgFrame *frameToUse = nsnull;
 
   if (nextFrameIndex == 0) {
     frameToUse = nextFrame;
     dirtyRect = mAnim->firstFrameRefreshArea;
   } else {
-    gfxIImageFrame *prevFrame = mFrames[previousFrameIndex];
+    imgFrame *prevFrame = mFrames[previousFrameIndex];
     if (!prevFrame)
       return NS_OK;
 
     // Change frame and announce it
     if (NS_FAILED(DoComposite(&frameToUse, &dirtyRect, prevFrame,
                               nextFrame, nextFrameIndex))) {
       // something went wrong, move on to next
       NS_WARNING("imgContainer::Notify(): Composing Frame Failed\n");
       mAnim->currentAnimationFrameIndex = nextFrameIndex;
       return NS_OK;
     }
   }
   // Set currentAnimationFrameIndex at the last possible moment
   mAnim->currentAnimationFrameIndex = nextFrameIndex;
   // Refreshes the screen
-  observer->FrameChanged(this, frameToUse, &dirtyRect);
+  observer->FrameChanged(this, &dirtyRect);
   
   return NS_OK;
 }
 
 //******************************************************************************
 // DoComposite gets called when the timer for animation get fired and we have to
 // update the composited frame of the animation.
-nsresult imgContainer::DoComposite(gfxIImageFrame** aFrameToUse,
+nsresult imgContainer::DoComposite(imgFrame** aFrameToUse,
                                    nsIntRect* aDirtyRect,
-                                   gfxIImageFrame* aPrevFrame,
-                                   gfxIImageFrame* aNextFrame,
+                                   imgFrame* aPrevFrame,
+                                   imgFrame* aNextFrame,
                                    PRInt32 aNextFrameIndex)
 {
   NS_ENSURE_ARG_POINTER(aDirtyRect);
   NS_ENSURE_ARG_POINTER(aPrevFrame);
   NS_ENSURE_ARG_POINTER(aNextFrame);
   NS_ENSURE_ARG_POINTER(aFrameToUse);
 
-  PRInt32 prevFrameDisposalMethod;
-  aPrevFrame->GetFrameDisposalMethod(&prevFrameDisposalMethod);
-
+  PRInt32 prevFrameDisposalMethod = aPrevFrame->GetFrameDisposalMethod();
   if (prevFrameDisposalMethod == imgIContainer::kDisposeRestorePrevious &&
       !mAnim->compositingPrevFrame)
     prevFrameDisposalMethod = imgIContainer::kDisposeClear;
-  nsIntRect prevFrameRect;
-  aPrevFrame->GetRect(prevFrameRect);
+
+  nsIntRect prevFrameRect = aPrevFrame->GetRect();
   PRBool isFullPrevFrame = (prevFrameRect.x == 0 && prevFrameRect.y == 0 &&
                             prevFrameRect.width == mSize.width &&
                             prevFrameRect.height == mSize.height);
 
   // Optimization: DisposeClearAll if the previous frame is the same size as
   //               container and it's clearing itself
   if (isFullPrevFrame && 
       (prevFrameDisposalMethod == imgIContainer::kDisposeClear))
     prevFrameDisposalMethod = imgIContainer::kDisposeClearAll;
 
-  PRInt32 nextFrameDisposalMethod;
-  nsIntRect nextFrameRect;
-  aNextFrame->GetFrameDisposalMethod(&nextFrameDisposalMethod);
-  aNextFrame->GetRect(nextFrameRect);
+  PRInt32 nextFrameDisposalMethod = aNextFrame->GetFrameDisposalMethod();
+  nsIntRect nextFrameRect = aNextFrame->GetRect();
   PRBool isFullNextFrame = (nextFrameRect.x == 0 && nextFrameRect.y == 0 &&
                             nextFrameRect.width == mSize.width &&
                             nextFrameRect.height == mSize.height);
 
-  gfx_format nextFormat;
-  aNextFrame->GetFormat(&nextFormat);
-  if (nextFormat != gfxIFormats::PAL && nextFormat != gfxIFormats::PAL_A1) {
+  if (!aNextFrame->GetIsPaletted()) {
     // Optimization: Skip compositing if the previous frame wants to clear the
     //               whole image
     if (prevFrameDisposalMethod == imgIContainer::kDisposeClearAll) {
       aDirtyRect->SetRect(0, 0, mSize.width, mSize.height);
       *aFrameToUse = aNextFrame;
       return NS_OK;
     }
   
     // Optimization: Skip compositing if this frame is the same size as the
     //               container and it's fully drawing over prev frame (no alpha)
     if (isFullNextFrame &&
         (nextFrameDisposalMethod != imgIContainer::kDisposeRestorePrevious) &&
-        (nextFormat == gfxIFormats::RGB)) {
+        !aNextFrame->GetHasAlpha()) {
       aDirtyRect->SetRect(0, 0, mSize.width, mSize.height);
       *aFrameToUse = aNextFrame;
       return NS_OK;
     }
   }
 
   // Calculate area that needs updating
   switch (prevFrameDisposalMethod) {
@@ -789,36 +1121,33 @@ nsresult imgContainer::DoComposite(gfxII
     *aFrameToUse = mAnim->compositingFrame;
     return NS_OK;
   }
 
   PRBool needToBlankComposite = PR_FALSE;
 
   // Create the Compositing Frame
   if (!mAnim->compositingFrame) {
-    nsresult rv;
-    mAnim->compositingFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2", &rv);
-    if (NS_FAILED(rv))
-      return rv;
-    rv = mAnim->compositingFrame->Init(0, 0, mSize.width, mSize.height,
-                                       gfxIFormats::RGB_A1, 24);
-    if (NS_FAILED(rv)) {
+    mAnim->compositingFrame = new imgFrame();
+    if (!mAnim->compositingFrame) {
       NS_WARNING("Failed to init compositingFrame!\n");
-      mAnim->compositingFrame = nsnull;
-      return rv;
+      return NS_ERROR_OUT_OF_MEMORY;
     }
+    nsresult rv = mAnim->compositingFrame->Init(0, 0, mSize.width, mSize.height,
+                                                gfxASurface::ImageFormatARGB32);
+    NS_ENSURE_SUCCESS(rv, rv);
     needToBlankComposite = PR_TRUE;
   } else if (aNextFrameIndex == 1) {
     // When we are looping the compositing frame needs to be cleared.
     needToBlankComposite = PR_TRUE;
   }
 
   // More optimizations possible when next frame is not transparent
   PRBool doDisposal = PR_TRUE;
-  if ((nextFormat == gfxIFormats::RGB)||(nextFormat == gfxIFormats::PAL)) {
+  if (!aNextFrame->GetHasAlpha()) {
     if (isFullNextFrame) {
       // Optimization: No need to dispose prev.frame when 
       // next frame is full frame and not transparent.
       doDisposal = PR_FALSE;
       // No need to blank the composite frame
       needToBlankComposite = PR_FALSE;
     } else {
       if ((prevFrameRect.x >= nextFrameRect.x) &&
@@ -867,82 +1196,74 @@ nsresult imgContainer::DoComposite(gfxII
       default:
         // Copy previous frame into compositingFrame before we put the new frame on top
         // Assumes that the previous frame represents a full frame (it could be
         // smaller in size than the container, as long as the frame before it erased
         // itself)
         // Note: Frame 1 never gets into DoComposite(), so (aNextFrameIndex - 1) will
         // always be a valid frame number.
         if (mAnim->lastCompositedFrameIndex != aNextFrameIndex - 1) {
-          gfx_format prevFormat;
-          aPrevFrame->GetFormat(&prevFormat);
-          if (isFullPrevFrame && 
-              prevFormat != gfxIFormats::PAL && prevFormat != gfxIFormats::PAL_A1) {
+          if (isFullPrevFrame && !aPrevFrame->GetIsPaletted())
             // Just copy the bits
             CopyFrameImage(aPrevFrame, mAnim->compositingFrame);
           } else {
             if (needToBlankComposite) {
               // Only blank composite when prev is transparent or not full.
-              if (!isFullPrevFrame ||
-                  (prevFormat != gfxIFormats::RGB && prevFormat != gfxIFormats::PAL)) {
+              if (aPrevFrame->GetHasAlpha() || !isFullPrevFrame) {
                 ClearFrame(mAnim->compositingFrame);
               }
             }
             DrawFrameTo(aPrevFrame, mAnim->compositingFrame, prevFrameRect);
           }
         }
-    }
   } else if (needToBlankComposite) {
     // If we just created the composite, it could have anything in it's
     // buffers. Clear them
     ClearFrame(mAnim->compositingFrame);
   }
 
   // Check if the frame we are composing wants the previous image restored afer
   // it is done. Don't store it (again) if last frame wanted its image restored
   // too
   if ((nextFrameDisposalMethod == imgIContainer::kDisposeRestorePrevious) &&
       (prevFrameDisposalMethod != imgIContainer::kDisposeRestorePrevious)) {
     // We are storing the whole image.
     // It would be better if we just stored the area that nextFrame is going to
     // overwrite.
     if (!mAnim->compositingPrevFrame) {
-      nsresult rv;
-      mAnim->compositingPrevFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2",
-                                                       &rv);
-      if (NS_FAILED(rv))
-        return rv;
-      rv = mAnim->compositingPrevFrame->Init(0, 0, mSize.width, mSize.height,
-                                              gfxIFormats::RGB_A1, 24);
-      if (NS_FAILED(rv))
-        return rv;
+      mAnim->compositingPrevFrame = new imgFrame();
+      if (!mAnim->compositingPrevFrame) {
+        NS_WARNING("Failed to init compositingFrame!\n");
+        return NS_ERROR_OUT_OF_MEMORY;
+      }
+      nsresult rv = mAnim->compositingPrevFrame->Init(0, 0, mSize.width, mSize.height,
+                                                      gfxASurface::ImageFormatARGB32);
+      NS_ENSURE_SUCCESS(rv, rv);
     }
+
     CopyFrameImage(mAnim->compositingFrame, mAnim->compositingPrevFrame);
   }
 
   // blit next frame into it's correct spot
   DrawFrameTo(aNextFrame, mAnim->compositingFrame, nextFrameRect);
+
   // Set timeout of CompositeFrame to timeout of frame we just composed
   // Bug 177948
-  PRInt32 timeout;
-  aNextFrame->GetTimeout(&timeout);
+  PRInt32 timeout = aNextFrame->GetTimeout();
   mAnim->compositingFrame->SetTimeout(timeout);
 
   // Tell the image that it is fully 'downloaded'.
-  nsIntRect r;
-  mAnim->compositingFrame->GetRect(r);
-  nsCOMPtr<nsIImage> img = do_GetInterface(mAnim->compositingFrame);
-  nsresult rv = img->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r);
+  nsresult rv = mAnim->compositingFrame->ImageUpdated(mAnim->compositingFrame->GetRect());
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // We don't want to keep composite images for 8bit frames...
   if (isFullNextFrame && mAnimationMode == kNormalAnimMode && mLoopCount != 0 &&
-      nextFormat != gfxIFormats::PAL && nextFormat != gfxIFormats::PAL_A1) {
+      !aNextFrame->GetIsPaletted()) {
     // We have a composited full frame
     // Store the composited frame into the mFrames[..] so we don't have to
     // continuously re-build it
     // Then set the previous frame's disposal to CLEAR_ALL so we just draw the
     // frame next time around
     if (CopyFrameImage(mAnim->compositingFrame, aNextFrame)) {
       aPrevFrame->SetFrameDisposalMethod(imgIContainer::kDisposeClearAll);
       mAnim->lastCompositedFrameIndex = -1;
@@ -954,61 +1275,60 @@ nsresult imgContainer::DoComposite(gfxII
   mAnim->lastCompositedFrameIndex = aNextFrameIndex;
   *aFrameToUse = mAnim->compositingFrame;
 
   return NS_OK;
 }
 
 //******************************************************************************
 // Fill aFrame with black. Does also clears the mask.
-void imgContainer::ClearFrame(gfxIImageFrame *aFrame)
+void imgContainer::ClearFrame(imgFrame *aFrame)
 {
   if (!aFrame)
     return;
 
-  nsCOMPtr<nsIImage> img(do_GetInterface(aFrame));
-  nsRefPtr<gfxASurface> surf;
+  aFrame->LockImageData();
 
-  img->LockImagePixels(0);
-  img->GetSurface(getter_AddRefs(surf));
+  nsRefPtr<gfxASurface> surf;
+  aFrame->GetSurface(getter_AddRefs(surf));
 
   // Erase the surface to transparent
   gfxContext ctx(surf);
   ctx.SetOperator(gfxContext::OPERATOR_CLEAR);
   ctx.Paint();
-  img->UnlockImagePixels(0);
+
+  aFrame->UnlockImageData();
 }
 
 //******************************************************************************
-void imgContainer::ClearFrame(gfxIImageFrame *aFrame, nsIntRect &aRect)
+void imgContainer::ClearFrame(imgFrame *aFrame, nsIntRect &aRect)
 {
-  if (!aFrame || aRect.width <= 0 || aRect.height <= 0) {
+  if (!aFrame || aRect.width <= 0 || aRect.height <= 0)
     return;
-  }
 
-  nsCOMPtr<nsIImage> img(do_GetInterface(aFrame));
-  nsRefPtr<gfxASurface> surf;
+  aFrame->LockImageData();
 
-  img->LockImagePixels(0);
-  img->GetSurface(getter_AddRefs(surf));
+  nsRefPtr<gfxASurface> surf;
+  aFrame->GetSurface(getter_AddRefs(surf));
 
   // Erase the destination rectangle to transparent
   gfxContext ctx(surf);
   ctx.SetOperator(gfxContext::OPERATOR_CLEAR);
   ctx.Rectangle(gfxRect(aRect.x, aRect.y, aRect.width, aRect.height));
   ctx.Fill();
-  img->UnlockImagePixels(0);
+
+  aFrame->UnlockImageData();
 }
 
 
 //******************************************************************************
 // Whether we succeed or fail will not cause a crash, and there's not much
 // we can do about a failure, so there we don't return a nsresult
-PRBool imgContainer::CopyFrameImage(gfxIImageFrame *aSrcFrame,
-                                    gfxIImageFrame *aDstFrame)
+PRBool imgContainer::CopyFrameImage(imgFrame *aSrcFrame,
+                                    imgFrame *aDstFrame)
 {
   PRUint8* aDataSrc;
   PRUint8* aDataDest;
   PRUint32 aDataLengthSrc;
   PRUint32 aDataLengthDest;
 
   if (!aSrcFrame || !aDstFrame)
     return PR_FALSE;
@@ -1031,122 +1351,119 @@ PRBool imgContainer::CopyFrameImage(gfxI
 
 //******************************************************************************
 /* 
  * aSrc is the current frame being drawn,
  * aDst is the composition frame where the current frame is drawn into.
  * aSrcRect is the size of the current frame, and the position of that frame
  *          in the composition frame.
  */
-nsresult imgContainer::DrawFrameTo(gfxIImageFrame *aSrc,
-                                   gfxIImageFrame *aDst, 
+nsresult imgContainer::DrawFrameTo(imgFrame *aSrc,
+                                   imgFrame *aDst, 
                                    nsIntRect& aSrcRect)
 {
   NS_ENSURE_ARG_POINTER(aSrc);
   NS_ENSURE_ARG_POINTER(aDst);
 
-  nsIntRect dstRect;
-  aDst->GetRect(dstRect);
+  nsIntRect dstRect = aDst->GetRect();
 
   // According to both AGIF and APNG specs, offsets are unsigned
   if (aSrcRect.x < 0 || aSrcRect.y < 0) {
     NS_WARNING("imgContainer::DrawFrameTo: negative offsets not allowed");
     return NS_ERROR_FAILURE;
   }
   // Outside the destination frame, skip it
   if ((aSrcRect.x > dstRect.width) || (aSrcRect.y > dstRect.height)) {
     return NS_OK;
   }
-  gfx_format format;
-  aSrc->GetFormat(&format);
-  if (format == gfxIFormats::PAL || format == gfxIFormats::PAL_A1) {
+
+  if (aSrc->GetIsPaletted()) {
     // Larger than the destination frame, clip it
     PRInt32 width = PR_MIN(aSrcRect.width, dstRect.width - aSrcRect.x);
     PRInt32 height = PR_MIN(aSrcRect.height, dstRect.height - aSrcRect.y);
 
     // The clipped image must now fully fit within destination image frame
     NS_ASSERTION((aSrcRect.x >= 0) && (aSrcRect.y >= 0) &&
                  (aSrcRect.x + width <= dstRect.width) &&
                  (aSrcRect.y + height <= dstRect.height),
                 "imgContainer::DrawFrameTo: Invalid aSrcRect");
 
     // clipped image size may be smaller than source, but not larger
     NS_ASSERTION((width <= aSrcRect.width) && (height <= aSrcRect.height),
                  "imgContainer::DrawFrameTo: source must be smaller than dest");
 
     if (NS_FAILED(aDst->LockImageData()))
       return NS_ERROR_FAILURE;
+
     // Get pointers to image data
     PRUint32 size;
     PRUint8 *srcPixels;
-    gfx_color *colormap;
-    gfx_color *dstPixels;
+    PRUint32 *colormap;
+    PRUint32 *dstPixels;
 
     aSrc->GetImageData(&srcPixels, &size);
-    aDst->GetImageData((PRUint8**)&dstPixels, &size);
     aSrc->GetPaletteData(&colormap, &size);
+    aDst->GetImageData((PRUint8 **)&dstPixels, &size);
     if (!srcPixels || !dstPixels || !colormap) {
       aDst->UnlockImageData();
       return NS_ERROR_FAILURE;
     }
 
     // Skip to the right offset
     dstPixels += aSrcRect.x + (aSrcRect.y * dstRect.width);
-    if (format == gfxIFormats::PAL) {
+    if (!aSrc->GetHasAlpha()) {
       for (PRInt32 r = height; r > 0; --r) {
         for (PRInt32 c = 0; c < width; c++) {
           dstPixels[c] = colormap[srcPixels[c]];
         }
         // Go to the next row in the source resp. destination image
         srcPixels += aSrcRect.width;
         dstPixels += dstRect.width;
       }
     } else {
-      // With transparent source, skip transparent pixels
       for (PRInt32 r = height; r > 0; --r) {
         for (PRInt32 c = 0; c < width; c++) {
           const PRUint32 color = colormap[srcPixels[c]];
           if (color)
             dstPixels[c] = color;
         }
         // Go to the next row in the source resp. destination image
         srcPixels += aSrcRect.width;
         dstPixels += dstRect.width;
       }
     }
+
     aDst->UnlockImageData();
     return NS_OK;
   }
 
-  nsCOMPtr<nsIImage> srcImg(do_GetInterface(aSrc));
   nsRefPtr<gfxPattern> srcPatt;
-  srcImg->GetPattern(getter_AddRefs(srcPatt));
+  aSrc->GetPattern(getter_AddRefs(srcPatt));
 
-  nsCOMPtr<nsIImage> dstImg(do_GetInterface(aDst));
+  aDst->LockImageData();
   nsRefPtr<gfxASurface> dstSurf;
-  // Note: dstImage has LockImageData() called on it above, so it's safe to get
-  // the surface.
-  dstImg->GetSurface(getter_AddRefs(dstSurf));
+  aDst->GetSurface(getter_AddRefs(dstSurf));
 
   gfxContext dst(dstSurf);
   dst.Translate(gfxPoint(aSrcRect.x, aSrcRect.y));
   dst.Rectangle(gfxRect(0, 0, aSrcRect.width, aSrcRect.height), PR_TRUE);
   
   // first clear the surface if the blend flag says so
-  PRInt32 blendMethod;
-  aSrc->GetBlendMethod(&blendMethod);
+  PRInt32 blendMethod = aSrc->GetBlendMethod();
   if (blendMethod == imgIContainer::kBlendSource) {
     gfxContext::GraphicsOperator defaultOperator = dst.CurrentOperator();
     dst.SetOperator(gfxContext::OPERATOR_CLEAR);
     dst.Fill();
     dst.SetOperator(defaultOperator);
   }
   dst.SetPattern(srcPatt);
   dst.Paint();
 
+  aDst->UnlockImageData();
+
   return NS_OK;
 }
 
 
 /********* Methods to implement lazy allocation of nsIProperties object *************/
 NS_IMETHODIMP imgContainer::Get(const char *prop, const nsIID & iid, void * *result)
 {
   if (!mProperties)
@@ -1202,23 +1519,25 @@ imgContainer::sDiscardTimerCallback(nsIT
 {
   imgContainer *self = (imgContainer *) aClosure;
 
   NS_ASSERTION(aTimer == self->mDiscardTimer,
                "imgContainer::DiscardTimerCallback() got a callback for an unknown timer");
 
   self->mDiscardTimer = nsnull;
 
-  int old_frame_count = self->mFrames.Count();
+  int old_frame_count = self->mFrames.Length();
 
   // Don't discard animated images, because we don't handle that very well. (See bug 414259.)
   if (self->mAnim) {
     return;
   }
 
+  for (int i = 0; i < old_frame_count; ++i)
+    delete self->mFrames[i];
   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,
@@ -1275,17 +1594,17 @@ imgContainer::RestoreDiscardedData(void)
   int num_expected_frames = mNumFrames;
 
   // To prevent that ReloadImages is called multiple times, reset the flag before reloading
   mDiscarded = PR_FALSE;
 
   rv = ReloadImages();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  NS_ASSERTION (mNumFrames == mFrames.Count(),
+  NS_ASSERTION (mNumFrames == PRInt32(mFrames.Length()),
                 "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",
@@ -1293,16 +1612,37 @@ imgContainer::RestoreDiscardedData(void)
            mDiscardableMimeType.get(),
            mNumFrames,
            num_containers_with_discardable_data,
            num_compressed_image_bytes));
 
   return NS_OK;
 }
 
+//******************************************************************************
+/* [noscript] void draw(in gfxContext aContext, in gfxGraphicsFilter aFilter, in gfxMatrix aUserSpaceToImageSpace, in gfxRect aFill, in nsIntRect aSubimage); */ 
+NS_IMETHODIMP imgContainer::Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter, 
+                                 gfxMatrix &aUserSpaceToImageSpace, gfxRect &aFill,
+                                 nsIntRect &aSubimage)
+{
+  NS_ENSURE_ARG_POINTER(aContext);
+
+  imgFrame *frame = GetCurrentImgFrame();
+  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
+
+  nsIntRect framerect = frame->GetRect();
+  nsIntMargin padding(framerect.x, framerect.y, 
+                      mSize.width - framerect.XMost(),
+                      mSize.height - framerect.YMost());
+
+  frame->Draw(aContext, aFilter, aUserSpaceToImageSpace, aFill, padding, aSubimage);
+
+  return NS_OK;
+}
+
 class ContainerLoader : public imgILoad,
                         public imgIDecoderObserver,
                         public nsSupportsWeakReference
 {
 public:
 
   NS_DECL_ISUPPORTS
   NS_DECL_IMGILOAD
@@ -1365,31 +1705,31 @@ ContainerLoader::OnStartDecode(imgIReque
 NS_IMETHODIMP
 ContainerLoader::OnStartContainer(imgIRequest *aRequest, imgIContainer *aContainer)
 {
   return NS_OK;
 }
 
 /* Implement imgIDecoderObserver::onStartFrame() */
 NS_IMETHODIMP
-ContainerLoader::OnStartFrame(imgIRequest *aRequest, gfxIImageFrame *aFrame)
+ContainerLoader::OnStartFrame(imgIRequest *aRequest, PRUint32 aFrame)
 {
   return NS_OK;
 }
 
 /* Implement imgIDecoderObserver::onDataAvailable() */
 NS_IMETHODIMP
-ContainerLoader::OnDataAvailable(imgIRequest *aRequest, gfxIImageFrame *aFrame, const nsIntRect * aRect)
+ContainerLoader::OnDataAvailable(imgIRequest *aRequest, PRBool aCurrentFrame, const nsIntRect * aRect)
 {
   return NS_OK;
 }
 
 /* Implement imgIDecoderObserver::onStopFrame() */
 NS_IMETHODIMP
-ContainerLoader::OnStopFrame(imgIRequest *aRequest, gfxIImageFrame *aFrame)
+ContainerLoader::OnStopFrame(imgIRequest *aRequest, PRUint32 aFrame)
 {
   return NS_OK;
 }
 
 /* Implement imgIDecoderObserver::onStopContainer() */
 NS_IMETHODIMP
 ContainerLoader::OnStopContainer(imgIRequest *aRequest, imgIContainer *aContainer)
 {
@@ -1407,31 +1747,31 @@ ContainerLoader::OnStopDecode(imgIReques
 NS_IMETHODIMP
 ContainerLoader::OnStopRequest(imgIRequest *aRequest, PRBool aIsLastPart)
 {
   return NS_OK;
 }
 
 /* implement imgIContainerObserver::frameChanged() */
 NS_IMETHODIMP
-ContainerLoader::FrameChanged(imgIContainer *aContainer, gfxIImageFrame *aFrame, nsIntRect * aDirtyRect)
+ContainerLoader::FrameChanged(imgIContainer *aContainer, nsIntRect * aDirtyRect)
 {
   return NS_OK;
 }
 
 nsresult
 imgContainer::ReloadImages(void)
 {
   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,
+  NS_ASSERTION(mFrames.Length() == 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",
@@ -1482,13 +1822,13 @@ imgContainer::ReloadImages(void)
   (void)decoder->WriteFrom(stream, mRestoreData.Length(), &written);
 
   result = decoder->Flush();
   NS_ENSURE_SUCCESS(result, result);
 
   result = decoder->Close();
   NS_ENSURE_SUCCESS(result, result);
 
-  NS_ASSERTION(mFrames.Count() == mNumFrames,
-               "imgContainer::ReloadImages(): the restored mFrames.Count() doesn't match mNumFrames!");
+  NS_ASSERTION(PRInt32(mFrames.Length()) == mNumFrames,
+               "imgContainer::ReloadImages(): the restored mFrames.Length() doesn't match mNumFrames!");
 
   return result;
 }
--- a/modules/libpr0n/src/imgContainer.h
+++ b/modules/libpr0n/src/imgContainer.h
@@ -50,28 +50,28 @@
  */
 
 #ifndef __imgContainer_h__
 #define __imgContainer_h__
 
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
 #include "imgIContainer.h"
-#include "gfxIImageFrame.h"
 #include "nsIProperties.h"
 #include "nsITimer.h"
 #include "nsWeakReference.h"
 #include "nsTArray.h"
+#include "imgFrame.h"
 
 #define NS_IMGCONTAINER_CID \
-{ /* 27f0682c-ff64-4dd2-ae7a-668e59f2fd38 */         \
-     0x27f0682c,                                     \
-     0xff64,                                         \
-     0x4dd2,                                         \
-    {0xae, 0x7a, 0x66, 0x8e, 0x59, 0xf2, 0xfd, 0x38} \
+{ /* c76ff2c1-9bf6-418a-b143-3340c00112f7 */         \
+     0x376ff2c1,                                     \
+     0x9bf6,                                         \
+     0x418a,                                         \
+    {0xb1, 0x43, 0x33, 0x40, 0xc0, 0x01, 0x12, 0xf7} \
 }
 
 /**
  * Handles static and animated image containers.
  *
  *
  * @par A Quick Walk Through
  * The decoder initializes this class and calls AppendFrame() to add a frame.
@@ -162,24 +162,24 @@ private:
     /** For managing blending of frames
      *
      * Some animations will use the compositingFrame to composite images
      * and just hand this back to the caller when it is time to draw the frame.
      * NOTE: When clearing compositingFrame, remember to set
      *       lastCompositedFrameIndex to -1.  Code assume that if
      *       lastCompositedFrameIndex >= 0 then compositingFrame exists.
      */
-    nsCOMPtr<gfxIImageFrame>   compositingFrame;
+    nsAutoPtr<imgFrame>        compositingFrame;
     /** the previous composited frame, for DISPOSE_RESTORE_PREVIOUS
      *
      * The Previous Frame (all frames composited up to the current) needs to be
      * stored in cases where the image specifies it wants the last frame back
      * when it's done with the current frame.
      */
-    nsCOMPtr<gfxIImageFrame>   compositingPrevFrame;
+    nsAutoPtr<imgFrame>        compositingPrevFrame;
     //! Timer to animate multiframed images
     nsCOMPtr<nsITimer>         timer;
     
     Anim() :
       firstFrameRefreshArea(),
       currentDecodingFrameIndex(0),
       currentAnimationFrameIndex(0),
       lastCompositedFrameIndex(-1),
@@ -190,103 +190,82 @@ private:
     }
     ~Anim()
     {
       if (timer)
         timer->Cancel();
     }
   };
 
-  gfxIImageFrame* GetCurrentFrameNoRef();
+  imgFrame* GetImgFrame(PRUint32 framenum);
+  imgFrame* GetCurrentImgFrame();
+  PRInt32 GetCurrentImgFrameIndex() const;
   
   inline Anim* ensureAnimExists() {
     if (!mAnim)
       mAnim = new Anim();
     return mAnim;
   }
   
   /** Function for doing the frame compositing of animations
    *
    * @param aFrameToUse Set by DoComposite
    *                   (aNextFrame, compositingFrame, or compositingPrevFrame)
    * @param aDirtyRect  Area that the display will need to update
    * @param aPrevFrame  Last Frame seen/processed
    * @param aNextFrame  Frame we need to incorperate/display
    * @param aNextFrameIndex Position of aNextFrame in mFrames list
    */
-  nsresult DoComposite(gfxIImageFrame** aFrameToUse, nsIntRect* aDirtyRect,
-                       gfxIImageFrame* aPrevFrame,
-                       gfxIImageFrame* aNextFrame,
+  nsresult DoComposite(imgFrame** aFrameToUse, nsIntRect* aDirtyRect,
+                       imgFrame* aPrevFrame,
+                       imgFrame* aNextFrame,
                        PRInt32 aNextFrameIndex);
   
-  /**
-   * Combine aOverlayFrame's mask into aCompositingFrame's mask.
-   *
-   * This takes the mask information from the passed in aOverlayFrame and
-   * inserts that information into the aCompositingFrame's mask at the proper
-   * offsets. It does *not* rebuild the entire mask.
-   *
-   * @param aCompositingFrame Target frame
-   * @param aOverlayFrame     This frame's mask is being copied
-   */
-  void BuildCompositeMask(gfxIImageFrame* aCompositingFrame,
-                          gfxIImageFrame* aOverlayFrame);
-  
-  /** Sets an area of the frame's mask.
-   *
-   * @param aFrame Target Frame
-   * @param aVisible Turn on (PR_TRUE) or off (PR_FALSE) visibility
-   *
-   * @note Invisible area of frame's image will need to be set to 0
-   */
-  void SetMaskVisibility(gfxIImageFrame *aFrame, PRBool aVisible);
-  //! @overload
-  void SetMaskVisibility(gfxIImageFrame *aFrame,
-                         PRInt32 aX, PRInt32 aY,
-                         PRInt32 aWidth, PRInt32 aHeight,
-                         PRBool aVisible);
-  //! @overload
-  void SetMaskVisibility(gfxIImageFrame *aFrame,
-                         nsIntRect &aRect, PRBool aVisible) {
-    SetMaskVisibility(aFrame, aRect.x, aRect.y,
-                      aRect.width, aRect.height, aVisible);
-  }
-  
   /** Clears an area of <aFrame> with transparent black.
    *
    * @param aFrame Target Frame
    *
    * @note Does also clears the transparancy mask
    */
-  static void ClearFrame(gfxIImageFrame* aFrame);
+  static void ClearFrame(imgFrame* aFrame);
   
   //! @overload
-  static void ClearFrame(gfxIImageFrame* aFrame, nsIntRect &aRect);
+  static void ClearFrame(imgFrame* aFrame, nsIntRect &aRect);
   
-  //! Copy one gfxIImageFrame's image and mask into another
-  static PRBool CopyFrameImage(gfxIImageFrame *aSrcFrame,
-                               gfxIImageFrame *aDstFrame);
+  //! Copy one frames's image and mask into another
+  static PRBool CopyFrameImage(imgFrame *aSrcFrame,
+                               imgFrame *aDstFrame);
   
-  /** Draws one gfxIImageFrame's image to into another,
+  /** Draws one frames's image to into another,
    * at the position specified by aRect
    *
    * @param aSrcFrame  Frame providing the source image
    * @param aDstFrame  Frame where the image is drawn into
    * @param aRect      The position and size to draw the image
    */
-  static nsresult DrawFrameTo(gfxIImageFrame *aSrcFrame,
-                              gfxIImageFrame *aDstFrame,
+  static nsresult DrawFrameTo(imgFrame *aSrcFrame,
+                              imgFrame *aDstFrame,
                               nsIntRect& aRect);
 
+  nsresult InternalAddFrameHelper(PRUint32 framenum, imgFrame *frame,
+                                  PRUint8 **imageData, PRUint32 *imageLength,
+                                  PRUint32 **paletteData, PRUint32 *paletteLength);
+  nsresult InternalAddFrame(PRUint32 framenum, PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight,
+                            gfxASurface::gfxImageFormat aFormat, PRUint8 aPaletteDepth,
+                            PRUint8 **imageData, PRUint32 *imageLength,
+                            PRUint32 **paletteData, PRUint32 *paletteLength);
+
+private: // data
+
   nsIntSize                  mSize;
   
-  //! All the <gfxIImageFrame>s of the PNG
+  //! All the frames of the image
   // *** 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;
+  nsTArray<imgFrame *>       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;
   
rename from gfx/src/shared/gfxImageFrame.cpp
rename to modules/libpr0n/src/imgFrame.cpp
--- a/gfx/src/shared/gfxImageFrame.cpp
+++ b/modules/libpr0n/src/imgFrame.cpp
@@ -10,419 +10,913 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is mozilla.org code.
  *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2001
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
- *   Stuart Parmenter <pavlov@netscape.com>
+ *   Joe Drew <joe@drew.ca> (original author)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of 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
  * decision by deleting the provisions above and replace them with the notice
  * 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 "gfxImageFrame.h"
-#include "nsIServiceManager.h"
+#include "imgFrame.h"
+
 #include <limits.h>
+
 #include "prmem.h"
+#include "prenv.h"
+
+#include "gfxPlatform.h"
+
+static PRBool gDisableOptimize = PR_FALSE;
+
+/*XXX get CAIRO_HAS_DDRAW_SURFACE */
+#include "cairo.h"
+
+#ifdef CAIRO_HAS_DDRAW_SURFACE
+#include "gfxDDrawSurface.h"
+#endif
+
+#if defined(XP_WIN) || defined(WINCE)
+#include "gfxWindowsPlatform.h"
+#endif
+
+#if defined(XP_WIN) && !defined(WINCE)
+
+/* Whether to use the windows surface; only for desktop win32 */
+#define USE_WIN_SURFACE 1
+
+static PRUint32 gTotalDDBs = 0;
+static PRUint32 gTotalDDBSize = 0;
+// only use up a maximum of 64MB in DDBs
+#define kMaxDDBSize (64*1024*1024)
+// and don't let anything in that's bigger than 4MB
+#define kMaxSingleDDBSize (4*1024*1024)
+
+#endif
+
+// Returns true if an image of aWidth x aHeight is allowed and legal.
+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 )) {
+    NS_WARNING("image too big");
+    return PR_FALSE;
+  }
+
+  // protect against division by zero - this really shouldn't happen
+  // if our consumers were well behaved, but they aren't (bug 368427)
+  if (NS_UNLIKELY(aHeight == 0)) {
+    return PR_FALSE;
+  }
 
-NS_IMPL_ISUPPORTS2(gfxImageFrame, gfxIImageFrame, nsIInterfaceRequestor)
+  // check to make sure we don't overflow a 32-bit
+  PRInt32 tmp = aWidth * aHeight;
+  if (NS_UNLIKELY(tmp / aHeight != aWidth)) {
+    NS_WARNING("width or height too large");
+    return PR_FALSE;
+  }
+  tmp = tmp * 4;
+  if (NS_UNLIKELY(tmp / 4 != aWidth * aHeight)) {
+    NS_WARNING("width or height too large");
+    return PR_FALSE;
+  }
+#if defined(XP_MACOSX)
+  // CoreGraphics is limited to images < 32K in *height*, so clamp all surfaces on the Mac to that height
+  if (NS_UNLIKELY(aHeight > SHRT_MAX)) {
+    NS_WARNING("image too big");
+    return PR_FALSE;
+  }
+#endif
+  return PR_TRUE;
+}
 
-gfxImageFrame::gfxImageFrame() :
-  mImageData(nsnull),
+// Returns whether we should, at this time, use image surfaces instead of
+// optimized platform-specific surfaces.
+static PRBool ShouldUseImageSurfaces()
+{
+#if defined(WINCE)
+  // There is no test on windows mobile to check for Gui resources.
+  // Allocate, until we run out of memory.
+  gfxWindowsPlatform::RenderMode rmode = gfxWindowsPlatform::GetPlatform()->GetRenderMode();
+  return rmode != gfxWindowsPlatform::RENDER_DDRAW &&
+      rmode != gfxWindowsPlatform::RENDER_DDRAW_GL;
+
+#elif defined(USE_WIN_SURFACE)
+  static const DWORD kGDIObjectsHighWaterMark = 7000;
+
+  // at 7000 GDI objects, stop allocating normal images to make sure
+  // we never hit the 10k hard limit.
+  // GetCurrentProcess() just returns (HANDLE)-1, it's inlined afaik
+  DWORD count = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
+  if (count == 0 ||
+      count > kGDIObjectsHighWaterMark)
+  {
+    // either something's broken (count == 0),
+    // or we hit our high water mark; disable
+    // image allocations for a bit.
+    return PR_TRUE;
+  }
+#endif
+
+  return PR_FALSE;
+}
+
+imgFrame::imgFrame() :
+  mDecoded(0, 0, 0, 0),
+  mPalettedImageData(nsnull),
+  mSinglePixelColor(0),
   mTimeout(100),
   mDisposalMethod(0), /* imgIContainer::kDisposeNotSpecified */
   mBlendMethod(1), /* imgIContainer::kBlendOver */
-  mInitialized(PR_FALSE),
-  mMutable(PR_TRUE)
+  mSinglePixel(PR_FALSE),
+  mNeverUseDeviceSurface(PR_FALSE),
+  mFormatChanged(PR_FALSE)
+#ifdef USE_WIN_SURFACE
+  , mIsDDBSurface(PR_FALSE)
+#endif
 {
-  /* member initializers and constructor code */
+  static PRBool hasCheckedOptimize = PR_FALSE;
+  if (!hasCheckedOptimize) {
+    if (PR_GetEnv("MOZ_DISABLE_IMAGE_OPTIMIZE")) {
+      gDisableOptimize = PR_TRUE;
+    }
+    hasCheckedOptimize = PR_TRUE;
+  }
 }
 
-gfxImageFrame::~gfxImageFrame()
+imgFrame::~imgFrame()
 {
-  /* destructor code */
-  PR_FREEIF(mImageData);
-  mInitialized = PR_FALSE;
+  PR_FREEIF(mPalettedImageData);
+#ifdef USE_WIN_SURFACE
+  if (mIsDDBSurface) {
+      gTotalDDBs--;
+      gTotalDDBSize -= mSize.width * mSize.height * 4;
+  }
+#endif
 }
 
-/* void init (in PRInt32 aX, in PRInt32 aY, in PRInt32 aWidth, in PRInt32 aHeight, in gfx_format aFormat); */
-NS_IMETHODIMP gfxImageFrame::Init(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, gfx_format aFormat,gfx_depth aDepth)
+nsresult imgFrame::Init(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, 
+                        gfxASurface::gfxImageFormat aFormat, PRInt8 aPaletteDepth /* = 0 */)
 {
-  if (mInitialized)
+  // assert for properties that should be verified by decoders, warn for properties related to bad content
+  if (!AllowedImageSize(aWidth, aHeight))
     return NS_ERROR_FAILURE;
 
-  // assert for properties that should be verified by decoders, warn for properties related to bad content
-  
-  if (aWidth <= 0 || aHeight <= 0) {
-    NS_ASSERTION(0, "error - negative image size\n");
-    return NS_ERROR_FAILURE;
-  }
+  // Check to see if we are running OOM
+  nsCOMPtr<nsIMemory> mem;
+  NS_GetMemoryManager(getter_AddRefs(mem));
+  if (!mem)
+    return NS_ERROR_UNEXPECTED;
 
-  /* check to make sure we don't overflow a 32-bit */
-  PRInt32 tmp = aWidth * aHeight;
-  if (tmp / aHeight != aWidth) {
-    NS_WARNING("width or height too large");
-    return NS_ERROR_FAILURE;
-  }
-  tmp = tmp * 4;
-  if (tmp / 4 != aWidth * aHeight) {
-    NS_WARNING("width or height too large");
-    return NS_ERROR_FAILURE;
-  }
-
-  /* reject over-wide or over-tall images */
-  const PRInt32 k64KLimit = 0x0000FFFF;
-  if ( aWidth > k64KLimit || aHeight > k64KLimit ){
-    NS_WARNING("image too big");
-    return NS_ERROR_FAILURE;
-  }
-  
-#if defined(XP_MACOSX)
-  // CoreGraphics is limited to images < 32K in *height*, so clamp all surfaces on the Mac to that height
-  if (aHeight > SHRT_MAX) {
-    NS_WARNING("image too big");
-    return NS_ERROR_FAILURE;
-  }
-#endif
+  PRBool lowMemory;
+  mem->IsLowMemory(&lowMemory);
+  if (lowMemory)
+    return NS_ERROR_OUT_OF_MEMORY;
 
   mOffset.MoveTo(aX, aY);
   mSize.SizeTo(aWidth, aHeight);
 
   mFormat = aFormat;
-  mDepth = aDepth;
-
-  PRBool needImage = PR_TRUE;
-  nsMaskRequirements maskReq;
-
-  switch (aFormat) {
-  case gfxIFormats::BGR:
-  case gfxIFormats::RGB:
-    maskReq = nsMaskRequirements_kNoMask;
-    break;
-
-  case gfxIFormats::BGRA:
-  case gfxIFormats::RGBA:
-    maskReq = nsMaskRequirements_kNeeds8Bit;
-    break;
+  mPaletteDepth = aPaletteDepth;
 
-  case gfxIFormats::BGR_A1:
-  case gfxIFormats::RGB_A1:
-    maskReq = nsMaskRequirements_kNeeds1Bit;
-    break;
-
-  case gfxIFormats::BGR_A8:
-  case gfxIFormats::RGB_A8:
-    maskReq = nsMaskRequirements_kNeeds8Bit;
-    break;
-
-  case gfxIFormats::PAL:
-  case gfxIFormats::PAL_A1:
-    needImage = PR_FALSE;
-    break;
-
-  default:
-    NS_ERROR("unsupported gfx_format\n");
-    return NS_ERROR_FAILURE;
-  }
-
-  if (needImage) {
-    if (aDepth != 24) {
-      NS_ERROR("This Depth is not supported");
+  if (aPaletteDepth != 0) {
+    // We're creating for a paletted image.
+    if (aPaletteDepth > 8) {
+      NS_ERROR("This Depth is not supported\n");
       return NS_ERROR_FAILURE;
     }
 
-    nsresult rv;
-    mImage = do_CreateInstance("@mozilla.org/gfx/image;1", &rv);
-    NS_ASSERTION(mImage, "creation of image failed");
-    if (NS_FAILED(rv)) return rv;
-  
-    rv = mImage->Init(aWidth, aHeight, aDepth, maskReq);
-    NS_ENSURE_SUCCESS(rv, rv);
+    mPalettedImageData = (PRUint8*)PR_MALLOC(PaletteDataLength() + GetImageDataLength());
+    NS_ENSURE_TRUE(mPalettedImageData, NS_ERROR_OUT_OF_MEMORY);
   } else {
-    if ((aDepth < 1) || (aDepth > 8)) {
-      NS_ERROR("This Depth is not supported\n");
-      return NS_ERROR_FAILURE;
+    // For Windows, we must create the device surface first (if we're
+    // going to) so that the image surface can wrap it.  Can't be done
+    // the other way around.
+#ifdef USE_WIN_SURFACE
+    if (!mNeverUseDeviceSurface && !ShouldUseImageSurfaces()) {
+      mWinSurface = new gfxWindowsSurface(gfxIntSize(mSize.width, mSize.height), mFormat);
+      if (mWinSurface && mWinSurface->CairoStatus() == 0) {
+        // no error
+        mImageSurface = mWinSurface->GetImageSurface();
+      } else {
+        mWinSurface = nsnull;
+      }
     }
-    mImageData = (PRUint8*)PR_MALLOC(PaletteDataLength() + ImageDataLength());
-    NS_ENSURE_TRUE(mImageData, NS_ERROR_OUT_OF_MEMORY);
+#endif
+
+    // For other platforms we create the image surface first and then
+    // possibly wrap it in a device surface.  This branch is also used
+    // on Windows if we're not using device surfaces or if we couldn't
+    // create one.
+    if (!mImageSurface)
+      mImageSurface = new gfxImageSurface(gfxIntSize(mSize.width, mSize.height), mFormat);
+
+    if (!mImageSurface || mImageSurface->CairoStatus()) {
+      mImageSurface = nsnull;
+      // guess
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+#ifdef XP_MACOSX
+    if (!mNeverUseDeviceSurface && !ShouldUseImageSurfaces()) {
+      mQuartzSurface = new gfxQuartzImageSurface(mImageSurface);
+    }
+#endif
   }
 
-  mInitialized = PR_TRUE;
   return NS_OK;
 }
 
+nsresult imgFrame::Optimize()
+{
+  if (gDisableOptimize)
+    return NS_OK;
 
-/* attribute boolean mutable */
-NS_IMETHODIMP gfxImageFrame::GetMutable(PRBool *aMutable)
-{
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
+  if (mPalettedImageData || mOptSurface || mSinglePixel)
+    return NS_OK;
+
+  /* Figure out if the entire image is a constant color */
+
+  // this should always be true
+  if (mImageSurface->Stride() == mSize.width * 4) {
+    PRUint32 *imgData = (PRUint32*) mImageSurface->Data();
+    PRUint32 firstPixel = * (PRUint32*) imgData;
+    PRUint32 pixelCount = mSize.width * mSize.height + 1;
+
+    while (--pixelCount && *imgData++ == firstPixel)
+      ;
+
+    if (pixelCount == 0) {
+      // all pixels were the same
+      if (mFormat == gfxASurface::ImageFormatARGB32 ||
+          mFormat == gfxASurface::ImageFormatRGB24)
+      {
+        mSinglePixelColor = gfxRGBA
+          (firstPixel,
+           (mFormat == gfxImageSurface::ImageFormatRGB24 ?
+            gfxRGBA::PACKED_XRGB :
+            gfxRGBA::PACKED_ARGB_PREMULTIPLIED));
+
+        mSinglePixel = PR_TRUE;
+
+        // blow away the older surfaces (if they exist), to release their memory
+        mImageSurface = nsnull;
+        mOptSurface = nsnull;
+#ifdef USE_WIN_SURFACE
+        mWinSurface = nsnull;
+#endif
+#ifdef XP_MACOSX
+        mQuartzSurface = nsnull;
+#endif
+        return NS_OK;
+      }
+    }
+
+    // if it's not RGB24/ARGB32, don't optimize, but we never hit this at the moment
+  }
+
+  // if we're being forced to use image surfaces due to
+  // resource constraints, don't try to optimize beyond same-pixel.
+  if (mNeverUseDeviceSurface || ShouldUseImageSurfaces())
+    return NS_OK;
+
+  mOptSurface = nsnull;
 
-  NS_ASSERTION(mInitialized, "gfxImageFrame::GetMutable called on non-inited gfxImageFrame");
-  *aMutable = mMutable;
-  return NS_OK;
-}
+#ifdef USE_WIN_SURFACE
+  // we need to special-case windows here, because windows has
+  // a distinction between DIB and DDB and we want to use DDBs as much
+  // as we can.
+  if (mWinSurface) {
+    // Don't do DDBs for large images; see bug 359147
+    // Note that we bother with DDBs at all because they are much faster
+    // on some systems; on others there isn't much of a speed difference
+    // between DIBs and DDBs.
+    //
+    // Originally this just limited to 1024x1024; but that still
+    // had us hitting overall total memory usage limits (which was
+    // around 220MB on my intel shared memory system with 2GB RAM
+    // and 16-128mb in use by the video card, so I can't make
+    // heads or tails out of this limit).
+    //
+    // So instead, we clamp the max size to 64MB (this limit shuld
+    // be made dynamic based on.. something.. as soon a we figure
+    // out that something) and also limit each individual image to
+    // be less than 4MB to keep very large images out of DDBs.
 
-NS_IMETHODIMP gfxImageFrame::SetMutable(PRBool aMutable)
-{
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
+    // assume (almost -- we don't quadword-align) worst-case size
+    PRUint32 ddbSize = mSize.width * mSize.height * 4;
+    if (ddbSize <= kMaxSingleDDBSize &&
+        ddbSize + gTotalDDBSize <= kMaxDDBSize)
+    {
+      nsRefPtr<gfxWindowsSurface> wsurf = mWinSurface->OptimizeToDDB(nsnull, gfxIntSize(mSize.width, mSize.height), mFormat);
+      if (wsurf) {
+        gTotalDDBs++;
+        gTotalDDBSize += ddbSize;
+        mIsDDBSurface = PR_TRUE;
+        mOptSurface = wsurf;
+      }
+    }
+    if (!mOptSurface && !mFormatChanged) {
+      // just use the DIB if the format has not changed
+      mOptSurface = mWinSurface;
+    }
+  }
+#endif
 
-  mMutable = aMutable;
+#ifdef XP_MACOSX
+  if (mQuartzSurface) {
+    mQuartzSurface->Flush();
+    mOptSurface = mQuartzSurface;
+  }
+#endif
+
+  if (mOptSurface == nsnull)
+    mOptSurface = gfxPlatform::GetPlatform()->OptimizeImage(mImageSurface, mFormat);
 
-  if (!aMutable && mImage)
-    mImage->Optimize(nsnull);
+  if (mOptSurface) {
+    mImageSurface = nsnull;
+#ifdef USE_WIN_SURFACE
+    mWinSurface = nsnull;
+#endif
+#ifdef XP_MACOSX
+    mQuartzSurface = nsnull;
+#endif
+  }
 
   return NS_OK;
 }
 
-/* readonly attribute PRInt32 x; */
-NS_IMETHODIMP gfxImageFrame::GetX(PRInt32 *aX)
+static PRBool                                                                                                       
+IsSafeImageTransformComponent(gfxFloat aValue)
 {
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
-
-  *aX = mOffset.x;
-  return NS_OK;
-}
-
-/* readonly attribute PRInt32 y; */
-NS_IMETHODIMP gfxImageFrame::GetY(PRInt32 *aY)
-{
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
-
-  *aY = mOffset.y;
-  return NS_OK;
+  return aValue >= -32768 && aValue <= 32767;
 }
 
-
-/* readonly attribute PRInt32 width; */
-NS_IMETHODIMP gfxImageFrame::GetWidth(PRInt32 *aWidth)
+void imgFrame::Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter,
+                    const gfxMatrix &aUserSpaceToImageSpace, const gfxRect& aFill,
+                    const nsIntMargin &aPadding, const nsIntRect &aSubimage)
 {
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
+  NS_ASSERTION(!aFill.IsEmpty(), "zero dest size --- fix caller");
+  NS_ASSERTION(!aSubimage.IsEmpty(), "zero source size --- fix caller");
+  NS_ASSERTION(!mPalettedImageData, "Directly drawing a paletted image!");
+
+  PRBool doPadding = aPadding != nsIntMargin(0,0,0,0);
+  PRBool doPartialDecode = !ImageComplete();
+  gfxContext::GraphicsOperator op = aContext->CurrentOperator();
+
+  if (mSinglePixel && !doPadding && ImageComplete()) {
+    // Single-color fast path
+    // if a == 0, it's a noop
+    if (mSinglePixelColor.a == 0.0)
+      return;
+
+    if (op == gfxContext::OPERATOR_OVER && mSinglePixelColor.a == 1.0)
+      aContext->SetOperator(gfxContext::OPERATOR_SOURCE);
+
+    aContext->SetDeviceColor(mSinglePixelColor);
+    aContext->NewPath();
+    aContext->Rectangle(aFill);
+    aContext->Fill();
+    aContext->SetOperator(op);
+    aContext->SetDeviceColor(gfxRGBA(0,0,0,0));
+    return;
+  }
+
+  gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace;
+  gfxRect sourceRect = userSpaceToImageSpace.Transform(aFill);
+  gfxRect imageRect(0, 0, mSize.width + aPadding.LeftRight(), mSize.height + aPadding.TopBottom());
+  gfxRect subimage(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height);
+  gfxRect fill = aFill;
+  nsRefPtr<gfxASurface> surface;
+  gfxImageSurface::gfxImageFormat format;
+
+  NS_ASSERTION(!sourceRect.Intersect(subimage).IsEmpty(),
+               "We must be allowed to sample *some* source pixels!");
+
+  PRBool doTile = !imageRect.Contains(sourceRect);
+  if (doPadding || doPartialDecode) {
+    gfxRect available = gfxRect(mDecoded.x, mDecoded.y, mDecoded.width, mDecoded.height) +
+      gfxPoint(aPadding.left, aPadding.top);
+
+    if (!doTile && !mSinglePixel) {
+      // Not tiling, and we have a surface, so we can account for
+      // padding and/or a partial decode just by twiddling parameters.
+      // First, update our user-space fill rect.
+      sourceRect = sourceRect.Intersect(available);
+      gfxMatrix imageSpaceToUserSpace = userSpaceToImageSpace;
+      imageSpaceToUserSpace.Invert();
+      fill = imageSpaceToUserSpace.Transform(sourceRect);
+
+      surface = ThebesSurface();
+      format = mFormat;
+      subimage = subimage.Intersect(available) - gfxPoint(aPadding.left, aPadding.top);
+      userSpaceToImageSpace.Multiply(gfxMatrix().Translate(-gfxPoint(aPadding.left, aPadding.top)));
+      sourceRect = sourceRect - gfxPoint(aPadding.left, aPadding.top);
+      imageRect = gfxRect(0, 0, mSize.width, mSize.height);
+    } else {
+      // Create a temporary surface
+      gfxIntSize size(PRInt32(imageRect.Width()), PRInt32(imageRect.Height()));
+      // Give this surface an alpha channel because there are
+      // transparent pixels in the padding or undecoded area
+      format = gfxASurface::ImageFormatARGB32;
+      surface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, format);
+      if (!surface || surface->CairoStatus() != 0)
+        return;
+
+      // Fill 'available' with whatever we've got
+      gfxContext tmpCtx(surface);
+      tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE);
+      if (mSinglePixel) {
+        tmpCtx.SetDeviceColor(mSinglePixelColor);
+      } else {
+        tmpCtx.SetSource(ThebesSurface(), gfxPoint(aPadding.left, aPadding.top));
+      }
+      tmpCtx.Rectangle(available);
+      tmpCtx.Fill();
+    }
+  } else {
+    NS_ASSERTION(!mSinglePixel, "This should already have been handled");
+    surface = ThebesSurface();
+    format = mFormat;
+  }
+  // At this point, we've taken care of mSinglePixel images, images with
+  // aPadding, and partially-decoded images.
+
+  if (!AllowedImageSize(fill.size.width + 1, fill.size.height + 1)) {
+    NS_WARNING("Destination area too large, bailing out");
+    return;
+  }
+
+  // Compute device-space-to-image-space transform. We need to sanity-
+  // check it to work around a pixman bug :-(
+  // XXX should we only do this for certain surface types?
+  gfxFloat deviceX, deviceY;
+  nsRefPtr<gfxASurface> currentTarget =
+    aContext->CurrentSurface(&deviceX, &deviceY);
+  gfxMatrix currentMatrix = aContext->CurrentMatrix();
+  gfxMatrix deviceToUser = currentMatrix;
+  deviceToUser.Invert();
+  deviceToUser.Translate(-gfxPoint(-deviceX, -deviceY));
+  gfxMatrix deviceToImage = deviceToUser;
+  deviceToImage.Multiply(userSpaceToImageSpace);
+
+  PRBool pushedGroup = PR_FALSE;
+  if (currentTarget->GetType() != gfxASurface::SurfaceTypeQuartz) {
+    // BEGIN working around cairo/pixman bug (bug 364968)
+    // Quartz's limits for matrix are much larger than pixman
+      
+    // Our device-space-to-image-space transform may not be acceptable to pixman.
+    if (!IsSafeImageTransformComponent(deviceToImage.xx) ||
+        !IsSafeImageTransformComponent(deviceToImage.xy) ||
+        !IsSafeImageTransformComponent(deviceToImage.yx) ||
+        !IsSafeImageTransformComponent(deviceToImage.yy)) {
+      NS_WARNING("Scaling up too much, bailing out");
+      return;
+    }
+
+    if (!IsSafeImageTransformComponent(deviceToImage.x0) ||
+        !IsSafeImageTransformComponent(deviceToImage.y0)) {
+      // We'll push a group, which will hopefully reduce our transform's
+      // translation so it's in bounds
+      aContext->Save();
+
+      // Clip the rounded-out-to-device-pixels bounds of the
+      // transformed fill area. This is the area for the group we
+      // want to push.
+      aContext->IdentityMatrix();
+      gfxRect bounds = currentMatrix.TransformBounds(fill);
+      bounds.RoundOut();
+      aContext->Clip(bounds);
+      aContext->SetMatrix(currentMatrix);
 
-  *aWidth = mSize.width;
-  return NS_OK;
+      aContext->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
+      aContext->SetOperator(gfxContext::OPERATOR_OVER);
+      pushedGroup = PR_TRUE;
+    }
+    // END working around cairo/pixman bug (bug 364968)
+  }
+
+  nsRefPtr<gfxPattern> pattern = new gfxPattern(surface);
+  pattern->SetMatrix(userSpaceToImageSpace);
+
+  // OK now, the hard part left is to account for the subimage sampling
+  // restriction. If all the transforms involved are just integer
+  // translations, then we assume no resampling will occur so there's
+  // nothing to do.
+  // XXX if only we had source-clipping in cairo!
+  if (!currentMatrix.HasNonIntegerTranslation() &&
+      !userSpaceToImageSpace.HasNonIntegerTranslation()) {
+    if (doTile) {
+      pattern->SetExtend(gfxPattern::EXTEND_REPEAT);
+    }
+  } else {
+    if (doTile || !subimage.Contains(imageRect)) {
+      // EXTEND_PAD won't help us here; we have to create a temporary
+      // surface to hold the subimage of pixels we're allowed to
+      // sample
+
+      gfxRect userSpaceClipExtents = aContext->GetClipExtents();
+      // This isn't optimal --- if aContext has a rotation then GetClipExtents
+      // will have to do a bounding-box computation, and TransformBounds might
+      // too, so we could get a better result if we computed image space clip
+      // extents in one go --- but it doesn't really matter and this is easier
+      // to understand.
+      gfxRect imageSpaceClipExtents = userSpaceToImageSpace.TransformBounds(userSpaceClipExtents);
+      // Inflate by one pixel because bilinear filtering will sample at most
+      // one pixel beyond the computed image pixel coordinate.
+      imageSpaceClipExtents.Outset(1.0);
+
+      gfxRect needed = imageSpaceClipExtents.Intersect(sourceRect).Intersect(subimage);
+      needed.RoundOut();
+
+      // if 'needed' is empty, nothing will be drawn since aFill
+      // must be entirely outside the clip region, so it doesn't
+      // matter what we do here, but we should avoid trying to
+      // create a zero-size surface.
+      if (!needed.IsEmpty()) {
+        gfxIntSize size(PRInt32(needed.Width()), PRInt32(needed.Height()));
+        nsRefPtr<gfxASurface> temp =
+          gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, format);
+        if (temp && temp->CairoStatus() == 0) {
+          gfxContext tmpCtx(temp);
+          tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE);
+          nsRefPtr<gfxPattern> tmpPattern = new gfxPattern(surface);
+          if (tmpPattern) {
+            tmpPattern->SetExtend(gfxPattern::EXTEND_REPEAT);
+            tmpPattern->SetMatrix(gfxMatrix().Translate(needed.pos));
+            tmpCtx.SetPattern(tmpPattern);
+            tmpCtx.Paint();
+            tmpPattern = new gfxPattern(temp);
+            if (tmpPattern) {
+              pattern.swap(tmpPattern);
+              pattern->SetMatrix(
+                  gfxMatrix(userSpaceToImageSpace).Multiply(gfxMatrix().Translate(-needed.pos)));
+            }
+          }
+        }
+      }
+    }
+
+    // In theory we can handle this using cairo's EXTEND_PAD,
+    // but implementation limitations mean we have to consult
+    // the surface type.
+    switch (currentTarget->GetType()) {
+      case gfxASurface::SurfaceTypeXlib:
+      case gfxASurface::SurfaceTypeXcb:
+      {
+        // See bug 324698.  This is a workaround for EXTEND_PAD not being
+        // implemented correctly on linux in the X server.
+        //
+        // Set the filter to CAIRO_FILTER_FAST --- otherwise,
+        // pixman's sampling will sample transparency for the outside edges and we'll
+        // get blurry edges.  CAIRO_EXTEND_PAD would also work here, if
+        // available
+        //
+        // But don't do this for simple downscales because it's horrible.
+        // Downscaling means that device-space coordinates are
+        // scaled *up* to find the image pixel coordinates.
+        //
+        // deviceToImage is slightly stale because up above we may
+        // have adjusted the pattern's matrix ... but the adjustment
+        // is only a translation so the scale factors in deviceToImage
+        // are still valid.
+        PRBool isDownscale =
+          deviceToImage.xx >= 1.0 && deviceToImage.yy >= 1.0 &&
+          deviceToImage.xy == 0.0 && deviceToImage.yx == 0.0;
+        if (!isDownscale) {
+          pattern->SetFilter(gfxPattern::FILTER_FAST);
+        }
+        break;
+      }
+
+      case gfxASurface::SurfaceTypeQuartz:
+      case gfxASurface::SurfaceTypeQuartzImage:
+        // Don't set EXTEND_PAD, Mac seems to be OK. Really?
+        pattern->SetFilter(aFilter);
+        break;
+
+      default:
+        // turn on EXTEND_PAD.
+        // This is what we really want for all surface types, if the
+        // implementation was universally good.
+        pattern->SetExtend(gfxPattern::EXTEND_PAD);
+        pattern->SetFilter(aFilter);
+        break;
+    }
+  }
+
+  if ((op == gfxContext::OPERATOR_OVER || pushedGroup) &&
+      format == gfxASurface::ImageFormatRGB24) {
+    aContext->SetOperator(gfxContext::OPERATOR_SOURCE);
+  }
+
+  // Phew! Now we can actually draw this image
+  aContext->NewPath();
+#ifdef MOZ_GFX_OPTIMIZE_MOBILE
+  pattern->SetFilter(gfxPattern::FILTER_FAST); 
+#endif
+  aContext->SetPattern(pattern);
+  aContext->Rectangle(fill);
+  aContext->Fill();
+
+  aContext->SetOperator(op);
+  if (pushedGroup) {
+    aContext->PopGroupToSource();
+    aContext->Paint();
+    aContext->Restore();
+  }
 }
 
-/* readonly attribute PRInt32 height; */
-NS_IMETHODIMP gfxImageFrame::GetHeight(PRInt32 *aHeight)
+nsresult imgFrame::Extract(const nsIntRect& aRegion, imgFrame** aResult)
 {
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
+  nsAutoPtr<imgFrame> subImage(new imgFrame());
+  if (!subImage)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  // The scaling problems described in bug 468496 are especially
+  // likely to be visible for the sub-image, as at present the only
+  // user is the border-image code and border-images tend to get
+  // stretched a lot.  At the same time, the performance concerns
+  // that prevent us from just using Cairo's fallback scaler when
+  // accelerated graphics won't cut it are less relevant to such
+  // images, since they also tend to be small.  Thus, we forcibly
+  // disable the use of anything other than a client-side image
+  // surface for the sub-image; this ensures that the correct
+  // (albeit slower) Cairo fallback scaler will be used.
+  subImage->mNeverUseDeviceSurface = PR_TRUE;
+
+  nsresult rv = subImage->Init(0, 0, aRegion.width, aRegion.height, 
+                               mFormat, mPaletteDepth);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  *aHeight = mSize.height;
-  return NS_OK;
-}
+  // scope to destroy ctx
+  {
+    gfxContext ctx(subImage->ThebesSurface());
+    ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
+    if (mSinglePixel) {
+      ctx.SetDeviceColor(mSinglePixelColor);
+    } else {
+      // SetSource() places point (0,0) of its first argument at
+      // the coordinages given by its second argument.  We want
+      // (x,y) of the image to be (0,0) of source space, so we
+      // put (0,0) of the image at (-x,-y).
+      ctx.SetSource(this->ThebesSurface(), gfxPoint(-aRegion.x, -aRegion.y));
+    }
+    ctx.Rectangle(gfxRect(0, 0, aRegion.width, aRegion.height));
+    ctx.Fill();
+  }
 
-/* void getRect(in nsRectRef rect); */
-NS_IMETHODIMP gfxImageFrame::GetRect(nsIntRect &aRect)
-{
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
+  nsIntRect filled(0, 0, aRegion.width, aRegion.height);
 
-  aRect.SetRect(mOffset.x, mOffset.y, mSize.width, mSize.height);
+  rv = subImage->ImageUpdated(filled);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  subImage->Optimize();
+
+  *aResult = subImage.forget();
 
   return NS_OK;
 }
 
-/* readonly attribute gfx_format format; */
-NS_IMETHODIMP gfxImageFrame::GetFormat(gfx_format *aFormat)
+nsresult imgFrame::ImageUpdated(const nsIntRect &aUpdateRect)
 {
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
-
-  *aFormat = mFormat;
-  return NS_OK;
-}
+  // Check to see if we are running OOM
+  nsCOMPtr<nsIMemory> mem;
+  NS_GetMemoryManager(getter_AddRefs(mem));
+  if (!mem)
+    return NS_ERROR_UNEXPECTED;
 
-/* readonly attribute boolean needsBackground; */
-NS_IMETHODIMP gfxImageFrame::GetNeedsBackground(PRBool *aNeedsBackground)
-{
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
+  PRBool lowMemory;
+  mem->IsLowMemory(&lowMemory);
+  if (lowMemory)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  mDecoded.UnionRect(mDecoded, aUpdateRect);
 
-  *aNeedsBackground = (mFormat != gfxIFormats::RGB && 
-                       mFormat != gfxIFormats::PAL &&
-                       mFormat != gfxIFormats::BGR) ||
-                      !mImage->GetIsImageComplete();
+  // clamp to bounds, in case someone sends a bogus updateRect (I'm looking at
+  // you, gif decoder)
+  nsIntRect boundsRect(0, 0, mSize.width, mSize.height);
+  mDecoded.IntersectRect(mDecoded, boundsRect);
+
+#ifdef XP_MACOSX
+  if (mQuartzSurface)
+    mQuartzSurface->Flush();
+#endif
   return NS_OK;
 }
 
+PRInt32 imgFrame::GetX() const
+{
+  return mOffset.x;
+}
 
-/* readonly attribute unsigned long imageBytesPerRow; */
-NS_IMETHODIMP gfxImageFrame::GetImageBytesPerRow(PRUint32 *aBytesPerRow)
+PRInt32 imgFrame::GetY() const
+{
+  return mOffset.y;
+}
+
+PRInt32 imgFrame::GetWidth() const
+{
+  return mSize.width;
+}
+
+PRInt32 imgFrame::GetHeight() const
+{
+  return mSize.height;
+}
+
+nsIntRect imgFrame::GetRect() const
 {
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
+  return nsIntRect(mOffset, mSize);
+}
+
+gfxASurface::gfxImageFormat imgFrame::GetFormat() const
+{
+  return mFormat;
+}
+
+PRBool imgFrame::GetNeedsBackground() const
+{
+  // We need a background painted if we have alpha or we're incomplete.
+  return (mFormat == gfxASurface::ImageFormatARGB32 || !ImageComplete());
+}
 
-  *aBytesPerRow = mImage ? mImage->GetLineStride(): mSize.width;
-  return NS_OK;
+PRUint32 imgFrame::GetImageBytesPerRow() const
+{
+  if (mImageSurface)
+    return mImageSurface->Stride();
+  else
+    return mSize.width;
+}
+
+PRUint32 imgFrame::GetImageDataLength() const
+{
+  if (mImageSurface)
+    return mImageSurface->Stride() * mSize.height;
+  else
+    return mSize.width * mSize.height;
 }
 
-/* readonly attribute unsigned long imageDataLength; */
-NS_IMETHODIMP gfxImageFrame::GetImageDataLength(PRUint32 *aBitsLength)
+void imgFrame::GetImageData(PRUint8 **aData, PRUint32 *length) const
 {
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
+  if (mImageSurface)
+    *aData = mImageSurface->Data();
+  else if (mPalettedImageData)
+    *aData = mPalettedImageData + PaletteDataLength();
+  else
+    *aData = nsnull;
 
-  *aBitsLength = ImageDataLength();
-  return NS_OK;
+  *length = GetImageDataLength();
+}
+
+PRBool imgFrame::GetIsPaletted() const
+{
+  return mPalettedImageData != nsnull;
+}
+
+PRBool imgFrame::GetHasAlpha() const
+{
+  return mFormat != gfxASurface::ImageFormatARGB32;
 }
 
-/* void getImageData([array, size_is(length)] out PRUint8 bits, out unsigned long length); */
-NS_IMETHODIMP gfxImageFrame::GetImageData(PRUint8 **aData, PRUint32 *length)
+void imgFrame::GetPaletteData(PRUint32 **aPalette, PRUint32 *length) const
+{
+  if (!mPalettedImageData) {
+    *aPalette = nsnull;
+    *length = 0;
+  } else {
+    *aPalette = (PRUint32 *) mPalettedImageData;
+    *length = PaletteDataLength();
+  }
+}
+
+nsresult imgFrame::LockImageData()
 {
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
+  if (mPalettedImageData)
+    return NS_OK;
+
+  if ((mOptSurface || mSinglePixel) && !mImageSurface) {
+    // Recover the pixels
+    mImageSurface = new gfxImageSurface(gfxIntSize(mSize.width, mSize.height),
+                                        gfxImageSurface::ImageFormatARGB32);
+    if (!mImageSurface || mImageSurface->CairoStatus())
+      return NS_ERROR_OUT_OF_MEMORY;
 
-  NS_ASSERTION(mMutable, "trying to get data on an immutable frame");
+    gfxContext context(mImageSurface);
+    context.SetOperator(gfxContext::OPERATOR_SOURCE);
+    if (mSinglePixel)
+      context.SetDeviceColor(mSinglePixelColor);
+    else
+      context.SetSource(mOptSurface);
+    context.Paint();
 
-  *aData = mImage ? mImage->GetBits() : (mImageData + PaletteDataLength());
-  *length = ImageDataLength();
+    mOptSurface = nsnull;
+#ifdef USE_WIN_SURFACE
+    mWinSurface = nsnull;
+#endif
+#ifdef XP_MACOSX
+    mQuartzSurface = nsnull;
+#endif
+  }
 
   return NS_OK;
 }
 
-/* void getPaletteData ([array, size_is (length)] out PRUint32 palette, out unsigned long length); */
-NS_IMETHODIMP gfxImageFrame::GetPaletteData(gfx_color **aPalette, PRUint32 *length)
+nsresult imgFrame::UnlockImageData()
 {
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
+  if (mPalettedImageData)
+    return NS_OK;
 
-  if (!mImageData)
-    return NS_ERROR_FAILURE;
-
-  *aPalette = (gfx_color*)mImageData;
-  *length = PaletteDataLength();
-
+#ifdef XP_MACOSX
+  if (mQuartzSurface)
+    mQuartzSurface->Flush();
+#endif
   return NS_OK;
 }
 
-/* void lockImageData (); */
-NS_IMETHODIMP gfxImageFrame::LockImageData()
-{
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
-
-  if (!mImage)
-    return NS_OK;
-  return mImage->LockImagePixels(PR_FALSE);
-}
-
-/* void unlockImageData (); */
-NS_IMETHODIMP gfxImageFrame::UnlockImageData()
+PRInt32 imgFrame::GetTimeout() const
 {
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
-
-  if (!mImage)
-    return NS_OK;
-  return mImage->UnlockImagePixels(PR_FALSE);
-}
-
-/* attribute long timeout; */
-NS_IMETHODIMP gfxImageFrame::GetTimeout(PRInt32 *aTimeout)
-{
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
-
   // Ensure a minimal time between updates so we don't throttle the UI thread.
   // consider 0 == unspecified and make it fast but not too fast.  See bug
   // 125137, bug 139677, and bug 207059.  The behavior of recent IE and Opera
   // versions seems to be:
   // IE 6/Win:
   //   10 - 50ms go 100ms
   //   >50ms go correct speed
   // Opera 7 final/Win:
   //   10ms goes 100ms
   //   >10ms go correct speed
   // It seems that there are broken tools out there that set a 0ms or 10ms
   // timeout when they really want a "default" one.  So munge values in that
   // range.
   if (mTimeout >= 0 && mTimeout <= 10)
-    *aTimeout = 100;
+    return 100;
   else
-    *aTimeout = mTimeout;
-
-  return NS_OK;
+    return mTimeout;
 }
 
-NS_IMETHODIMP gfxImageFrame::SetTimeout(PRInt32 aTimeout)
+void imgFrame::SetTimeout(PRInt32 aTimeout)
+{
+  mTimeout = aTimeout;
+}
+
+PRInt32 imgFrame::GetFrameDisposalMethod() const
 {
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
+  return mDisposalMethod;
+}
 
-  mTimeout = aTimeout;
-  return NS_OK;
+void imgFrame::SetFrameDisposalMethod(PRInt32 aFrameDisposalMethod)
+{
+  mDisposalMethod = aFrameDisposalMethod;
 }
 
-/* attribute long frameDisposalMethod; */
-NS_IMETHODIMP gfxImageFrame::GetFrameDisposalMethod(PRInt32 *aFrameDisposalMethod)
+PRInt32 imgFrame::GetBlendMethod() const
 {
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
+  return mBlendMethod;
+}
 
-  *aFrameDisposalMethod = mDisposalMethod;
-  return NS_OK;
-}
-NS_IMETHODIMP gfxImageFrame::SetFrameDisposalMethod(PRInt32 aFrameDisposalMethod)
+void imgFrame::SetBlendMethod(PRInt32 aBlendMethod)
 {
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
-
-  mDisposalMethod = aFrameDisposalMethod;
-  return NS_OK;
+  mBlendMethod = (PRInt8)aBlendMethod;
 }
 
-/* attribute long blendMethod; */
-NS_IMETHODIMP gfxImageFrame::GetBlendMethod(PRInt32 *aBlendMethod)
+PRBool imgFrame::ImageComplete() const
 {
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
-
-  *aBlendMethod = mBlendMethod;
-  return NS_OK;
-}
-NS_IMETHODIMP gfxImageFrame::SetBlendMethod(PRInt32 aBlendMethod)
-{
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
-
-  mBlendMethod = (PRInt8)aBlendMethod;
-  return NS_OK;
+  return mDecoded == nsIntRect(0, 0, mSize.width, mSize.height);
 }
 
-NS_IMETHODIMP gfxImageFrame::GetInterface(const nsIID & aIID, void * *result)
+// 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 imgFrame::SetHasNoAlpha()
 {
-  if (!mInitialized)
-    return NS_ERROR_NOT_INITIALIZED;
-
-  NS_ENSURE_ARG_POINTER(result);
-
-  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;
+  if (mFormat == gfxASurface::ImageFormatARGB32) {
+      mFormat = gfxASurface::ImageFormatRGB24;
+      mFormatChanged = PR_TRUE;
+  }
 }
rename from gfx/src/shared/gfxImageFrame.h
rename to modules/libpr0n/src/imgFrame.h
--- a/gfx/src/shared/gfxImageFrame.h
+++ b/modules/libpr0n/src/imgFrame.h
@@ -10,85 +10,169 @@
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is mozilla.org code.
  *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2000-2001
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
- *   Stuart Parmenter <pavlov@netscape.com>
+ *   Joe Drew <joe@drew.ca> (original author)
  *
  * Alternatively, the contents of this file may be used under the terms of
- * either of 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"),
+ * 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
  * decision by deleting the provisions above and replace them with the notice
  * 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 "gfxIImageFrame.h"
-#include "nsIInterfaceRequestor.h"
-#include "nsIInterfaceRequestorUtils.h"
+#ifndef imgFrame_h
+#define imgFrame_h
 
-#include "nsIImage.h"
-
+#include "nsRect.h"
 #include "nsPoint.h"
 #include "nsSize.h"
-
-#include "nsCOMPtr.h"
+#include "gfxTypes.h"
+#include "nsID.h"
+#include "gfxIFormats.h"
+#include "gfxContext.h"
+#include "gfxPattern.h"
+#include "gfxImageSurface.h"
+#if defined(XP_WIN)
+#include "gfxWindowsSurface.h"
+#elif defined(XP_MACOSX)
+#include "gfxQuartzImageSurface.h"
+#endif
+#include "nsAutoPtr.h"
 
-#define GFX_IMAGEFRAME_CID \
-{ /* aa699204-1dd1-11b2-84a9-a280c268e4fb */         \
-     0xaa699204,                                     \
-     0x1dd1,                                         \
-     0x11b2,                                         \
-    {0x84, 0xa9, 0xa2, 0x80, 0xc2, 0x68, 0xe4, 0xfb} \
-}
-
-class gfxImageFrame : public gfxIImageFrame,
-                      public nsIInterfaceRequestor
+class imgFrame
 {
 public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_GFXIIMAGEFRAME
-  NS_DECL_NSIINTERFACEREQUESTOR
+  imgFrame();
+  ~imgFrame();
+
+  nsresult Init(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, gfxASurface::gfxImageFormat aFormat, PRInt8 aPaletteDepth = 0);
+  nsresult Optimize();
+
+  void Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter,
+            const gfxMatrix &aUserSpaceToImageSpace, const gfxRect& aFill,
+            const nsIntMargin &aPadding, const nsIntRect &aSubimage);
+
+  nsresult Extract(const nsIntRect& aRegion, imgFrame** aResult);
+
+  nsresult ImageUpdated(const nsIntRect &aUpdateRect);
 
-  gfxImageFrame();
-  virtual ~gfxImageFrame();
+  PRInt32 GetX() const;
+  PRInt32 GetY() const;
+  PRInt32 GetWidth() const;
+  PRInt32 GetHeight() const;
+  nsIntRect GetRect() const;
+  gfxASurface::gfxImageFormat GetFormat() const;
+  PRBool GetNeedsBackground() const;
+  PRUint32 GetImageBytesPerRow() const;
+  PRUint32 GetImageDataLength() const;
+  PRBool GetIsPaletted() const;
+  PRBool GetHasAlpha() const;
+  void GetImageData(PRUint8 **aData, PRUint32 *length) const;
+  void GetPaletteData(PRUint32 **aPalette, PRUint32 *length) const;
 
-protected:
-  nsIntSize mSize;
+  PRInt32 GetTimeout() const;
+  void SetTimeout(PRInt32 aTimeout);
+
+  PRInt32 GetFrameDisposalMethod() const;
+  void SetFrameDisposalMethod(PRInt32 aFrameDisposalMethod);
+  PRInt32 GetBlendMethod() const;
+  void SetBlendMethod(PRInt32 aBlendMethod);
+  PRBool ImageComplete() const;
+
+  void SetHasNoAlpha();
+
+  nsresult LockImageData();
+  nsresult UnlockImageData();
 
-private:
-  PRUint32 PaletteDataLength() const {
-    return ((1 << mDepth) * sizeof(gfx_color));
+  nsresult GetSurface(gfxASurface **aSurface) const
+  {
+    *aSurface = ThebesSurface();
+    NS_IF_ADDREF(*aSurface);
+    return NS_OK;
+  }
+
+  nsresult GetPattern(gfxPattern **aPattern) const
+  {
+    if (mSinglePixel)
+      *aPattern = new gfxPattern(mSinglePixelColor);
+    else
+      *aPattern = new gfxPattern(ThebesSurface());
+    NS_ADDREF(*aPattern);
+    return NS_OK;
   }
 
-  PRUint32 ImageDataLength() const {
-    return (mImage ? mImage->GetLineStride() : mSize.width) * mSize.height;
+  gfxASurface* ThebesSurface() const
+  {
+    if (mOptSurface)
+      return mOptSurface;
+#if defined(XP_WIN) && !defined(WINCE)
+    if (mWinSurface)
+      return mWinSurface;
+#elif defined(XP_MACOSX)
+    if (mQuartzSurface)
+      return mQuartzSurface;
+#endif
+    return mImageSurface;
+  }
+
+
+private: // methods
+  PRUint32 PaletteDataLength() const {
+    return ((1 << mPaletteDepth) * sizeof(PRUint32));
   }
 
-  nsCOMPtr<nsIImage> mImage;
-  PRUint8*     mImageData;
+private: // data
+  nsRefPtr<gfxImageSurface> mImageSurface;
+  nsRefPtr<gfxASurface> mOptSurface;
+#if defined(XP_WIN) && !defined(WINCE)
+  nsRefPtr<gfxWindowsSurface> mWinSurface;
+#elif defined(XP_MACOSX)
+  nsRefPtr<gfxQuartzImageSurface> mQuartzSurface;
+#endif
+
+  nsIntSize    mSize;
+  nsIntPoint   mOffset;
+
+  nsIntRect    mDecoded;
+
+  // The palette and image data for images that are paletted, since Cairo
+  // doesn't support these images.
+  // The paletted data comes first, then the image data itself.
+  // Total length is PaletteDataLength() + GetImageDataLength().
+  PRUint8*     mPalettedImageData;
+
+  gfxRGBA      mSinglePixelColor;
 
   PRInt32      mTimeout; // -1 means display forever
-  nsIntPoint   mOffset;
   PRInt32      mDisposalMethod;
 
-  gfx_format   mFormat;
-  gfx_depth    mDepth;
+  gfxASurface::gfxImageFormat mFormat;
+  PRInt8       mPaletteDepth;
   PRInt8       mBlendMethod;
-  PRPackedBool mInitialized;
-  PRPackedBool mMutable;
+  PRPackedBool mSinglePixel;
+  PRPackedBool mNeverUseDeviceSurface;
+  PRPackedBool mFormatChanged;
+
+#ifdef XP_WIN
+  PRPackedBool mIsDDBSurface;
+#endif
+
 };
+
+#endif /* imgFrame_h */
--- a/modules/libpr0n/src/imgRequest.cpp
+++ b/modules/libpr0n/src/imgRequest.cpp
@@ -41,18 +41,16 @@
 
 #include "imgLoader.h"
 #include "imgRequestProxy.h"
 
 #include "imgILoader.h"
 #include "ImageErrors.h"
 #include "ImageLogging.h"
 
-#include "gfxIImageFrame.h"
-
 #include "netCore.h"
 
 #include "nsIChannel.h"
 #include "nsICachingChannel.h"
 #include "nsILoadGroup.h"
 #include "nsIInputStream.h"
 #include "nsIMultiPartChannel.h"
 #include "nsIHttpChannel.h"
@@ -264,34 +262,29 @@ nsresult imgRequest::NotifyProxyListener
     proxy->OnStartContainer(mImage);
 
   // Send frame messages (OnStartFrame, OnDataAvailable, OnStopFrame)
   PRUint32 nframes = 0;
   if (mImage)
     mImage->GetNumFrames(&nframes);
 
   if (nframes > 0) {
-    nsCOMPtr<gfxIImageFrame> frame;
-
-    // get the current frame or only frame
-    mImage->GetCurrentFrame(getter_AddRefs(frame));
-    NS_ENSURE_TRUE(frame, NS_ERROR_OUT_OF_MEMORY);
-
-    // OnStartFrame
+    PRUint32 frame;
+    mImage->GetCurrentFrameIndex(&frame);
     proxy->OnStartFrame(frame);
 
     if (!(mState & onStopContainer)) {
       // OnDataAvailable
       nsIntRect r;
-      frame->GetRect(r);  // XXX we should only send the currently decoded rectangle here.
+      mImage->GetCurrentFrameRect(r); // XXX we should only send the currently decoded rectangle here.
       proxy->OnDataAvailable(frame, &r);
     } else {
       // OnDataAvailable
       nsIntRect r;
-      frame->GetRect(r);  // We're done loading this image, send the the whole rect
+      mImage->GetCurrentFrameRect(r); // We're done loading this image, send the the whole rect
       proxy->OnDataAvailable(frame, &r);
 
       // OnStopFrame
       proxy->OnStopFrame(frame);
     }
   }
 
   // OnStopContainer
@@ -506,26 +499,25 @@ NS_IMETHODIMP imgRequest::GetIsMultiPart
 
   *aIsMultiPartChannel = mIsMultiPartChannel;
 
   return NS_OK;
 }
 
 /** imgIContainerObserver methods **/
 
-/* [noscript] void frameChanged (in imgIContainer container, in gfxIImageFrame newframe, in nsIntRect dirtyRect); */
+/* [noscript] void frameChanged (in imgIContainer container, in nsIntRect dirtyRect); */
 NS_IMETHODIMP imgRequest::FrameChanged(imgIContainer *container,
-                                       gfxIImageFrame *newframe,
                                        nsIntRect * dirtyRect)
 {
   LOG_SCOPE(gImgLog, "imgRequest::FrameChanged");
 
   nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
   while (iter.HasMore()) {
-    iter.GetNext()->FrameChanged(container, newframe, dirtyRect);
+    iter.GetNext()->FrameChanged(container, dirtyRect);
   }
 
   return NS_OK;
 }
 
 /** imgIDecoderObserver methods **/
 
 /* void onStartDecode (in imgIRequest request); */
@@ -572,61 +564,59 @@ NS_IMETHODIMP imgRequest::OnStartContain
   nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
   while (iter.HasMore()) {
     iter.GetNext()->OnStartContainer(image);
   }
 
   return NS_OK;
 }
 
-/* void onStartFrame (in imgIRequest request, in gfxIImageFrame frame); */
+/* void onStartFrame (in imgIRequest request, in unsigned long frame); */
 NS_IMETHODIMP imgRequest::OnStartFrame(imgIRequest *request,
-                                       gfxIImageFrame *frame)
+                                       PRUint32 frame)
 {
   LOG_SCOPE(gImgLog, "imgRequest::OnStartFrame");
 
   nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
   while (iter.HasMore()) {
     iter.GetNext()->OnStartFrame(frame);
   }
 
   return NS_OK;
 }
 
-/* [noscript] void onDataAvailable (in imgIRequest request, in gfxIImageFrame frame, [const] in nsIntRect rect); */
+/* [noscript] void onDataAvailable (in imgIRequest request, in boolean aCurrentFrame, [const] in nsIntRect rect); */
 NS_IMETHODIMP imgRequest::OnDataAvailable(imgIRequest *request,
-                                          gfxIImageFrame *frame,
+                                          PRBool aCurrentFrame,
                                           const nsIntRect * rect)
 {
   LOG_SCOPE(gImgLog, "imgRequest::OnDataAvailable");
 
   nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
   while (iter.HasMore()) {
-    iter.GetNext()->OnDataAvailable(frame, rect);
+    iter.GetNext()->OnDataAvailable(aCurrentFrame, rect);
   }
 
   return NS_OK;
 }
 
-/* void onStopFrame (in imgIRequest request, in gfxIImageFrame frame); */
+/* void onStopFrame (in imgIRequest request, in unsigned long frame); */
 NS_IMETHODIMP imgRequest::OnStopFrame(imgIRequest *request,
-                                      gfxIImageFrame *frame)
+                                      PRUint32 frame)
 {
-  NS_ASSERTION(frame, "imgRequest::OnStopFrame called with NULL frame");
-  if (!frame) return NS_ERROR_UNEXPECTED;
-
   LOG_SCOPE(gImgLog, "imgRequest::OnStopFrame");
 
   mImageStatus |= imgIRequest::STATUS_FRAME_COMPLETE;
 
   if (mCacheEntry) {
     PRUint32 cacheSize = mCacheEntry->GetDataSize();
 
     PRUint32 imageSize = 0;
-    frame->GetImageDataLength(&imageSize);
+    if (mImage)
+      mImage->GetFrameImageDataLength(frame, &imageSize);
 
     mCacheEntry->SetDataSize(cacheSize + imageSize);
 
 #ifdef DEBUG_joe
     nsCAutoString url;
     mURI->GetSpec(url);
 
     printf("CACHEPUT: %d %s %d\n", time(NULL), url.get(), cacheSize + imageSize);
--- a/modules/libpr0n/src/imgRequestProxy.cpp
+++ b/modules/libpr0n/src/imgRequestProxy.cpp
@@ -420,24 +420,24 @@ NS_IMETHODIMP imgRequestProxy::GetHasTra
     // The safe thing to do is to claim we have data
     *hasData = PR_TRUE;
   }
   return NS_OK;
 }
 
 /** imgIContainerObserver methods **/
 
-void imgRequestProxy::FrameChanged(imgIContainer *container, gfxIImageFrame *newframe, nsIntRect * dirtyRect)
+void imgRequestProxy::FrameChanged(imgIContainer *container, nsIntRect * dirtyRect)
 {
   LOG_FUNC(gImgLog, "imgRequestProxy::FrameChanged");
 
   if (mListener && !mCanceled) {
     // Hold a ref to the listener while we call it, just in case.
     nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
-    mListener->FrameChanged(container, newframe, dirtyRect);
+    mListener->FrameChanged(container, dirtyRect);
   }
 }
 
 /** imgIDecoderObserver methods **/
 
 void imgRequestProxy::OnStartDecode()
 {
   LOG_FUNC(gImgLog, "imgRequestProxy::OnStartDecode");
@@ -455,39 +455,39 @@ void imgRequestProxy::OnStartContainer(i
 
   if (mListener && !mCanceled) {
     // Hold a ref to the listener while we call it, just in case.
     nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
     mListener->OnStartContainer(this, image);
   }
 }
 
-void imgRequestProxy::OnStartFrame(gfxIImageFrame *frame)
+void imgRequestProxy::OnStartFrame(PRUint32 frame)
 {
   LOG_FUNC(gImgLog, "imgRequestProxy::OnStartFrame");
 
   if (mListener && !mCanceled) {
     // Hold a ref to the listener while we call it, just in case.
     nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
     mListener->OnStartFrame(this, frame);
   }
 }
 
-void imgRequestProxy::OnDataAvailable(gfxIImageFrame *frame, const nsIntRect * rect)
+void imgRequestProxy::OnDataAvailable(PRBool aCurrentFrame, const nsIntRect * rect)
 {
   LOG_FUNC(gImgLog, "imgRequestProxy::OnDataAvailable");
 
   if (mListener && !mCanceled) {
     // Hold a ref to the listener while we call it, just in case.
     nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
-    mListener->OnDataAvailable(this, frame, rect);
+    mListener->OnDataAvailable(this, aCurrentFrame, rect);
   }
 }
 
-void imgRequestProxy::OnStopFrame(gfxIImageFrame *frame)
+void imgRequestProxy::OnStopFrame(PRUint32 frame)
 {
   LOG_FUNC(gImgLog, "imgRequestProxy::OnStopFrame");
 
   if (mListener && !mCanceled) {
     // Hold a ref to the listener while we call it, just in case.
     nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
     mListener->OnStopFrame(this, frame);
   }
--- a/modules/libpr0n/src/imgRequestProxy.h
+++ b/modules/libpr0n/src/imgRequestProxy.h
@@ -106,24 +106,24 @@ protected:
       nsresult mStatus;
   };
 
 
 
   /* non-virtual imgIDecoderObserver methods */
   void OnStartDecode   ();
   void OnStartContainer(imgIContainer *aContainer);
-  void OnStartFrame    (gfxIImageFrame *aFrame);
-  void OnDataAvailable (gfxIImageFrame *aFrame, const nsIntRect * aRect);
-  void OnStopFrame     (gfxIImageFrame *aFrame);
+  void OnStartFrame    (PRUint32 aFrame);
+  void OnDataAvailable (PRBool aCurrentFrame, const nsIntRect * aRect);
+  void OnStopFrame     (PRUint32 aFrame);
   void OnStopContainer (imgIContainer *aContainer);
   void OnStopDecode    (nsresult status, const PRUnichar *statusArg); 
 
   /* non-virtual imgIContainerObserver methods */
-  void FrameChanged(imgIContainer *aContainer, gfxIImageFrame *aFrame, nsIntRect * aDirtyRect);
+  void FrameChanged(imgIContainer *aContainer, nsIntRect * aDirtyRect);
 
   /* non-virtual nsIRequestObserver (plus some) methods */
   void OnStartRequest(nsIRequest *request, nsISupports *ctxt);
   void OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult statusCode, PRBool aLastPart); 
 
   inline PRBool HasObserver() const {
     return mListener != nsnull;
   }
--- a/modules/libpr0n/src/imgTools.cpp
+++ b/modules/libpr0n/src/imgTools.cpp
@@ -41,19 +41,16 @@
 #include "nsString.h"
 #include "ImageErrors.h"
 #include "imgIContainer.h"
 #include "imgILoad.h"
 #include "imgIDecoder.h"
 #include "imgIEncoder.h"
 #include "imgIDecoderObserver.h"
 #include "imgIContainerObserver.h"
-#include "nsIImage.h"
-#include "gfxIImageFrame.h"
-#include "gfxImageSurface.h"
 #include "gfxContext.h"
 #include "nsStringStream.h"
 #include "nsComponentManagerUtils.h"
 #include "nsWeakReference.h"
 #include "nsIInterfaceRequestorUtils.h"
 
 
 /* ========== Utility classes ========== */
@@ -124,32 +121,31 @@ NS_IMETHODIMP
 HelperLoader::OnStartContainer(imgIRequest *aRequest, imgIContainer
 *aContainer)
 {
   return NS_OK;
 }
 
 /* Implement imgIDecoderObserver::onStartFrame() */
 NS_IMETHODIMP
-HelperLoader::OnStartFrame(imgIRequest *aRequest, gfxIImageFrame *aFrame)
+HelperLoader::OnStartFrame(imgIRequest *aRequest, PRUint32 aFrame)
 {
   return NS_OK;
 }
 
 /* Implement imgIDecoderObserver::onDataAvailable() */
 NS_IMETHODIMP
-HelperLoader::OnDataAvailable(imgIRequest *aRequest, gfxIImageFrame
-*aFrame, const nsIntRect * aRect)
+HelperLoader::OnDataAvailable(imgIRequest *aRequest, PRBool aCurrentFrame, const nsIntRect * aRect)
 {
   return NS_OK;
 }
 
 /* Implement imgIDecoderObserver::onStopFrame() */
 NS_IMETHODIMP
-HelperLoader::OnStopFrame(imgIRequest *aRequest, gfxIImageFrame *aFrame)
+HelperLoader::OnStopFrame(imgIRequest *aRequest, PRUint32 aFrame)
 {
   return NS_OK;
 }
 
 /* Implement imgIDecoderObserver::onStopContainer() */
 NS_IMETHODIMP
 HelperLoader::OnStopContainer(imgIRequest *aRequest, imgIContainer
 *aContainer)
@@ -169,18 +165,17 @@ PRUnichar *statusArg)
 NS_IMETHODIMP
 HelperLoader::OnStopRequest(imgIRequest *aRequest, PRBool aIsLastPart)
 {
   return NS_OK;
 }
   
 /* implement imgIContainerObserver::frameChanged() */
 NS_IMETHODIMP
-HelperLoader::FrameChanged(imgIContainer *aContainer,
-                           gfxIImageFrame *aFrame, nsIntRect * aDirtyRect)
+HelperLoader::FrameChanged(imgIContainer *aContainer, nsIntRect * aDirtyRect)
 {
   return NS_OK;
 }
 
 
 
 /* ========== imgITools implementation ========== */
 
@@ -225,17 +220,16 @@ NS_IMETHODIMP imgTools::DecodeImageData(
   rv = decoder->Init(loader);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRUint32 length;
   rv = aInStr->Available(&length);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRUint32 written;
-  NS_ENSURE_SUCCESS(rv, rv);
   rv = decoder->WriteFrom(aInStr, length, &written);
   NS_ENSURE_SUCCESS(rv, rv);
   if (written != length)
     NS_WARNING("decoder didn't eat all of its vegetables");
   rv = decoder->Flush();
   NS_ENSURE_SUCCESS(rv, rv);
   rv = decoder->Close();
   NS_ENSURE_SUCCESS(rv, rv);
@@ -280,79 +274,67 @@ NS_IMETHODIMP imgTools::EncodeScaledImag
   nsCAutoString encoderCID(
     NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type=") + aMimeType);
 
   nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get());
   if (!encoder)
     return NS_IMAGELIB_ERROR_NO_ENCODER;
 
   // Use frame 0 from the image container.
-  nsCOMPtr<gfxIImageFrame> frame;
-  rv = aContainer->GetFrameAt(0, getter_AddRefs(frame));
+  nsRefPtr<gfxImageSurface> frame;
+  rv = aContainer->CopyCurrentFrame(getter_AddRefs(frame));
   NS_ENSURE_SUCCESS(rv, rv);
   if (!frame)
     return NS_ERROR_NOT_AVAILABLE;
 
-  PRInt32 w,h;
-  frame->GetWidth(&w);
-  frame->GetHeight(&h);
+  PRInt32 w = frame->Width(), h = frame->Height();
   if (!w || !h)
     return NS_ERROR_FAILURE;
 
-  nsCOMPtr<nsIImage> img(do_GetInterface(frame));
   nsRefPtr<gfxImageSurface> dest;
 
   if (!doScaling) {
     // If we're not scaling the image, use the actual width/height.
     aScaledWidth  = w;
     aScaledHeight = h;
 
-    img->LockImagePixels(PR_FALSE);
-    bitmapData = img->GetBits();
-    if (!bitmapData) {
-      img->UnlockImagePixels(PR_FALSE);
+    bitmapData = frame->Data();
+    if (!bitmapData)
       return NS_ERROR_FAILURE;
-    }
 
-    frame->GetImageBytesPerRow(&strideSize);
+    strideSize = frame->Stride();
     bitmapDataLength = aScaledHeight * strideSize;
 
   } else {
     // Prepare to draw a scaled version of the image to a temporary surface...
 
-    // Get the source image surface
-    nsRefPtr<gfxPattern> gfxpat;
-    img->GetPattern(getter_AddRefs(gfxpat));
-
     // Create a temporary image surface
     dest = new gfxImageSurface(gfxIntSize(aScaledWidth, aScaledHeight),
                                gfxASurface::ImageFormatARGB32);
     if (!dest)
       return NS_ERROR_OUT_OF_MEMORY;
 
     gfxContext ctx(dest);
 
     // Set scaling
     gfxFloat sw = (double) aScaledWidth / w;
     gfxFloat sh = (double) aScaledHeight / h;
     ctx.Scale(sw, sh);
 
     // Paint a scaled image
     ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
-    ctx.SetPattern(gfxpat);
+    ctx.SetSource(frame);
     ctx.Paint();
 
     bitmapData = dest->Data();
     strideSize = dest->Stride();
     bitmapDataLength = aScaledHeight * strideSize;
   }
 
   // Encode the bitmap
   rv = encoder->InitFromData(bitmapData, bitmapDataLength,
                              aScaledWidth, aScaledHeight, strideSize,
                              imgIEncoder::INPUT_FORMAT_HOSTARGB, EmptyString());
-  if (!doScaling)
-    img->UnlockImagePixels(PR_FALSE);
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   return CallQueryInterface(encoder, aStream);
 }
--- a/modules/libpr0n/test/unit/test_imgtools.js
+++ b/modules/libpr0n/test/unit/test_imgtools.js
@@ -378,29 +378,33 @@ testdesc = "test decoding bad favicon (b
 
 imgName = "bug413512.ico";
 inMimeType = "image/x-icon";
 imgFile = do_get_file(imgName);
 
 istream = getFileInputStream(imgFile);
 do_check_eq(istream.available(), 17759);
 
-// You'd think the decoder would fail, but it doesn't. The decoders use
-// stream->ReadSegments with a callback, and buffered streams ignore errors
-// from the callback. :-( See bug 413595.
-outParam = { value: null };
-imgTools.decodeImageData(istream, inMimeType, outParam);
-container = outParam.value;
+try {
+  outParam = { value: null };
+  imgTools.decodeImageData(istream, inMimeType, outParam);
+  container = outParam.value;
 
-try {
-    istream = imgTools.encodeImage(container, "image/png");
+  // We should never hit this - decodeImageData throws an assertion because the
+  // image decoded doesn't have enough frames.
+  try {
+      istream = imgTools.encodeImage(container, "image/png");
+  } catch (e) {
+      err = e;
+  }
 } catch (e) {
-    err = e;
+  err = e;
 }
-checkExpectedError(/NS_ERROR_NOT_AVAILABLE/, err);
+
+checkExpectedError(/NS_ERROR_ILLEGAL_VALUE/, err);
 
 
 /* ========== end ========== */
 
 } catch (e) {
     throw "FAILED in test #" + testnum + " -- " + testdesc + ": " + e;
 }
 };
--- a/toolkit/library/libxul-config.mk
+++ b/toolkit/library/libxul-config.mk
@@ -90,17 +90,16 @@ endif
 LOCAL_INCLUDES += -I$(topsrcdir)/widget/src/os2
 endif
 
 # dependent libraries
 STATIC_LIBS += \
 	xpcom_core \
 	ucvutil_s \
 	gkgfx \
-	gfxshared_s \
 	$(NULL)
 
 #ifndef MOZ_EMBEDDING_LEVEL_DEFAULT
 ifndef WINCE
 ifdef MOZ_XPINSTALL
 STATIC_LIBS += \
 	mozreg_s \
 	$(NULL)
--- a/toolkit/system/gnome/nsAlertsIconListener.cpp
+++ b/toolkit/system/gnome/nsAlertsIconListener.cpp
@@ -31,20 +31,19 @@
  * decision by deleting the provisions above and replace them with the notice
  * 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 "nsAlertsIconListener.h"
+#include "imgIContainer.h"
 #include "imgILoader.h"
 #include "imgIRequest.h"
-#include "gfxIImageFrame.h"
-#include "nsIImage.h"
 #include "nsNetUtil.h"
 #include "nsIImageToPixbuf.h"
 #include "nsIStringBundle.h"
 
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <libnotify/notify.h>
 #include <gdk/gdk.h>
 
@@ -101,25 +100,25 @@ nsAlertsIconListener::OnStartContainer(i
                                        imgIContainer* aContainer)
 {
   return NS_OK;
 }