plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }