Bug 722861 - Add privacy information to image requests, and use a separate cache for private requests. r=joe

This commit is contained in:
Josh Matthews 2012-06-26 00:20:12 -04:00
parent 6eef761549
commit 1c909a96b0
22 changed files with 382 additions and 209 deletions

View File

@ -482,13 +482,6 @@ public:
return sIOService;
}
static imgILoader* GetImgLoader()
{
if (!sImgLoaderInitialized)
InitImgLoader();
return sImgLoader;
}
#ifdef MOZ_XTF
static nsIXTFService* GetXTFService();
#endif
@ -663,10 +656,17 @@ public:
int32_t aLoadFlags,
imgIRequest** aRequest);
/**
* Obtain an image loader that respects the given document/channel's privacy status.
* Null document/channel arguments return the public image loader.
*/
static imgILoader* GetImgLoaderForDocument(nsIDocument* aDoc);
static imgILoader* GetImgLoaderForChannel(nsIChannel* aChannel);
/**
* Returns whether the given URI is in the image cache.
*/
static bool IsImageInCache(nsIURI* aURI);
static bool IsImageInCache(nsIURI* aURI, nsIDocument* aDocument);
/**
* Method to get an imgIContainer from an image loading content
@ -2160,9 +2160,11 @@ private:
static bool sImgLoaderInitialized;
static void InitImgLoader();
// The following two members are initialized lazily
// The following four members are initialized lazily
static imgILoader* sImgLoader;
static imgILoader* sPrivateImgLoader;
static imgICache* sImgCache;
static imgICache* sPrivateImgCache;
static nsIConsoleService* sConsoleService;

View File

@ -50,6 +50,7 @@ EXPORTS_mozilla/dom = \
$(NULL)
LOCAL_INCLUDES = \
-I$(topsrcdir)/image/src \
$(NULL)
CPPSRCS = \

View File

@ -119,6 +119,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
#include "nsIDOMHTMLInputElement.h"
#include "nsParserConstants.h"
#include "nsIWebNavigation.h"
#include "nsILoadContext.h"
#include "nsTextFragment.h"
#include "mozilla/Selection.h"
@ -134,6 +135,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
#include "mozAutoDocUpdate.h"
#include "imgICache.h"
#include "imgLoader.h"
#include "xpcprivate.h" // nsXPConnect
#include "nsScriptSecurityManager.h"
#include "nsIChannelPolicy.h"
@ -187,7 +189,9 @@ nsIIOService *nsContentUtils::sIOService;
nsIXTFService *nsContentUtils::sXTFService = nullptr;
#endif
imgILoader *nsContentUtils::sImgLoader;
imgILoader *nsContentUtils::sPrivateImgLoader;
imgICache *nsContentUtils::sImgCache;
imgICache *nsContentUtils::sPrivateImgCache;
nsIConsoleService *nsContentUtils::sConsoleService;
nsDataHashtable<nsISupportsHashKey, EventNameMapping>* nsContentUtils::sAtomEventTable = nullptr;
nsDataHashtable<nsStringHashKey, EventNameMapping>* nsContentUtils::sStringEventTable = nullptr;
@ -508,15 +512,17 @@ nsContentUtils::InitImgLoader()
sImgLoaderInitialized = true;
// Ignore failure and just don't load images
nsresult rv = CallGetService("@mozilla.org/image/loader;1", &sImgLoader);
if (NS_FAILED(rv)) {
// no image loading for us. Oh, well.
sImgLoader = nullptr;
sImgCache = nullptr;
} else {
if (NS_FAILED(CallGetService("@mozilla.org/image/cache;1", &sImgCache )))
sImgCache = nullptr;
}
nsresult rv = CallCreateInstance("@mozilla.org/image/loader;1", &sImgLoader);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Creation should have succeeded");
rv = CallCreateInstance("@mozilla.org/image/loader;1", &sPrivateImgLoader);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Creation should have succeeded");
rv = CallQueryInterface(sImgLoader, &sImgCache);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "imgICache and imgILoader should be paired");
rv = CallQueryInterface(sPrivateImgLoader, &sPrivateImgCache);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "imgICache and imgILoader should be paired");
sPrivateImgCache->RespectPrivacyNotifications();
}
bool
@ -1493,7 +1499,9 @@ nsContentUtils::Shutdown()
NS_IF_RELEASE(sXTFService);
#endif
NS_IF_RELEASE(sImgLoader);
NS_IF_RELEASE(sPrivateImgLoader);
NS_IF_RELEASE(sImgCache);
NS_IF_RELEASE(sPrivateImgCache);
#ifdef IBMBIDI
NS_IF_RELEASE(sBidiKeyboard);
#endif
@ -2692,19 +2700,60 @@ nsContentUtils::CanLoadImage(nsIURI* aURI, nsISupports* aContext,
return NS_FAILED(rv) ? false : NS_CP_ACCEPTED(decision);
}
imgILoader*
nsContentUtils::GetImgLoaderForDocument(nsIDocument* aDoc)
{
if (!sImgLoaderInitialized)
InitImgLoader();
if (!aDoc)
return sImgLoader;
bool isPrivate = false;
nsCOMPtr<nsILoadGroup> loadGroup = aDoc->GetDocumentLoadGroup();
nsCOMPtr<nsIInterfaceRequestor> callbacks;
if (loadGroup) {
loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
if (callbacks) {
nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
isPrivate = loadContext && loadContext->UsePrivateBrowsing();
}
} else {
nsCOMPtr<nsIChannel> channel = aDoc->GetChannel();
if (channel) {
nsCOMPtr<nsILoadContext> context;
NS_QueryNotificationCallbacks(channel, context);
isPrivate = context && context->UsePrivateBrowsing();
}
}
return isPrivate ? sPrivateImgLoader : sImgLoader;
}
// static
imgILoader*
nsContentUtils::GetImgLoaderForChannel(nsIChannel* aChannel)
{
if (!sImgLoaderInitialized)
InitImgLoader();
if (!aChannel)
return sImgLoader;
nsCOMPtr<nsILoadContext> context;
NS_QueryNotificationCallbacks(aChannel, context);
return context && context->UsePrivateBrowsing() ? sPrivateImgLoader : sImgLoader;
}
// static
bool
nsContentUtils::IsImageInCache(nsIURI* aURI)
nsContentUtils::IsImageInCache(nsIURI* aURI, nsIDocument* aDocument)
{
if (!sImgLoaderInitialized)
InitImgLoader();
if (!sImgCache) return false;
imgILoader* loader = GetImgLoaderForDocument(aDocument);
nsCOMPtr<imgICache> cache = do_QueryInterface(loader);
// If something unexpected happened we return false, otherwise if props
// is set, the image is cached and we return true
nsCOMPtr<nsIProperties> props;
nsresult rv = sImgCache->FindEntryProperties(aURI, getter_AddRefs(props));
nsresult rv = cache->FindEntryProperties(aURI, getter_AddRefs(props));
return (NS_SUCCEEDED(rv) && props);
}
@ -2720,7 +2769,7 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
NS_PRECONDITION(aLoadingPrincipal, "Must have a principal");
NS_PRECONDITION(aRequest, "Null out param");
imgILoader* imgLoader = GetImgLoader();
imgILoader* imgLoader = GetImgLoaderForDocument(aLoadingDocument);
if (!imgLoader) {
// nothing we can do here
return NS_OK;

View File

@ -7681,7 +7681,7 @@ nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr)
// which indicates that the "real" load has already started and
// that we shouldn't preload it.
int16_t blockingStatus;
if (nsContentUtils::IsImageInCache(uri) ||
if (nsContentUtils::IsImageInCache(uri, static_cast<nsIDocument *>(this)) ||
!nsContentUtils::CanLoadImage(uri, static_cast<nsIDocument *>(this),
this, NodePrincipal(), &blockingStatus)) {
return;

View File

@ -88,7 +88,7 @@ nsImageLoadingContent::nsImageLoadingContent()
mCurrentRequestRegistered(false),
mPendingRequestRegistered(false)
{
if (!nsContentUtils::GetImgLoader()) {
if (!nsContentUtils::GetImgLoaderForChannel(nullptr)) {
mLoadingEnabled = false;
}
}
@ -334,7 +334,7 @@ nsImageLoadingContent::SetLoadingEnabled(bool aLoadingEnabled)
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
if (nsContentUtils::GetImgLoader()) {
if (nsContentUtils::GetImgLoaderForChannel(nullptr)) {
mLoadingEnabled = aLoadingEnabled;
}
return NS_OK;
@ -518,7 +518,7 @@ nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
if (!nsContentUtils::GetImgLoader()) {
if (!nsContentUtils::GetImgLoaderForChannel(aChannel)) {
return NS_ERROR_NULL_POINTER;
}
@ -537,7 +537,7 @@ nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
// Do the load.
nsCOMPtr<imgIRequest>& req = PrepareNextRequest();
nsresult rv = nsContentUtils::GetImgLoader()->
nsresult rv = nsContentUtils::GetImgLoaderForChannel(aChannel)->
LoadImageWithChannel(aChannel, this, doc, aListener,
getter_AddRefs(req));
if (NS_SUCCEEDED(rv)) {

View File

@ -477,7 +477,7 @@ URIEquals(nsIURI *a, nsIURI *b)
static bool
IsSupportedImage(const nsCString& aMimeType)
{
imgILoader* loader = nsContentUtils::GetImgLoader();
nsCOMPtr<imgILoader> loader = nsContentUtils::GetImgLoaderForChannel(nullptr);
if (!loader) {
return false;
}

View File

@ -24,9 +24,9 @@ nsWebNavigationInfo::Init()
mCategoryManager = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
mImgLoader = do_GetService("@mozilla.org/image/loader;1", &rv);
mImgLoader = nsContentUtils::GetImgLoaderForChannel(nullptr);
return rv;
return NS_OK;
}
NS_IMETHODIMP

View File

@ -301,8 +301,7 @@ nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode *aDOMNode, imgIR
NS_NewURI(getter_AddRefs(bgUri), bgStringValue);
NS_ENSURE_TRUE(bgUri, NS_ERROR_FAILURE);
nsCOMPtr<imgILoader> il(do_GetService(
"@mozilla.org/image/loader;1"));
nsCOMPtr<imgILoader> il(do_CreateInstance("@mozilla.org/image/loader;1"));
NS_ENSURE_TRUE(il, NS_ERROR_FAILURE);
return il->LoadImage(bgUri, nullptr, nullptr, principal, nullptr,

View File

@ -96,7 +96,7 @@ static nsresult
imglib_Initialize()
{
mozilla::image::DiscardTracker::Initialize();
imgLoader::InitCache();
imgLoader::GlobalInit();
return NS_OK;
}

View File

@ -17,7 +17,7 @@ interface nsIProperties;
* @version 0.1
* @see imagelib2
*/
[scriptable, uuid(f1b74aae-5661-4753-a21c-66dd644afebc)]
[scriptable, uuid(b06e0fa5-d6e2-4fa3-8fc0-7775aed96522)]
interface imgICache : nsISupports
{
/**
@ -49,4 +49,11 @@ interface imgICache : nsISupports
* @returns NULL if the URL was not found in the cache
*/
nsIProperties findEntryProperties(in nsIURI uri);
/**
* Make this cache instance respect private browsing notifications. This entails clearing
* the chrome and content caches whenever the last-pb-context-exited notification is
* observed.
*/
void respectPrivacyNotifications();
};

View File

@ -8,8 +8,11 @@
interface nsIInputStream;
interface imgIContainer;
interface imgILoader;
interface imgICache;
interface nsIDOMDocument;
[scriptable, uuid(8e16f39e-7012-46bd-aa22-2a7a3265608f)]
[scriptable, uuid(53dd1cbe-cb9f-4d9e-8104-1ab72851c88e)]
interface imgITools : nsISupports
{
/**
@ -71,6 +74,26 @@ interface imgITools : nsISupports
in long aHeight,
[optional] in AString outputOptions);
/**
* getImgLoaderForDocument
* Retrieve an image loader that reflects the privacy status of the given
* document.
*
* @param doc
* A document. Must not be null.
*/
imgILoader getImgLoaderForDocument(in nsIDOMDocument doc);
/**
* getImgLoaderForDocument
* Retrieve an image cache that reflects the privacy status of the given
* document.
*
* @param doc
* A document. Must not be null.
*/
imgICache getImgCacheForDocument(in nsIDOMDocument doc);
/**
* encodeCroppedImage
* Caller provides an image container, and the mime type it should be

View File

@ -50,7 +50,6 @@
#include "nsIApplicationCacheContainer.h"
#include "nsIMemoryReporter.h"
#include "nsIPrivateBrowsingService.h"
// we want to explore making the document own the load group
// so we can associate the document URI with the load group.
@ -58,6 +57,7 @@
#include "nsIHttpChannelInternal.h"
#include "nsIContentSecurityPolicy.h"
#include "nsIChannelPolicy.h"
#include "nsILoadContext.h"
#include "nsContentUtils.h"
@ -87,8 +87,11 @@ public:
{
AllSizes chrome;
AllSizes content;
imgLoader::sChromeCache.EnumerateRead(EntryAllSizes, &chrome);
imgLoader::sCache.EnumerateRead(EntryAllSizes, &content);
for (PRUint32 i = 0; i < mKnownLoaders.Length(); i++) {
mKnownLoaders[i]->mChromeCache.EnumerateRead(EntryAllSizes, &chrome);
mKnownLoaders[i]->mCache.EnumerateRead(EntryAllSizes, &content);
}
#define REPORT(_path, _kind, _amount, _desc) \
do { \
@ -155,8 +158,10 @@ public:
NS_IMETHOD GetExplicitNonHeap(int64_t *n)
{
size_t n2 = 0;
imgLoader::sChromeCache.EnumerateRead(EntryExplicitNonHeapSize, &n2);
imgLoader::sCache.EnumerateRead(EntryExplicitNonHeapSize, &n2);
for (PRUint32 i = 0; i < mKnownLoaders.Length(); i++) {
mKnownLoaders[i]->mChromeCache.EnumerateRead(EntryExplicitNonHeapSize, &n2);
mKnownLoaders[i]->mCache.EnumerateRead(EntryExplicitNonHeapSize, &n2);
}
*n = n2;
return NS_OK;
}
@ -164,11 +169,25 @@ public:
static int64_t GetImagesContentUsedUncompressed()
{
size_t n = 0;
imgLoader::sCache.EnumerateRead(EntryUsedUncompressedSize, &n);
for (PRUint32 i = 0; i < imgLoader::sMemReporter->mKnownLoaders.Length(); i++) {
imgLoader::sMemReporter->mKnownLoaders[i]->mCache.EnumerateRead(EntryUsedUncompressedSize, &n);
}
return n;
}
void RegisterLoader(imgLoader* aLoader)
{
mKnownLoaders.AppendElement(aLoader);
}
void UnregisterLoader(imgLoader* aLoader)
{
mKnownLoaders.RemoveElement(aLoader);
}
private:
nsTArray<imgLoader*> mKnownLoaders;
struct AllSizes {
size_t mUsedRaw;
size_t mUsedUncompressedHeap;
@ -339,11 +358,11 @@ nsProgressNotificationProxy::GetInterface(const nsIID& iid,
return NS_NOINTERFACE;
}
static void NewRequestAndEntry(bool aForcePrincipalCheckForCacheEntry,
static void NewRequestAndEntry(bool aForcePrincipalCheckForCacheEntry, imgLoader* aLoader,
imgRequest **aRequest, imgCacheEntry **aEntry)
{
nsRefPtr<imgRequest> request = new imgRequest();
nsRefPtr<imgCacheEntry> entry = new imgCacheEntry(request, aForcePrincipalCheckForCacheEntry);
nsRefPtr<imgRequest> request = new imgRequest(aLoader);
nsRefPtr<imgCacheEntry> entry = new imgCacheEntry(aLoader, request, aForcePrincipalCheckForCacheEntry);
request.forget(aRequest);
entry.forget(aEntry);
}
@ -511,8 +530,9 @@ static uint32_t SecondsFromPRTime(PRTime prTime)
return uint32_t(int64_t(prTime) / int64_t(PR_USEC_PER_SEC));
}
imgCacheEntry::imgCacheEntry(imgRequest *request, bool forcePrincipalCheck)
: mRequest(request),
imgCacheEntry::imgCacheEntry(imgLoader* loader, imgRequest *request, bool forcePrincipalCheck)
: mLoader(loader),
mRequest(request),
mDataSize(0),
mTouchedTime(SecondsFromPRTime(PR_Now())),
mExpiryTime(0),
@ -546,7 +566,7 @@ void imgCacheEntry::UpdateCache(int32_t diff /* = 0 */)
if (!Evicted() && HasNoProxies()) {
nsCOMPtr<nsIURI> uri;
mRequest->GetURI(getter_AddRefs(uri));
imgLoader::CacheEntriesChanged(uri, diff);
mLoader->CacheEntriesChanged(uri, diff);
}
}
@ -706,8 +726,6 @@ class imgCacheObserver MOZ_FINAL : public nsIObserver
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
private:
imgLoader mLoader;
};
NS_IMPL_ISUPPORTS1(imgCacheObserver, nsIObserver)
@ -717,10 +735,6 @@ imgCacheObserver::Observe(nsISupports* aSubject, const char* aTopic, const PRUni
{
if (strcmp(aTopic, "memory-pressure") == 0) {
DiscardTracker::DiscardAll();
mLoader.MinimizeCaches();
} else if (strcmp(aTopic, "chrome-flush-skin-caches") == 0 ||
strcmp(aTopic, "chrome-flush-caches") == 0) {
mLoader.ClearChromeImageCache();
}
return NS_OK;
}
@ -760,45 +774,44 @@ void imgCacheExpirationTracker::NotifyExpired(imgCacheEntry *entry)
// We can be called multiple times on the same entry. Don't do work multiple
// times.
if (!entry->Evicted())
imgLoader::RemoveFromCache(entry);
entry->Loader()->RemoveFromCache(entry);
imgLoader::VerifyCacheSizes();
entry->Loader()->VerifyCacheSizes();
}
imgCacheObserver *gCacheObserver;
imgCacheExpirationTracker *gCacheTracker;
imgLoader::imgCacheTable imgLoader::sCache;
imgCacheQueue imgLoader::sCacheQueue;
imgLoader::imgCacheTable imgLoader::sChromeCache;
imgCacheQueue imgLoader::sChromeCacheQueue;
double imgLoader::sCacheTimeWeight;
uint32_t imgLoader::sCacheMaxSize;
imgMemoryReporter* imgLoader::sMemReporter;
NS_IMPL_ISUPPORTS5(imgLoader, imgILoader, nsIContentSniffer, imgICache, nsISupportsWeakReference, nsIObserver)
imgLoader::imgLoader()
: mRespectPrivacy(false)
{
/* member initializers and constructor code */
sMemReporter->AddRef();
sMemReporter->RegisterLoader(this);
}
imgLoader::~imgLoader()
{
/* destructor code */
ClearChromeImageCache();
ClearImageCache();
sMemReporter->UnregisterLoader(this);
sMemReporter->Release();
}
void imgLoader::VerifyCacheSizes()
{
#ifdef DEBUG
if (!gCacheTracker)
if (!mCacheTracker)
return;
uint32_t cachesize = sCache.Count() + sChromeCache.Count();
uint32_t queuesize = sCacheQueue.GetNumElements() + sChromeCacheQueue.GetNumElements();
uint32_t cachesize = mCache.Count() + mChromeCache.Count();
uint32_t queuesize = mCacheQueue.GetNumElements() + mChromeCacheQueue.GetNumElements();
uint32_t trackersize = 0;
for (nsExpirationTracker<imgCacheEntry, 3>::Iterator it(gCacheTracker); it.Next(); )
for (nsExpirationTracker<imgCacheEntry, 3>::Iterator it(mCacheTracker); it.Next(); )
trackersize++;
NS_ABORT_IF_FALSE(queuesize == trackersize, "Queue and tracker sizes out of sync!");
NS_ABORT_IF_FALSE(queuesize <= cachesize, "Queue has more elements than cache!");
@ -810,9 +823,9 @@ imgLoader::imgCacheTable & imgLoader::GetCache(nsIURI *aURI)
bool chrome = false;
aURI->SchemeIs("chrome", &chrome);
if (chrome)
return sChromeCache;
return mChromeCache;
else
return sCache;
return mCache;
}
imgCacheQueue & imgLoader::GetCacheQueue(nsIURI *aURI)
@ -820,34 +833,22 @@ imgCacheQueue & imgLoader::GetCacheQueue(nsIURI *aURI)
bool chrome = false;
aURI->SchemeIs("chrome", &chrome);
if (chrome)
return sChromeCacheQueue;
return mChromeCacheQueue;
else
return sCacheQueue;
return mCacheQueue;
}
nsresult imgLoader::InitCache()
void imgLoader::GlobalInit()
{
NS_TIME_FUNCTION;
nsresult rv;
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (!os)
return NS_ERROR_FAILURE;
gCacheObserver = new imgCacheObserver();
NS_ADDREF(gCacheObserver);
os->AddObserver(gCacheObserver, "memory-pressure", false);
os->AddObserver(gCacheObserver, "chrome-flush-skin-caches", false);
os->AddObserver(gCacheObserver, "chrome-flush-caches", false);
gCacheTracker = new imgCacheExpirationTracker();
sCache.Init();
sChromeCache.Init();
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os)
os->AddObserver(gCacheObserver, "memory-pressure", false);
int32_t timeweight;
rv = Preferences::GetInt("image.cache.timeweight", &timeweight);
nsresult rv = Preferences::GetInt("image.cache.timeweight", &timeweight);
if (NS_SUCCEEDED(rv))
sCacheTimeWeight = timeweight / 1000.0;
else
@ -860,23 +861,49 @@ nsresult imgLoader::InitCache()
else
sCacheMaxSize = 5 * 1024 * 1024;
NS_RegisterMemoryMultiReporter(new imgMemoryReporter());
sMemReporter = new imgMemoryReporter();
NS_RegisterMemoryMultiReporter(sMemReporter);
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(ImagesContentUsedUncompressed));
return NS_OK;
}
nsresult imgLoader::InitCache()
{
NS_TIME_FUNCTION;
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (!os)
return NS_ERROR_FAILURE;
os->AddObserver(this, "memory-pressure", false);
os->AddObserver(this, "chrome-flush-skin-caches", false);
os->AddObserver(this, "chrome-flush-caches", false);
os->AddObserver(this, "last-pb-context-exited", false);
os->AddObserver(this, "profile-before-change", false);
os->AddObserver(this, "xpcom-shutdown", false);
mCacheTracker = new imgCacheExpirationTracker();
mCache.Init();
mChromeCache.Init();
return NS_OK;
}
nsresult imgLoader::Init()
{
InitCache();
ReadAcceptHeaderPref();
Preferences::AddWeakObserver(this, "image.http.accept");
// Listen for when we leave private browsing mode
nsCOMPtr<nsIObserverService> obService = mozilla::services::GetObserverService();
if (obService)
obService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, true);
return NS_OK;
}
NS_IMETHODIMP
imgLoader::RespectPrivacyNotifications()
{
mRespectPrivacy = true;
return NS_OK;
}
@ -888,12 +915,21 @@ imgLoader::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* a
if (!strcmp(NS_ConvertUTF16toUTF8(aData).get(), "image.http.accept")) {
ReadAcceptHeaderPref();
}
}
// ...and exits from private browsing.
else if (!strcmp(aTopic, NS_PRIVATE_BROWSING_SWITCH_TOPIC)) {
if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).Equals(aData))
} else if (strcmp(aTopic, "memory-pressure") == 0) {
MinimizeCaches();
} else if (strcmp(aTopic, "chrome-flush-skin-caches") == 0 ||
strcmp(aTopic, "chrome-flush-caches") == 0) {
MinimizeCaches();
ClearChromeImageCache();
} else if (strcmp(aTopic, "last-pb-context-exited") == 0) {
if (mRespectPrivacy) {
ClearImageCache();
ClearChromeImageCache();
}
} else if (strcmp(aTopic, "profile-before-change") == 0 ||
strcmp(aTopic, "xpcom-shutdown") == 0) {
mCacheTracker = nullptr;
}
// (Nothing else should bring us here)
@ -942,8 +978,8 @@ NS_IMETHODIMP imgLoader::FindEntryProperties(nsIURI *uri, nsIProperties **_retva
*_retval = nullptr;
if (cache.Get(spec, getter_AddRefs(entry)) && entry) {
if (gCacheTracker && entry->HasNoProxies())
gCacheTracker->MarkUsed(entry);
if (mCacheTracker && entry->HasNoProxies())
mCacheTracker->MarkUsed(entry);
nsRefPtr<imgRequest> request = getter_AddRefs(entry->GetRequest());
if (request) {
@ -957,27 +993,23 @@ NS_IMETHODIMP imgLoader::FindEntryProperties(nsIURI *uri, nsIProperties **_retva
void imgLoader::Shutdown()
{
ClearChromeImageCache();
ClearImageCache();
NS_IF_RELEASE(gCacheObserver);
delete gCacheTracker;
gCacheTracker = nullptr;
NS_RELEASE(gCacheObserver);
}
nsresult imgLoader::ClearChromeImageCache()
{
return EvictEntries(sChromeCache);
return EvictEntries(mChromeCache);
}
nsresult imgLoader::ClearImageCache()
{
return EvictEntries(sCache);
return EvictEntries(mCache);
}
void imgLoader::MinimizeCaches()
{
EvictEntries(sCacheQueue);
EvictEntries(sChromeCacheQueue);
EvictEntries(mCacheQueue);
EvictEntries(mChromeCacheQueue);
}
bool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry)
@ -1020,8 +1052,8 @@ bool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry)
if (entry->HasNoProxies()) {
nsresult addrv = NS_OK;
if (gCacheTracker)
addrv = gCacheTracker->AddObject(entry);
if (mCacheTracker)
addrv = mCacheTracker->AddObject(entry);
if (NS_SUCCEEDED(addrv)) {
imgCacheQueue &queue = GetCacheQueue(key);
@ -1051,8 +1083,8 @@ bool imgLoader::SetHasNoProxies(nsIURI *key, imgCacheEntry *entry)
nsresult addrv = NS_OK;
if (gCacheTracker)
addrv = gCacheTracker->AddObject(entry);
if (mCacheTracker)
addrv = mCacheTracker->AddObject(entry);
if (NS_SUCCEEDED(addrv)) {
queue.Push(entry);
@ -1081,8 +1113,8 @@ bool imgLoader::SetHasProxies(nsIURI *key)
imgCacheQueue &queue = GetCacheQueue(key);
queue.Remove(entry);
if (gCacheTracker)
gCacheTracker->RemoveObject(entry);
if (mCacheTracker)
mCacheTracker->RemoveObject(entry);
entry->SetHasNoProxies(false);
@ -1207,7 +1239,7 @@ bool imgLoader::ValidateRequestWithNewChannel(imgRequest *request,
return false;
nsRefPtr<imgCacheValidator> hvc =
new imgCacheValidator(progressproxy, request, aCX, forcePrincipalCheck);
new imgCacheValidator(progressproxy, this, request, aCX, forcePrincipalCheck);
nsCOMPtr<nsIStreamListener> listener = hvc.get();
@ -1388,8 +1420,8 @@ bool imgLoader::RemoveFromCache(nsIURI *aKey)
// Entries with no proxies are in the tracker.
if (entry->HasNoProxies()) {
if (gCacheTracker)
gCacheTracker->RemoveObject(entry);
if (mCacheTracker)
mCacheTracker->RemoveObject(entry);
queue.Remove(entry);
}
@ -1423,8 +1455,8 @@ bool imgLoader::RemoveFromCache(imgCacheEntry *entry)
if (entry->HasNoProxies()) {
LOG_STATIC_FUNC(gImgLog, "imgLoader::RemoveFromCache removing from tracker");
if (gCacheTracker)
gCacheTracker->RemoveObject(entry);
if (mCacheTracker)
mCacheTracker->RemoveObject(entry);
queue.Remove(entry);
}
@ -1524,6 +1556,25 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
nsresult rv;
nsLoadFlags requestFlags = nsIRequest::LOAD_NORMAL;
#ifdef DEBUG
bool isPrivate = false;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
if (channel) {
nsCOMPtr<nsILoadContext> loadContext;
NS_QueryNotificationCallbacks(channel, loadContext);
isPrivate = loadContext && loadContext->UsePrivateBrowsing();
} else if (aLoadGroup) {
nsCOMPtr<nsIInterfaceRequestor> callbacks;
aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
if (callbacks) {
nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
isPrivate = loadContext && loadContext->UsePrivateBrowsing();
}
}
MOZ_ASSERT(isPrivate == mRespectPrivacy);
#endif
// Get the default load flags from the loadgroup (if possible)...
if (aLoadGroup) {
aLoadGroup->GetLoadFlags(&requestFlags);
@ -1577,8 +1628,8 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
NS_ABORT_IF_FALSE(!request->HasCacheEntry(), "Proxyless entry's request has cache entry!");
request->SetCacheEntry(entry);
if (gCacheTracker)
gCacheTracker->MarkUsed(entry);
if (mCacheTracker)
mCacheTracker->MarkUsed(entry);
}
entry->Touch();
@ -1615,8 +1666,13 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
NewRequestAndEntry(forcePrincipalCheck, getter_AddRefs(request),
getter_AddRefs(entry));
#ifdef DEBUG
nsCOMPtr<nsILoadContext> loadContext;
NS_QueryNotificationCallbacks(newChannel, loadContext);
MOZ_ASSERT_IF(loadContext, loadContext->UsePrivateBrowsing() == mRespectPrivacy);
#endif
NewRequestAndEntry(forcePrincipalCheck, this, getter_AddRefs(request), getter_AddRefs(entry));
PR_LOG(gImgLog, PR_LOG_DEBUG,
("[this=%p] imgLoader::LoadImage -- Created new imgRequest [request=%p]\n", this, request.get()));
@ -1741,6 +1797,12 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
{
NS_ASSERTION(channel, "imgLoader::LoadImageWithChannel -- NULL channel pointer");
#ifdef DEBUG
nsCOMPtr<nsILoadContext> loadContext;
NS_QueryNotificationCallbacks(channel, loadContext);
MOZ_ASSERT_IF(loadContext, loadContext->UsePrivateBrowsing() == mRespectPrivacy);
#endif
nsRefPtr<imgRequest> request;
nsCOMPtr<nsIURI> uri;
@ -1798,8 +1860,8 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
NS_ABORT_IF_FALSE(!request->HasCacheEntry(), "Proxyless entry's request has cache entry!");
request->SetCacheEntry(entry);
if (gCacheTracker)
gCacheTracker->MarkUsed(entry);
if (mCacheTracker)
mCacheTracker->MarkUsed(entry);
}
}
}
@ -1826,7 +1888,7 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
// Default to doing a principal check because we don't know who
// started that load and whether their principal ended up being
// inherited on the channel.
NewRequestAndEntry(true, getter_AddRefs(request), getter_AddRefs(entry));
NewRequestAndEntry(true, this, getter_AddRefs(request), getter_AddRefs(entry));
// We use originalURI here to fulfil the imgIRequest contract on GetURI.
nsCOMPtr<nsIURI> originalURI;
@ -2038,17 +2100,16 @@ NS_IMPL_ISUPPORTS5(imgCacheValidator, nsIStreamListener, nsIRequestObserver,
nsIChannelEventSink, nsIInterfaceRequestor,
nsIAsyncVerifyRedirectCallback)
imgLoader imgCacheValidator::sImgLoader;
imgCacheValidator::imgCacheValidator(nsProgressNotificationProxy* progress,
imgRequest *request, void *aContext,
bool forcePrincipalCheckForCacheEntry)
imgLoader* loader, imgRequest *request,
void *aContext, bool forcePrincipalCheckForCacheEntry)
: mProgressProxy(progress),
mRequest(request),
mContext(aContext)
mContext(aContext),
mImgLoader(loader)
{
NewRequestAndEntry(forcePrincipalCheckForCacheEntry,
getter_AddRefs(mNewRequest), getter_AddRefs(mNewEntry));
NewRequestAndEntry(forcePrincipalCheckForCacheEntry, loader, getter_AddRefs(mNewRequest),
getter_AddRefs(mNewEntry));
}
imgCacheValidator::~imgCacheValidator()
@ -2151,7 +2212,7 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport
// Try to add the new request into the cache. Note that the entry must be in
// the cache before the proxies' ownership changes, because adding a proxy
// changes the caching behaviour for imgRequests.
sImgLoader.PutIntoCache(originalURI, mNewEntry);
mImgLoader->PutIntoCache(originalURI, mNewEntry);
uint32_t count = mProxies.Count();
for (int32_t i = count-1; i>=0; i--) {

View File

@ -27,16 +27,19 @@
#include "prlock.h"
#endif
class imgLoader;
class imgRequest;
class imgRequestProxy;
class imgIRequest;
class imgIDecoderObserver;
class nsILoadGroup;
class imgCacheExpirationTracker;
class imgMemoryReporter;
class imgCacheEntry
{
public:
imgCacheEntry(imgRequest *request, bool aForcePrincipalCheck);
imgCacheEntry(imgLoader* loader, imgRequest *request, bool aForcePrincipalCheck);
~imgCacheEntry();
nsrefcnt AddRef()
@ -130,6 +133,11 @@ public:
return mForcePrincipalCheck;
}
imgLoader* Loader() const
{
return mLoader;
}
private: // methods
friend class imgLoader;
friend class imgCacheQueue;
@ -148,6 +156,7 @@ private: // data
nsAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD
imgLoader* mLoader;
nsRefPtr<imgRequest> mRequest;
uint32_t mDataSize;
int32_t mTouchedTime;
@ -219,18 +228,19 @@ public:
static nsresult GetMimeTypeFromContent(const char* aContents, uint32_t aLength, nsACString& aContentType);
static void GlobalInit(); // for use by the factory
static void Shutdown(); // for use by the factory
static nsresult ClearChromeImageCache();
static nsresult ClearImageCache();
static void MinimizeCaches();
nsresult ClearChromeImageCache();
nsresult ClearImageCache();
void MinimizeCaches();
static nsresult InitCache();
nsresult InitCache();
static bool RemoveFromCache(nsIURI *aKey);
static bool RemoveFromCache(imgCacheEntry *entry);
bool RemoveFromCache(nsIURI *aKey);
bool RemoveFromCache(imgCacheEntry *entry);
static bool PutIntoCache(nsIURI *key, imgCacheEntry *entry);
bool PutIntoCache(nsIURI *key, imgCacheEntry *entry);
// Returns true if we should prefer evicting cache entry |two| over cache
// entry |one|.
@ -256,7 +266,7 @@ public:
return oneweight < twoweight;
}
static void VerifyCacheSizes();
void VerifyCacheSizes();
// The image loader maintains a hash table of all imgCacheEntries. However,
// only some of them will be evicted from the cache: those who have no
@ -269,8 +279,8 @@ public:
// HasObservers(). The request's cache entry will be re-set before this
// happens, by calling imgRequest::SetCacheEntry() when an entry with no
// observers is re-requested.
static bool SetHasNoProxies(nsIURI *key, imgCacheEntry *entry);
static bool SetHasProxies(nsIURI *key);
bool SetHasNoProxies(nsIURI *key, imgCacheEntry *entry);
bool SetHasProxies(nsIURI *key);
private: // methods
@ -307,27 +317,32 @@ private: // methods
typedef nsRefPtrHashtable<nsCStringHashKey, imgCacheEntry> imgCacheTable;
static nsresult EvictEntries(imgCacheTable &aCacheToClear);
static nsresult EvictEntries(imgCacheQueue &aQueueToClear);
nsresult EvictEntries(imgCacheTable &aCacheToClear);
nsresult EvictEntries(imgCacheQueue &aQueueToClear);
static imgCacheTable &GetCache(nsIURI *aURI);
static imgCacheQueue &GetCacheQueue(nsIURI *aURI);
static void CacheEntriesChanged(nsIURI *aURI, int32_t sizediff = 0);
static void CheckCacheLimits(imgCacheTable &cache, imgCacheQueue &queue);
imgCacheTable &GetCache(nsIURI *aURI);
imgCacheQueue &GetCacheQueue(nsIURI *aURI);
void CacheEntriesChanged(nsIURI *aURI, PRInt32 sizediff = 0);
void CheckCacheLimits(imgCacheTable &cache, imgCacheQueue &queue);
private: // data
friend class imgCacheEntry;
friend class imgMemoryReporter;
static imgCacheTable sCache;
static imgCacheQueue sCacheQueue;
imgCacheTable mCache;
imgCacheQueue mCacheQueue;
imgCacheTable mChromeCache;
imgCacheQueue mChromeCacheQueue;
static imgCacheTable sChromeCache;
static imgCacheQueue sChromeCacheQueue;
static double sCacheTimeWeight;
static uint32_t sCacheMaxSize;
static imgMemoryReporter* sMemReporter;
nsCString mAcceptHeader;
nsAutoPtr<imgCacheExpirationTracker> mCacheTracker;
bool mRespectPrivacy;
};
@ -395,8 +410,8 @@ class imgCacheValidator : public nsIStreamListener,
public nsIAsyncVerifyRedirectCallback
{
public:
imgCacheValidator(nsProgressNotificationProxy* progress, imgRequest *request,
void *aContext, bool forcePrincipalCheckForCacheEntry);
imgCacheValidator(nsProgressNotificationProxy* progress, imgLoader* loader,
imgRequest *request, void *aContext, bool forcePrincipalCheckForCacheEntry);
virtual ~imgCacheValidator();
void AddProxy(imgRequestProxy *aProxy);
@ -422,7 +437,7 @@ private:
void *mContext;
static imgLoader sImgLoader;
imgLoader* mImgLoader;
};
#endif // imgLoader_h__

View File

@ -79,8 +79,8 @@ NS_IMPL_ISUPPORTS8(imgRequest,
nsIInterfaceRequestor,
nsIAsyncVerifyRedirectCallback)
imgRequest::imgRequest() :
mValidator(nullptr), mImageSniffers("image-sniffing-services"),
imgRequest::imgRequest(imgLoader* aLoader) :
mLoader(aLoader), mValidator(nullptr), mImageSniffers("image-sniffing-services"),
mInnerWindowId(0), mCORSMode(imgIRequest::CORS_NONE),
mDecodeRequested(false), mIsMultiPartChannel(false), mGotData(false),
mIsInCache(false), mBlockingOnload(false)
@ -178,7 +178,7 @@ nsresult imgRequest::AddProxy(imgRequestProxy *proxy)
// proxies.
if (mObservers.IsEmpty()) {
NS_ABORT_IF_FALSE(mURI, "Trying to SetHasProxies without key uri.");
imgLoader::SetHasProxies(mURI);
mLoader->SetHasProxies(mURI);
}
// If we don't have any current observers, we should restart any animation.
@ -223,7 +223,7 @@ nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus, bool
if (mCacheEntry) {
NS_ABORT_IF_FALSE(mURI, "Removing last observer without key uri.");
imgLoader::SetHasNoProxies(mURI, mCacheEntry);
mLoader->SetHasNoProxies(mURI, mCacheEntry);
}
#if defined(PR_LOGGING)
else {
@ -328,9 +328,9 @@ void imgRequest::RemoveFromCache()
if (mIsInCache) {
// mCacheEntry is nulled out when we have no more observers.
if (mCacheEntry)
imgLoader::RemoveFromCache(mCacheEntry);
mLoader->RemoveFromCache(mCacheEntry);
else
imgLoader::RemoveFromCache(mURI);
mLoader->RemoveFromCache(mURI);
}
mCacheEntry = nullptr;

View File

@ -31,6 +31,7 @@
class imgCacheValidator;
class imgLoader;
class imgRequestProxy;
class imgCacheEntry;
class imgMemoryReporter;
@ -50,7 +51,7 @@ class imgRequest : public imgIDecoderObserver,
public nsIAsyncVerifyRedirectCallback
{
public:
imgRequest();
imgRequest(imgLoader* aLoader);
virtual ~imgRequest();
NS_DECL_ISUPPORTS
@ -183,6 +184,8 @@ public:
private:
friend class imgMemoryReporter;
// Weak reference to parent loader; this request cannot outlive its owner.
imgLoader* mLoader;
nsCOMPtr<nsIRequest> mRequest;
// The original URI we were loaded with. This is the same as the URI we are
// keyed on in the cache.

View File

@ -8,6 +8,8 @@
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsError.h"
#include "imgILoader.h"
#include "imgICache.h"
#include "imgIContainer.h"
#include "imgIEncoder.h"
#include "imgIDecoderObserver.h"
@ -19,10 +21,14 @@
#include "nsIInterfaceRequestorUtils.h"
#include "nsStreamUtils.h"
#include "nsNetUtil.h"
#include "nsContentUtils.h"
#include "RasterImage.h"
using namespace mozilla::image;
class nsIDOMDocument;
class nsIDocument;
/* ========== imgITools implementation ========== */
@ -269,3 +275,20 @@ NS_IMETHODIMP imgTools::GetFirstImageFrame(imgIContainer *aContainer,
frame.forget(aSurface);
return NS_OK;
}
NS_IMETHODIMP
imgTools::GetImgLoaderForDocument(nsIDOMDocument* aDoc, imgILoader** aLoader)
{
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
NS_IF_ADDREF(*aLoader = nsContentUtils::GetImgLoaderForDocument(doc));
return NS_OK;
}
NS_IMETHODIMP
imgTools::GetImgCacheForDocument(nsIDOMDocument* aDoc, imgICache** aCache)
{
nsCOMPtr<imgILoader> loader;
nsresult rv = GetImgLoaderForDocument(aDoc, getter_AddRefs(loader));
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(loader, aCache);
}

View File

@ -7,9 +7,10 @@
// Helper function to clear the image cache of content images
function clearImageCache()
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var imageCache = Components.classes["@mozilla.org/image/cache;1"]
.getService(Components.interfaces.imgICache);
var tools = SpecialPowers.wrap(Components)
.classes["@mozilla.org/image/tools;1"]
.getService(Components.interfaces.imgITools);
var imageCache = tools.getImgCacheForDocument(window.document);
imageCache.clearCache(false); // true=chrome, false=content
}

View File

@ -85,9 +85,8 @@ function checkSecondLoad()
{
do_test_pending();
var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader);
var listener = new ImageListener(checkClone, secondLoadDone);
requests.push(loader.loadImage(uri, null, null, null, null, listener, null, 0, null, null, null));
requests.push(gCurrentLoader.loadImage(uri, null, null, null, null, listener, null, 0, null, null, null));
listener.synchronous = false;
}
@ -139,12 +138,11 @@ function checkSecondChannelLoad()
var channellistener = new ChannelListener();
channel.asyncOpen(channellistener, null);
var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader);
var listener = new ImageListener(getChannelLoadImageStartCallback(channellistener),
getChannelLoadImageStopCallback(channellistener,
all_done_callback));
var outlistener = {};
requests.push(loader.loadImageWithChannel(channel, listener, null, outlistener));
requests.push(gCurrentLoader.loadImageWithChannel(channel, listener, null, outlistener));
channellistener.outputListener = outlistener.value;
listener.synchronous = false;
@ -152,11 +150,8 @@ function checkSecondChannelLoad()
function run_loadImageWithChannel_tests()
{
// To ensure we're testing what we expect to, clear the content image cache
// between test runs.
var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader);
loader.QueryInterface(Ci.imgICache);
loader.clearCache(false);
// To ensure we're testing what we expect to, create a new loader and cache.
gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader);
do_test_pending();
@ -165,12 +160,11 @@ function run_loadImageWithChannel_tests()
var channellistener = new ChannelListener();
channel.asyncOpen(channellistener, null);
var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader);
var listener = new ImageListener(getChannelLoadImageStartCallback(channellistener),
getChannelLoadImageStopCallback(channellistener,
checkSecondChannelLoad));
var outlistener = {};
requests.push(loader.loadImageWithChannel(channel, listener, null, outlistener));
requests.push(gCurrentLoader.loadImageWithChannel(channel, listener, null, outlistener));
channellistener.outputListener = outlistener.value;
listener.synchronous = false;
@ -185,12 +179,10 @@ function startImageCallback(otherCb)
{
return function(listener, request)
{
var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader);
// Make sure we can load the same image immediately out of the cache.
do_test_pending();
var listener2 = new ImageListener(null, function(foo, bar) { do_test_finished(); });
requests.push(loader.loadImage(uri, null, null, null, null, listener2, null, 0, null, null, null));
requests.push(gCurrentLoader.loadImage(uri, null, null, null, null, listener2, null, 0, null, null, null));
listener2.synchronous = false;
// Now that we've started another load, chain to the callback.
@ -198,13 +190,15 @@ function startImageCallback(otherCb)
}
}
var gCurrentLoader;
function run_test()
{
var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader);
gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader);
do_test_pending();
var listener = new ImageListener(startImageCallback(checkClone), firstLoadDone);
var req = loader.loadImage(uri, null, null, null, null, listener, null, 0, null, null, null);
var req = gCurrentLoader.loadImage(uri, null, null, null, null, listener, null, 0, null, null, null);
requests.push(req);
// Ensure that we don't cause any mayhem when we lock an image.

View File

@ -11,7 +11,9 @@ load('image_load_helpers.js');
var gHits = 0;
var gIoService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
var gLoader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader);
var gPublicLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader);
var gPrivateLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader);
gPrivateLoader.QueryInterface(Ci.imgICache).respectPrivacyNotifications();
function imageHandler(metadata, response) {
gHits++;
@ -55,7 +57,8 @@ function setup_chan(path, isPrivate, callback) {
var listener = new ImageListener(null, callback);
listeners.push(listener);
var outlistener = {};
requests.push(gLoader.loadImageWithChannel(chan, listener, null, outlistener));
var loader = isPrivate ? gPrivateLoader : gPublicLoader;
requests.push(loader.loadImageWithChannel(chan, listener, null, outlistener));
channelListener.outputListener = outlistener.value;
listener.synchronous = false;
}
@ -65,12 +68,12 @@ function loadImage(isPrivate, callback) {
var uri = gIoService.newURI(gImgPath, null, null);
var loadGroup = Cc["@mozilla.org/network/load-group;1"].createInstance(Ci.nsILoadGroup);
loadGroup.notificationCallbacks = new NotificationCallbacks(isPrivate);
requests.push(gLoader.loadImage(uri, null, null, null, loadGroup, listener, null, 0, null, null, null));
var loader = isPrivate ? gPrivateLoader : gPublicLoader;
requests.push(loader.loadImage(uri, null, null, null, loadGroup, listener, null, 0, null, null, null));
listener.synchronous = false;
}
function run_loadImage_tests() {
clearAllImageCaches();
let cs = Cc["@mozilla.org/network/cache-service;1"].getService(Ci.nsICacheService);
cs.evictEntries(Ci.nsICache.STORE_ANYWHERE);
@ -80,21 +83,14 @@ function run_loadImage_tests() {
loadImage(true, function() {
loadImage(true, function() {
do_check_eq(gHits, 2);
do_test_finished();
server.stop(do_test_finished);
});
});
});
});
}
function clearAllImageCaches() {
gLoader.QueryInterface(Ci.imgICache);
gLoader.clearCache(false, false);
gLoader.clearCache(false, true);
}
function run_test() {
clearAllImageCaches();
do_test_pending();
// We create a public channel that loads an image, then an identical

View File

@ -481,7 +481,7 @@ nsContentDLF::CreateXULDocument(const char* aCommand,
}
bool nsContentDLF::IsImageContentType(const char* aContentType) {
nsCOMPtr<imgILoader> loader(do_GetService("@mozilla.org/image/loader;1"));
nsCOMPtr<imgILoader> loader(do_CreateInstance("@mozilla.org/image/loader;1"));
bool isDecoderAvailable = false;
loader->SupportImageWithMimeType(aContentType, &isDecoderAvailable);
return isDecoderAvailable;

View File

@ -1786,8 +1786,8 @@ nsImageFrame::LoadIcon(const nsAString& aSpec,
nsCOMPtr<nsIURI> realURI;
SpecToURI(aSpec, sIOService, getter_AddRefs(realURI));
nsCOMPtr<imgILoader> il(do_GetService("@mozilla.org/image/loader;1", &rv));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<imgILoader> il =
nsContentUtils::GetImgLoaderForDocument(aPresContext->Document());
nsCOMPtr<nsILoadGroup> loadGroup;
GetLoadGroup(aPresContext, getter_AddRefs(loadGroup));

View File

@ -29,6 +29,7 @@
#include "gfxImageSurface.h"
#include "imgIContainer.h"
#include "nsCocoaUtils.h"
#include "nsContentUtils.h"
static const uint32_t kIconWidth = 16;
static const uint32_t kIconHeight = 16;
@ -278,10 +279,8 @@ nsMenuItemIconX::LoadIcon(nsIURI* aIconURI)
nsCOMPtr<nsILoadGroup> loadGroup = document->GetDocumentLoadGroup();
if (!loadGroup) return NS_ERROR_FAILURE;
nsresult rv = NS_ERROR_FAILURE;
nsCOMPtr<imgILoader> loader = do_GetService("@mozilla.org/image/loader;1",
&rv);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<imgILoader> loader = nsContentUtils::GetImgLoaderForDocument(document);
if (!loader) return NS_ERROR_FAILURE;
if (!mSetIcon) {
// Set a completely transparent 16x16 image as the icon on this menu item
@ -306,9 +305,9 @@ nsMenuItemIconX::LoadIcon(nsIURI* aIconURI)
// Passing in null for channelPolicy here since nsMenuItemIconX::LoadIcon is
// not exposed to web content
rv = loader->LoadImage(aIconURI, nullptr, nullptr, nullptr, loadGroup, this,
nullptr, nsIRequest::LOAD_NORMAL, nullptr, nullptr,
nullptr, getter_AddRefs(mIconRequest));
nsresult rv = loader->LoadImage(aIconURI, nullptr, nullptr, nullptr, loadGroup, this,
nullptr, nsIRequest::LOAD_NORMAL, nullptr, nullptr,
nullptr, getter_AddRefs(mIconRequest));
if (NS_FAILED(rv)) return rv;
// We need to request the icon be decoded (bug 573583, bug 705516).