diff options
author | aiju <devnull@localhost> | 2018-10-07 11:11:39 +0000 |
---|---|---|
committer | aiju <devnull@localhost> | 2018-10-07 11:11:39 +0000 |
commit | 4e4f2aca32c3409a5fca3341dccd14318c18f9b1 (patch) | |
tree | 442c77eb38f433e23526b49c3b076c8b66d0577f /sys/src/cmd/truetypefs.c | |
parent | ce062debb1edaa27548deea0f151a9d4c95414a7 (diff) |
add (unfinished but working) truetypefs
Diffstat (limited to 'sys/src/cmd/truetypefs.c')
-rw-r--r-- | sys/src/cmd/truetypefs.c | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/sys/src/cmd/truetypefs.c b/sys/src/cmd/truetypefs.c new file mode 100644 index 000000000..bcae086e7 --- /dev/null +++ b/sys/src/cmd/truetypefs.c @@ -0,0 +1,434 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include <fcall.h> +#include <9p.h> +#include <bio.h> +#include <ttf.h> + +static char Egreg[] = "my memory of truetype is fading"; +static char Enoent[] = "not found"; + +enum { MAXSUB = 0x100 }; + +typedef struct TFont TFont; +typedef struct TSubfont TSubfont; + +struct TFont { + int ref; + Qid qid; + Qid fileqid; + char *fontfile; + int nfontfile; + TTFont *ttf; + char *name9p; + char *name; + int size; + TFont *next, *prev; + TSubfont *sub[256]; +}; + +struct TSubfont { + TFont *font; + Rune start, end; + Qid qid; + char *data; + int ndata; + TSubfont *next; +}; + +typedef struct FidAux FidAux; + +struct FidAux { + enum { + FIDROOT, + FIDFONT, + FIDFONTF, + FIDSUB, + } type; + TFont *f; + TSubfont *sub; +}; + +TFont fontl = {.next = &fontl, .prev = &fontl}; + +static void * +emalloc(ulong n) +{ + void *v; + + v = mallocz(n, 1); + if(v == nil) sysfatal("malloc: %r"); + setmalloctag(v, getcallerpc(&n)); + return v; +} + +static uvlong +qidgen(void) +{ + static uvlong x; + + return ++x; +} + +static void +fsattach(Req *r) +{ + r->ofcall.qid = (Qid){0, 0, QTDIR}; + r->fid->qid = r->ofcall.qid; + r->fid->aux = emalloc(sizeof(FidAux)); + respond(r, nil); +} + +void +mksubfonts(TFont *f) +{ + int k; + TTChMap *c; + TTFontU *u; + TSubfont *s; + Fmt fmt; + int got0; + + u = f->ttf->u; + fmtstrinit(&fmt); + fmtprint(&fmt, "%d\t%d\n", f->ttf->ascentpx + f->ttf->descentpx, f->ttf->ascentpx); + got0 = 0; + for(c = u->cmap; c < u->cmap + u->ncmap; c++){ + for(k = c->start; k < c->end; k += MAXSUB){ + s = emalloc(sizeof(TSubfont)); + s->start = c->start; + if(c->start == 0) got0 = 1; + s->end = k + MAXSUB - 1; + if(s->end > c->end) + s->end = c->end; + s->font = f; + s->qid = (Qid){qidgen(), 0, 0}; + s->next = f->sub[c->start >> 8 & 0xff]; + f->sub[c->start >> 8 & 0xff] = s; + fmtprint(&fmt, "%#.4ux\t%#.4ux\ts.%.4ux-%.4ux\n", s->start, s->end, s->start, s->end); + } + } + if(!got0){ + s = emalloc(sizeof(TSubfont)); + s->start = 0; + s->end = 0; + s->font = f; + s->qid = (Qid){qidgen(), 0, 0}; + s->next = f->sub[0]; + f->sub[0] = s; + fmtprint(&fmt, "%#.4ux\t%#.4ux\ts.%.4ux-%.4ux\n", 0, 0, 0, 0); + } + f->fontfile = fmtstrflush(&fmt); + f->nfontfile = strlen(f->fontfile); +} + +static void +blit(uchar *t, int x, int y, int tstride, uchar *s, int w, int h) +{ + int tx, ty, sx, sy; + u16int b; + uchar *tp, *sp; + + if(y < 0) y = 0; + ty = y; + sp = s; + for(sy = 0; sy < h; sy++, ty++){ + tx = x; + tp = t + ty * tstride + (tx >> 3); + b = 0; + for(sx = 0; sx < w; sx += 8){ + b |= *sp++ << 8 - (tx & 7); + *tp++ |= b >> 8; + b <<= 8; + } + *tp |= b >> 8; + } +} + +static void +compilesub(TFont *f, TSubfont *s) +{ + int n, i, w, x, h, g, sz; + char *d, *p; + TTGlyph **gs; + TTFont *t; + + t = f->ttf; + n = s->end - s->start + 1; + gs = emalloc9p(sizeof(TTGlyph *) * n); + w = 0; + h = t->ascentpx + t->descentpx; + for(i = 0; i < n; i++){ + if(s->start + i == 0) + g = 0; + else + g = ttffindchar(t, s->start + i); + gs[i] = ttfgetglyph(t, g, 1); + w += gs[i]->width; + } + sz = 5 * 12 + (w+7>>3) * h + 3 * 12 + (n + 1) * 6; + d = emalloc(sz); + p = d + sprint(d, "%11s %11d %11d %11d %11d ", "k1", 0, 0, w, h); + x = 0; + for(i = 0; i < n; i++){ + blit((uchar*)p, x, t->ascentpx - gs[i]->ymaxpx, w+7>>3, gs[i]->bit, gs[i]->width, gs[i]->height); + x += gs[i]->width; + } + p += (w+7>>3) * h; + p += sprint(p, "%11d %11d %11d ", n, h, t->ascentpx); + x = 0; + for(i = 0; i < n; i++){ + *p++ = x; + *p++ = x >> 8; + *p++ = 0; + *p++ = h; + *p++ = gs[i]->xminpx; + *p++ = gs[i]->advanceWidthpx; + x += gs[i]->width; + } + *p++ = x; + *p = x >> 8; + s->data = d; + s->ndata = sz; + for(i = 0; i < n; i++) + ttfputglyph(gs[i]); + free(gs); +} + + +TFont * +tryfont(char *name) +{ + TTFont *ttf; + TFont *f; + char *d, *buf, *p; + int sz; + + for(f = fontl.next; f != &fontl; f = f->next) + if(strcmp(f->name9p, name) == 0) + return f; + d = strrchr(name, '.'); + if(d == nil){ + inval: + werrstr("invalid file name"); + return nil; + } + sz = strtol(d + 1, &p, 10); + if(d[1] == 0 || *p != 0) + goto inval; + buf = estrdup9p(name); + buf[d - name] = 0; + ttf = ttfopen(buf, sz, 0); + if(ttf == nil){ + free(buf); + return nil; + } + f = emalloc(sizeof(TFont)); + f->ttf = ttf; + f->name9p = strdup(name); + f->name = buf; + f->size = sz; + f->qid = (Qid){qidgen(), 0, QTDIR}; + f->fileqid = (Qid){qidgen(), 0, 0}; + f->next = &fontl; + f->prev = fontl.prev; + f->next->prev = f; + f->prev->next = f; + mksubfonts(f); + return f; +} + +static char * +fsclone(Fid *old, Fid *new) +{ + new->aux = emalloc(sizeof(FidAux)); + *(FidAux*)new->aux = *(FidAux*)old->aux; + return nil; +} + +static void +fsdestroyfid(Fid *f) +{ + FidAux *fa; + + fa = f->aux; + free(fa); + f->aux = nil; +} + +static TSubfont * +findsubfont(TFont *f, char *name) +{ + char *p, *q; + char buf[16]; + int a, b; + TSubfont *s; + + if(name[0] != 's' || name[1] != '.' || name[2] == '-') + return nil; + a = strtol(name + 2, &p, 16); + if(*p != '-') + return nil; + b = strtol(p + 1, &q, 16); + if(p + 1 == q || *q != 0) + return nil; + snprint(buf, nelem(buf), "s.%.4ux-%.4ux", a, b); + if(strcmp(buf, name) != 0) + return nil; + for(s = f->sub[a>>8&0xff]; s != nil; s = s->next) + if(s->start == a && s->end == b) + break; + return s; +} + +static char * +fswalk(Fid *fid, char *name, Qid *qid) +{ + static char errbuf[ERRMAX]; + FidAux *fa; + + fa = fid->aux; + assert(fa != nil); + switch(fa->type){ + case FIDROOT: + fa->f = tryfont(name); + if(fa->f == nil){ + rerrstr(errbuf, nelem(errbuf)); + return errbuf; + } + fa->f->ref++; + fa->type = FIDFONT; + fid->qid = fa->f->qid; + *qid = fa->f->qid; + return nil; + case FIDFONT: + if(strcmp(name, "font") == 0){ + fa->type = FIDFONTF; + fid->qid = fa->f->fileqid; + *qid = fa->f->fileqid; + return nil; + } + fa->sub = findsubfont(fa->f, name); + if(fa->sub == nil) + return Enoent; + fa->type = FIDSUB; + fid->qid = fa->sub->qid; + *qid = fa->sub->qid; + return nil; + default: + return Egreg; + } +} + +static void +fsstat(Req *r) +{ + FidAux *fa; + + fa = r->fid->aux; + assert(fa != nil); + r->d.uid = estrdup9p(getuser()); + r->d.gid = estrdup9p(getuser()); + r->d.muid = estrdup9p(getuser()); + r->d.mtime = r->d.atime = time(0); + r->d.qid = r->fid->qid; + switch(fa->type){ + case FIDROOT: + r->d.mode = 0777; + r->d.name = estrdup9p("/"); + respond(r, nil); + break; + case FIDFONT: + r->d.mode = 0777; + r->d.name = estrdup9p(fa->f->name9p); + respond(r, nil); + break; + case FIDFONTF: + r->d.mode = 0666; + r->d.name = estrdup9p("font"); + r->d.length = fa->f->nfontfile; + respond(r, nil); + break; + case FIDSUB: + r->d.mode = 0666; + r->d.name = smprint("s.%.4ux-%.4ux", fa->sub->start, fa->sub->end); + r->d.length = fa->sub->ndata; + respond(r, nil); + break; + default: + respond(r, Egreg); + } +} + +static int +fontdirread(int n, Dir *d, void *aux) +{ + FidAux *fa; + + fa = aux; + if(n == 0){ + d->name = estrdup9p("font"); + d->uid = estrdup9p(getuser()); + d->gid = estrdup9p(getuser()); + d->muid = estrdup9p(getuser()); + d->mode = 0666; + d->qid = fa->f->fileqid; + d->mtime = d->atime = time(0); + d->length = fa->f->nfontfile; + return 0; + } + return -1; +} + +static void +fsread(Req *r) +{ + FidAux *fa; + + fa = r->fid->aux; + assert(fa != nil); + switch(fa->type){ + case FIDROOT: + respond(r, nil); + break; + case FIDFONT: + dirread9p(r, fontdirread, fa); + respond(r, nil); + break; + case FIDFONTF: + readbuf(r, fa->f->fontfile, fa->f->nfontfile); + respond(r, nil); + break; + case FIDSUB: + if(fa->sub->data == nil) + compilesub(fa->f, fa->sub); + readbuf(r, fa->sub->data, fa->sub->ndata); + respond(r, nil); + break; + default: + respond(r, Egreg); + } +} + +Srv fssrv = { + .attach = fsattach, + .walk1 = fswalk, + .clone = fsclone, + .stat = fsstat, + .read = fsread, + .destroyfid = fsdestroyfid, +}; + +void +main(int argc, char **argv) +{ + ARGBEGIN { + default: + sysfatal("usage"); + } ARGEND; + + unmount(nil, "/n/ttf"); + postmountsrv(&fssrv, nil, "/n/ttf", 0); + exits(nil); +} |