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 Cached15 {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 void41 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;111 }112 fprint(2, "out of memory: %r\n");113 wexits("memory");114 }115 return im;116 }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 }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;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");159 }160 if(chatty) fprint(2, "cache%s return %d %p\n", ra, old.page, old.im);161 return old.im;162 }164 static void165 raproc(void *a)166 {167 Cached *c;169 c = a;170 lockdisplay(display);171 /*172 * If there is only one page in a fwdonly file, we may reach EOF173 * 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 }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;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;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 }