libdraw: autoscale fonts when moving between low and high dpi screens

Change-Id: I6093955b222db89dfe437fb723593b173d888d01
Reviewed-on: https://plan9port-review.googlesource.com/1170
Reviewed-by: Russ Cox <rsc@swtch.com>
This commit is contained in:
Russ Cox 2015-02-17 12:16:20 -05:00
parent 77f23268f7
commit 213fc4f6fb
9 changed files with 243 additions and 28 deletions

View file

@ -206,6 +206,9 @@ struct Display
struct Mux *mux;
int srvfd;
int dpi;
Font *firstfont;
Font *lastfont;
};
struct Image
@ -319,6 +322,15 @@ struct Font
Cachesubf *subf;
Cachefont **sub; /* as read from file */
Image *cacheimage;
/* doubly linked list of fonts known to display */
int ondisplaylist;
Font *next;
Font *prev;
/* on hi-dpi systems, one of these is set to f and the other is the other-dpi version of f */
Font *lodpi;
Font *hidpi;
};
#define Dx(r) ((r).max.x-(r).min.x)
@ -460,6 +472,7 @@ extern void borderop(Image*, Rectangle, int, Image*, Point, Drawop);
* Font management
*/
extern Font* openfont(Display*, char*);
extern int parsefontscale(char*, char**);
extern Font* buildfont(Display*, char*, char*);
extern void freefont(Font*);
extern Font* mkfont(Subfont*, Rune);
@ -483,11 +496,13 @@ extern int runestringnwidth(Font*, Rune*, int);
extern Point strsubfontwidth(Subfont*, char*);
extern int loadchar(Font*, Rune, Cacheinfo*, int, int, char**);
extern char* subfontname(char*, char*, int);
extern Subfont* _getsubfont(Display*, Font*, char*);
extern Subfont* _getsubfont(Display*, char*);
extern Subfont* getdefont(Display*);
extern void lockdisplay(Display*);
extern void unlockdisplay(Display*);
extern int drawlsetrefresh(u32int, int, void*, void*);
extern void loadhidpi(Font*);
extern void swapfont(Font*, Font**, Font**);
/*
* Predefined

View file

@ -487,6 +487,21 @@ point to the portion of the window inside the border;
sophisticated clients may use
.B _screen
to make further subwindows.
If
.I getwindow
is being called due to a resizing of the window,
the resize may be accompanied by a change in screen pixel density (DPI),
in which case the value of the
.BR Display 's
.B dpi
field and any open
.BR Font 's
.B height
and
.B ascent
fields may be updated during the call to
.IR getwindow .
Programs should discard any cached information about display or font sizes.
.\" Programs desiring multiple independent windows
.\" may use the mechanisms of
.\" .IR rio (4)

View file

@ -138,5 +138,23 @@ freefont(Font *f)
free(f->cache);
free(f->subf);
free(f->sub);
if(f->ondisplaylist) {
f->ondisplaylist = 0;
if(f->next)
f->next->prev = f->prev;
else
f->display->lastfont = f->prev;
if(f->prev)
f->prev->next = f->next;
else
f->display->firstfont = f->next;
}
if(f->lodpi != f)
freefont(f->lodpi);
if(f->hidpi != f)
freefont(f->hidpi);
free(f);
}

View file

@ -11,17 +11,20 @@ int _fontpipe(char*);
static void scalesubfont(Subfont*, int);
Subfont*
_getsubfont(Display *d, Font *ff, char *name)
_getsubfont(Display *d, char *name)
{
int fd;
Subfont *f;
fd = open(name, OREAD);
if(fd < 0 && strncmp(name, "/mnt/font/", 10) == 0)
fd = _fontpipe(name+10);
int scale;
char *fname;
scale = parsefontscale(name, &fname);
fd = open(fname, OREAD);
if(fd < 0 && strncmp(fname, "/mnt/font/", 10) == 0)
fd = _fontpipe(fname+10);
if(fd < 0){
fprint(2, "getsubfont: can't open %s: %r\n", name);
fprint(2, "getsubfont: can't open %s: %r\n", fname);
return 0;
}
/*
@ -38,8 +41,8 @@ _getsubfont(Display *d, Font *ff, char *name)
if(f == 0)
fprint(2, "getsubfont: can't read %s: %r\n", name);
close(fd);
if(ff->scale != 1 && ff->scale != 0)
scalesubfont(f, ff->scale);
if(scale > 1)
scalesubfont(f, scale);
return f;
}

View file

@ -199,6 +199,7 @@ int
getwindow(Display *d, int ref)
{
Image *i, *oi;
Font *f;
/* XXX check for destroyed? */
@ -219,6 +220,17 @@ getwindow(Display *d, int ref)
_freeimage1(screen);
screen = _allocwindow(screen, _screen, i->r, ref, DWhite);
d->screenimage = screen;
if(d->dpi >= DefaultDPI*3/2) {
for(f=d->firstfont; f != nil; f=f->next)
loadhidpi(f);
} else {
for(f=d->firstfont; f != nil; f=f->next)
if(f->lodpi != nil && f->lodpi != f)
swapfont(f, &f->hidpi, &f->lodpi);
}
return 0;
}

View file

@ -5,23 +5,41 @@
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*
openfont(Display *d, char *name)
openfont1(Display *d, char *name)
{
Font *fnt;
int fd, i, n, scale;
char *buf, *nambuf;
char *buf, *nambuf, *fname, *freename;
nambuf = 0;
scale = 1;
if('1' <= name[0] && name[0] <= '9' && name[1] == '*') {
scale = name[0] - '0';
name += 2;
}
fd = open(name, OREAD);
freename = nil;
scale = parsefontscale(name, &fname);
if(fd < 0 && strncmp(name, "/lib/font/bit/", 14) == 0){
nambuf = smprint("#9/font/%s", name+14);
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);
@ -31,12 +49,18 @@ openfont(Display *d, char *name)
free(nambuf);
return 0;
}
name = nambuf;
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(name, "/mnt/font/", 10) == 0) {
fd = _fontpipe(name+10);
if(fd < 0 && strncmp(fname, "/mnt/font/", 10) == 0) {
fd = _fontpipe(fname+10);
n = 8192;
}
if(fd < 0)
@ -59,6 +83,7 @@ openfont(Display *d, char *name)
fnt = buildfont(d, buf, name);
free(buf);
free(nambuf);
free(freename);
if(scale != 1) {
fnt->scale = scale;
fnt->height *= scale;
@ -68,6 +93,120 @@ openfont(Display *d, char *name)
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;
}
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 = smprint("%d*%s", f->scale*2, f->name);
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;
f = openfont1(d, name);
f->lodpi = f;
/* 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);
}
return f;
}
int
_fontpipe(char *name)
{

View file

@ -130,7 +130,7 @@ _string(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, Rune *r, i
}
if(subfontname){
freesubfont(sf);
if((sf=_getsubfont(f->display, f, subfontname)) == 0){
if((sf=_getsubfont(f->display, subfontname)) == 0){
def = f->display ? f->display->defaultfont : nil;
if(def && f!=def)
f = def;

View file

@ -48,7 +48,7 @@ _stringnwidth(Font *f, char *s, Rune *r, int len)
}
if(subfontname){
freesubfont(sf);
if((sf=_getsubfont(f->display, f, subfontname)) == 0){
if((sf=_getsubfont(f->display, subfontname)) == 0){
def = f->display ? f->display->defaultfont : nil;
if(def && f!=def)
f = def;

View file

@ -9,14 +9,16 @@
char*
subfontname(char *cfname, char *fname, int maxdepth)
{
char *t, *u, *tmp1, *tmp2;
int i;
char *t, *u, *tmp1, *tmp2, *base;
int i, scale;
scale = parsefontscale(fname, &base);
t = strdup(cfname); /* t is the return string */
if(strcmp(cfname, "*default*") == 0)
return t;
if(t[0] != '/'){
tmp2 = strdup(fname);
tmp2 = strdup(base);
u = utfrrune(tmp2, '/');
if(u)
u[0] = 0;
@ -38,13 +40,24 @@ subfontname(char *cfname, char *fname, int maxdepth)
tmp2 = smprint("%s.%d", t, i);
if(access(tmp2, AREAD) == 0) {
free(t);
if(scale > 1) {
t = smprint("%d*%s", scale, tmp2);
free(tmp2);
tmp2 = t;
}
return tmp2;
}
}
/* try default */
if(strncmp(t, "/mnt/font/", 10) == 0 || access(t, AREAD) == 0)
if(strncmp(t, "/mnt/font/", 10) == 0 || access(t, AREAD) == 0) {
if(scale > 1) {
tmp2 = smprint("%d*%s", scale, t);
free(t);
t = tmp2;
}
return t;
}
return nil;
}