ref: 103afe43213f6cb1e6969ffa72fe0dab1db1c45e
dir: /otf.c.in/
/* this file is generated. do not modify. */
#include "otfsys.h"
#include "otf.h"
int indentΔ = 2;
typedef struct Range Range;
struct Otf {
Otfile *f;
Range *r;
u8int *buf;
int bufsz;
int off;
/* extra fields to simplify parsing */
TableDirectory td;
TableRecord glyf;
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(Otfile *f)
{
Otf *o;
if((o = calloc(1, sizeof(*o))) == nil){
werrstr("no memory");
}else{
o->f = f;
if(read_TableDirectory(o, &o->td) != 0){
free(o);
o = nil;
}
}
return o;
}
void
otfprint(Otf *o, Otfile *out, int indent)
{
print_TableDirectory(out, indent, o, &o->td);
}
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 = o->f->seek(o->f->aux, 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 = o->f->seek(o->f->aux, 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 void
otfpopranges(Otf *o)
{
while(o->r != nil)
otfpoprange(o);
}
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 = o->f->read(o->f->aux, 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;
}
enum {
CGLYPH_FL_WORD_ARGS = 1<<0,
CGLYPH_FL_SIGNED_XY = 1<<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){
if(v->flags & CGLYPH_FL_SIGNED_XY){
v->arg1 = (s16int)(b[0]<<8 | b[1]);
v->arg2 = (s16int)(b[2]<<8 | b[3]);
}else{
v->arg1 = b[0]<<8 | b[1];
v->arg1 = b[2]<<8 | b[3];
}
}else if((b = otfreadn(o, 2)) != nil){
if(v->flags & CGLYPH_FL_SIGNED_XY){
v->arg1 = (s8int)b[0];
v->arg2 = (s8int)b[1];
}else{
v->arg1 = b[0];
v->arg2 = 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;
}
void
print_ComponentGlyph(Otfile *f, int indent, Otf *o, ComponentGlyph *v)
{
void *a = f->aux;
f->print(a, "%*s%s: %#"PRIx16"%s%s%s%s%s%s%s%s%s%s\n", indent, "", "flags", v->flags,
(v->flags&CGLYPH_FL_ROUND_TO_GRID_XY)?" CGLYPH_FL_ROUND_TO_GRID_XY":"",
(v->flags&CGLYPH_FL_SCALE)?" CGLYPH_FL_SCALE":"",
(v->flags&CGLYPH_FL_MORE_COMPONENTS)?" CGLYPH_FL_MORE_COMPONENTS":"",
(v->flags&CGLYPH_FL_SCALE_XY)?" CGLYPH_FL_SCALE_XY":"",
(v->flags&CGLYPH_FL_2X2_TRANSFORM)?" CGLYPH_FL_2X2_TRANSFORM":"",
(v->flags&CGLYPH_FL_INSTRUCTIONS)?" CGLYPH_FL_INSTRUCTIONS":"",
(v->flags&CGLYPH_FL_METRICS)?" CGLYPH_FL_METRICS":"",
(v->flags&CGLYPH_FL_OVERLAP_COMPOUND)?" CGLYPH_FL_OVERLAP_COMPOUND":"",
(v->flags&CGLYPH_FL_SCALED_COMPONENT_OFFSET)?" CGLYPH_FL_SCALED_COMPONENT_OFFSET":"",
(v->flags&CGLYPH_FL_UNSCALED_COMPONENT_OFFSET)?" CGLYPH_FL_UNSCALED_COMPONENT_OFFSET":""
);
f->print(a, "%*s%s: %"PRIu16"\n", indent, "", "glyphIndex", v->glyphIndex);
if(v->arg1 != 0 || v->arg2 != 0){
f->print(f->aux, "%*s%s: %d\n", indent, "", "arg1", v->arg1);
f->print(f->aux, "%*s%s: %d\n", indent, "", "arg2", v->arg2);
}
if(v->flags & CGLYPH_FL_SCALE){
f->print(a, "%*s%s: %g\n", indent, "", "scale", v->scale);
}else if(v->flags & CGLYPH_FL_SCALE_XY){
f->print(a, "%*s%s: %g\n", indent, "", "scaleX", v->scaleX);
f->print(a, "%*s%s: %g\n", indent, "", "scaleY", v->scaleY);
}else if(v->flags & CGLYPH_FL_2X2_TRANSFORM){
f->print(a, "%*s%s: %g\n", indent, "", "scaleX", v->scaleX);
f->print(a, "%*s%s: %g\n", indent, "", "scale01", v->scale01);
f->print(a, "%*s%s: %g\n", indent, "", "scale10", v->scale10);
f->print(a, "%*s%s: %g\n", indent, "", "scaleY", v->scaleY);
}
if(v->numInstr > 0 && v->instr != nil){
f->print(a, "%*s%s: %"PRIu16"\n", indent, "", "numInstr", v->numInstr);
f->print(a, "%*s%s:", indent, "", "instr");
for(int i = 0; i < v->numInstr; i++)
f->print(a, " %02"PRIx8, v->instr[i]);
f->print(a, "\n");
}
if(v->next != nil){
f->print(a, "%*s%s:\n", indent, "", "next");
print_ComponentGlyph(f, indent+indentΔ, o, v->next);
}
}
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, nc;
flags = nil;
if((v = calloc(1, sizeof(*v))) == nil){
nomem:
werrstr("no memory");
goto err;
}
v->numEndPtsOfContours = o->numberOfContours;
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->numPoints = 1 + v->endPtsOfContours[o->numberOfContours-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;
if((flags[nflags++] = *b) & GLYPH_FL_REPEAT){
flags[nflags-1] ^= GLYPH_FL_REPEAT;
if((b = otfreadn(o, 1)) == nil)
goto err;
if(nflags + *b > v->numPoints){
werrstr("repeat overflow (%d+%d > %d)", nflags, *b, v->numPoints);
goto err;
}
memset(flags+nflags, flags[nflags-1], *b);
nflags += *b;
}
}
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;
nc = *b;
if((flags[i] & GLYPH_FL_X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) == 0)
nc = -nc;
c = v->points[n++].x = c + nc;
}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;
nc = *b;
if((flags[i] & GLYPH_FL_Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) == 0)
nc = -nc;
c = v->points[n++].y = c + nc;
}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;
}
void
print_SimpleGlyph(Otfile *f, int indent, Otf *o, SimpleGlyph *v)
{
void *a = f->aux;
USED(o);
if(v->numEndPtsOfContours > 0){
f->print(a, "%*s%s:", indent, "", "endPtsOfContours");
for(int i = 0; i < v->numEndPtsOfContours; i++)
f->print(a, " %"PRId16, v->endPtsOfContours[i]);
f->print(a, "\n");
}
if(v->instructionLength > 0){
f->print(a, "%*s%s: %ud\n", indent, "", "instructionLength", v->instructionLength);
f->print(a, "%*s%s:", indent, "", "instructions");
for(int i = 0; i < v->instructionLength; i++)
f->print(a, " %02"PRIx8, v->instructions[i]);
f->print(a, "\n");
}
if(v->numPoints > 0){
f->print(a, "%*s%s: %d\n", indent, "", "numPoints", v->numPoints);
f->print(a, "%*s%s:", indent, "", "points");
for(int i = 0; i < v->numPoints; i++)
f->print(a, " (%d,%d,%s)", v->points[i].x, v->points[i].y, v->points[i].onCurve?"on":"off");
f->print(a, "\n");
}
}
Glyf *
otfglyf(Otf *o, int index)
{
Glyf *g;
int off, len, i;
if((g = calloc(1, sizeof(*g))) == nil){
werrstr("no memory");
goto err;
}
if(o->td.loca == nil){
werrstr("no loca table");
goto err;
}
if(o->glyf.offset == 0){
for(i = 0; i < o->td.numTables; i++){
TableRecord *rec = o->td.tableRecords+i;
if(rec->tableTag == (u32int)('g'<<24|'l'<<16|'y'<<8|'f')){
o->glyf = *rec;
break;
}
}
if(o->glyf.offset == 0){
werrstr("no glyf table");
goto err;
}
}
if(index < 0 || index >= o->numGlyphs){
werrstr("index out of range");
goto err;
}
if(o->indexToLocFormat == 0){
off = (int)o->td.loca->shortOffsets[index]*2;
len = (int)o->td.loca->shortOffsets[index+1]*2 - off;
}else{
off = o->td.loca->longOffsets[index];
len = o->td.loca->longOffsets[index+1] - off;
}
if(len < 1) /* no outlines */
return g;
if(otfpushrange(o, o->glyf.offset, o->glyf.length) < 0)
goto err;
if(otfpushrange(o, off, len) < 0)
goto err;
if(read_Glyf(o, g) < 0){
free(g);
g = nil;
}
otfpoprange(o);
otfpoprange(o);
return g;
err:
free(g);
otfpopranges(o);
return nil;
}
int
otfglyfnum(Otf *o)
{
return o->numGlyphs;
}