shithub: riscv

Download patch

ref: 4e4f2aca32c3409a5fca3341dccd14318c18f9b1
parent: ce062debb1edaa27548deea0f151a9d4c95414a7
author: aiju <devnull@localhost>
date: Sun Oct 7 07:11:39 EDT 2018

add (unfinished but working) truetypefs

--- /dev/null
+++ b/sys/src/cmd/truetypefs.c
@@ -1,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);
+}