📄 loader.cpp
字号:
Loader::Loader() : QObject(){ m_requestsPending.setAutoDelete( true ); m_requestsLoading.setAutoDelete( true ); connect(&m_timer, SIGNAL(timeout()), this, SLOT( servePendingRequests() ) );}void Loader::load(DocLoader* dl, CachedObject *object, bool incremental){ Request *req = new Request(dl, object, incremental); m_requestsPending.append(req); emit requestStarted( req->m_docLoader, req->object ); m_timer.start(0, true);}void Loader::servePendingRequests(){ while ( (m_requestsPending.count() != 0) && (m_requestsLoading.count() < MAX_JOB_COUNT) ) { // get the first pending request Request *req = m_requestsPending.take(0);#ifdef LOADER_DEBUG kdDebug( 6060 ) << "starting Loader url=" << req->object->url().string() << endl;#endif KURL u(req->object->url().string()); KIO::TransferJob* job = KIO::get( u, false, false /*no GUI*/); job->addMetaData("cache", KIO::getCacheControlString(req->object->cachePolicy())); if (!req->object->accept().isEmpty()) job->addMetaData("accept", req->object->accept()); if ( req->m_docLoader ) { job->addMetaData( "referrer", req->m_docLoader->doc()->URL().url() ); KHTMLPart *part = req->m_docLoader->part(); if (part ) { job->addMetaData( "cross-domain", part->toplevelURL().url() ); if (part->widget()) job->setWindow (part->widget()->topLevelWidget()); } } connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotFinished( KIO::Job * ) ) ); connect( job, SIGNAL( data( KIO::Job*, const QByteArray &)), SLOT( slotData( KIO::Job*, const QByteArray &))); if ( req->object->schedule() ) KIO::Scheduler::scheduleJob( job ); m_requestsLoading.insert(job, req); }}void Loader::slotFinished( KIO::Job* job ){ Request *r = m_requestsLoading.take( job ); KIO::TransferJob* j = static_cast<KIO::TransferJob*>(job); if ( !r ) return; if (j->error() || j->isErrorPage()) {#ifdef LOADER_DEBUG kdDebug(6060) << "Loader::slotFinished, with error. job->error()= " << j->error() << " job->isErrorPage()=" << j->isErrorPage() << endl;#endif r->object->error( job->error(), job->errorText().ascii() ); emit requestFailed( r->m_docLoader, r->object ); } else { r->object->data(r->m_buffer, true); emit requestDone( r->m_docLoader, r->object ); time_t expireDate = j->queryMetaData("expire-date").toLong();#ifdef LOADER_DEBUG kdDebug(6060) << "Loader::slotFinished, url = " << j->url().url() << endl;#endif r->object->setExpireDate( expireDate ); if ( r->object->type() == CachedObject::Image ) { QString fn = j->queryMetaData("content-disposition"); static_cast<CachedImage*>( r->object )->setSuggestedFilename(fn);#ifdef IMAGE_TITLES static_cast<CachedImage*>( r->object )->setSuggestedTitle(fn); KTempFile tf; tf.setAutoDelete(true); tf.file()->writeBlock((const char*)r->m_buffer.buffer().data(), r->m_buffer.size()); tf.sync(); KFileMetaInfo kfmi(tf.name()); if (!kfmi.isEmpty()) { KFileMetaInfoItem i = kfmi.item("Name"); if (i.isValid()) { static_cast<CachedImage*>(r->object)->setSuggestedTitle(i.string()); } else { i = kfmi.item("Title"); if (i.isValid()) { static_cast<CachedImage*>(r->object)->setSuggestedTitle(i.string()); } } }#endif } } r->object->finish();#ifdef LOADER_DEBUG kdDebug( 6060 ) << "Loader:: JOB FINISHED " << r->object << ": " << r->object->url().string() << endl;#endif delete r; if ( (m_requestsPending.count() != 0) && (m_requestsLoading.count() < MAX_JOB_COUNT / 2) ) m_timer.start(0, true);}void Loader::slotData( KIO::Job*job, const QByteArray &data ){ Request *r = m_requestsLoading[job]; if(!r) { kdDebug( 6060 ) << "got data for unknown request!" << endl; return; } if ( !r->m_buffer.isOpen() ) r->m_buffer.open( IO_WriteOnly ); r->m_buffer.writeBlock( data.data(), data.size() ); if(r->incremental) r->object->data( r->m_buffer, false );}int Loader::numRequests( DocLoader* dl ) const{ int res = 0; QPtrListIterator<Request> pIt( m_requestsPending ); for (; pIt.current(); ++pIt ) if ( pIt.current()->m_docLoader == dl ) res++; QPtrDictIterator<Request> lIt( m_requestsLoading ); for (; lIt.current(); ++lIt ) if ( lIt.current()->m_docLoader == dl ) res++; return res;}void Loader::cancelRequests( DocLoader* dl ){ QPtrListIterator<Request> pIt( m_requestsPending ); while ( pIt.current() ) { if ( pIt.current()->m_docLoader == dl ) { CDEBUG << "canceling pending request for " << pIt.current()->object->url().string() << endl; Cache::removeCacheEntry( pIt.current()->object ); m_requestsPending.remove( pIt ); } else ++pIt; } //kdDebug( 6060 ) << "got " << m_requestsLoading.count() << "loading requests" << endl; QPtrDictIterator<Request> lIt( m_requestsLoading ); while ( lIt.current() ) { if ( lIt.current()->m_docLoader == dl ) { //kdDebug( 6060 ) << "canceling loading request for " << lIt.current()->object->url().string() << endl; KIO::Job *job = static_cast<KIO::Job *>( lIt.currentKey() ); Cache::removeCacheEntry( lIt.current()->object ); m_requestsLoading.remove( lIt.currentKey() ); job->kill(); //emit requestFailed( dl, pIt.current()->object ); } else ++lIt; }}KIO::Job *Loader::jobForRequest( const DOM::DOMString &url ) const{ QPtrDictIterator<Request> it( m_requestsLoading ); for (; it.current(); ++it ) { CachedObject *obj = it.current()->object; if ( obj && obj->url() == url ) return static_cast<KIO::Job *>( it.currentKey() ); } return 0;}// ----------------------------------------------------------------------------QDict<CachedObject> *Cache::cache;QPtrList<DocLoader>* Cache::docloader;QPtrList<CachedObject> *Cache::freeList;Loader *Cache::m_loader;int Cache::maxSize = DEFCACHESIZE;int Cache::totalSizeOfLRU;QPixmap *Cache::nullPixmap;QPixmap *Cache::brokenPixmap;QPixmap *Cache::blockedPixmap;void Cache::init(){ if ( !cache ) cache = new QDict<CachedObject>(401, true); if ( !docloader ) docloader = new QPtrList<DocLoader>; if ( !nullPixmap ) nullPixmap = new QPixmap; if ( !brokenPixmap ) brokenPixmap = new QPixmap(KHTMLFactory::instance()->iconLoader()->loadIcon("file_broken", KIcon::Desktop, 16, KIcon::DisabledState)); if ( !blockedPixmap ) { blockedPixmap = new QPixmap(); blockedPixmap->loadFromData(blocked_icon_data, blocked_icon_len); } if ( !m_loader ) m_loader = new Loader(); if ( !freeList ) { freeList = new QPtrList<CachedObject>; freeList->setAutoDelete(true); }}void Cache::clear(){ if ( !cache ) return;#ifdef CACHE_DEBUG kdDebug( 6060 ) << "Cache: CLEAR!" << endl; statistics();#endif cache->setAutoDelete( true );#ifndef NDEBUG for (QDictIterator<CachedObject> it(*cache); it.current(); ++it) assert(it.current()->canDelete()); for (QPtrListIterator<CachedObject> it(*freeList); it.current(); ++it) assert(it.current()->canDelete());#endif delete cache; cache = 0; delete nullPixmap; nullPixmap = 0; delete brokenPixmap; brokenPixmap = 0; delete blockedPixmap; blockedPixmap = 0; delete m_loader; m_loader = 0; delete docloader; docloader = 0; delete freeList; freeList = 0;}template<typename CachedObjectType, enum CachedObject::Type CachedType>CachedObjectType* Cache::requestObject( DocLoader* dl, const KURL& kurl, const char* accept ){ KIO::CacheControl cachePolicy = dl ? dl->cachePolicy() : KIO::CC_Verify; QString url = kurl.url(); CachedObject* o = cache->find(url); if ( o && o->type() != CachedType ) { removeCacheEntry( o ); o = 0; } if ( o && dl->needReload( o, url ) ) { o = 0; assert( cache->find( url ) == 0 ); } if(!o) {#ifdef CACHE_DEBUG kdDebug( 6060 ) << "Cache: new: " << kurl.url() << endl;#endif CachedObjectType* cot = new CachedObjectType(dl, url, cachePolicy, accept); cache->insert( url, cot ); if ( cot->allowInLRUList() ) insertInLRUList( cot ); o = cot; }#ifdef CACHE_DEBUG else { kdDebug( 6060 ) << "Cache: using pending/cached: " << kurl.url() << endl; }#endif dl->insertCachedObject( o ); return static_cast<CachedObjectType *>(o);}void Cache::preloadStyleSheet( const QString &url, const QString &stylesheet_data){ CachedObject *o = cache->find(url); if(o) removeCacheEntry(o); CachedCSSStyleSheet *stylesheet = new CachedCSSStyleSheet(url, stylesheet_data); cache->insert( url, stylesheet );}void Cache::preloadScript( const QString &url, const QString &script_data){ CachedObject *o = cache->find(url); if(o) removeCacheEntry(o); CachedScript *script = new CachedScript(url, script_data); cache->insert( url, script );}void Cache::flush(bool force){ init(); if ( force || totalSizeOfLRU > maxSize + maxSize/4) { for ( int i = MAX_LRU_LISTS-1; i >= 0 && totalSizeOfLRU > maxSize; --i ) while ( totalSizeOfLRU > maxSize && m_LRULists[i].m_tail ) removeCacheEntry( m_LRULists[i].m_tail );#ifdef CACHE_DEBUG statistics();#endif } for ( CachedObject* p = freeList->first(); p; p = freeList->next() ) { if ( p->canDelete() ) freeList->remove(); }}void Cache::setSize( int bytes ){ maxSize = bytes; flush(true /* force */);}void Cache::statistics(){ CachedObject *o; // this function is for debugging purposes only init(); int size = 0; int msize = 0; int movie = 0; int images = 0; int scripts = 0; int stylesheets = 0; QDictIterator<CachedObject> it(*cache); for(it.toFirst(); it.current(); ++it) { o = it.current(); switch(o->type()) { case CachedObject::Image: { CachedImage *im = static_cast<CachedImage *>(o); images++; if(im->m != 0) { movie++; msize += im->size(); } break; } case CachedObject::CSSStyleSheet: stylesheets++; break; case CachedObject::Script: scripts++; break; } size += o->size(); } size /= 1024; kdDebug( 6060 ) << "------------------------- image cache statistics -------------------" << endl; kdDebug( 6060 ) << "Number of items in cache: " << cache->count() << endl; kdDebug( 6060 ) << "Number of cached images: " << images << endl; kdDebug( 6060 ) << "Number of cached movies: " << movie << endl; kdDebug( 6060 ) << "Number of cached scripts: " << scripts << endl; kdDebug( 6060 ) << "Number of cached stylesheets: " << stylesheets << endl; kdDebug( 6060 ) << "pixmaps: allocated space approx. " << size << " kB" << endl; kdDebug( 6060 ) << "movies : allocated space approx. " << msize/1024 << " kB" << endl; kdDebug( 6060 ) << "--------------------------------------------------------------------" << endl;}void Cache::removeCacheEntry( CachedObject *object ){ QString key = object->url().string(); cache->remove( key ); removeFromLRUList( object ); for (const DocLoader* dl=docloader->first(); dl; dl=docloader->next() ) dl->removeCachedObject( object ); if ( !object->free() ) { Cache::freeList->append( object ); object->m_free = true; }}static inline int FastLog2(unsigned int j){ unsigned int log2; log2 = 0; if (j & (j-1)) log2 += 1; if (j >> 16) log2 += 16, j >>= 16; if (j >> 8) log2 += 8, j >>= 8; if (j >> 4) log2 += 4, j >>= 4; if (j >> 2) log2 += 2, j >>= 2; if (j >> 1) log2 += 1; return log2;}static LRUList* getLRUListFor(CachedObject* o){ int accessCount = o->accessCount(); int queueIndex; if (accessCount == 0) { queueIndex = 0; } else { int sizeLog = FastLog2(o->size()); queueIndex = sizeLog/o->accessCount() - 1; if (queueIndex < 0) queueIndex = 0; if (queueIndex >= MAX_LRU_LISTS) queueIndex = MAX_LRU_LISTS-1; } return &m_LRULists[queueIndex];}void Cache::removeFromLRUList(CachedObject *object){ CachedObject *next = object->m_next; CachedObject *prev = object->m_prev; LRUList* list = getLRUListFor(object); CachedObject *&head = getLRUListFor(object)->m_head; if (next == 0 && prev == 0 && head != object) { return; } object->m_next = 0; object->m_prev = 0; if (next) next->m_prev = prev; else if (list->m_tail == object) list->m_tail = prev; if (prev) prev->m_next = next; else if (head == object) head = next; totalSizeOfLRU -= object->size();}void Cache::insertInLRUList(CachedObject *object){ removeFromLRUList(object); assert( object ); assert( !object->free() ); assert( object->canDelete() ); assert( object->allowInLRUList() ); LRUList* list = getLRUListFor(object); CachedObject *&head = list->m_head; object->m_next = head; if (head) head->m_prev = object; head = object; if (object->m_next == 0) list->m_tail = object; totalSizeOfLRU += object->size();}// --------------------------------------void CachedObjectClient::setPixmap(const QPixmap &, const QRect&, CachedImage *) {}void CachedObjectClient::setStyleSheet(const DOM::DOMString &/*url*/, const DOM::DOMString &/*sheet*/) {}void CachedObjectClient::notifyFinished(CachedObject * /*finishedObj*/) {}void CachedObjectClient::error(int /*err*/, const QString &/*text*/) {}#undef CDEBUG#include "loader.moc"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -