tpage: add caching from Plan 9 - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit b3453e08b88b3973f427c5bf982670bb5a09d259
 (DIR) parent 3c6ab1854e92467a7309cf244339c6f10c2b0d7d
 (HTM) Author: Fazlul Shahriar <fshahriar@gmail.com>
       Date:   Sun,  9 Aug 2009 20:13:48 -0400
       
       page: add caching from Plan 9
       
       http://codereview.appspot.com/105070
       
       Diffstat:
         A cmd/page/cache.c                    |     196 +++++++++++++++++++++++++++++++
         M src/cmd/page/mkfile                 |       1 +
         M src/cmd/page/page.c                 |       2 ++
         M src/cmd/page/page.h                 |       2 ++
         M src/cmd/page/view.c                 |      67 +++++--------------------------
       
       5 files changed, 212 insertions(+), 56 deletions(-)
       ---
 (DIR) diff --git a/cmd/page/cache.c b/cmd/page/cache.c
       t@@ -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;
       +}
 (DIR) diff --git a/src/cmd/page/mkfile b/src/cmd/page/mkfile
       t@@ -4,6 +4,7 @@ TARG=page
        
        HFILES=page.h
        OFILES=\
       +        cache.$O\
                filter.$O\
                gfx.$O\
                gs.$O\
 (DIR) diff --git a/src/cmd/page/page.c b/src/cmd/page/page.c
       t@@ -228,6 +228,8 @@ threadmain(int argc, char **argv)
                        fprint(2, "page: initdraw failed: %r\n");
                        wexits("initdraw");
                }
       +        display->locking = 1;
       +        
                truecolor = screen->depth > 8;
                viewer(doc);
                wexits(0);
 (DIR) diff --git a/src/cmd/page/page.h b/src/cmd/page/page.h
       t@@ -96,6 +96,8 @@ void        wexits(char*);
        Image*        xallocimage(Display*, Rectangle, ulong, int, ulong);
        int        bell(void*, char*);
        Image*        convert(Graphic *g);
       +Image*        cachedpage(Document*, int, int);
       +void        cacheflush(void);
        
        extern int stdinfd;
        extern int truecolor;
 (DIR) diff --git a/src/cmd/page/view.c b/src/cmd/page/view.c
       t@@ -115,55 +115,17 @@ menugen(int n)
        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;
                
                setcursor(mc, &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){
       +        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;
       -        }
        
                setcursor(mc, nil);
                if(showbottom){
       t@@ -268,7 +230,7 @@ void
        viewer(Document *dd)
        {
                int i, fd, n, oldpage;
       -        int nxt;
       +        int nxt, a;
                Channel *cp;
                Menu menu, midmenu;
                Mouse m;
       t@@ -372,7 +334,10 @@ viewer(Document *dd)
                         * a fair amount.  we don't care about doc->npage anymore, and
                         * all that can be done is select the next page.
                         */
       -                switch(alt(alts)) {
       +                unlockdisplay(display);
       +                a = alt(alts);
       +                lockdisplay(display);
       +                switch(a) {
                        case CKeyboard:
                                if(run <= 0xFF && isdigit(run)) {
                                        nxt = nxt*10+run-'0';
       t@@ -622,22 +587,12 @@ viewer(Document *dd)
                                                        break;
                                                }
                                        case Rot:        /* rotate 90 */
       -                                        setcursor(mc, &reading);
       -                                        im = rot90(im);
       -                                        setcursor(mc, nil);
                                                angle = (angle+90) % 360;
       -                                        redraw(screen);
       -                                        flushimage(display, 1);
       +                                        showpage(page, &menu);
                                                break;
                                        case Upside:         /* upside-down */
       -                                        if(im==nil)
       -                                                break;
       -                                        setcursor(mc, &reading);
       -                                        rot180(im);
       -                                        setcursor(mc, nil);
                                                angle = (angle+180) % 360;
       -                                        redraw(screen);
       -                                        flushimage(display, 1);
       +                                        showpage(page, &menu);
                                                break;
                                        case Restore:        /* restore */
                                                showpage(page, &menu);