Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <cursor.h>
5 #include <event.h>
6 #include <bio.h>
7 #include <plumb.h>
8 #include <ctype.h>
9 #include <keyboard.h>
10 #include <thread.h>
11 #include "page.h"
13 typedef struct Cached Cached;
14 struct Cached
15 {
16 Document *doc;
17 int page;
18 int angle;
19 Image *im;
20 int ppi;
21 };
23 static Cached cache[5];
24 static int rabusy;
26 static Image*
27 questionmark(void)
28 {
29 static Image *im;
31 if(im)
32 return im;
33 im = xallocimage(display, Rect(0,0,50,50), GREY1, 1, DBlack);
34 if(im == nil)
35 return nil;
36 string(im, ZP, display->white, ZP, display->defaultfont, "?");
37 return im;
38 }
40 void
41 cacheflush(void)
42 {
43 int i;
44 Cached *c;
46 for(i=0; i<nelem(cache); i++){
47 c = &cache[i];
48 if(c->im)
49 freeimage(c->im);
50 c->im = nil;
51 c->doc = nil;
52 }
53 }
55 static Image*
56 _cachedpage(Document *doc, int angle, int page, char *ra)
57 {
58 int i;
59 Cached *c, old;
60 Image *im, *tmp;
61 int ppi = 100;
62 PDFInfo *pdf;
63 PSInfo *ps;
65 if((page < 0 || page >= doc->npage) && !doc->fwdonly)
66 return nil;
68 if (doc->type == Tpdf){
69 pdf = (PDFInfo *) doc->extra;
70 ppi = pdf->gs.ppi;
71 }
72 else{
73 if (doc->type == Tps){
74 ps = (PSInfo *) doc->extra;
75 ppi = ps->gs.ppi;
76 }
77 }
79 Again:
80 for(i=0; i<nelem(cache); i++){
81 c = &cache[i];
82 if(c->doc == doc && c->angle == angle && c->page == page && c->ppi == ppi){
83 if(chatty) fprint(2, "cache%s hit %d\n", ra, page);
84 goto Found;
85 }
86 if(c->doc == nil)
87 break;
88 }
90 if(i >= nelem(cache))
91 i = nelem(cache)-1;
92 c = &cache[i];
93 if(c->im)
94 freeimage(c->im);
95 c->im = nil;
96 c->doc = nil;
97 c->page = -1;
98 c->ppi = -1;
100 if(chatty) fprint(2, "cache%s load %d\n", ra, page);
101 im = doc->drawpage(doc, page);
102 if(im == nil){
103 if(doc->fwdonly) /* end of file */
104 wexits(0);
105 im = questionmark();
106 if(im == nil){
107 Flush:
108 if(i > 0){
109 cacheflush();
110 goto Again;
112 fprint(2, "out of memory: %r\n");
113 wexits("memory");
115 return im;
118 if(im->r.min.x != 0 || im->r.min.y != 0){
119 /* translate to 0,0 */
120 tmp = xallocimage(display, Rect(0, 0, Dx(im->r), Dy(im->r)), im->chan, 0, DNofill);
121 if(tmp == nil){
122 freeimage(im);
123 goto Flush;
125 drawop(tmp, tmp->r, im, nil, im->r.min, S);
126 freeimage(im);
127 im = tmp;
130 switch(angle){
131 case 90:
132 im = rot90(im);
133 break;
134 case 180:
135 rot180(im);
136 break;
137 case 270:
138 im = rot270(im);
139 break;
141 if(im == nil)
142 goto Flush;
144 c->doc = doc;
145 c->page = page;
146 c->angle = angle;
147 c->im = im;
148 c->ppi = ppi;
150 Found:
151 if(chatty) fprint(2, "cache%s mtf %d @%d:", ra, c->page, i);
152 old = *c;
153 memmove(cache+1, cache, (c-cache)*sizeof cache[0]);
154 cache[0] = old;
155 if(chatty){
156 for(i=0; i<nelem(cache); i++)
157 fprint(2, " %d", cache[i].page);
158 fprint(2, "\n");
160 if(chatty) fprint(2, "cache%s return %d %p\n", ra, old.page, old.im);
161 return old.im;
164 static void
165 raproc(void *a)
167 Cached *c;
169 c = a;
170 lockdisplay(display);
171 /*
172 * If there is only one page in a fwdonly file, we may reach EOF
173 * while doing readahead and page will exit without showing anything.
174 */
175 if(!c->doc->fwdonly)
176 _cachedpage(c->doc, c->angle, c->page, "-ra");
177 rabusy = 0;
178 unlockdisplay(display);
179 free(c);
180 threadexits(0);
183 Image*
184 cachedpage(Document *doc, int angle, int page)
186 static int lastpage = -1;
187 Cached *c;
188 Image *im;
189 int ra;
191 if(doc->npage < 1)
192 return display->white;
194 im = _cachedpage(doc, angle, page, "");
195 if(im == nil)
196 return nil;
198 /* readahead */
199 ra = -1;
200 if(!rabusy){
201 if(page == lastpage+1)
202 ra = page+1;
203 else if(page == lastpage-1)
204 ra = page-1;
206 lastpage = page;
207 if(ra >= 0){
208 c = emalloc(sizeof(*c));
209 c->doc = doc;
210 c->angle = angle;
211 c->page = ra;
212 c->im = nil;
213 rabusy = 1;
214 if(proccreate(raproc, c, mainstacksize) == -1)
215 rabusy = 0;
217 return im;