cache.c (3719B)
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" 12 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 }; 22 23 static Cached cache[5]; 24 static int rabusy; 25 26 static Image* 27 questionmark(void) 28 { 29 static Image *im; 30 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 } 39 40 void 41 cacheflush(void) 42 { 43 int i; 44 Cached *c; 45 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 } 54 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; 64 65 if((page < 0 || page >= doc->npage) && !doc->fwdonly) 66 return nil; 67 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 } 78 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 } 89 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; 99 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; 111 } 112 fprint(2, "out of memory: %r\n"); 113 wexits("memory"); 114 } 115 return im; 116 } 117 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; 124 } 125 drawop(tmp, tmp->r, im, nil, im->r.min, S); 126 freeimage(im); 127 im = tmp; 128 } 129 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; 140 } 141 if(im == nil) 142 goto Flush; 143 144 c->doc = doc; 145 c->page = page; 146 c->angle = angle; 147 c->im = im; 148 c->ppi = ppi; 149 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"); 159 } 160 if(chatty) fprint(2, "cache%s return %d %p\n", ra, old.page, old.im); 161 return old.im; 162 } 163 164 static void 165 raproc(void *a) 166 { 167 Cached *c; 168 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); 181 } 182 183 Image* 184 cachedpage(Document *doc, int angle, int page) 185 { 186 static int lastpage = -1; 187 Cached *c; 188 Image *im; 189 int ra; 190 191 if(doc->npage < 1) 192 return display->white; 193 194 im = _cachedpage(doc, angle, page, ""); 195 if(im == nil) 196 return nil; 197 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; 205 } 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; 216 } 217 return im; 218 }