blob: 5f0565b4aa2b8c3a9578bac6fcbeae62cf947c34 [file] [log] [blame]
/*
Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org>
2004, 2005 Rob Buis <buis@kde.org>
Based on khtml code by:
Copyright (C) 1998 Lars Knoll <knoll@kde.org>
Copyright (C) 2001-2003 Dirk Mueller <mueller@kde.org>
Copyright (C) 2002 Waldo Bastian <bastian@kde.org>
Copyright (C) 2003 Apple Computer, Inc.
This file is part of the KDE project
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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
// regarding the LRU:
// http://www.is.kyusan-u.ac.jp/~chengk/pub/papers/compsac00_A07-07.pdf
*/
#include "config.h"
#include <kdebug.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <qpixmap.h>
#include "KDOMCache.h"
#include "KDOMLoader.h"
#include "KDOMCachedImage.h"
#include "KDOMCacheHelper.h"
using namespace KDOM;
#define KDOM_CACHE_DICT_SIZE 401
#define KDOM_CACHE_DEFAULT_SIZE 2146304 // 2096 * 1024
Loader *Cache::s_loader = 0;
Q3Dict<CachedObject> *Cache::s_objectDict = 0;
Q3PtrList<CachedObject> *Cache::s_freeList = 0;
Q3PtrList<DocumentLoader> *Cache::s_docLoaderList = 0;
QPixmap *Cache::nullPixmap;
QPixmap *Cache::brokenPixmap;
QPixmap *Cache::blockedPixmap;
int Cache::s_maxSize = KDOM_CACHE_DEFAULT_SIZE;
int Cache::s_totalSizeOfLRU = 0;
void Cache::init()
{
if(!s_loader)
s_loader = new Loader();
if(!s_objectDict)
s_objectDict = new Q3Dict<CachedObject>(KDOM_CACHE_DICT_SIZE, true);
if(!s_docLoaderList)
s_docLoaderList = new Q3PtrList<DocumentLoader>;
if(!s_freeList)
{
s_freeList = new Q3PtrList<CachedObject>;
s_freeList->setAutoDelete(true);
}
if(!nullPixmap)
nullPixmap = new QPixmap();
if(!brokenPixmap)
#ifdef APPLE_CHANGES
brokenPixmap = KWQLoadPixmap("missing_image");
#else
brokenPixmap = new QPixmap(KGlobal::iconLoader()->loadIcon(QString::fromLatin1("file_broken"),
KIcon::Desktop, 16, KIcon::DisabledState));
#endif
}
void Cache::clear()
{
if(!s_objectDict)
return;
#ifdef CACHE_DEBUG
kdDebug() << "[KDOM::Cache] clear()" << endl;
statistics();
#endif
s_objectDict->setAutoDelete(true);
delete s_loader; s_loader = 0;
delete s_freeList; s_freeList = 0;
delete s_objectDict; s_objectDict = 0;
delete s_docLoaderList; s_docLoaderList = 0;
delete nullPixmap; nullPixmap = 0;
delete brokenPixmap; brokenPixmap = 0;
delete blockedPixmap; blockedPixmap = 0;
}
void Cache::flush(bool force)
{
init();
if(force || s_totalSizeOfLRU > (s_maxSize + s_maxSize / 4))
{
for(int i = KDOM_CACHE_MAX_LRU_LISTS - 1; i >= 0 && s_totalSizeOfLRU > s_maxSize; --i)
{
while(s_totalSizeOfLRU > s_maxSize && s_lruLists[i].tail)
removeCacheEntry(s_lruLists[i].tail);
}
#ifdef CACHE_DEBUG
statistics();
#endif
}
for(CachedObject *p = s_freeList->first(); p != 0; p = s_freeList->next())
{
if(p->canDelete())
s_freeList->remove();
}
}
void Cache::setSize(int bytes)
{
s_maxSize = bytes;
flush(true /* force */);
}
bool Cache::hasPending(CachedObject::Type type)
{
Q3DictIterator<CachedObject> it(*s_objectDict);
for(it.toFirst(); it.current(); ++it)
{
if(it.current()->type() == type &&
it.current()->status() != CachedObject::Cached)
return true;
}
return false;
}
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;
int documents = 0;
Q3DictIterator<CachedObject> it(*s_objectDict);
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_movie != 0)
{
movie++;
msize += im->size();
}
break;
}
case CachedObject::StyleSheet:
{
stylesheets++;
break;
}
case CachedObject::Script:
{
scripts++;
break;
}
case CachedObject::TextDocument:
{
documents++;
break;
}
}
size += o->size();
}
size /= 1024;
kdDebug() << "------------------------- image cache statistics -------------------" << endl;
kdDebug() << "Number of items in cache: " << s_objectDict->count() << endl;
kdDebug() << "Number of cached images: " << images << endl;
kdDebug() << "Number of cached movies: " << movie << endl;
kdDebug() << "Number of cached scripts: " << scripts << endl;
kdDebug() << "Number of cached stylesheets: " << stylesheets << endl;
kdDebug() << "pixmaps: allocated space approx. " << size << " kB" << endl;
kdDebug() << "movies : allocated space approx. " << msize/1024 << " kB" << endl;
kdDebug() << "Number of cached XML documents: " << documents << endl;
kdDebug() << "--------------------------------------------------------------------" << endl;
}
void Cache::removeCacheEntry(CachedObject *object)
{
QString key = object->url().string();
s_objectDict->remove(key);
removeFromLRUList(object);
for(const DocumentLoader *docLoader = s_docLoaderList->first(); docLoader != 0; docLoader = s_docLoaderList->next())
docLoader->removeCachedObject(object);
if(!object->free())
{
s_freeList->append(object);
object->m_free = true;
}
}
void Cache::removeFromLRUList(CachedObject *object)
{
CachedObject *next = object->m_next;
CachedObject *prev = object->m_prev;
LRUList *list = lruListFor(object);
CachedObject *&head = lruListFor(object)->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->tail == object)
list->tail = prev;
if(prev)
prev->m_next = next;
else if(head == object)
head = next;
s_totalSizeOfLRU -= object->size();
}
void Cache::insertInLRUList(CachedObject *object)
{
removeFromLRUList(object);
Q_ASSERT(object != 0);
Q_ASSERT(!object->free());
Q_ASSERT(object->canDelete());
Q_ASSERT(object->allowInLRUList());
LRUList *list = lruListFor(object);
CachedObject *&head = list->head;
object->m_next = head;
if(head)
head->m_prev = object;
head = object;
if(object->m_next == 0)
list->tail = object;
s_totalSizeOfLRU += object->size();
}
// vim:ts=4:noet