commit 213fc4f6fb26bb5781ea3e489bf4cc5c2aca591e from: Russ Cox date: Tue Feb 17 20:51:23 2015 UTC 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 commit - 77f23268f7073b254e91748d4764768bab6d6f1f commit + 213fc4f6fb26bb5781ea3e489bf4cc5c2aca591e blob - ff760dd7609a921c1c8912cf5585f71d118706b8 blob + 329108d91c0b5094f735012e80486b06305c141f --- include/draw.h +++ include/draw.h @@ -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*, P * 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 blob - d07c269acfedef5fa46f0b1d1462cc50186d81c2 blob + 43214f1f46fbf9bf2780fa27ca553f4e4ff6cd70 --- man/man3/graphics.3 +++ man/man3/graphics.3 @@ -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) blob - 0f14022e1195dd325160e334fbe256064d0097e6 blob + 512bc9d363f199f48dd7a889047b944ead4a7e1b --- src/libdraw/buildfont.c +++ src/libdraw/buildfont.c @@ -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); } blob - 3f3b69545612c0351eb15e7047c3c2bbd48547d3 blob + 1a5006b469baced6aeeaf129f22bc5e2ff0335a4 --- src/libdraw/getsubfont.c +++ src/libdraw/getsubfont.c @@ -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; + 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); - fd = open(name, OREAD); - if(fd < 0 && strncmp(name, "/mnt/font/", 10) == 0) - fd = _fontpipe(name+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; } blob - b2df7fd780abe136744bb02658c283569b841ad7 blob + 452b6da76e00dde5bde44d4aaf50dc7169ff1f44 --- src/libdraw/init.c +++ src/libdraw/init.c @@ -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; } blob - ae1462d41e344a6a668685e3d34b26fdd21aee15 blob + 97102a2225d322403aed7b2ef6999fa329b1d375 --- src/libdraw/openfont.c +++ src/libdraw/openfont.c @@ -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) { blob - c84112ec3539865e86c46962da88e684eb60d13b blob + 392a7e8a7fb3c24cedd503f378569ce6f7ff24ce --- src/libdraw/string.c +++ src/libdraw/string.c @@ -130,7 +130,7 @@ _string(Image *dst, Point pt, Image *src, Point sp, Fo } 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; blob - e4630ca3ec40eb5b6d5442c3e424cb2c9c6b66be blob + 522fbc0115d07609314b5133b5ef1adf11eddbb7 --- src/libdraw/stringwidth.c +++ src/libdraw/stringwidth.c @@ -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; blob - 874528befd5520b41b107d347d5616de63b3cad4 blob + 9280244afe8d406077ff0882313daf0ef94a058e --- src/libdraw/subfontname.c +++ src/libdraw/subfontname.c @@ -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; }