📄 loader.cpp
字号:
/* This file is part of the KDE libraries Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) Copyright (C) 2001-2003 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., 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. // regarding the LRU: // http://www.is.kyusan-u.ac.jp/~chengk/pub/papers/compsac00_A07-07.pdf*/#undef CACHE_DEBUG//#define CACHE_DEBUG#ifdef CACHE_DEBUG#define CDEBUG kdDebug(6060)#else#define CDEBUG kndDebug()#endif#undef LOADER_DEBUG//#define LOADER_DEBUG#include <assert.h>#include "misc/loader.h"#include "misc/seed.h"// default cache size#define DEFCACHESIZE 2096*1024#define MAX_JOB_COUNT 32#include <qasyncio.h>#include <qasyncimageio.h>#include <qpainter.h>#include <qbitmap.h>#include <qmovie.h>#include <qwidget.h>#include <kapplication.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"#ifdef IMAGE_TITLES#include <qfile.h>#include <kfilemetainfo.h>#include <ktempfile.h>#endif#include "html/html_documentimpl.h"#include "css/css_stylesheetimpl.h"#include "xml/dom_docimpl.h"#include "blocked_icon.cpp"using namespace khtml;using namespace DOM;#define MAX_LRU_LISTS 20struct LRUList { CachedObject* m_head; CachedObject* m_tail; LRUList() : m_head(0), m_tail(0) {}};static LRUList m_LRULists[MAX_LRU_LISTS];static LRUList* getLRUListFor(CachedObject* o);CachedObjectClient::~CachedObjectClient(){}CachedObject::~CachedObject(){ Cache::removeFromLRUList(this);}void CachedObject::finish(){ m_status = Cached;}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; if ( allowInLRUList() ) Cache::removeFromLRUList( this ); m_request = _request; if ( allowInLRUList() ) Cache::insertInLRUList( this );}void CachedObject::ref(CachedObjectClient *c){ // unfortunately we can be ref'ed multiple times from the // same object, because it uses e.g. the same foreground // and the same background picture. so deal with it. m_clients.insert(c,c); Cache::removeFromLRUList(this); m_accessCount++;}void CachedObject::deref(CachedObjectClient *c){ assert( c ); assert( m_clients.count() ); assert( !canDelete() ); assert( m_clients.find( c ) ); Cache::flush(); m_clients.remove(c); if (allowInLRUList()) Cache::insertInLRUList(this);}void CachedObject::setSize(int size){ bool sizeChanged; if ( !m_next && !m_prev && getLRUListFor(this)->m_head != this ) sizeChanged = false; else sizeChanged = ( size - m_size ) != 0; // 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);}QTextCodec* CachedObject::codecForBuffer( const QString& charset, const QByteArray& buffer ) const{ // we don't use heuristicContentMatch here since it is a) far too slow and // b) having too much functionality for our case. uchar* d = ( uchar* ) buffer.data(); int s = buffer.size(); if ( s >= 3 && d[0] == 0xef && d[1] == 0xbb && d[2] == 0xbf) return QTextCodec::codecForMib( 106 ); // UTF-8 if ( s >= 2 && ((d[0] == 0xff && d[1] == 0xfe) || (d[0] == 0xfe && d[1] == 0xff))) return QTextCodec::codecForMib( 1000 ); // UCS-2 if(!charset.isEmpty()) { QTextCodec* c = KGlobal::charsets()->codecForName(charset); if(c->mibEnum() == 11) { // iso8859-8 (visually ordered) c = QTextCodec::codecForName("iso8859-8-i"); } return c; } return QTextCodec::codecForMib(4); // latin-1}// -------------------------------------------------------------------------------------------CachedCSSStyleSheet::CachedCSSStyleSheet(DocLoader* dl, const DOMString &url, KIO::CacheControl _cachePolicy, const char *accept) : CachedObject(url, CSSStyleSheet, _cachePolicy, 0){ // Set the type we want (probably css or xml) QString ah = QString::fromLatin1( accept ); if ( !ah.isEmpty() ) ah += ","; ah += "*/*;q=0.1"; setAccept( ah ); m_hadError = false; m_wasBlocked = false; m_err = 0; // load the file Cache::loader()->load(dl, this, false); m_loading = true;}CachedCSSStyleSheet::CachedCSSStyleSheet(const DOMString &url, const QString &stylesheet_data) : CachedObject(url, CSSStyleSheet, KIO::CC_Verify, stylesheet_data.length()){ m_loading = false; m_status = Persistent; m_sheet = DOMString(stylesheet_data);}void CachedCSSStyleSheet::ref(CachedObjectClient *c){ CachedObject::ref(c); if (!m_loading) { if (m_hadError) c->error( m_err, m_errText ); else c->setStyleSheet( m_url, m_sheet ); }}void CachedCSSStyleSheet::data( QBuffer &buffer, bool eof ){ if(!eof) return; buffer.close(); setSize(buffer.buffer().size()); QTextCodec* c = codecForBuffer( m_charset, buffer.buffer() ); QString data = c->toUnicode( buffer.buffer().data(), m_size ); // workaround Qt bugs m_sheet = data[0] == QChar::byteOrderMark ? DOMString(data.mid( 1 ) ) : DOMString(data); m_loading = false; checkNotify();}void CachedCSSStyleSheet::checkNotify(){ if(m_loading || m_hadError) return; CDEBUG << "CachedCSSStyleSheet:: finishedLoading " << m_url.string() << endl; // it() first increments, then returnes the current item. // this avoids skipping an item when setStyleSheet deletes the "current" one. for (QPtrDictIterator<CachedObjectClient> it( m_clients ); it.current();) it()->setStyleSheet( m_url, m_sheet );}void CachedCSSStyleSheet::error( int err, const char* text ){ m_hadError = true; m_err = err; m_errText = text; m_loading = false; // it() first increments, then returnes the current item. // this avoids skipping an item when setStyleSheet deletes the "current" one. for (QPtrDictIterator<CachedObjectClient> it( m_clients ); it.current();) it()->error( m_err, m_errText );}// -------------------------------------------------------------------------------------------CachedScript::CachedScript(DocLoader* dl, const DOMString &url, KIO::CacheControl _cachePolicy, const char*) : CachedObject(url, Script, _cachePolicy, 0){ // 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;}CachedScript::CachedScript(const DOMString &url, const QString &script_data) : CachedObject(url, Script, KIO::CC_Verify, script_data.length()){ m_loading = false; m_status = Persistent; m_script = DOMString(script_data);}void CachedScript::ref(CachedObjectClient *c){ CachedObject::ref(c); if(!m_loading) c->notifyFinished(this);}void CachedScript::data( QBuffer &buffer, bool eof ){ if(!eof) return; buffer.close(); setSize(buffer.buffer().size()); QTextCodec* c = codecForBuffer( m_charset, buffer.buffer() ); QString data = c->toUnicode( buffer.buffer().data(), m_size ); m_script = data[0] == QChar::byteOrderMark ? DOMString(data.mid( 1 ) ) : DOMString(data); m_loading = false; checkNotify();}void CachedScript::checkNotify(){ if(m_loading) return; for (QPtrDictIterator<CachedObjectClient> it( m_clients); it.current();) it()->notifyFinished(this);}void CachedScript::error( int /*err*/, const char* /*text*/ ){ m_loading = false; checkNotify();}// ------------------------------------------------------------------------------------------namespace khtml{class ImageSource : public QDataSource{public: ImageSource(QByteArray buf) : buffer( buf ), pos( 0 ), eof( false ), rew(false ), rewable( true ) {} int readyToSend() { if(eof && pos == buffer.size()) return -1; return buffer.size() - pos; } void 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; } } /** * Sets the EOF state. */ void setEOF( bool state ) { eof = state; } bool rewindable() const { return rewable; } void enableRewind(bool on) { rew = on; } /* Calls reset() on the QIODevice. */ void rewind() { pos = 0; if (!rew) { QDataSource::rewind(); } else ready(); } /* Indicates that the buffered data is no longer needed. */ void 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; } } QByteArray buffer; unsigned int pos;private: bool eof : 1; bool rew : 1; bool rewable : 1;};} // end namespacestatic QString buildAcceptHeader(){ return "image/png, image/jpeg, video/x-mng, image/jp2, image/gif;q=0.5,*/*;q=0.1";}// -------------------------------------------------------------------------------------CachedImage::CachedImage(DocLoader* dl, const DOMString &url, KIO::CacheControl _cachePolicy, const char*) : QObject(), CachedObject(url, Image, _cachePolicy, 0){ static const QString &acceptHeader = KGlobal::staticQString( buildAcceptHeader() ); m = 0; p = 0; pixPart = 0; bg = 0; bgColor = qRgba( 0, 0, 0, 0xFF ); typeChecked = false; isFullyTransparent = false; monochrome = false; formatType = 0; m_status = Unknown; imgSource = 0; setAccept( acceptHeader ); m_showAnimations = dl->showAnimations(); if ( KHTMLFactory::defaultHTMLSettings()->isAdFiltered( url.string() ) ) { m_wasBlocked = true; CachedObject::finish(); }}CachedImage::~CachedImage(){ clear();}void CachedImage::ref( CachedObjectClient *c ){ CachedObject::ref(c); if( m ) { m->unpause(); if( m->finished() || m_clients.count() == 1 ) m->restart(); } // for mouseovers, dynamic changes if ( m_status >= Persistent && !valid_rect().isNull() ) { c->setPixmap( pixmap(), valid_rect(), this); c->notifyFinished( this ); }}void CachedImage::deref( CachedObjectClient *c ){ CachedObject::deref(c); if(m && m_clients.isEmpty() && m->running()) m->pause();}#define BGMINWIDTH 32#define BGMINHEIGHT 32const QPixmap &CachedImage::tiled_pixmap(const QColor& newc){ static QRgb bgTransparant = qRgba( 0, 0, 0, 0xFF ); if ( (bgColor != bgTransparant) && (bgColor != newc.rgb()) ) { delete bg; bg = 0; } if (bg) return *bg; const QPixmap &r = pixmap(); if (r.isNull()) return r; // no error indication for background images if(m_hadError||m_wasBlocked) return *Cache::nullPixmap; bool isvalid = newc.isValid(); QSize s(pixmap_size()); int w = r.width(); int h = r.height(); if ( w*h < 8192 ) { if ( r.width() < BGMINWIDTH ) w = ((BGMINWIDTH / s.width())+1) * s.width(); if ( r.height() < BGMINHEIGHT ) h = ((BGMINHEIGHT / s.height())+1) * s.height(); }#ifdef Q_WS_X11 if ( r.hasAlphaChannel() && ((w != r.width()) || (h != r.height())) ) { bg = new QPixmap(w, h); //Tile horizontally on the first stripe
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -