tfont.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tfont.c (7635B) | |
--- | |
1 #include <u.h> | |
2 #include <libc.h> | |
3 #include <draw.h> | |
4 | |
5 static int fontresize(Font*, int, int, int); | |
6 #if 0 | |
7 static int freeup(Font*); | |
8 #endif | |
9 | |
10 #define PJW 0 /* use NUL==pjw for invisible charact… | |
11 | |
12 static Rune empty[] = { 0 }; | |
13 int | |
14 cachechars(Font *f, char **ss, Rune **rr, ushort *cp, int max, int *wp, … | |
15 { | |
16 int i, th, sh, h, ld, w, rw, wid, nc; | |
17 char *sp; | |
18 Rune r, *rp, vr; | |
19 ulong a; | |
20 Cacheinfo *c, *tc, *ec; | |
21 | |
22 if(ss){ | |
23 sp = *ss; | |
24 rp = empty; | |
25 }else{ | |
26 sp = ""; | |
27 rp = *rr; | |
28 } | |
29 wid = 0; | |
30 *subfontname = 0; | |
31 for(i=0; i<max && (*sp || *rp); sp+=w, rp+=rw){ | |
32 if(ss){ | |
33 r = *(uchar*)sp; | |
34 if(r < Runeself) | |
35 w = 1; | |
36 else{ | |
37 w = chartorune(&vr, sp); | |
38 r = vr; | |
39 } | |
40 rw = 0; | |
41 }else{ | |
42 r = *rp; | |
43 w = 0; | |
44 rw = 1; | |
45 } | |
46 | |
47 sh = (17 * (uint)r) & (f->ncache-NFLOOK-1); | |
48 c = &f->cache[sh]; | |
49 ec = c+NFLOOK; | |
50 h = sh; | |
51 while(c < ec){ | |
52 if(c->value==r && c->age) | |
53 goto Found; | |
54 c++; | |
55 h++; | |
56 } | |
57 | |
58 /* | |
59 * Not found; toss out oldest entry | |
60 */ | |
61 a = ~0; | |
62 th = sh; | |
63 tc = &f->cache[th]; | |
64 while(tc < ec){ | |
65 if(tc->age < a){ | |
66 a = tc->age; | |
67 h = th; | |
68 c = tc; | |
69 } | |
70 tc++; | |
71 th++; | |
72 } | |
73 | |
74 if(a && (f->age-a)<500){ /* kicking out too recen… | |
75 nc = 2*(f->ncache-NFLOOK) + NFLOOK; | |
76 if(nc <= MAXFCACHE){ | |
77 if(i == 0) | |
78 fontresize(f, f->width, nc, f->m… | |
79 /* else flush first; retry will resize */ | |
80 break; | |
81 } | |
82 } | |
83 | |
84 if(c->age == f->age) /* flush pending string outp… | |
85 break; | |
86 | |
87 ld = loadchar(f, r, c, h, i, subfontname); | |
88 if(ld <= 0){ | |
89 if(ld == 0) | |
90 continue; | |
91 break; | |
92 } | |
93 c = &f->cache[h]; /* may have reallocated f->cach… | |
94 | |
95 Found: | |
96 wid += c->width; | |
97 c->age = f->age; | |
98 cp[i] = h; | |
99 i++; | |
100 } | |
101 if(ss) | |
102 *ss = sp; | |
103 else | |
104 *rr = rp; | |
105 *wp = wid; | |
106 return i; | |
107 } | |
108 | |
109 void | |
110 agefont(Font *f) | |
111 { | |
112 Cacheinfo *c, *ec; | |
113 Cachesubf *s, *es; | |
114 | |
115 f->age++; | |
116 if(f->age == 65536){ | |
117 /* | |
118 * Renormalize ages | |
119 */ | |
120 c = f->cache; | |
121 ec = c+f->ncache; | |
122 while(c < ec){ | |
123 if(c->age){ | |
124 c->age >>= 2; | |
125 c->age++; | |
126 } | |
127 c++; | |
128 } | |
129 s = f->subf; | |
130 es = s+f->nsubf; | |
131 while(s < es){ | |
132 if(s->age){ | |
133 if(s->age<SUBFAGE && s->cf->name != nil){ | |
134 /* clean up */ | |
135 freesubfont(s->f); | |
136 s->cf = nil; | |
137 s->f = nil; | |
138 s->age = 0; | |
139 }else{ | |
140 s->age >>= 2; | |
141 s->age++; | |
142 } | |
143 } | |
144 s++; | |
145 } | |
146 f->age = (65536>>2) + 1; | |
147 } | |
148 } | |
149 | |
150 static Subfont* | |
151 cf2subfont(Cachefont *cf, Font *f) | |
152 { | |
153 int depth; | |
154 char *name; | |
155 Subfont *sf; | |
156 | |
157 name = cf->subfontname; | |
158 if(name == nil){ | |
159 depth = 0; | |
160 if(f->display){ | |
161 if(f->display->screenimage) | |
162 depth = f->display->screenimage->depth; | |
163 }else | |
164 depth = 8; | |
165 name = subfontname(cf->name, f->name, depth); | |
166 if(name == nil) | |
167 return nil; | |
168 cf->subfontname = name; | |
169 } | |
170 sf = lookupsubfont(f->display, name); | |
171 return sf; | |
172 } | |
173 | |
174 /* return 1 if load succeeded, 0 if failed, -1 if must retry */ | |
175 int | |
176 loadchar(Font *f, Rune r, Cacheinfo *c, int h, int noflush, char **subfo… | |
177 { | |
178 int i, oi, wid, top, bottom; | |
179 int pic; /* need >16 bits for adding offset below */ | |
180 Fontchar *fi; | |
181 Cachefont *cf; | |
182 Cachesubf *subf, *of; | |
183 uchar *b; | |
184 | |
185 pic = r; | |
186 Again: | |
187 for(i=0; i<f->nsub; i++){ | |
188 cf = f->sub[i]; | |
189 if(cf->min<=pic && pic<=cf->max) | |
190 goto Found; | |
191 } | |
192 TryPJW: | |
193 if(pic != PJW){ | |
194 pic = PJW; | |
195 goto Again; | |
196 } | |
197 return 0; | |
198 | |
199 Found: | |
200 /* | |
201 * Choose exact or oldest | |
202 */ | |
203 oi = 0; | |
204 subf = &f->subf[0]; | |
205 for(i=0; i<f->nsubf; i++){ | |
206 if(cf == subf->cf) | |
207 goto Found2; | |
208 if(subf->age < f->subf[oi].age) | |
209 oi = i; | |
210 subf++; | |
211 } | |
212 subf = &f->subf[oi]; | |
213 | |
214 if(subf->f){ | |
215 if(f->age-subf->age>SUBFAGE || f->nsubf>MAXSUBF){ | |
216 Toss: | |
217 /* ancient data; toss */ | |
218 freesubfont(subf->f); | |
219 subf->cf = nil; | |
220 subf->f = nil; | |
221 subf->age = 0; | |
222 }else{ /* too recent; gro… | |
223 of = f->subf; | |
224 f->subf = realloc(of, (f->nsubf+DSUBF)*sizeof *s… | |
225 if(f->subf == nil){ | |
226 f->subf = of; | |
227 goto Toss; | |
228 } | |
229 memset(f->subf+f->nsubf, 0, DSUBF*sizeof *subf); | |
230 subf = &f->subf[f->nsubf]; | |
231 f->nsubf += DSUBF; | |
232 } | |
233 } | |
234 subf->age = 0; | |
235 subf->cf = nil; | |
236 subf->f = cf2subfont(cf, f); | |
237 if(subf->f == nil){ | |
238 if(cf->subfontname == nil) | |
239 goto TryPJW; | |
240 *subfontname = cf->subfontname; | |
241 return -1; | |
242 } | |
243 | |
244 subf->cf = cf; | |
245 if(subf->f->ascent > f->ascent && f->display){ | |
246 /* should print something? this is a mistake in the font… | |
247 /* must prevent c->top from going negative when loading … | |
248 Image *b; | |
249 int d, t; | |
250 d = subf->f->ascent - f->ascent; | |
251 b = subf->f->bits; | |
252 draw(b, b->r, b, nil, addpt(b->r.min, Pt(0, d))); | |
253 draw(b, Rect(b->r.min.x, b->r.max.y-d, b->r.max.x, b->r.… | |
254 for(i=0; i<subf->f->n; i++){ | |
255 t = subf->f->info[i].top-d; | |
256 if(t < 0) | |
257 t = 0; | |
258 subf->f->info[i].top = t; | |
259 t = subf->f->info[i].bottom-d; | |
260 if(t < 0) | |
261 t = 0; | |
262 subf->f->info[i].bottom = t; | |
263 } | |
264 subf->f->ascent = f->ascent; | |
265 } | |
266 | |
267 Found2: | |
268 subf->age = f->age; | |
269 | |
270 /* possible overflow here, but works out okay */ | |
271 pic += cf->offset; | |
272 pic -= cf->min; | |
273 if(pic >= subf->f->n) | |
274 goto TryPJW; | |
275 fi = &subf->f->info[pic]; | |
276 if(fi->width == 0) | |
277 goto TryPJW; | |
278 wid = (fi+1)->x - fi->x; | |
279 if(f->width < wid || f->width == 0 || f->maxdepth < subf->f->bit… | |
280 /* | |
281 * Flush, free, reload (easier than reformatting f->b) | |
282 */ | |
283 if(noflush) | |
284 return -1; | |
285 if(f->width < wid) | |
286 f->width = wid; | |
287 if(f->maxdepth < subf->f->bits->depth) | |
288 f->maxdepth = subf->f->bits->depth; | |
289 i = fontresize(f, f->width, f->ncache, f->maxdepth); | |
290 if(i <= 0) | |
291 return i; | |
292 /* c is still valid as didn't reallocate f->cache */ | |
293 } | |
294 c->value = r; | |
295 top = fi->top + (f->ascent-subf->f->ascent); | |
296 bottom = fi->bottom + (f->ascent-subf->f->ascent); | |
297 c->width = fi->width; | |
298 c->x = h*f->width; | |
299 c->left = fi->left; | |
300 if(f->display == nil) | |
301 return 1; | |
302 flushimage(f->display, 0); /* flush any pending errors */ | |
303 b = bufimage(f->display, 37); | |
304 if(b == 0) | |
305 return 0; | |
306 b[0] = 'l'; | |
307 BPLONG(b+1, f->cacheimage->id); | |
308 BPLONG(b+5, subf->f->bits->id); | |
309 BPSHORT(b+9, c-f->cache); | |
310 BPLONG(b+11, c->x); | |
311 BPLONG(b+15, top); | |
312 BPLONG(b+19, c->x+((fi+1)->x-fi->x)); | |
313 BPLONG(b+23, bottom); | |
314 BPLONG(b+27, fi->x); | |
315 BPLONG(b+31, fi->top); | |
316 b[35] = fi->left; | |
317 b[36] = fi->width; | |
318 return 1; | |
319 } | |
320 | |
321 /* release all subfonts, return number freed */ | |
322 #if 0 | |
323 static | |
324 int | |
325 freeup(Font *f) | |
326 { | |
327 Cachesubf *s, *es; | |
328 int nf; | |
329 | |
330 if(f->sub[0]->name == nil) /* font from mkfont; don't fre… | |
331 return 0; | |
332 s = f->subf; | |
333 es = s+f->nsubf; | |
334 nf = 0; | |
335 while(s < es){ | |
336 if(s->age){ | |
337 freesubfont(s->f); | |
338 s->cf = nil; | |
339 s->f = nil; | |
340 s->age = 0; | |
341 nf++; | |
342 } | |
343 s++; | |
344 } | |
345 return nf; | |
346 } | |
347 #endif | |
348 | |
349 /* return whether resize succeeded && f->cache is unchanged */ | |
350 static int | |
351 fontresize(Font *f, int wid, int ncache, int depth) | |
352 { | |
353 Cacheinfo *i; | |
354 int ret; | |
355 Image *new; | |
356 uchar *b; | |
357 Display *d; | |
358 | |
359 ret = 0; | |
360 if(depth <= 0) | |
361 depth = 1; | |
362 | |
363 d = f->display; | |
364 if(d == nil) | |
365 goto Nodisplay; | |
366 | |
367 new = allocimage(d, Rect(0, 0, ncache*wid, f->height), CHAN1(CGr… | |
368 if(new == nil){ | |
369 fprint(2, "font cache resize failed: %r\n"); | |
370 abort(); | |
371 goto Return; | |
372 } | |
373 flushimage(d, 0); /* flush any pending errors */ | |
374 b = bufimage(d, 1+4+4+1); | |
375 if(b == 0){ | |
376 freeimage(new); | |
377 goto Return; | |
378 } | |
379 b[0] = 'i'; | |
380 BPLONG(b+1, new->id); | |
381 BPLONG(b+5, ncache); | |
382 b[9] = f->ascent; | |
383 if(flushimage(d, 0) < 0){ | |
384 fprint(2, "resize: init failed: %r\n"); | |
385 freeimage(new); | |
386 goto Return; | |
387 } | |
388 freeimage(f->cacheimage); | |
389 f->cacheimage = new; | |
390 Nodisplay: | |
391 f->width = wid; | |
392 f->maxdepth = depth; | |
393 ret = 1; | |
394 if(f->ncache != ncache){ | |
395 i = malloc(ncache*sizeof f->cache[0]); | |
396 if(i != nil){ | |
397 ret = 0; | |
398 free(f->cache); | |
399 f->ncache = ncache; | |
400 f->cache = i; | |
401 } | |
402 /* else just wipe the cache clean and things will be ok … | |
403 } | |
404 Return: | |
405 memset(f->cache, 0, f->ncache*sizeof f->cache[0]); | |
406 return ret; | |
407 } |