Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
5 extern vlong _drawflength(int);
6 int _fontpipe(char*);
8 int
9 parsefontscale(char *name, char **base)
10 {
11 char *p;
12 int scale;
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 }
29 extern char _defontfile[];
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;
38 nambuf = 0;
39 freename = nil;
40 scale = parsefontscale(name, &fname);
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 }
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;
107 return fnt;
110 void
111 swapfont(Font *targ, Font **oldp, Font **newp)
113 Font f, *old, *new;
115 if(targ != *oldp)
116 sysfatal("bad swapfont %p %p %p", targ, *oldp, *newp);
118 old = *oldp;
119 new = *newp;
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;
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;
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;
169 *oldp = new;
170 *newp = old;
173 static char*
174 hidpiname(Font *f)
176 char *p, *q;
177 int size;
179 // If font name has form x,y return y.
180 p = strchr(f->namespec, ',');
181 if(p != nil)
182 return strdup(p+1);
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);
196 // Otherwise use pixel doubling.
197 scale:
198 return smprint("%d*%s", f->scale*2, f->name);
201 void
202 loadhidpi(Font *f)
204 char *name;
205 Font *fnew;
207 if(f->hidpi == f)
208 return;
209 if(f->hidpi != nil) {
210 swapfont(f, &f->lodpi, &f->hidpi);
211 return;
214 name = hidpiname(f);
215 fnew = openfont1(f->display, name);
216 if(fnew == nil)
217 return;
218 f->hidpi = fnew;
219 free(name);
221 swapfont(f, &f->lodpi, &f->hidpi);
224 Font*
225 openfont(Display *d, char *name)
227 Font *f;
228 char *p;
229 char *namespec;
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';
237 f = openfont1(d, name);
238 if(!f)
239 return nil;
240 f->lodpi = f;
241 free(f->namespec);
242 f->namespec = namespec;
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;
256 /* if this is a hi-dpi display, find hi-dpi version and swap */
257 if(d->dpi >= DefaultDPI*3/2)
258 loadhidpi(f);
261 free(name);
263 return f;
266 int
267 _fontpipe(char *name)
269 int p[2];
270 char c;
271 char buf[1024], *argv[10];
272 int nbuf, pid;
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;
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);
296 close(p[1]);
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;
307 if(c == '\001')
308 break;
310 return p[0];