plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

openfont.c (5560B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <draw.h>
      4 
      5 extern vlong _drawflength(int);
      6 int _fontpipe(char*);
      7 
      8 int
      9 parsefontscale(char *name, char **base)
     10 {
     11 	char *p;
     12 	int scale;
     13 
     14 	p = name;
     15 	scale = 0;
     16 	while('0' <= *p && *p <= '9') {
     17 		scale = scale*10 + *p - '0';
     18 		p++;
     19 	}
     20 	if(*p == '*' && scale > 0)
     21 		*base = p+1;
     22 	else {
     23 		*base = name;
     24 		scale = 1;
     25 	}
     26 	return scale;
     27 }
     28 
     29 extern char _defontfile[];
     30 
     31 Font*
     32 openfont1(Display *d, char *name)
     33 {
     34 	Font *fnt;
     35 	int fd, i, n, scale;
     36 	char *buf, *nambuf, *nambuf0, *fname, *freename;
     37 
     38 	nambuf = 0;
     39 	freename = nil;
     40 	scale = parsefontscale(name, &fname);
     41 
     42 	if(strcmp(fname, "*default*") == 0) {
     43 		buf = strdup(_defontfile);
     44 		goto build;
     45 	}
     46 	fd = open(fname, OREAD);
     47 	if(fd < 0 && strncmp(fname, "/lib/font/bit/", 14) == 0){
     48 		nambuf = smprint("#9/font/%s", fname+14);
     49 		if(nambuf == nil)
     50 			return 0;
     51 		nambuf0 = unsharp(nambuf);
     52 		if(nambuf0 != nambuf)
     53 			free(nambuf);
     54 		nambuf = nambuf0;
     55 		if(nambuf == nil)
     56 			return 0;
     57 		if((fd = open(nambuf, OREAD)) < 0){
     58 			free(nambuf);
     59 			return 0;
     60 		}
     61 		if(scale > 1) {
     62 			name = smprint("%d*%s", scale, nambuf);
     63 			freename = name;
     64 		} else {
     65 			name = nambuf;
     66 		}
     67 	}
     68 	if(fd >= 0)
     69 		n = _drawflength(fd);
     70 	if(fd < 0 && strncmp(fname, "/mnt/font/", 10) == 0) {
     71 		fd = _fontpipe(fname+10);
     72 		n = 1024*1024;
     73 	}
     74 	if(fd < 0){
     75 		free(nambuf);
     76 		free(freename);
     77 		return 0;
     78 	}
     79 
     80 	buf = malloc(n+1);
     81 	if(buf == 0){
     82 		close(fd);
     83 		free(nambuf);
     84 		free(freename);
     85 		return 0;
     86 	}
     87 	i = readn(fd, buf, n);
     88 	close(fd);
     89 	if(i <= 0){
     90 		free(buf);
     91 		free(nambuf);
     92 		free(freename);
     93 		return 0;
     94 	}
     95 	buf[i] = 0;
     96 build:
     97 	fnt = buildfont(d, buf, name);
     98 	free(buf);
     99 	free(nambuf);
    100 	free(freename);
    101 	if(scale != 1) {
    102 		fnt->scale = scale;
    103 		fnt->height *= scale;
    104 		fnt->ascent *= scale;
    105 		fnt->width *= scale;
    106 	}
    107 	return fnt;
    108 }
    109 
    110 void
    111 swapfont(Font *targ, Font **oldp, Font **newp)
    112 {
    113 	Font f, *old, *new;
    114 
    115 	if(targ != *oldp)
    116 		sysfatal("bad swapfont %p %p %p", targ, *oldp, *newp);
    117 
    118 	old = *oldp;
    119 	new = *newp;
    120 
    121 	f.name = old->name;
    122 	f.display = old->display;
    123 	f.height = old->height;
    124 	f.ascent = old->ascent;
    125 	f.width = old->width;
    126 	f.nsub = old->nsub;
    127 	f.age = old->age;
    128 	f.maxdepth = old->maxdepth;
    129 	f.ncache = old->ncache;
    130 	f.nsubf = old->nsubf;
    131 	f.scale = old->scale;
    132 	f.cache = old->cache;
    133 	f.subf = old->subf;
    134 	f.sub = old->sub;
    135 	f.cacheimage = old->cacheimage;
    136 
    137 	old->name = new->name;
    138 	old->display = new->display;
    139 	old->height = new->height;
    140 	old->ascent = new->ascent;
    141 	old->width = new->width;
    142 	old->nsub = new->nsub;
    143 	old->age = new->age;
    144 	old->maxdepth = new->maxdepth;
    145 	old->ncache = new->ncache;
    146 	old->nsubf = new->nsubf;
    147 	old->scale = new->scale;
    148 	old->cache = new->cache;
    149 	old->subf = new->subf;
    150 	old->sub = new->sub;
    151 	old->cacheimage = new->cacheimage;
    152 
    153 	new->name = f.name;
    154 	new->display = f.display;
    155 	new->height = f.height;
    156 	new->ascent = f.ascent;
    157 	new->width = f.width;
    158 	new->nsub = f.nsub;
    159 	new->age = f.age;
    160 	new->maxdepth = f.maxdepth;
    161 	new->ncache = f.ncache;
    162 	new->nsubf = f.nsubf;
    163 	new->scale = f.scale;
    164 	new->cache = f.cache;
    165 	new->subf = f.subf;
    166 	new->sub = f.sub;
    167 	new->cacheimage = f.cacheimage;
    168 
    169 	*oldp = new;
    170 	*newp = old;
    171 }
    172 
    173 static char*
    174 hidpiname(Font *f)
    175 {
    176 	char *p, *q;
    177 	int size;
    178 
    179 	// If font name has form x,y return y.
    180 	p = strchr(f->namespec, ',');
    181 	if(p != nil)
    182 		return strdup(p+1);
    183 
    184 	// If font name is /mnt/font/Name/Size/font, scale Size.
    185 	if(strncmp(f->name, "/mnt/font/", 10) == 0) {
    186 		p = strchr(f->name+10, '/');
    187 		if(p == nil || *++p < '0' || *p > '9')
    188 			goto scale;
    189 		q = p;
    190 		size = 0;
    191 		while('0' <= *q && *q <= '9')
    192 			size = size*10 + *q++ - '0';
    193 		return smprint("%.*s%d%s", utfnlen(f->name, p-f->name), f->name, size*2, q);
    194 	}
    195 
    196 	// Otherwise use pixel doubling.
    197 scale:
    198 	return smprint("%d*%s", f->scale*2, f->name);
    199 }
    200 
    201 void
    202 loadhidpi(Font *f)
    203 {
    204 	char *name;
    205 	Font *fnew;
    206 
    207 	if(f->hidpi == f)
    208 		return;
    209 	if(f->hidpi != nil) {
    210 		swapfont(f, &f->lodpi, &f->hidpi);
    211 		return;
    212 	}
    213 
    214 	name = hidpiname(f);
    215 	fnew = openfont1(f->display, name);
    216 	if(fnew == nil)
    217 		return;
    218 	f->hidpi = fnew;
    219 	free(name);
    220 
    221 	swapfont(f, &f->lodpi, &f->hidpi);
    222 }
    223 
    224 Font*
    225 openfont(Display *d, char *name)
    226 {
    227 	Font *f;
    228 	char *p;
    229 	char *namespec;
    230 
    231 	// If font name has form x,y use x for lodpi, y for hidpi.
    232 	name = strdup(name);
    233 	namespec = strdup(name);
    234 	if((p = strchr(name, ',')) != nil)
    235 		*p = '\0';
    236 
    237 	f = openfont1(d, name);
    238 	if(!f)
    239 		return nil;
    240 	f->lodpi = f;
    241 	free(f->namespec);
    242 	f->namespec = namespec;
    243 
    244 	/* add to display list for when dpi changes */
    245 	/* d can be nil when invoked from mc. */
    246 	if(d != nil) {
    247 		f->ondisplaylist = 1;
    248 		f->prev = d->lastfont;
    249 		f->next = nil;
    250 		if(f->prev)
    251 			f->prev->next = f;
    252 		else
    253 			d->firstfont = f;
    254 		d->lastfont = f;
    255 
    256 		/* if this is a hi-dpi display, find hi-dpi version and swap */
    257 		if(d->dpi >= DefaultDPI*3/2)
    258 			loadhidpi(f);
    259 	}
    260 
    261 	free(name);
    262 
    263 	return f;
    264 }
    265 
    266 int
    267 _fontpipe(char *name)
    268 {
    269 	int p[2];
    270 	char c;
    271 	char buf[1024], *argv[10];
    272 	int nbuf, pid;
    273 
    274 	if(pipe(p) < 0)
    275 		return -1;
    276 	pid = rfork(RFNOWAIT|RFFDG|RFPROC);
    277 	if(pid < 0) {
    278 		close(p[0]);
    279 		close(p[1]);
    280 		return -1;
    281 	}
    282 	if(pid == 0) {
    283 		close(p[0]);
    284 		dup(p[1], 1);
    285 		dup(p[1], 2);
    286 		if(p[1] > 2)
    287 			close(p[1]);
    288 		argv[0] = "fontsrv";
    289 		argv[1] = "-pp";
    290 		argv[2] = name;
    291 		argv[3] = nil;
    292 		execvp("fontsrv", argv);
    293 		print("exec fontsrv: %r\n");
    294 		_exit(0);
    295 	}
    296 	close(p[1]);
    297 
    298 	// success marked with leading \001.
    299 	// otherwise an error happened.
    300 	for(nbuf=0; nbuf<sizeof buf-1; nbuf++) {
    301 		if(read(p[0], &c, 1) < 1 || c == '\n') {
    302 			buf[nbuf] = '\0';
    303 			werrstr(buf);
    304 			close(p[0]);
    305 			return -1;
    306 		}
    307 		if(c == '\001')
    308 			break;
    309 	}
    310 	return p[0];
    311 }