blob: 95e1410ae76c82bf389ac0e8edc768999cec8c0f [file] [log] [blame]
/*
This file is part of the KDE libraries
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 Apple Computer, Inc.
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 "DocLoader.h"
#include "Cache.h"
#include "CachedCSSStyleSheet.h"
#include "CachedImage.h"
#include "CachedScript.h"
#include "CachedXSLStyleSheet.h"
#include "Document.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "loader.h"
namespace WebCore {
DocLoader::DocLoader(Frame *frame, Document* doc)
: m_cache(cache())
, m_cachePolicy(CachePolicyVerify)
, m_frame(frame)
, m_doc(doc)
, m_requestCount(0)
, m_autoLoadImages(true)
, m_loadInProgress(false)
, m_allowStaleResources(false)
{
m_cache->addDocLoader(this);
}
DocLoader::~DocLoader()
{
HashMap<String, CachedResource*>::iterator end = m_docResources.end();
for (HashMap<String, CachedResource*>::iterator it = m_docResources.begin(); it != end; ++it)
it->second->setDocLoader(0);
m_cache->removeDocLoader(this);
}
void DocLoader::checkForReload(const KURL& fullURL)
{
if (m_allowStaleResources)
return; //Don't reload resources while pasting
if (m_cachePolicy == CachePolicyVerify) {
if (!m_reloadedURLs.contains(fullURL.url())) {
CachedResource* existing = cache()->resourceForURL(fullURL.url());
if (existing && existing->isExpired()) {
cache()->remove(existing);
m_reloadedURLs.add(fullURL.url());
}
}
} else if ((m_cachePolicy == CachePolicyReload) || (m_cachePolicy == CachePolicyRefresh)) {
if (!m_reloadedURLs.contains(fullURL.url())) {
CachedResource* existing = cache()->resourceForURL(fullURL.url());
if (existing)
cache()->remove(existing);
m_reloadedURLs.add(fullURL.url());
}
}
}
CachedImage* DocLoader::requestImage(const String& url)
{
CachedImage* resource = static_cast<CachedImage*>(requestResource(CachedResource::ImageResource, url));
if (autoLoadImages() && resource && resource->stillNeedsLoad()) {
resource->setLoading(true);
cache()->loader()->load(this, resource, true);
}
return resource;
}
CachedCSSStyleSheet* DocLoader::requestCSSStyleSheet(const String& url, const String& charset, bool isUserStyleSheet)
{
// FIXME: Passing true for "skipCanLoadCheck" here in the isUserStyleSheet case won't have any effect
// if this resource is already in the cache. It's theoretically possible that what's in the cache already
// is a load that failed because of the canLoad check. Probably not an issue in practice.
CachedCSSStyleSheet *sheet = static_cast<CachedCSSStyleSheet*>(requestResource(CachedResource::CSSStyleSheet, url, &charset, isUserStyleSheet, !isUserStyleSheet));
// A user style sheet can outlive its DocLoader so don't store any pointers to it
if (sheet && isUserStyleSheet) {
sheet->setDocLoader(0);
m_docResources.remove(sheet->url());
}
return sheet;
}
CachedCSSStyleSheet* DocLoader::requestUserCSSStyleSheet(const String& url, const String& charset)
{
return requestCSSStyleSheet(url, charset, true);
}
CachedScript* DocLoader::requestScript(const String& url, const String& charset)
{
return static_cast<CachedScript*>(requestResource(CachedResource::Script, url, &charset));
}
#if ENABLE(XSLT)
CachedXSLStyleSheet* DocLoader::requestXSLStyleSheet(const String& url)
{
return static_cast<CachedXSLStyleSheet*>(requestResource(CachedResource::XSLStyleSheet, url));
}
#endif
#if ENABLE(XBL)
CachedXBLDocument* DocLoader::requestXBLDocument(const String& url)
{
return static_cast<CachedXSLStyleSheet*>(requestResource(CachedResource::XBL, url));
}
#endif
CachedResource* DocLoader::requestResource(CachedResource::Type type, const String& url, const String* charset, bool skipCanLoadCheck, bool sendResourceLoadCallbacks)
{
KURL fullURL = m_doc->completeURL(url.deprecatedString());
if (cache()->disabled()) {
HashMap<String, CachedResource*>::iterator it = m_docResources.find(fullURL.url());
if (it != m_docResources.end()) {
it->second->setDocLoader(0);
m_docResources.remove(it);
}
}
if (m_frame && m_frame->loader()->isReloading())
setCachePolicy(CachePolicyReload);
checkForReload(fullURL);
CachedResource* resource = cache()->requestResource(this, type, fullURL, charset, skipCanLoadCheck, sendResourceLoadCallbacks);
if (resource) {
m_docResources.set(resource->url(), resource);
checkCacheObjectStatus(resource);
}
return resource;
}
void DocLoader::setAutoLoadImages(bool enable)
{
if (enable == m_autoLoadImages)
return;
m_autoLoadImages = enable;
if (!m_autoLoadImages)
return;
HashMap<String, CachedResource*>::iterator end = m_docResources.end();
for (HashMap<String, CachedResource*>::iterator it = m_docResources.begin(); it != end; ++it) {
CachedResource* resource = it->second;
if (resource->type() == CachedResource::ImageResource) {
CachedImage* image = const_cast<CachedImage*>(static_cast<const CachedImage *>(resource));
CachedResource::Status status = image->status();
if (status != CachedResource::Unknown)
continue;
cache()->loader()->load(this, image, true);
}
}
}
void DocLoader::setCachePolicy(CachePolicy cachePolicy)
{
m_cachePolicy = cachePolicy;
}
void DocLoader::removeCachedResource(CachedResource* resource) const
{
m_docResources.remove(resource->url());
}
void DocLoader::setLoadInProgress(bool load)
{
m_loadInProgress = load;
if (!load && m_frame)
m_frame->loader()->loadDone();
}
void DocLoader::checkCacheObjectStatus(CachedResource* resource)
{
// Return from the function for objects that we didn't load from the cache.
if (!resource)
return;
switch (resource->status()) {
case CachedResource::Cached:
break;
case CachedResource::NotCached:
case CachedResource::Unknown:
case CachedResource::New:
case CachedResource::Pending:
return;
}
// Notify the caller that we "loaded".
if (!m_frame || m_frame->loader()->haveToldBridgeAboutLoad(resource->url()))
return;
ResourceRequest request(resource->url());
const ResourceResponse& response = resource->response();
SharedBuffer* data = resource->data();
if (resource->sendResourceLoadCallbacks()) {
// FIXME: If the WebKit client changes or cancels the request, WebCore does not respect this and continues the load.
m_frame->loader()->loadedResourceFromMemoryCache(request, response, data ? data->size() : 0);
}
m_frame->loader()->didTellBridgeAboutLoad(resource->url());
}
void DocLoader::incrementRequestCount()
{
++m_requestCount;
}
void DocLoader::decrementRequestCount()
{
--m_requestCount;
ASSERT(m_requestCount > -1);
}
int DocLoader::requestCount()
{
if (loadInProgress())
return m_requestCount + 1;
return m_requestCount;
}
}