aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFazlul Shahriar <fshahriar@gmail.com>2009-08-09 20:13:48 -0400
committerFazlul Shahriar <fshahriar@gmail.com>2009-08-09 20:13:48 -0400
commitb3453e08b88b3973f427c5bf982670bb5a09d259 (patch)
tree81abf4765d533a44284383694cf0aa7369c973bb
parent3c6ab1854e92467a7309cf244339c6f10c2b0d7d (diff)
downloadplan9port-b3453e08b88b3973f427c5bf982670bb5a09d259.tar.gz
plan9port-b3453e08b88b3973f427c5bf982670bb5a09d259.tar.bz2
plan9port-b3453e08b88b3973f427c5bf982670bb5a09d259.zip
page: add caching from Plan 9
http://codereview.appspot.com/105070
-rw-r--r--cmd/page/cache.c196
-rw-r--r--src/cmd/page/mkfile1
-rw-r--r--src/cmd/page/page.c2
-rw-r--r--src/cmd/page/page.h2
-rw-r--r--src/cmd/page/view.c67
5 files changed, 212 insertions, 56 deletions
diff --git a/cmd/page/cache.c b/cmd/page/cache.c
new file mode 100644
index 00000000..87c2c25a
--- /dev/null
+++ b/cmd/page/cache.c
@@ -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;
+}
diff --git a/src/cmd/page/mkfile b/src/cmd/page/mkfile
index bcd02a8d..e1a2162f 100644
--- a/src/cmd/page/mkfile
+++ b/src/cmd/page/mkfile
@@ -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
index 32ba9c2f..23da4b91 100644
--- a/src/cmd/page/page.c
+++ b/src/cmd/page/page.c
@@ -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
index 3dff4789..e4b320e5 100644
--- a/src/cmd/page/page.h
+++ b/src/cmd/page/page.h
@@ -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
index 8fc6fa79..c59a0edb 100644
--- a/src/cmd/page/view.c
+++ b/src/cmd/page/view.c
@@ -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){
@@ -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;
@@ -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';
@@ -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);