]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/truetypefs.c
etheriwl: don't break controller on command flush timeout
[plan9front.git] / sys / src / cmd / truetypefs.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <fcall.h>
5 #include <9p.h>
6 #include <bio.h>
7 #include <ttf.h>
8
9 static char Egreg[] = "my memory of truetype is fading";
10 static char Enoent[] = "not found";
11
12 static char *fontpath = "/lib/font/ttf";
13
14 enum { MAXSUB = 0x100 };
15
16 typedef struct TFont TFont;
17 typedef struct TSubfont TSubfont;
18
19 struct TFont {
20         int ref;
21         Qid qid;
22         Qid fileqid;
23         char *fontfile;
24         int nfontfile;
25         TTFont *ttf;
26         char *name9p;
27         char *name;
28         int size;
29         TFont *next, *prev;
30         TSubfont *sub[256];
31 };
32
33 struct TSubfont {
34         TFont *font;
35         Rune start, end;
36         Qid qid;
37         char *data;
38         int ndata;
39         TSubfont *next;
40 };
41
42 typedef struct FidAux FidAux;
43
44 struct FidAux {
45         enum {
46                 FIDROOT,
47                 FIDFONT,
48                 FIDFONTF,
49                 FIDSUB,
50         } type;
51         TFont *f;
52         TSubfont *sub;
53 };
54
55 TFont fontl = {.next = &fontl, .prev = &fontl};
56
57 static void *
58 emalloc(ulong n)
59 {
60         void *v;
61         
62         v = mallocz(n, 1);
63         if(v == nil) sysfatal("malloc: %r");
64         setmalloctag(v, getcallerpc(&n));
65         return v;
66 }
67
68 static uvlong
69 qidgen(void)
70 {
71         static uvlong x;
72         
73         return ++x;
74 }
75
76 static void
77 fsattach(Req *r)
78 {
79         r->ofcall.qid = (Qid){0, 0, QTDIR};
80         r->fid->qid = r->ofcall.qid;
81         r->fid->aux = emalloc(sizeof(FidAux));
82         respond(r, nil);
83 }
84
85 void
86 mksubfonts(TFont *f)
87 {
88         int k;
89         TTChMap *c;
90         TTFontU *u;
91         TSubfont *s;
92         Fmt fmt;
93         int got0;
94         
95         u = f->ttf->u;
96         fmtstrinit(&fmt);
97         fmtprint(&fmt, "%d\t%d\n", f->ttf->ascentpx + f->ttf->descentpx, f->ttf->ascentpx);
98         got0 = 0;
99         for(c = u->cmap; c < u->cmap + u->ncmap; c++){
100                 for(k = c->start; k < c->end; k += MAXSUB){
101                         s = emalloc(sizeof(TSubfont));
102                         s->start = k;
103                         if(k == 0) got0 = 1;
104                         s->end = k + MAXSUB - 1;
105                         if(s->end > c->end)
106                                 s->end = c->end;
107                         s->font = f;
108                         s->qid = (Qid){qidgen(), 0, 0};
109                         s->next = f->sub[k >> 8 & 0xff];
110                         f->sub[k >> 8 & 0xff] = s;
111                         fmtprint(&fmt, "%#.4ux\t%#.4ux\ts.%.4ux-%.4ux\n", s->start, s->end, s->start, s->end);
112                 }
113         }
114         if(!got0){
115                 s = emalloc(sizeof(TSubfont));
116                 s->start = 0;
117                 s->end = 0;
118                 s->font = f;
119                 s->qid = (Qid){qidgen(), 0, 0};
120                 s->next = f->sub[0];
121                 f->sub[0] = s;
122                 fmtprint(&fmt, "%#.4ux\t%#.4ux\ts.%.4ux-%.4ux\n", 0, 0, 0, 0);
123         }
124         f->fontfile = fmtstrflush(&fmt);
125         f->nfontfile = strlen(f->fontfile);
126 }
127
128 static void
129 blit(uchar *t, int x, int y, int tstride, uchar *s, int w, int h)
130 {
131         int tx, ty, sx, sy;
132         u16int b;
133         uchar *tp, *sp;
134         
135         if(y < 0) y = 0;
136         ty = y;
137         sp = s;
138         for(sy = 0; sy < h; sy++, ty++){
139                 tx = x;
140                 tp = t + ty * tstride + (tx >> 3);
141                 b = 0;
142                 for(sx = 0; sx < w; sx += 8){
143                         b |= *sp++ << 8 - (tx & 7);
144                         *tp++ |= b >> 8;
145                         b <<= 8;
146                 }
147                 *tp |= b >> 8;
148         }
149 }
150
151 static void
152 compilesub(TFont *f, TSubfont *s)
153 {
154         int n, i, w, x, h, g, sz;
155         char *d, *p;
156         TTGlyph **gs;
157         TTFont *t;
158         
159         t = f->ttf;
160         n = s->end - s->start + 1;
161         gs = emalloc9p(sizeof(TTGlyph *) * n);
162         w = 0;
163         h = t->ascentpx + t->descentpx;
164         for(i = 0; i < n; i++){
165                 if(s->start + i == 0)
166                         g = 0;
167                 else
168                         g = ttffindchar(t, s->start + i);
169                 gs[i] = ttfgetglyph(t, g, 1);
170                 w += gs[i]->width;
171         }
172         sz = 5 * 12 + (w+7>>3) * h + 3 * 12 + (n + 1) * 6;
173         d = emalloc(sz);
174         p = d + sprint(d, "%11s %11d %11d %11d %11d ", "k1", 0, 0, w, h);
175         x = 0;
176         for(i = 0; i < n; i++){
177                 blit((uchar*)p, x, t->ascentpx - gs[i]->ymaxpx, w+7>>3, gs[i]->bit, gs[i]->width, gs[i]->height);
178                 x += gs[i]->width;
179         }
180         p += (w+7>>3) * h;
181         p += sprint(p, "%11d %11d %11d ", n, h, t->ascentpx);
182         x = 0;
183         for(i = 0; i < n; i++){
184                 *p++ = x;
185                 *p++ = x >> 8;
186                 *p++ = 0;
187                 *p++ = h;
188                 *p++ = gs[i]->xminpx;
189                 if(gs[i]->advanceWidthpx != 0)
190                         *p++ = gs[i]->advanceWidthpx;
191                 else
192                         *p++ = gs[i]->width;
193                 x += gs[i]->width;
194         }
195         *p++ = x;
196         *p = x >> 8;
197         s->data = d;
198         s->ndata = sz;
199         for(i = 0; i < n; i++)
200                 ttfputglyph(gs[i]);
201         free(gs);
202 }
203
204
205 TFont *
206 tryfont(char *name)
207 {
208         TTFont *ttf;
209         TFont *f;
210         char *d, *buf, *p;
211         int sz;
212         
213         for(f = fontl.next; f != &fontl; f = f->next)
214                 if(strcmp(f->name9p, name) == 0)
215                         return f;
216         d = strrchr(name, '.');
217         if(d == nil){
218         inval:
219                 werrstr("invalid file name");
220                 return nil;
221         }
222         sz = strtol(d + 1, &p, 10);
223         if(d[1] == 0 || *p != 0)
224                 goto inval;
225         buf = estrdup9p(name);
226         buf[d - name] = 0;
227         p = smprint("%s/%s", fontpath, buf);
228         if(p == nil)
229                 sysfatal("smprint: %r");
230         ttf = ttfopen(p, sz, 0);
231         free(p);
232         if(ttf == nil){
233                 free(buf);
234                 return nil;
235         }
236         f = emalloc(sizeof(TFont));
237         f->ttf = ttf;
238         f->name9p = strdup(name);
239         f->name = buf;
240         f->size = sz;
241         f->qid = (Qid){qidgen(), 0, QTDIR};
242         f->fileqid = (Qid){qidgen(), 0, 0};
243         f->next = &fontl;
244         f->prev = fontl.prev;
245         f->next->prev = f;
246         f->prev->next = f;
247         mksubfonts(f);
248         return f;
249 }
250
251 static char *
252 fsclone(Fid *old, Fid *new)
253 {
254         new->aux = emalloc(sizeof(FidAux));
255         *(FidAux*)new->aux = *(FidAux*)old->aux;
256         return nil;
257 }
258
259 static void
260 fsdestroyfid(Fid *f)
261 {
262         FidAux *fa;
263         
264         fa = f->aux;
265         free(fa);
266         f->aux = nil;
267 }
268
269 static TSubfont *
270 findsubfont(TFont *f, char *name)
271 {
272         char *p, *q;
273         char buf[16];
274         int a, b;
275         TSubfont *s;
276
277         if(name[0] != 's' || name[1] != '.' || name[2] == '-')
278                 return nil;
279         a = strtol(name + 2, &p, 16);
280         if(*p != '-')
281                 return nil;
282         b = strtol(p + 1, &q, 16);
283         if(p + 1 == q || *q != 0)
284                 return nil;
285         snprint(buf, nelem(buf), "s.%.4ux-%.4ux", a, b);
286         if(strcmp(buf, name) != 0)
287                 return nil;
288         for(s = f->sub[a>>8&0xff]; s != nil; s = s->next)
289                 if(s->start == a && s->end == b)
290                         break;
291         return s;
292 }
293
294 static char *
295 fswalk(Fid *fid, char *name, Qid *qid)
296 {
297         static char errbuf[ERRMAX];
298         FidAux *fa;
299
300         fa = fid->aux;
301         assert(fa != nil);
302         switch(fa->type){
303         case FIDROOT:
304                 fa->f = tryfont(name);
305                 if(fa->f == nil){
306                         rerrstr(errbuf, nelem(errbuf));
307                         return errbuf;
308                 }
309                 fa->f->ref++;
310                 fa->type = FIDFONT;
311                 fid->qid = fa->f->qid;
312                 *qid = fa->f->qid;
313                 return nil;
314         case FIDFONT:
315                 if(strcmp(name, "font") == 0){
316                         fa->type = FIDFONTF;
317                         fid->qid = fa->f->fileqid;
318                         *qid = fa->f->fileqid;
319                         return nil;
320                 }
321                 fa->sub = findsubfont(fa->f, name);
322                 if(fa->sub == nil)
323                         return Enoent;
324                 fa->type = FIDSUB;
325                 fid->qid = fa->sub->qid;
326                 *qid = fa->sub->qid;
327                 return nil;
328         default:
329                 return Egreg;
330         }
331 }
332
333 static void
334 fsstat(Req *r)
335 {
336         FidAux *fa;
337
338         fa = r->fid->aux;
339         assert(fa != nil);
340         r->d.uid = estrdup9p(getuser());
341         r->d.gid = estrdup9p(getuser());
342         r->d.muid = estrdup9p(getuser());
343         r->d.mtime = r->d.atime = time(0);
344         r->d.qid = r->fid->qid;
345         switch(fa->type){
346         case FIDROOT:
347                 r->d.mode = 0777;
348                 r->d.name = estrdup9p("/");
349                 respond(r, nil);
350                 break;
351         case FIDFONT:
352                 r->d.mode = 0777;
353                 r->d.name = estrdup9p(fa->f->name9p);
354                 respond(r, nil);
355                 break;
356         case FIDFONTF:
357                 r->d.mode = 0666;
358                 r->d.name = estrdup9p("font");
359                 r->d.length = fa->f->nfontfile;
360                 respond(r, nil);
361                 break;
362         case FIDSUB:
363                 r->d.mode = 0666;
364                 r->d.name = smprint("s.%.4ux-%.4ux", fa->sub->start, fa->sub->end);
365                 r->d.length = fa->sub->ndata;
366                 respond(r, nil);
367                 break;
368         default:
369                 respond(r, Egreg);
370         }
371 }
372
373 static int
374 fontdirread(int n, Dir *d, void *aux)
375 {
376         FidAux *fa;
377         
378         fa = aux;
379         if(n == 0){
380                 d->name = estrdup9p("font");
381                 d->uid = estrdup9p(getuser());
382                 d->gid = estrdup9p(getuser());
383                 d->muid = estrdup9p(getuser());
384                 d->mode = 0666;
385                 d->qid = fa->f->fileqid;
386                 d->mtime = d->atime = time(0);
387                 d->length = fa->f->nfontfile;
388                 return 0;
389         }
390         return -1;
391 }
392
393 static void
394 fsread(Req *r)
395 {
396         FidAux *fa;
397
398         fa = r->fid->aux;
399         assert(fa != nil);
400         switch(fa->type){
401         case FIDROOT:
402                 respond(r, nil);
403                 break;
404         case FIDFONT:
405                 dirread9p(r, fontdirread, fa);
406                 respond(r, nil);
407                 break;
408         case FIDFONTF:
409                 readbuf(r, fa->f->fontfile, fa->f->nfontfile);
410                 respond(r, nil);
411                 break;
412         case FIDSUB:
413                 if(fa->sub->data == nil)
414                         compilesub(fa->f, fa->sub);
415                 readbuf(r, fa->sub->data, fa->sub->ndata);
416                 respond(r, nil);
417                 break;
418         default:
419                 respond(r, Egreg);
420         }
421 }
422
423 Srv fssrv = {
424         .attach = fsattach,
425         .walk1 = fswalk,
426         .clone = fsclone,
427         .stat = fsstat,
428         .read = fsread,
429         .destroyfid = fsdestroyfid,
430 };
431
432 static void
433 usage(void)
434 {
435         fprint(2, "usage: %s [-F fontpath]\n", argv0);
436         exits("usage");
437 }
438
439 void
440 main(int argc, char **argv)
441 {
442         ARGBEGIN {
443         case 'F':
444                 fontpath = EARGF(usage());
445                 break;
446         default:
447                 usage();
448         } ARGEND;
449         
450         unmount(nil, "/n/ttf");
451         postmountsrv(&fssrv, nil, "/n/ttf", 0);
452         exits(nil);
453 }