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 "page.h" 11 12 typedef struct Cached Cached; 13 struct Cached 14 { 15 Document *doc; 16 int page; 17 int angle; 18 Image *im; 19 }; 20 21 static Cached cache[5]; 22 23 static Image* 24 questionmark(void) 25 { 26 static Image *im; 27 28 if(im) 29 return im; 30 im = xallocimage(display, Rect(0,0,50,50), GREY1, 1, DBlack); 31 if(im == nil) 32 return nil; 33 string(im, ZP, display->white, ZP, display->defaultfont, "?"); 34 return im; 35 } 36 37 void 38 cacheflush(void) 39 { 40 int i; 41 Cached *c; 42 43 for(i=0; i<nelem(cache); i++){ 44 c = &cache[i]; 45 if(c->im) 46 freeimage(c->im); 47 c->im = nil; 48 c->doc = nil; 49 } 50 } 51 52 static Image* 53 _cachedpage(Document *doc, int angle, int page, char *ra) 54 { 55 int i; 56 Cached *c, old; 57 Image *im, *tmp; 58 static int lastpage = -1; 59 60 if((page < 0 || page >= doc->npage) && !doc->fwdonly) 61 return nil; 62 63 Again: 64 for(i=0; i<nelem(cache); i++){ 65 c = &cache[i]; 66 if(c->doc == doc && c->angle == angle && c->page == page){ 67 if(chatty) fprint(2, "cache%s hit %d\n", ra, page); 68 goto Found; 69 } 70 if(c->doc == nil) 71 break; 72 } 73 74 if(i >= nelem(cache)) 75 i = nelem(cache)-1; 76 c = &cache[i]; 77 if(c->im) 78 freeimage(c->im); 79 c->im = nil; 80 c->doc = nil; 81 c->page = -1; 82 83 if(chatty) fprint(2, "cache%s load %d\n", ra, page); 84 im = doc->drawpage(doc, page); 85 if(im == nil){ 86 if(doc->fwdonly) /* end of file */ 87 wexits(0); 88 im = questionmark(); 89 if(im == nil){ 90 Flush: 91 if(i > 0){ 92 cacheflush(); 93 goto Again; 94 } 95 fprint(2, "out of memory: %r\n"); 96 wexits("memory"); 97 } 98 return im; 99 } 100 101 if(im->r.min.x != 0 || im->r.min.y != 0){ 102 /* translate to 0,0 */ 103 tmp = xallocimage(display, Rect(0, 0, Dx(im->r), Dy(im->r)), im->chan, 0, DNofill); 104 if(tmp == nil){ 105 freeimage(im); 106 goto Flush; 107 } 108 drawop(tmp, tmp->r, im, nil, im->r.min, S); 109 freeimage(im); 110 im = tmp; 111 } 112 113 switch(angle){ 114 case 90: 115 im = rot90(im); 116 break; 117 case 180: 118 rot180(im); 119 break; 120 case 270: 121 im = rot270(im); 122 break; 123 } 124 if(im == nil) 125 goto Flush; 126 127 c->doc = doc; 128 c->page = page; 129 c->angle = angle; 130 c->im = im; 131 132 Found: 133 if(chatty) fprint(2, "cache%s mtf %d @%d:", ra, c->page, i); 134 old = *c; 135 memmove(cache+1, cache, (c-cache)*sizeof cache[0]); 136 cache[0] = old; 137 if(chatty){ 138 for(i=0; i<nelem(cache); i++) 139 fprint(2, " %d", cache[i].page); 140 fprint(2, "\n"); 141 } 142 if(chatty) fprint(2, "cache%s return %d %p\n", ra, old.page, old.im); 143 return old.im; 144 } 145 146 Image* 147 cachedpage(Document *doc, int angle, int page) 148 { 149 static int lastpage = -1; 150 static int rabusy; 151 Image *im; 152 int ra; 153 154 if(doc->npage < 1) 155 return display->white; 156 157 im = _cachedpage(doc, angle, page, ""); 158 if(im == nil) 159 return nil; 160 161 /* readahead */ 162 ra = -1; 163 if(!rabusy){ 164 if(page == lastpage+1) 165 ra = page+1; 166 else if(page == lastpage-1) 167 ra = page-1; 168 } 169 lastpage = page; 170 if(ra >= 0){ 171 rabusy = 1; 172 switch(rfork(RFPROC|RFMEM|RFNOWAIT)){ 173 case -1: 174 rabusy = 0; 175 break; 176 case 0: 177 lockdisplay(display); 178 _cachedpage(doc, angle, ra, "-ra"); 179 rabusy = 0; 180 unlockdisplay(display); 181 _exits(nil); 182 default: 183 break; 184 } 185 } 186 return im; 187 } 188