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