xref: /plan9/sys/src/libdraw/font.c (revision 6bbfed0d85c6d7248503ef0614d0f1e40438b735)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier 
57dd7cddfSDavid du Colombier static int	fontresize(Font*, int, int, int);
67dd7cddfSDavid du Colombier static int	freeup(Font*);
77dd7cddfSDavid du Colombier 
87dd7cddfSDavid du Colombier #define	PJW	0	/* use NUL==pjw for invisible characters */
97dd7cddfSDavid du Colombier 
107dd7cddfSDavid du Colombier int
cachechars(Font * f,char ** ss,Rune ** rr,ushort * cp,int max,int * wp,char ** subfontname)117dd7cddfSDavid du Colombier cachechars(Font *f, char **ss, Rune **rr, ushort *cp, int max, int *wp, char **subfontname)
127dd7cddfSDavid du Colombier {
137dd7cddfSDavid du Colombier 	int i, th, sh, h, ld, w, rw, wid, nc;
147dd7cddfSDavid du Colombier 	char *sp;
157dd7cddfSDavid du Colombier 	Rune r, *rp, vr;
167dd7cddfSDavid du Colombier 	ulong a;
177dd7cddfSDavid du Colombier 	Cacheinfo *c, *tc, *ec;
187dd7cddfSDavid du Colombier 
197dd7cddfSDavid du Colombier 	if(ss){
207dd7cddfSDavid du Colombier 		sp = *ss;
217dd7cddfSDavid du Colombier 		rp = L"";
227dd7cddfSDavid du Colombier 	}else{
237dd7cddfSDavid du Colombier 		sp = "";
247dd7cddfSDavid du Colombier 		rp = *rr;
257dd7cddfSDavid du Colombier 	}
267dd7cddfSDavid du Colombier 	wid = 0;
277dd7cddfSDavid du Colombier 	*subfontname = 0;
28ac1798d1SDavid du Colombier 	for(i=0; i<max && (*sp || *rp); sp+=w, rp+=rw){
297dd7cddfSDavid du Colombier 		if(ss){
307dd7cddfSDavid du Colombier 			r = *(uchar*)sp;
317dd7cddfSDavid du Colombier 			if(r < Runeself)
327dd7cddfSDavid du Colombier 				w = 1;
337dd7cddfSDavid du Colombier 			else{
347dd7cddfSDavid du Colombier 				w = chartorune(&vr, sp);
357dd7cddfSDavid du Colombier 				r = vr;
367dd7cddfSDavid du Colombier 			}
377dd7cddfSDavid du Colombier 			rw = 0;
387dd7cddfSDavid du Colombier 		}else{
397dd7cddfSDavid du Colombier 			r = *rp;
407dd7cddfSDavid du Colombier 			w = 0;
417dd7cddfSDavid du Colombier 			rw = 1;
427dd7cddfSDavid du Colombier 		}
437dd7cddfSDavid du Colombier 
447dd7cddfSDavid du Colombier 		sh = (17 * (uint)r) & (f->ncache-NFLOOK-1);
457dd7cddfSDavid du Colombier 		c = &f->cache[sh];
467dd7cddfSDavid du Colombier 		ec = c+NFLOOK;
477dd7cddfSDavid du Colombier 		h = sh;
487dd7cddfSDavid du Colombier 		while(c < ec){
497dd7cddfSDavid du Colombier 			if(c->value==r && c->age)
507dd7cddfSDavid du Colombier 				goto Found;
517dd7cddfSDavid du Colombier 			c++;
527dd7cddfSDavid du Colombier 			h++;
537dd7cddfSDavid du Colombier 		}
547dd7cddfSDavid du Colombier 
557dd7cddfSDavid du Colombier 		/*
567dd7cddfSDavid du Colombier 		 * Not found; toss out oldest entry
577dd7cddfSDavid du Colombier 		 */
587dd7cddfSDavid du Colombier 		a = ~0;
597dd7cddfSDavid du Colombier 		th = sh;
607dd7cddfSDavid du Colombier 		tc = &f->cache[th];
617dd7cddfSDavid du Colombier 		while(tc < ec){
627dd7cddfSDavid du Colombier 			if(tc->age < a){
637dd7cddfSDavid du Colombier 				a = tc->age;
647dd7cddfSDavid du Colombier 				h = th;
657dd7cddfSDavid du Colombier 				c = tc;
667dd7cddfSDavid du Colombier 			}
677dd7cddfSDavid du Colombier 			tc++;
687dd7cddfSDavid du Colombier 			th++;
697dd7cddfSDavid du Colombier 		}
707dd7cddfSDavid du Colombier 
717dd7cddfSDavid du Colombier 		if(a && (f->age-a)<500){	/* kicking out too recent; resize */
727dd7cddfSDavid du Colombier 			nc = 2*(f->ncache-NFLOOK) + NFLOOK;
737dd7cddfSDavid du Colombier 			if(nc <= MAXFCACHE){
747dd7cddfSDavid du Colombier 				if(i == 0)
757dd7cddfSDavid du Colombier 					fontresize(f, f->width, nc, f->maxdepth);
767dd7cddfSDavid du Colombier 				/* else flush first; retry will resize */
777dd7cddfSDavid du Colombier 				break;
787dd7cddfSDavid du Colombier 			}
797dd7cddfSDavid du Colombier 		}
807dd7cddfSDavid du Colombier 
817dd7cddfSDavid du Colombier 		if(c->age == f->age)	/* flush pending string output */
827dd7cddfSDavid du Colombier 			break;
837dd7cddfSDavid du Colombier 
847dd7cddfSDavid du Colombier 		ld = loadchar(f, r, c, h, i, subfontname);
857dd7cddfSDavid du Colombier 		if(ld <= 0){
867dd7cddfSDavid du Colombier 			if(ld == 0)
877dd7cddfSDavid du Colombier 				continue;
887dd7cddfSDavid du Colombier 			break;
897dd7cddfSDavid du Colombier 		}
907dd7cddfSDavid du Colombier 		c = &f->cache[h];	/* may have reallocated f->cache */
917dd7cddfSDavid du Colombier 
927dd7cddfSDavid du Colombier 	    Found:
937dd7cddfSDavid du Colombier 		wid += c->width;
947dd7cddfSDavid du Colombier 		c->age = f->age;
957dd7cddfSDavid du Colombier 		cp[i] = h;
967dd7cddfSDavid du Colombier 		i++;
977dd7cddfSDavid du Colombier 	}
987dd7cddfSDavid du Colombier 	if(ss)
997dd7cddfSDavid du Colombier 		*ss = sp;
1007dd7cddfSDavid du Colombier 	else
1017dd7cddfSDavid du Colombier 		*rr = rp;
1027dd7cddfSDavid du Colombier 	*wp = wid;
1037dd7cddfSDavid du Colombier 	return i;
1047dd7cddfSDavid du Colombier }
1057dd7cddfSDavid du Colombier 
1067dd7cddfSDavid du Colombier void
agefont(Font * f)1077dd7cddfSDavid du Colombier agefont(Font *f)
1087dd7cddfSDavid du Colombier {
1097dd7cddfSDavid du Colombier 	Cacheinfo *c, *ec;
1107dd7cddfSDavid du Colombier 	Cachesubf *s, *es;
1117dd7cddfSDavid du Colombier 
1127dd7cddfSDavid du Colombier 	f->age++;
1137dd7cddfSDavid du Colombier 	if(f->age == 65536){
1147dd7cddfSDavid du Colombier 		/*
1157dd7cddfSDavid du Colombier 		 * Renormalize ages
1167dd7cddfSDavid du Colombier 		 */
1177dd7cddfSDavid du Colombier 		c = f->cache;
1187dd7cddfSDavid du Colombier 		ec = c+f->ncache;
1197dd7cddfSDavid du Colombier 		while(c < ec){
1207dd7cddfSDavid du Colombier 			if(c->age){
1217dd7cddfSDavid du Colombier 				c->age >>= 2;
1227dd7cddfSDavid du Colombier 				c->age++;
1237dd7cddfSDavid du Colombier 			}
1247dd7cddfSDavid du Colombier 			c++;
1257dd7cddfSDavid du Colombier 		}
1267dd7cddfSDavid du Colombier 		s = f->subf;
1277dd7cddfSDavid du Colombier 		es = s+f->nsubf;
1287dd7cddfSDavid du Colombier 		while(s < es){
1297dd7cddfSDavid du Colombier 			if(s->age){
1307dd7cddfSDavid du Colombier 				if(s->age<SUBFAGE && s->cf->name != nil){
1317dd7cddfSDavid du Colombier 					/* clean up */
132*6bbfed0dSDavid du Colombier 					if(display &&
133*6bbfed0dSDavid du Colombier 					    s->f != display->defaultsubfont)
1347dd7cddfSDavid du Colombier 						freesubfont(s->f);
1357dd7cddfSDavid du Colombier 					s->cf = nil;
1367dd7cddfSDavid du Colombier 					s->f = nil;
1377dd7cddfSDavid du Colombier 					s->age = 0;
1387dd7cddfSDavid du Colombier 				}else{
1397dd7cddfSDavid du Colombier 					s->age >>= 2;
1407dd7cddfSDavid du Colombier 					s->age++;
1417dd7cddfSDavid du Colombier 				}
1427dd7cddfSDavid du Colombier 			}
1437dd7cddfSDavid du Colombier 			s++;
1447dd7cddfSDavid du Colombier 		}
1457dd7cddfSDavid du Colombier 		f->age = (65536>>2) + 1;
1467dd7cddfSDavid du Colombier 	}
1477dd7cddfSDavid du Colombier }
1487dd7cddfSDavid du Colombier 
1497dd7cddfSDavid du Colombier static Subfont*
cf2subfont(Cachefont * cf,Font * f)1507dd7cddfSDavid du Colombier cf2subfont(Cachefont *cf, Font *f)
1517dd7cddfSDavid du Colombier {
1529a747e4fSDavid du Colombier 	int depth;
1537dd7cddfSDavid du Colombier 	char *name;
1547dd7cddfSDavid du Colombier 	Subfont *sf;
1557dd7cddfSDavid du Colombier 
1567dd7cddfSDavid du Colombier 	name = cf->subfontname;
1577dd7cddfSDavid du Colombier 	if(name == nil){
1582df1634fSDavid du Colombier 		if(f->display && f->display->screenimage)
1599a747e4fSDavid du Colombier 			depth = f->display->screenimage->depth;
1602df1634fSDavid du Colombier 		else
161b8661318SDavid du Colombier 			depth = 8;
1629a747e4fSDavid du Colombier 		name = subfontname(cf->name, f->name, depth);
1637dd7cddfSDavid du Colombier 		if(name == nil)
1647dd7cddfSDavid du Colombier 			return nil;
1657dd7cddfSDavid du Colombier 		cf->subfontname = name;
1667dd7cddfSDavid du Colombier 	}
1677dd7cddfSDavid du Colombier 	sf = lookupsubfont(f->display, name);
1687dd7cddfSDavid du Colombier 	return sf;
1697dd7cddfSDavid du Colombier }
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier /* return 1 if load succeeded, 0 if failed, -1 if must retry */
1727dd7cddfSDavid du Colombier int
loadchar(Font * f,Rune r,Cacheinfo * c,int h,int noflush,char ** subfontname)1737dd7cddfSDavid du Colombier loadchar(Font *f, Rune r, Cacheinfo *c, int h, int noflush, char **subfontname)
1747dd7cddfSDavid du Colombier {
1757dd7cddfSDavid du Colombier 	int i, oi, wid, top, bottom;
1767dd7cddfSDavid du Colombier 	Rune pic;
1777dd7cddfSDavid du Colombier 	Fontchar *fi;
1787dd7cddfSDavid du Colombier 	Cachefont *cf;
1797dd7cddfSDavid du Colombier 	Cachesubf *subf, *of;
1807dd7cddfSDavid du Colombier 	uchar *b;
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier 	pic = r;
1837dd7cddfSDavid du Colombier     Again:
1847dd7cddfSDavid du Colombier 	for(i=0; i<f->nsub; i++){
1857dd7cddfSDavid du Colombier 		cf = f->sub[i];
1867dd7cddfSDavid du Colombier 		if(cf->min<=pic && pic<=cf->max)
1877dd7cddfSDavid du Colombier 			goto Found;
1887dd7cddfSDavid du Colombier 	}
1897dd7cddfSDavid du Colombier     TryPJW:
1907dd7cddfSDavid du Colombier 	if(pic != PJW){
1917dd7cddfSDavid du Colombier 		pic = PJW;
1927dd7cddfSDavid du Colombier 		goto Again;
1937dd7cddfSDavid du Colombier 	}
1947dd7cddfSDavid du Colombier 	return 0;
1957dd7cddfSDavid du Colombier 
1967dd7cddfSDavid du Colombier     Found:
1977dd7cddfSDavid du Colombier 	/*
1987dd7cddfSDavid du Colombier 	 * Choose exact or oldest
1997dd7cddfSDavid du Colombier 	 */
2007dd7cddfSDavid du Colombier 	oi = 0;
2017dd7cddfSDavid du Colombier 	subf = &f->subf[0];
2027dd7cddfSDavid du Colombier 	for(i=0; i<f->nsubf; i++){
2037dd7cddfSDavid du Colombier 		if(cf == subf->cf)
2047dd7cddfSDavid du Colombier 			goto Found2;
2057dd7cddfSDavid du Colombier 		if(subf->age < f->subf[oi].age)
2067dd7cddfSDavid du Colombier 			oi = i;
2077dd7cddfSDavid du Colombier 		subf++;
2087dd7cddfSDavid du Colombier 	}
2097dd7cddfSDavid du Colombier 	subf = &f->subf[oi];
2107dd7cddfSDavid du Colombier 
2117dd7cddfSDavid du Colombier 	if(subf->f){
2127dd7cddfSDavid du Colombier 		if(f->age-subf->age>SUBFAGE || f->nsubf>MAXSUBF){
2137dd7cddfSDavid du Colombier     Toss:
2147dd7cddfSDavid du Colombier 			/* ancient data; toss */
2157dd7cddfSDavid du Colombier 			freesubfont(subf->f);
2167dd7cddfSDavid du Colombier 			subf->cf = nil;
2177dd7cddfSDavid du Colombier 			subf->f = nil;
2187dd7cddfSDavid du Colombier 			subf->age = 0;
2197dd7cddfSDavid du Colombier 		}else{				/* too recent; grow instead */
2207dd7cddfSDavid du Colombier 			of = f->subf;
2217dd7cddfSDavid du Colombier 			f->subf = malloc((f->nsubf+DSUBF)*sizeof *subf);
2227dd7cddfSDavid du Colombier 			if(f->subf == nil){
2237dd7cddfSDavid du Colombier 				f->subf = of;
2247dd7cddfSDavid du Colombier 				goto Toss;
2257dd7cddfSDavid du Colombier 			}
2267dd7cddfSDavid du Colombier 			memmove(f->subf, of, (f->nsubf+DSUBF)*sizeof *subf);
2277dd7cddfSDavid du Colombier 			memset(f->subf+f->nsubf, 0, DSUBF*sizeof *subf);
2287dd7cddfSDavid du Colombier 			subf = &f->subf[f->nsubf];
2297dd7cddfSDavid du Colombier 			f->nsubf += DSUBF;
2307dd7cddfSDavid du Colombier 			free(of);
2317dd7cddfSDavid du Colombier 		}
2327dd7cddfSDavid du Colombier 	}
2337dd7cddfSDavid du Colombier 	subf->age = 0;
2347dd7cddfSDavid du Colombier 	subf->cf = nil;
2357dd7cddfSDavid du Colombier 	subf->f = cf2subfont(cf, f);
2367dd7cddfSDavid du Colombier 	if(subf->f == nil){
23780ee5cbfSDavid du Colombier 		if(cf->subfontname == nil)
23880ee5cbfSDavid du Colombier 			goto TryPJW;
2397dd7cddfSDavid du Colombier 		*subfontname = cf->subfontname;
2407dd7cddfSDavid du Colombier 		return -1;
2417dd7cddfSDavid du Colombier 	}
2427dd7cddfSDavid du Colombier 
2437dd7cddfSDavid du Colombier 	subf->cf = cf;
244b8661318SDavid du Colombier 	if(subf->f->ascent > f->ascent && f->display){
2457dd7cddfSDavid du Colombier 		/* should print something? this is a mistake in the font file */
2467dd7cddfSDavid du Colombier 		/* must prevent c->top from going negative when loading cache */
2477dd7cddfSDavid du Colombier 		Image *b;
2487dd7cddfSDavid du Colombier 		int d, t;
2497dd7cddfSDavid du Colombier 		d = subf->f->ascent - f->ascent;
2507dd7cddfSDavid du Colombier 		b = subf->f->bits;
2517dd7cddfSDavid du Colombier 		draw(b, b->r, b, nil, addpt(b->r.min, Pt(0, d)));
2527dd7cddfSDavid du Colombier 		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);
2537dd7cddfSDavid du Colombier 		for(i=0; i<subf->f->n; i++){
2547dd7cddfSDavid du Colombier 			t = subf->f->info[i].top-d;
2557dd7cddfSDavid du Colombier 			if(t < 0)
2567dd7cddfSDavid du Colombier 				t = 0;
2577dd7cddfSDavid du Colombier 			subf->f->info[i].top = t;
2587dd7cddfSDavid du Colombier 			t = subf->f->info[i].bottom-d;
2597dd7cddfSDavid du Colombier 			if(t < 0)
2607dd7cddfSDavid du Colombier 				t = 0;
2617dd7cddfSDavid du Colombier 			subf->f->info[i].bottom = t;
2627dd7cddfSDavid du Colombier 		}
2637dd7cddfSDavid du Colombier 		subf->f->ascent = f->ascent;
2647dd7cddfSDavid du Colombier 	}
2657dd7cddfSDavid du Colombier 
2667dd7cddfSDavid du Colombier     Found2:
2677dd7cddfSDavid du Colombier 	subf->age = f->age;
2687dd7cddfSDavid du Colombier 
2691517f4bcSDavid du Colombier 	/* possible overflow here, but works out okay */
2707dd7cddfSDavid du Colombier 	pic += cf->offset;
2711517f4bcSDavid du Colombier 	pic -= cf->min;
2721517f4bcSDavid du Colombier 	if(pic >= subf->f->n)
2737dd7cddfSDavid du Colombier 		goto TryPJW;
2741517f4bcSDavid du Colombier 	fi = &subf->f->info[pic];
2757dd7cddfSDavid du Colombier 	if(fi->width == 0)
2767dd7cddfSDavid du Colombier 		goto TryPJW;
2777dd7cddfSDavid du Colombier 	wid = (fi+1)->x - fi->x;
2787dd7cddfSDavid du Colombier 	if(f->width < wid || f->width == 0 || f->maxdepth < subf->f->bits->depth){
2797dd7cddfSDavid du Colombier 		/*
2807dd7cddfSDavid du Colombier 		 * Flush, free, reload (easier than reformatting f->b)
2817dd7cddfSDavid du Colombier 		 */
2827dd7cddfSDavid du Colombier 		if(noflush)
2837dd7cddfSDavid du Colombier 			return -1;
2847dd7cddfSDavid du Colombier 		if(f->width < wid)
2857dd7cddfSDavid du Colombier 			f->width = wid;
2867dd7cddfSDavid du Colombier 		if(f->maxdepth < subf->f->bits->depth)
2877dd7cddfSDavid du Colombier 			f->maxdepth = subf->f->bits->depth;
2887dd7cddfSDavid du Colombier 		i = fontresize(f, f->width, f->ncache, f->maxdepth);
2897dd7cddfSDavid du Colombier 		if(i <= 0)
2907dd7cddfSDavid du Colombier 			return i;
2917dd7cddfSDavid du Colombier 		/* c is still valid as didn't reallocate f->cache */
2927dd7cddfSDavid du Colombier 	}
2937dd7cddfSDavid du Colombier 	c->value = r;
2947dd7cddfSDavid du Colombier 	top = fi->top + (f->ascent-subf->f->ascent);
2957dd7cddfSDavid du Colombier 	bottom = fi->bottom + (f->ascent-subf->f->ascent);
2967dd7cddfSDavid du Colombier 	c->width = fi->width;
2977dd7cddfSDavid du Colombier 	c->x = h*f->width;
2987dd7cddfSDavid du Colombier 	c->left = fi->left;
299b8661318SDavid du Colombier 	if(f->display == nil)
300b8661318SDavid du Colombier 		return 1;
3017dd7cddfSDavid du Colombier 	flushimage(f->display, 0);	/* flush any pending errors */
3027dd7cddfSDavid du Colombier 	b = bufimage(f->display, 37);
3037dd7cddfSDavid du Colombier 	if(b == 0)
3047dd7cddfSDavid du Colombier 		return 0;
3057dd7cddfSDavid du Colombier 	b[0] = 'l';
3067dd7cddfSDavid du Colombier 	BPLONG(b+1, f->cacheimage->id);
3077dd7cddfSDavid du Colombier 	BPLONG(b+5, subf->f->bits->id);
3087dd7cddfSDavid du Colombier 	BPSHORT(b+9, c-f->cache);
3097dd7cddfSDavid du Colombier 	BPLONG(b+11, c->x);
3107dd7cddfSDavid du Colombier 	BPLONG(b+15, top);
3117dd7cddfSDavid du Colombier 	BPLONG(b+19, c->x+((fi+1)->x-fi->x));
3127dd7cddfSDavid du Colombier 	BPLONG(b+23, bottom);
3137dd7cddfSDavid du Colombier 	BPLONG(b+27, fi->x);
3147dd7cddfSDavid du Colombier 	BPLONG(b+31, fi->top);
3157dd7cddfSDavid du Colombier 	b[35] = fi->left;
3167dd7cddfSDavid du Colombier 	b[36] = fi->width;
3177dd7cddfSDavid du Colombier 	return 1;
3187dd7cddfSDavid du Colombier }
3197dd7cddfSDavid du Colombier 
3207dd7cddfSDavid du Colombier /* release all subfonts, return number freed */
3217dd7cddfSDavid du Colombier static
3227dd7cddfSDavid du Colombier int
freeup(Font * f)3237dd7cddfSDavid du Colombier freeup(Font *f)
3247dd7cddfSDavid du Colombier {
3257dd7cddfSDavid du Colombier 	Cachesubf *s, *es;
3267dd7cddfSDavid du Colombier 	int nf;
3277dd7cddfSDavid du Colombier 
3287dd7cddfSDavid du Colombier 	if(f->sub[0]->name == nil)	/* font from mkfont; don't free */
3297dd7cddfSDavid du Colombier 		return 0;
3307dd7cddfSDavid du Colombier 	s = f->subf;
3317dd7cddfSDavid du Colombier 	es = s+f->nsubf;
3327dd7cddfSDavid du Colombier 	nf = 0;
3337dd7cddfSDavid du Colombier 	while(s < es){
3347dd7cddfSDavid du Colombier 		if(s->age){
3357dd7cddfSDavid du Colombier 			freesubfont(s->f);
3367dd7cddfSDavid du Colombier 			s->cf = nil;
3377dd7cddfSDavid du Colombier 			s->f = nil;
3387dd7cddfSDavid du Colombier 			s->age = 0;
3397dd7cddfSDavid du Colombier 			nf++;
3407dd7cddfSDavid du Colombier 		}
3417dd7cddfSDavid du Colombier 		s++;
3427dd7cddfSDavid du Colombier 	}
3437dd7cddfSDavid du Colombier 	return nf;
3447dd7cddfSDavid du Colombier }
3457dd7cddfSDavid du Colombier 
3467dd7cddfSDavid du Colombier /* return whether resize succeeded && f->cache is unchanged */
3477dd7cddfSDavid du Colombier static int
fontresize(Font * f,int wid,int ncache,int depth)3487dd7cddfSDavid du Colombier fontresize(Font *f, int wid, int ncache, int depth)
3497dd7cddfSDavid du Colombier {
3507dd7cddfSDavid du Colombier 	Cacheinfo *i;
3517dd7cddfSDavid du Colombier 	int ret;
3527dd7cddfSDavid du Colombier 	Image *new;
3537dd7cddfSDavid du Colombier 	uchar *b;
3547dd7cddfSDavid du Colombier 	Display *d;
3557dd7cddfSDavid du Colombier 
3567dd7cddfSDavid du Colombier 	ret = 0;
3577dd7cddfSDavid du Colombier 	if(depth <= 0)
3587dd7cddfSDavid du Colombier 		depth = 1;
3594af5a9a1SDavid du Colombier 	if(wid <= 0)
3604af5a9a1SDavid du Colombier 		wid = 1;
3617dd7cddfSDavid du Colombier 
362b8661318SDavid du Colombier 	d = f->display;
363b8661318SDavid du Colombier 	if(d == nil)
364b8661318SDavid du Colombier 		goto Nodisplay;
365b8661318SDavid du Colombier 
3667dd7cddfSDavid du Colombier 	new = allocimage(d, Rect(0, 0, ncache*wid, f->height), CHAN1(CGrey, depth), 0, 0);
3677dd7cddfSDavid du Colombier 	if(new == nil){
3689a747e4fSDavid du Colombier 		fprint(2, "font cache resize failed: %r\n");
3697dd7cddfSDavid du Colombier 		abort();
3707dd7cddfSDavid du Colombier 		goto Return;
3717dd7cddfSDavid du Colombier 	}
3727dd7cddfSDavid du Colombier 	flushimage(d, 0);	/* flush any pending errors */
3737dd7cddfSDavid du Colombier 	b = bufimage(d, 1+4+4+1);
3747dd7cddfSDavid du Colombier 	if(b == 0){
3757dd7cddfSDavid du Colombier 		freeimage(new);
3767dd7cddfSDavid du Colombier 		goto Return;
3777dd7cddfSDavid du Colombier 	}
3787dd7cddfSDavid du Colombier 	b[0] = 'i';
3797dd7cddfSDavid du Colombier 	BPLONG(b+1, new->id);
3807dd7cddfSDavid du Colombier 	BPLONG(b+5, ncache);
3817dd7cddfSDavid du Colombier 	b[9] = f->ascent;
3827dd7cddfSDavid du Colombier 	if(flushimage(d, 0) < 0){
3839a747e4fSDavid du Colombier 		fprint(2, "resize: init failed: %r\n");
3847dd7cddfSDavid du Colombier 		freeimage(new);
3857dd7cddfSDavid du Colombier 		goto Return;
3867dd7cddfSDavid du Colombier 	}
3877dd7cddfSDavid du Colombier 	freeimage(f->cacheimage);
3887dd7cddfSDavid du Colombier 	f->cacheimage = new;
389b8661318SDavid du Colombier     Nodisplay:
3907dd7cddfSDavid du Colombier 	f->width = wid;
3917dd7cddfSDavid du Colombier 	f->maxdepth = depth;
3927dd7cddfSDavid du Colombier 	ret = 1;
3937dd7cddfSDavid du Colombier 	if(f->ncache != ncache){
3947dd7cddfSDavid du Colombier 		i = malloc(ncache*sizeof f->cache[0]);
3957dd7cddfSDavid du Colombier 		if(i != nil){
3967dd7cddfSDavid du Colombier 			ret = 0;
3977dd7cddfSDavid du Colombier 			free(f->cache);
3987dd7cddfSDavid du Colombier 			f->ncache = ncache;
3997dd7cddfSDavid du Colombier 			f->cache = i;
4007dd7cddfSDavid du Colombier 		}
4017dd7cddfSDavid du Colombier 		/* else just wipe the cache clean and things will be ok */
4027dd7cddfSDavid du Colombier 	}
4037dd7cddfSDavid du Colombier     Return:
4047dd7cddfSDavid du Colombier 	memset(f->cache, 0, f->ncache*sizeof f->cache[0]);
4057dd7cddfSDavid du Colombier 	return ret;
4067dd7cddfSDavid du Colombier }
407