1 /* This file is part of the KDE project
3 * Copyright (C) 2000 Waldo Bastian <bastian@kde.org>
4 * Copyright (C) 2007 Nick Shaforostoff <shafff@ukr.net>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
22 #include "khtml_pagecache.h"
24 #include <kfilterdev.h>
25 #include <QTemporaryFile>
26 #include <kstandarddirs.h>
31 #include <QtCore/QTimer>
32 #include <QtCore/QFile>
34 #include <sys/types.h>
38 // We keep 12 pages in memory.
39 #ifndef KHTML_PAGE_CACHE_SIZE
40 #define KHTML_PAGE_CACHE_SIZE 12
43 template class QList
<KHTMLPageCacheDelivery
*>;
44 class KHTMLPageCacheEntry
46 friend class KHTMLPageCache
;
48 KHTMLPageCacheEntry(long id
);
50 ~KHTMLPageCacheEntry();
52 void addData(const QByteArray
&data
);
55 bool isComplete() const {return m_complete
;}
56 QString
fileName() const {return m_fileName
;}
58 KHTMLPageCacheDelivery
*fetchData(QObject
*recvObj
, const char *recvSlot
);
67 class KHTMLPageCachePrivate
72 QHash
<int, KHTMLPageCacheEntry
*> dict
;
73 QList
<KHTMLPageCacheDelivery
*> delivery
;
74 QQueue
<long> expireQueue
;
77 KHTMLPageCacheEntry::KHTMLPageCacheEntry(long id
)
82 QTemporaryFile
* f
=new QTemporaryFile(KStandardDirs::locateLocal("tmp", "")+"khtmlcacheXXXXXX.tmp");
84 m_fileName
=f
->fileName();
85 f
->setAutoRemove(false);
88 m_file
= KFilterDev::deviceForFile(m_fileName
, "application/x-gzip"/*,false*/);
89 m_file
->open(QIODevice::WriteOnly
);
92 KHTMLPageCacheEntry::~KHTMLPageCacheEntry()
95 QFile::remove(m_fileName
);
100 KHTMLPageCacheEntry::addData(const QByteArray
&data
)
106 KHTMLPageCacheEntry::endData()
109 m_file
->write(m_buffer
);
115 KHTMLPageCacheDelivery
*
116 KHTMLPageCacheEntry::fetchData(QObject
*recvObj
, const char *recvSlot
)
118 // Duplicate fd so that entry can be safely deleted while delivering the data.
119 KHTMLPageCacheDelivery
*delivery
=new KHTMLPageCacheDelivery(
120 KFilterDev::deviceForFile (m_fileName
, "application/x-gzip")
122 delivery
->file
->open(QIODevice::ReadOnly
);
124 recvObj
->connect(delivery
, SIGNAL(emitData(const QByteArray
&)), recvSlot
);
125 delivery
->recvObj
= recvObj
;
130 KHTMLPageCache::self()
132 K_GLOBAL_STATIC(KHTMLPageCache
, _self
)
136 KHTMLPageCache::KHTMLPageCache()
137 :d( new KHTMLPageCachePrivate
)
140 d
->deliveryActive
= false;
143 KHTMLPageCache::~KHTMLPageCache()
146 qDeleteAll(d
->delivery
);
151 KHTMLPageCache::createCacheEntry()
154 KHTMLPageCacheEntry
*entry
= new KHTMLPageCacheEntry(d
->newId
);
155 d
->dict
.insert(d
->newId
, entry
);
156 d
->expireQueue
.append(d
->newId
);
157 if (d
->expireQueue
.count() > KHTML_PAGE_CACHE_SIZE
)
158 delete d
->dict
.take(d
->expireQueue
.dequeue());
163 KHTMLPageCache::addData(long id
, const QByteArray
&data
)
166 KHTMLPageCacheEntry
*entry
= d
->dict
.value( id
);
168 entry
->addData(data
);
172 KHTMLPageCache::endData(long id
)
174 KHTMLPageCacheEntry
*entry
= d
->dict
.value( id
);
180 KHTMLPageCache::cancelEntry(long id
)
182 KHTMLPageCacheEntry
*entry
= d
->dict
.take( id
);
185 d
->expireQueue
.removeAll(entry
->m_id
);
191 KHTMLPageCache::isValid(long id
)
193 return d
->dict
.contains(id
);
197 KHTMLPageCache::isComplete(long id
)
199 KHTMLPageCacheEntry
*entry
= d
->dict
.value( id
);
201 return entry
->isComplete();
206 KHTMLPageCache::fetchData(long id
, QObject
*recvObj
, const char *recvSlot
)
208 KHTMLPageCacheEntry
*entry
= d
->dict
.value( id
);
209 if (!entry
|| !entry
->isComplete()) return;
211 // Make this entry the most recent entry.
212 d
->expireQueue
.removeAll(entry
->m_id
);
213 d
->expireQueue
.enqueue(entry
->m_id
);
215 d
->delivery
.append( entry
->fetchData(recvObj
, recvSlot
) );
216 if (!d
->deliveryActive
)
218 d
->deliveryActive
= true;
219 QTimer::singleShot(20, this, SLOT(sendData()));
224 KHTMLPageCache::cancelFetch(QObject
*recvObj
)
226 QMutableListIterator
<KHTMLPageCacheDelivery
*> it( d
->delivery
);
227 while (it
.hasNext()) {
228 KHTMLPageCacheDelivery
* delivery
= it
.next();
229 if (delivery
->recvObj
== recvObj
)
238 KHTMLPageCache::sendData()
240 if (d
->delivery
.isEmpty())
242 d
->deliveryActive
= false;
246 KHTMLPageCacheDelivery
*delivery
= d
->delivery
.takeFirst();
249 QByteArray
byteArray(delivery
->file
->read(64*1024));
250 delivery
->emitData(byteArray
);
253 if (delivery
->file
->atEnd())
256 delivery
->file
->close();
257 delivery
->emitData(QByteArray()); // Empty array
261 d
->delivery
.append( delivery
);
263 QTimer::singleShot(0, this, SLOT(sendData()));
267 KHTMLPageCache::saveData(long id
, QDataStream
*str
)
269 assert(d
->dict
.contains( id
));
270 KHTMLPageCacheEntry
*entry
= d
->dict
.value( id
);
272 if (!entry
->isComplete())
274 QTimer::singleShot(20, this, SLOT(saveData()));
278 QIODevice
* file
= KFilterDev::deviceForFile (entry
->fileName(), "application/x-gzip");
279 if (!file
->open(QIODevice::ReadOnly
))
282 QByteArray
byteArray(file
->readAll());
285 str
->writeRawData(byteArray
.constData(), byteArray
.length());
289 KHTMLPageCacheDelivery::~KHTMLPageCacheDelivery()
295 #include "khtml_pagecache.moc"