openfont.c (5560B)
1 #include <u.h> 2 #include <libc.h> 3 #include <draw.h> 4 5 extern vlong _drawflength(int); 6 int _fontpipe(char*); 7 8 int 9 parsefontscale(char *name, char **base) 10 { 11 char *p; 12 int scale; 13 14 p = name; 15 scale = 0; 16 while('0' <= *p && *p <= '9') { 17 scale = scale*10 + *p - '0'; 18 p++; 19 } 20 if(*p == '*' && scale > 0) 21 *base = p+1; 22 else { 23 *base = name; 24 scale = 1; 25 } 26 return scale; 27 } 28 29 extern char _defontfile[]; 30 31 Font* 32 openfont1(Display *d, char *name) 33 { 34 Font *fnt; 35 int fd, i, n, scale; 36 char *buf, *nambuf, *nambuf0, *fname, *freename; 37 38 nambuf = 0; 39 freename = nil; 40 scale = parsefontscale(name, &fname); 41 42 if(strcmp(fname, "*default*") == 0) { 43 buf = strdup(_defontfile); 44 goto build; 45 } 46 fd = open(fname, OREAD); 47 if(fd < 0 && strncmp(fname, "/lib/font/bit/", 14) == 0){ 48 nambuf = smprint("#9/font/%s", fname+14); 49 if(nambuf == nil) 50 return 0; 51 nambuf0 = unsharp(nambuf); 52 if(nambuf0 != nambuf) 53 free(nambuf); 54 nambuf = nambuf0; 55 if(nambuf == nil) 56 return 0; 57 if((fd = open(nambuf, OREAD)) < 0){ 58 free(nambuf); 59 return 0; 60 } 61 if(scale > 1) { 62 name = smprint("%d*%s", scale, nambuf); 63 freename = name; 64 } else { 65 name = nambuf; 66 } 67 } 68 if(fd >= 0) 69 n = _drawflength(fd); 70 if(fd < 0 && strncmp(fname, "/mnt/font/", 10) == 0) { 71 fd = _fontpipe(fname+10); 72 n = 1024*1024; 73 } 74 if(fd < 0){ 75 free(nambuf); 76 free(freename); 77 return 0; 78 } 79 80 buf = malloc(n+1); 81 if(buf == 0){ 82 close(fd); 83 free(nambuf); 84 free(freename); 85 return 0; 86 } 87 i = readn(fd, buf, n); 88 close(fd); 89 if(i <= 0){ 90 free(buf); 91 free(nambuf); 92 free(freename); 93 return 0; 94 } 95 buf[i] = 0; 96 build: 97 fnt = buildfont(d, buf, name); 98 free(buf); 99 free(nambuf); 100 free(freename); 101 if(scale != 1) { 102 fnt->scale = scale; 103 fnt->height *= scale; 104 fnt->ascent *= scale; 105 fnt->width *= scale; 106 } 107 return fnt; 108 } 109 110 void 111 swapfont(Font *targ, Font **oldp, Font **newp) 112 { 113 Font f, *old, *new; 114 115 if(targ != *oldp) 116 sysfatal("bad swapfont %p %p %p", targ, *oldp, *newp); 117 118 old = *oldp; 119 new = *newp; 120 121 f.name = old->name; 122 f.display = old->display; 123 f.height = old->height; 124 f.ascent = old->ascent; 125 f.width = old->width; 126 f.nsub = old->nsub; 127 f.age = old->age; 128 f.maxdepth = old->maxdepth; 129 f.ncache = old->ncache; 130 f.nsubf = old->nsubf; 131 f.scale = old->scale; 132 f.cache = old->cache; 133 f.subf = old->subf; 134 f.sub = old->sub; 135 f.cacheimage = old->cacheimage; 136 137 old->name = new->name; 138 old->display = new->display; 139 old->height = new->height; 140 old->ascent = new->ascent; 141 old->width = new->width; 142 old->nsub = new->nsub; 143 old->age = new->age; 144 old->maxdepth = new->maxdepth; 145 old->ncache = new->ncache; 146 old->nsubf = new->nsubf; 147 old->scale = new->scale; 148 old->cache = new->cache; 149 old->subf = new->subf; 150 old->sub = new->sub; 151 old->cacheimage = new->cacheimage; 152 153 new->name = f.name; 154 new->display = f.display; 155 new->height = f.height; 156 new->ascent = f.ascent; 157 new->width = f.width; 158 new->nsub = f.nsub; 159 new->age = f.age; 160 new->maxdepth = f.maxdepth; 161 new->ncache = f.ncache; 162 new->nsubf = f.nsubf; 163 new->scale = f.scale; 164 new->cache = f.cache; 165 new->subf = f.subf; 166 new->sub = f.sub; 167 new->cacheimage = f.cacheimage; 168 169 *oldp = new; 170 *newp = old; 171 } 172 173 static char* 174 hidpiname(Font *f) 175 { 176 char *p, *q; 177 int size; 178 179 // If font name has form x,y return y. 180 p = strchr(f->namespec, ','); 181 if(p != nil) 182 return strdup(p+1); 183 184 // If font name is /mnt/font/Name/Size/font, scale Size. 185 if(strncmp(f->name, "/mnt/font/", 10) == 0) { 186 p = strchr(f->name+10, '/'); 187 if(p == nil || *++p < '0' || *p > '9') 188 goto scale; 189 q = p; 190 size = 0; 191 while('0' <= *q && *q <= '9') 192 size = size*10 + *q++ - '0'; 193 return smprint("%.*s%d%s", utfnlen(f->name, p-f->name), f->name, size*2, q); 194 } 195 196 // Otherwise use pixel doubling. 197 scale: 198 return smprint("%d*%s", f->scale*2, f->name); 199 } 200 201 void 202 loadhidpi(Font *f) 203 { 204 char *name; 205 Font *fnew; 206 207 if(f->hidpi == f) 208 return; 209 if(f->hidpi != nil) { 210 swapfont(f, &f->lodpi, &f->hidpi); 211 return; 212 } 213 214 name = hidpiname(f); 215 fnew = openfont1(f->display, name); 216 if(fnew == nil) 217 return; 218 f->hidpi = fnew; 219 free(name); 220 221 swapfont(f, &f->lodpi, &f->hidpi); 222 } 223 224 Font* 225 openfont(Display *d, char *name) 226 { 227 Font *f; 228 char *p; 229 char *namespec; 230 231 // If font name has form x,y use x for lodpi, y for hidpi. 232 name = strdup(name); 233 namespec = strdup(name); 234 if((p = strchr(name, ',')) != nil) 235 *p = '\0'; 236 237 f = openfont1(d, name); 238 if(!f) 239 return nil; 240 f->lodpi = f; 241 free(f->namespec); 242 f->namespec = namespec; 243 244 /* add to display list for when dpi changes */ 245 /* d can be nil when invoked from mc. */ 246 if(d != nil) { 247 f->ondisplaylist = 1; 248 f->prev = d->lastfont; 249 f->next = nil; 250 if(f->prev) 251 f->prev->next = f; 252 else 253 d->firstfont = f; 254 d->lastfont = f; 255 256 /* if this is a hi-dpi display, find hi-dpi version and swap */ 257 if(d->dpi >= DefaultDPI*3/2) 258 loadhidpi(f); 259 } 260 261 free(name); 262 263 return f; 264 } 265 266 int 267 _fontpipe(char *name) 268 { 269 int p[2]; 270 char c; 271 char buf[1024], *argv[10]; 272 int nbuf, pid; 273 274 if(pipe(p) < 0) 275 return -1; 276 pid = rfork(RFNOWAIT|RFFDG|RFPROC); 277 if(pid < 0) { 278 close(p[0]); 279 close(p[1]); 280 return -1; 281 } 282 if(pid == 0) { 283 close(p[0]); 284 dup(p[1], 1); 285 dup(p[1], 2); 286 if(p[1] > 2) 287 close(p[1]); 288 argv[0] = "fontsrv"; 289 argv[1] = "-pp"; 290 argv[2] = name; 291 argv[3] = nil; 292 execvp("fontsrv", argv); 293 print("exec fontsrv: %r\n"); 294 _exit(0); 295 } 296 close(p[1]); 297 298 // success marked with leading \001. 299 // otherwise an error happened. 300 for(nbuf=0; nbuf<sizeof buf-1; nbuf++) { 301 if(read(p[0], &c, 1) < 1 || c == '\n') { 302 buf[nbuf] = '\0'; 303 werrstr(buf); 304 close(p[0]); 305 return -1; 306 } 307 if(c == '\001') 308 break; 309 } 310 return p[0]; 311 }