1 76193d7c 2003-09-30 devnull #include <u.h>
2 76193d7c 2003-09-30 devnull #include <libc.h>
3 76193d7c 2003-09-30 devnull #include <draw.h>
5 76193d7c 2003-09-30 devnull static int fontresize(Font*, int, int, int);
7 76193d7c 2003-09-30 devnull static int freeup(Font*);
10 76193d7c 2003-09-30 devnull #define PJW 0 /* use NUL==pjw for invisible characters */
12 76193d7c 2003-09-30 devnull static Rune empty[] = { 0 };
14 76193d7c 2003-09-30 devnull cachechars(Font *f, char **ss, Rune **rr, ushort *cp, int max, int *wp, char **subfontname)
16 76193d7c 2003-09-30 devnull int i, th, sh, h, ld, w, rw, wid, nc;
17 76193d7c 2003-09-30 devnull char *sp;
18 76193d7c 2003-09-30 devnull Rune r, *rp, vr;
20 76193d7c 2003-09-30 devnull Cacheinfo *c, *tc, *ec;
23 76193d7c 2003-09-30 devnull sp = *ss;
24 76193d7c 2003-09-30 devnull rp = empty;
27 76193d7c 2003-09-30 devnull rp = *rr;
30 76193d7c 2003-09-30 devnull *subfontname = 0;
31 15680d56 2004-03-05 devnull for(i=0; i<max && (*sp || *rp); sp+=w, rp+=rw){
33 76193d7c 2003-09-30 devnull r = *(uchar*)sp;
34 76193d7c 2003-09-30 devnull if(r < Runeself)
37 76193d7c 2003-09-30 devnull w = chartorune(&vr, sp);
47 76193d7c 2003-09-30 devnull sh = (17 * (uint)r) & (f->ncache-NFLOOK-1);
48 76193d7c 2003-09-30 devnull c = &f->cache[sh];
49 76193d7c 2003-09-30 devnull ec = c+NFLOOK;
51 76193d7c 2003-09-30 devnull while(c < ec){
52 76193d7c 2003-09-30 devnull if(c->value==r && c->age)
53 76193d7c 2003-09-30 devnull goto Found;
59 76193d7c 2003-09-30 devnull * Not found; toss out oldest entry
63 76193d7c 2003-09-30 devnull tc = &f->cache[th];
64 76193d7c 2003-09-30 devnull while(tc < ec){
65 76193d7c 2003-09-30 devnull if(tc->age < a){
66 76193d7c 2003-09-30 devnull a = tc->age;
74 76193d7c 2003-09-30 devnull if(a && (f->age-a)<500){ /* kicking out too recent; resize */
75 76193d7c 2003-09-30 devnull nc = 2*(f->ncache-NFLOOK) + NFLOOK;
76 76193d7c 2003-09-30 devnull if(nc <= MAXFCACHE){
77 76193d7c 2003-09-30 devnull if(i == 0)
78 76193d7c 2003-09-30 devnull fontresize(f, f->width, nc, f->maxdepth);
79 76193d7c 2003-09-30 devnull /* else flush first; retry will resize */
84 76193d7c 2003-09-30 devnull if(c->age == f->age) /* flush pending string output */
87 76193d7c 2003-09-30 devnull ld = loadchar(f, r, c, h, i, subfontname);
88 76193d7c 2003-09-30 devnull if(ld <= 0){
89 76193d7c 2003-09-30 devnull if(ld == 0)
90 76193d7c 2003-09-30 devnull continue;
93 76193d7c 2003-09-30 devnull c = &f->cache[h]; /* may have reallocated f->cache */
96 76193d7c 2003-09-30 devnull wid += c->width;
97 76193d7c 2003-09-30 devnull c->age = f->age;
98 76193d7c 2003-09-30 devnull cp[i] = h;
102 76193d7c 2003-09-30 devnull *ss = sp;
104 76193d7c 2003-09-30 devnull *rr = rp;
105 76193d7c 2003-09-30 devnull *wp = wid;
106 76193d7c 2003-09-30 devnull return i;
110 76193d7c 2003-09-30 devnull agefont(Font *f)
112 76193d7c 2003-09-30 devnull Cacheinfo *c, *ec;
113 76193d7c 2003-09-30 devnull Cachesubf *s, *es;
115 76193d7c 2003-09-30 devnull f->age++;
116 76193d7c 2003-09-30 devnull if(f->age == 65536){
118 76193d7c 2003-09-30 devnull * Renormalize ages
120 76193d7c 2003-09-30 devnull c = f->cache;
121 76193d7c 2003-09-30 devnull ec = c+f->ncache;
122 76193d7c 2003-09-30 devnull while(c < ec){
123 76193d7c 2003-09-30 devnull if(c->age){
124 76193d7c 2003-09-30 devnull c->age >>= 2;
125 76193d7c 2003-09-30 devnull c->age++;
129 76193d7c 2003-09-30 devnull s = f->subf;
130 76193d7c 2003-09-30 devnull es = s+f->nsubf;
131 76193d7c 2003-09-30 devnull while(s < es){
132 76193d7c 2003-09-30 devnull if(s->age){
133 76193d7c 2003-09-30 devnull if(s->age<SUBFAGE && s->cf->name != nil){
134 76193d7c 2003-09-30 devnull /* clean up */
135 76193d7c 2003-09-30 devnull if(s->f != display->defaultsubfont)
136 76193d7c 2003-09-30 devnull freesubfont(s->f);
137 76193d7c 2003-09-30 devnull s->cf = nil;
138 76193d7c 2003-09-30 devnull s->f = nil;
139 76193d7c 2003-09-30 devnull s->age = 0;
141 76193d7c 2003-09-30 devnull s->age >>= 2;
142 76193d7c 2003-09-30 devnull s->age++;
147 76193d7c 2003-09-30 devnull f->age = (65536>>2) + 1;
151 76193d7c 2003-09-30 devnull static Subfont*
152 76193d7c 2003-09-30 devnull cf2subfont(Cachefont *cf, Font *f)
154 76193d7c 2003-09-30 devnull int depth;
155 76193d7c 2003-09-30 devnull char *name;
156 76193d7c 2003-09-30 devnull Subfont *sf;
158 76193d7c 2003-09-30 devnull name = cf->subfontname;
159 76193d7c 2003-09-30 devnull if(name == nil){
160 76193d7c 2003-09-30 devnull depth = 0;
161 76193d7c 2003-09-30 devnull if(f->display){
162 76193d7c 2003-09-30 devnull if(f->display->screenimage)
163 76193d7c 2003-09-30 devnull depth = f->display->screenimage->depth;
165 4e206880 2004-04-25 devnull depth = 8;
166 76193d7c 2003-09-30 devnull name = subfontname(cf->name, f->name, depth);
167 76193d7c 2003-09-30 devnull if(name == nil)
168 76193d7c 2003-09-30 devnull return nil;
169 76193d7c 2003-09-30 devnull cf->subfontname = name;
171 76193d7c 2003-09-30 devnull sf = lookupsubfont(f->display, name);
172 76193d7c 2003-09-30 devnull return sf;
175 76193d7c 2003-09-30 devnull /* return 1 if load succeeded, 0 if failed, -1 if must retry */
177 76193d7c 2003-09-30 devnull loadchar(Font *f, Rune r, Cacheinfo *c, int h, int noflush, char **subfontname)
179 76193d7c 2003-09-30 devnull int i, oi, wid, top, bottom;
180 76193d7c 2003-09-30 devnull Rune pic;
181 76193d7c 2003-09-30 devnull Fontchar *fi;
182 76193d7c 2003-09-30 devnull Cachefont *cf;
183 76193d7c 2003-09-30 devnull Cachesubf *subf, *of;
184 76193d7c 2003-09-30 devnull uchar *b;
186 76193d7c 2003-09-30 devnull pic = r;
188 76193d7c 2003-09-30 devnull for(i=0; i<f->nsub; i++){
189 76193d7c 2003-09-30 devnull cf = f->sub[i];
190 76193d7c 2003-09-30 devnull if(cf->min<=pic && pic<=cf->max)
191 76193d7c 2003-09-30 devnull goto Found;
194 76193d7c 2003-09-30 devnull if(pic != PJW){
195 76193d7c 2003-09-30 devnull pic = PJW;
196 76193d7c 2003-09-30 devnull goto Again;
198 76193d7c 2003-09-30 devnull return 0;
202 76193d7c 2003-09-30 devnull * Choose exact or oldest
205 76193d7c 2003-09-30 devnull subf = &f->subf[0];
206 76193d7c 2003-09-30 devnull for(i=0; i<f->nsubf; i++){
207 76193d7c 2003-09-30 devnull if(cf == subf->cf)
208 76193d7c 2003-09-30 devnull goto Found2;
209 76193d7c 2003-09-30 devnull if(subf->age < f->subf[oi].age)
213 76193d7c 2003-09-30 devnull subf = &f->subf[oi];
215 76193d7c 2003-09-30 devnull if(subf->f){
216 76193d7c 2003-09-30 devnull if(f->age-subf->age>SUBFAGE || f->nsubf>MAXSUBF){
218 76193d7c 2003-09-30 devnull /* ancient data; toss */
219 76193d7c 2003-09-30 devnull freesubfont(subf->f);
220 76193d7c 2003-09-30 devnull subf->cf = nil;
221 76193d7c 2003-09-30 devnull subf->f = nil;
222 76193d7c 2003-09-30 devnull subf->age = 0;
223 76193d7c 2003-09-30 devnull }else{ /* too recent; grow instead */
224 76193d7c 2003-09-30 devnull of = f->subf;
225 76193d7c 2003-09-30 devnull f->subf = malloc((f->nsubf+DSUBF)*sizeof *subf);
226 76193d7c 2003-09-30 devnull if(f->subf == nil){
227 76193d7c 2003-09-30 devnull f->subf = of;
228 76193d7c 2003-09-30 devnull goto Toss;
230 76193d7c 2003-09-30 devnull memmove(f->subf, of, (f->nsubf+DSUBF)*sizeof *subf);
231 76193d7c 2003-09-30 devnull memset(f->subf+f->nsubf, 0, DSUBF*sizeof *subf);
232 76193d7c 2003-09-30 devnull subf = &f->subf[f->nsubf];
233 76193d7c 2003-09-30 devnull f->nsubf += DSUBF;
234 76193d7c 2003-09-30 devnull free(of);
237 76193d7c 2003-09-30 devnull subf->age = 0;
238 76193d7c 2003-09-30 devnull subf->cf = nil;
239 76193d7c 2003-09-30 devnull subf->f = cf2subfont(cf, f);
240 76193d7c 2003-09-30 devnull if(subf->f == nil){
241 76193d7c 2003-09-30 devnull if(cf->subfontname == nil)
242 76193d7c 2003-09-30 devnull goto TryPJW;
243 76193d7c 2003-09-30 devnull *subfontname = cf->subfontname;
244 76193d7c 2003-09-30 devnull return -1;
247 76193d7c 2003-09-30 devnull subf->cf = cf;
248 4e206880 2004-04-25 devnull if(subf->f->ascent > f->ascent && f->display){
249 76193d7c 2003-09-30 devnull /* should print something? this is a mistake in the font file */
250 76193d7c 2003-09-30 devnull /* must prevent c->top from going negative when loading cache */
251 76193d7c 2003-09-30 devnull Image *b;
252 76193d7c 2003-09-30 devnull int d, t;
253 76193d7c 2003-09-30 devnull d = subf->f->ascent - f->ascent;
254 76193d7c 2003-09-30 devnull b = subf->f->bits;
255 76193d7c 2003-09-30 devnull draw(b, b->r, b, nil, addpt(b->r.min, Pt(0, d)));
256 76193d7c 2003-09-30 devnull draw(b, Rect(b->r.min.x, b->r.max.y-d, b->r.max.x, b->r.max.y), f->display->black, nil, b->r.min);
257 76193d7c 2003-09-30 devnull for(i=0; i<subf->f->n; i++){
258 76193d7c 2003-09-30 devnull t = subf->f->info[i].top-d;
259 76193d7c 2003-09-30 devnull if(t < 0)
261 76193d7c 2003-09-30 devnull subf->f->info[i].top = t;
262 76193d7c 2003-09-30 devnull t = subf->f->info[i].bottom-d;
263 76193d7c 2003-09-30 devnull if(t < 0)
265 76193d7c 2003-09-30 devnull subf->f->info[i].bottom = t;
267 76193d7c 2003-09-30 devnull subf->f->ascent = f->ascent;
271 76193d7c 2003-09-30 devnull subf->age = f->age;
273 76193d7c 2003-09-30 devnull pic += cf->offset;
274 76193d7c 2003-09-30 devnull if(pic-cf->min >= subf->f->n)
275 76193d7c 2003-09-30 devnull goto TryPJW;
276 76193d7c 2003-09-30 devnull fi = &subf->f->info[pic - cf->min];
277 76193d7c 2003-09-30 devnull if(fi->width == 0)
278 76193d7c 2003-09-30 devnull goto TryPJW;
279 76193d7c 2003-09-30 devnull wid = (fi+1)->x - fi->x;
280 76193d7c 2003-09-30 devnull if(f->width < wid || f->width == 0 || f->maxdepth < subf->f->bits->depth){
282 76193d7c 2003-09-30 devnull * Flush, free, reload (easier than reformatting f->b)
284 76193d7c 2003-09-30 devnull if(noflush)
285 76193d7c 2003-09-30 devnull return -1;
286 76193d7c 2003-09-30 devnull if(f->width < wid)
287 76193d7c 2003-09-30 devnull f->width = wid;
288 76193d7c 2003-09-30 devnull if(f->maxdepth < subf->f->bits->depth)
289 76193d7c 2003-09-30 devnull f->maxdepth = subf->f->bits->depth;
290 76193d7c 2003-09-30 devnull i = fontresize(f, f->width, f->ncache, f->maxdepth);
291 76193d7c 2003-09-30 devnull if(i <= 0)
292 76193d7c 2003-09-30 devnull return i;
293 76193d7c 2003-09-30 devnull /* c is still valid as didn't reallocate f->cache */
295 76193d7c 2003-09-30 devnull c->value = r;
296 76193d7c 2003-09-30 devnull top = fi->top + (f->ascent-subf->f->ascent);
297 76193d7c 2003-09-30 devnull bottom = fi->bottom + (f->ascent-subf->f->ascent);
298 76193d7c 2003-09-30 devnull c->width = fi->width;
299 76193d7c 2003-09-30 devnull c->x = h*f->width;
300 76193d7c 2003-09-30 devnull c->left = fi->left;
301 4e206880 2004-04-25 devnull if(f->display == nil)
302 4e206880 2004-04-25 devnull return 1;
303 76193d7c 2003-09-30 devnull flushimage(f->display, 0); /* flush any pending errors */
304 76193d7c 2003-09-30 devnull b = bufimage(f->display, 37);
305 76193d7c 2003-09-30 devnull if(b == 0)
306 76193d7c 2003-09-30 devnull return 0;
307 76193d7c 2003-09-30 devnull b[0] = 'l';
308 76193d7c 2003-09-30 devnull BPLONG(b+1, f->cacheimage->id);
309 76193d7c 2003-09-30 devnull BPLONG(b+5, subf->f->bits->id);
310 76193d7c 2003-09-30 devnull BPSHORT(b+9, c-f->cache);
311 76193d7c 2003-09-30 devnull BPLONG(b+11, c->x);
312 76193d7c 2003-09-30 devnull BPLONG(b+15, top);
313 76193d7c 2003-09-30 devnull BPLONG(b+19, c->x+((fi+1)->x-fi->x));
314 76193d7c 2003-09-30 devnull BPLONG(b+23, bottom);
315 76193d7c 2003-09-30 devnull BPLONG(b+27, fi->x);
316 76193d7c 2003-09-30 devnull BPLONG(b+31, fi->top);
317 76193d7c 2003-09-30 devnull b[35] = fi->left;
318 76193d7c 2003-09-30 devnull b[36] = fi->width;
319 76193d7c 2003-09-30 devnull return 1;
322 76193d7c 2003-09-30 devnull /* release all subfonts, return number freed */
326 76193d7c 2003-09-30 devnull freeup(Font *f)
328 76193d7c 2003-09-30 devnull Cachesubf *s, *es;
331 76193d7c 2003-09-30 devnull if(f->sub[0]->name == nil) /* font from mkfont; don't free */
332 76193d7c 2003-09-30 devnull return 0;
333 76193d7c 2003-09-30 devnull s = f->subf;
334 76193d7c 2003-09-30 devnull es = s+f->nsubf;
336 76193d7c 2003-09-30 devnull while(s < es){
337 76193d7c 2003-09-30 devnull if(s->age){
338 76193d7c 2003-09-30 devnull freesubfont(s->f);
339 76193d7c 2003-09-30 devnull s->cf = nil;
340 76193d7c 2003-09-30 devnull s->f = nil;
341 76193d7c 2003-09-30 devnull s->age = 0;
346 76193d7c 2003-09-30 devnull return nf;
350 76193d7c 2003-09-30 devnull /* return whether resize succeeded && f->cache is unchanged */
351 76193d7c 2003-09-30 devnull static int
352 76193d7c 2003-09-30 devnull fontresize(Font *f, int wid, int ncache, int depth)
354 76193d7c 2003-09-30 devnull Cacheinfo *i;
355 76193d7c 2003-09-30 devnull int ret;
356 76193d7c 2003-09-30 devnull Image *new;
357 76193d7c 2003-09-30 devnull uchar *b;
358 76193d7c 2003-09-30 devnull Display *d;
360 76193d7c 2003-09-30 devnull ret = 0;
361 76193d7c 2003-09-30 devnull if(depth <= 0)
362 76193d7c 2003-09-30 devnull depth = 1;
364 4e206880 2004-04-25 devnull d = f->display;
365 4e206880 2004-04-25 devnull if(d == nil)
366 4e206880 2004-04-25 devnull goto Nodisplay;
368 76193d7c 2003-09-30 devnull new = allocimage(d, Rect(0, 0, ncache*wid, f->height), CHAN1(CGrey, depth), 0, 0);
369 76193d7c 2003-09-30 devnull if(new == nil){
370 76193d7c 2003-09-30 devnull fprint(2, "font cache resize failed: %r\n");
371 76193d7c 2003-09-30 devnull abort();
372 76193d7c 2003-09-30 devnull goto Return;
374 76193d7c 2003-09-30 devnull flushimage(d, 0); /* flush any pending errors */
375 76193d7c 2003-09-30 devnull b = bufimage(d, 1+4+4+1);
376 76193d7c 2003-09-30 devnull if(b == 0){
377 76193d7c 2003-09-30 devnull freeimage(new);
378 76193d7c 2003-09-30 devnull goto Return;
380 76193d7c 2003-09-30 devnull b[0] = 'i';
381 76193d7c 2003-09-30 devnull BPLONG(b+1, new->id);
382 76193d7c 2003-09-30 devnull BPLONG(b+5, ncache);
383 76193d7c 2003-09-30 devnull b[9] = f->ascent;
384 76193d7c 2003-09-30 devnull if(flushimage(d, 0) < 0){
385 76193d7c 2003-09-30 devnull fprint(2, "resize: init failed: %r\n");
386 76193d7c 2003-09-30 devnull freeimage(new);
387 76193d7c 2003-09-30 devnull goto Return;
389 76193d7c 2003-09-30 devnull freeimage(f->cacheimage);
390 76193d7c 2003-09-30 devnull f->cacheimage = new;
391 4e206880 2004-04-25 devnull Nodisplay:
392 76193d7c 2003-09-30 devnull f->width = wid;
393 76193d7c 2003-09-30 devnull f->maxdepth = depth;
394 76193d7c 2003-09-30 devnull ret = 1;
395 76193d7c 2003-09-30 devnull if(f->ncache != ncache){
396 76193d7c 2003-09-30 devnull i = malloc(ncache*sizeof f->cache[0]);
397 76193d7c 2003-09-30 devnull if(i != nil){
398 76193d7c 2003-09-30 devnull ret = 0;
399 76193d7c 2003-09-30 devnull free(f->cache);
400 76193d7c 2003-09-30 devnull f->ncache = ncache;
401 76193d7c 2003-09-30 devnull f->cache = i;
403 76193d7c 2003-09-30 devnull /* else just wipe the cache clean and things will be ok */
406 76193d7c 2003-09-30 devnull memset(f->cache, 0, f->ncache*sizeof f->cache[0]);
407 76193d7c 2003-09-30 devnull return ret;