cache.c 3.1 KB

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