shithub: fnt

ref: c8e83c81d910049123621d766bc837abc9103145
dir: /otf.c.in/

View raw version
/* this file is generated. do not modify. */
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "otf.h"

typedef struct Range Range;

struct Otf {
	Biobuf *f;
	Range *r;
	u8int *buf;
	int bufsz;
	int off;
	/* extra fields to simplify parsing */
OTF_EXTRA_FIELDS
};

struct Range {
	int start;
	int len;
	int prevoff;
	Range *par;
};

#define rchr(s) (be ? ((s)[0]<<8 | (s)[1]) : ((s)[1]<<8 | (s)[0]))

static u8int mark[] = {0x00, 0x00, 0xc0, 0xe0, 0xf0};

static int
utf16to8(u8int *o, int osz, u8int *s, int sz)
{
	u32int c, c2;
	int i, wr, j, be;

	i = 0;
	be = 1;
	if(s[0] == 0xfe && s[1] == 0xff)
		i += 2;
	else if(s[0] == 0xff && s[1] == 0xfe){
		be = 0;
		i += 2;
	}

	for(; i < sz-1 && osz > 1;){
		c = rchr(&s[i]);
		i += 2;
		if(c >= 0xd800 && c <= 0xdbff && i < sz-1){
			c2 = rchr(&s[i]);
			if(c2 >= 0xdc00 && c2 <= 0xdfff){
				c = 0x10000 | (c - 0xd800)<<10 | (c2 - 0xdc00);
				i += 2;
			}else
				return -1;
		}else if(c >= 0xdc00 && c <= 0xdfff)
			return -1;

		if(c < 0x80)
			wr = 1;
		else if(c < 0x800)
			wr = 2;
		else if(c < 0x10000)
			wr = 3;
		else
			wr = 4;

		osz -= wr;
		if(osz < 1)
			break;

		o += wr;
		for(j = wr; j > 1; j--){
			*(--o) = (c & 0xbf) | 0x80;
			c >>= 6;
		}
		*(--o) = (u8int)c | mark[wr];
		o += wr;
	}

	*o = 0;
	return i;
}

static char *
strtoutf8(Otf *o, u8int *in, int sz)
{
	char *s;

	// FIXME this is not sufficient, obviously - need more platform/encoding handling
	if(o->platformID == 0 || (o->platformID == 3 && o->encodingID == 1)){
		s = malloc(sz/2+1);
		utf16to8((u8int*)s, sz/2+1, in, sz);
	}else{
		s = malloc(sz+1);
		memcpy(s, in, sz);
		s[sz] = 0;
	}
	return s;
}

Otf *
otfopen(char *path)
{
	Otf *o;
	Biobuf *f;

	if((f = Bopen(path, OREAD)) == nil)
		return nil;
	if((o = calloc(1, sizeof(*o))) == nil){
		werrstr("no memory");
		Bterm(f);
	}else{
		o->f = f;
	}
	return o;
}

void
otfclose(Otf *o)
{
	if(o == nil)
		return;
	// FIXME traverse and free everything
	free(o);
}

static int
otfpushrange(Otf *o, int off, int len)
{
	Range *r;
	int x;

	r = nil;
	if(o->r != nil){
		if(len < 0)
			len = o->r->len - off;
		if(len < 0 || off+len > o->r->len){
			werrstr("range overflow (len %d) by %d bytes", len, off+len - o->r->len);
			goto err;
		}
		off += o->r->start;
	}else if(len < 0){
		len = 0x7fffffff;
	}
	if((r = malloc(sizeof(*r))) == nil){
		werrstr("no memory");
		goto err;
	}
	r->par = o->r;
	r->start = off;
	r->len = len;
	r->prevoff = o->off;
	if((x = Bseek(o->f, off, 0)) != off){
		werrstr("seek offset: need %d, got %d", off, x);
		goto err;
	}
	o->off = off;
	o->r = r;
	return 0;
err:
	free(r);
	return -1;
}

static int
otfpoprange(Otf *o)
{
	Range *r;
	int x;

	r = o->r;
	if(r == nil){
		werrstr("pop without push");
		goto err;
	}
	if((x = Bseek(o->f, r->prevoff, 0)) != r->prevoff){
		werrstr("seek offset: need %d, got %d", r->prevoff, x);
		goto err;
	}
	o->off = r->prevoff;
	o->r = r->par;
	free(r);
	return 0;
err:
	return -1;
}

static u8int *
otfreadn(Otf *o, int n)
{
	Range *r;
	u8int *b;
	int x;

	r = o->r;
	if(r != nil && o->off+n > r->start+r->len){
		werrstr("need %d at %d, have %d at %d", n, o->off, r->len, r->start);
		goto err;
	}
	if(n > o->bufsz){
		if((b = realloc(o->buf, n)) == nil){
			werrstr("no memory");
			goto err;
		}
		o->buf = b;
		o->bufsz = n;
	}
	if((x = Bread(o->f, o->buf, n)) != n){
		werrstr("need %d, got %d; off %d", n, x, o->off);
		goto err;
	}
	o->off += n;

	return o->buf;
err:
	return nil;
}

static int
otfarray(Otf *o, void **arr_, void *fun_, int elsz, int num)
{
	int i;
	int (*fun)(Otf*, void*);
	u8int *arr;

	if((arr = calloc(num, elsz)) == nil){
		werrstr("no memory");
		goto err;
	}
	fun = fun_;
	for(i = 0; i < num; i++){
		if(fun(o, arr + i*elsz) < 0)
			goto err;
	}
	*arr_ = arr;
	return 0;
err:
	free(arr);
	return -1;
}

static int
read_ComponentGlyph(Otf *o, ComponentGlyph **out, int instr)
{
	ComponentGlyph *v;
	u8int *b;

	if((v = calloc(1, sizeof(*v))) == nil){
nomem:
		werrstr("no memory");
		goto err;
	}

	if((b = otfreadn(o, 2*2)) == nil)
		goto err;
	v->flags = b[0]<<8 | b[1];
	v->glyphIndex = b[2]<<8 | b[3];
	instr |= v->flags & CGLYPH_FL_INSTRUCTIONS;

	if((v->flags & CGLYPH_FL_WORD_ARGS) != 0 && (b = otfreadn(o, 2*2)) != nil){
		v->arg1.u16 = b[0]<<8 | b[1];
		v->arg2.u16 = b[2]<<8 | b[3];
	}else if((b = otfreadn(o, 2)) != nil){
		v->arg1.u8 = b[0];
		v->arg2.u8 = b[1];
	}
	if(b == nil)
		goto err;
	if((v->flags & CGLYPH_FL_SCALE) != 0 && (b = otfreadn(o, 2)) != nil){
		v->scale = (b[0]<<8 | b[1]>>14)+(b[0]<<8 | b[1]&((1<<14)-1))/16384.0;
	}else if((v->flags & CGLYPH_FL_SCALE_XY) != 0 && (b = otfreadn(o, 2*2)) != nil){
		v->scaleX = (b[0]<<8 | b[1]>>14)+(b[0]<<8 | b[1]&((1<<14)-1))/16384.0;
		v->scaleY = (b[2]<<8 | b[3]>>14)+(b[2]<<8 | b[3]&((1<<14)-1))/16384.0;
	}else if((v->flags & CGLYPH_FL_2X2_TRANSFORM) != 0 && (b = otfreadn(o, 2*2*2)) != nil){
		v->scaleX = (b[0]<<8 | b[1]>>14)+(b[0]<<8 | b[1]&((1<<14)-1))/16384.0;
		v->scale01 = (b[2]<<8 | b[3]>>14)+(b[2]<<8 | b[3]&((1<<14)-1))/16384.0;
		v->scale10 = (b[4]<<8 | b[5]>>14)+(b[4]<<8 | b[5]&((1<<14)-1))/16384.0;
		v->scaleY = (b[6]<<8 | b[7]>>14)+(b[6]<<8 | b[7]&((1<<14)-1))/16384.0;
	}
	if(b == nil)
		goto err;
	if((v->flags & CGLYPH_FL_MORE_COMPONENTS) != 0){
		if(read_ComponentGlyph(o, &v->next, instr) != 0){
			free(v);
			return -1;
		}
	}else if(instr != 0){
		if((b = otfreadn(o, 2)) == nil)
			goto err;
		v->numInstr = b[0]<<8 | b[1];
		if((v->instr = malloc(v->numInstr)) == nil)
			goto nomem;
		if(v->numInstr > 0 && (b = otfreadn(o, v->numInstr)) == nil)
			goto err;
		memcpy(v->instr, b, v->numInstr);
	}
	*out = v;
	return 0;
err:
	if(v != nil)
		free(v->instr);
	free(v);
	werrstr("ComponentGlyph: %r");
	return -1;
}

enum {
	GLYPH_FL_ON_CURVE_POINT = 1<<0,
	GLYPH_FL_X_SHORT_VECTOR = 1<<1,
	GLYPH_FL_Y_SHORT_VECTOR = 1<<2,
	GLYPH_FL_REPEAT = 1<<3,
	GLYPH_FL_X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR = 1<<4,
	GLYPH_FL_Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR = 1<<5,
	GLYPH_FL_OVERLAP_SIMPLE = 1<<6,
};

static int
read_SimpleGlyph(Otf *o, SimpleGlyph **out)
{
	SimpleGlyph *v;
	u8int *b, *flags;
	int i, n, nflags, c;

	flags = nil;
	if((v = calloc(1, sizeof(*v))) == nil){
nomem:
		werrstr("no memory");
		goto err;
	}

	n = o->numberOfContours;
	if((b = otfreadn(o, 2*n+2)) == nil)
		goto err;
	if((v->endPtsOfContours = malloc(2*n)) == nil)
		goto nomem;
	for(int i = 0; i < n; i++)
		v->endPtsOfContours[i] = b[2*i+0]<<8 | b[2*i+1];

	v->instructionLength = b[2*n+0]<<8 | b[2*n+1];
	n = v->instructionLength;
	if((b = otfreadn(o, n)) == nil)
		goto err;
	if((v->instructions = malloc(n)) == nil)
		goto nomem;
	memcpy(v->instructions, b, n);

	if((flags = malloc(v->numPoints)) == nil) /* not supposed to be more than that, 64Kb max */
		goto nomem;
	for(nflags = 0; nflags < v->numPoints;){
		if((b = otfreadn(o, 1)) == nil)
			goto err;
		flags[nflags] = *b;
		if((flags[nflags] & GLYPH_FL_REPEAT) != 0){
			flags[nflags] ^= GLYPH_FL_REPEAT;
			if((b = otfreadn(o, 1)) == nil)
				goto err;
			if(nflags + 1 + *b > v->numPoints){
				werrstr("repeat overflow");
				goto err;
			}
			memset(flags+nflags+1, flags[nflags], *b);
			nflags += 1 + *b;
		}else{
			nflags++;
		}
	}

	v->numPoints = v->endPtsOfContours[o->numberOfContours-1];
	if((v->points = calloc(v->numPoints, sizeof(*v->points))) == nil)
		goto nomem;

	/* flags first */
	for(i = n = 0; i < nflags && n < v->numPoints; i++, n++)
		v->points[n].onCurve = (flags[i] & GLYPH_FL_ON_CURVE_POINT) != 0;

	/* read packed x coordinates */
	c = 0;
	for(i = n = 0; i < nflags && n < v->numPoints; i++){
		if((flags[i] & GLYPH_FL_X_SHORT_VECTOR) != 0){
			if((b = otfreadn(o, 1)) == nil)
				goto err;
			c = *b;
			if((flags[i] & GLYPH_FL_X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) == 0)
				c = -c;
			v->points[n++].x = c;
		}else if((flags[i] & GLYPH_FL_X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) != 0){
			v->points[n++].x = c;
		}else{
			if((b = otfreadn(o, 2)) == nil)
				goto err;
			c += (s16int)(b[0]<<8 | b[1]);
			v->points[n++].x = c;
		}
	}

	/* read packed y coordinates */
	c = 0;
	for(i = n = 0; i < nflags && n < v->numPoints; i++){
		if((flags[i] & GLYPH_FL_Y_SHORT_VECTOR) != 0){
			if((b = otfreadn(o, 1)) == nil)
				goto err;
			c = *b;
			if((flags[i] & GLYPH_FL_Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) == 0)
				c = -c;
			v->points[n++].y = c;
		}else if((flags[i] & GLYPH_FL_Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) != 0){
			v->points[n++].y = c;
		}else{
			if((b = otfreadn(o, 2)) == nil)
				goto err;
			c += (s16int)(b[0]<<8 | b[1]);
			v->points[n++].y = c;
		}
	}

	free(flags);
	*out = v;
	return 0;
err:
	free(flags);
	if(v != nil){
		free(v->endPtsOfContours);
		free(v->instructions);
		free(v->points);
	}
	free(v);
	werrstr("SimpleGlyph: %r");
	return -1;
}

int indentΔ = 2;

static int
Tfmt(Fmt *f)
{
	Tm t;
	s64int v = va_arg(f->args, s64int);
	return fmtprint(f, "%τ", tmfmt(tmtime(&t, v, nil), nil));
}

static int
Vfmt(Fmt *f)
{
	u32int v = va_arg(f->args, u32int);
	return fmtprint(f, "%d.%d", v>>16, v&0xffff);
}

static int
tfmt(Fmt *f)
{
	u32int v = va_arg(f->args, u32int);
	if(v == 0)
		return fmtprint(f, "<nil>");
	return fmtprint(f, "%c%c%c%c", v>>24, v>>16, v>>8, v>>0);
}

void
otfinit(void)
{
	tmfmtinstall();
	fmtinstall('V', Vfmt);
	fmtinstall('T', Tfmt);
	fmtinstall('t', tfmt);
}