page: add caching from Plan 9

http://codereview.appspot.com/105070
This commit is contained in:
Fazlul Shahriar 2009-08-09 20:13:48 -04:00
parent 3c6ab1854e
commit b3453e08b8
5 changed files with 212 additions and 56 deletions

196
cmd/page/cache.c Normal file
View file

@ -0,0 +1,196 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <cursor.h>
#include <event.h>
#include <bio.h>
#include <plumb.h>
#include <ctype.h>
#include <keyboard.h>
#include <thread.h>
#include "page.h"
typedef struct Cached Cached;
struct Cached
{
Document *doc;
int page;
int angle;
Image *im;
};
static Cached cache[5];
static int rabusy;
static Image*
questionmark(void)
{
static Image *im;
if(im)
return im;
im = xallocimage(display, Rect(0,0,50,50), GREY1, 1, DBlack);
if(im == nil)
return nil;
string(im, ZP, display->white, ZP, display->defaultfont, "?");
return im;
}
void
cacheflush(void)
{
int i;
Cached *c;
for(i=0; i<nelem(cache); i++){
c = &cache[i];
if(c->im)
freeimage(c->im);
c->im = nil;
c->doc = nil;
}
}
static Image*
_cachedpage(Document *doc, int angle, int page, char *ra)
{
int i;
Cached *c, old;
Image *im, *tmp;
if((page < 0 || page >= doc->npage) && !doc->fwdonly)
return nil;
Again:
for(i=0; i<nelem(cache); i++){
c = &cache[i];
if(c->doc == doc && c->angle == angle && c->page == page){
if(chatty) fprint(2, "cache%s hit %d\n", ra, page);
goto Found;
}
if(c->doc == nil)
break;
}
if(i >= nelem(cache))
i = nelem(cache)-1;
c = &cache[i];
if(c->im)
freeimage(c->im);
c->im = nil;
c->doc = nil;
c->page = -1;
if(chatty) fprint(2, "cache%s load %d\n", ra, page);
im = doc->drawpage(doc, page);
if(im == nil){
if(doc->fwdonly) /* end of file */
wexits(0);
im = questionmark();
if(im == nil){
Flush:
if(i > 0){
cacheflush();
goto Again;
}
fprint(2, "out of memory: %r\n");
wexits("memory");
}
return im;
}
if(im->r.min.x != 0 || im->r.min.y != 0){
/* translate to 0,0 */
tmp = xallocimage(display, Rect(0, 0, Dx(im->r), Dy(im->r)), im->chan, 0, DNofill);
if(tmp == nil){
freeimage(im);
goto Flush;
}
drawop(tmp, tmp->r, im, nil, im->r.min, S);
freeimage(im);
im = tmp;
}
switch(angle){
case 90:
im = rot90(im);
break;
case 180:
rot180(im);
break;
case 270:
im = rot270(im);
break;
}
if(im == nil)
goto Flush;
c->doc = doc;
c->page = page;
c->angle = angle;
c->im = im;
Found:
if(chatty) fprint(2, "cache%s mtf %d @%d:", ra, c->page, i);
old = *c;
memmove(cache+1, cache, (c-cache)*sizeof cache[0]);
cache[0] = old;
if(chatty){
for(i=0; i<nelem(cache); i++)
fprint(2, " %d", cache[i].page);
fprint(2, "\n");
}
if(chatty) fprint(2, "cache%s return %d %p\n", ra, old.page, old.im);
return old.im;
}
static void
raproc(void *a)
{
Cached *c;
c = a;
lockdisplay(display);
_cachedpage(c->doc, c->angle, c->page, "-ra");
rabusy = 0;
unlockdisplay(display);
free(c);
threadexits(0);
}
Image*
cachedpage(Document *doc, int angle, int page)
{
static int lastpage = -1;
Cached *c;
Image *im;
int ra;
if(doc->npage < 1)
return display->white;
im = _cachedpage(doc, angle, page, "");
if(im == nil)
return nil;
/* readahead */
ra = -1;
if(!rabusy){
if(page == lastpage+1)
ra = page+1;
else if(page == lastpage-1)
ra = page-1;
}
lastpage = page;
if(ra >= 0){
c = emalloc(sizeof(*c));
c->doc = doc;
c->angle = angle;
c->page = ra;
c->im = nil;
rabusy = 1;
if(proccreate(raproc, c, mainstacksize) == -1)
rabusy = 0;
}
return im;
}

View file

@ -4,6 +4,7 @@ TARG=page
HFILES=page.h HFILES=page.h
OFILES=\ OFILES=\
cache.$O\
filter.$O\ filter.$O\
gfx.$O\ gfx.$O\
gs.$O\ gs.$O\

View file

@ -228,6 +228,8 @@ threadmain(int argc, char **argv)
fprint(2, "page: initdraw failed: %r\n"); fprint(2, "page: initdraw failed: %r\n");
wexits("initdraw"); wexits("initdraw");
} }
display->locking = 1;
truecolor = screen->depth > 8; truecolor = screen->depth > 8;
viewer(doc); viewer(doc);
wexits(0); wexits(0);

View file

@ -96,6 +96,8 @@ void wexits(char*);
Image* xallocimage(Display*, Rectangle, ulong, int, ulong); Image* xallocimage(Display*, Rectangle, ulong, int, ulong);
int bell(void*, char*); int bell(void*, char*);
Image* convert(Graphic *g); Image* convert(Graphic *g);
Image* cachedpage(Document*, int, int);
void cacheflush(void);
extern int stdinfd; extern int stdinfd;
extern int truecolor; extern int truecolor;

View file

@ -115,55 +115,17 @@ menugen(int n)
void void
showpage(int page, Menu *m) showpage(int page, Menu *m)
{ {
Image *tmp;
if(doc->fwdonly) if(doc->fwdonly)
m->lasthit = 0; /* this page */ m->lasthit = 0; /* this page */
else else
m->lasthit = reverse ? doc->npage-1-page : page; m->lasthit = reverse ? doc->npage-1-page : page;
setcursor(mc, &reading); setcursor(mc, &reading);
freeimage(im); im = cachedpage(doc, angle, page);
if((page < 0 || page >= doc->npage) && !doc->fwdonly){ if(im == nil)
im = nil;
return;
}
im = doc->drawpage(doc, page);
if(im == nil) {
if(doc->fwdonly) /* this is how we know we're out of pages */
wexits(0); wexits(0);
if(resizing)
im = xallocimage(display, Rect(0,0,50,50), GREY1, 1, DBlack);
if(im == nil) {
fprint(2, "out of memory: %r\n");
wexits("memory");
}
string(im, ZP, display->white, ZP, display->defaultfont, "?");
}else if(resizing){
resize(Dx(im->r), Dy(im->r)); resize(Dx(im->r), Dy(im->r));
}
if(im->r.min.x > 0 || im->r.min.y > 0) {
tmp = xallocimage(display, Rect(0, 0, Dx(im->r), Dy(im->r)), im->chan, 0, DNofill);
if(tmp == nil) {
fprint(2, "out of memory during showpage: %r\n");
wexits("memory");
}
drawop(tmp, tmp->r, im, nil, im->r.min, S);
freeimage(im);
im = tmp;
}
switch(angle){
case 90:
im = rot90(im);
break;
case 180:
rot180(im);
break;
case 270:
im = rot270(im);
break;
}
setcursor(mc, nil); setcursor(mc, nil);
if(showbottom){ if(showbottom){
@ -268,7 +230,7 @@ void
viewer(Document *dd) viewer(Document *dd)
{ {
int i, fd, n, oldpage; int i, fd, n, oldpage;
int nxt; int nxt, a;
Channel *cp; Channel *cp;
Menu menu, midmenu; Menu menu, midmenu;
Mouse m; Mouse m;
@ -372,7 +334,10 @@ viewer(Document *dd)
* a fair amount. we don't care about doc->npage anymore, and * a fair amount. we don't care about doc->npage anymore, and
* all that can be done is select the next page. * all that can be done is select the next page.
*/ */
switch(alt(alts)) { unlockdisplay(display);
a = alt(alts);
lockdisplay(display);
switch(a) {
case CKeyboard: case CKeyboard:
if(run <= 0xFF && isdigit(run)) { if(run <= 0xFF && isdigit(run)) {
nxt = nxt*10+run-'0'; nxt = nxt*10+run-'0';
@ -622,22 +587,12 @@ viewer(Document *dd)
break; break;
} }
case Rot: /* rotate 90 */ case Rot: /* rotate 90 */
setcursor(mc, &reading);
im = rot90(im);
setcursor(mc, nil);
angle = (angle+90) % 360; angle = (angle+90) % 360;
redraw(screen); showpage(page, &menu);
flushimage(display, 1);
break; break;
case Upside: /* upside-down */ case Upside: /* upside-down */
if(im==nil)
break;
setcursor(mc, &reading);
rot180(im);
setcursor(mc, nil);
angle = (angle+180) % 360; angle = (angle+180) % 360;
redraw(screen); showpage(page, &menu);
flushimage(display, 1);
break; break;
case Restore: /* restore */ case Restore: /* restore */
showpage(page, &menu); showpage(page, &menu);