Backed out 4 changesets (bug 815471, bug 821023, bug 816374, bug 816362) for reftest failures.
authorRyan VanderMeulen <ryanvm@gmail.com>
Sun, 16 Dec 2012 21:13:35 -0500
changeset 116236 47bd1f6fd8ed14f3ba6811e23c5f8463533b3e64
parent 116235 1ac4491232e58341646bb692eca957a4d6f36079
child 116237 17d7f3bbe60ea96979d9b27aadc226e6fa83d72b
push id19799
push userryanvm@gmail.com
push dateMon, 17 Dec 2012 02:14:31 +0000
treeherdermozilla-inbound@47bd1f6fd8ed [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs815471, 821023, 816374, 816362
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 4 changesets (bug 815471, bug 821023, bug 816374, bug 816362) for reftest failures.
image/build/nsImageModule.cpp
image/public/imgITools.idl
image/src/Decoder.cpp
image/src/Decoder.h
image/src/Image.cpp
image/src/Image.h
image/src/ImageFactory.cpp
image/src/ImageFactory.h
image/src/Makefile.in
image/src/RasterImage.cpp
image/src/RasterImage.h
image/src/VectorImage.cpp
image/src/VectorImage.h
image/src/imgLoader.cpp
image/src/imgRequest.cpp
image/src/imgRequest.h
image/src/imgRequestProxy.cpp
image/src/imgRequestProxy.h
image/src/imgStatusTracker.cpp
image/src/imgStatusTracker.h
image/src/imgTools.cpp
image/src/imgTools.h
image/test/unit/test_imgtools.js
--- a/image/build/nsImageModule.cpp
+++ b/image/build/nsImageModule.cpp
@@ -23,49 +23,57 @@
 #include "DiscardTracker.h"
 
 #include "nsICOEncoder.h"
 #include "nsPNGEncoder.h"
 #include "nsJPEGEncoder.h"
 #include "nsBMPEncoder.h"
 
 // objects that just require generic constructors
+namespace mozilla {
+namespace image {
+NS_GENERIC_FACTORY_CONSTRUCTOR(RasterImage)
+}
+}
 using namespace mozilla::image;
 
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(imgLoader, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(imgRequestProxy)
 NS_GENERIC_FACTORY_CONSTRUCTOR(imgTools)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsICOEncoder)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsJPEGEncoder)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsPNGEncoder)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsBMPEncoder)
 NS_DEFINE_NAMED_CID(NS_IMGLOADER_CID);
 NS_DEFINE_NAMED_CID(NS_IMGREQUESTPROXY_CID);
 NS_DEFINE_NAMED_CID(NS_IMGTOOLS_CID);
+NS_DEFINE_NAMED_CID(NS_RASTERIMAGE_CID);
 NS_DEFINE_NAMED_CID(NS_ICOENCODER_CID);
 NS_DEFINE_NAMED_CID(NS_JPEGENCODER_CID);
 NS_DEFINE_NAMED_CID(NS_PNGENCODER_CID);
 NS_DEFINE_NAMED_CID(NS_BMPENCODER_CID);
 
 static const mozilla::Module::CIDEntry kImageCIDs[] = {
   { &kNS_IMGLOADER_CID, false, NULL, imgLoaderConstructor, },
   { &kNS_IMGREQUESTPROXY_CID, false, NULL, imgRequestProxyConstructor, },
   { &kNS_IMGTOOLS_CID, false, NULL, imgToolsConstructor, },
+  { &kNS_RASTERIMAGE_CID, false, NULL, RasterImageConstructor, },
   { &kNS_ICOENCODER_CID, false, NULL, nsICOEncoderConstructor, },
   { &kNS_JPEGENCODER_CID, false, NULL, nsJPEGEncoderConstructor, },
   { &kNS_PNGENCODER_CID, false, NULL, nsPNGEncoderConstructor, },
   { &kNS_BMPENCODER_CID, false, NULL, nsBMPEncoderConstructor, },
   { NULL }
 };
 
 static const mozilla::Module::ContractIDEntry kImageContracts[] = {
   { "@mozilla.org/image/cache;1", &kNS_IMGLOADER_CID },
   { "@mozilla.org/image/loader;1", &kNS_IMGLOADER_CID },
   { "@mozilla.org/image/request;1", &kNS_IMGREQUESTPROXY_CID },
   { "@mozilla.org/image/tools;1", &kNS_IMGTOOLS_CID },
+  { "@mozilla.org/image/rasterimage;1", &kNS_RASTERIMAGE_CID },
   { "@mozilla.org/image/encoder;2?type=image/vnd.microsoft.icon", &kNS_ICOENCODER_CID },
   { "@mozilla.org/image/encoder;2?type=image/jpeg", &kNS_JPEGENCODER_CID },
   { "@mozilla.org/image/encoder;2?type=image/png", &kNS_PNGENCODER_CID },
   { "@mozilla.org/image/encoder;2?type=image/bmp", &kNS_BMPENCODER_CID },
   { NULL }
 };
 
 static const mozilla::Module::CategoryEntry kImageCategories[] = {
--- a/image/public/imgITools.idl
+++ b/image/public/imgITools.idl
@@ -9,56 +9,39 @@
 interface nsIInputStream;
 interface imgIContainer;
 interface imgILoader;
 interface imgICache;
 interface nsIDOMDocument;
 interface imgIScriptedNotificationObserver;
 interface imgINotificationObserver;
 
-[scriptable, builtinclass, uuid(4c2383a4-931c-484d-8c4a-973590f66e3f)]
+[scriptable, builtinclass, uuid(98bd5bf9-87eb-4d92-81b1-4cd10c64f7b2)]
 interface imgITools : nsISupports
 {
     /**
-     * decodeImage
-     * Caller provides an input stream and mimetype. We read from the stream
-     * and decompress it (according to the specified mime type) and return
-     * the resulting imgIContainer.
-     *
-     * @param aStream
-     *        An input stream for an encoded image file.
-     * @param aMimeType
-     *        Type of image in the stream.
-     */
-    imgIContainer decodeImage(in nsIInputStream aStream,
-                              in ACString aMimeType);
-
-    /**
      * decodeImageData
      * Caller provides an input stream and mimetype. We read from the stream
      * and decompress it (according to the specified mime type) and return
      * the resulting imgIContainer. (If the caller already has a container,
      * it can be provided as input to be reused).
      *
-     * This method is deprecated; new code should use |decodeImage|. Callers
-     * of |decodeImageData| must provide a |null| aContainer argument.
-     *
      * @param aStream
      *        An input stream for an encoded image file.
      * @param aMimeType
      *        Type of image in the stream.
      * @param aContainer
      *        An imgIContainer holding the decoded image. Specify |null| when
      *        calling to have one created, otherwise specify a container to
      *        be used. It is an error to pass an already-initialized container
      *        as aContainer.
      */
-    [deprecated] void decodeImageData(in nsIInputStream aStream,
-                                      in ACString aMimeType,
-                                      inout imgIContainer aContainer);
+    void decodeImageData(in nsIInputStream aStream,
+                         in ACString aMimeType,
+                         inout imgIContainer aContainer);
 
     /**
      * encodeImage
      * Caller provides an image container, and the mime type it should be
      * encoded to. We return an input stream for the encoded image data.
      *
      * @param aContainer
      *        An image container.
--- a/image/src/Decoder.cpp
+++ b/image/src/Decoder.cpp
@@ -19,17 +19,16 @@ Decoder::Decoder(RasterImage &aImage, im
   , mDecodeDone(false)
   , mDataError(false)
   , mFrameCount(0)
   , mFailCode(NS_OK)
   , mInitialized(false)
   , mSizeDecode(false)
   , mInFrame(false)
   , mIsAnimated(false)
-  , mFirstWrite(true)
 {
 }
 
 Decoder::~Decoder()
 {
   mInitialized = false;
 }
 
@@ -38,52 +37,45 @@ Decoder::~Decoder()
  */
 
 void
 Decoder::Init()
 {
   // No re-initializing
   NS_ABORT_IF_FALSE(!mInitialized, "Can't re-initialize a decoder!");
 
+  // Fire OnStartDecode at init time to support bug 512435
+  if (!IsSizeDecode() && mObserver)
+      mObserver->OnStartDecode();
+
   // Implementation-specific initialization
   InitInternal();
   mInitialized = true;
 }
 
 // Initializes a decoder whose aImage and aObserver is already being used by a
 // parent decoder
 void
 Decoder::InitSharedDecoder()
 {
   // No re-initializing
   NS_ABORT_IF_FALSE(!mInitialized, "Can't re-initialize a decoder!");
 
-  // Prevent duplicate notifications.
-  mFirstWrite = false;
-
   // Implementation-specific initialization
   InitInternal();
   mInitialized = true;
 }
 
 void
 Decoder::Write(const char* aBuffer, uint32_t aCount)
 {
   // We're strict about decoder errors
   NS_ABORT_IF_FALSE(!HasDecoderError(),
                     "Not allowed to make more decoder calls after error!");
 
-  // If this is our first write, fire OnStartDecode to support bug 512435.
-  if (mFirstWrite) {
-    if (!IsSizeDecode() && mObserver)
-      mObserver->OnStartDecode();
-
-    mFirstWrite = false;
-  }
-
   // If a data error occured, just ignore future data
   if (HasDataError())
     return;
 
   // Pass the data along to the implementation
   WriteInternal(aBuffer, aCount);
 }
 
--- a/image/src/Decoder.h
+++ b/image/src/Decoder.h
@@ -187,15 +187,14 @@ private:
   nsIntRect mInvalidRect; // Tracks an invalidation region in the current frame.
 
   nsresult mFailCode;
 
   bool mInitialized;
   bool mSizeDecode;
   bool mInFrame;
   bool mIsAnimated;
-  bool mFirstWrite;
 };
 
 } // namespace image
 } // namespace mozilla
 
 #endif // MOZILLA_IMAGELIB_DECODER_H_
--- a/image/src/Image.cpp
+++ b/image/src/Image.cpp
@@ -4,30 +4,29 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Image.h"
 
 namespace mozilla {
 namespace image {
 
 // Constructor
-Image::Image(imgStatusTracker* aStatusTracker, nsIURI* aURI) :
+Image::Image(imgStatusTracker* aStatusTracker) :
   mInnerWindowId(0),
-  mURI(aURI),
   mAnimationConsumers(0),
   mAnimationMode(kNormalAnimMode),
   mInitialized(false),
   mAnimating(false),
   mError(false)
 {
   if (aStatusTracker) {
     mStatusTracker = aStatusTracker;
     mStatusTracker->SetImage(this);
   } else {
-    mStatusTracker = new imgStatusTracker(this);
+    mStatusTracker = new imgStatusTracker(this, nullptr);
   }
 }
 
 uint32_t
 Image::SizeOfData()
 {
   if (mError)
     return 0;
--- a/image/src/Image.h
+++ b/image/src/Image.h
@@ -3,19 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_IMAGELIB_IMAGE_H_
 #define MOZILLA_IMAGELIB_IMAGE_H_
 
 #include "imgIContainer.h"
 #include "imgStatusTracker.h"
-#include "nsIURI.h"
-#include "nsIRequest.h"
-#include "nsIInputStream.h"
 
 namespace mozilla {
 namespace image {
 
 class Image : public imgIContainer
 {
 public:
   imgStatusTracker& GetStatusTracker() { return *mStatusTracker; }
@@ -45,16 +42,17 @@ public:
    * Creates a new image container.
    *
    * @param aObserver Observer to send decoder and animation notifications to.
    * @param aMimeType The mimetype of the image.
    * @param aFlags Initialization flags of the INIT_FLAG_* variety.
    */
   virtual nsresult Init(imgIDecoderObserver* aObserver,
                         const char* aMimeType,
+                        const char* aURIString,
                         uint32_t aFlags) = 0;
 
   /**
    * The rectangle defining the location and size of the currently displayed
    * frame.
    */
   virtual void GetCurrentFrameRect(nsIntRect& aRect) = 0;
 
@@ -85,61 +83,25 @@ public:
   static eDecoderType GetDecoderType(const char *aMimeType);
 
   void IncrementAnimationConsumers();
   void DecrementAnimationConsumers();
 #ifdef DEBUG
   uint32_t GetAnimationConsumers() { return mAnimationConsumers; }
 #endif
 
-  /**
-   * Called from OnDataAvailable when the stream associated with the image has
-   * received new image data. The arguments are the same as OnDataAvailable's,
-   * but by separating this functionality into a different method we don't
-   * interfere with subclasses which wish to implement nsIStreamListener.
-   *
-   * Images should not do anything that could send out notifications until they
-   * have received their first OnImageDataAvailable notification; in
-   * particular, this means that instantiating decoders should be deferred
-   * until OnImageDataAvailable is called.
-   */
-  virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
-                                        nsISupports* aContext,
-                                        nsIInputStream* aInStr,
-                                        uint64_t aSourceOffset,
-                                        uint32_t aCount) = 0;
-
-  /**
-   * Called from OnStopRequest when the image's underlying request completes.
-   * The arguments are the same as OnStopRequest's, but by separating this
-   * functionality into a different method we don't interfere with subclasses
-   * which wish to implement nsIStreamListener.
-   */
-  virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
-                                       nsISupports* aContext,
-                                       nsresult status) = 0;
-
-  /**
-   * Called for multipart images to allow for any necessary reinitialization
-   * when there's a new part to add.
-   */
-  virtual nsresult OnNewSourceData() = 0;
-
   void SetInnerWindowID(uint64_t aInnerWindowId) {
     mInnerWindowId = aInnerWindowId;
   }
   uint64_t InnerWindowID() const { return mInnerWindowId; }
 
-  bool HasError()    { return mError; }
-  void SetHasError() { mError = true; }
-
-  nsIURI* GetURI() { return mURI; }
+  bool HasError() { return mError; }
 
 protected:
-  Image(imgStatusTracker* aStatusTracker, nsIURI* aURI);
+  Image(imgStatusTracker* aStatusTracker);
 
   // Shared functionality for implementors of imgIContainer. Every
   // implementation of attribute animationMode should forward here.
   nsresult GetAnimationModeInternal(uint16_t *aAnimationMode);
   nsresult SetAnimationModeInternal(uint16_t aAnimationMode);
 
   /**
    * Decides whether animation should or should not be happening,
@@ -148,18 +110,17 @@ protected:
   virtual void EvaluateAnimation();
 
   virtual nsresult StartAnimation() = 0;
   virtual nsresult StopAnimation() = 0;
 
   uint64_t mInnerWindowId;
 
   // Member data shared by all implementations of this abstract class
-  nsRefPtr<imgStatusTracker>  mStatusTracker;
-  nsCOMPtr<nsIURI>            mURI;
+  nsAutoPtr<imgStatusTracker> mStatusTracker;
   uint32_t                    mAnimationConsumers;
   uint16_t                    mAnimationMode;   // Enum values in imgIContainer
   bool                        mInitialized:1;   // Have we been initalized?
   bool                        mAnimating:1;     // Are we currently animating?
   bool                        mError:1;         // Error handling
 
   /**
    * Extended by child classes, if they have additional
deleted file mode 100644
--- a/image/src/ImageFactory.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "mozilla/Preferences.h"
-#include "mozilla/Likely.h"
-
-#include "nsIHttpChannel.h"
-#include "nsSimpleURI.h"
-
-#include "RasterImage.h"
-#include "VectorImage.h"
-
-#include "ImageFactory.h"
-
-namespace mozilla {
-namespace image {
-
-const char* SVG_MIMETYPE = "image/svg+xml";
-
-// Global preferences related to image containers.
-static bool gInitializedPrefCaches = false;
-static bool gDecodeOnDraw = false;
-static bool gDiscardable = false;
-
-static void
-InitPrefCaches()
-{
-  Preferences::AddBoolVarCache(&gDiscardable, "image.mem.discardable");
-  Preferences::AddBoolVarCache(&gDecodeOnDraw, "image.mem.decodeondraw");
-  gInitializedPrefCaches = true;
-}
-
-static uint32_t
-ComputeImageFlags(nsIURI* uri, bool isMultiPart)
-{
-  nsresult rv;
-
-  // We default to the static globals
-  bool isDiscardable = gDiscardable;
-  bool doDecodeOnDraw = gDecodeOnDraw;
-
-  // We want UI to be as snappy as possible and not to flicker. Disable discarding
-  // and decode-on-draw for chrome URLS
-  bool isChrome = false;
-  rv = uri->SchemeIs("chrome", &isChrome);
-  if (NS_SUCCEEDED(rv) && isChrome)
-    isDiscardable = doDecodeOnDraw = false;
-
-  // We don't want resources like the "loading" icon to be discardable or
-  // decode-on-draw either.
-  bool isResource = false;
-  rv = uri->SchemeIs("resource", &isResource);
-  if (NS_SUCCEEDED(rv) && isResource)
-    isDiscardable = doDecodeOnDraw = false;
-
-  // For multipart/x-mixed-replace, we basically want a direct channel to the
-  // decoder. Disable both for this case as well.
-  if (isMultiPart)
-    isDiscardable = doDecodeOnDraw = false;
-
-  // We have all the information we need
-  uint32_t imageFlags = Image::INIT_FLAG_NONE;
-  if (isDiscardable)
-    imageFlags |= Image::INIT_FLAG_DISCARDABLE;
-  if (doDecodeOnDraw)
-    imageFlags |= Image::INIT_FLAG_DECODE_ON_DRAW;
-  if (isMultiPart)
-    imageFlags |= Image::INIT_FLAG_MULTIPART;
-
-  return imageFlags;
-}
-
-/* static */ already_AddRefed<Image>
-ImageFactory::CreateImage(nsIRequest* aRequest,
-                          imgStatusTracker* aStatusTracker,
-                          const nsCString& aMimeType,
-                          nsIURI* aURI,
-                          bool aIsMultiPart,
-                          uint32_t aInnerWindowId)
-{
-  // Register our pref observers if we haven't yet.
-  if (MOZ_UNLIKELY(!gInitializedPrefCaches))
-    InitPrefCaches();
-
-  // Compute the image's initialization flags.
-  uint32_t imageFlags = ComputeImageFlags(aURI, aIsMultiPart);
-
-  // Select the type of image to create based on MIME type.
-  if (aMimeType.Equals(SVG_MIMETYPE)) {
-    return CreateVectorImage(aRequest, aStatusTracker, aMimeType,
-                             aURI, imageFlags, aInnerWindowId);
-  } else {
-    return CreateRasterImage(aRequest, aStatusTracker, aMimeType,
-                             aURI, imageFlags, aInnerWindowId);
-  }
-}
-
-// Marks an image as having an error before returning it. Used with macros like
-// NS_ENSURE_SUCCESS, since we guarantee to always return an image even if an
-// error occurs, but callers need to be able to tell that this happened.
-template <typename T>
-static already_AddRefed<Image>
-BadImage(nsRefPtr<T>& image)
-{
-  image->SetHasError();
-  return image.forget();
-}
-
-/* static */ already_AddRefed<Image>
-ImageFactory::CreateAnonymousImage(const nsCString& aMimeType)
-{
-  nsresult rv;
-
-  nsRefPtr<RasterImage> newImage = new RasterImage();
-
-  rv = newImage->Init(nullptr, aMimeType.get(), Image::INIT_FLAG_NONE);
-  NS_ENSURE_SUCCESS(rv, BadImage(newImage));
-
-  return newImage.forget();
-}
-
-/* static */ already_AddRefed<Image>
-
-ImageFactory::CreateRasterImage(nsIRequest* aRequest,
-                                imgStatusTracker* aStatusTracker,
-                                const nsCString& aMimeType,
-                                nsIURI* aURI,
-                                uint32_t aImageFlags,
-                                uint32_t aInnerWindowId)
-{
-  nsresult rv;
-
-  nsRefPtr<RasterImage> newImage = new RasterImage(aStatusTracker, aURI);
-
-  rv = newImage->Init(aStatusTracker->GetDecoderObserver(),
-                      aMimeType.get(), aImageFlags);
-  NS_ENSURE_SUCCESS(rv, BadImage(newImage));
-
-  newImage->SetInnerWindowID(aInnerWindowId);
-
-  // Use content-length as a size hint for http channels.
-  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
-  if (httpChannel) {
-    nsAutoCString contentLength;
-    rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-length"),
-                                        contentLength);
-    if (NS_SUCCEEDED(rv)) {
-      int32_t len = contentLength.ToInteger(&rv);
-
-      // Pass anything usable on so that the RasterImage can preallocate
-      // its source buffer
-      if (len > 0) {
-        uint32_t sizeHint = (uint32_t) len;
-        sizeHint = NS_MIN<uint32_t>(sizeHint, 20000000); // Bound by something reasonable
-        rv = newImage->SetSourceSizeHint(sizeHint);
-        if (NS_FAILED(rv)) {
-          // Flush memory, try to get some back, and try again
-          rv = nsMemory::HeapMinimize(true);
-          nsresult rv2 = newImage->SetSourceSizeHint(sizeHint);
-          // If we've still failed at this point, things are going downhill
-          if (NS_FAILED(rv) || NS_FAILED(rv2)) {
-            NS_WARNING("About to hit OOM in imagelib!");
-          }
-        }
-      }
-    }
-  }
-
-  return newImage.forget();
-}
-
-/* static */ already_AddRefed<Image>
-ImageFactory::CreateVectorImage(nsIRequest* aRequest,
-                                imgStatusTracker* aStatusTracker,
-                                const nsCString& aMimeType,
-                                nsIURI* aURI,
-                                uint32_t aImageFlags,
-                                uint32_t aInnerWindowId)
-{
-  nsresult rv;
-
-  nsRefPtr<VectorImage> newImage = new VectorImage(aStatusTracker, aURI);
-
-  rv = newImage->Init(aStatusTracker->GetDecoderObserver(),
-                      aMimeType.get(), aImageFlags);
-  NS_ENSURE_SUCCESS(rv, BadImage(newImage));
-
-  newImage->SetInnerWindowID(aInnerWindowId);
-
-  rv = newImage->OnStartRequest(aRequest, nullptr);
-  NS_ENSURE_SUCCESS(rv, BadImage(newImage));
-
-  return newImage.forget();
-}
-
-} // namespace image
-} // namespace mozilla
deleted file mode 100644
--- a/image/src/ImageFactory.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIURI.h"
-#include "nsIRequest.h"
-
-#include "imgIContainer.h"
-#include "imgStatusTracker.h"
-
-#include "Image.h"
-
-namespace mozilla {
-namespace image {
-
-extern const char* SVG_MIMETYPE;
-
-struct ImageFactory
-{
-  /**
-   * Creates a new image with the given properties.
-   *
-   * @param aRequest       The associated request.
-   * @param aStatusTracker A status tracker for the image to use.
-   * @param aMimeType      The mimetype of the image.
-   * @param aURI           The URI of the image.
-   * @param aIsMultiPart   Whether the image is part of a multipart request.
-   * @param aInnerWindowId The window this image belongs to.
-   */
-  static already_AddRefed<Image> CreateImage(nsIRequest* aRequest,
-                                             imgStatusTracker* aStatusTracker,
-                                             const nsCString& aMimeType,
-                                             nsIURI* aURI,
-                                             bool aIsMultiPart,
-                                             uint32_t aInnerWindowId);
-  /**
-   * Creates a new image which isn't associated with a URI or loaded through
-   * the usual image loading mechanism.
-   *
-   * @param aMimeType      The mimetype of the image.
-   */
-  static already_AddRefed<Image> CreateAnonymousImage(const nsCString& aMimeType);
-
-
-private:
-  // Factory functions that create specific types of image containers.
-  static already_AddRefed<Image> CreateRasterImage(nsIRequest* aRequest,
-                                                   imgStatusTracker* aStatusTracker,
-                                                   const nsCString& aMimeType,
-                                                   nsIURI* aURI,
-                                                   uint32_t aImageFlags,
-                                                   uint32_t aInnerWindowId);
-
-  static already_AddRefed<Image> CreateVectorImage(nsIRequest* aRequest,
-                                                   imgStatusTracker* aStatusTracker,
-                                                   const nsCString& aMimeType,
-                                                   nsIURI* aURI,
-                                                   uint32_t aImageFlags,
-                                                   uint32_t aInnerWindowId);
-
-  // This is a static factory class, so disallow instantiation.
-  virtual ~ImageFactory() = 0;
-};
-
-} // namespace image
-} // namespace mozilla
--- a/image/src/Makefile.in
+++ b/image/src/Makefile.in
@@ -21,17 +21,16 @@ FAIL_ON_WARNINGS = 1
 
 EXPORTS		=  imgLoader.h \
 		   imgRequest.h \
 		   imgRequestProxy.h \
 		   $(NULL)
 
 CPPSRCS		= \
 			Image.cpp \
-			ImageFactory.cpp \
 			Decoder.cpp \
 			DiscardTracker.cpp \
 			RasterImage.cpp \
 			ScriptedNotificationObserver.cpp \
 			SVGDocumentWrapper.cpp \
 			VectorImage.cpp \
 			imgFrame.cpp \
 			imgLoader.cpp    \
@@ -39,19 +38,16 @@ CPPSRCS		= \
 			imgRequestProxy.cpp \
 			imgTools.cpp \
 			imgStatusTracker.cpp \
 			$(NULL)
 
 # We need to instantiate the decoders
 LOCAL_INCLUDES += -I$(topsrcdir)/image/decoders
 
-# For URI-related functionality
-LOCAL_INCLUDES += -I$(topsrcdir)/netwerk/base/src
-
 # Because SVGDocumentWrapper.cpp includes "nsSVGSVGElement.h"
 LOCAL_INCLUDES += \
 			-I$(topsrcdir)/content/svg/content/src \
 			-I$(topsrcdir)/content/base/src \
 			$(NULL)
 
 # Because VectorImage.cpp includes nsSVGUtils.h and nsSVGEffects.h
 LOCAL_INCLUDES += -I$(topsrcdir)/layout/svg
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -347,19 +347,18 @@ static nsCOMPtr<nsIThread> sScaleWorkerT
 #ifndef DEBUG
 NS_IMPL_ISUPPORTS2(RasterImage, imgIContainer, nsIProperties)
 #else
 NS_IMPL_ISUPPORTS3(RasterImage, imgIContainer, nsIProperties,
                    imgIContainerDebug)
 #endif
 
 //******************************************************************************
-RasterImage::RasterImage(imgStatusTracker* aStatusTracker,
-                         nsIURI* aURI /* = nullptr */) :
-  Image(aStatusTracker, aURI), // invoke superclass's constructor
+RasterImage::RasterImage(imgStatusTracker* aStatusTracker) :
+  Image(aStatusTracker), // invoke superclass's constructor
   mSize(0,0),
   mFrameDecodeFlags(DECODE_FLAGS_DEFAULT),
   mAnim(nullptr),
   mLoopCount(-1),
   mObserver(nullptr),
   mLockCount(0),
   mDecoder(nullptr),
   mDecodeRequest(this),
@@ -437,16 +436,17 @@ RasterImage::Initialize()
   // Create our singletons now, so we don't have to worry about what thread
   // they're created on.
   DecodeWorker::Singleton();
 }
 
 nsresult
 RasterImage::Init(imgIDecoderObserver *aObserver,
                   const char* aMimeType,
+                  const char* aURIString,
                   uint32_t aFlags)
 {
   // We don't support re-initialization
   if (mInitialized)
     return NS_ERROR_ILLEGAL_VALUE;
 
   // Not sure an error can happen before init, but be safe
   if (mError)
@@ -459,16 +459,17 @@ RasterImage::Init(imgIDecoderObserver *a
   NS_ABORT_IF_FALSE(!(aFlags & INIT_FLAG_MULTIPART) ||
                     (!(aFlags & INIT_FLAG_DISCARDABLE) &&
                      !(aFlags & INIT_FLAG_DECODE_ON_DRAW)),
                     "Can't be discardable or decode-on-draw for multipart");
 
   // Store initialization data
   mObserver = do_GetWeakReference(aObserver);
   mSourceDataMimeType.Assign(aMimeType);
+  mURIString.Assign(aURIString);
   mDiscardable = !!(aFlags & INIT_FLAG_DISCARDABLE);
   mDecodeOnDraw = !!(aFlags & INIT_FLAG_DECODE_ON_DRAW);
   mMultipart = !!(aFlags & INIT_FLAG_MULTIPART);
 
   // Statistics
   if (mDiscardable) {
     num_discardable_containers++;
     discardable_source_bytes += mSourceData.Length();
@@ -682,17 +683,17 @@ RasterImage::ExtractFrame(uint32_t aWhic
     return NS_ERROR_FAILURE;
 
   // Make a new container. This should switch to another class with bug 505959.
   nsRefPtr<RasterImage> img(new RasterImage());
 
   // We don't actually have a mimetype in this case. The empty string tells the
   // init routine not to try to instantiate a decoder. This should be fixed in
   // bug 505959.
-  img->Init(nullptr, "", INIT_FLAG_NONE);
+  img->Init(nullptr, "", "", INIT_FLAG_NONE);
   img->SetSize(aRegion.width, aRegion.height);
   img->mDecoded = true; // Also, we need to mark the image as decoded
   img->mHasBeenDecoded = true;
   img->mFrameDecodeFlags = aFlags & DECODE_FLAGS_MASK;
 
   if (!ApplyDecodeFlags(aFlags))
     return NS_ERROR_NOT_AVAILABLE;
   
@@ -1799,17 +1800,17 @@ get_header_str (char *buf, char *data, s
     buf[i * 2]     = hex[(data[i] >> 4) & 0x0f];
     buf[i * 2 + 1] = hex[data[i] & 0x0f];
   }
 
   buf[i * 2] = 0;
 }
 
 nsresult
-RasterImage::OnImageDataComplete(nsIRequest*, nsISupports*, nsresult)
+RasterImage::SourceDataComplete()
 {
   if (mError)
     return NS_ERROR_FAILURE;
 
   // If we've been called before, ignore. Otherwise, flag that we have everything
   if (mHasSourceData)
     return NS_OK;
   mHasSourceData = true;
@@ -1861,37 +1862,17 @@ RasterImage::OnImageDataComplete(nsIRequ
   if (CanDiscard()) {
     nsresult rv = DiscardTracker::Reset(&mDiscardTrackerNode);
     CONTAINER_ENSURE_SUCCESS(rv);
   }
   return NS_OK;
 }
 
 nsresult
-RasterImage::OnImageDataAvailable(nsIRequest*,
-                                  nsISupports*,
-                                  nsIInputStream* aInStr,
-                                  uint64_t,
-                                  uint32_t aCount)
-{
-  nsresult rv;
- 
-  // WriteToRasterImage always consumes everything it gets
-  // if it doesn't run out of memory
-  uint32_t bytesRead;
-  rv = aInStr->ReadSegments(WriteToRasterImage, this, aCount, &bytesRead);
-
-  NS_ABORT_IF_FALSE(bytesRead == aCount || HasError(),
-    "WriteToRasterImage should consume everything or the image must be in error!");
-
-  return rv;
-}
-
-nsresult
-RasterImage::OnNewSourceData()
+RasterImage::NewSourceData()
 {
   nsresult rv;
 
   if (mError)
     return NS_ERROR_FAILURE;
 
   // The source data should be complete before calling this
   NS_ABORT_IF_FALSE(mHasSourceData,
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -18,17 +18,16 @@
 #define mozilla_imagelib_RasterImage_h_
 
 #include "Image.h"
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
 #include "imgIContainer.h"
 #include "nsIProperties.h"
 #include "nsITimer.h"
-#include "nsIRequest.h"
 #include "nsWeakReference.h"
 #include "nsTArray.h"
 #include "imgFrame.h"
 #include "nsThreadUtils.h"
 #include "DiscardTracker.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/LinkedList.h"
@@ -148,27 +147,28 @@ class RasterImage : public Image
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPROPERTIES
   NS_DECL_IMGICONTAINER
 #ifdef DEBUG
   NS_DECL_IMGICONTAINERDEBUG
 #endif
 
-  // (no public constructor - use ImageFactory)
+  RasterImage(imgStatusTracker* aStatusTracker = nullptr);
   virtual ~RasterImage();
 
   virtual nsresult StartAnimation();
   virtual nsresult StopAnimation();
 
   // Methods inherited from Image
   nsresult Init(imgIDecoderObserver* aObserver,
                 const char* aMimeType,
+                const char* aURIString,
                 uint32_t aFlags);
-  virtual void  GetCurrentFrameRect(nsIntRect& aRect) MOZ_OVERRIDE;
+  void     GetCurrentFrameRect(nsIntRect& aRect);
 
   // Raster-specific methods
   static NS_METHOD WriteToRasterImage(nsIInputStream* aIn, void* aClosure,
                                       const char* aFromRawSegment,
                                       uint32_t aToOffset, uint32_t aCount,
                                       uint32_t* aWriteCount);
 
   /* The index of the current frame that would be drawn if the image was to be
@@ -244,25 +244,21 @@ public:
    * The decoder will use this data, either immediately or at draw time, to
    * decode the image.
    *
    * XXX This method's only caller (WriteToContainer) ignores the return
    * value. Should this just return void?
    */
   nsresult AddSourceData(const char *aBuffer, uint32_t aCount);
 
-  virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
-                                        nsISupports* aContext,
-                                        nsIInputStream* aInStr,
-                                        uint64_t aSourceOffset,
-                                        uint32_t aCount) MOZ_OVERRIDE;
-  virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
-                                       nsISupports* aContext,
-                                       nsresult aResult) MOZ_OVERRIDE;
-  virtual nsresult OnNewSourceData() MOZ_OVERRIDE;
+  /* Called after the all the source data has been added with addSourceData. */
+  nsresult SourceDataComplete();
+
+  /* Called for multipart images when there's a new source image to add. */
+  nsresult NewSourceData();
 
   /**
    * A hint of the number of bytes of source data that the image contains. If
    * called early on, this can help reduce copying and reallocations by
    * appropriately preallocating the source data buffer.
    *
    * We take this approach rather than having the source data management code do
    * something more complicated (like chunklisting) because HTTP is by far the
@@ -727,21 +723,17 @@ private: // data
   // Helpers
   void DoError();
   bool CanDiscard();
   bool CanForciblyDiscard();
   bool DiscardingActive();
   bool StoringSourceData() const;
 
 protected:
-  RasterImage(imgStatusTracker* aStatusTracker = nullptr, nsIURI* aURI = nullptr);
-
   bool ShouldAnimate();
-
-  friend class ImageFactory;
 };
 
 inline NS_IMETHODIMP RasterImage::GetAnimationMode(uint16_t *aAnimationMode) {
   return GetAnimationModeInternal(aAnimationMode);
 }
 
 inline NS_IMETHODIMP RasterImage::SetAnimationMode(uint16_t aAnimationMode) {
   return SetAnimationModeInternal(aAnimationMode);
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -164,19 +164,18 @@ SVGDrawingCallback::operator()(gfxContex
 NS_IMPL_ISUPPORTS3(VectorImage,
                    imgIContainer,
                    nsIStreamListener,
                    nsIRequestObserver)
 
 //------------------------------------------------------------------------------
 // Constructor / Destructor
 
-VectorImage::VectorImage(imgStatusTracker* aStatusTracker,
-                         nsIURI* aURI /* = nullptr */) :
-  Image(aStatusTracker, aURI), // invoke superclass's constructor
+VectorImage::VectorImage(imgStatusTracker* aStatusTracker) :
+  Image(aStatusTracker), // invoke superclass's constructor
   mRestrictedRegion(0, 0, 0, 0),
   mIsInitialized(false),
   mIsFullyLoaded(false),
   mIsDrawing(false),
   mHaveAnimations(false),
   mHaveRestrictedRegion(false)
 {
 }
@@ -186,16 +185,17 @@ VectorImage::~VectorImage()
 }
 
 //------------------------------------------------------------------------------
 // Methods inherited from Image.h
 
 nsresult
 VectorImage::Init(imgIDecoderObserver* aObserver,
                   const char* aMimeType,
+                  const char* aURIString,
                   uint32_t aFlags)
 {
   // We don't support re-initialization
   if (mIsInitialized)
     return NS_ERROR_ILLEGAL_VALUE;
 
   NS_ABORT_IF_FALSE(!mIsFullyLoaded && !mHaveAnimations &&
                     !mHaveRestrictedRegion && !mError,
@@ -239,40 +239,16 @@ VectorImage::NonHeapSizeOfDecoded() cons
 
 size_t
 VectorImage::OutOfProcessSizeOfDecoded() const
 {
   return 0;
 }
 
 nsresult
-VectorImage::OnImageDataComplete(nsIRequest* aRequest,
-                                 nsISupports* aContext,
-                                 nsresult aStatus)
-{
-  return OnStopRequest(aRequest, aContext, aStatus);
-}
-
-nsresult
-VectorImage::OnImageDataAvailable(nsIRequest* aRequest,
-                                  nsISupports* aContext,
-                                  nsIInputStream* aInStr,
-                                  uint64_t aSourceOffset,
-                                  uint32_t aCount)
-{
-  return OnDataAvailable(aRequest, aContext, aInStr, aSourceOffset, aCount);
-}
-
-nsresult
-VectorImage::OnNewSourceData()
-{
-  return NS_OK;
-}
-
-nsresult
 VectorImage::StartAnimation()
 {
   if (mError)
     return NS_ERROR_FAILURE;
 
   NS_ABORT_IF_FALSE(ShouldAnimate(), "Should not animate!");
 
   mSVGDocumentWrapper->StartAnimation();
--- a/image/src/VectorImage.h
+++ b/image/src/VectorImage.h
@@ -3,17 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_imagelib_VectorImage_h_
 #define mozilla_imagelib_VectorImage_h_
 
 #include "Image.h"
 #include "nsIStreamListener.h"
-#include "nsIRequest.h"
 #include "nsWeakReference.h"
 #include "mozilla/TimeStamp.h"
 
 class imgIDecoderObserver;
 
 namespace mozilla {
 namespace layers {
 class LayerManager;
@@ -28,46 +27,35 @@ class VectorImage : public Image,
                     public nsIStreamListener
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_IMGICONTAINER
 
-  // (no public constructor - use ImageFactory)
+  VectorImage(imgStatusTracker* aStatusTracker = nullptr);
   virtual ~VectorImage();
 
   // Methods inherited from Image
   nsresult Init(imgIDecoderObserver* aObserver,
                 const char* aMimeType,
+                const char* aURIString,
                 uint32_t aFlags);
-  virtual void GetCurrentFrameRect(nsIntRect& aRect) MOZ_OVERRIDE;
+  void GetCurrentFrameRect(nsIntRect& aRect);
 
   virtual size_t HeapSizeOfSourceWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const;
   virtual size_t HeapSizeOfDecodedWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const;
   virtual size_t NonHeapSizeOfDecoded() const;
   virtual size_t OutOfProcessSizeOfDecoded() const;
 
-  virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
-                                        nsISupports* aContext,
-                                        nsIInputStream* aInStr,
-                                        uint64_t aSourceOffset,
-                                        uint32_t aCount) MOZ_OVERRIDE;
-  virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
-                                       nsISupports* aContext,
-                                       nsresult status) MOZ_OVERRIDE;
-  virtual nsresult OnNewSourceData() MOZ_OVERRIDE;
-
   // Callback for SVGRootRenderingObserver
   void InvalidateObserver();
 
 protected:
-  VectorImage(imgStatusTracker* aStatusTracker = nullptr, nsIURI* aURI = nullptr);
-
   virtual nsresult StartAnimation();
   virtual nsresult StopAnimation();
   virtual bool     ShouldAnimate();
 
 private:
   nsWeakPtr                          mObserver;   //! imgIDecoderObserver
   nsRefPtr<SVGDocumentWrapper>       mSVGDocumentWrapper;
   nsRefPtr<SVGRootRenderingObserver> mRenderingObserver;
@@ -79,18 +67,16 @@ private:
 
   bool           mIsInitialized:1;        // Have we been initalized?
   bool           mIsFullyLoaded:1;        // Has OnStopRequest been called?
   bool           mIsDrawing:1;            // Are we currently drawing?
   bool           mHaveAnimations:1;       // Is our SVG content SMIL-animated?
                                           // (Only set after mIsFullyLoaded.)
   bool           mHaveRestrictedRegion:1; // Are we a restricted-region clone
                                           // created via ExtractFrame?
-
-  friend class ImageFactory;
 };
 
 inline NS_IMETHODIMP VectorImage::GetAnimationMode(uint16_t *aAnimationMode) {
   return GetAnimationModeInternal(aAnimationMode);
 }
 
 inline NS_IMETHODIMP VectorImage::SetAnimationMode(uint16_t aAnimationMode) {
   return SetAnimationModeInternal(aAnimationMode);
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -698,18 +698,17 @@ nsresult imgLoader::CreateNewProxyForReq
      |Init()| adds the request to the loadgroup.
    */
   proxyRequest->SetLoadFlags(aLoadFlags);
 
   nsCOMPtr<nsIURI> uri;
   aRequest->GetURI(getter_AddRefs(uri));
 
   // init adds itself to imgRequest's list of observers
-  nsresult rv = proxyRequest->Init(aRequest, &aRequest->GetStatusTracker(),
-                                   aLoadGroup, uri, aObserver);
+  nsresult rv = proxyRequest->Init(&aRequest->GetStatusTracker(), aLoadGroup, uri, aObserver);
   if (NS_FAILED(rv)) {
     NS_RELEASE(proxyRequest);
     return rv;
   }
 
   // transfer reference to caller
   *_retval = proxyRequest;
 
--- a/image/src/imgRequest.cpp
+++ b/image/src/imgRequest.cpp
@@ -12,17 +12,18 @@
  * gets changed.
  * This #undef needs to be in multiple places because we don't always pull
  * headers in in the same order.
  */
 #undef LoadImage
 
 #include "imgLoader.h"
 #include "imgRequestProxy.h"
-#include "ImageFactory.h"
+#include "RasterImage.h"
+#include "VectorImage.h"
 
 #include "imgILoader.h"
 
 #include "netCore.h"
 
 #include "nsIChannel.h"
 #include "nsICachingChannel.h"
 #include "nsILoadGroup.h"
@@ -41,22 +42,39 @@
 #include "nsICacheVisitor.h"
 
 #include "nsString.h"
 #include "nsXPIDLString.h"
 #include "plstr.h" // PL_strcasestr(...)
 #include "nsNetUtil.h"
 #include "nsIProtocolHandler.h"
 
+#include "mozilla/Preferences.h"
+#include "mozilla/Likely.h"
+
 #include "DiscardTracker.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 
+#define SVG_MIMETYPE "image/svg+xml"
+
 using namespace mozilla;
 using namespace mozilla::image;
 
+static bool gInitializedPrefCaches = false;
+static bool gDecodeOnDraw = false;
+static bool gDiscardable = false;
+
+static void
+InitPrefCaches()
+{
+  Preferences::AddBoolVarCache(&gDiscardable, "image.mem.discardable");
+  Preferences::AddBoolVarCache(&gDecodeOnDraw, "image.mem.decodeondraw");
+  gInitializedPrefCaches = true;
+}
+
 #if defined(PR_LOGGING)
 PRLogModuleInfo *
 GetImgLog()
 {
   static PRLogModuleInfo *sImgLog;
   if (!sImgLog)
     sImgLog = PR_NewLogModule("imgRequest");
   return sImgLog;
@@ -66,29 +84,37 @@ GetImgLog()
 NS_IMPL_ISUPPORTS5(imgRequest,
                    nsIStreamListener, nsIRequestObserver,
                    nsIChannelEventSink,
                    nsIInterfaceRequestor,
                    nsIAsyncVerifyRedirectCallback)
 
 imgRequest::imgRequest(imgLoader* aLoader)
  : mLoader(aLoader)
- , mStatusTracker(new imgStatusTracker(nullptr))
+ , mStatusTracker(new imgStatusTracker(nullptr, this))
  , mValidator(nullptr)
  , mInnerWindowId(0)
  , mCORSMode(imgIRequest::CORS_NONE)
  , mDecodeRequested(false)
  , mIsMultiPartChannel(false)
  , mGotData(false)
  , mIsInCache(false)
  , mResniffMimeType(false)
-{ }
+{
+  // Register our pref observers if we haven't yet.
+  if (MOZ_UNLIKELY(!gInitializedPrefCaches)) {
+    InitPrefCaches();
+  }
+}
 
 imgRequest::~imgRequest()
 {
+  // The status tracker can outlive this request, and needs to know it's dying.
+  GetStatusTracker().ClearRequest();
+
   if (mURI) {
     nsAutoCString spec;
     mURI->GetSpec(spec);
     LOG_FUNC_WITH_PARAM(GetImgLog(), "imgRequest::~imgRequest()", "keyuri", spec.get());
   } else
     LOG_FUNC(GetImgLog(), "imgRequest::~imgRequest()");
 }
 
@@ -522,36 +548,35 @@ imgRequest::StartDecoding()
 
 /* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
 NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt)
 {
   LOG_SCOPE(GetImgLog(), "imgRequest::OnStartRequest");
 
   // Figure out if we're multipart
   nsCOMPtr<nsIMultiPartChannel> mpchan(do_QueryInterface(aRequest));
-  if (mpchan) {
-    mIsMultiPartChannel = true;
-    GetStatusTracker().SetIsMultipart();
-  }
+  if (mpchan)
+      mIsMultiPartChannel = true;
 
   // If we're not multipart, we shouldn't have an image yet
   NS_ABORT_IF_FALSE(mIsMultiPartChannel || !mImage,
                     "Already have an image for non-multipart request");
 
   // If we're multipart and about to load another image, signal so we can
   // detect the mime type in OnDataAvailable.
   if (mIsMultiPartChannel && mImage) {
     mResniffMimeType = true;
-
-    // Tell the image to reinitialize itself. We have to do this in
-    // OnStartRequest so that its state machine is always in a consistent
-    // state.
-    // Note that if our MIME type changes, mImage will be replaced with a
-    // new object.
-    mImage->OnNewSourceData();
+    if (mImage->GetType() == imgIContainer::TYPE_RASTER) {
+        // Tell the RasterImage to reinitialize itself. We have to do this in
+        // OnStartRequest so that its state machine is always in a consistent
+        // state.
+        // Note that if our MIME type changes, mImage will be replaced with a
+        // new object.
+        static_cast<RasterImage*>(mImage.get())->NewSourceData();
+      }
   }
 
   /*
    * If mRequest is null here, then we need to set it so that we'll be able to
    * cancel it if our Cancel() method is called.  Note that this can only
    * happen for multipart channels.  We could simply not null out mRequest for
    * non-last parts, if GetIsLastPart() were reliable, but it's not.  See
    * https://bugzilla.mozilla.org/show_bug.cgi?id=339610
@@ -620,22 +645,31 @@ NS_IMETHODIMP imgRequest::OnStopRequest(
     mPrevChannelSink = nullptr;
     mChannel = nullptr;
   }
 
   // Tell the image that it has all of the source data. Note that this can
   // trigger a failure, since the image might be waiting for more non-optional
   // data and this is the point where we break the news that it's not coming.
   if (mImage) {
-    nsresult rv = mImage->OnImageDataComplete(aRequest, ctxt, status);
+    nsresult rv;
+    if (mImage->GetType() == imgIContainer::TYPE_RASTER) {
+      // Notify the image
+      rv = static_cast<RasterImage*>(mImage.get())->SourceDataComplete();
+    } else { // imageType == imgIContainer::TYPE_VECTOR
+      nsCOMPtr<nsIStreamListener> imageAsStream = do_QueryInterface(mImage);
+      NS_ABORT_IF_FALSE(imageAsStream,
+                        "SVG-typed Image failed QI to nsIStreamListener");
+      rv = imageAsStream->OnStopRequest(aRequest, ctxt, status);
+    }
 
-    // If we got an error in the OnImageDataComplete() call, we don't want to
-    // proceed as if nothing bad happened. However, we also want to give
-    // precedence to failure status codes from necko, since presumably they're
-    // more meaningful.
+    // If we got an error in the SourceDataComplete() / OnStopRequest() call,
+    // we don't want to proceed as if nothing bad happened. However, we also
+    // want to give precedence to failure status codes from necko, since
+    // presumably they're more meaningful.
     if (NS_FAILED(rv) && NS_SUCCEEDED(status))
       status = rv;
   }
 
   imgStatusTracker& statusTracker = GetStatusTracker();
   statusTracker.RecordStopRequest(lastPart, status);
 
   // If the request went through, update the cache entry size. Otherwise,
@@ -721,31 +755,40 @@ imgRequest::OnDataAvailable(nsIRequest *
     }
 
     // If we're a regular image and this is the first call to OnDataAvailable,
     // this will always be true. If we've resniffed our MIME type (i.e. we're a
     // multipart/x-mixed-replace image), we have to be able to switch our image
     // type and decoder.
     // We always reinitialize for SVGs, because they have no way of
     // reinitializing themselves.
-    if (mContentType != newType || newType.Equals(SVG_MIMETYPE)) {
+    if (mContentType != newType || newType.EqualsLiteral(SVG_MIMETYPE)) {
       mContentType = newType;
 
       // If we've resniffed our MIME type and it changed, we need to create a
       // new status tracker to give to the image, because we don't have one of
       // our own any more.
       if (mResniffMimeType) {
         NS_ABORT_IF_FALSE(mIsMultiPartChannel, "Resniffing a non-multipart image");
-
-        imgStatusTracker* freshTracker = new imgStatusTracker(nullptr);
+        imgStatusTracker* freshTracker = new imgStatusTracker(nullptr, this);
         freshTracker->AdoptConsumers(&GetStatusTracker());
         mStatusTracker = freshTracker;
+      }
 
-        mResniffMimeType = false;
+      mResniffMimeType = false;
+
+      /* now we have mimetype, so we can infer the image type that we want */
+      if (mContentType.EqualsLiteral(SVG_MIMETYPE)) {
+        mImage = new VectorImage(mStatusTracker.forget());
+      } else {
+        mImage = new RasterImage(mStatusTracker.forget());
       }
+      mImage->SetInnerWindowID(mInnerWindowId);
+
+      GetStatusTracker().OnDataAvailable();
 
       /* set our mimetype as a property */
       nsCOMPtr<nsISupportsCString> contentType(do_CreateInstance("@mozilla.org/supports-cstring;1"));
       if (contentType) {
         contentType->SetData(mContentType);
         mProperties->Set("type", contentType);
       }
 
@@ -759,47 +802,131 @@ imgRequest::OnDataAvailable(nsIRequest *
         if (contentDisposition) {
           contentDisposition->SetData(disposition);
           mProperties->Set("content-disposition", contentDisposition);
         }
       }
 
       LOG_MSG_WITH_PARAM(GetImgLog(), "imgRequest::OnDataAvailable", "content type", mContentType.get());
 
-      // Now we can create a new image to hold the data. If we don't have a decoder
-      // for this mimetype we'll find out about it here.
-      mImage = ImageFactory::CreateImage(aRequest, mStatusTracker, mContentType,
-                                         mURI, mIsMultiPartChannel, mInnerWindowId);
+      //
+      // Figure out our Image initialization flags
+      //
+
+      // We default to the static globals
+      bool isDiscardable = gDiscardable;
+      bool doDecodeOnDraw = gDecodeOnDraw;
 
-      // Release our copy of the status tracker since the image owns it now.
-      mStatusTracker = nullptr;
+      // We want UI to be as snappy as possible and not to flicker. Disable discarding
+      // and decode-on-draw for chrome URLS
+      bool isChrome = false;
+      rv = mURI->SchemeIs("chrome", &isChrome);
+      if (NS_SUCCEEDED(rv) && isChrome)
+        isDiscardable = doDecodeOnDraw = false;
+
+      // We don't want resources like the "loading" icon to be discardable or
+      // decode-on-draw either.
+      bool isResource = false;
+      rv = mURI->SchemeIs("resource", &isResource);
+      if (NS_SUCCEEDED(rv) && isResource)
+        isDiscardable = doDecodeOnDraw = false;
+
+      // For multipart/x-mixed-replace, we basically want a direct channel to the
+      // decoder. Disable both for this case as well.
+      if (mIsMultiPartChannel)
+        isDiscardable = doDecodeOnDraw = false;
 
-      // Notify listeners that we have an image.
-      // XXX(seth): The name of this notification method is pretty misleading.
-      GetStatusTracker().OnDataAvailable();
+      // We have all the information we need
+      uint32_t imageFlags = Image::INIT_FLAG_NONE;
+      if (isDiscardable)
+        imageFlags |= Image::INIT_FLAG_DISCARDABLE;
+      if (doDecodeOnDraw)
+        imageFlags |= Image::INIT_FLAG_DECODE_ON_DRAW;
+      if (mIsMultiPartChannel)
+        imageFlags |= Image::INIT_FLAG_MULTIPART;
 
-      if (mImage->HasError() && !mIsMultiPartChannel) { // Probably bad mimetype
-        // We allow multipart images to fail to initialize without cancelling the
-        // load because subsequent images might be fine; thus only single part
-        // images end up here.
-        this->Cancel(NS_ERROR_FAILURE);
+      // Get our URI string
+      nsAutoCString uriString;
+      rv = mURI->GetSpec(uriString);
+      if (NS_FAILED(rv))
+        uriString.Assign("<unknown image URI>");
+
+      // Initialize the image that we created above. For RasterImages, this
+      // instantiates a decoder behind the scenes, so if we don't have a decoder
+      // for this mimetype we'll find out about it here.
+      rv = mImage->Init(GetStatusTracker().GetDecoderObserver(),
+                        mContentType.get(), uriString.get(), imageFlags);
+
+      // We allow multipart images to fail to initialize without cancelling the
+      // load because subsequent images might be fine.
+      if (NS_FAILED(rv) && !mIsMultiPartChannel) { // Probably bad mimetype
+
+        this->Cancel(rv);
         return NS_BINDING_ABORTED;
       }
 
-      NS_ABORT_IF_FALSE(!!GetStatusTracker().GetImage(), "Status tracker should have an image!");
-      NS_ABORT_IF_FALSE(mImage, "imgRequest should have an image!");
+      if (mImage->GetType() == imgIContainer::TYPE_RASTER) {
+        /* Use content-length as a size hint for http channels. */
+        nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
+        if (httpChannel) {
+          nsAutoCString contentLength;
+          rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-length"),
+                                              contentLength);
+          if (NS_SUCCEEDED(rv)) {
+            int32_t len = contentLength.ToInteger(&rv);
 
-      if (mDecodeRequested)
-        mImage->StartDecoding();
+            // Pass anything usable on so that the RasterImage can preallocate
+            // its source buffer
+            if (len > 0) {
+              uint32_t sizeHint = (uint32_t) len;
+              sizeHint = NS_MIN<uint32_t>(sizeHint, 20000000); /* Bound by something reasonable */
+              RasterImage* rasterImage = static_cast<RasterImage*>(mImage.get());
+              rv = rasterImage->SetSourceSizeHint(sizeHint);
+              if (NS_FAILED(rv)) {
+                // Flush memory, try to get some back, and try again
+                rv = nsMemory::HeapMinimize(true);
+                nsresult rv2 = rasterImage->SetSourceSizeHint(sizeHint);
+                // If we've still failed at this point, things are going downhill
+                if (NS_FAILED(rv) || NS_FAILED(rv2)) {
+                  NS_WARNING("About to hit OOM in imagelib!");
+                }
+              }
+            }
+          }
+        }
+      }
+
+      if (mImage->GetType() == imgIContainer::TYPE_RASTER) {
+        // If we were waiting on the image to do something, now's our chance.
+        if (mDecodeRequested) {
+          mImage->StartDecoding();
+        }
+      } else { // mImage->GetType() == imgIContainer::TYPE_VECTOR
+        nsCOMPtr<nsIStreamListener> imageAsStream = do_QueryInterface(mImage);
+        NS_ABORT_IF_FALSE(imageAsStream,
+                          "SVG-typed Image failed QI to nsIStreamListener");
+        imageAsStream->OnStartRequest(aRequest, nullptr);
+      }
     }
   }
 
-  // Notify the image that it has new data.
-  rv = mImage->OnImageDataAvailable(aRequest, ctxt, inStr, sourceOffset, count);
-
+  if (mImage->GetType() == imgIContainer::TYPE_RASTER) {
+    // WriteToRasterImage always consumes everything it gets
+    // if it doesn't run out of memory
+    uint32_t bytesRead;
+    rv = inStr->ReadSegments(RasterImage::WriteToRasterImage,
+                             static_cast<void*>(mImage),
+                             count, &bytesRead);
+    NS_ABORT_IF_FALSE(bytesRead == count || mImage->HasError(),
+  "WriteToRasterImage should consume everything or the image must be in error!");
+  } else { // mImage->GetType() == imgIContainer::TYPE_VECTOR
+    nsCOMPtr<nsIStreamListener> imageAsStream = do_QueryInterface(mImage);
+    rv = imageAsStream->OnDataAvailable(aRequest, ctxt, inStr,
+                                        sourceOffset, count);
+  }
   if (NS_FAILED(rv)) {
     PR_LOG(GetImgLog(), PR_LOG_WARNING,
            ("[this=%p] imgRequest::OnDataAvailable -- "
             "copy to RasterImage failed\n", this));
     this->Cancel(NS_IMAGELIB_ERROR_FAILURE);
     return NS_BINDING_ABORTED;
   }
 
--- a/image/src/imgRequest.h
+++ b/image/src/imgRequest.h
@@ -193,17 +193,17 @@ private:
   nsCOMPtr<nsIURI> mURI;
   // The URI of the resource we ended up loading after all redirects, etc.
   nsCOMPtr<nsIURI> mCurrentURI;
   // The principal of the document which loaded this image. Used when validating for CORS.
   nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
   // The principal of this image.
   nsCOMPtr<nsIPrincipal> mPrincipal;
   // Status-tracker -- transferred to mImage, when it gets instantiated
-  nsRefPtr<imgStatusTracker> mStatusTracker;
+  nsAutoPtr<imgStatusTracker> mStatusTracker;
   nsRefPtr<mozilla::image::Image> mImage;
   nsCOMPtr<nsIProperties> mProperties;
   nsCOMPtr<nsISupports> mSecurityInfo;
   nsCOMPtr<nsIChannel> mChannel;
   nsCOMPtr<nsIInterfaceRequestor> mPrevChannelSink;
   nsCOMPtr<nsIApplicationCache> mApplicationCache;
 
   nsCOMPtr<nsITimedChannel> mTimedChannel;
--- a/image/src/imgRequestProxy.cpp
+++ b/image/src/imgRequestProxy.cpp
@@ -143,29 +143,27 @@ imgRequestProxy::~imgRequestProxy()
        the last observer.  This allows the image to continue to download and
        be cached even if no one is using it currently.
     */
     mCanceled = true;
     GetOwner()->RemoveProxy(this, NS_OK);
   }
 }
 
-nsresult imgRequestProxy::Init(imgRequest* aOwner,
-                               imgStatusTracker* aStatusTracker,
+nsresult imgRequestProxy::Init(imgStatusTracker* aStatusTracker,
                                nsILoadGroup* aLoadGroup,
-                               nsIURI* aURI,
-                               imgINotificationObserver* aObserver)
+                               nsIURI* aURI, imgINotificationObserver* aObserver)
 {
   NS_PRECONDITION(!GetOwner() && !mListener, "imgRequestProxy is already initialized");
 
-  LOG_SCOPE_WITH_PARAM(GetImgLog(), "imgRequestProxy::Init", "request", aOwner);
+  LOG_SCOPE_WITH_PARAM(GetImgLog(), "imgRequestProxy::Init", "request", aStatusTracker->GetRequest());
 
   NS_ABORT_IF_FALSE(mAnimationConsumers == 0, "Cannot have animation before Init");
 
-  mBehaviour->SetOwner(aOwner);
+  mBehaviour->SetOwner(aStatusTracker->GetRequest());
   mListener = aObserver;
   // Make sure to addref mListener before the AddProxy call below, since
   // that call might well want to release it if the imgRequest has
   // already seen OnStopRequest.
   if (mListener) {
     mListenerIsStrongRef = true;
     NS_ADDREF(mListener);
   }
@@ -581,18 +579,17 @@ nsresult imgRequestProxy::PerformClone(i
 
   // It is important to call |SetLoadFlags()| before calling |Init()| because
   // |Init()| adds the request to the loadgroup.
   // When a request is added to a loadgroup, its load flags are merged
   // with the load flags of the loadgroup.
   // XXXldb That's not true anymore.  Stuff from imgLoader adds the
   // request to the loadgroup.
   clone->SetLoadFlags(mLoadFlags);
-  nsresult rv = clone->Init(mBehaviour->GetOwner(), &GetStatusTracker(),
-                            mLoadGroup, mURI, aObserver);
+  nsresult rv = clone->Init(&GetStatusTracker(), mLoadGroup, mURI, aObserver);
   if (NS_FAILED(rv))
     return rv;
 
   // Assign to *aClone before calling Notify so that if the caller expects to
   // only be notified for requests it's already holding pointers to it won't be
   // surprised.
   NS_ADDREF(*aClone = clone);
 
@@ -677,30 +674,16 @@ NS_IMETHODIMP imgRequestProxy::GetHasTra
     // The safe thing to do is to claim we have data
     *hasData = true;
   }
   return NS_OK;
 }
 
 /** imgIDecoderObserver methods **/
 
-void imgRequestProxy::OnStartDecode()
-{
-  // This notification is deliberately not propagated since there are no
-  // listeners who care about it.
-  if (GetOwner()) {
-    // In the case of streaming jpegs, it is possible to get multiple
-    // OnStartDecodes which indicates the beginning of a new decode.  The cache
-    // entry's size therefore needs to be reset to 0 here.  If we do not do
-    // this, the code in imgStatusTrackerObserver::OnStopFrame will continue to
-    // increase the data size cumulatively.
-    GetOwner()->ResetCacheEntry();
-  }
-}
-
 void imgRequestProxy::OnStartContainer()
 {
   LOG_FUNC(GetImgLog(), "imgRequestProxy::OnStartContainer");
 
   if (mListener && !mCanceled && !mSentStartContainer) {
     // Hold a ref to the listener while we call it, just in case.
     nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
     mListener->Notify(this, imgINotificationObserver::SIZE_AVAILABLE, nullptr);
@@ -735,40 +718,30 @@ void imgRequestProxy::OnStopDecode()
   LOG_FUNC(GetImgLog(), "imgRequestProxy::OnStopDecode");
 
   if (mListener && !mCanceled) {
     // Hold a ref to the listener while we call it, just in case.
     nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
     mListener->Notify(this, imgINotificationObserver::DECODE_COMPLETE, nullptr);
   }
 
-  if (GetOwner()) {
-    // We finished the decode, and thus have the decoded frames. Update the cache
-    // entry size to take this into account.
-    GetOwner()->UpdateCacheEntrySize();
-
-    // Multipart needs reset for next OnStartContainer.
-    if (GetOwner()->GetMultipart())
-      mSentStartContainer = false;
-  }
+  // Multipart needs reset for next OnStartContainer
+  if (GetOwner() && GetOwner()->GetMultipart())
+    mSentStartContainer = false;
 }
 
 void imgRequestProxy::OnDiscard()
 {
   LOG_FUNC(GetImgLog(), "imgRequestProxy::OnDiscard");
 
   if (mListener && !mCanceled) {
     // Hold a ref to the listener while we call it, just in case.
     nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
     mListener->Notify(this, imgINotificationObserver::DISCARD, nullptr);
   }
-  if (GetOwner()) {
-    // Update the cache entry size, since we just got rid of frame data.
-    GetOwner()->UpdateCacheEntrySize();
-  }
 }
 
 void imgRequestProxy::OnImageIsAnimated()
 {
   LOG_FUNC(GetImgLog(), "imgRequestProxy::OnImageIsAnimated");
   if (mListener && !mCanceled) {
     // Hold a ref to the listener while we call it, just in case.
     nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
@@ -908,33 +881,33 @@ imgRequestProxy::GetStaticRequest(imgReq
     return rv;
 
   nsRefPtr<Image> frame = static_cast<Image*>(currentFrame.get());
 
   // Create a static imgRequestProxy with our new extracted frame.
   nsCOMPtr<nsIPrincipal> currentPrincipal;
   GetImagePrincipal(getter_AddRefs(currentPrincipal));
   nsRefPtr<imgRequestProxy> req = new imgRequestProxyStatic(frame, currentPrincipal);
-  req->Init(nullptr, &frame->GetStatusTracker(), nullptr, mURI, nullptr);
+  req->Init(&frame->GetStatusTracker(), nullptr, mURI, nullptr);
 
   NS_ADDREF(*aReturn = req);
 
   return NS_OK;
 }
 
 void imgRequestProxy::NotifyListener()
 {
   // It would be nice to notify the observer directly in the status tracker
   // instead of through the proxy, but there are several places we do extra
   // processing when we receive notifications (like OnStopRequest()), and we
   // need to check mCanceled everywhere too.
 
   if (GetOwner()) {
     // Send the notifications to our listener asynchronously.
-    GetStatusTracker().Notify(this);
+    GetStatusTracker().Notify(GetOwner(), this);
   } else {
     // We don't have an imgRequest, so we can only notify the clone of our
     // current state, but we still have to do that asynchronously.
     NS_ABORT_IF_FALSE(GetImage(),
                       "if we have no imgRequest, we should have an Image");
     GetStatusTracker().NotifyCurrentState(this);
   }
 }
--- a/image/src/imgRequestProxy.h
+++ b/image/src/imgRequestProxy.h
@@ -53,21 +53,19 @@ public:
   NS_DECL_NSISECURITYINFOPROVIDER
   // nsITimedChannel declared below
 
   imgRequestProxy();
   virtual ~imgRequestProxy();
 
   // Callers to Init or ChangeOwner are required to call NotifyListener after
   // (although not immediately after) doing so.
-  nsresult Init(imgRequest* aOwner,
-                imgStatusTracker* aStatusTracker,
+  nsresult Init(imgStatusTracker* aStatusTracker,
                 nsILoadGroup *aLoadGroup,
-                nsIURI* aURI,
-                imgINotificationObserver *aObserver);
+                nsIURI* aURI, imgINotificationObserver *aObserver);
 
   nsresult ChangeOwner(imgRequest *aNewOwner); // this will change mOwner.  Do not call this if the previous
                                                // owner has already sent notifications out!
 
   void AddToLoadGroup();
   void RemoveFromLoadGroup(bool releaseLoadGroup);
 
   inline bool HasObserver() const {
@@ -133,17 +131,16 @@ protected:
       nsresult mStatus;
   };
 
   // The following notification functions are protected to ensure that (friend
   // class) imgStatusTracker is the only class allowed to send us
   // notifications.
 
   /* non-virtual imgIDecoderObserver methods */
-  void OnStartDecode     ();
   void OnStartContainer  ();
   void OnFrameUpdate     (const nsIntRect * aRect);
   void OnStopFrame       ();
   void OnStopDecode      ();
   void OnDiscard         ();
   void OnImageIsAnimated ();
 
   /* non-virtual sort-of-nsIRequestObserver methods */
--- a/image/src/imgStatusTracker.cpp
+++ b/image/src/imgStatusTracker.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "imgStatusTracker.h"
 
+#include "imgRequest.h"
 #include "imgIContainer.h"
 #include "imgRequestProxy.h"
 #include "Image.h"
 #include "ImageLogging.h"
 #include "RasterImage.h"
 #include "nsIObserverService.h"
 
 #include "mozilla/Util.h"
@@ -46,35 +47,37 @@ NS_IMETHODIMP imgStatusTrackerObserver::
 /** imgIDecoderObserver methods **/
 
 NS_IMETHODIMP imgStatusTrackerObserver::OnStartDecode()
 {
   LOG_SCOPE(GetImgLog(), "imgStatusTrackerObserver::OnStartDecode");
   NS_ABORT_IF_FALSE(mTracker->GetImage(),
                     "OnStartDecode callback before we've created our image");
 
-  mTracker->RecordStartDecode();
-
-  nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
-  while (iter.HasMore()) {
-    mTracker->SendStartDecode(iter.GetNext());
-  }
-
-  if (mTracker->IsMultipart()) {
+  if (mTracker->GetRequest() && !mTracker->GetRequest()->GetMultipart()) {
     MOZ_ASSERT(!mTracker->mBlockingOnload);
     mTracker->mBlockingOnload = true;
 
     mTracker->RecordBlockOnload();
 
     nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
     while (iter.HasMore()) {
       mTracker->SendBlockOnload(iter.GetNext());
     }
   }
 
+  /* In the case of streaming jpegs, it is possible to get multiple OnStartDecodes which
+     indicates the beginning of a new decode.
+     The cache entry's size therefore needs to be reset to 0 here.  If we do not do this,
+     the code in imgStatusTrackerObserver::OnStopFrame will continue to increase the data size cumulatively.
+  */
+  if (mTracker->GetRequest()) {
+    mTracker->GetRequest()->ResetCacheEntry();
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP imgStatusTrackerObserver::OnStartRequest()
 {
   NS_NOTREACHED("imgRequest(imgIDecoderObserver)::OnStartRequest");
   return NS_OK;
 }
@@ -127,38 +130,58 @@ NS_IMETHODIMP imgStatusTrackerObserver::
     mTracker->SendStopFrame(iter.GetNext());
   }
 
   mTracker->MaybeUnblockOnload();
 
   return NS_OK;
 }
 
+static void
+FireFailureNotification(imgRequest* aRequest)
+{
+  // Some kind of problem has happened with image decoding.
+  // Report the URI to net:failed-to-process-uri-conent observers.
+
+  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
+  if (os) {
+    nsCOMPtr<nsIURI> uri;
+    aRequest->GetURI(getter_AddRefs(uri));
+    os->NotifyObservers(uri, "net:failed-to-process-uri-content", nullptr);
+  }
+}
+
 /* void onStopDecode (in nsresult status); */
 NS_IMETHODIMP imgStatusTrackerObserver::OnStopDecode(nsresult aStatus)
 {
   LOG_SCOPE(GetImgLog(), "imgStatusTrackerObserver::OnStopDecode");
   NS_ABORT_IF_FALSE(mTracker->GetImage(),
                     "OnStopDecode callback before we've created our image");
 
+  // We finished the decode, and thus have the decoded frames. Update the cache
+  // entry size to take this into account.
+  if (mTracker->GetRequest()) {
+    mTracker->GetRequest()->UpdateCacheEntrySize();
+  }
+
   bool preexistingError = mTracker->GetImageStatus() == imgIRequest::STATUS_ERROR;
 
   mTracker->RecordStopDecode(aStatus);
 
   nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
   while (iter.HasMore()) {
     mTracker->SendStopDecode(iter.GetNext(), aStatus);
   }
 
   // This is really hacky. We need to handle the case where we start decoding,
   // block onload, but then hit an error before we get to our first frame.
   mTracker->MaybeUnblockOnload();
 
-  if (NS_FAILED(aStatus) && !preexistingError) {
-    mTracker->FireFailureNotification();
+  if (NS_FAILED(aStatus) && !preexistingError && mTracker->GetRequest()) {
+    FireFailureNotification(mTracker->GetRequest());
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP imgStatusTrackerObserver::OnStopRequest(bool aLastPart)
 {
   NS_NOTREACHED("imgRequest(imgIDecoderObserver)::OnStopRequest");
@@ -168,16 +191,21 @@ NS_IMETHODIMP imgStatusTrackerObserver::
 /* void onDiscard (); */
 NS_IMETHODIMP imgStatusTrackerObserver::OnDiscard()
 {
   NS_ABORT_IF_FALSE(mTracker->GetImage(),
                     "OnDiscard callback before we've created our image");
 
   mTracker->RecordDiscard();
 
+  // Update the cache entry size, since we just got rid of frame data
+  if (mTracker->GetRequest()) {
+    mTracker->GetRequest()->UpdateCacheEntrySize();
+  }
+
   nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
   while (iter.HasMore()) {
     mTracker->SendDiscard(iter.GetNext());
   }
 
   return NS_OK;
 }
 
@@ -192,31 +220,31 @@ NS_IMETHODIMP imgStatusTrackerObserver::
     mTracker->SendImageIsAnimated(iter.GetNext());
   }
 
   return NS_OK;
 }
 
 // imgStatusTracker methods
 
-imgStatusTracker::imgStatusTracker(Image* aImage)
+imgStatusTracker::imgStatusTracker(Image* aImage, imgRequest* aRequest)
   : mImage(aImage),
-    mTrackerObserver(new imgStatusTrackerObserver(this)),
+    mRequest(aRequest),
     mState(0),
     mImageStatus(imgIRequest::STATUS_NONE),
-    mIsMultipart(false),
     mHadLastPart(false),
-    mBlockingOnload(false)
+    mBlockingOnload(false),
+    mTrackerObserver(new imgStatusTrackerObserver(this))
 {}
 
 imgStatusTracker::imgStatusTracker(const imgStatusTracker& aOther)
   : mImage(aOther.mImage),
+    mRequest(aOther.mRequest),
     mState(aOther.mState),
     mImageStatus(aOther.mImageStatus),
-    mIsMultipart(aOther.mIsMultipart),
     mHadLastPart(aOther.mHadLastPart),
     mBlockingOnload(aOther.mBlockingOnload)
     // Note: we explicitly don't copy mRequestRunnable, because it won't be
     // nulled out when the mRequestRunnable's Run function eventually gets
     // called.
 {}
 
 void
@@ -241,69 +269,71 @@ imgStatusTracker::GetImageStatus() const
 {
   return mImageStatus;
 }
 
 // A helper class to allow us to call SyncNotify asynchronously.
 class imgRequestNotifyRunnable : public nsRunnable
 {
   public:
-    imgRequestNotifyRunnable(imgStatusTracker* aTracker, imgRequestProxy* aRequestProxy)
-      : mTracker(aTracker)
+    imgRequestNotifyRunnable(imgRequest* request, imgRequestProxy* requestproxy)
+      : mRequest(request)
     {
-      mProxies.AppendElement(aRequestProxy);
+      mProxies.AppendElement(requestproxy);
     }
 
     NS_IMETHOD Run()
     {
+      imgStatusTracker& statusTracker = mRequest->GetStatusTracker();
+
       for (uint32_t i = 0; i < mProxies.Length(); ++i) {
         mProxies[i]->SetNotificationsDeferred(false);
-        mTracker->SyncNotify(mProxies[i]);
+        statusTracker.SyncNotify(mProxies[i]);
       }
 
-      mTracker->mRequestRunnable = nullptr;
+      statusTracker.mRequestRunnable = nullptr;
       return NS_OK;
     }
 
     void AddProxy(imgRequestProxy* aRequestProxy)
     {
       mProxies.AppendElement(aRequestProxy);
     }
 
   private:
     friend class imgStatusTracker;
 
-    nsRefPtr<imgStatusTracker> mTracker;
-    nsTArray< nsRefPtr<imgRequestProxy> > mProxies;
+    nsRefPtr<imgRequest> mRequest;
+    nsTArray<nsRefPtr<imgRequestProxy> > mProxies;
 };
 
 void
-imgStatusTracker::Notify(imgRequestProxy* proxy)
+imgStatusTracker::Notify(imgRequest* request, imgRequestProxy* proxy)
 {
 #ifdef PR_LOGGING
-  if (GetImage() && GetImage()->GetURI()) {
-    nsCOMPtr<nsIURI> uri(GetImage()->GetURI());
-    nsAutoCString spec;
-    uri->GetSpec(spec);
-    LOG_FUNC_WITH_PARAM(GetImgLog(), "imgStatusTracker::Notify async", "uri", spec.get());
-  } else {
-    LOG_FUNC_WITH_PARAM(GetImgLog(), "imgStatusTracker::Notify async", "uri", "<unknown>");
-  }
+  nsCOMPtr<nsIURI> uri;
+  request->GetURI(getter_AddRefs(uri));
+  nsAutoCString spec;
+  uri->GetSpec(spec);
+  LOG_FUNC_WITH_PARAM(GetImgLog(), "imgStatusTracker::Notify async", "uri", spec.get());
 #endif
 
   proxy->SetNotificationsDeferred(true);
 
   // If we have an existing runnable that we can use, we just append this proxy
   // to its list of proxies to be notified. This ensures we don't unnecessarily
   // delay onload.
   imgRequestNotifyRunnable* runnable = static_cast<imgRequestNotifyRunnable*>(mRequestRunnable.get());
-  if (runnable) {
+  if (runnable && runnable->mRequest == request) {
     runnable->AddProxy(proxy);
   } else {
-    mRequestRunnable = new imgRequestNotifyRunnable(this, proxy);
+    // It's okay to overwrite an existing mRequestRunnable, because adding a
+    // new proxy is strictly a performance optimization. The notification will
+    // always happen, regardless of whether we hold a reference to a runnable.
+    mRequestRunnable = new imgRequestNotifyRunnable(request, proxy);
     NS_DispatchToCurrentThread(mRequestRunnable);
   }
 }
 
 // A helper class to allow us to call SyncNotify asynchronously for a given,
 // fixed, state.
 class imgStatusNotifyRunnable : public nsRunnable
 {
@@ -363,39 +393,36 @@ imgStatusTracker::SyncNotify(imgRequestP
   // OnStartRequest
   if (mState & stateRequestStarted)
     proxy->OnStartRequest();
 
   // OnStartContainer
   if (mState & stateHasSize)
     proxy->OnStartContainer();
 
-  // OnStartDecode
-  if (mState & stateDecodeStarted)
-    proxy->OnStartDecode();
-
   // BlockOnload
   if (mState & stateBlockingOnload)
     proxy->BlockOnload();
 
   if (mImage) {
-    // OnDataAvailable
-    // XXX - Should only send partial rects here, but that needs to
-    // wait until we fix up the observer interface
-    nsIntRect r;
-    mImage->GetCurrentFrameRect(r);
+    int16_t imageType = mImage->GetType();
+    // Send frame messages (OnDataAvailable, OnStopFrame)
+    if (imageType == imgIContainer::TYPE_VECTOR ||
+        static_cast<RasterImage*>(mImage)->GetNumFrames() > 0) {
 
-    // If there's any content in this frame at all (always true for
-    // vector images, true for raster images that have decoded at
-    // least one frame) then send OnFrameUpdate.
-    if (!r.IsEmpty())
+      // OnDataAvailable
+      // XXX - Should only send partial rects here, but that needs to
+      // wait until we fix up the observer interface
+      nsIntRect r;
+      mImage->GetCurrentFrameRect(r);
       proxy->OnFrameUpdate(&r);
 
-    if (mState & stateFrameStopped)
-      proxy->OnStopFrame();
+      if (mState & stateFrameStopped)
+        proxy->OnStopFrame();
+    }
 
     // OnImageIsAnimated
     bool isAnimated = false;
 
     nsresult rv = mImage->GetAnimated(&isAnimated);
     if (NS_SUCCEEDED(rv) && isAnimated) {
       proxy->OnImageIsAnimated();
     }
@@ -467,35 +494,21 @@ imgStatusTracker::RecordLoaded()
   mImageStatus |= imgIRequest::STATUS_SIZE_AVAILABLE | imgIRequest::STATUS_LOAD_COMPLETE;
   mHadLastPart = true;
 }
 
 void
 imgStatusTracker::RecordDecoded()
 {
   NS_ABORT_IF_FALSE(mImage, "RecordDecoded called before we have an Image");
-  mState |= stateDecodeStarted | stateDecodeStopped | stateFrameStopped;
+  mState |= stateDecodeStopped | stateFrameStopped;
   mImageStatus |= imgIRequest::STATUS_FRAME_COMPLETE | imgIRequest::STATUS_DECODE_COMPLETE;
 }
 
 void
-imgStatusTracker::RecordStartDecode()
-{
-  NS_ABORT_IF_FALSE(mImage, "RecordStartDecode without an Image");
-  mState |= stateDecodeStarted;
-}
-
-void
-imgStatusTracker::SendStartDecode(imgRequestProxy* aProxy)
-{
-  if (!aProxy->NotificationsDeferred())
-    aProxy->OnStartDecode();
-}
-
-void
 imgStatusTracker::RecordStartContainer(imgIContainer* aContainer)
 {
   NS_ABORT_IF_FALSE(mImage,
                     "RecordStartContainer called before we have an Image");
   NS_ABORT_IF_FALSE(mImage == aContainer,
                     "RecordStartContainer called with wrong Image");
   mState |= stateHasSize;
   mImageStatus |= imgIRequest::STATUS_SIZE_AVAILABLE;
@@ -626,17 +639,16 @@ void
 imgStatusTracker::RecordStartRequest()
 {
   // We're starting a new load, so clear any status and state bits indicating
   // load/decode
   mImageStatus &= ~imgIRequest::STATUS_LOAD_PARTIAL;
   mImageStatus &= ~imgIRequest::STATUS_LOAD_COMPLETE;
   mImageStatus &= ~imgIRequest::STATUS_FRAME_COMPLETE;
   mState &= ~stateRequestStarted;
-  mState &= ~stateDecodeStarted;
   mState &= ~stateDecodeStopped;
   mState &= ~stateRequestStopped;
   mState &= ~stateBlockingOnload;
 
   mState |= stateRequestStarted;
 }
 
 void
@@ -688,18 +700,18 @@ imgStatusTracker::OnStopRequest(bool aLa
 
   RecordStopRequest(aLastPart, aStatus);
   /* notify the kids */
   nsTObserverArray<imgRequestProxy*>::ForwardIterator srIter(mConsumers);
   while (srIter.HasMore()) {
     SendStopRequest(srIter.GetNext(), aLastPart, aStatus);
   }
 
-  if (NS_FAILED(aStatus) && !preexistingError) {
-    FireFailureNotification();
+  if (NS_FAILED(aStatus) && !preexistingError && GetRequest()) {
+    FireFailureNotification(GetRequest());
   }
 }
 
 void
 imgStatusTracker::OnDataAvailable()
 {
   // Notify any imgRequestProxys that are observing us that we have an Image.
   nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mConsumers);
@@ -751,20 +763,12 @@ imgStatusTracker::MaybeUnblockOnload()
 
   nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mConsumers);
   while (iter.HasMore()) {
     SendUnblockOnload(iter.GetNext());
   }
 }
 
 void
-imgStatusTracker::FireFailureNotification()
+imgStatusTracker::ClearRequest()
 {
-  // Some kind of problem has happened with image decoding.
-  // Report the URI to net:failed-to-process-uri-conent observers.
-  nsIURI* uri = GetImage()->GetURI();
-  if (uri) {
-    nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
-    if (os) {
-      os->NotifyObservers(uri, "net:failed-to-process-uri-content", nullptr);
-    }
-  }
+  mRequest = nullptr;
 }
--- a/image/src/imgStatusTracker.h
+++ b/image/src/imgStatusTracker.h
@@ -3,41 +3,40 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef imgStatusTracker_h__
 #define imgStatusTracker_h__
 
 class imgIContainer;
+class imgRequest;
 class imgRequestProxy;
 class imgStatusNotifyRunnable;
 class imgRequestNotifyRunnable;
 class imgStatusTracker;
 struct nsIntRect;
 namespace mozilla {
 namespace image {
 class Image;
 } // namespace image
 } // namespace mozilla
 
 
-#include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsTObserverArray.h"
 #include "nsIRunnable.h"
 #include "nscore.h"
 #include "nsWeakReference.h"
 #include "imgIDecoderObserver.h"
 
 enum {
   stateRequestStarted    = 1u << 0,
   stateHasSize           = 1u << 1,
-  stateDecodeStarted     = 1u << 2,
   stateDecodeStopped     = 1u << 3,
   stateFrameStopped      = 1u << 4,
   stateRequestStopped    = 1u << 5,
   stateBlockingOnload    = 1u << 6
 };
 
 class imgStatusTrackerObserver : public imgIDecoderObserver,
                                  public nsSupportsWeakReference
@@ -66,40 +65,37 @@ private:
  * to imgRequestProxys, both synchronously (i.e., the status now) and
  * asynchronously (the status later).
  *
  * When a new proxy needs to be notified of the current state of an image, call
  * the Notify() method on this class with the relevant proxy as its argument,
  * and the notifications will be replayed to the proxy asynchronously.
  */
 
-class imgStatusTracker : public mozilla::RefCounted<imgStatusTracker>
+class imgStatusTracker
 {
 public:
   // aImage is the image that this status tracker will pass to the
   // imgRequestProxys in SyncNotify() and EmulateRequestFinished(), and must be
   // alive as long as this instance is, because we hold a weak reference to it.
-  imgStatusTracker(mozilla::image::Image* aImage);
+  imgStatusTracker(mozilla::image::Image* aImage, imgRequest* aRequest);
   imgStatusTracker(const imgStatusTracker& aOther);
 
   // Image-setter, for imgStatusTrackers created by imgRequest::Init, which
   // are created before their Image is created.  This method should only
   // be called once, and only on an imgStatusTracker that was initialized
   // without an image.
   void SetImage(mozilla::image::Image* aImage);
 
-  // Inform this status tracker that it is associated with a multipart image.
-  void SetIsMultipart() { mIsMultipart = true; }
-
   // Schedule an asynchronous "replaying" of all the notifications that would
   // have to happen to put us in the current state.
   // We will also take note of any notifications that happen between the time
   // Notify() is called and when we call SyncNotify on |proxy|, and replay them
   // as well.
-  void Notify(imgRequestProxy* proxy);
+  void Notify(imgRequest* request, imgRequestProxy* proxy);
 
   // Schedule an asynchronous "replaying" of all the notifications that would
   // have to happen to put us in the state we are in right now.
   // Unlike Notify(), does *not* take into account future notifications.
   // This is only useful if you do not have an imgRequest, e.g., if you are a
   // static request returned from imgIRequest::GetStaticRequest().
   void NotifyCurrentState(imgRequestProxy* proxy);
 
@@ -147,18 +143,16 @@ public:
   // StartContainer, StopRequest.
   void RecordLoaded();
 
   // Shorthand for recording all the decode notifications: StartDecode,
   // StartFrame, DataAvailable, StopFrame, StopDecode.
   void RecordDecoded();
 
   /* non-virtual imgIDecoderObserver methods */
-  void RecordStartDecode();
-  void SendStartDecode(imgRequestProxy* aProxy);
   void RecordStartContainer(imgIContainer* aContainer);
   void SendStartContainer(imgRequestProxy* aProxy);
   void RecordDataAvailable();
   void SendDataAvailable(imgRequestProxy* aProxy, const nsIntRect* aRect);
   void RecordStopFrame();
   void SendStopFrame(imgRequestProxy* aProxy);
   void RecordStopDecode(nsresult statusg);
   void SendStopDecode(imgRequestProxy* aProxy, nsresult aStatus);
@@ -187,41 +181,41 @@ public:
   // is different from all the other notifications.
   void RecordBlockOnload();
   void SendBlockOnload(imgRequestProxy* aProxy);
   void RecordUnblockOnload();
   void SendUnblockOnload(imgRequestProxy* aProxy);
 
   void MaybeUnblockOnload();
 
-  bool IsMultipart() const { return mIsMultipart; }
+  // Null out any reference to an associated image request
+  void ClearRequest();
 
   // Weak pointer getters - no AddRefs.
   inline mozilla::image::Image* GetImage() const { return mImage; }
+  inline imgRequest* GetRequest() const { return mRequest; }
 
   inline imgIDecoderObserver* GetDecoderObserver() { return mTrackerObserver.get(); }
 
 private:
   friend class imgStatusNotifyRunnable;
   friend class imgRequestNotifyRunnable;
   friend class imgStatusTrackerObserver;
 
-  void FireFailureNotification();
-
   nsCOMPtr<nsIRunnable> mRequestRunnable;
 
-  // Weak pointer to the image. The image owns the status tracker.
+  // Weak pointers to the image and request. The request owns the image, and
+  // the image (or the request, if there's no image) owns the status tracker.
   mozilla::image::Image* mImage;
+  imgRequest* mRequest;
+  uint32_t mState;
+  uint32_t mImageStatus;
+  bool mHadLastPart;
+  bool mBlockingOnload;
 
   // List of proxies attached to the image. Each proxy represents a consumer
   // using the image.
   nsTObserverArray<imgRequestProxy*> mConsumers;
 
   nsRefPtr<imgStatusTrackerObserver> mTrackerObserver;
-
-  uint32_t mState;
-  uint32_t mImageStatus;
-  bool mIsMultipart    : 1;
-  bool mHadLastPart    : 1;
-  bool mBlockingOnload : 1;
 };
 
 #endif
--- a/image/src/imgTools.cpp
+++ b/image/src/imgTools.cpp
@@ -17,17 +17,17 @@
 #include "gfxContext.h"
 #include "nsStringStream.h"
 #include "nsComponentManagerUtils.h"
 #include "nsWeakReference.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsStreamUtils.h"
 #include "nsNetUtil.h"
 #include "nsContentUtils.h"
-#include "ImageFactory.h"
+#include "RasterImage.h"
 #include "ScriptedNotificationObserver.h"
 #include "imgIScriptedNotificationObserver.h"
 
 using namespace mozilla::image;
 
 class nsIDOMDocument;
 class nsIDocument;
 
@@ -42,66 +42,71 @@ imgTools::imgTools()
   /* member initializers and constructor code */
 }
 
 imgTools::~imgTools()
 {
   /* destructor code */
 }
 
+
 NS_IMETHODIMP imgTools::DecodeImageData(nsIInputStream* aInStr,
                                         const nsACString& aMimeType,
                                         imgIContainer **aContainer)
 {
-  NS_ABORT_IF_FALSE(*aContainer == nullptr,
-                    "Cannot provide an existing image container to DecodeImageData");
-
-  return DecodeImage(aInStr, aMimeType, aContainer);
-}
-
-NS_IMETHODIMP imgTools::DecodeImage(nsIInputStream* aInStr,
-                                    const nsACString& aMimeType,
-                                    imgIContainer **aContainer)
-{
   nsresult rv;
-  nsRefPtr<Image> image;
+  RasterImage* image;  // convenience alias for *aContainer
 
   NS_ENSURE_ARG_POINTER(aInStr);
 
-  // Create a new image container to hold the decoded data.
-  nsAutoCString mimeType(aMimeType);
-  image = ImageFactory::CreateAnonymousImage(mimeType);
+  // If the caller didn't provide an imgIContainer, create one.
+  if (*aContainer) {
+    NS_ABORT_IF_FALSE((*aContainer)->GetType() == imgIContainer::TYPE_RASTER,
+                      "wrong type of imgIContainer for decoding into");
+    image = static_cast<RasterImage*>(*aContainer);
+  } else {
+    *aContainer = image = new RasterImage();
+    NS_ADDREF(image);
+  }
 
-  if (image->HasError())
-    return NS_ERROR_FAILURE;
+  // Initialize the Image. If we're using the one from the caller, we
+  // require that it not be initialized.
+  nsCString mimeType(aMimeType);
+  rv = image->Init(nullptr, mimeType.get(), "<unknown>", Image::INIT_FLAG_NONE);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  // Prepare the input stream.
   nsCOMPtr<nsIInputStream> inStream = aInStr;
   if (!NS_InputStreamIsBuffered(aInStr)) {
     nsCOMPtr<nsIInputStream> bufStream;
     rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream), aInStr, 1024);
     if (NS_SUCCEEDED(rv))
       inStream = bufStream;
   }
 
-  // Figure out how much data we've been passed.
+  // Figure out how much data we've been passed
   uint64_t length;
   rv = inStream->Available(&length);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(length <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
 
-  // Send the source data to the Image.
-  rv = image->OnImageDataAvailable(nullptr, nullptr, inStream, 0, uint32_t(length));
+  // Send the source data to the Image. WriteToRasterImage always
+  // consumes everything it gets if it doesn't run out of memory.
+  uint32_t bytesRead;
+  rv = inStream->ReadSegments(RasterImage::WriteToRasterImage,
+                              static_cast<void*>(image),
+                              (uint32_t)length, &bytesRead);
   NS_ENSURE_SUCCESS(rv, rv);
-  // Let the Image know we've sent all the data.
-  rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK);
+  NS_ABORT_IF_FALSE(bytesRead == length || image->HasError(),
+  "WriteToRasterImage should consume everything or the image must be in error!");
+
+  // Let the Image know we've sent all the data
+  rv = image->SourceDataComplete();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // All done.
-  NS_ADDREF(*aContainer = image.get());
+  // All done
   return NS_OK;
 }
 
 
 NS_IMETHODIMP imgTools::EncodeImage(imgIContainer *aContainer,
                                     const nsACString& aMimeType,
                                     const nsAString& aOutputOptions,
                                     nsIInputStream **aStream)
--- a/image/src/imgTools.h
+++ b/image/src/imgTools.h
@@ -3,21 +3,21 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "imgITools.h"
 #include "gfxContext.h"
 
 #define NS_IMGTOOLS_CID \
-{ /* 4c2383a4-931c-484d-8c4a-973590f66e3f */         \
-     0x4c2383a4,                                     \
-     0x931c,                                         \
-     0x484d,                                         \
-    {0x8c, 0x4a, 0x97, 0x35, 0x90, 0xf6, 0x6e, 0x3f} \
+{ /* fd9a9e8a-a77b-496a-b7bb-263df9715149 */         \
+     0xfd9a9e8a,                                     \
+     0xa77b,                                         \
+     0x496a,                                         \
+    {0xb7, 0xbb, 0x26, 0x3d, 0xf9, 0x71, 0x51, 0x49} \
 }
 
 class imgTools : public imgITools
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_IMGITOOLS
 
--- a/image/test/unit/test_imgtools.js
+++ b/image/test/unit/test_imgtools.js
@@ -144,18 +144,16 @@ testdesc = "test decoding a PNG";
 // 64x64 png, 8415 bytes.
 var imgName = "image1.png";
 var inMimeType = "image/png";
 var imgFile = do_get_file(imgName);
 
 var istream = getFileInputStream(imgFile);
 do_check_eq(istream.available(), 8415);
 
-// Use decodeImageData for this test even though it's deprecated to ensure that
-// it correctly forwards to decodeImage and continues to work.
 var outParam = { value: null };
 imgTools.decodeImageData(istream, inMimeType, outParam);
 var container = outParam.value;
 
 // It's not easy to look at the pixel values from JS, so just
 // check the container's size.
 do_check_eq(container.width,  64);
 do_check_eq(container.height, 64);
@@ -206,17 +204,19 @@ testdesc = "test decoding a JPEG";
 // 32x32 jpeg, 3494 bytes.
 imgName = "image2.jpg";
 inMimeType = "image/jpeg";
 imgFile = do_get_file(imgName);
 
 istream = getFileInputStream(imgFile);
 do_check_eq(istream.available(), 3494);
 
-container = imgTools.decodeImage(istream, inMimeType);
+outParam = {};
+imgTools.decodeImageData(istream, inMimeType, outParam);
+container = outParam.value;
 
 // It's not easy to look at the pixel values from JS, so just
 // check the container's size.
 do_check_eq(container.width,  32);
 do_check_eq(container.height, 32);
 
 
 /* ========== 5 ========== */
@@ -268,17 +268,19 @@ testdesc = "test decoding a ICO";
 // 16x16 ico, 1406 bytes.
 imgName = "image3.ico";
 inMimeType = "image/x-icon";
 imgFile = do_get_file(imgName);
 
 istream = getFileInputStream(imgFile);
 do_check_eq(istream.available(), 1406);
 
-container = imgTools.decodeImage(istream, inMimeType);
+outParam = { value: null };
+imgTools.decodeImageData(istream, inMimeType, outParam);
+container = outParam.value;
 
 // It's not easy to look at the pixel values from JS, so just
 // check the container's size.
 do_check_eq(container.width,  16);
 do_check_eq(container.height, 16);
 
 
 /* ========== 8 ========== */
@@ -326,17 +328,19 @@ testdesc = "test decoding a GIF";
 // 32x32 gif, 1809 bytes.
 imgName = "image4.gif";
 inMimeType = "image/gif";
 imgFile = do_get_file(imgName);
 
 istream = getFileInputStream(imgFile);
 do_check_eq(istream.available(), 1809);
 
-container = imgTools.decodeImage(istream, inMimeType);
+outParam = { value: null };
+imgTools.decodeImageData(istream, inMimeType, outParam);
+container = outParam.value;
 
 // It's not easy to look at the pixel values from JS, so just
 // check the container's size.
 do_check_eq(container.width, 32);
 do_check_eq(container.height, 32);
 
 /* ========== 11 ========== */
 testnum++;
@@ -434,17 +438,19 @@ testdesc = "test cropping a JPG";
 // 32x32 jpeg, 3494 bytes.
 imgName = "image2.jpg";
 inMimeType = "image/jpeg";
 imgFile = do_get_file(imgName);
 
 istream = getFileInputStream(imgFile);
 do_check_eq(istream.available(), 3494);
 
-container = imgTools.decodeImage(istream, inMimeType);
+outParam = {};
+imgTools.decodeImageData(istream, inMimeType, outParam);
+container = outParam.value;
 
 // It's not easy to look at the pixel values from JS, so just
 // check the container's size.
 do_check_eq(container.width,  32);
 do_check_eq(container.height, 32);
 
 // encode a cropped image
 istream = imgTools.encodeCroppedImage(container, "image/jpeg", 0, 0, 16, 16);
@@ -652,17 +658,19 @@ for(var i=0; i<testData.length; ++i) {
 
     var imgFile = do_get_file(dict["refImage"]);
     var istream = getFileInputStream(imgFile);
     var refBytes = streamToArray(istream);
 
     imgFile = do_get_file(dict["preImage"]);
     istream = getFileInputStream(imgFile);
 
-    var container = imgTools.decodeImage(istream, dict["preImageMimeType"]);
+    var outParam = { value: null };
+    imgTools.decodeImageData(istream, dict["preImageMimeType"], outParam);
+    var container = outParam.value;
 
     istream = imgTools.encodeImage(container, dict["refImageMimeType"]);
 
     var sstream = Cc["@mozilla.org/storagestream;1"].
 	          createInstance(Ci.nsIStorageStream);
     sstream.init(4096, 4294967295, null);
     var ostream = sstream.getOutputStream(0);
     var bostream = Cc["@mozilla.org/network/buffered-output-stream;1"].
@@ -688,19 +696,21 @@ imgName = "bug413512.ico";
 inMimeType = "image/x-icon";
 imgFile = do_get_file(imgName);
 
 istream = getFileInputStream(imgFile);
 do_check_eq(istream.available(), 17759);
 var errsrc = "none";
 
 try {
-  container = imgTools.decodeImage(istream, inMimeType);
+  outParam = { value: null };
+  imgTools.decodeImageData(istream, inMimeType, outParam);
+  container = outParam.value;
 
-  // We should never hit this - decodeImage throws an assertion because the
+  // 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;
       errsrc = "encode";
   }
 } catch (e) {
@@ -718,17 +728,19 @@ testdesc = "test correct ico hotspots (b
 
 imgName = "bug815359.ico";
 inMimeType = "image/x-icon";
 imgFile = do_get_file(imgName);
 
 istream = getFileInputStream(imgFile);
 do_check_eq(istream.available(), 4286);
 
-container = imgTools.decodeImage(istream, inMimeType);
+outParam = { value: null };
+imgTools.decodeImageData(istream, inMimeType, outParam);
+container = outParam.value;
 
 var props = container.QueryInterface(Ci.nsIProperties);
 
 do_check_eq(props.get("hotspotX", Ci.nsISupportsPRUint32).data, 10);
 do_check_eq(props.get("hotspotY", Ci.nsISupportsPRUint32).data, 9);
 
 
 /* ========== end ========== */