Adds 5-image cache and read-ahead to page. The old Alef page did read-ahead and I always felt bad about not implementing it in the new one. Inspired by and replaces patch/page-bitmapcache. Thanks, zfolkerts! Reference: /n/sources/patch/applied/page-cra Date: Tue Sep 18 05:07:00 CES 2007 Signed-off-by: rsc@swtch.com --- /sys/src/cmd/page/mkfile Tue Sep 18 05:05:31 2007 +++ /sys/src/cmd/page/mkfile Tue Sep 18 05:05:31 2007 @@ -4,6 +4,7 @@ HFILES=page.h OFILES=\ + cache.$O\ filter.$O\ gfx.$O\ gs.$O\ --- /sys/src/cmd/page/ps.c Tue Sep 18 05:05:34 2007 +++ /sys/src/cmd/page/ps.c Tue Sep 18 05:05:32 2007 @@ -198,7 +198,7 @@ Keepreading: while(p = Brdline(b, eol)) { if(p[0] == '%') - if(chatty) fprint(2, "ps %.*s\n", utfnlen(p, Blinelen(b)-1), p); + if(chatty > 1) fprint(2, "ps %.*s\n", utfnlen(p, Blinelen(b)-1), p); if(npage == mpage) { mpage *= 2; page = erealloc(page, mpage*sizeof(*page)); --- /sys/src/cmd/page/cache.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/page/cache.c Tue Sep 18 05:08:59 2007 @@ -0,0 +1,184 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "page.h" + +typedef struct Cached Cached; +struct Cached +{ + Document *doc; + int page; + int angle; + Image *im; +}; + +static Cached cache[5]; + +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; iim) + 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; + static int lastpage = -1; + + if((page < 0 || page >= doc->npage) && !doc->fwdonly) + return nil; + +Again: + for(i=0; idoc == 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= 0){ + rabusy = 1; + switch(rfork(RFPROC|RFMEM|RFNOWAIT)){ + case -1: + rabusy = 0; + break; + case 0: + lockdisplay(display); + _cachedpage(doc, angle, ra, "-ra"); + rabusy = 0; + unlockdisplay(display); + _exits(nil); + default: + break; + } + } + return im; +} --- /sys/src/cmd/page/page.c Tue Sep 18 05:05:38 2007 +++ /sys/src/cmd/page/page.c Tue Sep 18 05:05:38 2007 @@ -221,6 +221,8 @@ fprint(2, "page: initdraw failed: %r\n"); wexits("initdraw"); } + display->locking = 1; + truecolor = screen->depth > 8; viewer(doc); wexits(0); --- /sys/src/cmd/page/page.h Tue Sep 18 05:05:42 2007 +++ /sys/src/cmd/page/page.h Tue Sep 18 05:05:41 2007 @@ -70,6 +70,8 @@ Image* xallocimage(Display*, Rectangle, ulong, int, ulong); int bell(void*, char*); int opentemp(char *template); +Image* cachedpage(Document*, int, int); +void cacheflush(void); extern int stdinfd; extern int truecolor; --- /sys/src/cmd/page/view.c Tue Sep 18 05:05:46 2007 +++ /sys/src/cmd/page/view.c Tue Sep 18 05:05:46 2007 @@ -15,6 +15,7 @@ Document *doc; Image *im; +Image *tofree; int page; int angle = 0; int showbottom = 0; /* on the next showpage, move the image so the bottom is visible. */ @@ -58,6 +59,16 @@ RMenu = 3, }; +static void +delayfreeimage(Image *m) +{ + if(m == tofree) + return; + if(tofree) + freeimage(tofree); + tofree = m; +} + void unhide(void) { @@ -118,55 +129,18 @@ void showpage(int page, Menu *m) { - Image *tmp; - if(doc->fwdonly) m->lasthit = 0; /* this page */ else m->lasthit = reverse ? doc->npage-1-page : page; esetcursor(&reading); - freeimage(im); - if((page < 0 || page >= doc->npage) && !doc->fwdonly){ - 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); - - 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){ + delayfreeimage(nil); + im = cachedpage(doc, angle, page); + if(im == nil) + wexits(0); + if(resizing) 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; - } esetcursor(nil); if(showbottom){ @@ -344,7 +318,10 @@ * a fair amount. we don't care about doc->npage anymore, and * all that can be done is select the next page. */ - switch(eread(Emouse|Ekeyboard|Eplumb, &e)){ + unlockdisplay(display); + i = eread(Emouse|Ekeyboard|Eplumb, &e); + lockdisplay(display); + switch(i){ case Ekeyboard: if(e.kbdc <= 0xFF && isdigit(e.kbdc)) { nxt = nxt*10+e.kbdc-'0'; @@ -396,12 +373,8 @@ case 'u': if(im==nil) break; - esetcursor(&reading); - rot180(im); - esetcursor(nil); angle = (angle+180) % 360; - redraw(screen); - flushimage(display, 1); + showpage(page, &menu); break; case '-': case '\b': @@ -486,7 +459,9 @@ dxy = subpt(m.xy, oxy); oxy = m.xy; translate(dxy); + unlockdisplay(display); m = emouse(); + lockdisplay(display); } while(m.buttons == Left); if(m.buttons) { dxy = subpt(xy0, oxy); @@ -498,7 +473,9 @@ if(doc->npage == 0) break; + unlockdisplay(display); n = emenuhit(Middle, &m, &midmenu); + lockdisplay(display); if(n == -1) break; switch(n){ @@ -561,8 +538,8 @@ wexits("memory"); } resample(im, tmp); - freeimage(im); im = tmp; + delayfreeimage(tmp); esetcursor(nil); ul = screen->r.min; redraw(screen); @@ -586,8 +563,8 @@ wexits("memory"); } resample(im, tmp); - freeimage(im); im = tmp; + delayfreeimage(tmp); esetcursor(nil); ul = screen->r.min; redraw(screen); @@ -595,22 +572,12 @@ break; } case Rot: /* rotate 90 */ - esetcursor(&reading); - im = rot90(im); - esetcursor(nil); angle = (angle+90) % 360; - redraw(screen); - flushimage(display, 1); + showpage(page, &menu); break; case Upside: /* upside-down */ - if(im==nil) - break; - esetcursor(&reading); - rot180(im); - esetcursor(nil); angle = (angle+180) % 360; - redraw(screen); - flushimage(display, 1); + showpage(page, &menu); break; case Restore: /* restore */ showpage(page, &menu); @@ -662,7 +629,9 @@ break; oldpage = page; + unlockdisplay(display); n = emenuhit(RMenu, &m, &menu); + lockdisplay(display); if(n == -1) break;