summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/loader/cache/CachedResourceLoader.cpp
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/loader/cache/CachedResourceLoader.cpp
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/loader/cache/CachedResourceLoader.cpp')
-rw-r--r--Source/WebCore/loader/cache/CachedResourceLoader.cpp733
1 files changed, 733 insertions, 0 deletions
diff --git a/Source/WebCore/loader/cache/CachedResourceLoader.cpp b/Source/WebCore/loader/cache/CachedResourceLoader.cpp
new file mode 100644
index 0000000..3fcace6
--- /dev/null
+++ b/Source/WebCore/loader/cache/CachedResourceLoader.cpp
@@ -0,0 +1,733 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
+ Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
+ Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
+ Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+
+#include "config.h"
+#include "CachedResourceLoader.h"
+
+#include "CachedCSSStyleSheet.h"
+#include "CachedFont.h"
+#include "CachedImage.h"
+#include "CachedResourceRequest.h"
+#include "CachedScript.h"
+#include "CachedXSLStyleSheet.h"
+#include "Console.h"
+#include "DOMWindow.h"
+#include "Document.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "HTMLElement.h"
+#include "Logging.h"
+#include "MemoryCache.h"
+#include "PingLoader.h"
+#include "SecurityOrigin.h"
+#include "Settings.h"
+#include <wtf/text/StringConcatenate.h>
+
+#define PRELOAD_DEBUG 0
+
+namespace WebCore {
+
+static CachedResource* createResource(CachedResource::Type type, const KURL& url, const String& charset)
+{
+ switch (type) {
+ case CachedResource::ImageResource:
+ return new CachedImage(url.string());
+ case CachedResource::CSSStyleSheet:
+ return new CachedCSSStyleSheet(url.string(), charset);
+ case CachedResource::Script:
+ return new CachedScript(url.string(), charset);
+ case CachedResource::FontResource:
+ return new CachedFont(url.string());
+#if ENABLE(XSLT)
+ case CachedResource::XSLStyleSheet:
+ return new CachedXSLStyleSheet(url.string());
+#endif
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+ return new CachedResource(url.string(), CachedResource::LinkPrefetch);
+#endif
+ }
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+CachedResourceLoader::CachedResourceLoader(Document* document)
+ : m_cache(cache())
+ , m_document(document)
+ , m_requestCount(0)
+#ifdef ANDROID_BLOCK_NETWORK_IMAGE
+ , m_blockNetworkImage(false)
+#endif
+ , m_autoLoadImages(true)
+ , m_loadFinishing(false)
+ , m_allowStaleResources(false)
+{
+ m_cache->addCachedResourceLoader(this);
+}
+
+CachedResourceLoader::~CachedResourceLoader()
+{
+ cancelRequests();
+ clearPreloads();
+ DocumentResourceMap::iterator end = m_documentResources.end();
+ for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it)
+ it->second->setOwningCachedResourceLoader(0);
+ m_cache->removeCachedResourceLoader(this);
+
+ // Make sure no requests still point to this CachedResourceLoader
+ ASSERT(m_requestCount == 0);
+}
+
+CachedResource* CachedResourceLoader::cachedResource(const String& resourceURL) const
+{
+ KURL url = m_document->completeURL(resourceURL);
+ return cachedResource(url);
+}
+
+CachedResource* CachedResourceLoader::cachedResource(const KURL& resourceURL) const
+{
+ KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL);
+ return m_documentResources.get(url).get();
+}
+
+Frame* CachedResourceLoader::frame() const
+{
+ return m_document->frame();
+}
+
+CachedImage* CachedResourceLoader::requestImage(const String& url)
+{
+ if (Frame* f = frame()) {
+ Settings* settings = f->settings();
+ if (!f->loader()->client()->allowImages(!settings || settings->areImagesEnabled()))
+ return 0;
+
+ if (f->loader()->pageDismissalEventBeingDispatched()) {
+ KURL completeURL = m_document->completeURL(url);
+ if (completeURL.isValid() && canRequest(CachedResource::ImageResource, completeURL))
+ PingLoader::loadImage(f, completeURL);
+ return 0;
+ }
+ }
+ CachedImage* resource = static_cast<CachedImage*>(requestResource(CachedResource::ImageResource, url, String()));
+ if (autoLoadImages() && resource && resource->stillNeedsLoad()) {
+#ifdef ANDROID_BLOCK_NETWORK_IMAGE
+ if (shouldBlockNetworkImage(url)) {
+ return resource;
+ }
+#endif
+ resource->setLoading(true);
+ load(resource, true);
+ }
+ return resource;
+}
+
+CachedFont* CachedResourceLoader::requestFont(const String& url)
+{
+ return static_cast<CachedFont*>(requestResource(CachedResource::FontResource, url, String()));
+}
+
+CachedCSSStyleSheet* CachedResourceLoader::requestCSSStyleSheet(const String& url, const String& charset, ResourceLoadPriority priority)
+{
+ return static_cast<CachedCSSStyleSheet*>(requestResource(CachedResource::CSSStyleSheet, url, charset, priority));
+}
+
+CachedCSSStyleSheet* CachedResourceLoader::requestUserCSSStyleSheet(const String& requestURL, const String& charset)
+{
+ KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(KURL(KURL(), requestURL));
+
+ if (CachedResource* existing = cache()->resourceForURL(url)) {
+ if (existing->type() == CachedResource::CSSStyleSheet)
+ return static_cast<CachedCSSStyleSheet*>(existing);
+ cache()->remove(existing);
+ }
+ CachedCSSStyleSheet* userSheet = new CachedCSSStyleSheet(url, charset);
+
+ bool inCache = cache()->add(userSheet);
+ if (!inCache)
+ userSheet->setInCache(true);
+
+ userSheet->load(this, /*incremental*/ false, SkipSecurityCheck, /*sendResourceLoadCallbacks*/ false);
+
+ if (!inCache)
+ userSheet->setInCache(false);
+
+ return userSheet;
+}
+
+CachedScript* CachedResourceLoader::requestScript(const String& url, const String& charset)
+{
+ return static_cast<CachedScript*>(requestResource(CachedResource::Script, url, charset));
+}
+
+#if ENABLE(XSLT)
+CachedXSLStyleSheet* CachedResourceLoader::requestXSLStyleSheet(const String& url)
+{
+ return static_cast<CachedXSLStyleSheet*>(requestResource(CachedResource::XSLStyleSheet, url, String()));
+}
+#endif
+
+#if ENABLE(LINK_PREFETCH)
+CachedResource* CachedResourceLoader::requestLinkPrefetch(const String& url)
+{
+ ASSERT(frame());
+ return requestResource(CachedResource::LinkPrefetch, url, String());
+}
+#endif
+
+bool CachedResourceLoader::canRequest(CachedResource::Type type, const KURL& url)
+{
+ // Some types of resources can be loaded only from the same origin. Other
+ // types of resources, like Images, Scripts, and CSS, can be loaded from
+ // any URL.
+ switch (type) {
+ case CachedResource::ImageResource:
+ case CachedResource::CSSStyleSheet:
+ case CachedResource::Script:
+ case CachedResource::FontResource:
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+#endif
+ // These types of resources can be loaded from any origin.
+ // FIXME: Are we sure about CachedResource::FontResource?
+ break;
+#if ENABLE(XSLT)
+ case CachedResource::XSLStyleSheet:
+ if (!m_document->securityOrigin()->canRequest(url)) {
+ printAccessDeniedMessage(url);
+ return false;
+ }
+ break;
+#endif
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ // Given that the load is allowed by the same-origin policy, we should
+ // check whether the load passes the mixed-content policy.
+ //
+ // Note: Currently, we always allow mixed content, but we generate a
+ // callback to the FrameLoaderClient in case the embedder wants to
+ // update any security indicators.
+ //
+ switch (type) {
+ case CachedResource::Script:
+#if ENABLE(XSLT)
+ case CachedResource::XSLStyleSheet:
+#endif
+ // These resource can inject script into the current document.
+ if (Frame* f = frame())
+ f->loader()->checkIfRunInsecureContent(m_document->securityOrigin(), url);
+ break;
+ case CachedResource::ImageResource:
+ case CachedResource::CSSStyleSheet:
+ case CachedResource::FontResource: {
+ // These resources can corrupt only the frame's pixels.
+ if (Frame* f = frame()) {
+ Frame* top = f->tree()->top();
+ top->loader()->checkIfDisplayInsecureContent(top->document()->securityOrigin(), url);
+ }
+ break;
+ }
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+ // Prefetch cannot affect the current document.
+ break;
+#endif
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ // FIXME: Consider letting the embedder block mixed content loads.
+ return true;
+}
+
+CachedResource* CachedResourceLoader::requestResource(CachedResource::Type type, const String& resourceURL, const String& charset, ResourceLoadPriority priority, bool forPreload)
+{
+ KURL url = m_document->completeURL(resourceURL);
+
+ LOG(ResourceLoading, "CachedResourceLoader::requestResource '%s', charset '%s', priority=%d, forPreload=%u", url.string().latin1().data(), charset.latin1().data(), priority, forPreload);
+
+ // If only the fragment identifiers differ, it is the same resource.
+ url = MemoryCache::removeFragmentIdentifierIfNeeded(url);
+
+ if (!url.isValid())
+ return 0;
+
+ if (!canRequest(type, url))
+ return 0;
+
+ // FIXME: Figure out what is the correct way to merge this security check with the one above.
+ if (!document()->securityOrigin()->canDisplay(url)) {
+ if (!forPreload)
+ FrameLoader::reportLocalLoadFailed(document()->frame(), url.string());
+ LOG(ResourceLoading, "CachedResourceLoader::requestResource URL was not allowed by SecurityOrigin::canDisplay");
+ return 0;
+ }
+
+ if (cache()->disabled()) {
+ DocumentResourceMap::iterator it = m_documentResources.find(url.string());
+ if (it != m_documentResources.end()) {
+ it->second->setOwningCachedResourceLoader(0);
+ m_documentResources.remove(it);
+ }
+ }
+
+ // See if we can use an existing resource from the cache.
+ CachedResource* resource = cache()->resourceForURL(url);
+
+ switch (determineRevalidationPolicy(type, forPreload, resource)) {
+ case Load:
+ resource = loadResource(type, url, charset, priority);
+ break;
+ case Reload:
+ cache()->remove(resource);
+ resource = loadResource(type, url, charset, priority);
+ break;
+ case Revalidate:
+ resource = revalidateResource(resource, priority);
+ break;
+ case Use:
+ cache()->resourceAccessed(resource);
+ notifyLoadedFromMemoryCache(resource);
+ break;
+ }
+
+ if (!resource)
+ return 0;
+
+ ASSERT(resource->url() == url.string());
+ m_documentResources.set(resource->url(), resource);
+
+ return resource;
+}
+
+CachedResource* CachedResourceLoader::revalidateResource(CachedResource* resource, ResourceLoadPriority priority)
+{
+ ASSERT(resource);
+ ASSERT(resource->inCache());
+ ASSERT(!cache()->disabled());
+ ASSERT(resource->canUseCacheValidator());
+ ASSERT(!resource->resourceToRevalidate());
+
+ const String& url = resource->url();
+ CachedResource* newResource = createResource(resource->type(), KURL(ParsedURLString, url), resource->encoding());
+
+ LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource, resource);
+ newResource->setResourceToRevalidate(resource);
+
+ cache()->remove(resource);
+ cache()->add(newResource);
+
+ newResource->setLoadPriority(priority);
+ newResource->load(this);
+
+ m_validatedURLs.add(url);
+ return newResource;
+}
+
+CachedResource* CachedResourceLoader::loadResource(CachedResource::Type type, const KURL& url, const String& charset, ResourceLoadPriority priority)
+{
+ ASSERT(!cache()->resourceForURL(url));
+
+ LOG(ResourceLoading, "Loading CachedResource for '%s'.", url.string().latin1().data());
+
+ CachedResource* resource = createResource(type, url, charset);
+
+ bool inCache = cache()->add(resource);
+
+ // Pretend the resource is in the cache, to prevent it from being deleted during the load() call.
+ // FIXME: CachedResource should just use normal refcounting instead.
+ if (!inCache)
+ resource->setInCache(true);
+
+ resource->setLoadPriority(priority);
+ resource->load(this);
+
+ if (!inCache) {
+ resource->setOwningCachedResourceLoader(this);
+ resource->setInCache(false);
+ }
+
+ // We don't support immediate loads, but we do support immediate failure.
+ if (resource->errorOccurred()) {
+ if (inCache)
+ cache()->remove(resource);
+ else
+ delete resource;
+ return 0;
+ }
+
+ m_validatedURLs.add(url.string());
+ return resource;
+}
+
+CachedResourceLoader::RevalidationPolicy CachedResourceLoader::determineRevalidationPolicy(CachedResource::Type type, bool forPreload, CachedResource* existingResource) const
+{
+ if (!existingResource)
+ return Load;
+
+ // We already have a preload going for this URL.
+ if (forPreload && existingResource->isPreloaded())
+ return Use;
+
+ // If the same URL has been loaded as a different type, we need to reload.
+ if (existingResource->type() != type) {
+ LOG(ResourceLoading, "CachedResourceLoader::determineRevalidationPolicy reloading due to type mismatch.");
+ return Reload;
+ }
+
+ // Don't reload resources while pasting.
+ if (m_allowStaleResources)
+ return Use;
+
+ // Alwaus use preloads.
+ if (existingResource->isPreloaded())
+ return Use;
+
+ // Avoid loading the same resource multiple times for a single document, even if the cache policies would tell us to.
+ if (m_validatedURLs.contains(existingResource->url()))
+ return Use;
+
+ // CachePolicyReload always reloads
+ if (cachePolicy() == CachePolicyReload) {
+ LOG(ResourceLoading, "CachedResourceLoader::determineRevalidationPolicy reloading due to CachePolicyReload.");
+ return Reload;
+ }
+
+ // CachePolicyHistoryBuffer uses the cache no matter what.
+ if (cachePolicy() == CachePolicyHistoryBuffer)
+ return Use;
+
+ // We'll try to reload the resource if it failed last time.
+ if (existingResource->errorOccurred()) {
+ LOG(ResourceLoading, "CachedResourceLoader::determineRevalidationPolicye reloading due to resource being in the error state");
+ return Reload;
+ }
+
+ // For resources that are not yet loaded we ignore the cache policy.
+ if (existingResource->isLoading())
+ return Use;
+
+ // Check if the cache headers requires us to revalidate (cache expiration for example).
+ if (existingResource->mustRevalidateDueToCacheHeaders(cachePolicy())) {
+ // See if the resource has usable ETag or Last-modified headers.
+ if (existingResource->canUseCacheValidator())
+ return Revalidate;
+
+ // No, must reload.
+ LOG(ResourceLoading, "CachedResourceLoader::determineRevalidationPolicy reloading due to missing cache validators.");
+ return Reload;
+ }
+
+ return Use;
+}
+
+void CachedResourceLoader::printAccessDeniedMessage(const KURL& url) const
+{
+ if (url.isNull())
+ return;
+
+ if (!frame())
+ return;
+
+ Settings* settings = frame()->settings();
+ if (!settings || settings->privateBrowsingEnabled())
+ return;
+
+ String message = m_document->url().isNull() ?
+ makeString("Unsafe attempt to load URL ", url.string(), '.') :
+ makeString("Unsafe attempt to load URL ", url.string(), " from frame with URL ", m_document->url().string(), ". Domains, protocols and ports must match.\n");
+
+ // FIXME: provide a real line number and source URL.
+ frame()->domWindow()->console()->addMessage(OtherMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String());
+}
+
+void CachedResourceLoader::setAutoLoadImages(bool enable)
+{
+ if (enable == m_autoLoadImages)
+ return;
+
+ m_autoLoadImages = enable;
+
+ if (!m_autoLoadImages)
+ return;
+
+ DocumentResourceMap::iterator end = m_documentResources.end();
+ for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it) {
+ CachedResource* resource = it->second.get();
+ if (resource->type() == CachedResource::ImageResource) {
+ CachedImage* image = const_cast<CachedImage*>(static_cast<const CachedImage*>(resource));
+#ifdef ANDROID_BLOCK_NETWORK_IMAGE
+ if (shouldBlockNetworkImage(image->url()))
+ continue;
+#endif
+
+ if (image->stillNeedsLoad())
+ load(image, true);
+ }
+ }
+}
+
+#ifdef ANDROID_BLOCK_NETWORK_IMAGE
+bool CachedResourceLoader::shouldBlockNetworkImage(const String& url) const
+{
+ if (!m_blockNetworkImage)
+ return false;
+
+ KURL kurl = m_document->completeURL(url);
+ if (kurl.protocolIs("http") || kurl.protocolIs("https"))
+ return true;
+
+ return false;
+}
+
+void CachedResourceLoader::setBlockNetworkImage(bool block)
+{
+ if (block == m_blockNetworkImage)
+ return;
+
+ m_blockNetworkImage = block;
+
+ if (!m_autoLoadImages || m_blockNetworkImage)
+ return;
+
+ DocumentResourceMap::iterator end = m_documentResources.end();
+ for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it) {
+ CachedResource* resource = it->second.get();
+ if (resource->type() == CachedResource::ImageResource) {
+ CachedImage* image = const_cast<CachedImage*>(static_cast<const CachedImage*>(resource));
+ if (image->stillNeedsLoad())
+ load(image, true);
+ }
+ }
+}
+#endif
+
+CachePolicy CachedResourceLoader::cachePolicy() const
+{
+ return frame() ? frame()->loader()->subresourceCachePolicy() : CachePolicyVerify;
+}
+
+void CachedResourceLoader::removeCachedResource(CachedResource* resource) const
+{
+#ifndef NDEBUG
+ DocumentResourceMap::iterator it = m_documentResources.find(resource->url());
+ if (it != m_documentResources.end())
+ ASSERT(it->second.get() == resource);
+#endif
+ m_documentResources.remove(resource->url());
+}
+
+void CachedResourceLoader::load(CachedResource* resource, bool incremental, SecurityCheckPolicy securityCheck, bool sendResourceLoadCallbacks)
+{
+ incrementRequestCount(resource);
+
+ RefPtr<CachedResourceRequest> request = CachedResourceRequest::load(this, resource, incremental, securityCheck, sendResourceLoadCallbacks);
+ if (request)
+ m_requests.add(request);
+}
+
+void CachedResourceLoader::loadDone(CachedResourceRequest* request)
+{
+ m_loadFinishing = false;
+ RefPtr<CachedResourceRequest> protect(request);
+ if (request)
+ m_requests.remove(request);
+ if (frame())
+ frame()->loader()->loadDone();
+ checkForPendingPreloads();
+}
+
+void CachedResourceLoader::cancelRequests()
+{
+ clearPendingPreloads();
+ Vector<CachedResourceRequest*, 256> requestsToCancel;
+ RequestSet::iterator end = m_requests.end();
+ for (RequestSet::iterator i = m_requests.begin(); i != end; ++i)
+ requestsToCancel.append((*i).get());
+
+ for (unsigned i = 0; i < requestsToCancel.size(); ++i)
+ requestsToCancel[i]->didFail(true);
+}
+
+void CachedResourceLoader::notifyLoadedFromMemoryCache(CachedResource* resource)
+{
+ if (!resource || !frame() || resource->status() != CachedResource::Cached)
+ return;
+
+ // FIXME: If the WebKit client changes or cancels the request, WebCore does not respect this and continues the load.
+ frame()->loader()->loadedResourceFromMemoryCache(resource);
+}
+
+void CachedResourceLoader::incrementRequestCount(const CachedResource* res)
+{
+ if (res->isPrefetch())
+ return;
+
+ ++m_requestCount;
+}
+
+void CachedResourceLoader::decrementRequestCount(const CachedResource* res)
+{
+ if (res->isPrefetch())
+ return;
+
+ --m_requestCount;
+ ASSERT(m_requestCount > -1);
+}
+
+int CachedResourceLoader::requestCount()
+{
+ if (m_loadFinishing)
+ return m_requestCount + 1;
+ return m_requestCount;
+}
+
+void CachedResourceLoader::preload(CachedResource::Type type, const String& url, const String& charset, bool referencedFromBody)
+{
+ bool hasRendering = m_document->body() && m_document->body()->renderer();
+ if (!hasRendering && (referencedFromBody || type == CachedResource::ImageResource)) {
+ // Don't preload images or body resources before we have something to draw. This prevents
+ // preloads from body delaying first display when bandwidth is limited.
+ PendingPreload pendingPreload = { type, url, charset };
+ m_pendingPreloads.append(pendingPreload);
+ return;
+ }
+ requestPreload(type, url, charset);
+}
+
+void CachedResourceLoader::checkForPendingPreloads()
+{
+ unsigned count = m_pendingPreloads.size();
+ if (!count || !m_document->body() || !m_document->body()->renderer())
+ return;
+ for (unsigned i = 0; i < count; ++i) {
+ PendingPreload& preload = m_pendingPreloads[i];
+ // Don't request preload if the resource already loaded normally (this will result in double load if the page is being reloaded with cached results ignored).
+ if (!cachedResource(m_document->completeURL(preload.m_url)))
+ requestPreload(preload.m_type, preload.m_url, preload.m_charset);
+ }
+ m_pendingPreloads.clear();
+}
+
+void CachedResourceLoader::requestPreload(CachedResource::Type type, const String& url, const String& charset)
+{
+ String encoding;
+ if (type == CachedResource::Script || type == CachedResource::CSSStyleSheet)
+ encoding = charset.isEmpty() ? m_document->frame()->loader()->writer()->encoding() : charset;
+
+ CachedResource* resource = requestResource(type, url, encoding, ResourceLoadPriorityUnresolved, true);
+ if (!resource || (m_preloads && m_preloads->contains(resource)))
+ return;
+ resource->increasePreloadCount();
+
+ if (!m_preloads)
+ m_preloads = adoptPtr(new ListHashSet<CachedResource*>);
+ m_preloads->add(resource);
+
+#if PRELOAD_DEBUG
+ printf("PRELOADING %s\n", resource->url().latin1().data());
+#endif
+}
+
+void CachedResourceLoader::clearPreloads()
+{
+#if PRELOAD_DEBUG
+ printPreloadStats();
+#endif
+ if (!m_preloads)
+ return;
+
+ ListHashSet<CachedResource*>::iterator end = m_preloads->end();
+ for (ListHashSet<CachedResource*>::iterator it = m_preloads->begin(); it != end; ++it) {
+ CachedResource* res = *it;
+ res->decreasePreloadCount();
+ if (res->canDelete() && !res->inCache())
+ delete res;
+ else if (res->preloadResult() == CachedResource::PreloadNotReferenced)
+ cache()->remove(res);
+ }
+ m_preloads.clear();
+}
+
+void CachedResourceLoader::clearPendingPreloads()
+{
+ m_pendingPreloads.clear();
+}
+
+#if PRELOAD_DEBUG
+void CachedResourceLoader::printPreloadStats()
+{
+ unsigned scripts = 0;
+ unsigned scriptMisses = 0;
+ unsigned stylesheets = 0;
+ unsigned stylesheetMisses = 0;
+ unsigned images = 0;
+ unsigned imageMisses = 0;
+ ListHashSet<CachedResource*>::iterator end = m_preloads.end();
+ for (ListHashSet<CachedResource*>::iterator it = m_preloads.begin(); it != end; ++it) {
+ CachedResource* res = *it;
+ if (res->preloadResult() == CachedResource::PreloadNotReferenced)
+ printf("!! UNREFERENCED PRELOAD %s\n", res->url().latin1().data());
+ else if (res->preloadResult() == CachedResource::PreloadReferencedWhileComplete)
+ printf("HIT COMPLETE PRELOAD %s\n", res->url().latin1().data());
+ else if (res->preloadResult() == CachedResource::PreloadReferencedWhileLoading)
+ printf("HIT LOADING PRELOAD %s\n", res->url().latin1().data());
+
+ if (res->type() == CachedResource::Script) {
+ scripts++;
+ if (res->preloadResult() < CachedResource::PreloadReferencedWhileLoading)
+ scriptMisses++;
+ } else if (res->type() == CachedResource::CSSStyleSheet) {
+ stylesheets++;
+ if (res->preloadResult() < CachedResource::PreloadReferencedWhileLoading)
+ stylesheetMisses++;
+ } else {
+ images++;
+ if (res->preloadResult() < CachedResource::PreloadReferencedWhileLoading)
+ imageMisses++;
+ }
+
+ if (res->errorOccurred())
+ cache()->remove(res);
+
+ res->decreasePreloadCount();
+ }
+ m_preloads.clear();
+
+ if (scripts)
+ printf("SCRIPTS: %d (%d hits, hit rate %d%%)\n", scripts, scripts - scriptMisses, (scripts - scriptMisses) * 100 / scripts);
+ if (stylesheets)
+ printf("STYLESHEETS: %d (%d hits, hit rate %d%%)\n", stylesheets, stylesheets - stylesheetMisses, (stylesheets - stylesheetMisses) * 100 / stylesheets);
+ if (images)
+ printf("IMAGES: %d (%d hits, hit rate %d%%)\n", images, images - imageMisses, (images - imageMisses) * 100 / images);
+}
+#endif
+
+}