1 /* imgcache.c
2 * Image cache
3 * (c) 2002 Mikulas Patocka
4 * This file is a part of the Links program, released under GPL.
5 */
6
7 #include "cfg.h"
8
9 #ifdef G
10
11 #include "links.h"
12
13 static struct list_head image_cache_ref = { &image_cache_ref, &image_cache_ref };
14 static struct list_head image_cache_deref = { &image_cache_deref, &image_cache_deref };
15
16 #define CACHED_IMAGE_HASH_SIZE 1024
17 static struct cached_image *image_hash[CACHED_IMAGE_HASH_SIZE];
18
hash_image(int bg,unsigned char * url,int xw,int yw,int xyw_meaning)19 static unsigned hash_image(int bg, unsigned char *url, int xw, int yw, int xyw_meaning)
20 {
21 unsigned hash = hash_string(url);
22 hash = hash * 0x55 + bg;
23 hash = hash * 0x55 + xw;
24 hash = hash * 0x55 + yw;
25 hash = hash * 0x55 + xyw_meaning;
26 return hash % CACHED_IMAGE_HASH_SIZE;
27 }
28
29 /* xyw_meaning either MEANING_DIMS or MEANING_AUTOSCALE. */
find_cached_image(int bg,unsigned char * url,int xw,int yw,int xyw_meaning,int scale,unsigned aspect)30 struct cached_image *find_cached_image(int bg, unsigned char *url, int xw, int yw, int xyw_meaning, int scale, unsigned aspect)
31 {
32 struct cached_image *i;
33 unsigned hash = hash_image(bg, url, xw, yw, xyw_meaning);
34 if (xw >= 0 && yw >= 0 && xyw_meaning == MEANING_DIMS) {
35 /* The xw and yw is already scaled so that scale and
36 * aspect don't matter.
37 */
38 for (i = image_hash[hash]; i; i = i->hash_fwdlink) {
39 if (i->background_color == bg
40 && !strcmp(cast_const_char i->url, cast_const_char url)
41 && i->wanted_xw == xw
42 && i->wanted_yw == yw
43 && i->wanted_xyw_meaning == xyw_meaning
44 ) goto hit;
45 }
46 } else {
47 for (i = image_hash[hash]; i; i = i->hash_fwdlink) {
48 if (i->background_color == bg
49 && !strcmp(cast_const_char i->url, cast_const_char url)
50 && i->wanted_xw == xw
51 && i->wanted_yw == yw
52 && i->wanted_xyw_meaning == xyw_meaning
53 && i->scale == scale
54 && i->aspect == aspect
55 ) goto hit;
56 }
57 }
58 return NULL;
59
60 hit:
61 i->cimg_refcount++;
62 del_from_list(i);
63 add_to_list(image_cache_ref, i);
64 return i;
65 }
66
add_image_to_cache(struct cached_image * ci)67 void add_image_to_cache(struct cached_image *ci)
68 {
69 unsigned hash = hash_image(ci->background_color, ci->url, (int)ci->wanted_xw, (int)ci->wanted_yw, ci->wanted_xyw_meaning);
70 ci->hash_fwdlink = image_hash[hash];
71 if (ci->hash_fwdlink)
72 ci->hash_fwdlink->hash_backlink = &ci->hash_fwdlink;
73 ci->hash_backlink = &image_hash[hash];
74 image_hash[hash] = ci;
75 ci->cimg_refcount = 1;
76 add_to_list(image_cache_ref, ci);
77 }
78
deref_cached_image(struct cached_image * ci)79 void deref_cached_image(struct cached_image *ci)
80 {
81 if (ci->cimg_refcount <= 0)
82 internal_error("deref_cached_image: refcount underflow: %d", ci->cimg_refcount);
83 ci->cimg_refcount--;
84 if (!ci->cimg_refcount) {
85 del_from_list(ci);
86 add_to_list(image_cache_deref, ci);
87 }
88 }
89
image_size(struct cached_image * cimg)90 static unsigned long image_size(struct cached_image *cimg)
91 {
92 unsigned long siz = sizeof(struct cached_image);
93 switch (cimg->state) {
94 case 0:
95 case 1:
96 case 2:
97 case 3:
98 case 8:
99 case 9:
100 case 10:
101 case 11:
102 break;
103
104 case 12:
105 case 14:
106 siz += (unsigned long)cimg->width * cimg->height * cimg->buffer_bytes_per_pixel;
107 if (cimg->bmp_used){
108 case 13:
109 case 15:
110 siz += (unsigned long)cimg->bmp.x * cimg->bmp.y * (drv->depth & 7);
111 }
112 break;
113
114 #ifdef DEBUG
115 default:
116 fprintf(stderr, "cimg->state=%d\n", cimg->state);
117 internal_error("Invalid cimg->state in image_size\n");
118 break;
119 #endif /* #ifdef DEBUG */
120 }
121 return siz;
122 }
123
shrink_image_cache(int u)124 static int shrink_image_cache(int u)
125 {
126 struct cached_image *i;
127 struct list_head *li;
128 longlong si = 0;
129 int r = 0;
130 foreach(struct cached_image, i, li, image_cache_deref) si += image_size(i);
131 foreachback(struct cached_image, i, li, image_cache_deref) {
132 if (si <= image_cache_size && u == SH_CHECK_QUOTA)
133 break;
134 li = li->next;
135 r = ST_SOMETHING_FREED;
136 si -= image_size(i);
137 del_from_list(i);
138 if (i->hash_fwdlink)
139 i->hash_fwdlink->hash_backlink = i->hash_backlink;
140 *i->hash_backlink = i->hash_fwdlink;
141 img_destruct_cached_image(i);
142 if (u == SH_FREE_SOMETHING) break;
143 }
144 return r | (list_empty(image_cache_deref) && list_empty(image_cache_ref) ? ST_CACHE_EMPTY : 0);
145 }
146
imgcache_info(int type)147 my_uintptr_t imgcache_info(int type)
148 {
149 struct cached_image *i;
150 struct list_head *li;
151 my_uintptr_t n = 0;
152 foreach(struct cached_image, i, li, image_cache_ref) {
153 switch (type) {
154 case CI_BYTES:
155 n += image_size(i);
156 break;
157 case CI_LOCKED:
158 case CI_FILES:
159 n++;
160 break;
161 default:
162 internal_error("imgcache_info: query %d", type);
163 }
164 }
165 foreach(struct cached_image, i, li, image_cache_deref) {
166 switch (type) {
167 case CI_BYTES:
168 n += image_size(i);
169 break;
170 case CI_LOCKED:
171 break;
172 case CI_FILES:
173 n++;
174 break;
175 default:
176 internal_error("imgcache_info: query %d", type);
177 }
178 }
179 return n;
180 }
181
init_imgcache(void)182 void init_imgcache(void)
183 {
184 unsigned i;
185 register_cache_upcall(shrink_image_cache, MF_GPI, cast_uchar "imgcache");
186 for (i = 0; i < CACHED_IMAGE_HASH_SIZE; i++)
187 image_hash[i] = NULL;
188 }
189
190 #endif
191