cache.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <draw.h>
  12. #include <cursor.h>
  13. #include <event.h>
  14. #include <bio.h>
  15. #include <plumb.h>
  16. #include <ctype.h>
  17. #include <keyboard.h>
  18. #include "page.h"
  19. typedef struct Cached Cached;
  20. struct Cached
  21. {
  22. Document *doc;
  23. int page;
  24. int angle;
  25. Image *im;
  26. };
  27. static Cached cache[5];
  28. static Image*
  29. questionmark(void)
  30. {
  31. static Image *im;
  32. if(im)
  33. return im;
  34. im = xallocimage(display, Rect(0,0,50,50), GREY1, 1, DBlack);
  35. if(im == nil)
  36. return nil;
  37. string(im, ZP, display->white, ZP, display->defaultfont, "?");
  38. return im;
  39. }
  40. void
  41. cacheflush(void)
  42. {
  43. int i;
  44. Cached *c;
  45. for(i=0; i<nelem(cache); i++){
  46. c = &cache[i];
  47. if(c->im)
  48. freeimage(c->im);
  49. c->im = nil;
  50. c->doc = nil;
  51. }
  52. }
  53. static Image*
  54. _cachedpage(Document *doc, int angle, int page, char *ra)
  55. {
  56. int i;
  57. Cached *c, old;
  58. Image *im, *tmp;
  59. if((page < 0 || page >= doc->npage) && !doc->fwdonly)
  60. return nil;
  61. Again:
  62. for(i=0; i<nelem(cache); i++){
  63. c = &cache[i];
  64. if(c->doc == doc && c->angle == angle && c->page == page){
  65. if(chatty) fprint(2, "cache%s hit %d\n", ra, page);
  66. goto Found;
  67. }
  68. if(c->doc == nil)
  69. break;
  70. }
  71. if(i >= nelem(cache))
  72. i = nelem(cache)-1;
  73. c = &cache[i];
  74. if(c->im)
  75. freeimage(c->im);
  76. c->im = nil;
  77. c->doc = nil;
  78. c->page = -1;
  79. if(chatty) fprint(2, "cache%s load %d\n", ra, page);
  80. im = doc->drawpage(doc, page);
  81. if(im == nil){
  82. if(doc->fwdonly) /* end of file */
  83. wexits(0);
  84. im = questionmark();
  85. if(im == nil){
  86. Flush:
  87. if(i > 0){
  88. cacheflush();
  89. goto Again;
  90. }
  91. fprint(2, "out of memory: %r\n");
  92. wexits("memory");
  93. }
  94. return im;
  95. }
  96. if(im->r.min.x != 0 || im->r.min.y != 0){
  97. /* translate to 0,0 */
  98. tmp = xallocimage(display, Rect(0, 0, Dx(im->r), Dy(im->r)), im->chan, 0, DNofill);
  99. if(tmp == nil){
  100. freeimage(im);
  101. goto Flush;
  102. }
  103. drawop(tmp, tmp->r, im, nil, im->r.min, S);
  104. freeimage(im);
  105. im = tmp;
  106. }
  107. switch(angle){
  108. case 90:
  109. im = rot90(im);
  110. break;
  111. case 180:
  112. rot180(im);
  113. break;
  114. case 270:
  115. im = rot270(im);
  116. break;
  117. }
  118. if(im == nil)
  119. goto Flush;
  120. c->doc = doc;
  121. c->page = page;
  122. c->angle = angle;
  123. c->im = im;
  124. Found:
  125. if(chatty) fprint(2, "cache%s mtf %d @%d:", ra, c->page, i);
  126. old = *c;
  127. memmove(cache+1, cache, (c-cache)*sizeof cache[0]);
  128. cache[0] = old;
  129. if(chatty){
  130. for(i=0; i<nelem(cache); i++)
  131. fprint(2, " %d", cache[i].page);
  132. fprint(2, "\n");
  133. }
  134. if(chatty) fprint(2, "cache%s return %d %p\n", ra, old.page, old.im);
  135. return old.im;
  136. }
  137. Image*
  138. cachedpage(Document *doc, int angle, int page)
  139. {
  140. static int lastpage = -1;
  141. static int rabusy;
  142. Image *im;
  143. int ra;
  144. if(doc->npage < 1)
  145. return display->white;
  146. im = _cachedpage(doc, angle, page, "");
  147. if(im == nil)
  148. return nil;
  149. /* readahead */
  150. ra = -1;
  151. if(!rabusy){
  152. if(page == lastpage+1)
  153. ra = page+1;
  154. else if(page == lastpage-1)
  155. ra = page-1;
  156. }
  157. lastpage = page;
  158. if(ra >= 0){
  159. rabusy = 1;
  160. switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
  161. case -1:
  162. rabusy = 0;
  163. break;
  164. case 0:
  165. lockdisplay(display);
  166. _cachedpage(doc, angle, ra, "-ra");
  167. rabusy = 0;
  168. unlockdisplay(display);
  169. _exits(nil);
  170. default:
  171. break;
  172. }
  173. }
  174. return im;
  175. }