diff --git a/image/ImageCacheKey.cpp b/image/ImageCacheKey.cpp index 35d2c90128d..33ba6ca4cbf 100644 --- a/image/ImageCacheKey.cpp +++ b/image/ImageCacheKey.cpp @@ -17,37 +17,67 @@ 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 +BlobSerial(ImageURL* aURI) +{ + nsAutoCString spec; + aURI->GetSpec(spec); + + nsRefPtr 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) { } @@ -55,6 +85,12 @@ ImageCacheKey::ImageCacheKey(ImageCacheKey&& aOther) 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; } @@ -65,10 +101,19 @@ ImageCacheKey::Spec() const } /* static */ uint32_t -ImageCacheKey::ComputeHash(ImageURL* aURI) +ImageCacheKey::ComputeHash(ImageURL* aURI, + const Maybe& 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); diff --git a/image/ImageCacheKey.h b/image/ImageCacheKey.h index e77a0221432..fb6b8b8271b 100644 --- a/image/ImageCacheKey.h +++ b/image/ImageCacheKey.h @@ -10,6 +10,8 @@ #ifndef mozilla_image_src_ImageCacheKey_h #define mozilla_image_src_ImageCacheKey_h +#include "mozilla/Maybe.h" + class nsIURI; namespace mozilla { @@ -42,9 +44,11 @@ public: bool IsChrome() const { return mIsChrome; } private: - static uint32_t ComputeHash(ImageURL* aURI); + static uint32_t ComputeHash(ImageURL* aURI, + const Maybe& aBlobSerial); nsRefPtr mURI; + Maybe mBlobSerial; uint32_t mHash; bool mIsChrome; };