Bug 1065818 - Clean up memory reports and use of decoded size for image cache entries. r=tn,njn
☠☠ backed out by 5901f49c4269 ☠ ☠
authorSeth Fowler <seth@mozilla.com>
Wed, 26 Nov 2014 01:37:57 -0800
changeset 217574 2ac38e52731788f471ae35e2692e9b2045252b7f
parent 217573 503b808459522cd8017b86710c2c770442b9d78d
child 217575 bf063d26159a77b6efda599ebe28883bfca12eaa
push id52318
push usermfowler@mozilla.com
push dateWed, 26 Nov 2014 09:38:15 +0000
treeherdermozilla-inbound@2ac38e527317 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn, njn
bugs1065818
milestone36.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
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.