1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "ImageCacheKey.h"
8 #include "mozilla/Move.h"
11 #include "nsHostObjectProtocolHandler.h"
13 #include "mozilla/dom/workers/ServiceWorkerManager.h"
14 #include "nsIDOMDocument.h"
15 #include "nsIDocument.h"
16 #include "nsPrintfCString.h"
25 URISchemeIs(ImageURL
* aURI
, const char* aScheme
)
27 bool schemeMatches
= false;
28 if (NS_WARN_IF(NS_FAILED(aURI
->SchemeIs(aScheme
, &schemeMatches
)))) {
34 static Maybe
<uint64_t>
35 BlobSerial(ImageURL
* aURI
)
40 RefPtr
<BlobImpl
> blob
;
41 if (NS_SUCCEEDED(NS_GetBlobForBlobURISpec(spec
, getter_AddRefs(blob
))) &&
43 return Some(blob
->GetSerialNumber());
49 ImageCacheKey::ImageCacheKey(nsIURI
* aURI
, nsIDOMDocument
* aDocument
)
50 : mURI(new ImageURL(aURI
))
51 , mControlledDocument(GetControlledDocumentToken(aDocument
))
52 , mIsChrome(URISchemeIs(mURI
, "chrome"))
54 MOZ_ASSERT(NS_IsMainThread());
56 if (URISchemeIs(mURI
, "blob")) {
57 mBlobSerial
= BlobSerial(mURI
);
60 mHash
= ComputeHash(mURI
, mBlobSerial
, mControlledDocument
);
63 ImageCacheKey::ImageCacheKey(ImageURL
* aURI
, nsIDOMDocument
* aDocument
)
65 , mControlledDocument(GetControlledDocumentToken(aDocument
))
66 , mIsChrome(URISchemeIs(mURI
, "chrome"))
70 if (URISchemeIs(mURI
, "blob")) {
71 mBlobSerial
= BlobSerial(mURI
);
74 mHash
= ComputeHash(mURI
, mBlobSerial
, mControlledDocument
);
77 ImageCacheKey::ImageCacheKey(const ImageCacheKey
& aOther
)
79 , mBlobSerial(aOther
.mBlobSerial
)
80 , mControlledDocument(aOther
.mControlledDocument
)
82 , mIsChrome(aOther
.mIsChrome
)
85 ImageCacheKey::ImageCacheKey(ImageCacheKey
&& aOther
)
86 : mURI(Move(aOther
.mURI
))
87 , mBlobSerial(Move(aOther
.mBlobSerial
))
88 , mControlledDocument(aOther
.mControlledDocument
)
90 , mIsChrome(aOther
.mIsChrome
)
94 ImageCacheKey::operator==(const ImageCacheKey
& aOther
) const
96 // Don't share the image cache between a controlled document and anything else.
97 if (mControlledDocument
!= aOther
.mControlledDocument
) {
100 if (mBlobSerial
|| aOther
.mBlobSerial
) {
101 // If at least one of us has a blob serial, just compare the blob serial and
102 // the ref portion of the URIs.
103 return mBlobSerial
== aOther
.mBlobSerial
&&
104 mURI
->HasSameRef(*aOther
.mURI
);
107 // For non-blob URIs, compare the URIs.
108 return *mURI
== *aOther
.mURI
;
112 ImageCacheKey::Spec() const
117 /* static */ uint32_t
118 ImageCacheKey::ComputeHash(ImageURL
* aURI
,
119 const Maybe
<uint64_t>& aBlobSerial
,
120 void* aControlledDocument
)
122 // Since we frequently call Hash() several times in a row on the same
123 // ImageCacheKey, as an optimization we compute our hash once and store it.
125 nsPrintfCString
ptr("%p", aControlledDocument
);
127 // For blob URIs, we hash the serial number of the underlying blob, so that
128 // different blob URIs which point to the same blob share a cache entry. We
129 // also include the ref portion of the URI to support -moz-samplesize, which
130 // requires us to create different Image objects even if the source data is
134 return HashGeneric(*aBlobSerial
, HashString(ref
+ ptr
));
137 // For non-blob URIs, we hash the URI spec.
140 return HashString(spec
+ ptr
);
144 ImageCacheKey::GetControlledDocumentToken(nsIDOMDocument
* aDocument
)
146 // For non-controlled documents, we just return null. For controlled
147 // documents, we cast the pointer into a void* to avoid dereferencing
148 // it (since we only use it for comparisons), and return it.
149 void* pointer
= nullptr;
150 using dom::workers::ServiceWorkerManager
;
151 RefPtr
<ServiceWorkerManager
> swm
= ServiceWorkerManager::GetInstance();
152 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(aDocument
);
155 if (swm
->IsControlled(doc
, rv
)) {
163 } // namespace mozilla