00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #undef CACHE_DEBUG
00028
00029 #include <assert.h>
00030
00031 #include "loader.h"
00032
00033
00034 #define MAXCACHEABLE 40*1024
00035
00036 #define DEFCACHESIZE 512*1024
00037
00038 #include <qasyncio.h>
00039 #include <qasyncimageio.h>
00040 #include <qpainter.h>
00041 #include <qbitmap.h>
00042 #include <qmovie.h>
00043 #include <qwidget.h>
00044
00045 #include <kio/job.h>
00046 #include <kio/jobclasses.h>
00047 #include <kglobal.h>
00048 #include <kimageio.h>
00049 #include <kcharsets.h>
00050 #include <kiconloader.h>
00051 #include <scheduler.h>
00052 #include <kdebug.h>
00053 #include "khtml_factory.h"
00054 #include "khtml_part.h"
00055
00056 #include "html/html_documentimpl.h"
00057 #include "css/css_stylesheetimpl.h"
00058 #include "xml/dom_docimpl.h"
00059
00060 using namespace khtml;
00061 using namespace DOM;
00062
00063 void CachedObject::finish()
00064 {
00065 if( m_size > MAXCACHEABLE )
00066 m_status = Uncacheable;
00067 else
00068 m_status = Cached;
00069 KURL url(m_url.string());
00070 if (m_expireDateChanged && url.protocol().startsWith("http"))
00071 {
00072 m_expireDateChanged = false;
00073 KIO::http_update_cache(url, false, m_expireDate);
00074 #ifdef CACHE_DEBUG
00075 kdDebug(6060) << " Setting expire date for image "<<m_url.string()<<" to " << m_expireDate << endl;
00076 #endif
00077 }
00078 #ifdef CACHE_DEBUG
00079 else kdDebug(6060) << " No expire date for image "<<m_url.string()<<endl;
00080 #endif
00081 }
00082
00083 void CachedObject::setExpireDate(time_t _expireDate, bool changeHttpCache)
00084 {
00085 if ( _expireDate == m_expireDate)
00086 return;
00087
00088 if (m_status == Uncacheable || m_status == Cached)
00089 {
00090 finish();
00091 }
00092 m_expireDate = _expireDate;
00093 if (changeHttpCache && m_expireDate)
00094 m_expireDateChanged = true;
00095 }
00096
00097 bool CachedObject::isExpired() const
00098 {
00099 if (!m_expireDate) return false;
00100 time_t now = time(0);
00101 return (difftime(now, m_expireDate) >= 0);
00102 }
00103
00104 void CachedObject::setRequest(Request *_request)
00105 {
00106 if ( _request && !m_request )
00107 m_status = Pending;
00108 m_request = _request;
00109 if (canDelete() && m_free)
00110 delete this;
00111 }
00112
00113
00114
00115 CachedCSSStyleSheet::CachedCSSStyleSheet(DocLoader* dl, const DOMString &url, KIO::CacheControl _cachePolicy, time_t _expireDate, const QString& charset)
00116 : CachedObject(url, CSSStyleSheet, _cachePolicy, _expireDate)
00117 {
00118
00119 setAccept( QString::fromLatin1("text/css") );
00120
00121 Cache::loader()->load(dl, this, false);
00122 m_loading = true;
00123 bool b;
00124 if(!charset.isEmpty())
00125 {
00126 m_codec = KGlobal::charsets()->codecForName(charset, b);
00127 if(m_codec->mibEnum() == 11) {
00128
00129 m_codec = QTextCodec::codecForName("iso8859-8-i");
00130 }
00131 }
00132 else
00133 m_codec = QTextCodec::codecForMib(4);
00134 }
00135
00136 CachedCSSStyleSheet::CachedCSSStyleSheet(const DOMString &url, const QString &stylesheet_data)
00137 : CachedObject(url, CSSStyleSheet, KIO::CC_Verify, 0)
00138 {
00139 m_loading = false;
00140 m_status = Persistent;
00141 m_codec = 0;
00142 m_size = stylesheet_data.length();
00143 m_sheet = DOMString(stylesheet_data);
00144 }
00145
00146
00147 CachedCSSStyleSheet::~CachedCSSStyleSheet()
00148 {
00149 }
00150
00151 void CachedCSSStyleSheet::ref(CachedObjectClient *c)
00152 {
00153
00154 m_clients.remove(c);
00155 m_clients.append(c);
00156
00157 if(!m_loading) c->setStyleSheet( m_url, m_sheet );
00158 }
00159
00160 void CachedCSSStyleSheet::deref(CachedObjectClient *c)
00161 {
00162 Cache::flush();
00163 m_clients.remove(c);
00164
00165 if ( canDelete() && m_free )
00166 delete this;
00167 }
00168
00169 void CachedCSSStyleSheet::data( QBuffer &buffer, bool eof )
00170 {
00171 if(!eof) return;
00172 buffer.close();
00173 m_size = buffer.buffer().size();
00174 QString data = m_codec->toUnicode( buffer.buffer().data(), m_size );
00175 m_sheet = DOMString(data);
00176 m_loading = false;
00177
00178 checkNotify();
00179 }
00180
00181 void CachedCSSStyleSheet::checkNotify()
00182 {
00183 if(m_loading) return;
00184
00185 #ifdef CACHE_DEBUG
00186 kdDebug( 6060 ) << "CachedCSSStyleSheet:: finishedLoading " << m_url.string() << endl;
00187 #endif
00188
00189
00190
00191 for (QPtrListIterator<CachedObjectClient> it( m_clients ); it.current();)
00192 it()->setStyleSheet( m_url, m_sheet );
00193 }
00194
00195
00196 void CachedCSSStyleSheet::error( int , const char * )
00197 {
00198 m_loading = false;
00199 checkNotify();
00200 }
00201
00202
00203
00204 CachedScript::CachedScript(DocLoader* dl, const DOMString &url, KIO::CacheControl _cachePolicy, time_t _expireDate, const QString& charset)
00205 : CachedObject(url, Script, _cachePolicy, _expireDate)
00206 {
00207
00208
00209
00210 setAccept( QString::fromLatin1("*/*") );
00211
00212 Cache::loader()->load(dl, this, false);
00213 m_loading = true;
00214 bool b;
00215 if(!charset.isEmpty()) {
00216 m_codec = KGlobal::charsets()->codecForName(charset, b);
00217 if(m_codec->mibEnum() == 11) {
00218
00219 m_codec = QTextCodec::codecForName("iso8859-8-i");
00220 }
00221 }
00222 else
00223 m_codec = QTextCodec::codecForMib(4);
00224 }
00225
00226 CachedScript::CachedScript(const DOMString &url, const QString &script_data)
00227 : CachedObject(url, Script, KIO::CC_Verify, 0)
00228 {
00229 m_loading = false;
00230 m_status = Persistent;
00231 m_codec = 0;
00232 m_size = script_data.length();
00233 m_script = DOMString(script_data);
00234 }
00235
00236 CachedScript::~CachedScript()
00237 {
00238 }
00239
00240 void CachedScript::ref(CachedObjectClient *c)
00241 {
00242
00243 m_clients.remove(c);
00244 m_clients.append(c);
00245
00246 if(!m_loading) c->notifyFinished(this);
00247 }
00248
00249 void CachedScript::deref(CachedObjectClient *c)
00250 {
00251 Cache::flush();
00252 m_clients.remove(c);
00253 if ( canDelete() && m_free )
00254 delete this;
00255 }
00256
00257 void CachedScript::data( QBuffer &buffer, bool eof )
00258 {
00259 if(!eof) return;
00260 buffer.close();
00261 m_size = buffer.buffer().size();
00262 QString data = m_codec->toUnicode( buffer.buffer().data(), m_size );
00263 m_script = DOMString(data);
00264 m_loading = false;
00265 checkNotify();
00266 }
00267
00268 void CachedScript::checkNotify()
00269 {
00270 if(m_loading) return;
00271
00272 for (QPtrListIterator<CachedObjectClient> it( m_clients); it.current();)
00273 it()->notifyFinished(this);
00274 }
00275
00276
00277 void CachedScript::error( int , const char * )
00278 {
00279 m_loading = false;
00280 checkNotify();
00281 }
00282
00283
00284
00285 namespace khtml
00286 {
00287
00288 class ImageSource : public QDataSource
00289 {
00290 public:
00291 ImageSource(QByteArray buf);
00292
00297 int readyToSend();
00298
00302 void sendTo(QDataSink*, int count);
00303
00307 void setEOF( bool state );
00308
00312 bool rewindable() const;
00313
00317 void enableRewind(bool on);
00318
00319
00320
00321
00322 void rewind();
00323
00324
00325
00326
00327
00328 void cleanBuffer();
00329
00330 QByteArray buffer;
00331 unsigned int pos;
00332 private:
00333 bool eof : 1;
00334 bool rew : 1;
00335 bool rewable : 1;
00336 };
00337 }
00338
00339
00340 ImageSource::ImageSource(QByteArray buf)
00341 {
00342 buffer = buf;
00343 rew = false;
00344 pos = 0;
00345 eof = false;
00346 rewable = true;
00347 }
00348
00349 int ImageSource::readyToSend()
00350 {
00351 if(eof && pos == buffer.size())
00352 return -1;
00353
00354 return buffer.size() - pos;
00355 }
00356
00357 void ImageSource::sendTo(QDataSink* sink, int n)
00358 {
00359 sink->receive((const uchar*)&buffer.at(pos), n);
00360
00361 pos += n;
00362
00363
00364 if(eof && pos == buffer.size() && !rewable)
00365 {
00366 buffer.resize(0);
00367 pos = 0;
00368 }
00369 }
00370
00371 void ImageSource::setEOF( bool state )
00372 {
00373 eof = state;
00374 }
00375
00376
00377 bool ImageSource::rewindable() const
00378 {
00379 return rewable;
00380 }
00381
00382
00383 void ImageSource::enableRewind(bool on)
00384 {
00385 rew = on;
00386 }
00387
00388
00389 void ImageSource::rewind()
00390 {
00391 pos = 0;
00392 if (!rew) {
00393 QDataSource::rewind();
00394 } else
00395 ready();
00396 }
00397
00398 void ImageSource::cleanBuffer()
00399 {
00400
00401 if(rew)
00402 return;
00403
00404 rewable = false;
00405
00406
00407 if(eof && pos == buffer.size())
00408 {
00409 buffer.resize(0);
00410 pos = 0;
00411 }
00412 }
00413
00414 static QString buildAcceptHeader()
00415 {
00416 QString result = KImageIO::mimeTypes( KImageIO::Reading ).join(", ");
00417 if (result.right(2) == ", ")
00418 result = result.left(result.length()-2);
00419 return result;
00420 }
00421
00422 static bool crossDomain(const QString &a, const QString &b)
00423 {
00424 if (a == b) return false;
00425
00426 QStringList l1 = QStringList::split('.', a);
00427 QStringList l2 = QStringList::split('.', b);
00428
00429 while(l1.count() > l2.count())
00430 l1.pop_front();
00431
00432 while(l2.count() > l1.count())
00433 l2.pop_front();
00434
00435 while(l2.count() >= 2)
00436 {
00437 if (l1 == l2)
00438 return false;
00439
00440 l1.pop_front();
00441 l2.pop_front();
00442 }
00443 return true;
00444 }
00445
00446
00447
00448 CachedImage::CachedImage(DocLoader* dl, const DOMString &url, KIO::CacheControl _cachePolicy, time_t _expireDate)
00449 : QObject(), CachedObject(url, Image, _cachePolicy, _expireDate)
00450 {
00451 static const QString &acceptHeader = KGlobal::staticQString( buildAcceptHeader() );
00452
00453 m = 0;
00454 p = 0;
00455 pixPart = 0;
00456 bg = 0;
00457 bgColor = qRgba( 0, 0, 0, 0xFF );
00458 typeChecked = false;
00459 isFullyTransparent = false;
00460 errorOccured = false;
00461 monochrome = false;
00462 formatType = 0;
00463 m_status = Unknown;
00464 m_size = 0;
00465 imgSource = 0;
00466 setAccept( acceptHeader );
00467 m_showAnimations = dl->showAnimations();
00468 }
00469
00470 CachedImage::~CachedImage()
00471 {
00472 clear();
00473 }
00474
00475 void CachedImage::ref( CachedObjectClient *c )
00476 {
00477 #ifdef CACHE_DEBUG
00478 kdDebug( 6060 ) << this << " CachedImage::ref(" << c << ") pixmap.isNull()=" << pixmap().isNull() << " valid_rect.isNull()=" << valid_rect().isNull()<< " status=" << m_status << endl;
00479 #endif
00480
00481
00482 m_clients.remove(c);
00483 m_clients.append(c);
00484
00485 if( m ) {
00486 m->unpause();
00487 if( m->finished() || m_clients.count() == 1 )
00488 m->restart();
00489 }
00490
00491
00492 if ( m_status >= Persistent && !valid_rect().isNull() )
00493 c->setPixmap( pixmap(), valid_rect(), this);
00494 }
00495
00496 void CachedImage::deref( CachedObjectClient *c )
00497 {
00498 #ifdef CACHE_DEBUG
00499 kdDebug( 6060 ) << this << " CachedImage::deref(" << c << ") " << endl;
00500 #endif
00501 Cache::flush();
00502 m_clients.remove( c );
00503 if(m && m_clients.isEmpty() && m->running())
00504 m->pause();
00505 if ( canDelete() && m_free )
00506 delete this;
00507 }
00508
00509 #define BGMINWIDTH 32
00510 #define BGMINHEIGHT 32
00511
00512 const QPixmap &CachedImage::tiled_pixmap(const QColor& newc)
00513 {
00514 static QRgb bgTransparant = qRgba( 0, 0, 0, 0xFF );
00515 if ( (bgColor != bgTransparant) && (bgColor != newc.rgb()) ) {
00516 delete bg; bg = 0;
00517 }
00518
00519 if (bg)
00520 return *bg;
00521
00522 const QPixmap &r = pixmap();
00523
00524 if (r.isNull()) return r;
00525
00526
00527 if(errorOccured) return *Cache::nullPixmap;
00528
00529 bool isvalid = newc.isValid();
00530 QSize s(pixmap_size());
00531 int w = r.width();
00532 int h = r.height();
00533 if ( w*h < 8192 )
00534 {
00535 if ( r.width() < BGMINWIDTH )
00536 w = ((BGMINWIDTH / s.width())+1) * s.width();
00537 if ( r.height() < BGMINHEIGHT )
00538 h = ((BGMINHEIGHT / s.height())+1) * s.height();
00539 }
00540 if ( (w != r.width()) || (h != r.height()) || (isvalid && r.mask()))
00541 {
00542 QPixmap pix = r;
00543 if ( w != r.width() || (isvalid && pix.mask()))
00544 {
00545 bg = new QPixmap(w, r.height());
00546 QPainter p(bg);
00547 if(isvalid) p.fillRect(0, 0, w, r.height(), newc);
00548 p.drawTiledPixmap(0, 0, w, r.height(), pix);
00549 if(!isvalid && pix.mask())
00550 {
00551
00552
00553 QBitmap newmask(w, r.height());
00554 QPainter pm(&newmask);
00555 pm.drawTiledPixmap(0, 0, w, r.height(), *pix.mask());
00556 bg->setMask(newmask);
00557 bgColor = bgTransparant;
00558 }
00559 else
00560 bgColor= newc.rgb();
00561 pix = *bg;
00562 }
00563 if ( h != r.height() )
00564 {
00565 delete bg;
00566 bg = new QPixmap(w, h);
00567 QPainter p(bg);
00568 if(isvalid) p.fillRect(0, 0, w, h, newc);
00569 p.drawTiledPixmap(0, 0, w, h, pix);
00570 if(!isvalid && pix.mask())
00571 {
00572
00573
00574 QBitmap newmask(w, h);
00575 QPainter pm(&newmask);
00576 pm.drawTiledPixmap(0, 0, w, h, *pix.mask());
00577 bg->setMask(newmask);
00578 bgColor = bgTransparant;
00579 }
00580 else
00581 bgColor= newc.rgb();
00582 }
00583 return *bg;
00584 }
00585
00586 return r;
00587 }
00588
00589 const QPixmap &CachedImage::pixmap( ) const
00590 {
00591 if(errorOccured)
00592 return *Cache::brokenPixmap;
00593
00594 if(m)
00595 {
00596 if(m->framePixmap().size() != m->getValidRect().size() && m->getValidRect().size().isValid())
00597 {
00598
00599
00600
00601 if(!pixPart) pixPart = new QPixmap(m->getValidRect().size());
00602
00603 (*pixPart) = m->framePixmap();
00604 pixPart->resize(m->getValidRect().size());
00605 return *pixPart;
00606 }
00607 else
00608 return m->framePixmap();
00609 }
00610 else if(p)
00611 return *p;
00612
00613 return *Cache::nullPixmap;
00614 }
00615
00616
00617 QSize CachedImage::pixmap_size() const
00618 {
00619 return (m ? m->framePixmap().size() : ( p ? p->size() : QSize()));
00620 }
00621
00622
00623 QRect CachedImage::valid_rect() const
00624 {
00625 return m ? m->getValidRect() : ( p ? p->rect() : QRect());
00626 }
00627
00628
00629 void CachedImage::do_notify(const QPixmap& p, const QRect& r)
00630 {
00631 CachedObjectClient *c;
00632
00633 for ( c = m_clients.first(); c != 0; c = m_clients.next() )
00634 c->setPixmap( p, r, this);
00635 }
00636
00637
00638 void CachedImage::movieUpdated( const QRect& r )
00639 {
00640 #ifdef CACHE_DEBUG
00641 qDebug("movie updated %d/%d/%d/%d, pixmap size %d/%d", r.x(), r.y(), r.right(), r.bottom(),
00642 m->framePixmap().size().width(), m->framePixmap().size().height());
00643 #endif
00644
00645 do_notify(m->framePixmap(), r);
00646 }
00647
00648 void CachedImage::movieStatus(int status)
00649 {
00650 #ifdef CACHE_DEBUG
00651 qDebug("movieStatus(%d)", status);
00652 #endif
00653
00654
00655
00656
00657
00658
00659
00660 if(status == QMovie::EndOfFrame)
00661 {
00662 const QImage& im = m->frameImage();
00663 monochrome = ( ( im.depth() <= 8 ) && ( im.numColors() - int( im.hasAlphaBuffer() ) <= 2 ) );
00664 for (int i = 0; monochrome && i < im.numColors(); ++i)
00665 if (im.colorTable()[i] != qRgb(0xff, 0xff, 0xff) &&
00666 im.colorTable()[i] != qRgb(0x00, 0x00, 0x00))
00667 monochrome = false;
00668 if( (im.width() < 5 || im.height() < 5) && im.hasAlphaBuffer())
00669 {
00670 QImage am = im.createAlphaMask();
00671 if(am.depth() == 1)
00672 {
00673 bool solid = false;
00674 for(int y = 0; y < am.height(); y++)
00675 for(int x = 0; x < am.width(); x++)
00676 if(am.pixelIndex(x, y)) {
00677 solid = true;
00678 break;
00679 }
00680 isFullyTransparent = (!solid);
00681 }
00682 }
00683
00684
00685
00686 delete bg;
00687 bg = 0;
00688 }
00689
00690
00691 if((status == QMovie::EndOfMovie && (!m || m->frameNumber() <= 1)) ||
00692 ((status == QMovie::EndOfLoop) && (m_showAnimations == KHTMLSettings::KAnimationLoopOnce)) ||
00693 ((status == QMovie::EndOfFrame) && (m_showAnimations == KHTMLSettings::KAnimationDisabled))
00694 )
00695 {
00696 if(imgSource)
00697 {
00698 setShowAnimations( KHTMLSettings::KAnimationDisabled );
00699
00700
00701
00702 if (p && monochrome && p->depth() > 1 )
00703 {
00704 QPixmap* pix = new QPixmap;
00705 pix->convertFromImage( p->convertToImage().convertDepth( 1 ), MonoOnly|AvoidDither );
00706 if ( p->mask() )
00707 pix->setMask( *p->mask() );
00708 delete p;
00709 p = pix;
00710 monochrome = false;
00711 }
00712 }
00713 for (QPtrListIterator<CachedObjectClient> it( m_clients ); it.current();)
00714 it()->notifyFinished(this);
00715 }
00716
00717 #if 0
00718 if((status == QMovie::EndOfFrame) || (status == QMovie::EndOfMovie))
00719 {
00720 #ifdef CACHE_DEBUG
00721 QRect r(valid_rect());
00722 qDebug("movie Status frame update %d/%d/%d/%d, pixmap size %d/%d", r.x(), r.y(), r.right(), r.bottom(),
00723 pixmap().size().width(), pixmap().size().height());
00724 #endif
00725 do_notify(pixmap(), valid_rect());
00726 }
00727 #endif
00728 }
00729
00730 void CachedImage::movieResize(const QSize& )
00731 {
00732
00733 }
00734
00735 void CachedImage::setShowAnimations( KHTMLSettings::KAnimationAdvice showAnimations )
00736 {
00737 m_showAnimations = showAnimations;
00738 if ( (m_showAnimations == KHTMLSettings::KAnimationDisabled) && imgSource ) {
00739 imgSource->cleanBuffer();
00740 delete p;
00741 p = new QPixmap(m->framePixmap());
00742
00743 m->disconnectUpdate( this, SLOT( movieUpdated( const QRect &) ));
00744 m->disconnectStatus( this, SLOT( movieStatus( int ) ));
00745 m->disconnectResize( this, SLOT( movieResize( const QSize& ) ) );
00746 QTimer::singleShot(0, this, SLOT( deleteMovie()));
00747 imgSource = 0;
00748 }
00749 }
00750
00751 void CachedImage::deleteMovie()
00752 {
00753 delete m; m = 0;
00754 }
00755
00756 void CachedImage::clear()
00757 {
00758 delete m; m = 0;
00759 delete p; p = 0;
00760 delete bg; bg = 0;
00761 bgColor = qRgba( 0, 0, 0, 0xff );
00762 delete pixPart; pixPart = 0;
00763
00764 formatType = 0;
00765
00766 typeChecked = false;
00767 m_size = 0;
00768
00769
00770 imgSource = 0;
00771 }
00772
00773 void CachedImage::data ( QBuffer &_buffer, bool eof )
00774 {
00775 #ifdef CACHE_DEBUG
00776 kdDebug( 6060 ) << this << "in CachedImage::data(buffersize " << _buffer.buffer().size() <<", eof=" << eof << endl;
00777 #endif
00778 if ( !typeChecked )
00779 {
00780 formatType = QImageDecoder::formatName( (const uchar*)_buffer.buffer().data(), _buffer.size());
00781 typeChecked = true;
00782
00783 if ( formatType )
00784 {
00785 imgSource = new ImageSource( _buffer.buffer());
00786 m = new QMovie( imgSource, 8192 );
00787 m->connectUpdate( this, SLOT( movieUpdated( const QRect &) ));
00788 m->connectStatus( this, SLOT( movieStatus(int)));
00789 m->connectResize( this, SLOT( movieResize( const QSize& ) ) );
00790 }
00791 }
00792
00793 if ( imgSource )
00794 {
00795 imgSource->setEOF(eof);
00796 imgSource->maybeReady();
00797 }
00798
00799 if(eof)
00800 {
00801
00802
00803
00804 if(typeChecked && !formatType)
00805 {
00806 #ifdef CACHE_DEBUG
00807 kdDebug(6060) << "CachedImage::data(): reloading as pixmap:" << endl;
00808 #endif
00809 p = new QPixmap( _buffer.buffer() );
00810
00811 #ifdef CACHE_DEBUG
00812 kdDebug(6060) << "CachedImage::data(): image is null: " << p->isNull() << endl;
00813 #endif
00814 if(p->isNull())
00815 {
00816 errorOccured = true;
00817 do_notify(pixmap(), QRect(0, 0, 16, 16));
00818 }
00819 else
00820 do_notify(*p, p->rect());
00821 }
00822
00823 QSize s = pixmap_size();
00824 m_size = s.width() * s.height() * 2;
00825 }
00826 }
00827
00828 void CachedImage::finish()
00829 {
00830 Status oldStatus = m_status;
00831 CachedObject::finish();
00832 if ( oldStatus != m_status ) {
00833 const QPixmap &pm = pixmap();
00834 do_notify( pm, pm.rect() );
00835 }
00836 }
00837
00838
00839 void CachedImage::error( int , const char * )
00840 {
00841 #ifdef CACHE_DEBUG
00842 kdDebug(6060) << "CahcedImage::error" << endl;
00843 #endif
00844
00845 clear();
00846 typeChecked = true;
00847 errorOccured = true;
00848 do_notify(pixmap(), QRect(0, 0, 16, 16));
00849 }
00850
00851
00852
00853 Request::Request(DocLoader* dl, CachedObject *_object, bool _incremental)
00854 {
00855 object = _object;
00856 object->setRequest(this);
00857 incremental = _incremental;
00858 m_docLoader = dl;
00859 }
00860
00861 Request::~Request()
00862 {
00863 object->setRequest(0);
00864 }
00865
00866
00867
00868 DocLoader::DocLoader(KHTMLPart* part, DocumentImpl* doc)
00869 {
00870 m_cachePolicy = KIO::CC_Verify;
00871 m_expireDate = 0;
00872 m_creationDate = time(0);
00873 m_bautoloadImages = true;
00874 m_showAnimations = KHTMLSettings::KAnimationEnabled;
00875 m_part = part;
00876 m_doc = doc;
00877
00878 Cache::docloader->append( this );
00879 }
00880
00881 DocLoader::~DocLoader()
00882 {
00883 Cache::docloader->remove( this );
00884 }
00885
00886 void DocLoader::setCacheCreationDate(time_t _creationDate)
00887 {
00888 if (_creationDate)
00889 m_creationDate = _creationDate;
00890 else
00891 m_creationDate = time(0);
00892 }
00893
00894 void DocLoader::setExpireDate(time_t _expireDate, bool relative)
00895 {
00896 if (relative)
00897 m_expireDate = _expireDate + m_creationDate;
00898 else
00899 m_expireDate = _expireDate;
00900 #ifdef CACHE_DEBUG
00901 kdDebug(6061) << "docLoader: " << m_expireDate - time(0) << " seconds left until reload required.\n";
00902 #endif
00903 }
00904
00905 bool DocLoader::needReload(const KURL &fullURL)
00906 {
00907 bool reload = false;
00908 if (m_cachePolicy == KIO::CC_Verify)
00909 {
00910 if (!m_reloadedURLs.contains(fullURL.url()))
00911 {
00912 CachedObject *existing = Cache::cache->find(fullURL.url());
00913 if (existing && existing->isExpired())
00914 {
00915 Cache::removeCacheEntry(existing);
00916 m_reloadedURLs.append(fullURL.url());
00917 reload = true;
00918 }
00919 }
00920 }
00921 else if ((m_cachePolicy == KIO::CC_Reload) || (m_cachePolicy == KIO::CC_Refresh))
00922 {
00923 if (!m_reloadedURLs.contains(fullURL.url()))
00924 {
00925 CachedObject *existing = Cache::cache->find(fullURL.url());
00926 if (existing)
00927 {
00928 Cache::removeCacheEntry(existing);
00929 }
00930 m_reloadedURLs.append(fullURL.url());
00931 reload = true;
00932 }
00933 }
00934 return reload;
00935 }
00936
00937 CachedImage *DocLoader::requestImage( const DOM::DOMString &url)
00938 {
00939 KURL fullURL = m_doc->completeURL( url.string() );
00940 if ( m_part && m_part->onlyLocalReferences() && fullURL.protocol() != "file") return 0;
00941
00942 bool reload = needReload(fullURL);
00943
00944 return Cache::requestImage(this, url, reload, m_expireDate);
00945 }
00946
00947 CachedCSSStyleSheet *DocLoader::requestStyleSheet( const DOM::DOMString &url, const QString& charset)
00948 {
00949 KURL fullURL = m_doc->completeURL( url.string() );
00950 if ( m_part && m_part->onlyLocalReferences() && fullURL.protocol() != "file") return 0;
00951
00952 bool reload = needReload(fullURL);
00953
00954 return Cache::requestStyleSheet(this, url, reload, m_expireDate, charset);
00955 }
00956
00957 CachedScript *DocLoader::requestScript( const DOM::DOMString &url, const QString& charset)
00958 {
00959 KURL fullURL = m_doc->completeURL( url.string() );
00960 if ( m_part && m_part->onlyLocalReferences() && fullURL.protocol() != "file") return 0;
00961
00962 bool reload = needReload(fullURL);
00963
00964 return Cache::requestScript(this, url, reload, m_expireDate, charset);
00965 }
00966
00967 void DocLoader::setAutoloadImages( bool enable )
00968 {
00969 if ( enable == m_bautoloadImages )
00970 return;
00971
00972 m_bautoloadImages = enable;
00973
00974 if ( !m_bautoloadImages ) return;
00975
00976 for ( const CachedObject* co=m_docObjects.first(); co; co=m_docObjects.next() )
00977 if ( co->type() == CachedObject::Image )
00978 {
00979 CachedImage *img = const_cast<CachedImage*>( static_cast<const CachedImage *>( co ) );
00980
00981 CachedObject::Status status = img->status();
00982 if ( status != CachedObject::Unknown )
00983 continue;
00984
00985 Cache::loader()->load(this, img, true);
00986 }
00987 }
00988
00989 void DocLoader::setCachePolicy( KIO::CacheControl cachePolicy )
00990 {
00991 m_cachePolicy = cachePolicy;
00992 }
00993
00994 void DocLoader::setShowAnimations( KHTMLSettings::KAnimationAdvice showAnimations )
00995 {
00996 if ( showAnimations == m_showAnimations ) return;
00997 m_showAnimations = showAnimations;
00998
00999 const CachedObject* co;
01000 for ( co=m_docObjects.first(); co; co=m_docObjects.next() )
01001 if ( co->type() == CachedObject::Image )
01002 {
01003 CachedImage *img = const_cast<CachedImage*>( static_cast<const CachedImage *>( co ) );
01004
01005 img->setShowAnimations( showAnimations );
01006 }
01007 }
01008
01009 void DocLoader::removeCachedObject( CachedObject* o ) const
01010 {
01011 m_docObjects.removeRef( o );
01012 }
01013
01014
01015
01016 Loader::Loader() : QObject()
01017 {
01018 m_requestsPending.setAutoDelete( true );
01019 m_requestsLoading.setAutoDelete( true );
01020 }
01021
01022 Loader::~Loader()
01023 {
01024 }
01025
01026 void Loader::load(DocLoader* dl, CachedObject *object, bool incremental)
01027 {
01028 Request *req = new Request(dl, object, incremental);
01029 m_requestsPending.append(req);
01030
01031 emit requestStarted( req->m_docLoader, req->object );
01032
01033 QTimer::singleShot( 0, this, SLOT( servePendingRequests() ) );
01034 }
01035
01036 void Loader::servePendingRequests()
01037 {
01038 if ( m_requestsPending.count() == 0 )
01039 return;
01040
01041
01042 Request *req = m_requestsPending.take(0);
01043
01044 #ifdef CACHE_DEBUG
01045 kdDebug( 6060 ) << "starting Loader url=" << req->object->url().string() << endl;
01046 #endif
01047
01048 KURL u(req->object->url().string());
01049 KIO::TransferJob* job = KIO::get( u, false, false );
01050
01051 job->addMetaData("cache", KIO::getCacheControlString(req->object->cachePolicy()));
01052 if (!req->object->accept().isEmpty())
01053 job->addMetaData("accept", req->object->accept());
01054 if ( req->m_docLoader ) {
01055 KURL r = req->m_docLoader->doc()->URL();
01056 r.setRef(QString::null);
01057 if ( r.protocol().startsWith( "http" ) && r.path().isEmpty() )
01058 r.setPath( "/" );
01059 job->addMetaData("referrer", r.url());
01060 QString domain = r.host();
01061 if (req->m_docLoader->doc()->isHTMLDocument())
01062 domain = static_cast<HTMLDocumentImpl*>(req->m_docLoader->doc())->domain().string();
01063 if (crossDomain(u.host(), domain))
01064 job->addMetaData("cross-domain", "true");
01065
01066 KHTMLPart *part = req->m_docLoader->part();
01067 if (part && part->widget() && part->widget()->topLevelWidget())
01068 job->setWindow (part->widget()->topLevelWidget());
01069 }
01070
01071 connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotFinished( KIO::Job * ) ) );
01072 connect( job, SIGNAL( data( KIO::Job*, const QByteArray &)),
01073 SLOT( slotData( KIO::Job*, const QByteArray &)));
01074
01075 if ( req->object->schedule() )
01076 KIO::Scheduler::scheduleJob( job );
01077
01078 m_requestsLoading.insert(job, req);
01079 }
01080
01081 void Loader::slotFinished( KIO::Job* job )
01082 {
01083 Request *r = m_requestsLoading.take( job );
01084 KIO::TransferJob* j = static_cast<KIO::TransferJob*>(job);
01085
01086 if ( !r )
01087 return;
01088
01089 if (j->error() || j->isErrorPage())
01090 {
01091 #ifdef CACHE_DEBUG
01092 kdDebug(6060) << "Loader::slotFinished, with error. job->error()= " << j->error() << " job->isErrorPage()=" << j->isErrorPage() << endl;
01093 #endif
01094 r->object->error( job->error(), job->errorText().ascii() );
01095 emit requestFailed( r->m_docLoader, r->object );
01096 }
01097 else
01098 {
01099 r->object->data(r->m_buffer, true);
01100 emit requestDone( r->m_docLoader, r->object );
01101 time_t expireDate = j->queryMetaData("expire-date").toLong();
01102 #ifdef CACHE_DEBUG
01103 kdDebug(6060) << "Loader::slotFinished, url = " << j->url().url() << " expires " << ctime(&expireDate) << endl;
01104 #endif
01105 r->object->setExpireDate(expireDate, false);
01106 }
01107
01108 r->object->finish();
01109
01110 #ifdef CACHE_DEBUG
01111 kdDebug( 6060 ) << "Loader:: JOB FINISHED " << r->object << ": " << r->object->url().string() << endl;
01112 #endif
01113
01114 delete r;
01115 QTimer::singleShot( 0, this, SLOT( servePendingRequests() ) );
01116 }
01117
01118 void Loader::slotData( KIO::Job*job, const QByteArray &data )
01119 {
01120 Request *r = m_requestsLoading[job];
01121 if(!r) {
01122 kdDebug( 6060 ) << "got data for unknown request!" << endl;
01123 return;
01124 }
01125
01126 if ( !r->m_buffer.isOpen() )
01127 r->m_buffer.open( IO_WriteOnly );
01128
01129 r->m_buffer.writeBlock( data.data(), data.size() );
01130
01131 if(r->incremental)
01132 r->object->data( r->m_buffer, false );
01133 }
01134
01135 int Loader::numRequests( DocLoader* dl ) const
01136 {
01137 int res = 0;
01138
01139 QPtrListIterator<Request> pIt( m_requestsPending );
01140 for (; pIt.current(); ++pIt )
01141 if ( pIt.current()->m_docLoader == dl )
01142 res++;
01143
01144 QPtrDictIterator<Request> lIt( m_requestsLoading );
01145 for (; lIt.current(); ++lIt )
01146 if ( lIt.current()->m_docLoader == dl )
01147 res++;
01148
01149 return res;
01150 }
01151
01152 void Loader::cancelRequests( DocLoader* dl )
01153 {
01154
01155
01156 QPtrListIterator<Request> pIt( m_requestsPending );
01157 while ( pIt.current() )
01158 {
01159 if ( pIt.current()->m_docLoader == dl )
01160 {
01161 #ifdef CACHE_DEBUG
01162 kdDebug( 6060 ) << "cancelling pending request for " << pIt.current()->object->url().string() << endl;
01163 #endif
01164
01165 Cache::removeCacheEntry( pIt.current()->object );
01166 m_requestsPending.remove( pIt );
01167 }
01168 else
01169 ++pIt;
01170 }
01171
01172
01173
01174 QPtrDictIterator<Request> lIt( m_requestsLoading );
01175 while ( lIt.current() )
01176 {
01177 if ( lIt.current()->m_docLoader == dl )
01178 {
01179
01180 KIO::Job *job = static_cast<KIO::Job *>( lIt.currentKey() );
01181 Cache::removeCacheEntry( lIt.current()->object );
01182 m_requestsLoading.remove( lIt.currentKey() );
01183 job->kill();
01184
01185 }
01186 else
01187 ++lIt;
01188 }
01189 }
01190
01191 KIO::Job *Loader::jobForRequest( const DOM::DOMString &url ) const
01192 {
01193 QPtrDictIterator<Request> it( m_requestsLoading );
01194
01195 for (; it.current(); ++it )
01196 {
01197 CachedObject *obj = it.current()->object;
01198
01199 if ( obj && obj->url() == url )
01200 return static_cast<KIO::Job *>( it.currentKey() );
01201 }
01202
01203 return 0;
01204 }
01205
01206
01207
01208
01209 QDict<CachedObject> *Cache::cache = 0;
01210 QPtrList<DocLoader>* Cache::docloader = 0;
01211 Cache::LRUList *Cache::lru = 0;
01212 Loader *Cache::m_loader = 0;
01213
01214 int Cache::maxSize = DEFCACHESIZE;
01215 int Cache::flushCount = 0;
01216 int Cache::cacheSize = 0;
01217
01218 QPixmap *Cache::nullPixmap = 0;
01219 QPixmap *Cache::brokenPixmap = 0;
01220
01221 void Cache::init()
01222 {
01223 if ( !cache )
01224 cache = new QDict<CachedObject>(401, true);
01225
01226 if ( !lru )
01227 lru = new LRUList;
01228
01229 if ( !docloader )
01230 docloader = new QPtrList<DocLoader>;
01231
01232 if ( !nullPixmap )
01233 nullPixmap = new QPixmap;
01234
01235 if ( !brokenPixmap )
01236
01237 brokenPixmap = new QPixmap(KHTMLFactory::instance()->iconLoader()->loadIcon("file_broken", KIcon::Desktop, 16, KIcon::DisabledState));
01238
01239 if ( !m_loader )
01240 m_loader = new Loader();
01241 }
01242
01243 void Cache::clear()
01244 {
01245 if ( !cache ) return;
01246 #ifdef CACHE_DEBUG
01247 kdDebug( 6060 ) << "Cache: CLEAR!" << endl;
01248 statistics();
01249 #endif
01250 cache->setAutoDelete( true );
01251
01252 #if 0
01253 for (QDictIterator<CachedObject> it(*cache); it.current(); ++it)
01254 assert(it.current()->canDelete());
01255 #endif
01256
01257 delete cache; cache = 0;
01258 delete lru; lru = 0;
01259 delete nullPixmap; nullPixmap = 0;
01260 delete brokenPixmap; brokenPixmap = 0;
01261 delete m_loader; m_loader = 0;
01262 delete docloader; docloader = 0;
01263 }
01264
01265 CachedImage *Cache::requestImage( DocLoader* dl, const DOMString & url, bool reload, time_t _expireDate )
01266 {
01267
01268 KURL kurl;
01269 KIO::CacheControl cachePolicy;
01270 if ( dl )
01271 {
01272 kurl = dl->m_doc->completeURL( url.string() );
01273 cachePolicy = dl->cachePolicy();
01274 }
01275 else
01276 {
01277 kurl = url.string();
01278 cachePolicy = KIO::CC_Verify;
01279 }
01280
01281 if( kurl.isMalformed() )
01282 {
01283 #ifdef CACHE_DEBUG
01284 kdDebug( 6060 ) << "Cache: Malformed url: " << kurl.url() << endl;
01285 #endif
01286 return 0;
01287 }
01288
01289 CachedObject *o = 0;
01290 if (!reload)
01291 o = cache->find(kurl.url());
01292 if(!o)
01293 {
01294 #ifdef CACHE_DEBUG
01295 kdDebug( 6060 ) << "Cache: new: " << kurl.url() << endl;
01296 #endif
01297 CachedImage *im = new CachedImage(dl, kurl.url(), cachePolicy, _expireDate);
01298 cache->insert( kurl.url(), im );
01299 lru->prepend( kurl.url() );
01300 o = im;
01301 }
01302
01303 if (o->status() == CachedObject::Unknown && dl && dl->autoloadImages())
01304 Cache::loader()->load(dl, o, true);
01305
01306 o->setExpireDate(_expireDate, true);
01307
01308 if(!(o->type() == CachedObject::Image))
01309 {
01310 #ifdef CACHE_DEBUG
01311 kdDebug( 6060 ) << "Cache::Internal Error in requestImage url=" << kurl.url() << "!" << endl;
01312 #endif
01313 return 0;
01314 }
01315
01316 #ifdef CACHE_DEBUG
01317 if( o->status() == CachedObject::Pending )
01318 kdDebug( 6060 ) << "Cache: loading in progress: " << kurl.url() << endl;
01319 else
01320 kdDebug( 6060 ) << "Cache: using cached: " << kurl.url() << ", status " << o->status() << endl;
01321 #endif
01322
01323 lru->touch( kurl.url() );
01324 if ( dl ) {
01325 dl->m_docObjects.remove( o );
01326 dl->m_docObjects.append( o );
01327 }
01328 return static_cast<CachedImage *>(o);
01329 }
01330
01331 CachedCSSStyleSheet *Cache::requestStyleSheet( DocLoader* dl, const DOMString & url, bool , time_t _expireDate, const QString& charset)
01332 {
01333
01334 KURL kurl;
01335 KIO::CacheControl cachePolicy;
01336 if ( dl )
01337 {
01338 kurl = dl->m_doc->completeURL( url.string() );
01339 cachePolicy = dl->cachePolicy();
01340 }
01341 else
01342 {
01343 kurl = url.string();
01344 cachePolicy = KIO::CC_Verify;
01345 }
01346
01347 if( kurl.isMalformed() )
01348 {
01349 kdDebug( 6060 ) << "Cache: Malformed url: " << kurl.url() << endl;
01350 return 0;
01351 }
01352
01353 CachedObject *o = cache->find(kurl.url());
01354 if(!o)
01355 {
01356 #ifdef CACHE_DEBUG
01357 kdDebug( 6060 ) << "Cache: new: " << kurl.url() << endl;
01358 #endif
01359 CachedCSSStyleSheet *sheet = new CachedCSSStyleSheet(dl, kurl.url(), cachePolicy, _expireDate, charset);
01360 cache->insert( kurl.url(), sheet );
01361 lru->prepend( kurl.url() );
01362 o = sheet;
01363 }
01364
01365 o->setExpireDate(_expireDate, true);
01366
01367 if(!(o->type() == CachedObject::CSSStyleSheet))
01368 {
01369 #ifdef CACHE_DEBUG
01370 kdDebug( 6060 ) << "Cache::Internal Error in requestStyleSheet url=" << kurl.url() << "!" << endl;
01371 #endif
01372 return 0;
01373 }
01374
01375 #ifdef CACHE_DEBUG
01376 if( o->status() == CachedObject::Pending )
01377 kdDebug( 6060 ) << "Cache: loading in progress: " << kurl.url() << endl;
01378 else
01379 kdDebug( 6060 ) << "Cache: using cached: " << kurl.url() << endl;
01380 #endif
01381
01382 lru->touch( kurl.url() );
01383 if ( dl ) {
01384 dl->m_docObjects.remove( o );
01385 dl->m_docObjects.append( o );
01386 }
01387 return static_cast<CachedCSSStyleSheet *>(o);
01388 }
01389
01390 void Cache::preloadStyleSheet( const QString &url, const QString &stylesheet_data)
01391 {
01392 CachedObject *o = cache->find(url);
01393 if(o)
01394 removeCacheEntry(o);
01395
01396 CachedCSSStyleSheet *stylesheet = new CachedCSSStyleSheet(url, stylesheet_data);
01397 cache->insert( url, stylesheet );
01398 }
01399
01400 CachedScript *Cache::requestScript( DocLoader* dl, const DOM::DOMString &url, bool , time_t _expireDate, const QString& charset)
01401 {
01402
01403 KURL kurl;
01404 KIO::CacheControl cachePolicy;
01405 if ( dl )
01406 {
01407 kurl = dl->m_doc->completeURL( url.string() );
01408 cachePolicy = dl->cachePolicy();
01409 }
01410 else
01411 {
01412 kurl = url.string();
01413 cachePolicy = KIO::CC_Verify;
01414 }
01415
01416 if( kurl.isMalformed() )
01417 {
01418 kdDebug( 6060 ) << "Cache: Malformed url: " << kurl.url() << endl;
01419 return 0;
01420 }
01421
01422 CachedObject *o = cache->find(kurl.url());
01423 if(!o)
01424 {
01425 #ifdef CACHE_DEBUG
01426 kdDebug( 6060 ) << "Cache: new: " << kurl.url() << endl;
01427 #endif
01428 CachedScript *script = new CachedScript(dl, kurl.url(), cachePolicy, _expireDate, charset);
01429 cache->insert( kurl.url(), script );
01430 lru->prepend( kurl.url() );
01431 o = script;
01432 }
01433
01434 o->setExpireDate(_expireDate, true);
01435
01436 if(!(o->type() == CachedObject::Script))
01437 {
01438 #ifdef CACHE_DEBUG
01439 kdDebug( 6060 ) << "Cache::Internal Error in requestScript url=" << kurl.url() << "!" << endl;
01440 #endif
01441 return 0;
01442 }
01443
01444 #ifdef CACHE_DEBUG
01445 if( o->status() == CachedObject::Pending )
01446 kdDebug( 6060 ) << "Cache: loading in progress: " << kurl.url() << endl;
01447 else
01448 kdDebug( 6060 ) << "Cache: using cached: " << kurl.url() << endl;
01449 #endif
01450
01451 lru->touch( kurl.url() );
01452 if ( dl ) {
01453 dl->m_docObjects.remove( o );
01454 dl->m_docObjects.append( o );
01455 }
01456 return static_cast<CachedScript *>(o);
01457 }
01458
01459 void Cache::preloadScript( const QString &url, const QString &script_data)
01460 {
01461 CachedObject *o = cache->find(url);
01462 if(o)
01463 removeCacheEntry(o);
01464
01465 CachedScript *script = new CachedScript(url, script_data);
01466 cache->insert( url, script );
01467 }
01468
01469 void Cache::flush(bool force)
01470 {
01471 if (force)
01472 flushCount = 0;
01473
01474 if (!lru || (lru->count() < (uint) flushCount))
01475 return;
01476
01477 init();
01478
01479 #ifdef CACHE_DEBUG
01480 statistics();
01481 kdDebug( 6060 ) << "Cache: flush()" << endl;
01482 #endif
01483
01484 int _cacheSize = 0;
01485
01486 for ( QStringList::Iterator it = lru->fromLast(); it != lru->end(); )
01487 {
01488 QString url = *it;
01489 --it;
01490 CachedObject *o = cache->find( url );
01491
01492 if( !o->canDelete() || o->status() == CachedObject::Persistent ) {
01493 continue;
01494
01495 }
01496
01497 if( o->status() != CachedObject::Uncacheable )
01498 {
01499 _cacheSize += o->size();
01500
01501 if( _cacheSize < maxSize )
01502 continue;
01503 }
01504 removeCacheEntry( o );
01505 }
01506 Cache::cacheSize = _cacheSize;
01507
01508 flushCount = lru->count()+10;
01509 #ifdef CACHE_DEBUG
01510
01511 #endif
01512 }
01513
01514 void Cache::setSize( int bytes )
01515 {
01516 maxSize = bytes;
01517
01518 flushCount = 0;
01519 flush(true);
01520 }
01521
01522 void Cache::statistics()
01523 {
01524 CachedObject *o;
01525
01526 init();
01527
01528 int size = 0;
01529 int msize = 0;
01530 int movie = 0;
01531 int images = 0;
01532 int scripts = 0;
01533 int stylesheets = 0;
01534 QDictIterator<CachedObject> it(*cache);
01535 for(it.toFirst(); it.current(); ++it)
01536 {
01537 o = it.current();
01538 switch(o->type()) {
01539 case CachedObject::Image:
01540 {
01541 CachedImage *im = static_cast<CachedImage *>(o);
01542 images++;
01543 if(im->m != 0)
01544 {
01545 qDebug("found image with movie: %p", im);
01546
01547 movie++;
01548 msize += im->size();
01549 }
01550 break;
01551 }
01552 case CachedObject::CSSStyleSheet:
01553 stylesheets++;
01554 break;
01555 case CachedObject::Script:
01556 scripts++;
01557 break;
01558 }
01559 size += o->size();
01560 }
01561 size /= 1024;
01562
01563 kdDebug( 6060 ) << "------------------------- image cache statistics -------------------" << endl;
01564 kdDebug( 6060 ) << "Number of items in cache: " << cache->count() << endl;
01565 kdDebug( 6060 ) << "Number of items in lru : " << lru->count() << endl;
01566 kdDebug( 6060 ) << "Number of cached images: " << images << endl;
01567 kdDebug( 6060 ) << "Number of cached movies: " << movie << endl;
01568 kdDebug( 6060 ) << "Number of cached scripts: " << scripts << endl;
01569 kdDebug( 6060 ) << "Number of cached stylesheets: " << stylesheets << endl;
01570 kdDebug( 6060 ) << "pixmaps: allocated space approx. " << size << " kB" << endl;
01571 kdDebug( 6060 ) << "movies : allocated space approx. " << msize/1024 << " kB" << endl;
01572 kdDebug( 6060 ) << "--------------------------------------------------------------------" << endl;
01573 }
01574
01575 void Cache::removeCacheEntry( CachedObject *object )
01576 {
01577 QString key = object->url().string();
01578
01579
01580
01581 object->setFree( true );
01582
01583 cache->remove( key );
01584 lru->remove( key );
01585
01586 const DocLoader* dl;
01587 for ( dl=docloader->first(); dl; dl=docloader->next() )
01588 dl->removeCachedObject( object );
01589
01590 if ( object->canDelete() )
01591 delete object;
01592 }
01593
01594
01595
01596
01597 void CachedObjectClient::setPixmap(const QPixmap &, const QRect&, CachedImage *) {}
01598 void CachedObjectClient::setStyleSheet(const DOM::DOMString &, const DOM::DOMString &) {}
01599 void CachedObjectClient::notifyFinished(CachedObject * ) {}
01600
01601
01602 #include "loader.moc"