1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3
* The contents of this file are subject to the Mozilla Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/MPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is mozilla.org code.
15
* The Initial Developer of the Original Code is Netscape
16
* Communications Corporation. Portions created by Netscape are
17
* Copyright (C) 2001 Netscape Communications Corporation.
18
* All Rights Reserved.
21
* Stuart Parmenter <pavlov@netscape.com>
26
#include "ImageLogging.h"
28
#include "imgRequest.h"
30
#include "nsXPIDLString.h"
32
#include "nsIServiceManager.h"
33
#include "nsIMemory.h"
34
#include "nsIObserverService.h"
37
#include "nsICacheService.h"
38
#include "nsICacheSession.h"
39
#include "nsICacheEntryDescriptor.h"
42
#include "nsIFileURL.h"
44
NS_IMPL_ISUPPORTS3(imgCache, imgICache, nsIObserver, nsISupportsWeakReference)
48
/* member initializers and constructor code */
56
nsresult imgCache::Init()
58
imgCache* cache = new imgCache();
59
if(!cache) return NS_ERROR_OUT_OF_MEMORY;
61
nsCOMPtr<nsIObserverService> os = do_GetService("@mozilla.org/observer-service;1");
63
os->AddObserver(cache, "memory-pressure", PR_FALSE);
64
os->AddObserver(cache, "chrome-flush-skin-caches", PR_FALSE);
65
os->AddObserver(cache, "chrome-flush-caches", PR_FALSE);
71
/* void clearCache (in boolean chrome); */
72
NS_IMETHODIMP imgCache::ClearCache(PRBool chrome)
75
return imgCache::ClearChromeImageCache();
77
return imgCache::ClearImageCache();
81
/* void removeEntry(in nsIURI uri); */
82
NS_IMETHODIMP imgCache::RemoveEntry(nsIURI *uri)
84
if (imgCache::Remove(uri))
87
return NS_ERROR_NOT_AVAILABLE;
90
static nsCOMPtr<nsICacheSession> gSession = nsnull;
91
static nsCOMPtr<nsICacheSession> gChromeSession = nsnull;
93
void GetCacheSession(nsIURI *aURI, nsICacheSession **_retval)
95
NS_ASSERTION(aURI, "Null URI!");
97
PRBool isChrome = PR_FALSE;
98
aURI->SchemeIs("chrome", &isChrome);
100
if (gSession && !isChrome) {
106
if (gChromeSession && isChrome) {
107
*_retval = gChromeSession;
112
nsCOMPtr<nsICacheService> cacheService(do_GetService("@mozilla.org/network/cache-service;1"));
114
NS_WARNING("Unable to get the cache service");
118
nsCOMPtr<nsICacheSession> newSession;
119
cacheService->CreateSession(isChrome ? "image-chrome" : "image",
120
nsICache::STORE_IN_MEMORY,
121
nsICache::NOT_STREAM_BASED,
122
getter_AddRefs(newSession));
125
NS_WARNING("Unable to create a cache session");
130
gChromeSession = newSession;
132
gSession = newSession;
133
gSession->SetDoomEntriesIfExpired(PR_FALSE);
136
*_retval = newSession;
141
void imgCache::Shutdown()
144
gChromeSession = nsnull;
148
nsresult imgCache::ClearChromeImageCache()
153
return gChromeSession->EvictEntries();
156
nsresult imgCache::ClearImageCache()
161
return gSession->EvictEntries();
166
PRBool imgCache::Put(nsIURI *aKey, imgRequest *request, nsICacheEntryDescriptor **aEntry)
168
LOG_STATIC_FUNC(gImgLog, "imgCache::Put");
172
nsCOMPtr<nsICacheSession> ses;
173
GetCacheSession(aKey, getter_AddRefs(ses));
174
if (!ses) return PR_FALSE;
177
aKey->GetAsciiSpec(spec);
179
nsCOMPtr<nsICacheEntryDescriptor> entry;
181
rv = ses->OpenCacheEntry(spec.get(), nsICache::ACCESS_WRITE, nsICache::BLOCKING, getter_AddRefs(entry));
183
if (NS_FAILED(rv) || !entry)
186
nsCOMPtr<nsISupports> sup = NS_REINTERPRET_CAST(nsISupports*, request);
187
entry->SetCacheElement(sup);
191
// If file, force revalidation on expiration
193
aKey->SchemeIs("file", &isFile);
195
entry->SetMetaDataElement("MustValidateIfExpired", "true");
204
SecondsFromPRTime(PRTime prTime)
206
PRInt64 microSecondsPerSecond, intermediateResult;
209
LL_I2L(microSecondsPerSecond, PR_USEC_PER_SEC);
210
LL_DIV(intermediateResult, prTime, microSecondsPerSecond);
211
LL_L2UI(seconds, intermediateResult);
216
PRBool imgCache::Get(nsIURI *aKey, PRBool *aHasExpired, imgRequest **aRequest, nsICacheEntryDescriptor **aEntry)
218
LOG_STATIC_FUNC(gImgLog, "imgCache::Get");
222
nsCOMPtr<nsICacheSession> ses;
223
GetCacheSession(aKey, getter_AddRefs(ses));
224
if (!ses) return PR_FALSE;
227
aKey->GetAsciiSpec(spec);
229
nsCOMPtr<nsICacheEntryDescriptor> entry;
231
rv = ses->OpenCacheEntry(spec.get(), nsICache::ACCESS_READ, nsICache::BLOCKING, getter_AddRefs(entry));
233
if (NS_FAILED(rv) || !entry)
237
PRUint32 expirationTime;
238
rv = entry->GetExpirationTime(&expirationTime);
239
if (NS_FAILED(rv) || (expirationTime <= SecondsFromPRTime(PR_Now()))) {
240
*aHasExpired = PR_TRUE;
242
*aHasExpired = PR_FALSE;
244
// Special treatment for file URLs - entry has expired if file has changed
245
nsCOMPtr<nsIFileURL> fileUrl(do_QueryInterface(aKey));
247
PRUint32 lastModTime;
248
entry->GetLastModified(&lastModTime);
250
nsCOMPtr<nsIFile> theFile;
251
rv = fileUrl->GetFile(getter_AddRefs(theFile));
252
if (NS_SUCCEEDED(rv)) {
254
rv = theFile->GetLastModifiedTime(&fileLastMod);
255
if (NS_SUCCEEDED(rv)) {
256
// nsIFile uses millisec, NSPR usec
257
PRInt64 one_thousand = LL_INIT(0, 1000);
258
LL_MUL(fileLastMod, fileLastMod, one_thousand);
259
*aHasExpired = SecondsFromPRTime((PRTime)fileLastMod) > lastModTime;
265
nsCOMPtr<nsISupports> sup;
266
entry->GetCacheElement(getter_AddRefs(sup));
268
*aRequest = NS_REINTERPRET_CAST(imgRequest*, sup.get());
269
NS_IF_ADDREF(*aRequest);
278
PRBool imgCache::Remove(nsIURI *aKey)
280
LOG_STATIC_FUNC(gImgLog, "imgCache::Remove");
281
if (!aKey) return PR_FALSE;
284
nsCOMPtr<nsICacheSession> ses;
285
GetCacheSession(aKey, getter_AddRefs(ses));
286
if (!ses) return PR_FALSE;
289
aKey->GetAsciiSpec(spec);
291
nsCOMPtr<nsICacheEntryDescriptor> entry;
293
rv = ses->OpenCacheEntry(spec.get(), nsICache::ACCESS_READ, nsICache::BLOCKING, getter_AddRefs(entry));
295
if (NS_FAILED(rv) || !entry)
305
imgCache::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aSomeData)
307
if (strcmp(aTopic, "memory-pressure") == 0 ||
308
strcmp(aTopic, "chrome-flush-skin-caches") == 0 ||
309
strcmp(aTopic, "chrome-flush-caches") == 0)