📄 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) 2003 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 40*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"#endifusing namespace khtml;using namespace DOM;#if APPLE_CHANGESstatic bool cacheDisabled;#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 itemclass CachedObjectClientWalker {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 KWQReleaseResponse(m_response);#endif}void CachedObject::finish(){ if( m_size > MAXCACHEABLE ) 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);}#if APPLE_CHANGESvoid CachedObject::setResponse(KWIQResponse *response){ KWQRetainResponse(response); KWQReleaseResponse(m_response); m_response = response;}#endifvoid 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; m_sheet = DOMString(stylesheet_data);}CachedCSSStyleSheet::~CachedCSSStyleSheet(){}void CachedCSSStyleSheet::ref(CachedObjectClient *c){ CachedObject::ref(c); if(!m_loading) c->setStyleSheet( m_url, m_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; buffer.close(); setSize(buffer.buffer().size()); QString data = m_codec->toUnicode( buffer.buffer().data(), size() ); m_sheet = DOMString(data); m_loading = false; checkNotify();}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()) c->setStyleSheet(m_url, m_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; m_script = DOMString(script_data);}CachedScript::~CachedScript(){}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()); QString data = m_codec->toUnicode( buffer.buffer().data(), size() ); m_script = DOMString(data); 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(){ if(eof && pos == buffer.size()) return -1; return buffer.size() - pos;}void ImageSource::sendTo(QDataSink* sink, int n){ sink->receive((const uchar*)&buffer.at(pos), n); pos += n; // buffer is no longer needed if(eof && pos == buffer.size() && !rewable) { buffer.resize(0); pos = 0; }}void ImageSource::setEOF( bool state ){ eof = state;#if KWIQ if (eof) QDataSource::eof();#endif }// ImageSource's is rewindable.bool ImageSource::rewindable() const{ return rewable;}// Enables rewinding. No special action is taken.void ImageSource::enableRewind(bool on){ rew = on;}// Calls reset() on the QIODevice.void ImageSource::rewind(){ pos = 0; if (!rew) { QDataSource::rewind(); } else ready();}void ImageSource::cleanBuffer(){ // if we need to be able to rewind, buffer is needed if(rew) return; rewable = false; // buffer is no longer needed if(eof && pos == buffer.size()) { buffer.resize(0); pos = 0; }}static QString buildAcceptHeader(){ QString result = KImageIO::mimeTypes( KImageIO::Reading ).join(", "); if (result.right(2) == ", ") result = result.left(result.length()-2); return result;}#endif // APPLE_CHANGESstatic bool crossDomain(const QString &a, const QString &b){ if (a == b) return false; QStringList l1 = QStringList::split('.', a); QStringList l2 = QStringList::split('.', b); while(l1.count() > l2.count()) l1.pop_front(); while(l2.count() > l1.count()) l2.pop_front(); while(l2.count() >= 2) { if (l1 == l2) return false; l1.pop_front(); l2.pop_front(); } return true;}// -------------------------------------------------------------------------------------CachedImage::CachedImage(DocLoader* dl, const DOMString &url, KIO::CacheControl _cachePolicy, time_t _expireDate) : QObject(), CachedObject(url, Image, _cachePolicy, _expireDate)#if APPLE_CHANGES , m_dataSize(0)#endif{#if KWIQ QOBJECT_TYPE(khtml::CachedImage);#endif#if !APPLE_CHANGES static const QString &acceptHeader = KGlobal::staticQString( buildAcceptHeader() );#endif m = 0; p = 0; pixPart = 0; bg = 0;#if !APPLE_CHANGES || KWIQ bgColor = qRgba( 0, 0, 0, 0xFF ); typeChecked = false;#endif isFullyTransparent = false; errorOccured = false; monochrome = false; formatType = 0; m_status = Unknown; imgSource = 0; m_loading = true;#if !APPLE_CHANGES setAccept( acceptHeader );#endif m_showAnimations = dl->showAnimations();}CachedImage::~CachedImage(){ clear();}void CachedImage::ref( CachedObjectClient *c ){#ifdef CACHE_DEBUG kdDebug( 6060 ) << this << " CachedImage::ref(" << c << ") " << endl;#endif CachedObject::ref(c); if( m ) { m->unpause(); if( m->finished() || m_clients.count() == 1 ) m->restart(); } // for mouseovers, dynamic changes if (!valid_rect().isNull())
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -