/* TODO: this might take some time, would be good to show a dialog to let the user know he has to wait until we finish */ void RenderCache::CancelRendering(DisplayModel* dm) { ClearQueueForDisplayModel(dm); for (;;) { EnterCriticalSection(&requestAccess); if (!curReq || (curReq->dm != dm)) { // to be on the safe side ClearQueueForDisplayModel(dm); LeaveCriticalSection(&requestAccess); return; } AbortCurrentRequest(); LeaveCriticalSection(&requestAccess); /* TODO: busy loop is not good, but I don't have a better idea */ Sleep(50); } }
/* Render a bitmap for page <pageNo> in <dm>. */ void RenderCache::RequestRendering(DisplayModel *dm, int pageNo, TilePosition tile, bool clearQueueForPage) { ScopedCritSec scope(&requestAccess); assert(dm); if (!dm || dm->dontRenderFlag) return; int rotation = NormalizeRotation(dm->Rotation()); float zoom = dm->ZoomReal(pageNo); if (curReq && (curReq->pageNo == pageNo) && (curReq->dm == dm) && (curReq->tile == tile)) { if ((curReq->zoom == zoom) && (curReq->rotation == rotation)) { /* we're already rendering exactly the same page */ return; } /* Currently rendered page is for the same page but with different zoom or rotation, so abort it */ AbortCurrentRequest(); } // clear requests for tiles of different resolution and invisible tiles if (clearQueueForPage) ClearQueueForDisplayModel(dm, pageNo, &tile); for (int i = 0; i < requestCount; i++) { PageRenderRequest* req = &(requests[i]); if ((req->pageNo == pageNo) && (req->dm == dm) && (req->tile == tile)) { if ((req->zoom == zoom) && (req->rotation == rotation)) { /* Request with exactly the same parameters already queued for rendering. Move it to the top of the queue so that it'll be rendered faster. */ PageRenderRequest tmp; tmp = requests[requestCount-1]; requests[requestCount-1] = *req; *req = tmp; } else { /* There was a request queued for the same page but with different zoom or rotation, so only replace this request */ req->zoom = zoom; req->rotation = rotation; } return; } } if (Exists(dm, pageNo, rotation, zoom, &tile)) { /* This page has already been rendered in the correct dimensions and isn't about to be rerendered in different dimensions */ return; } Render(dm, pageNo, rotation, zoom, &tile); }
// marks all tiles containing rect of pageNo as out of date void RenderCache::Invalidate(DisplayModel* dm, int pageNo, RectD rect) { ScopedCritSec scopeReq(&requestAccess); ClearQueueForDisplayModel(dm, pageNo); if (curReq && curReq->dm == dm && curReq->pageNo == pageNo) AbortCurrentRequest(); ScopedCritSec scopeCache(&cacheAccess); RectD mediabox = dm->GetEngine()->PageMediabox(pageNo); for (int i = 0; i < cacheCount; i++) { if (cache[i]->dm == dm && cache[i]->pageNo == pageNo && !GetTileRect(mediabox, cache[i]->tile).Intersect(rect).IsEmpty()) { cache[i]->zoom = INVALID_ZOOM; cache[i]->outOfDate = true; } } }
// reduce the size of tiles in order to hopefully use less memory overall bool RenderCache::ReduceTileSize() { if (maxTileSize.dx < 200 || maxTileSize.dy < 200) return false; ScopedCritSec scope1(&requestAccess); ScopedCritSec scope2(&cacheAccess); if (maxTileSize.dx > maxTileSize.dy) (int)maxTileSize.dx /= 2; else (int)maxTileSize.dy /= 2; // invalidate all rendered bitmaps and all requests while (cacheCount > 0) FreeForDisplayModel(cache[0]->dm); while (requestCount > 0) ClearQueueForDisplayModel(requests[0].dm); AbortCurrentRequest(); return true; }