312 lines
5.4 KiB
C
312 lines
5.4 KiB
C
#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;
|
|
}
|
|
|
|
extern char _defontfile[];
|
|
|
|
Font*
|
|
openfont1(Display *d, char *name)
|
|
{
|
|
Font *fnt;
|
|
int fd, i, n, scale;
|
|
char *buf, *nambuf, *nambuf0, *fname, *freename;
|
|
|
|
nambuf = 0;
|
|
freename = nil;
|
|
scale = parsefontscale(name, &fname);
|
|
|
|
if(strcmp(fname, "*default*") == 0) {
|
|
buf = strdup(_defontfile);
|
|
goto build;
|
|
}
|
|
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;
|
|
nambuf0 = unsharp(nambuf);
|
|
if(nambuf0 != nambuf)
|
|
free(nambuf);
|
|
nambuf = nambuf0;
|
|
if(nambuf == nil)
|
|
return 0;
|
|
if((fd = open(nambuf, OREAD)) < 0){
|
|
free(nambuf);
|
|
return 0;
|
|
}
|
|
if(scale > 1) {
|
|
name = smprint("%d*%s", scale, nambuf);
|
|
freename = name;
|
|
} else {
|
|
name = nambuf;
|
|
}
|
|
}
|
|
if(fd >= 0)
|
|
n = _drawflength(fd);
|
|
if(fd < 0 && strncmp(fname, "/mnt/font/", 10) == 0) {
|
|
fd = _fontpipe(fname+10);
|
|
n = 1024*1024;
|
|
}
|
|
if(fd < 0){
|
|
free(nambuf);
|
|
free(freename);
|
|
return 0;
|
|
}
|
|
|
|
buf = malloc(n+1);
|
|
if(buf == 0){
|
|
close(fd);
|
|
free(nambuf);
|
|
free(freename);
|
|
return 0;
|
|
}
|
|
i = readn(fd, buf, n);
|
|
close(fd);
|
|
if(i <= 0){
|
|
free(buf);
|
|
free(nambuf);
|
|
free(freename);
|
|
return 0;
|
|
}
|
|
buf[i] = 0;
|
|
build:
|
|
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;
|
|
free(f->namespec);
|
|
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];
|
|
}
|