summaryrefslogtreecommitdiff
path: root/image/ImageCacheKey.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'image/ImageCacheKey.cpp')
-rw-r--r--image/ImageCacheKey.cpp167
1 files changed, 167 insertions, 0 deletions
diff --git a/image/ImageCacheKey.cpp b/image/ImageCacheKey.cpp
new file mode 100644
index 0000000000..da194fa554
--- /dev/null
+++ b/image/ImageCacheKey.cpp
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ImageCacheKey.h"
+
+#include "mozilla/Move.h"
+#include "File.h"
+#include "ImageURL.h"
+#include "nsHostObjectProtocolHandler.h"
+#include "nsString.h"
+#include "mozilla/dom/workers/ServiceWorkerManager.h"
+#include "nsIDocument.h"
+#include "nsPrintfCString.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);
+
+ RefPtr<BlobImpl> blob;
+ if (NS_SUCCEEDED(NS_GetBlobForBlobURISpec(spec, getter_AddRefs(blob))) &&
+ blob) {
+ return Some(blob->GetSerialNumber());
+ }
+
+ return Nothing();
+}
+
+ImageCacheKey::ImageCacheKey(nsIURI* aURI,
+ const PrincipalOriginAttributes& aAttrs,
+ nsIDocument* aDocument,
+ nsresult& aRv)
+ : mURI(new ImageURL(aURI, aRv))
+ , mOriginAttributes(aAttrs)
+ , mControlledDocument(GetControlledDocumentToken(aDocument))
+ , mIsChrome(URISchemeIs(mURI, "chrome"))
+{
+ NS_ENSURE_SUCCESS_VOID(aRv);
+
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (URISchemeIs(mURI, "blob")) {
+ mBlobSerial = BlobSerial(mURI);
+ }
+
+ mHash = ComputeHash(mURI, mBlobSerial, mOriginAttributes, mControlledDocument);
+}
+
+ImageCacheKey::ImageCacheKey(ImageURL* aURI,
+ const PrincipalOriginAttributes& aAttrs,
+ nsIDocument* aDocument)
+ : mURI(aURI)
+ , mOriginAttributes(aAttrs)
+ , mControlledDocument(GetControlledDocumentToken(aDocument))
+ , mIsChrome(URISchemeIs(mURI, "chrome"))
+{
+ MOZ_ASSERT(aURI);
+
+ if (URISchemeIs(mURI, "blob")) {
+ mBlobSerial = BlobSerial(mURI);
+ }
+
+ mHash = ComputeHash(mURI, mBlobSerial, mOriginAttributes, mControlledDocument);
+}
+
+ImageCacheKey::ImageCacheKey(const ImageCacheKey& aOther)
+ : mURI(aOther.mURI)
+ , mBlobSerial(aOther.mBlobSerial)
+ , mOriginAttributes(aOther.mOriginAttributes)
+ , mControlledDocument(aOther.mControlledDocument)
+ , mHash(aOther.mHash)
+ , mIsChrome(aOther.mIsChrome)
+{ }
+
+ImageCacheKey::ImageCacheKey(ImageCacheKey&& aOther)
+ : mURI(Move(aOther.mURI))
+ , mBlobSerial(Move(aOther.mBlobSerial))
+ , mOriginAttributes(aOther.mOriginAttributes)
+ , mControlledDocument(aOther.mControlledDocument)
+ , mHash(aOther.mHash)
+ , mIsChrome(aOther.mIsChrome)
+{ }
+
+bool
+ImageCacheKey::operator==(const ImageCacheKey& aOther) const
+{
+ // Don't share the image cache between a controlled document and anything else.
+ if (mControlledDocument != aOther.mControlledDocument) {
+ return false;
+ }
+ // The origin attributes always have to match.
+ if (mOriginAttributes != aOther.mOriginAttributes) {
+ return false;
+ }
+ if (mBlobSerial || aOther.mBlobSerial) {
+ // If at least one of us has a blob serial, just compare the blob serial and
+ // the ref portion of the URIs.
+ return mBlobSerial == aOther.mBlobSerial &&
+ mURI->HasSameRef(*aOther.mURI);
+ }
+
+ // 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,
+ const Maybe<uint64_t>& aBlobSerial,
+ const PrincipalOriginAttributes& aAttrs,
+ void* aControlledDocument)
+{
+ // 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.
+
+ nsPrintfCString ptr("%p", aControlledDocument);
+ nsAutoCString suffix;
+ aAttrs.CreateSuffix(suffix);
+
+ return AddToHash(0, aURI->ComputeHash(aBlobSerial),
+ HashString(suffix), HashString(ptr));
+}
+
+/* static */ void*
+ImageCacheKey::GetControlledDocumentToken(nsIDocument* aDocument)
+{
+ // For non-controlled documents, we just return null. For controlled
+ // documents, we cast the pointer into a void* to avoid dereferencing
+ // it (since we only use it for comparisons), and return it.
+ void* pointer = nullptr;
+ using dom::workers::ServiceWorkerManager;
+ RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+ if (aDocument && swm) {
+ ErrorResult rv;
+ if (swm->IsControlled(aDocument, rv)) {
+ pointer = aDocument;
+ }
+ }
+ return pointer;
+}
+
+} // namespace image
+} // namespace mozilla