merge mozilla-aurora to b2g44 a=merge
[gecko.git] / image / ImageCacheKey.cpp
blobcc5042546463faaff0c56a3bd701b02aaec850a6
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"
9 #include "File.h"
10 #include "ImageURL.h"
11 #include "nsHostObjectProtocolHandler.h"
12 #include "nsString.h"
13 #include "mozilla/dom/workers/ServiceWorkerManager.h"
14 #include "nsIDOMDocument.h"
15 #include "nsIDocument.h"
16 #include "nsPrintfCString.h"
18 namespace mozilla {
20 using namespace dom;
22 namespace image {
24 bool
25 URISchemeIs(ImageURL* aURI, const char* aScheme)
27 bool schemeMatches = false;
28 if (NS_WARN_IF(NS_FAILED(aURI->SchemeIs(aScheme, &schemeMatches)))) {
29 return false;
31 return schemeMatches;
34 static Maybe<uint64_t>
35 BlobSerial(ImageURL* aURI)
37 nsAutoCString spec;
38 aURI->GetSpec(spec);
40 RefPtr<BlobImpl> blob;
41 if (NS_SUCCEEDED(NS_GetBlobForBlobURISpec(spec, getter_AddRefs(blob))) &&
42 blob) {
43 return Some(blob->GetSerialNumber());
46 return Nothing();
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)
64 : mURI(aURI)
65 , mControlledDocument(GetControlledDocumentToken(aDocument))
66 , mIsChrome(URISchemeIs(mURI, "chrome"))
68 MOZ_ASSERT(aURI);
70 if (URISchemeIs(mURI, "blob")) {
71 mBlobSerial = BlobSerial(mURI);
74 mHash = ComputeHash(mURI, mBlobSerial, mControlledDocument);
77 ImageCacheKey::ImageCacheKey(const ImageCacheKey& aOther)
78 : mURI(aOther.mURI)
79 , mBlobSerial(aOther.mBlobSerial)
80 , mControlledDocument(aOther.mControlledDocument)
81 , mHash(aOther.mHash)
82 , mIsChrome(aOther.mIsChrome)
83 { }
85 ImageCacheKey::ImageCacheKey(ImageCacheKey&& aOther)
86 : mURI(Move(aOther.mURI))
87 , mBlobSerial(Move(aOther.mBlobSerial))
88 , mControlledDocument(aOther.mControlledDocument)
89 , mHash(aOther.mHash)
90 , mIsChrome(aOther.mIsChrome)
91 { }
93 bool
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) {
98 return false;
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;
111 const char*
112 ImageCacheKey::Spec() const
114 return mURI->Spec();
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);
126 if (aBlobSerial) {
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
131 // the same.
132 nsAutoCString ref;
133 aURI->GetRef(ref);
134 return HashGeneric(*aBlobSerial, HashString(ref + ptr));
137 // For non-blob URIs, we hash the URI spec.
138 nsAutoCString spec;
139 aURI->GetSpec(spec);
140 return HashString(spec + ptr);
143 /* static */ void*
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);
153 if (doc && swm) {
154 ErrorResult rv;
155 if (swm->IsControlled(doc, rv)) {
156 pointer = doc;
159 return pointer;
162 } // namespace image
163 } // namespace mozilla