tpage: add caching from Plan 9 - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
LICENSE
---
commit b3453e08b88b3973f427c5bf982670bb5a09d259
parent 3c6ab1854e92467a7309cf244339c6f10c2b0d7d
Author: Fazlul Shahriar 
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(-)
---
diff --git a/cmd/page/cache.c b/cmd/page/cache.c
t@@ -0,0 +1,196 @@
+#include 
+#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 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; 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;
+
+        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; idoc, 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;
+}
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\
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);
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;
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);