📄 loader.cpp
字号:
/*
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 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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.
*/
#undef CACHE_DEBUG
//#define CACHE_DEBUG
#include <assert.h>
#include "loader.h"
// up to which size is a picture for sure cacheable
#define MAXCACHEABLE 128*1024
// default cache size
#define DEFCACHESIZE 4096*1024
#include <qasyncio.h>
#include <qasyncimageio.h>
#include <qpainter.h>
#include <qbitmap.h>
#include <qmovie.h>
#include <kio/job.h>
#include <kio/jobclasses.h>
#include <kglobal.h>
#include <kimageio.h>
#include <kcharsets.h>
#include <kiconloader.h>
#include <scheduler.h>
#include <kdebug.h>
#include "khtml_factory.h"
#include "khtml_part.h"
#include "html/html_documentimpl.h"
#include "css/css_stylesheetimpl.h"
#ifndef KHTML_NO_XBL
#include "xbl/xbl_docimpl.h"
#endif
#if APPLE_CHANGES
#include "KWQAssertions.h"
#include "KWQLoader.h"
#include "KWQDef.h"
#endif
using namespace khtml;
using namespace DOM;
#if APPLE_CHANGES
static bool cacheDisabled;
#endif
// a class to handle OOM for memory cache
#ifdef __OOM__
namespace khtml
{
class CacheMemCollector : public MMemoryCollector
{
public:
CacheMemCollector();
TUint Collect(TUint aRequired);
void Restore();
TOOMPriority Priority() { return EOOM_PriorityMiddle; }
unsigned int iInitialSize;
};
static CacheMemCollector* oom_collector = 0;
}
#endif
// Call this "walker" instead of iterator so people won't expect Qt or STL-style iterator interface.
// Just keep calling next() on this. It's safe from deletions of the current item
class CachedObjectClientWalker
OOM_MODIFIED
{
public:
CachedObjectClientWalker(const QPtrDict<CachedObjectClient> &clients) : _current(0), _iterator(clients) { }
CachedObjectClient *next();
private:
CachedObjectClient *_current;
QPtrDictIterator<CachedObjectClient> _iterator;
};
CachedObject::~CachedObject()
{
if(m_deleted) abort();
Cache::removeFromLRUList(this);
m_deleted = true;
#if APPLE_CHANGES
setResponse(0);
#if !NOKIA_CHANGES
setAllData(0);
#endif
#endif
}
void CachedObject::finish()
{
if (m_size > Cache::maxCacheableObjectSize())
m_status = Uncacheable;
else
m_status = Cached;
KURL url(m_url.string());
if (m_expireDateChanged && url.protocol().startsWith("http"))
{
m_expireDateChanged = false;
KIO::http_update_cache(url, false, m_expireDate);
#ifdef CACHE_DEBUG
kdDebug(6060) << " Setting expire date for image "<<m_url.string()<<" to " << m_expireDate << endl;
#endif
}
#ifdef CACHE_DEBUG
else kdDebug(6060) << " No expire date for image "<<m_url.string()<<endl;
#endif
}
void CachedObject::setExpireDate(time_t _expireDate, bool changeHttpCache)
{
if ( _expireDate == m_expireDate)
return;
if (m_status == Uncacheable || m_status == Cached)
{
finish();
}
m_expireDate = _expireDate;
if (changeHttpCache && m_expireDate)
m_expireDateChanged = true;
}
bool CachedObject::isExpired() const
{
if (!m_expireDate) return false;
time_t now = time(0);
return (difftime(now, m_expireDate) >= 0);
}
void CachedObject::setRequest(Request *_request)
{
if ( _request && !m_request )
m_status = Pending;
m_request = _request;
if (canDelete() && m_free)
delete this;
else if (allowInLRUList())
Cache::insertInLRUList(this);
}
void CachedObject::ref(CachedObjectClient *c)
{
m_clients.insert(c, c);
Cache::removeFromLRUList(this);
increaseAccessCount();
}
void CachedObject::deref(CachedObjectClient *c)
{
m_clients.remove(c);
if (allowInLRUList())
Cache::insertInLRUList(this);
}
void CachedObject::setSize(int size)
{
bool sizeChanged = Cache::adjustSize(this, size - m_size);
// The object must now be moved to a different queue, since its size has been changed.
if (sizeChanged && allowInLRUList())
Cache::removeFromLRUList(this);
m_size = size;
if (sizeChanged && allowInLRUList())
Cache::insertInLRUList(this);
}
// -------------------------------------------------------------------------------------------
CachedCSSStyleSheet::CachedCSSStyleSheet(DocLoader* dl, const DOMString &url, KIO::CacheControl _cachePolicy, time_t _expireDate, const QString& charset)
: CachedObject(url, CSSStyleSheet, _cachePolicy, _expireDate)
{
// It's css we want.
setAccept( QString::fromLatin1("text/css") );
// load the file
Cache::loader()->load(dl, this, false);
m_loading = true;
bool b;
if(!charset.isEmpty())
m_codec = KGlobal::charsets()->codecForName(charset, b);
else
m_codec = QTextCodec::codecForName("iso8859-1");
}
CachedCSSStyleSheet::CachedCSSStyleSheet(const DOMString &url, const QString &stylesheet_data)
: CachedObject(url, CSSStyleSheet, KIO::CC_Verify, 0, stylesheet_data.length())
{
m_loading = false;
m_status = Persistent;
m_codec = 0;
#if NOKIA_CHANGES
m_stringData = stylesheet_data;
#else
m_sheet = DOMString(stylesheet_data);
#endif
}
CachedCSSStyleSheet::~CachedCSSStyleSheet()
{
}
#if NOKIA_CHANGES
const DOM::DOMString CachedCSSStyleSheet::sheet() const
{
// decode when needed, saves memory since undecoded data is usually 8-bit
DOMString sheet;
if (m_codec)
sheet = m_codec->toUnicode( m_data.data(), m_data.size() );
else
sheet = m_stringData;
return sheet;
}
#endif
void CachedCSSStyleSheet::ref(CachedObjectClient *c)
{
CachedObject::ref(c);
if(!m_loading) c->setStyleSheet( m_url, sheet() );
}
void CachedCSSStyleSheet::deref(CachedObjectClient *c)
{
Cache::flush();
CachedObject::deref(c);
if ( canDelete() && m_free )
delete this;
}
void CachedCSSStyleSheet::data( QBuffer &buffer, bool eof )
{
if(!eof) return;
OOM_CRITICAL_PATH_BEGIN( "CachedCSSStyleSheet::data", buffer.buffer().size() )
buffer.close();
setSize(buffer.buffer().size());
#if NOKIA_CHANGES
m_data = buffer.buffer();
#else
QString data = m_codec->toUnicode( buffer.buffer().data(), size() );
m_sheet = DOMString(data);
#endif
m_loading = false;
checkNotify();
OOM_CRITICAL_PATH_END
}
void CachedCSSStyleSheet::checkNotify()
{
if(m_loading) return;
#ifdef CACHE_DEBUG
kdDebug( 6060 ) << "CachedCSSStyleSheet:: finishedLoading " << m_url.string() << endl;
#endif
CachedObjectClientWalker w(m_clients);
while (CachedObjectClient *c = w.next()) {
if (m_response && !KWQIsResponseURLEqualToURL(m_response, m_url))
c->setStyleSheet(DOMString(KWQResponseURL(m_response)), sheet());
else
c->setStyleSheet(m_url, sheet());
}
}
void CachedCSSStyleSheet::error( int /*err*/, const char */*text*/ )
{
m_loading = false;
checkNotify();
}
// -------------------------------------------------------------------------------------------
CachedScript::CachedScript(DocLoader* dl, const DOMString &url, KIO::CacheControl _cachePolicy, time_t _expireDate, const QString& charset)
: CachedObject(url, Script, _cachePolicy, _expireDate)
{
// It's javascript we want.
// But some websites think their scripts are <some wrong mimetype here>
// and refuse to serve them if we only accept application/x-javascript.
setAccept( QString::fromLatin1("*/*") );
// load the file
Cache::loader()->load(dl, this, false);
m_loading = true;
bool b;
if(!charset.isEmpty())
m_codec = KGlobal::charsets()->codecForName(charset, b);
else
m_codec = QTextCodec::codecForName("iso8859-1");
}
CachedScript::CachedScript(const DOMString &url, const QString &script_data)
: CachedObject(url, Script, KIO::CC_Verify, 0, script_data.length())
{
m_loading = false;
m_status = Persistent;
m_codec = 0;
#if NOKIA_CHANGES
m_stringData = script_data;
#else
m_script = DOMString(script_data);
#endif
}
CachedScript::~CachedScript()
{
}
#if NOKIA_CHANGES
const DOM::DOMString CachedScript::script() const
{
// decode when needed, saves memory since undecoded data is usually 8-bit
DOMString script;
if (m_codec)
script = m_codec->toUnicode( m_data.data(), m_data.size() );
else
script = m_stringData;
return script;
}
#endif
void CachedScript::ref(CachedObjectClient *c)
{
CachedObject::ref(c);
if(!m_loading) c->notifyFinished(this);
}
void CachedScript::deref(CachedObjectClient *c)
{
Cache::flush();
CachedObject::deref(c);
if ( canDelete() && m_free )
delete this;
}
void CachedScript::data( QBuffer &buffer, bool eof )
{
if(!eof) return;
buffer.close();
setSize(buffer.buffer().size());
#if NOKIA_CHANGES
m_data = buffer.buffer();
#else
QString data = m_codec->toUnicode( buffer.buffer().data(), size() );
m_script = DOMString(data);
#endif
m_loading = false;
checkNotify();
}
void CachedScript::checkNotify()
{
if(m_loading) return;
CachedObjectClientWalker w(m_clients);
while (CachedObjectClient *c = w.next())
c->notifyFinished(this);
}
void CachedScript::error( int /*err*/, const char */*text*/ )
{
m_loading = false;
checkNotify();
}
// ------------------------------------------------------------------------------------------
#if !APPLE_CHANGES
namespace khtml
{
class ImageSource : public QDataSource
{
public:
ImageSource(QByteArray buf);
/**
* Overload QDataSource::readyToSend() and returns the number
* of bytes ready to send if not eof instead of returning -1.
*/
int readyToSend();
/*!
Reads and sends a block of data.
*/
void sendTo(QDataSink*, int count);
/**
* Sets the EOF state.
*/
void setEOF( bool state );
/*!
KHTMLImageSource's is rewindable.
*/
bool rewindable() const;
/*!
Enables rewinding. No special action is taken.
*/
void enableRewind(bool on);
/*
Calls reset() on the QIODevice.
*/
void rewind();
/*
Indicates that the buffered data is no longer
needed.
*/
void cleanBuffer();
QByteArray buffer;
unsigned int pos;
private:
bool eof : 1;
bool rew : 1;
bool rewable : 1;
};
}
ImageSource::ImageSource(QByteArray buf)
{
buffer = buf;
rew = false;
pos = 0;
eof = false;
rewable = true;
}
int ImageSource::readyToSend()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -