Bug 1154974 (Part 2) - Merge image cache entries for blobs URIs with the same underlying blob. r=baku
authorSeth Fowler <mark.seth.fowler@gmail.com>
Wed, 20 May 2015 18:49:53 -0700
changeset 264611 fc204743547e054661a61d6defcc892053cc7e98
parent 264610 4ee8035b043d3d7c4bd2d410253b29c606f763ad
child 264613 edddd285c20c0fb2d389c87a022fc300c5dba331
push idunknown
push userunknown
push dateunknown
reviewersbaku
bugs1154974
milestone41.0a1
Bug 1154974 (Part 2) - Merge image cache entries for blobs URIs with the same underlying blob. r=baku
image/ImageCacheKey.cpp
image/ImageCacheKey.h
--- a/image/ImageCacheKey.cpp
+++ b/image/ImageCacheKey.cpp
@@ -12,67 +12,112 @@
 #include "nsString.h"
 
 namespace mozilla {
 
 using namespace dom;
 
 namespace image {
 
+bool
+URISchemeIs(ImageURL* aURI, const char* aScheme)
+{
+  bool schemeMatches = false;
+  if (NS_WARN_IF(NS_FAILED(aURI->SchemeIs(aScheme, &schemeMatches)))) {
+    return false;
+  }
+  return schemeMatches;
+}
+
+static Maybe<uint64_t>
+BlobSerial(ImageURL* aURI)
+{
+  nsAutoCString spec;
+  aURI->GetSpec(spec);
+
+  nsRefPtr<BlobImpl> blob;
+  if (NS_SUCCEEDED(NS_GetBlobForBlobURISpec(spec, getter_AddRefs(blob))) &&
+      blob) {
+    return Some(blob->GetSerialNumber());
+  }
+
+  return Nothing();
+}
+
 ImageCacheKey::ImageCacheKey(nsIURI* aURI)
   : mURI(new ImageURL(aURI))
+  , mIsChrome(URISchemeIs(mURI, "chrome"))
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mURI);
 
-  bool isChrome;
-  mIsChrome = NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome;
+  if (URISchemeIs(mURI, "blob")) {
+    mBlobSerial = BlobSerial(mURI);
+  }
 
-  mHash = ComputeHash(mURI);
+  mHash = ComputeHash(mURI, mBlobSerial);
 }
 
 ImageCacheKey::ImageCacheKey(ImageURL* aURI)
   : mURI(aURI)
+  , mIsChrome(URISchemeIs(mURI, "chrome"))
 {
-  MOZ_ASSERT(mURI);
+  MOZ_ASSERT(aURI);
 
-  bool isChrome;
-  mIsChrome = NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome;
+  if (URISchemeIs(mURI, "blob")) {
+    mBlobSerial = BlobSerial(mURI);
+  }
 
-  mHash = ComputeHash(mURI);
+  mHash = ComputeHash(mURI, mBlobSerial);
 }
 
 ImageCacheKey::ImageCacheKey(const ImageCacheKey& aOther)
   : mURI(aOther.mURI)
+  , mBlobSerial(aOther.mBlobSerial)
   , mHash(aOther.mHash)
   , mIsChrome(aOther.mIsChrome)
 { }
 
 ImageCacheKey::ImageCacheKey(ImageCacheKey&& aOther)
   : mURI(Move(aOther.mURI))
+  , mBlobSerial(Move(aOther.mBlobSerial))
   , mHash(aOther.mHash)
   , mIsChrome(aOther.mIsChrome)
 { }
 
 bool
 ImageCacheKey::operator==(const ImageCacheKey& aOther) const
 {
+  if (mBlobSerial || aOther.mBlobSerial) {
+    // If at least one of us has a blob serial, just compare those.
+    return mBlobSerial == aOther.mBlobSerial;
+  }
+
+  // For non-blob URIs, compare the URIs.
   return *mURI == *aOther.mURI;
 }
 
 const char*
 ImageCacheKey::Spec() const
 {
   return mURI->Spec();
 }
 
 /* static */ uint32_t
-ImageCacheKey::ComputeHash(ImageURL* aURI)
+ImageCacheKey::ComputeHash(ImageURL* aURI,
+                           const Maybe<uint64_t>& aBlobSerial)
 {
   // Since we frequently call Hash() several times in a row on the same
   // ImageCacheKey, as an optimization we compute our hash once and store it.
+
+  if (aBlobSerial) {
+    // For blob URIs, we hash the serial number of the underlying blob, so that
+    // different blob URIs which point to the same blob share a cache entry.
+    return HashGeneric(*aBlobSerial);
+  }
+
+  // For non-blob URIs, we hash the URI spec.
   nsAutoCString spec;
   aURI->GetSpec(spec);
   return HashString(spec);
 }
 
 } // namespace image
 } // namespace mozilla
--- a/image/ImageCacheKey.h
+++ b/image/ImageCacheKey.h
@@ -5,16 +5,18 @@
 
 /**
  * ImageCacheKey is the key type for the image cache (see imgLoader.h).
  */
 
 #ifndef mozilla_image_src_ImageCacheKey_h
 #define mozilla_image_src_ImageCacheKey_h
 
+#include "mozilla/Maybe.h"
+
 class nsIURI;
 
 namespace mozilla {
 namespace image {
 
 class ImageURL;
 
 /**
@@ -37,19 +39,21 @@ public:
 
   /// A weak pointer to the URI spec for this cache entry. For logging only.
   const char* Spec() const;
 
   /// Is this cache entry for a chrome image?
   bool IsChrome() const { return mIsChrome; }
 
 private:
-  static uint32_t ComputeHash(ImageURL* aURI);
+  static uint32_t ComputeHash(ImageURL* aURI,
+                              const Maybe<uint64_t>& aBlobSerial);
 
   nsRefPtr<ImageURL> mURI;
+  Maybe<uint64_t> mBlobSerial;
   uint32_t mHash;
   bool mIsChrome;
 };
 
 } // namespace image
 } // namespace mozilla
 
 #endif // mozilla_image_src_ImageCacheKey_h