Bug 1065818 - Clean up memory reports and use of decoded size for image cache entries. r=tn,njn
☠☠ backed out by daab9019a617 ☠ ☠
authorSeth Fowler <seth@mozilla.com>
Tue, 25 Nov 2014 02:13:46 -0800
changeset 217462 2d6db5d2f985e0993d6f4cef7bf6801c9204c436
parent 217461 f8188964544599190714eea76aadd383ee532bba
child 217463 76097ee6d6f9630e109616d413daf560aeeb8312
push idunknown
push userunknown
push dateunknown
reviewerstn, njn
bugs1065818
milestone36.0a1
Bug 1065818 - Clean up memory reports and use of decoded size for image cache entries. r=tn,njn
image/src/DynamicImage.cpp
image/src/DynamicImage.h
image/src/FrameBlender.cpp
image/src/FrameBlender.h
image/src/Image.cpp
image/src/Image.h
image/src/ImageWrapper.cpp
image/src/ImageWrapper.h
image/src/RasterImage.cpp
image/src/RasterImage.h
image/src/SurfaceCache.cpp
image/src/VectorImage.cpp
image/src/VectorImage.h
image/src/imgFrame.cpp
image/src/imgFrame.h
image/src/imgLoader.cpp
image/src/imgRequest.cpp
image/src/imgRequest.h
image/src/imgRequestProxy.cpp
--- a/image/src/DynamicImage.cpp
+++ b/image/src/DynamicImage.cpp
@@ -38,51 +38,27 @@ DynamicImage::GetProgressTracker()
 
 nsIntRect
 DynamicImage::FrameRect(uint32_t aWhichFrame)
 {
   gfxIntSize size(mDrawable->Size());
   return nsIntRect(0, 0, size.width, size.height);
 }
 
-uint32_t
-DynamicImage::SizeOfData()
-{
-  // We don't know the answer to this (and the same goes for the other
-  // memory-related methods) since gfxDrawable doesn't expose a way to check.
-  return 0;
-}
-
 size_t
-DynamicImage::HeapSizeOfSourceWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const
+DynamicImage::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
 {
   return 0;
 }
 
 size_t
-DynamicImage::HeapSizeOfDecodedWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const
-{
-  return 0;
-}
-
-size_t
-DynamicImage::NonHeapSizeOfDecoded() const
+DynamicImage::SizeOfDecoded(gfxMemoryLocation aLocation,
+                            MallocSizeOf aMallocSizeOf) const
 {
-  return 0;
-}
-
-size_t
-DynamicImage::OutOfProcessSizeOfDecoded() const
-{
-  return 0;
-}
-
-size_t
-DynamicImage::HeapSizeOfVectorImageDocument(nsACString* aDocURL) const
-{
+  // We don't know the answer since gfxDrawable doesn't expose this information.
   return 0;
 }
 
 void
 DynamicImage::IncrementAnimationConsumers()
 { }
 
 void
--- a/image/src/DynamicImage.h
+++ b/image/src/DynamicImage.h
@@ -32,22 +32,19 @@ public:
   }
 
   // Inherited methods from Image.
   virtual nsresult Init(const char* aMimeType, uint32_t aFlags) MOZ_OVERRIDE;
 
   virtual already_AddRefed<ProgressTracker> GetProgressTracker() MOZ_OVERRIDE;
   virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
 
-  virtual uint32_t SizeOfData() MOZ_OVERRIDE;
-  virtual size_t HeapSizeOfSourceWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
-  virtual size_t HeapSizeOfDecodedWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
-  virtual size_t NonHeapSizeOfDecoded() const MOZ_OVERRIDE;
-  virtual size_t OutOfProcessSizeOfDecoded() const MOZ_OVERRIDE;
-  virtual size_t HeapSizeOfVectorImageDocument(nsACString* aDocURL = nullptr) const MOZ_OVERRIDE;
+  virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
+  virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation,
+                               MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
 
   virtual void IncrementAnimationConsumers() MOZ_OVERRIDE;
   virtual void DecrementAnimationConsumers() MOZ_OVERRIDE;
 #ifdef DEBUG
   virtual uint32_t GetAnimationConsumers() MOZ_OVERRIDE;
 #endif
 
   virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
--- a/image/src/FrameBlender.cpp
+++ b/image/src/FrameBlender.cpp
@@ -558,36 +558,33 @@ FrameBlender::Discard()
   // timers are cancelled.
   NS_ABORT_IF_FALSE(!mAnim, "Asked to discard for animated image!");
 
   // Delete all the decoded frames, then clear the array.
   ClearFrames();
 }
 
 size_t
-FrameBlender::SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
-                                                      MallocSizeOf aMallocSizeOf) const
+FrameBlender::SizeOfDecoded(gfxMemoryLocation aLocation,
+                            MallocSizeOf aMallocSizeOf) const
 {
   size_t n = 0;
 
   for (uint32_t i = 0; i < mFrames.Length(); ++i) {
-    n += mFrames[i]->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation,
-                                                                   aMallocSizeOf);
+    n += mFrames[i]->SizeOfExcludingThis(aLocation, aMallocSizeOf);
   }
 
   if (mAnim) {
     if (mAnim->compositingFrame) {
       n += mAnim->compositingFrame
-                ->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation,
-                                                                aMallocSizeOf);
+                ->SizeOfExcludingThis(aLocation, aMallocSizeOf);
     }
     if (mAnim->compositingPrevFrame) {
       n += mAnim->compositingPrevFrame
-                ->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation,
-                                                                aMallocSizeOf);
+                ->SizeOfExcludingThis(aLocation, aMallocSizeOf);
     }
   }
 
   return n;
 }
 
 void
 FrameBlender::ResetAnimation()
--- a/image/src/FrameBlender.h
+++ b/image/src/FrameBlender.h
@@ -67,18 +67,18 @@ public:
    */
   void SetLoopCount(int32_t aLoopCount);
   int32_t GetLoopCount() const;
 
   void Discard();
 
   void SetSize(nsIntSize aSize) { mSize = aSize; }
 
-  size_t SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
-                                                 MallocSizeOf aMallocSizeOf) const;
+  size_t SizeOfDecoded(gfxMemoryLocation aLocation,
+                       MallocSizeOf aMallocSizeOf) const;
 
   void ResetAnimation();
 
   // "Blend" method indicates how the current image is combined with the
   // previous image.
   enum FrameBlendMethod {
     // All color components of the frame, including alpha, overwrite the current
     // contents of the frame's output buffer region
--- a/image/src/Image.cpp
+++ b/image/src/Image.cpp
@@ -19,31 +19,16 @@ ImageResource::ImageResource(ImageURL* a
   mAnimationConsumers(0),
   mAnimationMode(kNormalAnimMode),
   mInitialized(false),
   mAnimating(false),
   mError(false)
 {
 }
 
-uint32_t
-ImageResource::SizeOfData()
-{
-  if (mError)
-    return 0;
-
-  // This is not used by memory reporters, but for sizing the cache, which is
-  // why it uses |moz_malloc_size_of| rather than a
-  // |MOZ_DEFINE_MALLOC_SIZE_OF|.
-  return uint32_t(HeapSizeOfSourceWithComputedFallback(moz_malloc_size_of) +
-                  HeapSizeOfDecodedWithComputedFallback(moz_malloc_size_of) +
-                  NonHeapSizeOfDecoded() +
-                  OutOfProcessSizeOfDecoded());
-}
-
 // Translates a mimetype into a concrete decoder
 Image::eDecoderType
 Image::GetDecoderType(const char *aMimeType)
 {
   // By default we don't know
   eDecoderType rv = eDecoderType_unknown;
 
   // PNG
--- a/image/src/Image.h
+++ b/image/src/Image.h
@@ -2,16 +2,17 @@
 /* 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 MOZILLA_IMAGELIB_IMAGE_H_
 #define MOZILLA_IMAGELIB_IMAGE_H_
 
 #include "mozilla/MemoryReporting.h"
+#include "gfx2DGlue.h"                // for gfxMemoryLocation
 #include "imgIContainer.h"
 #include "ProgressTracker.h"
 #include "ImageURL.h"
 #include "nsStringFwd.h"
 
 class nsIRequest;
 class nsIInputStream;
 
@@ -67,35 +68,27 @@ public:
   virtual void SetProgressTracker(ProgressTracker* aProgressTracker) {}
 
   /**
    * The rectangle defining the location and size of the given frame.
    */
   virtual nsIntRect FrameRect(uint32_t aWhichFrame) = 0;
 
   /**
-   * The size, in bytes, occupied by the significant data portions of the image.
-   * This includes both compressed source data and decoded frames.
+   * The size, in bytes, occupied by the compressed source data of the image.
+   * If MallocSizeOf does not work on this platform, uses a fallback approach to
+   * ensure that something reasonable is always returned.
    */
-  virtual uint32_t SizeOfData() = 0;
+  virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const = 0;
 
   /**
-   * The components that make up SizeOfData().
+   * The size, in bytes, occupied by the image's decoded data.
    */
-  virtual size_t HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const = 0;
-  virtual size_t HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const = 0;
-  virtual size_t NonHeapSizeOfDecoded() const = 0;
-  virtual size_t OutOfProcessSizeOfDecoded() const = 0;
-
-  /**
-   * Gets the size of the memory taken up for the parsed vector image's
-   * document (e.g. SVGDocument), and returns the document's URL via the
-   * aDocURL outparam.
-   */
-  virtual size_t HeapSizeOfVectorImageDocument(nsACString* aDocURL = nullptr) const = 0;
+  virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation,
+                               MallocSizeOf aMallocSizeOf) const = 0;
 
   virtual void IncrementAnimationConsumers() = 0;
   virtual void DecrementAnimationConsumers() = 0;
 #ifdef DEBUG
   virtual uint32_t GetAnimationConsumers() = 0;
 #endif
 
   /**
@@ -151,17 +144,16 @@ public:
     MOZ_ASSERT(progressTracker);
     return progressTracker.forget();
   }
   void SetProgressTracker(ProgressTracker* aProgressTracker) MOZ_OVERRIDE MOZ_FINAL {
     MOZ_ASSERT(aProgressTracker);
     MOZ_ASSERT(!mProgressTracker);
     mProgressTracker = aProgressTracker;
   }
-  virtual uint32_t SizeOfData() MOZ_OVERRIDE;
 
   virtual void IncrementAnimationConsumers() MOZ_OVERRIDE;
   virtual void DecrementAnimationConsumers() MOZ_OVERRIDE;
 #ifdef DEBUG
   virtual uint32_t GetAnimationConsumers() MOZ_OVERRIDE { return mAnimationConsumers; }
 #endif
 
   virtual void SetInnerWindowID(uint64_t aInnerWindowId) MOZ_OVERRIDE {
--- a/image/src/ImageWrapper.cpp
+++ b/image/src/ImageWrapper.cpp
@@ -34,44 +34,27 @@ ImageWrapper::GetProgressTracker()
 }
 
 nsIntRect
 ImageWrapper::FrameRect(uint32_t aWhichFrame)
 {
   return mInnerImage->FrameRect(aWhichFrame);
 }
 
-uint32_t
-ImageWrapper::SizeOfData()
+size_t
+ImageWrapper::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
 {
-  return mInnerImage->SizeOfData();
-}
-
-size_t
-ImageWrapper::HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
-{
-  return mInnerImage->HeapSizeOfSourceWithComputedFallback(aMallocSizeOf);
+  return mInnerImage->SizeOfSourceWithComputedFallback(aMallocSizeOf);
 }
 
 size_t
-ImageWrapper::HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const
-{
-  return mInnerImage->HeapSizeOfDecodedWithComputedFallback(aMallocSizeOf);
-}
-
-size_t
-ImageWrapper::NonHeapSizeOfDecoded() const
+ImageWrapper::SizeOfDecoded(gfxMemoryLocation aLocation,
+                            MallocSizeOf aMallocSizeOf) const
 {
-  return mInnerImage->NonHeapSizeOfDecoded();
-}
-
-size_t
-ImageWrapper::OutOfProcessSizeOfDecoded() const
-{
-  return mInnerImage->OutOfProcessSizeOfDecoded();
+  return mInnerImage->SizeOfDecoded(aLocation, aMallocSizeOf);
 }
 
 void
 ImageWrapper::IncrementAnimationConsumers()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Main thread only to encourage serialization "
                                 "with DecrementAnimationConsumers");
   mInnerImage->IncrementAnimationConsumers();
--- a/image/src/ImageWrapper.h
+++ b/image/src/ImageWrapper.h
@@ -22,25 +22,18 @@ public:
   NS_DECL_IMGICONTAINER
 
   // Inherited methods from Image.
   virtual nsresult Init(const char* aMimeType, uint32_t aFlags) MOZ_OVERRIDE;
 
   virtual already_AddRefed<ProgressTracker> GetProgressTracker() MOZ_OVERRIDE;
   virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
 
-  virtual uint32_t SizeOfData() MOZ_OVERRIDE;
-  virtual size_t HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
-  virtual size_t HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
-  virtual size_t NonHeapSizeOfDecoded() const MOZ_OVERRIDE;
-  virtual size_t OutOfProcessSizeOfDecoded() const MOZ_OVERRIDE;
-
-  virtual size_t HeapSizeOfVectorImageDocument(nsACString* aDocURL = nullptr) const MOZ_OVERRIDE {
-    return mInnerImage->HeapSizeOfVectorImageDocument(aDocURL);
-  }
+  virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
+  virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation, MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE; 
 
   virtual void IncrementAnimationConsumers() MOZ_OVERRIDE;
   virtual void DecrementAnimationConsumers() MOZ_OVERRIDE;
 #ifdef DEBUG
   virtual uint32_t GetAnimationConsumers() MOZ_OVERRIDE;
 #endif
 
   virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -959,63 +959,41 @@ RasterImage::UpdateImageContainer()
   if (!image) {
     return;
   }
 
   mImageContainer->SetCurrentImage(image);
 }
 
 size_t
-RasterImage::HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
+RasterImage::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
 {
   // n == 0 is possible for two reasons.
   // - This is a zero-length image.
   // - We're on a platform where moz_malloc_size_of always returns 0.
   // In either case the fallback works appropriately.
   size_t n = mSourceData.SizeOfExcludingThis(aMallocSizeOf);
   if (n == 0) {
     n = mSourceData.Length();
   }
   return n;
 }
 
 size_t
-RasterImage::SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
-                                                     MallocSizeOf aMallocSizeOf) const
+RasterImage::SizeOfDecoded(gfxMemoryLocation aLocation,
+                           MallocSizeOf aMallocSizeOf) const
 {
   size_t n = 0;
   n += SurfaceCache::SizeOfSurfaces(ImageKey(this), aLocation, aMallocSizeOf);
   if (mFrameBlender) {
-    n += mFrameBlender->SizeOfDecodedWithComputedFallbackIfHeap(aLocation,
-                                                                aMallocSizeOf);
+    n += mFrameBlender->SizeOfDecoded(aLocation, aMallocSizeOf);
   }
   return n;
 }
 
-size_t
-RasterImage::HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const
-{
-  return SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation::IN_PROCESS_HEAP,
-                                                 aMallocSizeOf);
-}
-
-size_t
-RasterImage::NonHeapSizeOfDecoded() const
-{
-  return SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation::IN_PROCESS_NONHEAP,
-                                                 nullptr);
-}
-
-size_t
-RasterImage::OutOfProcessSizeOfDecoded() const
-{
-  return SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation::OUT_OF_PROCESS,
-                                                 nullptr);
-}
-
 RawAccessFrameRef
 RasterImage::InternalAddFrame(uint32_t aFrameNum,
                               const nsIntRect& aFrameRect,
                               uint32_t aDecodeFlags,
                               SurfaceFormat aFormat,
                               uint8_t aPaletteDepth,
                               imgFrame* aPreviousFrame)
 {
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -166,24 +166,19 @@ public:
   static NS_METHOD WriteToRasterImage(nsIInputStream* aIn, void* aClosure,
                                       const char* aFromRawSegment,
                                       uint32_t aToOffset, uint32_t aCount,
                                       uint32_t* aWriteCount);
 
   /* The total number of frames in this image. */
   uint32_t GetNumFrames() const;
 
-  virtual size_t HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const;
-  virtual size_t HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const;
-  virtual size_t NonHeapSizeOfDecoded() const;
-  virtual size_t OutOfProcessSizeOfDecoded() const;
-
-  virtual size_t HeapSizeOfVectorImageDocument(nsACString* aDocURL = nullptr) const MOZ_OVERRIDE {
-    return 0;
-  }
+  virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const;
+  virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation,
+                               MallocSizeOf aMallocSizeOf) const;
 
   /* Triggers discarding. */
   void Discard(bool aForce = false, bool aNotify = true);
   void ForceDiscard() { Discard(/* aForce = */ true); }
 
   /* Callbacks for decoders */
   /** Sets the size and inherent orientation of the container. This should only
    * be called by the decoder. This function may be called multiple times, but
--- a/image/src/SurfaceCache.cpp
+++ b/image/src/SurfaceCache.cpp
@@ -170,19 +170,18 @@ public:
 
     void Add(CachedSurface* aCachedSurface)
     {
       MOZ_ASSERT(aCachedSurface, "Should have a CachedSurface");
 
       if (!aCachedSurface->mSurface) {
         return;
       }
-
-      mSum += aCachedSurface->mSurface->
-        SizeOfExcludingThisWithComputedFallbackIfHeap(mLocation, mMallocSizeOf);
+      mSum += aCachedSurface->mSurface->SizeOfExcludingThis(mLocation,
+                                                            mMallocSizeOf);
     }
 
     size_t Result() const { return mSum; }
 
   private:
     gfxMemoryLocation mLocation;
     MallocSizeOf      mMallocSizeOf;
     size_t            mSum;
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -361,79 +361,43 @@ VectorImage::Init(const char* aMimeType,
 
 nsIntRect
 VectorImage::FrameRect(uint32_t aWhichFrame)
 {
   return nsIntRect::GetMaxSizedIntRect();
 }
 
 size_t
-VectorImage::HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
+VectorImage::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
 {
-  // We're not storing the source data -- we just feed that directly to
-  // our helper SVG document as we receive it, for it to parse.
-  // So 0 is an appropriate return value here.
-  // If implementing this, we'll need to restructure our callers to make sure
-  // any amount we return is attributed to the vector images measure (i.e.
-  // "explicit/images/{content,chrome}/vector/{used,unused}/...")
-  return 0;
-}
+  nsIDocument* doc = mSVGDocumentWrapper->GetDocument();
+  if (!doc) {
+    return 0; // No document, so no memory used for the document.
+  }
+
+  nsWindowSizes windowSizes(aMallocSizeOf);
+  doc->DocAddSizeOfIncludingThis(&windowSizes);
 
-size_t
-VectorImage::HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const
-{
-  // If implementing this, we'll need to restructure our callers to make sure
-  // any amount we return is attributed to the vector images measure (i.e.
-  // "explicit/images/{content,chrome}/vector/{used,unused}/...")
-  // XXX(seth): Same goes for the other *SizeOfDecoded() methods. We'll do this
-  // in bug 921300 or one of its blockers. For now it seems worthwhile to get
-  // this memory accounted for, even if it gets listed under 'raster'. It does
-  // make some perverse sense, since we are after all reporting on raster data
-  // here - it just happens to be computed from a vector document.
-  return SurfaceCache::SizeOfSurfaces(ImageKey(this),
-                                      gfxMemoryLocation::IN_PROCESS_HEAP,
-                                      aMallocSizeOf);
+  if (windowSizes.getTotalSize() == 0) {
+    // MallocSizeOf fails on this platform. Because we also use this method for
+    // determining the size of cache entries, we need to return something
+    // reasonable here. Unfortunately, there's no way to estimate the document's
+    // size accurately, so we just use a constant value of 100KB, which will
+    // generally underestimate the true size.
+    return 100 * 1024;
+  }
+
+  return windowSizes.getTotalSize();
 }
 
 size_t
-VectorImage::NonHeapSizeOfDecoded() const
-{
-  return SurfaceCache::SizeOfSurfaces(ImageKey(this),
-                                      gfxMemoryLocation::IN_PROCESS_NONHEAP,
-                                      nullptr);
-}
-
-size_t
-VectorImage::OutOfProcessSizeOfDecoded() const
+VectorImage::SizeOfDecoded(gfxMemoryLocation aLocation,
+                           MallocSizeOf aMallocSizeOf) const
 {
-  return SurfaceCache::SizeOfSurfaces(ImageKey(this),
-                                      gfxMemoryLocation::OUT_OF_PROCESS,
-                                      nullptr);
-}
-
-MOZ_DEFINE_MALLOC_SIZE_OF(WindowsMallocSizeOf);
-
-size_t
-VectorImage::HeapSizeOfVectorImageDocument(nsACString* aDocURL) const
-{
-  nsIDocument* doc = mSVGDocumentWrapper->GetDocument();
-  if (!doc) {
-    if (aDocURL) {
-      mURI->GetSpec(*aDocURL);
-    }
-    return 0; // No document, so no memory used for the document
-  }
-
-  if (aDocURL) {
-    doc->GetDocumentURI()->GetSpec(*aDocURL);
-  }
-
-  nsWindowSizes windowSizes(WindowsMallocSizeOf);
-  doc->DocAddSizeOfIncludingThis(&windowSizes);
-  return windowSizes.getTotalSize();
+  return SurfaceCache::SizeOfSurfaces(ImageKey(this), aLocation, aMallocSizeOf);
 }
 
 nsresult
 VectorImage::OnImageDataComplete(nsIRequest* aRequest,
                                  nsISupports* aContext,
                                  nsresult aStatus,
                                  bool aLastPart)
 {
--- a/image/src/VectorImage.h
+++ b/image/src/VectorImage.h
@@ -37,22 +37,19 @@ public:
 
   // (no public constructor - use ImageFactory)
 
   // Methods inherited from Image
   nsresult Init(const char* aMimeType,
                 uint32_t aFlags);
   virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
 
-  virtual size_t HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const;
-  virtual size_t HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const;
-  virtual size_t NonHeapSizeOfDecoded() const;
-  virtual size_t OutOfProcessSizeOfDecoded() const;
-
-  virtual size_t HeapSizeOfVectorImageDocument(nsACString* aDocURL = nullptr) const MOZ_OVERRIDE;
+  virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
+  virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation,
+                               MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
 
   virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
                                         nsISupports* aContext,
                                         nsIInputStream* aInStr,
                                         uint64_t aSourceOffset,
                                         uint32_t aCount) MOZ_OVERRIDE;
   virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
                                        nsISupports* aContext,
--- a/image/src/imgFrame.cpp
+++ b/image/src/imgFrame.cpp
@@ -900,39 +900,32 @@ bool imgFrame::GetCompositingFailed() co
   return mCompositingFailed;
 }
 
 void imgFrame::SetCompositingFailed(bool val)
 {
   mCompositingFailed = val;
 }
 
-// If |aLocation| indicates this is heap memory, we try to measure things with
-// |aMallocSizeOf|.  If that fails (because the platform doesn't support it) or
-// it's non-heap memory, we fall back to computing the size analytically.
 size_t
-imgFrame::SizeOfExcludingThisWithComputedFallbackIfHeap(gfxMemoryLocation aLocation, MallocSizeOf aMallocSizeOf) const
+imgFrame::SizeOfExcludingThis(gfxMemoryLocation aLocation,
+                              MallocSizeOf aMallocSizeOf) const
 {
   // aMallocSizeOf is only used if aLocation==gfxMemoryLocation::IN_PROCESS_HEAP.  It
   // should be nullptr otherwise.
   NS_ABORT_IF_FALSE(
     (aLocation == gfxMemoryLocation::IN_PROCESS_HEAP &&  aMallocSizeOf) ||
     (aLocation != gfxMemoryLocation::IN_PROCESS_HEAP && !aMallocSizeOf),
     "mismatch between aLocation and aMallocSizeOf");
 
   size_t n = 0;
 
   if (mPalettedImageData && aLocation == gfxMemoryLocation::IN_PROCESS_HEAP) {
-    size_t n2 = aMallocSizeOf(mPalettedImageData);
-    if (n2 == 0) {
-      n2 = GetImageDataLength() + PaletteDataLength();
-    }
-    n += n2;
+    n += aMallocSizeOf(mPalettedImageData);
   }
-
   if (mImageSurface && aLocation == gfxMemoryLocation::IN_PROCESS_HEAP) {
     n += aMallocSizeOf(mImageSurface);
   }
   if (mOptSurface && aLocation == gfxMemoryLocation::IN_PROCESS_HEAP) {
     n += aMallocSizeOf(mOptSurface);
   }
 
   if (mVBuf && aLocation == gfxMemoryLocation::IN_PROCESS_HEAP) {
--- a/image/src/imgFrame.h
+++ b/image/src/imgFrame.h
@@ -126,19 +126,18 @@ public:
 
   bool IsSinglePixel()
   {
     return mSinglePixel;
   }
 
   TemporaryRef<SourceSurface> CachedSurface();
 
-  size_t SizeOfExcludingThisWithComputedFallbackIfHeap(
-           gfxMemoryLocation aLocation,
-           MallocSizeOf aMallocSizeOf) const;
+  size_t SizeOfExcludingThis(gfxMemoryLocation aLocation,
+                             MallocSizeOf aMallocSizeOf) const;
 
   uint8_t GetPaletteDepth() const { return mPaletteDepth; }
   uint32_t PaletteDataLength() const {
     if (!mPaletteDepth)
       return 0;
 
     return ((1 << mPaletteDepth) * sizeof(uint32_t));
   }
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -49,95 +49,60 @@
 using namespace mozilla;
 using namespace mozilla::image;
 using namespace mozilla::net;
 
 MOZ_DEFINE_MALLOC_SIZE_OF(ImagesMallocSizeOf)
 
 class imgMemoryReporter MOZ_FINAL : public nsIMemoryReporter
 {
-  ~imgMemoryReporter() {}
+  ~imgMemoryReporter() { }
 
 public:
   NS_DECL_ISUPPORTS
 
-  NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aHandleReport,
-                            nsISupports *aData, bool aAnonymize)
+  NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
+                            nsISupports* aData, bool aAnonymize)
   {
     nsresult rv;
-    ImageSizes chrome;
-    ImageSizes content;
-    ImageSizes uncached;
+    nsTArray<ImageMemoryCounter> chrome;
+    nsTArray<ImageMemoryCounter> content;
+    nsTArray<ImageMemoryCounter> uncached;
 
     for (uint32_t i = 0; i < mKnownLoaders.Length(); i++) {
-      mKnownLoaders[i]->mChromeCache.EnumerateRead(EntryImageSizes, &chrome);
-      mKnownLoaders[i]->mCache.EnumerateRead(EntryImageSizes, &content);
+      mKnownLoaders[i]->mChromeCache.EnumerateRead(DoRecordCounter, &chrome);
+      mKnownLoaders[i]->mCache.EnumerateRead(DoRecordCounter, &content);
       MutexAutoLock lock(mKnownLoaders[i]->mUncachedImagesMutex);
-      mKnownLoaders[i]->mUncachedImages.EnumerateEntries(EntryUncachedImageSizes, &uncached);
+      mKnownLoaders[i]->
+        mUncachedImages.EnumerateEntries(DoRecordCounterUncached, &uncached);
     }
 
     // Note that we only need to anonymize content image URIs.
 
-    rv = ReportInfoArray(aHandleReport, aData, chrome.mRasterUsedImageInfo,
-                         "images/chrome/raster/used");
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = ReportInfoArray(aHandleReport, aData, chrome.mRasterUnusedImageInfo,
-                         "images/chrome/raster/unused");
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = ReportInfoArray(aHandleReport, aData, chrome.mVectorUsedImageDocInfo,
-                         "images/chrome/vector/used/documents");
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = ReportInfoArray(aHandleReport, aData, chrome.mVectorUnusedImageDocInfo,
-                         "images/chrome/vector/unused/documents");
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = ReportInfoArray(aHandleReport, aData, content.mRasterUsedImageInfo,
-                         "images/content/raster/used", aAnonymize);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = ReportInfoArray(aHandleReport, aData, content.mRasterUnusedImageInfo,
-                         "images/content/raster/unused", aAnonymize);
+    rv = ReportCounterArray(aHandleReport, aData, chrome, "images/chrome");
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = ReportInfoArray(aHandleReport, aData, content.mVectorUsedImageDocInfo,
-                         "images/content/vector/used/documents", aAnonymize);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = ReportInfoArray(aHandleReport, aData, content.mVectorUnusedImageDocInfo,
-                         "images/content/vector/unused/documents", aAnonymize);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // The uncached images can contain both content and chrome images, so anonymize it.
-    rv = ReportInfoArray(aHandleReport, aData, uncached.mRasterUsedImageInfo,
-                         "images/uncached/raster/used", aAnonymize);
+    rv = ReportCounterArray(aHandleReport, aData, content,
+                            "images/content", aAnonymize);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = ReportInfoArray(aHandleReport, aData, uncached.mRasterUnusedImageInfo,
-                         "images/uncached/raster/unused", aAnonymize);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = ReportInfoArray(aHandleReport, aData, uncached.mVectorUsedImageDocInfo,
-                         "images/uncached/vector/used/documents", aAnonymize);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = ReportInfoArray(aHandleReport, aData, uncached.mVectorUnusedImageDocInfo,
-                         "images/uncached/vector/unused/documents", aAnonymize);
+    // Uncached images may be content or chrome, so anonymize them.
+    rv = ReportCounterArray(aHandleReport, aData, uncached,
+                            "images/uncached", aAnonymize);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 
   static int64_t ImagesContentUsedUncompressedDistinguishedAmount()
   {
     size_t n = 0;
     for (uint32_t i = 0; i < imgLoader::sMemReporter->mKnownLoaders.Length(); i++) {
-      imgLoader::sMemReporter->mKnownLoaders[i]->mCache.EnumerateRead(EntryUsedUncompressedSize, &n);
+      imgLoader::sMemReporter->mKnownLoaders[i]->
+        mCache.EnumerateRead(DoRecordCounterUsedDecoded, &n);
     }
     return n;
   }
 
   void RegisterLoader(imgLoader* aLoader)
   {
     mKnownLoaders.AppendElement(aLoader);
   }
@@ -145,316 +110,353 @@ public:
   void UnregisterLoader(imgLoader* aLoader)
   {
     mKnownLoaders.RemoveElement(aLoader);
   }
 
 private:
   nsTArray<imgLoader*> mKnownLoaders;
 
-  struct RasterSizes
+  struct MemoryCounter
   {
-    size_t mRaw;
-    size_t mUncompressedHeap;
-    size_t mUncompressedNonheap;
-
-    RasterSizes()
-      : mRaw(0)
-      , mUncompressedHeap(0)
-      , mUncompressedNonheap(0)
-    {}
-
-    void add(const RasterSizes &aOther)
+    MemoryCounter()
+      : mSource(0)
+      , mDecodedHeap(0)
+      , mDecodedNonHeap(0)
+    { }
+
+    void SetSource(size_t aCount) { mSource = aCount; }
+    size_t Source() const { return mSource; }
+    void SetDecodedHeap(size_t aCount) { mDecodedHeap = aCount; }
+    size_t DecodedHeap() const { return mDecodedHeap; }
+    void SetDecodedNonHeap(size_t aCount) { mDecodedNonHeap = aCount; }
+    size_t DecodedNonHeap() const { return mDecodedNonHeap; }
+
+    MemoryCounter& operator+=(const MemoryCounter& aOther)
     {
-      mRaw += aOther.mRaw;
-      mUncompressedHeap += aOther.mUncompressedHeap;
-      mUncompressedNonheap += aOther.mUncompressedNonheap;
+      mSource += aOther.mSource;
+      mDecodedHeap += aOther.mDecodedHeap;
+      mDecodedNonHeap += aOther.mDecodedNonHeap;
+      return *this;
     }
 
-    bool isNotable() const
+  private:
+    size_t mSource;
+    size_t mDecodedHeap;
+    size_t mDecodedNonHeap;
+  };
+
+  struct ImageMemoryCounter
+  {
+    ImageMemoryCounter(uint16_t aType, const nsACString& aURI, bool aIsUsed)
+      : mURI(aURI)
+      , mType(aType)
+      , mIsUsed(aIsUsed)
+    {
+      MOZ_ASSERT(!mURI.IsEmpty(), "Should have a URI for all images");
+    }
+
+    nsCString& URI() { return mURI; }
+    const nsCString& URI() const { return mURI; }
+    uint16_t Type() const { return mType; }
+    MemoryCounter& Values() { return mValues; }
+    const MemoryCounter& Values() const { return mValues; }
+    bool IsUsed() const { return mIsUsed; }
+
+    bool IsNotable() const
     {
       const size_t NotableThreshold = 16 * 1024;
-      size_t total = mRaw + mUncompressedHeap + mUncompressedNonheap;
-      return total >= NotableThreshold;
-    }
-  };
-
-  struct VectorDocSizes
-  {
-    size_t mSize;
-
-    VectorDocSizes()
-      : mSize(0)
-    {}
-
-    void add(const VectorDocSizes &aOther)
-    {
-      mSize += aOther.mSize;
-    }
-
-    bool isNotable() const
-    {
-      const size_t NotableThreshold = 16 * 1024;
-      size_t total = mSize;
+      size_t total = mValues.Source() + mValues.DecodedHeap()
+                                      + mValues.DecodedNonHeap();
       return total >= NotableThreshold;
     }
-  };
-
-  template <typename ImageSizes>
-  struct ImageInfo
-  {
-    ImageSizes mSizes;
+
+  private:
     nsCString mURI;
-  };
-
-  struct ImageSizes
-  {
-    nsTArray<ImageInfo<RasterSizes> >    mRasterUsedImageInfo;
-    nsTArray<ImageInfo<RasterSizes> >    mRasterUnusedImageInfo;
-    nsTArray<ImageInfo<VectorDocSizes> > mVectorUsedImageDocInfo;
-    nsTArray<ImageInfo<VectorDocSizes> > mVectorUnusedImageDocInfo;
+    uint16_t mType;
+    MemoryCounter mValues;
+    bool mIsUsed;
   };
 
-  // Definitions specialized for raster and vector images are below.
-  template<typename Sizes>
-  nsresult ReportSizes(nsIMemoryReporterCallback *aHandleReport,
-                       nsISupports *aData,
-                       const nsACString &aPathPrefix,
-                       const nsACString &aLocation,
-                       Sizes aSizes);
-
-  // This is used to report all images of a single kind, e.g. all
-  // "chrome/raster/used" images.
-  template <typename Sizes>
-  nsresult ReportInfoArray(nsIMemoryReporterCallback *aHandleReport,
-                           nsISupports *aData,
-                           const nsTArray<ImageInfo<Sizes> > &aInfoArray,
-                           const char *aPathPartStr, bool aAnonymize = false)
+  struct MemoryTotal
+  {
+    MemoryTotal& operator+=(const ImageMemoryCounter& aImageCounter)
+    {
+      if (aImageCounter.Type() == imgIContainer::TYPE_RASTER) {
+        if (aImageCounter.IsUsed()) {
+          mUsedRasterCounter += aImageCounter.Values();
+        } else {
+          mUnusedRasterCounter += aImageCounter.Values();
+        }
+      } else if (aImageCounter.Type() == imgIContainer::TYPE_VECTOR) {
+        if (aImageCounter.IsUsed()) {
+          mUsedVectorCounter += aImageCounter.Values();
+        } else {
+          mUnusedVectorCounter += aImageCounter.Values();
+        }
+      } else {
+        MOZ_CRASH("Unexpected image type");
+      }
+
+      return *this;
+    }
+
+    const MemoryCounter& UsedRaster() const { return mUsedRasterCounter; }
+    const MemoryCounter& UnusedRaster() const { return mUnusedRasterCounter; }
+    const MemoryCounter& UsedVector() const { return mUsedVectorCounter; }
+    const MemoryCounter& UnusedVector() const { return mUnusedVectorCounter; }
+
+  private:
+    MemoryCounter mUsedRasterCounter;
+    MemoryCounter mUnusedRasterCounter;
+    MemoryCounter mUsedVectorCounter;
+    MemoryCounter mUnusedVectorCounter;
+  };
+
+
+  // Reports all images of a single kind, e.g. all used chrome images.
+  nsresult ReportCounterArray(nsIHandleReportCallback* aHandleReport,
+                              nsISupports* aData,
+                              const nsTArray<ImageMemoryCounter>& aCounterArray,
+                              const char* aPathPrefix,
+                              bool aAnonymize = false)
   {
     nsresult rv;
-    Sizes totalSizes;
-    Sizes nonNotableSizes;
-
-    nsCString pathPart(aPathPartStr);
-    nsCString explicitPathPrefix(aPathPartStr);
-    explicitPathPrefix.Insert("explicit/", 0);
+    MemoryTotal summaryTotal;
+    MemoryTotal nonNotableTotal;
 
     // Report notable images, and compute total and non-notable aggregate sizes.
-    for (uint32_t i = 0; i < aInfoArray.Length(); i++) {
-      ImageInfo<Sizes> info = aInfoArray[i];
+    for (uint32_t i = 0; i < aCounterArray.Length(); i++) {
+      ImageMemoryCounter counter = aCounterArray[i];
 
       if (aAnonymize) {
-        info.mURI.Truncate();
-        info.mURI.AppendPrintf("<anonymized-%u>", i);
+        counter.URI().Truncate();
+        counter.URI().AppendPrintf("<anonymized-%u>", i);
       } else {
-        // info.mURI can be a data: URI, and thus extremely long. Truncate if
-        // necessary.
+        // The URI could be an extremely long data: URI. Truncate if needed.
         static const size_t max = 256;
-        if (info.mURI.Length() > max) {
-          info.mURI.Truncate(max);
-          info.mURI.AppendLiteral(" (truncated)");
+        if (counter.URI().Length() > max) {
+          counter.URI().Truncate(max);
+          counter.URI().AppendLiteral(" (truncated)");
         }
-        info.mURI.ReplaceChar('/', '\\');
+        counter.URI().ReplaceChar('/', '\\');
       }
 
-      totalSizes.add(info.mSizes);
-
-      if (!info.mSizes.isNotable()) {
-        nonNotableSizes.add(info.mSizes);
+      summaryTotal += counter;
+
+      if (counter.IsNotable()) {
+        rv = ReportCounter(aHandleReport, aData, aPathPrefix, counter);
+        NS_ENSURE_SUCCESS(rv, rv);
       } else {
-        // Report the notable image.
-        rv = ReportSizes(aHandleReport, aData, explicitPathPrefix,
-                         info.mURI, info.mSizes);
-        NS_ENSURE_SUCCESS(rv, rv);
+        nonNotableTotal += counter;
       }
     }
 
     // Report non-notable images in aggregate.
-    rv = ReportSizes(aHandleReport, aData, explicitPathPrefix,
-                     NS_LITERAL_CSTRING("<non-notable images>"),
-                     nonNotableSizes);
+    rv = ReportTotal(aHandleReport, aData, /* aExplicit = */ true,
+                     aPathPrefix, "<non-notable images>/", nonNotableTotal);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    // Report image totals in aggregate, without the "explicit/" prefix.
-    rv = ReportSizes(aHandleReport, aData, pathPart, EmptyCString(),
-                     totalSizes);
+    // Report a summary in aggregate, outside of the explicit tree.
+    rv = ReportTotal(aHandleReport, aData, /* aExplicit = */ false,
+                     aPathPrefix, "", summaryTotal);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 
-  static PLDHashOperator EntryImageSizes(const nsACString&,
-                                         imgCacheEntry *aEntry,
-                                         void *aUserArg)
+  static nsresult ReportCounter(nsIHandleReportCallback* aHandleReport,
+                                nsISupports* aData,
+                                const char* aPathPrefix,
+                                const ImageMemoryCounter& aCounter)
+  {
+    nsAutoCString pathPrefix(NS_LITERAL_CSTRING("explicit/"));
+    pathPrefix.Append(aPathPrefix);
+    pathPrefix.Append(aCounter.Type() == imgIContainer::TYPE_RASTER
+                        ? "/raster/"
+                        : "/vector/");
+    pathPrefix.Append(aCounter.IsUsed() ? "used/" : "unused/");
+    pathPrefix.Append("image(");
+    if (aCounter.URI().IsEmpty()) {
+      pathPrefix.Append("<unknown URI>");
+    } else {
+      pathPrefix.Append(aCounter.URI());
+    }
+    pathPrefix.Append(")/");
+
+    return ReportValues(aHandleReport, aData, pathPrefix, aCounter.Values());
+  }
+
+  static nsresult ReportTotal(nsIHandleReportCallback* aHandleReport,
+                              nsISupports* aData,
+                              bool aExplicit,
+                              const char* aPathPrefix,
+                              const char* aPathInfix,
+                              const MemoryTotal& aTotal)
+  {
+    nsresult rv;
+
+    nsAutoCString pathPrefix;
+    if (aExplicit) {
+      pathPrefix.Append("explicit/");
+    }
+    pathPrefix.Append(aPathPrefix);
+
+    nsAutoCString rasterUsedPrefix(pathPrefix);
+    rasterUsedPrefix.Append("/raster/used/");
+    rasterUsedPrefix.Append(aPathInfix);
+    rv = ReportValues(aHandleReport, aData, rasterUsedPrefix,
+                      aTotal.UsedRaster());
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsAutoCString rasterUnusedPrefix(pathPrefix);
+    rasterUnusedPrefix.Append("/raster/unused/");
+    rasterUnusedPrefix.Append(aPathInfix);
+    rv = ReportValues(aHandleReport, aData, rasterUnusedPrefix,
+                      aTotal.UnusedRaster());
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsAutoCString vectorUsedPrefix(pathPrefix);
+    vectorUsedPrefix.Append("/vector/used/");
+    vectorUsedPrefix.Append(aPathInfix);
+    rv = ReportValues(aHandleReport, aData, vectorUsedPrefix,
+                      aTotal.UsedVector());
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsAutoCString vectorUnusedPrefix(pathPrefix);
+    vectorUnusedPrefix.Append("/vector/unused/");
+    vectorUnusedPrefix.Append(aPathInfix);
+    rv = ReportValues(aHandleReport, aData, vectorUnusedPrefix,
+                      aTotal.UnusedVector());
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
+  static nsresult ReportValues(nsIHandleReportCallback* aHandleReport,
+                               nsISupports* aData,
+                               const nsACString& aPathPrefix,
+                               const MemoryCounter& aCounter)
+  {
+    nsresult rv;
+
+    rv = ReportValue(aHandleReport, aData, KIND_HEAP, aPathPrefix,
+                     "source",
+                     "Raster image source data and vector image documents.",
+                     aCounter.Source());
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = ReportValue(aHandleReport, aData, KIND_HEAP, aPathPrefix,
+                     "decoded-heap",
+                     "Decoded image data which is stored on the heap.",
+                     aCounter.DecodedHeap());
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = ReportValue(aHandleReport, aData, KIND_NONHEAP, aPathPrefix,
+                     "decoded-nonheap",
+                     "Decoded image data which isn't stored on the heap.",
+                     aCounter.DecodedNonHeap());
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
+  static nsresult ReportValue(nsIHandleReportCallback* aHandleReport,
+                              nsISupports* aData,
+                              int32_t aKind,
+                              const nsACString& aPathPrefix,
+                              const char* aPathSuffix,
+                              const char* aDescription,
+                              size_t aValue)
+  {
+    if (aValue == 0) {
+      return NS_OK;
+    }
+
+    nsAutoCString desc(aDescription);
+    nsAutoCString path(aPathPrefix);
+    path.Append(aPathSuffix);
+
+    return aHandleReport->Callback(EmptyCString(), path, aKind, UNITS_BYTES,
+                                   aValue, desc, aData);
+  }
+
+  static PLDHashOperator DoRecordCounter(const nsACString&,
+                                         imgCacheEntry* aEntry,
+                                         void* aUserArg)
   {
     nsRefPtr<imgRequest> req = aEntry->GetRequest();
-    Image *image = static_cast<Image*>(req->mImage.get());
-    if (image) {
-      ImageSizes *sizes = static_cast<ImageSizes*>(aUserArg);
-
-      nsRefPtr<ImageURL> imageURL(image->GetURI());
-      nsAutoCString spec;
-      imageURL->GetSpec(spec);
-      ImageInfo<RasterSizes> rasterInfo;
-      rasterInfo.mSizes.mRaw =
-          image->HeapSizeOfSourceWithComputedFallback(ImagesMallocSizeOf);
-      rasterInfo.mSizes.mUncompressedHeap =
-          image->HeapSizeOfDecodedWithComputedFallback(ImagesMallocSizeOf);
-      rasterInfo.mSizes.mUncompressedNonheap = image->NonHeapSizeOfDecoded();
-      rasterInfo.mURI = spec.get();
-      if (!aEntry->HasNoProxies()) {
-        sizes->mRasterUsedImageInfo.AppendElement(rasterInfo);
-      } else {
-        sizes->mRasterUnusedImageInfo.AppendElement(rasterInfo);
-      }
-
-      ImageInfo<VectorDocSizes> vectorInfo;
-      vectorInfo.mSizes.mSize =
-        image->HeapSizeOfVectorImageDocument(&vectorInfo.mURI);
-      if (!vectorInfo.mURI.IsEmpty()) {
-        if (!aEntry->HasNoProxies()) {
-          sizes->mVectorUsedImageDocInfo.AppendElement(vectorInfo);
-        } else {
-          sizes->mVectorUnusedImageDocInfo.AppendElement(vectorInfo);
-        }
-      }
-    }
-
+    RecordCounterForRequest(req,
+                            static_cast<nsTArray<ImageMemoryCounter>*>(aUserArg),
+                            !aEntry->HasNoProxies());
     return PL_DHASH_NEXT;
   }
 
-  static PLDHashOperator EntryUncachedImageSizes(nsPtrHashKey<imgRequest>* aEntry,
+  static PLDHashOperator DoRecordCounterUncached(nsPtrHashKey<imgRequest>* aEntry,
                                                  void* aUserArg)
   {
     nsRefPtr<imgRequest> req = aEntry->GetKey();
-    Image *image = static_cast<Image*>(req->mImage.get());
-    if (image) {
-      ImageSizes *sizes = static_cast<ImageSizes*>(aUserArg);
-
-      nsRefPtr<ImageURL> imageURL(image->GetURI());
-      nsAutoCString spec;
-      imageURL->GetSpec(spec);
-      ImageInfo<RasterSizes> rasterInfo;
-      rasterInfo.mSizes.mRaw =
-          image->HeapSizeOfSourceWithComputedFallback(ImagesMallocSizeOf);
-      rasterInfo.mSizes.mUncompressedHeap =
-          image->HeapSizeOfDecodedWithComputedFallback(ImagesMallocSizeOf);
-      rasterInfo.mSizes.mUncompressedNonheap = image->NonHeapSizeOfDecoded();
-      rasterInfo.mURI = spec.get();
-      if (req->HasConsumers()) {
-        sizes->mRasterUsedImageInfo.AppendElement(rasterInfo);
-      } else {
-        sizes->mRasterUnusedImageInfo.AppendElement(rasterInfo);
-      }
-
-      ImageInfo<VectorDocSizes> vectorInfo;
-      vectorInfo.mSizes.mSize =
-        image->HeapSizeOfVectorImageDocument(&vectorInfo.mURI);
-      if (!vectorInfo.mURI.IsEmpty()) {
-        if (req->HasConsumers()) {
-          sizes->mVectorUsedImageDocInfo.AppendElement(vectorInfo);
-        } else {
-          sizes->mVectorUnusedImageDocInfo.AppendElement(vectorInfo);
-        }
-      }
-    }
-
+    RecordCounterForRequest(req,
+                            static_cast<nsTArray<ImageMemoryCounter>*>(aUserArg),
+                            req->HasConsumers());
     return PL_DHASH_NEXT;
   }
 
-  static PLDHashOperator EntryUsedUncompressedSize(const nsACString&,
-                                                   imgCacheEntry *aEntry,
-                                                   void *aUserArg)
+  static void RecordCounterForRequest(imgRequest* aRequest,
+                                      nsTArray<ImageMemoryCounter>* aArray,
+                                      bool aIsUsed)
   {
-    if (!aEntry->HasNoProxies()) {
-      size_t *n = static_cast<size_t*>(aUserArg);
-      nsRefPtr<imgRequest> req = aEntry->GetRequest();
-      Image *image = static_cast<Image*>(req->mImage.get());
-      if (image) {
-        // Both this and EntryImageSizes measure
-        // images/content/raster/used/uncompressed memory.  This function's
-        // measurement is secondary -- the result doesn't go in the "explicit"
-        // tree -- so we use moz_malloc_size_of instead of ImagesMallocSizeOf
-        // to prevent DMD from seeing it reported twice.
-        *n += image->HeapSizeOfDecodedWithComputedFallback(moz_malloc_size_of);
-        *n += image->NonHeapSizeOfDecoded();
-      }
+    auto image = static_cast<Image*>(aRequest->mImage.get());
+    if (!image) {
+      return;
     }
 
+    nsRefPtr<ImageURL> imageURL(image->GetURI());
+    nsAutoCString spec;
+    imageURL->GetSpec(spec);
+
+    ImageMemoryCounter counter(image->GetType(), spec, aIsUsed);
+
+    counter.Values().SetSource(image->
+        SizeOfSourceWithComputedFallback(ImagesMallocSizeOf));
+    counter.Values().SetDecodedHeap(image->
+        SizeOfDecoded(gfxMemoryLocation::IN_PROCESS_HEAP, ImagesMallocSizeOf));
+    counter.Values().SetDecodedNonHeap(image->
+        SizeOfDecoded(gfxMemoryLocation::IN_PROCESS_NONHEAP, nullptr));
+
+    aArray->AppendElement(counter);
+  }
+
+  static PLDHashOperator DoRecordCounterUsedDecoded(const nsACString&,
+                                                    imgCacheEntry* aEntry,
+                                                    void* aUserArg)
+  {
+    if (aEntry->HasNoProxies()) {
+      return PL_DHASH_NEXT;
+    }
+
+    nsRefPtr<imgRequest> req = aEntry->GetRequest();
+    auto image = static_cast<Image*>(req->mImage.get());
+    if (!image) {
+      return PL_DHASH_NEXT;
+    }
+
+    // Both this and EntryImageSizes measure images/content/raster/used/decoded
+    // memory.  This function's measurement is secondary -- the result doesn't
+    // go in the "explicit" tree -- so we use moz_malloc_size_of instead of
+    // ImagesMallocSizeOf to prevent DMD from seeing it reported twice.
+    auto n = static_cast<size_t*>(aUserArg);
+    *n += image->SizeOfDecoded(gfxMemoryLocation::IN_PROCESS_HEAP,
+                               moz_malloc_size_of);
+    *n += image->SizeOfDecoded(gfxMemoryLocation::IN_PROCESS_NONHEAP,
+                               moz_malloc_size_of);
     return PL_DHASH_NEXT;
   }
 };
 
-// Specialisation of this method for raster images.
-template<>
-nsresult imgMemoryReporter::ReportSizes(
-  nsIMemoryReporterCallback *aHandleReport, nsISupports *aData,
-  const nsACString &aPathPrefix, const nsACString &aLocation,
-  RasterSizes aSizes)
-{
-#define REPORT(_pathPrefix, _pathSuffix, _location, _kind, _amount, _desc)    \
-  do {                                                                        \
-    if (_amount > 0) {                                                        \
-      nsCString path(_pathPrefix);                                            \
-      path.Append("/");                                                       \
-      if (!_location.IsEmpty()) {                                             \
-        path.Append("image(");                                                \
-        path.Append(_location);                                               \
-        path.Append(")/");                                                    \
-      }                                                                       \
-      path.Append(_pathSuffix);                                               \
-      nsresult rv;                                                            \
-      rv = aHandleReport->Callback(EmptyCString(), path, _kind, UNITS_BYTES,  \
-                                   _amount, NS_LITERAL_CSTRING(_desc), aData);\
-      NS_ENSURE_SUCCESS(rv, rv);                                              \
-    }                                                                         \
-  } while (0)
-
-  REPORT(aPathPrefix, "raw", aLocation, KIND_HEAP,
-         aSizes.mRaw, "Compressed image data.");
-
-  REPORT(aPathPrefix, "uncompressed-heap", aLocation, KIND_HEAP,
-         aSizes.mUncompressedHeap, "Uncompressed image data.");
-
-  REPORT(aPathPrefix, "uncompressed-nonheap", aLocation, KIND_NONHEAP,
-         aSizes.mUncompressedNonheap, "Uncompressed image data.");
-#undef REPORT
-  return NS_OK;
-}
-
-// Specialisation of this method for vector images.
-template<>
-nsresult imgMemoryReporter::ReportSizes(
-  nsIMemoryReporterCallback *aHandleReport, nsISupports *aData,
-  const nsACString &aPathPrefix, const nsACString &aLocation,
-  VectorDocSizes aSizes)
-{
-#define REPORT(_pathPrefix, _location, _amount, _desc)                        \
-  do {                                                                        \
-    if (_amount > 0) {                                                        \
-      nsCString path(_pathPrefix);                                            \
-      if (!_location.IsEmpty()) {                                             \
-        path.Append("/document(");                                            \
-        path.Append(_location);                                               \
-        path.Append(")");                                                     \
-      }                                                                       \
-      nsresult rv;                                                            \
-      rv = aHandleReport->Callback(EmptyCString(), path, KIND_HEAP,           \
-                                   UNITS_BYTES, _amount,                      \
-                                   NS_LITERAL_CSTRING(_desc), aData);         \
-      NS_ENSURE_SUCCESS(rv, rv);                                              \
-    }                                                                         \
-  } while (0)
-
-  REPORT(aPathPrefix, aLocation, aSizes.mSize,
-         "Parsed vector image documents.");
-#undef REPORT
-  return NS_OK;
-}
-
 NS_IMPL_ISUPPORTS(imgMemoryReporter, nsIMemoryReporter)
 
 NS_IMPL_ISUPPORTS(nsProgressNotificationProxy,
                   nsIProgressEventSink,
                   nsIChannelEventSink,
                   nsIInterfaceRequestor)
 
 NS_IMETHODIMP
--- a/image/src/imgRequest.cpp
+++ b/image/src/imgRequest.cpp
@@ -450,18 +450,20 @@ void imgRequest::AdjustPriority(imgReque
 void imgRequest::SetIsInCache(bool incache)
 {
   LOG_FUNC_WITH_PARAM(GetImgLog(), "imgRequest::SetIsCacheable", "incache", incache);
   mIsInCache = incache;
 }
 
 void imgRequest::UpdateCacheEntrySize()
 {
-  if (mCacheEntry)
-    mCacheEntry->SetDataSize(mImage->SizeOfData());
+  if (mCacheEntry) {
+    size_t size = mImage->SizeOfSourceWithComputedFallback(moz_malloc_size_of);
+    mCacheEntry->SetDataSize(size);
+  }
 }
 
 void imgRequest::SetCacheValidation(imgCacheEntry* aCacheEntry, nsIRequest* aRequest)
 {
   /* get the expires info */
   if (aCacheEntry) {
     nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(aRequest));
     if (cacheChannel) {
--- a/image/src/imgRequest.h
+++ b/image/src/imgRequest.h
@@ -136,19 +136,16 @@ public:
   already_AddRefed<ProgressTracker> GetProgressTracker();
 
   // Get the current principal of the image. No AddRefing.
   inline nsIPrincipal* GetPrincipal() const { return mPrincipal.get(); }
 
   // Resize the cache entry to 0 if it exists
   void ResetCacheEntry();
 
-  // Update the cache entry size based on the image container
-  void UpdateCacheEntrySize();
-
   // OK to use on any thread.
   nsresult GetURI(ImageURL **aURI);
   nsresult GetCurrentURI(nsIURI **aURI);
 
   nsresult GetImageErrorCode(void);
 
 private:
   friend class imgCacheEntry;
@@ -178,16 +175,19 @@ private:
   // Reset the cache entry after we've dropped our reference to it. Used by the
   // imgLoader when our cache entry is re-requested after we've dropped our
   // reference to it.
   void SetCacheEntry(imgCacheEntry *entry);
 
   // Returns whether we've got a reference to the cache entry.
   bool HasCacheEntry() const;
 
+  // Update the cache entry size based on the image container.
+  void UpdateCacheEntrySize();
+
   // Return the priority of the underlying network request, or return
   // PRIORITY_NORMAL if it doesn't support nsISupportsPriority.
   int32_t Priority() const;
 
   // Adjust the priority of the underlying network request by the given delta
   // on behalf of the given proxy.
   void AdjustPriority(imgRequestProxy *aProxy, int32_t aDelta);
 
--- a/image/src/imgRequestProxy.cpp
+++ b/image/src/imgRequestProxy.cpp
@@ -771,37 +771,27 @@ void imgRequestProxy::OnDecodeComplete()
 {
   LOG_FUNC(GetImgLog(), "imgRequestProxy::OnDecodeComplete");
 
   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();
-  }
 }
 
 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::OnUnlockedDraw()
 {
   LOG_FUNC(GetImgLog(), "imgRequestProxy::OnUnlockedDraw");
 
   if (mListener && !mCanceled) {
     // Hold a ref to the listener while we call it, just in case.