From ce4a32fe52ef09d8f5ff1dd22c001110902b60a2 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: 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 --- khtml/khtml_pagecache.cpp | 313 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 khtml/khtml_pagecache.cpp (limited to 'khtml/khtml_pagecache.cpp') 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 + * + * 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 +#include +#include + +#include +#include + +#include +#include +#include + +// We keep 12 pages in memory. +#ifndef KHTML_PAGE_CACHE_SIZE +#define KHTML_PAGE_CACHE_SIZE 12 +#endif + +template class QPtrList; +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 m_data; + KTempFile *m_file; +}; + +class KHTMLPageCachePrivate +{ +public: + long newId; + QIntDict dict; + QPtrList delivery; + QPtrList 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 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" -- cgit v1.2.1