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:
parent
77f23268f7
commit
213fc4f6fb
9 changed files with 243 additions and 28 deletions
|
|
@ -206,6 +206,9 @@ struct Display
|
||||||
struct Mux *mux;
|
struct Mux *mux;
|
||||||
int srvfd;
|
int srvfd;
|
||||||
int dpi;
|
int dpi;
|
||||||
|
|
||||||
|
Font *firstfont;
|
||||||
|
Font *lastfont;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Image
|
struct Image
|
||||||
|
|
@ -319,6 +322,15 @@ struct Font
|
||||||
Cachesubf *subf;
|
Cachesubf *subf;
|
||||||
Cachefont **sub; /* as read from file */
|
Cachefont **sub; /* as read from file */
|
||||||
Image *cacheimage;
|
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)
|
#define Dx(r) ((r).max.x-(r).min.x)
|
||||||
|
|
@ -460,6 +472,7 @@ extern void borderop(Image*, Rectangle, int, Image*, Point, Drawop);
|
||||||
* Font management
|
* Font management
|
||||||
*/
|
*/
|
||||||
extern Font* openfont(Display*, char*);
|
extern Font* openfont(Display*, char*);
|
||||||
|
extern int parsefontscale(char*, char**);
|
||||||
extern Font* buildfont(Display*, char*, char*);
|
extern Font* buildfont(Display*, char*, char*);
|
||||||
extern void freefont(Font*);
|
extern void freefont(Font*);
|
||||||
extern Font* mkfont(Subfont*, Rune);
|
extern Font* mkfont(Subfont*, Rune);
|
||||||
|
|
@ -483,11 +496,13 @@ extern int runestringnwidth(Font*, Rune*, int);
|
||||||
extern Point strsubfontwidth(Subfont*, char*);
|
extern Point strsubfontwidth(Subfont*, char*);
|
||||||
extern int loadchar(Font*, Rune, Cacheinfo*, int, int, char**);
|
extern int loadchar(Font*, Rune, Cacheinfo*, int, int, char**);
|
||||||
extern char* subfontname(char*, char*, int);
|
extern char* subfontname(char*, char*, int);
|
||||||
extern Subfont* _getsubfont(Display*, Font*, char*);
|
extern Subfont* _getsubfont(Display*, char*);
|
||||||
extern Subfont* getdefont(Display*);
|
extern Subfont* getdefont(Display*);
|
||||||
extern void lockdisplay(Display*);
|
extern void lockdisplay(Display*);
|
||||||
extern void unlockdisplay(Display*);
|
extern void unlockdisplay(Display*);
|
||||||
extern int drawlsetrefresh(u32int, int, void*, void*);
|
extern int drawlsetrefresh(u32int, int, void*, void*);
|
||||||
|
extern void loadhidpi(Font*);
|
||||||
|
extern void swapfont(Font*, Font**, Font**);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Predefined
|
* Predefined
|
||||||
|
|
|
||||||
|
|
@ -487,6 +487,21 @@ point to the portion of the window inside the border;
|
||||||
sophisticated clients may use
|
sophisticated clients may use
|
||||||
.B _screen
|
.B _screen
|
||||||
to make further subwindows.
|
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
|
.\" Programs desiring multiple independent windows
|
||||||
.\" may use the mechanisms of
|
.\" may use the mechanisms of
|
||||||
.\" .IR rio (4)
|
.\" .IR rio (4)
|
||||||
|
|
|
||||||
|
|
@ -138,5 +138,23 @@ freefont(Font *f)
|
||||||
free(f->cache);
|
free(f->cache);
|
||||||
free(f->subf);
|
free(f->subf);
|
||||||
free(f->sub);
|
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);
|
free(f);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,17 +11,20 @@ int _fontpipe(char*);
|
||||||
static void scalesubfont(Subfont*, int);
|
static void scalesubfont(Subfont*, int);
|
||||||
|
|
||||||
Subfont*
|
Subfont*
|
||||||
_getsubfont(Display *d, Font *ff, char *name)
|
_getsubfont(Display *d, char *name)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
Subfont *f;
|
Subfont *f;
|
||||||
|
int scale;
|
||||||
fd = open(name, OREAD);
|
char *fname;
|
||||||
if(fd < 0 && strncmp(name, "/mnt/font/", 10) == 0)
|
|
||||||
fd = _fontpipe(name+10);
|
scale = parsefontscale(name, &fname);
|
||||||
|
fd = open(fname, OREAD);
|
||||||
|
if(fd < 0 && strncmp(fname, "/mnt/font/", 10) == 0)
|
||||||
|
fd = _fontpipe(fname+10);
|
||||||
|
|
||||||
if(fd < 0){
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|
@ -38,8 +41,8 @@ _getsubfont(Display *d, Font *ff, char *name)
|
||||||
if(f == 0)
|
if(f == 0)
|
||||||
fprint(2, "getsubfont: can't read %s: %r\n", name);
|
fprint(2, "getsubfont: can't read %s: %r\n", name);
|
||||||
close(fd);
|
close(fd);
|
||||||
if(ff->scale != 1 && ff->scale != 0)
|
if(scale > 1)
|
||||||
scalesubfont(f, ff->scale);
|
scalesubfont(f, scale);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -199,6 +199,7 @@ int
|
||||||
getwindow(Display *d, int ref)
|
getwindow(Display *d, int ref)
|
||||||
{
|
{
|
||||||
Image *i, *oi;
|
Image *i, *oi;
|
||||||
|
Font *f;
|
||||||
|
|
||||||
/* XXX check for destroyed? */
|
/* XXX check for destroyed? */
|
||||||
|
|
||||||
|
|
@ -219,6 +220,17 @@ getwindow(Display *d, int ref)
|
||||||
_freeimage1(screen);
|
_freeimage1(screen);
|
||||||
screen = _allocwindow(screen, _screen, i->r, ref, DWhite);
|
screen = _allocwindow(screen, _screen, i->r, ref, DWhite);
|
||||||
d->screenimage = screen;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,23 +5,41 @@
|
||||||
extern vlong _drawflength(int);
|
extern vlong _drawflength(int);
|
||||||
int _fontpipe(char*);
|
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*
|
Font*
|
||||||
openfont(Display *d, char *name)
|
openfont1(Display *d, char *name)
|
||||||
{
|
{
|
||||||
Font *fnt;
|
Font *fnt;
|
||||||
int fd, i, n, scale;
|
int fd, i, n, scale;
|
||||||
char *buf, *nambuf;
|
char *buf, *nambuf, *fname, *freename;
|
||||||
|
|
||||||
nambuf = 0;
|
nambuf = 0;
|
||||||
scale = 1;
|
freename = nil;
|
||||||
if('1' <= name[0] && name[0] <= '9' && name[1] == '*') {
|
scale = parsefontscale(name, &fname);
|
||||||
scale = name[0] - '0';
|
|
||||||
name += 2;
|
|
||||||
}
|
|
||||||
fd = open(name, OREAD);
|
|
||||||
|
|
||||||
if(fd < 0 && strncmp(name, "/lib/font/bit/", 14) == 0){
|
fd = open(fname, OREAD);
|
||||||
nambuf = smprint("#9/font/%s", name+14);
|
if(fd < 0 && strncmp(fname, "/lib/font/bit/", 14) == 0){
|
||||||
|
nambuf = smprint("#9/font/%s", fname+14);
|
||||||
if(nambuf == nil)
|
if(nambuf == nil)
|
||||||
return 0;
|
return 0;
|
||||||
nambuf = unsharp(nambuf);
|
nambuf = unsharp(nambuf);
|
||||||
|
|
@ -31,12 +49,18 @@ openfont(Display *d, char *name)
|
||||||
free(nambuf);
|
free(nambuf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
name = nambuf;
|
fname = nambuf;
|
||||||
|
if(scale > 1) {
|
||||||
|
name = smprint("%d*%s", scale, fname);
|
||||||
|
freename = name;
|
||||||
|
} else {
|
||||||
|
name = fname;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(fd >= 0)
|
if(fd >= 0)
|
||||||
n = _drawflength(fd);
|
n = _drawflength(fd);
|
||||||
if(fd < 0 && strncmp(name, "/mnt/font/", 10) == 0) {
|
if(fd < 0 && strncmp(fname, "/mnt/font/", 10) == 0) {
|
||||||
fd = _fontpipe(name+10);
|
fd = _fontpipe(fname+10);
|
||||||
n = 8192;
|
n = 8192;
|
||||||
}
|
}
|
||||||
if(fd < 0)
|
if(fd < 0)
|
||||||
|
|
@ -59,6 +83,7 @@ openfont(Display *d, char *name)
|
||||||
fnt = buildfont(d, buf, name);
|
fnt = buildfont(d, buf, name);
|
||||||
free(buf);
|
free(buf);
|
||||||
free(nambuf);
|
free(nambuf);
|
||||||
|
free(freename);
|
||||||
if(scale != 1) {
|
if(scale != 1) {
|
||||||
fnt->scale = scale;
|
fnt->scale = scale;
|
||||||
fnt->height *= scale;
|
fnt->height *= scale;
|
||||||
|
|
@ -68,6 +93,120 @@ openfont(Display *d, char *name)
|
||||||
return fnt;
|
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
|
int
|
||||||
_fontpipe(char *name)
|
_fontpipe(char *name)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ _string(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, Rune *r, i
|
||||||
}
|
}
|
||||||
if(subfontname){
|
if(subfontname){
|
||||||
freesubfont(sf);
|
freesubfont(sf);
|
||||||
if((sf=_getsubfont(f->display, f, subfontname)) == 0){
|
if((sf=_getsubfont(f->display, subfontname)) == 0){
|
||||||
def = f->display ? f->display->defaultfont : nil;
|
def = f->display ? f->display->defaultfont : nil;
|
||||||
if(def && f!=def)
|
if(def && f!=def)
|
||||||
f = def;
|
f = def;
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ _stringnwidth(Font *f, char *s, Rune *r, int len)
|
||||||
}
|
}
|
||||||
if(subfontname){
|
if(subfontname){
|
||||||
freesubfont(sf);
|
freesubfont(sf);
|
||||||
if((sf=_getsubfont(f->display, f, subfontname)) == 0){
|
if((sf=_getsubfont(f->display, subfontname)) == 0){
|
||||||
def = f->display ? f->display->defaultfont : nil;
|
def = f->display ? f->display->defaultfont : nil;
|
||||||
if(def && f!=def)
|
if(def && f!=def)
|
||||||
f = def;
|
f = def;
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,16 @@
|
||||||
char*
|
char*
|
||||||
subfontname(char *cfname, char *fname, int maxdepth)
|
subfontname(char *cfname, char *fname, int maxdepth)
|
||||||
{
|
{
|
||||||
char *t, *u, *tmp1, *tmp2;
|
char *t, *u, *tmp1, *tmp2, *base;
|
||||||
int i;
|
int i, scale;
|
||||||
|
|
||||||
|
scale = parsefontscale(fname, &base);
|
||||||
|
|
||||||
t = strdup(cfname); /* t is the return string */
|
t = strdup(cfname); /* t is the return string */
|
||||||
if(strcmp(cfname, "*default*") == 0)
|
if(strcmp(cfname, "*default*") == 0)
|
||||||
return t;
|
return t;
|
||||||
if(t[0] != '/'){
|
if(t[0] != '/'){
|
||||||
tmp2 = strdup(fname);
|
tmp2 = strdup(base);
|
||||||
u = utfrrune(tmp2, '/');
|
u = utfrrune(tmp2, '/');
|
||||||
if(u)
|
if(u)
|
||||||
u[0] = 0;
|
u[0] = 0;
|
||||||
|
|
@ -38,13 +40,24 @@ subfontname(char *cfname, char *fname, int maxdepth)
|
||||||
tmp2 = smprint("%s.%d", t, i);
|
tmp2 = smprint("%s.%d", t, i);
|
||||||
if(access(tmp2, AREAD) == 0) {
|
if(access(tmp2, AREAD) == 0) {
|
||||||
free(t);
|
free(t);
|
||||||
|
if(scale > 1) {
|
||||||
|
t = smprint("%d*%s", scale, tmp2);
|
||||||
|
free(tmp2);
|
||||||
|
tmp2 = t;
|
||||||
|
}
|
||||||
return tmp2;
|
return tmp2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try default */
|
/* 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 t;
|
||||||
|
}
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue