You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
338 lines
9.7 KiB
338 lines
9.7 KiB
//
|
|
// Class: documentPageCache
|
|
//
|
|
// Cache that holds a number of pages in a document.
|
|
// Part of KDVI- A previewer for TeX DVI files.
|
|
//
|
|
// (C) 2004 Stefan Kebekus. Distributed under the GPL.
|
|
|
|
#include <config.h>
|
|
|
|
#include <kdebug.h>
|
|
#include <tqapplication.h>
|
|
|
|
#include "documentPageCache.h"
|
|
#include "documentRenderer.h"
|
|
#include "kvsprefs.h"
|
|
#include "renderedDocumentPagePixmap.h"
|
|
|
|
|
|
//#define documentPageCache_DEBUG
|
|
|
|
|
|
DocumentPageCache::DocumentPageCache()
|
|
: maxMemory(2*16777216), LRUCache(maxMemory, 200)
|
|
{
|
|
LRUCache.setAutoDelete(true);
|
|
|
|
resolutionInDPI = 0.0;
|
|
Length w,h;
|
|
w.setLength_in_mm(200);
|
|
h.setLength_in_mm(300);
|
|
userPreferredSize.setPageSize(w,h);
|
|
useDocumentSpecifiedSize = true;
|
|
}
|
|
|
|
|
|
DocumentPageCache::~DocumentPageCache()
|
|
{
|
|
}
|
|
|
|
|
|
void DocumentPageCache::setRenderer(DocumentRenderer *_renderer)
|
|
{
|
|
clear();
|
|
renderer = _renderer;
|
|
}
|
|
|
|
|
|
SimplePageSize DocumentPageCache::sizeOfPage(const PageNumber& page) const
|
|
{
|
|
// Paranoid safety checks
|
|
if (!page.isValid()) {
|
|
kdError(1223) << "DocumentPageCache::sizeOfPage( " << page << ") called with invalid page number." << endl;
|
|
return SimplePageSize();
|
|
}
|
|
if (renderer.isNull()) {
|
|
kdError(1223) << "DocumentPageCache::sizeOfPage( " << page << ") called when no renderer was set." << endl;
|
|
return SimplePageSize();
|
|
}
|
|
|
|
SimplePageSize s = renderer->sizeOfPage(page);
|
|
if (!useDocumentSpecifiedSize)
|
|
s = userPreferredSize;
|
|
|
|
if (!s.isValid())
|
|
{
|
|
// If the size is invalid use the size of the first Page in the document
|
|
// as an estimate.
|
|
s = renderer->sizeOfPage(1);
|
|
if (!s.isValid())
|
|
s = userPreferredSize;
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
void DocumentPageCache::setResolution(double res)
|
|
{
|
|
resolutionInDPI = res;
|
|
}
|
|
|
|
TQSize DocumentPageCache::sizeOfPageInPixel(const PageNumber& pg) const
|
|
{
|
|
// Paranoid safety checks
|
|
if (renderer.isNull()) {
|
|
kdError(1223) << "DocumentPageCache::sizeOfPageInPixel( " << pg << " ) called but no renderer was set" << endl;
|
|
return TQSize();
|
|
}
|
|
if (!pg.isValid()) {
|
|
kdError(1223) << "DocumentPageCache::sizeOfPageInPixel( " << pg << " ) called with invalid argument" << endl;
|
|
return TQSize();
|
|
}
|
|
|
|
SimplePageSize ps = sizeOfPage(pg);
|
|
if (ps.isValid())
|
|
return ps.sizeInPixel(resolutionInDPI);
|
|
return userPreferredSize.sizeInPixel(resolutionInDPI);
|
|
}
|
|
|
|
|
|
bool DocumentPageCache::isPageCached(const PageNumber& pageNumber, const TQSize& size)
|
|
{
|
|
// Paranoid checks
|
|
if (renderer.isNull()) {
|
|
kdError(1223) << "DocumentPageCache::isPageCached(..) called but no renderer was set" << endl;
|
|
return false;
|
|
}
|
|
if (!pageNumber.isValid()) {
|
|
kdError(1223) << "DocumentPageCache::isPageCached( " << pageNumber << " ) called, with invalid argument." << endl;
|
|
return false;
|
|
}
|
|
if (renderer->totalPages() < pageNumber) {
|
|
kdError(1223) << "DocumentPageCache::isPageCached( " << pageNumber
|
|
<< " ) called but document contains only " << renderer->totalPages() << " pages." << endl;
|
|
return false;
|
|
}
|
|
|
|
TQString key = createKey(pageNumber, size);
|
|
|
|
// Check if the page that we are looking for is in the cache.
|
|
// We are not accessing the page, so we don't want it to be moved into the front.
|
|
RenderedDocumentPagePixmap* page = LRUCache.find(key, false);
|
|
|
|
if (page)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
TQString DocumentPageCache::createKey(const PageNumber& pageNumber, const TQSize& size)
|
|
{
|
|
TQString key;
|
|
|
|
key = TQString::number(pageNumber) + ":" +
|
|
TQString::number(size.width()) + ":" + TQString::number(size.height());
|
|
|
|
return key;
|
|
}
|
|
|
|
TQString DocumentPageCache::createKey(const PageNumber& pageNumber)
|
|
{
|
|
TQSize pageSize = sizeOfPageInPixel(pageNumber);
|
|
|
|
TQString key;
|
|
|
|
key = TQString::number(pageNumber) + ":" +
|
|
TQString::number(pageSize.width()) + ":" + TQString::number(pageSize.height());
|
|
|
|
return key;
|
|
}
|
|
|
|
bool DocumentPageCache::isPageCached(const PageNumber& pageNumber)
|
|
{
|
|
// Paranoid checks
|
|
if (renderer.isNull()) {
|
|
kdError(1223) << "DocumentPageCache::isPageCached(..) called but no renderer was set" << endl;
|
|
return false;
|
|
}
|
|
if (!pageNumber.isValid()) {
|
|
kdError(1223) << "DocumentPageCache::isPageCached( " << pageNumber << " ) called, with invalid argument." << endl;
|
|
return false;
|
|
}
|
|
if (renderer->totalPages() < pageNumber) {
|
|
kdError(1223) << "DocumentPageCache::isPageCached( " << pageNumber
|
|
<< " ) called but document contains only " << renderer->totalPages() << " pages." << endl;
|
|
return false;
|
|
}
|
|
|
|
return isPageCached(pageNumber, sizeOfPageInPixel(pageNumber));
|
|
}
|
|
|
|
RenderedDocumentPagePixmap* DocumentPageCache::getPage(const PageNumber& pageNr)
|
|
{
|
|
#ifdef DocumentPageCache_DEBUG
|
|
kdDebug(1223) << "DocumentPageCache::getPage( pageNr=" << pageNr << " )" << endl;
|
|
#endif
|
|
|
|
// Paranoid checks
|
|
if (renderer.isNull()) {
|
|
kdError(1223) << "DocumentPageCache::getPage(..) called but no renderer was set" << endl;
|
|
return 0;
|
|
}
|
|
if (!pageNr.isValid()) {
|
|
kdError(1223) << "DocumentPageCache::getPage( " << pageNr << " ) called, with invalid argument." << endl;
|
|
return 0;
|
|
}
|
|
if (renderer->totalPages() < pageNr) {
|
|
kdError(1223) << "DocumentPageCache::getPage( " << pageNr << " ) called but document contains only " << renderer->totalPages() << " pages." << endl;
|
|
return 0;
|
|
}
|
|
|
|
// First check if the page that we are looking for is in the cache
|
|
RenderedDocumentPagePixmap* page;
|
|
page = LRUCache.find(createKey(pageNr));
|
|
|
|
if (page)
|
|
return page;
|
|
|
|
// The page was not found in the cache, so we have to make a new
|
|
// page and add this to the cache.
|
|
page = createDocumentPagePixmap();
|
|
|
|
// If that failed, issue an error message and quit.
|
|
if (page == 0) {
|
|
kdError(1223) << "DocumentPageCache::getPage(..) cannot allocate DocumentPage structure" << endl;
|
|
return 0;
|
|
}
|
|
|
|
// Now 'page' contains a point to a page structure that we can
|
|
// use. Add the page to the cache, and apply the renderer to the page.
|
|
page->setPageNumber(pageNr);
|
|
if (!renderer.isNull())
|
|
{
|
|
if (resolutionInDPI > 0.0)
|
|
{
|
|
page->resize(sizeOfPageInPixel(pageNr));
|
|
TQApplication::setOverrideCursor( waitCursor );
|
|
renderer->drawPage(resolutionInDPI, page);
|
|
TQApplication::restoreOverrideCursor();
|
|
|
|
// We always set the cache capacity to be at least n times the cost of the page we want to insert.
|
|
// Where n is the number of pages that can be visible at the same time at very high zoomlevels.
|
|
// n depends on the layout mode.
|
|
// If these pages are not all in the cache, scrolling the view becomes very slow, because for each
|
|
// paint event the pages need to be rerendered.
|
|
// We set n for each viewmode differently so that the user is able to reduce memory consuption by
|
|
// switching to a simpler viewmode like Single Page.
|
|
int n = 4;
|
|
switch (KVSPrefs::viewMode())
|
|
{
|
|
case KVSPrefs::EnumViewMode::SinglePage:
|
|
n = 1;
|
|
break;
|
|
case KVSPrefs::EnumViewMode::Continuous:
|
|
n = 2;
|
|
break;
|
|
default:
|
|
n = 4;
|
|
}
|
|
LRUCache.setMaxCost(TQMAX(page->memory() * n, maxMemory));
|
|
|
|
if (!LRUCache.insert(createKey(pageNr), page, page->memory()))
|
|
{
|
|
kdError() << "DocumentPageCache::getPage(): inserting pagestructure into the cache failed.\n This should never happen. If you see this message, something is very wrong." << endl;
|
|
}
|
|
}
|
|
else
|
|
kdError(1223) << "DocumentPageCache::getPage() called, but no resolution or negative resolution was set" << endl;
|
|
}
|
|
|
|
return page;
|
|
}
|
|
|
|
|
|
RenderedDocumentPagePixmap* DocumentPageCache::createDocumentPagePixmap() const
|
|
{
|
|
return new RenderedDocumentPagePixmap();
|
|
}
|
|
|
|
|
|
void DocumentPageCache::clear()
|
|
{
|
|
LRUCache.clear();
|
|
}
|
|
|
|
|
|
void DocumentPageCache::setUserPreferredSize(const SimplePageSize& s)
|
|
{
|
|
bool sizeChanged = !userPreferredSize.isNearlyEqual(s);
|
|
userPreferredSize = s;
|
|
|
|
if (sizeChanged)
|
|
emit(paperSizeChanged());
|
|
}
|
|
|
|
|
|
void DocumentPageCache::setUseDocumentSpecifiedSize(bool b)
|
|
{
|
|
bool valChanged = (useDocumentSpecifiedSize == b);
|
|
|
|
useDocumentSpecifiedSize = b;
|
|
if (valChanged)
|
|
emit(paperSizeChanged());
|
|
}
|
|
|
|
|
|
TQPixmap DocumentPageCache::createThumbnail(const PageNumber& pageNr, int width)
|
|
{
|
|
// Paranoid checks
|
|
if (renderer.isNull()) {
|
|
kdError(1223) << "DocumentPageCache::createThumbnail(..) called but no renderer was set" << endl;
|
|
thumbnailPage.resize(0,0);
|
|
return thumbnailPage;
|
|
}
|
|
if (renderer->totalPages() < pageNr) {
|
|
kdError(1223) << "DocumentPageCache::createThumbnail( " << pageNr << ", width ) called but document contains only " << renderer->totalPages() << " pages." << endl;
|
|
thumbnailPage.resize(0,0);
|
|
return thumbnailPage;
|
|
}
|
|
if (!pageNr.isValid()) {
|
|
kdError(1223) << "DocumentPageCache::createThumbnail(..) called for page with invalid page specification" << endl;
|
|
thumbnailPage.resize(0,0);
|
|
return thumbnailPage;
|
|
}
|
|
if (!sizeOfPage().isValid()) {
|
|
kdError(1223) << "DocumentPageCache::createThumbnail(..) called for page with invalid size" << endl;
|
|
thumbnailPage.resize(0,0);
|
|
return thumbnailPage;
|
|
}
|
|
|
|
thumbnailPage.setPageNumber(pageNr);
|
|
thumbnailPage.resize(width, (int)(width/sizeOfPage(pageNr).aspectRatio() + 0.5 ) );
|
|
renderer->drawThumbnail((double)(width)/sizeOfPage(pageNr).width().getLength_in_inch(), &thumbnailPage);
|
|
|
|
if (KVSPrefs::changeColors() && KVSPrefs::renderMode() != KVSPrefs::EnumRenderMode::Paper)
|
|
{
|
|
return thumbnailPage.accessiblePixmap();
|
|
}
|
|
else
|
|
{
|
|
return thumbnailPage;
|
|
}
|
|
}
|
|
|
|
void DocumentPageCache::deselectText()
|
|
{
|
|
userSelection.clear();
|
|
emit textSelected(false);
|
|
}
|
|
|
|
void DocumentPageCache::selectText(const TextSelection& selection)
|
|
{
|
|
userSelection = selection;
|
|
emit textSelected(!userSelection.isEmpty());
|
|
}
|
|
|
|
#include "documentPageCache.moc"
|