|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <draw.h> | 
|  |  | 
|  | extern vlong _drawflength(int); | 
|  | int _fontpipe(char*); | 
|  |  | 
|  | int | 
|  | parsefontscale(char *name, char **base) | 
|  | { | 
|  | char *p; | 
|  | int scale; | 
|  |  | 
|  | p = name; | 
|  | scale = 0; | 
|  | while('0' <= *p && *p <= '9') { | 
|  | scale = scale*10 + *p - '0'; | 
|  | p++; | 
|  | } | 
|  | if(*p == '*' && scale > 0) | 
|  | *base = p+1; | 
|  | else { | 
|  | *base = name; | 
|  | scale = 1; | 
|  | } | 
|  | return scale; | 
|  | } | 
|  |  | 
|  | Font* | 
|  | openfont1(Display *d, char *name) | 
|  | { | 
|  | Font *fnt; | 
|  | int fd, i, n, scale; | 
|  | char *buf, *nambuf, *fname, *freename; | 
|  |  | 
|  | nambuf = 0; | 
|  | freename = nil; | 
|  | scale = parsefontscale(name, &fname); | 
|  |  | 
|  | fd = open(fname, OREAD); | 
|  | if(fd < 0 && strncmp(fname, "/lib/font/bit/", 14) == 0){ | 
|  | nambuf = smprint("#9/font/%s", fname+14); | 
|  | if(nambuf == nil) | 
|  | return 0; | 
|  | nambuf = unsharp(nambuf); | 
|  | if(nambuf == nil) | 
|  | return 0; | 
|  | if((fd = open(nambuf, OREAD)) < 0){ | 
|  | free(nambuf); | 
|  | return 0; | 
|  | } | 
|  | fname = nambuf; | 
|  | if(scale > 1) { | 
|  | name = smprint("%d*%s", scale, fname); | 
|  | freename = name; | 
|  | } else { | 
|  | name = fname; | 
|  | } | 
|  | } | 
|  | if(fd >= 0) | 
|  | n = _drawflength(fd); | 
|  | if(fd < 0 && strncmp(fname, "/mnt/font/", 10) == 0) { | 
|  | fd = _fontpipe(fname+10); | 
|  | n = 128*1024; | 
|  | } | 
|  | if(fd < 0) | 
|  | return 0; | 
|  |  | 
|  | buf = malloc(n+1); | 
|  | if(buf == 0){ | 
|  | close(fd); | 
|  | free(nambuf); | 
|  | return 0; | 
|  | } | 
|  | i = readn(fd, buf, n); | 
|  | close(fd); | 
|  | if(i <= 0){ | 
|  | free(buf); | 
|  | free(nambuf); | 
|  | return 0; | 
|  | } | 
|  | buf[i] = 0; | 
|  | fnt = buildfont(d, buf, name); | 
|  | free(buf); | 
|  | free(nambuf); | 
|  | free(freename); | 
|  | if(scale != 1) { | 
|  | fnt->scale = scale; | 
|  | fnt->height *= scale; | 
|  | fnt->ascent *= scale; | 
|  | fnt->width *= scale; | 
|  | } | 
|  | return fnt; | 
|  | } | 
|  |  | 
|  | void | 
|  | swapfont(Font *targ, Font **oldp, Font **newp) | 
|  | { | 
|  | Font f, *old, *new; | 
|  |  | 
|  | if(targ != *oldp) | 
|  | sysfatal("bad swapfont %p %p %p", targ, *oldp, *newp); | 
|  |  | 
|  | old = *oldp; | 
|  | new = *newp; | 
|  |  | 
|  | f.name = old->name; | 
|  | f.display = old->display; | 
|  | f.height = old->height; | 
|  | f.ascent = old->ascent; | 
|  | f.width = old->width; | 
|  | f.nsub = old->nsub; | 
|  | f.age = old->age; | 
|  | f.maxdepth = old->maxdepth; | 
|  | f.ncache = old->ncache; | 
|  | f.nsubf = old->nsubf; | 
|  | f.scale = old->scale; | 
|  | f.cache = old->cache; | 
|  | f.subf = old->subf; | 
|  | f.sub = old->sub; | 
|  | f.cacheimage = old->cacheimage; | 
|  |  | 
|  | old->name = new->name; | 
|  | old->display = new->display; | 
|  | old->height = new->height; | 
|  | old->ascent = new->ascent; | 
|  | old->width = new->width; | 
|  | old->nsub = new->nsub; | 
|  | old->age = new->age; | 
|  | old->maxdepth = new->maxdepth; | 
|  | old->ncache = new->ncache; | 
|  | old->nsubf = new->nsubf; | 
|  | old->scale = new->scale; | 
|  | old->cache = new->cache; | 
|  | old->subf = new->subf; | 
|  | old->sub = new->sub; | 
|  | old->cacheimage = new->cacheimage; | 
|  |  | 
|  | new->name = f.name; | 
|  | new->display = f.display; | 
|  | new->height = f.height; | 
|  | new->ascent = f.ascent; | 
|  | new->width = f.width; | 
|  | new->nsub = f.nsub; | 
|  | new->age = f.age; | 
|  | new->maxdepth = f.maxdepth; | 
|  | new->ncache = f.ncache; | 
|  | new->nsubf = f.nsubf; | 
|  | new->scale = f.scale; | 
|  | new->cache = f.cache; | 
|  | new->subf = f.subf; | 
|  | new->sub = f.sub; | 
|  | new->cacheimage = f.cacheimage; | 
|  |  | 
|  | *oldp = new; | 
|  | *newp = old; | 
|  | } | 
|  |  | 
|  | static char* | 
|  | hidpiname(Font *f) | 
|  | { | 
|  | char *p, *q; | 
|  | int size; | 
|  |  | 
|  | // If font name has form x,y return y. | 
|  | p = strchr(f->namespec, ','); | 
|  | if(p != nil) | 
|  | return strdup(p+1); | 
|  |  | 
|  | // If font name is /mnt/font/Name/Size/font, scale Size. | 
|  | if(strncmp(f->name, "/mnt/font/", 10) == 0) { | 
|  | p = strchr(f->name+10, '/'); | 
|  | if(p == nil || *++p < '0' || *p > '9') | 
|  | goto scale; | 
|  | q = p; | 
|  | size = 0; | 
|  | while('0' <= *q && *q <= '9') | 
|  | size = size*10 + *q++ - '0'; | 
|  | return smprint("%.*s%d%s", utfnlen(f->name, p-f->name), f->name, size*2, q); | 
|  | } | 
|  |  | 
|  | // Otherwise use pixel doubling. | 
|  | scale: | 
|  | return smprint("%d*%s", f->scale*2, f->name); | 
|  | } | 
|  |  | 
|  | void | 
|  | loadhidpi(Font *f) | 
|  | { | 
|  | char *name; | 
|  | Font *fnew; | 
|  |  | 
|  | if(f->hidpi == f) | 
|  | return; | 
|  | if(f->hidpi != nil) { | 
|  | swapfont(f, &f->lodpi, &f->hidpi); | 
|  | return; | 
|  | } | 
|  |  | 
|  | name = hidpiname(f); | 
|  | fnew = openfont1(f->display, name); | 
|  | if(fnew == nil) | 
|  | return; | 
|  | f->hidpi = fnew; | 
|  | free(name); | 
|  |  | 
|  | swapfont(f, &f->lodpi, &f->hidpi); | 
|  | } | 
|  |  | 
|  | Font* | 
|  | openfont(Display *d, char *name) | 
|  | { | 
|  | Font *f; | 
|  | char *p; | 
|  | char *namespec; | 
|  |  | 
|  | // If font name has form x,y use x for lodpi, y for hidpi. | 
|  | name = strdup(name); | 
|  | namespec = strdup(name); | 
|  | if((p = strchr(name, ',')) != nil) | 
|  | *p = '\0'; | 
|  |  | 
|  | f = openfont1(d, name); | 
|  | if(!f) | 
|  | return nil; | 
|  | f->lodpi = f; | 
|  | f->namespec = namespec; | 
|  |  | 
|  | /* add to display list for when dpi changes */ | 
|  | /* d can be nil when invoked from mc. */ | 
|  | if(d != nil) { | 
|  | f->ondisplaylist = 1; | 
|  | f->prev = d->lastfont; | 
|  | f->next = nil; | 
|  | if(f->prev) | 
|  | f->prev->next = f; | 
|  | else | 
|  | d->firstfont = f; | 
|  | d->lastfont = f; | 
|  |  | 
|  | /* if this is a hi-dpi display, find hi-dpi version and swap */ | 
|  | if(d->dpi >= DefaultDPI*3/2) | 
|  | loadhidpi(f); | 
|  | } | 
|  |  | 
|  | free(name); | 
|  |  | 
|  | return f; | 
|  | } | 
|  |  | 
|  | int | 
|  | _fontpipe(char *name) | 
|  | { | 
|  | int p[2]; | 
|  | char c; | 
|  | char buf[1024], *argv[10]; | 
|  | int nbuf, pid; | 
|  |  | 
|  | if(pipe(p) < 0) | 
|  | return -1; | 
|  | pid = rfork(RFNOWAIT|RFFDG|RFPROC); | 
|  | if(pid < 0) { | 
|  | close(p[0]); | 
|  | close(p[1]); | 
|  | return -1; | 
|  | } | 
|  | if(pid == 0) { | 
|  | close(p[0]); | 
|  | dup(p[1], 1); | 
|  | dup(p[1], 2); | 
|  | if(p[1] > 2) | 
|  | close(p[1]); | 
|  | argv[0] = "fontsrv"; | 
|  | argv[1] = "-pp"; | 
|  | argv[2] = name; | 
|  | argv[3] = nil; | 
|  | execvp("fontsrv", argv); | 
|  | print("exec fontsrv: %r\n"); | 
|  | _exit(0); | 
|  | } | 
|  | close(p[1]); | 
|  |  | 
|  | // success marked with leading \001. | 
|  | // otherwise an error happened. | 
|  | for(nbuf=0; nbuf<sizeof buf-1; nbuf++) { | 
|  | if(read(p[0], &c, 1) < 1 || c == '\n') { | 
|  | buf[nbuf] = '\0'; | 
|  | werrstr(buf); | 
|  | close(p[0]); | 
|  | return -1; | 
|  | } | 
|  | if(c == '\001') | 
|  | break; | 
|  | } | 
|  | return p[0]; | 
|  | } |