diff options
author | Steve Block <steveblock@google.com> | 2011-05-06 11:45:16 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-05-12 13:44:10 +0100 |
commit | cad810f21b803229eb11403f9209855525a25d57 (patch) | |
tree | 29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/loader/cache/CachedResourceLoader.cpp | |
parent | 121b0cf4517156d0ac5111caf9830c51b69bae8f (diff) | |
download | external_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.cpp | 733 |
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 + +} |