xref: /plan9/sys/src/cmd/page/cache.c (revision 7c6c2e8d73aeebe8bc54f9f50e052486c4af02da)
1493edcedSDavid du Colombier #include <u.h>
2493edcedSDavid du Colombier #include <libc.h>
3493edcedSDavid du Colombier #include <draw.h>
4493edcedSDavid du Colombier #include <cursor.h>
5493edcedSDavid du Colombier #include <event.h>
6493edcedSDavid du Colombier #include <bio.h>
7493edcedSDavid du Colombier #include <plumb.h>
8493edcedSDavid du Colombier #include <ctype.h>
9493edcedSDavid du Colombier #include <keyboard.h>
10493edcedSDavid du Colombier #include "page.h"
11493edcedSDavid du Colombier 
12493edcedSDavid du Colombier typedef struct Cached Cached;
13493edcedSDavid du Colombier struct Cached
14493edcedSDavid du Colombier {
15493edcedSDavid du Colombier 	Document *doc;
16493edcedSDavid du Colombier 	int page;
17493edcedSDavid du Colombier 	int angle;
18493edcedSDavid du Colombier 	Image *im;
19493edcedSDavid du Colombier };
20493edcedSDavid du Colombier 
21493edcedSDavid du Colombier static Cached cache[5];
22493edcedSDavid du Colombier 
23493edcedSDavid du Colombier static Image*
questionmark(void)24493edcedSDavid du Colombier questionmark(void)
25493edcedSDavid du Colombier {
26493edcedSDavid du Colombier 	static Image *im;
27493edcedSDavid du Colombier 
28493edcedSDavid du Colombier 	if(im)
29493edcedSDavid du Colombier 		return im;
30493edcedSDavid du Colombier 	im = xallocimage(display, Rect(0,0,50,50), GREY1, 1, DBlack);
31493edcedSDavid du Colombier 	if(im == nil)
32493edcedSDavid du Colombier 		return nil;
33493edcedSDavid du Colombier 	string(im, ZP, display->white, ZP, display->defaultfont, "?");
34493edcedSDavid du Colombier 	return im;
35493edcedSDavid du Colombier }
36493edcedSDavid du Colombier 
37493edcedSDavid du Colombier void
cacheflush(void)38493edcedSDavid du Colombier cacheflush(void)
39493edcedSDavid du Colombier {
40493edcedSDavid du Colombier 	int i;
41493edcedSDavid du Colombier 	Cached *c;
42493edcedSDavid du Colombier 
43493edcedSDavid du Colombier 	for(i=0; i<nelem(cache); i++){
44493edcedSDavid du Colombier 		c = &cache[i];
45493edcedSDavid du Colombier 		if(c->im)
46493edcedSDavid du Colombier 			freeimage(c->im);
47493edcedSDavid du Colombier 		c->im = nil;
48493edcedSDavid du Colombier 		c->doc = nil;
49493edcedSDavid du Colombier 	}
50493edcedSDavid du Colombier }
51493edcedSDavid du Colombier 
52493edcedSDavid du Colombier static Image*
_cachedpage(Document * doc,int angle,int page,char * ra)53493edcedSDavid du Colombier _cachedpage(Document *doc, int angle, int page, char *ra)
54493edcedSDavid du Colombier {
55493edcedSDavid du Colombier 	int i;
56493edcedSDavid du Colombier 	Cached *c, old;
57493edcedSDavid du Colombier 	Image *im, *tmp;
58493edcedSDavid du Colombier 	static int lastpage = -1;
59493edcedSDavid du Colombier 
60493edcedSDavid du Colombier 	if((page < 0 || page >= doc->npage) && !doc->fwdonly)
61493edcedSDavid du Colombier 		return nil;
62493edcedSDavid du Colombier 
63493edcedSDavid du Colombier Again:
64493edcedSDavid du Colombier 	for(i=0; i<nelem(cache); i++){
65493edcedSDavid du Colombier 		c = &cache[i];
66493edcedSDavid du Colombier 		if(c->doc == doc && c->angle == angle && c->page == page){
67493edcedSDavid du Colombier 			if(chatty) fprint(2, "cache%s hit %d\n", ra, page);
68493edcedSDavid du Colombier 			goto Found;
69493edcedSDavid du Colombier 		}
70493edcedSDavid du Colombier 		if(c->doc == nil)
71493edcedSDavid du Colombier 			break;
72493edcedSDavid du Colombier 	}
73493edcedSDavid du Colombier 
74493edcedSDavid du Colombier 	if(i >= nelem(cache))
75493edcedSDavid du Colombier 		i = nelem(cache)-1;
76493edcedSDavid du Colombier 	c = &cache[i];
77493edcedSDavid du Colombier 	if(c->im)
78493edcedSDavid du Colombier 		freeimage(c->im);
79493edcedSDavid du Colombier 	c->im = nil;
80493edcedSDavid du Colombier 	c->doc = nil;
81493edcedSDavid du Colombier 	c->page = -1;
82493edcedSDavid du Colombier 
83493edcedSDavid du Colombier 	if(chatty) fprint(2, "cache%s load %d\n", ra, page);
84493edcedSDavid du Colombier 	im = doc->drawpage(doc, page);
85493edcedSDavid du Colombier 	if(im == nil){
86493edcedSDavid du Colombier 		if(doc->fwdonly)	/* end of file */
87493edcedSDavid du Colombier 			wexits(0);
88493edcedSDavid du Colombier 		im = questionmark();
89493edcedSDavid du Colombier 		if(im == nil){
90493edcedSDavid du Colombier 		Flush:
91493edcedSDavid du Colombier 			if(i > 0){
92493edcedSDavid du Colombier 				cacheflush();
93493edcedSDavid du Colombier 				goto Again;
94493edcedSDavid du Colombier 			}
95493edcedSDavid du Colombier 			fprint(2, "out of memory: %r\n");
96493edcedSDavid du Colombier 			wexits("memory");
97493edcedSDavid du Colombier 		}
98493edcedSDavid du Colombier 		return im;
99493edcedSDavid du Colombier 	}
100493edcedSDavid du Colombier 
101493edcedSDavid du Colombier 	if(im->r.min.x != 0 || im->r.min.y != 0){
102493edcedSDavid du Colombier 		/* translate to 0,0 */
103493edcedSDavid du Colombier 		tmp = xallocimage(display, Rect(0, 0, Dx(im->r), Dy(im->r)), im->chan, 0, DNofill);
104493edcedSDavid du Colombier 		if(tmp == nil){
105493edcedSDavid du Colombier 			freeimage(im);
106493edcedSDavid du Colombier 			goto Flush;
107493edcedSDavid du Colombier 		}
108493edcedSDavid du Colombier 		drawop(tmp, tmp->r, im, nil, im->r.min, S);
109493edcedSDavid du Colombier 		freeimage(im);
110493edcedSDavid du Colombier 		im = tmp;
111493edcedSDavid du Colombier 	}
112493edcedSDavid du Colombier 
113493edcedSDavid du Colombier 	switch(angle){
114493edcedSDavid du Colombier 	case 90:
115493edcedSDavid du Colombier 		im = rot90(im);
116493edcedSDavid du Colombier 		break;
117493edcedSDavid du Colombier 	case 180:
118493edcedSDavid du Colombier 		rot180(im);
119493edcedSDavid du Colombier 		break;
120493edcedSDavid du Colombier 	case 270:
121493edcedSDavid du Colombier 		im = rot270(im);
122493edcedSDavid du Colombier 		break;
123493edcedSDavid du Colombier 	}
124493edcedSDavid du Colombier 	if(im == nil)
125493edcedSDavid du Colombier 		goto Flush;
126493edcedSDavid du Colombier 
127493edcedSDavid du Colombier 	c->doc = doc;
128493edcedSDavid du Colombier 	c->page = page;
129493edcedSDavid du Colombier 	c->angle = angle;
130493edcedSDavid du Colombier 	c->im = im;
131493edcedSDavid du Colombier 
132493edcedSDavid du Colombier Found:
133493edcedSDavid du Colombier 	if(chatty) fprint(2, "cache%s mtf %d @%d:", ra, c->page, i);
134493edcedSDavid du Colombier 	old = *c;
135493edcedSDavid du Colombier 	memmove(cache+1, cache, (c-cache)*sizeof cache[0]);
136493edcedSDavid du Colombier 	cache[0] = old;
137493edcedSDavid du Colombier 	if(chatty){
138493edcedSDavid du Colombier 		for(i=0; i<nelem(cache); i++)
139493edcedSDavid du Colombier 			fprint(2, " %d", cache[i].page);
140493edcedSDavid du Colombier 		fprint(2, "\n");
141493edcedSDavid du Colombier 	}
142493edcedSDavid du Colombier 	if(chatty) fprint(2, "cache%s return %d %p\n", ra, old.page, old.im);
143493edcedSDavid du Colombier 	return old.im;
144493edcedSDavid du Colombier }
145493edcedSDavid du Colombier 
146493edcedSDavid du Colombier Image*
cachedpage(Document * doc,int angle,int page)147493edcedSDavid du Colombier cachedpage(Document *doc, int angle, int page)
148493edcedSDavid du Colombier {
149493edcedSDavid du Colombier 	static int lastpage = -1;
150493edcedSDavid du Colombier 	static int rabusy;
151493edcedSDavid du Colombier 	Image *im;
152493edcedSDavid du Colombier 	int ra;
153493edcedSDavid du Colombier 
154*7c6c2e8dSDavid du Colombier 	if(doc->npage < 1)
155*7c6c2e8dSDavid du Colombier 		return display->white;
156*7c6c2e8dSDavid du Colombier 
157493edcedSDavid du Colombier 	im = _cachedpage(doc, angle, page, "");
158493edcedSDavid du Colombier 	if(im == nil)
159493edcedSDavid du Colombier 		return nil;
160493edcedSDavid du Colombier 
161493edcedSDavid du Colombier 	/* readahead */
162493edcedSDavid du Colombier 	ra = -1;
163493edcedSDavid du Colombier 	if(!rabusy){
164493edcedSDavid du Colombier 		if(page == lastpage+1)
165493edcedSDavid du Colombier 			ra = page+1;
166493edcedSDavid du Colombier 		else if(page == lastpage-1)
167493edcedSDavid du Colombier 			ra = page-1;
168493edcedSDavid du Colombier 	}
169493edcedSDavid du Colombier 	lastpage = page;
170493edcedSDavid du Colombier 	if(ra >= 0){
171493edcedSDavid du Colombier 		rabusy = 1;
172493edcedSDavid du Colombier 		switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
173493edcedSDavid du Colombier 		case -1:
174493edcedSDavid du Colombier 			rabusy = 0;
175493edcedSDavid du Colombier 			break;
176493edcedSDavid du Colombier 		case 0:
177493edcedSDavid du Colombier 			lockdisplay(display);
178493edcedSDavid du Colombier 			_cachedpage(doc, angle, ra, "-ra");
179493edcedSDavid du Colombier 			rabusy = 0;
180493edcedSDavid du Colombier 			unlockdisplay(display);
181493edcedSDavid du Colombier 			_exits(nil);
182493edcedSDavid du Colombier 		default:
183493edcedSDavid du Colombier 			break;
184493edcedSDavid du Colombier 		}
185493edcedSDavid du Colombier 	}
186493edcedSDavid du Colombier 	return im;
187493edcedSDavid du Colombier }
188