summaryrefslogtreecommitdiffstats
path: root/khtml/khtml_pagecache.cpp
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch)
tree5ac38a06f3dde268dc7927dc155896926aaf7012 /khtml/khtml_pagecache.cpp
downloadtdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz
tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'khtml/khtml_pagecache.cpp')
-rw-r--r--khtml/khtml_pagecache.cpp313
1 files changed, 313 insertions, 0 deletions
diff --git a/khtml/khtml_pagecache.cpp b/khtml/khtml_pagecache.cpp
new file mode 100644
index 000000000..88c523a2b
--- /dev/null
+++ b/khtml/khtml_pagecache.cpp
@@ -0,0 +1,313 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2000 Waldo Bastian <bastian@kde.org>
+ *
+ * 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.
+ */
+
+#include "khtml_pagecache.h"
+
+#include <kstaticdeleter.h>
+#include <ktempfile.h>
+#include <kstandarddirs.h>
+
+#include <qintdict.h>
+#include <qtimer.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <assert.h>
+
+// We keep 12 pages in memory.
+#ifndef KHTML_PAGE_CACHE_SIZE
+#define KHTML_PAGE_CACHE_SIZE 12
+#endif
+
+template class QPtrList<KHTMLPageCacheDelivery>;
+class KHTMLPageCacheEntry
+{
+ friend class KHTMLPageCache;
+public:
+ KHTMLPageCacheEntry(long id);
+
+ ~KHTMLPageCacheEntry();
+
+ void addData(const QByteArray &data);
+
+ void endData();
+
+ bool isComplete()
+ { return m_complete; }
+
+ KHTMLPageCacheDelivery *fetchData(QObject *recvObj, const char *recvSlot);
+private:
+ long m_id;
+ bool m_complete;
+ QValueList<QByteArray> m_data;
+ KTempFile *m_file;
+};
+
+class KHTMLPageCachePrivate
+{
+public:
+ long newId;
+ QIntDict<KHTMLPageCacheEntry> dict;
+ QPtrList<KHTMLPageCacheDelivery> delivery;
+ QPtrList<KHTMLPageCacheEntry> expireQueue;
+ bool deliveryActive;
+};
+
+KHTMLPageCacheEntry::KHTMLPageCacheEntry(long id) : m_id(id), m_complete(false)
+{
+ QString path = locateLocal("tmp", "khtmlcache");
+ m_file = new KTempFile(path);
+ m_file->unlink();
+}
+
+KHTMLPageCacheEntry::~KHTMLPageCacheEntry()
+{
+ delete m_file;
+}
+
+
+void
+KHTMLPageCacheEntry::addData(const QByteArray &data)
+{
+ if (m_file->status() == 0)
+ m_file->dataStream()->writeRawBytes(data.data(), data.size());
+}
+
+void
+KHTMLPageCacheEntry::endData()
+{
+ m_complete = true;
+ if ( m_file->status() == 0) {
+ m_file->dataStream()->device()->flush();
+ m_file->dataStream()->device()->at(0);
+ }
+}
+
+
+KHTMLPageCacheDelivery *
+KHTMLPageCacheEntry::fetchData(QObject *recvObj, const char *recvSlot)
+{
+ // Duplicate fd so that entry can be safely deleted while delivering the data.
+ int fd = dup(m_file->handle());
+ lseek(fd, 0, SEEK_SET);
+ KHTMLPageCacheDelivery *delivery = new KHTMLPageCacheDelivery(fd);
+ recvObj->connect(delivery, SIGNAL(emitData(const QByteArray&)), recvSlot);
+ delivery->recvObj = recvObj;
+ return delivery;
+}
+
+static KStaticDeleter<KHTMLPageCache> pageCacheDeleter;
+
+KHTMLPageCache *KHTMLPageCache::_self = 0;
+
+KHTMLPageCache *
+KHTMLPageCache::self()
+{
+ if (!_self)
+ _self = pageCacheDeleter.setObject(_self, new KHTMLPageCache);
+ return _self;
+}
+
+KHTMLPageCache::KHTMLPageCache()
+{
+ d = new KHTMLPageCachePrivate;
+ d->newId = 1;
+ d->deliveryActive = false;
+}
+
+KHTMLPageCache::~KHTMLPageCache()
+{
+ d->delivery.setAutoDelete(true);
+ d->dict.setAutoDelete(true);
+ delete d;
+}
+
+long
+KHTMLPageCache::createCacheEntry()
+{
+ KHTMLPageCacheEntry *entry = new KHTMLPageCacheEntry(d->newId);
+ d->dict.insert(d->newId, entry);
+ d->expireQueue.append(entry);
+ if (d->expireQueue.count() > KHTML_PAGE_CACHE_SIZE)
+ {
+ KHTMLPageCacheEntry *entry = d->expireQueue.take(0);
+ d->dict.remove(entry->m_id);
+ delete entry;
+ }
+ return (d->newId++);
+}
+
+void
+KHTMLPageCache::addData(long id, const QByteArray &data)
+{
+ KHTMLPageCacheEntry *entry = d->dict.find(id);
+ if (entry)
+ entry->addData(data);
+}
+
+void
+KHTMLPageCache::endData(long id)
+{
+ KHTMLPageCacheEntry *entry = d->dict.find(id);
+ if (entry)
+ entry->endData();
+}
+
+void
+KHTMLPageCache::cancelEntry(long id)
+{
+ KHTMLPageCacheEntry *entry = d->dict.take(id);
+ if (entry)
+ {
+ d->expireQueue.removeRef(entry);
+ delete entry;
+ }
+}
+
+bool
+KHTMLPageCache::isValid(long id)
+{
+ return (d->dict.find(id) != 0);
+}
+
+bool
+KHTMLPageCache::isComplete(long id)
+{
+ KHTMLPageCacheEntry *entry = d->dict.find(id);
+ if (entry)
+ return entry->isComplete();
+ return false;
+}
+
+void
+KHTMLPageCache::fetchData(long id, QObject *recvObj, const char *recvSlot)
+{
+ KHTMLPageCacheEntry *entry = d->dict.find(id);
+ if (!entry || !entry->isComplete()) return;
+
+ // Make this entry the most recent entry.
+ d->expireQueue.removeRef(entry);
+ d->expireQueue.append(entry);
+
+ d->delivery.append( entry->fetchData(recvObj, recvSlot) );
+ if (!d->deliveryActive)
+ {
+ d->deliveryActive = true;
+ QTimer::singleShot(20, this, SLOT(sendData()));
+ }
+}
+
+void
+KHTMLPageCache::cancelFetch(QObject *recvObj)
+{
+ KHTMLPageCacheDelivery *next;
+ for(KHTMLPageCacheDelivery* delivery = d->delivery.first();
+ delivery;
+ delivery = next)
+ {
+ next = d->delivery.next();
+ if (delivery->recvObj == recvObj)
+ {
+ d->delivery.removeRef(delivery);
+ delete delivery;
+ }
+ }
+}
+
+void
+KHTMLPageCache::sendData()
+{
+ if (d->delivery.isEmpty())
+ {
+ d->deliveryActive = false;
+ return;
+ }
+ KHTMLPageCacheDelivery *delivery = d->delivery.take(0);
+ assert(delivery);
+
+ char buf[8192];
+ QByteArray byteArray;
+
+ int n = read(delivery->fd, buf, 8192);
+
+ if ((n < 0) && (errno == EINTR))
+ {
+ // try again later
+ d->delivery.append( delivery );
+ }
+ else if (n <= 0)
+ {
+ // done.
+ delivery->emitData(byteArray); // Empty array
+ delete delivery;
+ }
+ else
+ {
+ byteArray.setRawData(buf, n);
+ delivery->emitData(byteArray);
+ byteArray.resetRawData(buf, n);
+ d->delivery.append( delivery );
+ }
+ QTimer::singleShot(0, this, SLOT(sendData()));
+}
+
+void
+KHTMLPageCache::saveData(long id, QDataStream *str)
+{
+ KHTMLPageCacheEntry *entry = d->dict.find(id);
+ assert(entry);
+
+ int fd = entry->m_file->handle();
+ if ( fd < 0 ) return;
+
+ off_t pos = lseek(fd, 0, SEEK_CUR);
+ lseek(fd, 0, SEEK_SET);
+
+ char buf[8192];
+
+ while(true)
+ {
+ int n = read(fd, buf, 8192);
+ if ((n < 0) && (errno == EINTR))
+ {
+ // try again
+ continue;
+ }
+ else if (n <= 0)
+ {
+ // done.
+ break;
+ }
+ else
+ {
+ str->writeRawBytes(buf, n);
+ }
+ }
+
+ if (pos != (off_t)-1)
+ lseek(fd, pos, SEEK_SET);
+}
+
+KHTMLPageCacheDelivery::~KHTMLPageCacheDelivery()
+{
+ close(fd);
+}
+
+#include "khtml_pagecache.moc"