ref: dc095bf883919052348b9f8ba907bb3807e2283d
parent: 0e24bab6a96841fd3d8752ef0d8916f7659d355e
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Tue Jun 25 00:22:24 EDT 2024
add glyf reading logic (untested)
--- a/gen.rkt
+++ b/gen.rkt
@@ -566,6 +566,57 @@
typedef struct Otf Otf;
#pragma incomplete Otf
+typedef struct ComponentGlyph ComponentGlyph;
+
+enum {
+ CGLYPH_FL_WORD_ARGS = 1<<0,
+ CGLYPH_FL_SIGNED_XY = 1<<1,
+ CGLYPH_FL_ROUND_TO_GRID_XY = 1<<2,
+ CGLYPH_FL_SCALE = 1<<3,
+ CGLYPH_FL_MORE_COMPONENTS = 1<<5,
+ CGLYPH_FL_SCALE_XY = 1<<6,
+ CGLYPH_FL_2X2_TRANSFORM = 1<<7,
+ CGLYPH_FL_INSTRUCTIONS = 1<<8,
+ CGLYPH_FL_METRICS = 1<<9,
+ CGLYPH_FL_OVERLAP_COMPOUND = 1<<10,
+ CGLYPH_FL_SCALED_COMPONENT_OFFSET = 1<<11,
+ CGLYPH_FL_UNSCALED_COMPONENT_OFFSET = 1<<12,
+};
+
+struct ComponentGlyph {
+ u16int flags;
+ u16int glyphIndex;
+ union {
+ u8int u8;
+ s8int s8;
+ u16int u16;
+ s16int s16;
+ }arg1, arg2;
+ float scale, scaleX, scale01, scale10, scaleY;
+ u16int numInstr;
+ u8int *instr;
+ ComponentGlyph *next;
+};
+
+typedef struct Point Point;
+
+struct Point {
+ int x;
+ int y;
+ int onCurve;
+};
+
+typedef struct SimpleGlyph SimpleGlyph;
+
+struct SimpleGlyph {
+ u16int *endPtsOfContours;
+ u16int instructionLength;
+ u8int *instructions;
+
+ int numPoints;
+ Point *points;
+};
+
EOF
)
(printf (format gen-h))
--- a/otf.c
+++ b/otf.c
@@ -821,69 +821,9 @@
}
int
-read_SimpleGlyph(Otf *o, SimpleGlyph *v)
+read_Glyf(Otf *o, Glyf *v)
{
u8int *b;
- if((b = otfreadn(o, o->numberOfContours*2)) == nil)
- goto err;
- v->endPtsOfContours = malloc(o->numberOfContours*sizeof(*v->endPtsOfContours));
- for(int i = 0; i < o->numberOfContours; i++)
- v->endPtsOfContours[i] = b[0+i*2]<<8 | b[1+i*2];
- if((b = otfreadn(o, 2)) == nil)
- goto err;
- v->instructionLength = b[0]<<8 | b[1];
- if((b = otfreadn(o, v->instructionLength*1)) == nil)
- goto err;
- v->instructions = malloc(v->instructionLength*sizeof(*v->instructions));
- for(int i = 0; i < v->instructionLength; i++)
- v->instructions[i] = b[0+i*1];
- if((b = otfreadn(o, 1)) == nil)
- goto err;
- v->flags = b[0];
- return 0;
-err:
- werrstr("%s: %r", "SimpleGlyph");
- return -1;
-}
-
-void
-print_SimpleGlyph(Biobuf *f, int indent, Otf *o, SimpleGlyph *v)
-{
- for(int i = 0; i < o->numberOfContours; i++)
- Bprint(f, "%*s%s[%d]: %ud\n", indent, "", "endPtsOfContours", i, v->endPtsOfContours[i]);
- Bprint(f, "%*s%s: %ud\n", indent, "", "instructionLength", v->instructionLength);
- for(int i = 0; i < v->instructionLength; i++)
- Bprint(f, "%*s%s[%d]: %ud\n", indent, "", "instructions", i, v->instructions[i]);
- Bprint(f, "%*s%s: %#ux%s%s%s%s%s%s%s\n", indent, "", "flags", v->flags, (v->flags&GLYPH_FL_ON_CURVE_POINT)?" GLYPH_FL_ON_CURVE_POINT":"", (v->flags&GLYPH_FL_X_SHORT_VECTOR)?" GLYPH_FL_X_SHORT_VECTOR":"", (v->flags&GLYPH_FL_Y_SHORT_VECTOR)?" GLYPH_FL_Y_SHORT_VECTOR":"", (v->flags&GLYPH_FL_REPEAT)?" GLYPH_FL_REPEAT":"", (v->flags&GLYPH_FL_X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR)?" GLYPH_FL_X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR":"", (v->flags&GLYPH_FL_Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR)?" GLYPH_FL_Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR":"", (v->flags&GLYPH_FL_OVERLAP_SIMPLE)?" GLYPH_FL_OVERLAP_SIMPLE":"");
- USED(o);
-}
-
-int
-read_CompositeGlyph(Otf *o, CompositeGlyph *v)
-{
- u8int *b;
- if((b = otfreadn(o, 4)) == nil)
- goto err;
- v->flags = b[0]<<8 | b[1];
- v->glyphIndex = b[2]<<8 | b[3];
- return 0;
-err:
- werrstr("%s: %r", "CompositeGlyph");
- return -1;
-}
-
-void
-print_CompositeGlyph(Biobuf *f, int indent, Otf *o, CompositeGlyph *v)
-{
- Bprint(f, "%*s%s: %#ux%s%s%s%s%s%s%s%s%s%s%s%s\n", indent, "", "flags", v->flags, (v->flags&CGLYPH_FL_WORD_ARGS)?" CGLYPH_FL_WORD_ARGS":"", (v->flags&CGLYPH_FL_SIGNED_XY)?" CGLYPH_FL_SIGNED_XY":"", (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":"");
- Bprint(f, "%*s%s: %ud\n", indent, "", "glyphIndex", v->glyphIndex);
- USED(o);
-}
-
-int
-read_GlyfHeader(Otf *o, GlyfHeader *v)
-{
- u8int *b;
if((b = otfreadn(o, 10)) == nil)
goto err;
v->numberOfContours = b[0]<<8 | b[1];
@@ -892,26 +832,18 @@
v->yMin = b[4]<<8 | b[5];
v->xMax = b[6]<<8 | b[7];
v->yMax = b[8]<<8 | b[9];
- if(v->numberOfContours > 0){
- if(read_SimpleGlyph(o, &v->simpleGlyph) < 0){
- werrstr("%s: %r", "simpleGlyph");
- goto err;
- }
- }
- if(v->numberOfContours < 0){
- if(read_CompositeGlyph(o, &v->compositeGlyph) < 0){
- werrstr("%s: %r", "compositeGlyph");
- goto err;
- }
- }
+ if(v->numberOfContours < 0 && read_ComponentGlyph(o, &v->component, 0) < 0)
+ goto err;
+ if(v->numberOfContours > 0 && read_SimpleGlyph(o, &v->simple) < 0)
+ goto err;
return 0;
err:
- werrstr("%s: %r", "GlyfHeader");
+ werrstr("%s: %r", "Glyf");
return -1;
}
void
-print_GlyfHeader(Biobuf *f, int indent, Otf *o, GlyfHeader *v)
+print_Glyf(Biobuf *f, int indent, Otf *o, Glyf *v)
{
Bprint(f, "%*s%s: %d\n", indent, "", "numberOfContours", v->numberOfContours);
Bprint(f, "%*s%s: %d\n", indent, "", "xMin", v->xMin);
@@ -918,14 +850,6 @@
Bprint(f, "%*s%s: %d\n", indent, "", "yMin", v->yMin);
Bprint(f, "%*s%s: %d\n", indent, "", "xMax", v->xMax);
Bprint(f, "%*s%s: %d\n", indent, "", "yMax", v->yMax);
- if(v->numberOfContours > 0){
- Bprint(f, "%*s%s:\n", indent, "", "simpleGlyph");
- print_SimpleGlyph(f, indent+indentΔ, o, &v->simpleGlyph);
- }
- if(v->numberOfContours < 0){
- Bprint(f, "%*s%s:\n", indent, "", "compositeGlyph");
- print_CompositeGlyph(f, indent+indentΔ, o, &v->compositeGlyph);
- }
USED(o);
}
@@ -5072,7 +4996,7 @@
case (u32int)('l'<<24|'o'<<16|'c'<<8|'a'):
{
static int retried = 0;
- if(v->head == nil){
+ if(v->head == nil || v->maxp == nil){
if(retried){
werrstr("%s: deps missing", "TableLoca");
goto err;
--- a/otf.h
+++ b/otf.h
@@ -1,6 +1,57 @@
/* this file is generated. do not modify. */
typedef struct Otf Otf;
#pragma incomplete Otf
+
+typedef struct ComponentGlyph ComponentGlyph;
+
+enum {
+ CGLYPH_FL_WORD_ARGS = 1<<0,
+ CGLYPH_FL_SIGNED_XY = 1<<1,
+ CGLYPH_FL_ROUND_TO_GRID_XY = 1<<2,
+ CGLYPH_FL_SCALE = 1<<3,
+ CGLYPH_FL_MORE_COMPONENTS = 1<<5,
+ CGLYPH_FL_SCALE_XY = 1<<6,
+ CGLYPH_FL_2X2_TRANSFORM = 1<<7,
+ CGLYPH_FL_INSTRUCTIONS = 1<<8,
+ CGLYPH_FL_METRICS = 1<<9,
+ CGLYPH_FL_OVERLAP_COMPOUND = 1<<10,
+ CGLYPH_FL_SCALED_COMPONENT_OFFSET = 1<<11,
+ CGLYPH_FL_UNSCALED_COMPONENT_OFFSET = 1<<12,
+};
+
+struct ComponentGlyph {
+ u16int flags;
+ u16int glyphIndex;
+ union {
+ u8int u8;
+ s8int s8;
+ u16int u16;
+ s16int s16;
+ }arg1, arg2;
+ float scale, scaleX, scale01, scale10, scaleY;
+ u16int numInstr;
+ u8int *instr;
+ ComponentGlyph *next;
+};
+
+typedef struct Point Point;
+
+struct Point {
+ int x;
+ int y;
+ int onCurve;
+};
+
+typedef struct SimpleGlyph SimpleGlyph;
+
+struct SimpleGlyph {
+ u16int *endPtsOfContours;
+ u16int instructionLength;
+ u8int *instructions;
+
+ int numPoints;
+ Point *points;
+};
typedef struct SubHeader SubHeader;
typedef struct MapGroup MapGroup;
typedef struct SubtableCmap0 SubtableCmap0;
@@ -21,9 +72,7 @@
typedef struct TableCmap TableCmap;
typedef struct TableHead TableHead;
typedef struct TableHhea TableHhea;
-typedef struct SimpleGlyph SimpleGlyph;
-typedef struct CompositeGlyph CompositeGlyph;
-typedef struct GlyfHeader GlyfHeader;
+typedef struct Glyf Glyf;
typedef struct LongHorMetric LongHorMetric;
typedef struct TableMaxp TableMaxp;
typedef struct TableHmtx TableHmtx;
@@ -364,63 +413,18 @@
int read_TableHhea(Otf *o, TableHhea *v);
void print_TableHhea(Biobuf *f, int indent, Otf *o, TableHhea *v);
-enum { // SimpleGlyph
- // flags
- 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,
-};
-
-struct SimpleGlyph {
- u16int *endPtsOfContours;
- u16int instructionLength;
- u8int *instructions;
- u8int flags;
-};
-
-int read_SimpleGlyph(Otf *o, SimpleGlyph *v);
-void print_SimpleGlyph(Biobuf *f, int indent, Otf *o, SimpleGlyph *v);
-
-enum { // CompositeGlyph
- // flags
- CGLYPH_FL_WORD_ARGS = 1<<0,
- CGLYPH_FL_SIGNED_XY = 1<<1,
- CGLYPH_FL_ROUND_TO_GRID_XY = 1<<2,
- CGLYPH_FL_SCALE = 1<<3,
- CGLYPH_FL_MORE_COMPONENTS = 1<<5,
- CGLYPH_FL_SCALE_XY = 1<<6,
- CGLYPH_FL_2X2_TRANSFORM = 1<<7,
- CGLYPH_FL_INSTRUCTIONS = 1<<8,
- CGLYPH_FL_METRICS = 1<<9,
- CGLYPH_FL_OVERLAP_COMPOUND = 1<<10,
- CGLYPH_FL_SCALED_COMPONENT_OFFSET = 1<<11,
- CGLYPH_FL_UNSCALED_COMPONENT_OFFSET = 1<<12,
-};
-
-struct CompositeGlyph {
- u16int flags;
- u16int glyphIndex;
-};
-
-int read_CompositeGlyph(Otf *o, CompositeGlyph *v);
-void print_CompositeGlyph(Biobuf *f, int indent, Otf *o, CompositeGlyph *v);
-
-struct GlyfHeader {
+struct Glyf {
s16int numberOfContours;
s16int xMin;
s16int yMin;
s16int xMax;
s16int yMax;
- SimpleGlyph simpleGlyph;
- CompositeGlyph compositeGlyph;
+ ComponentGlyph *component;
+ SimpleGlyph *simple;
};
-int read_GlyfHeader(Otf *o, GlyfHeader *v);
-void print_GlyfHeader(Biobuf *f, int indent, Otf *o, GlyfHeader *v);
+int read_Glyf(Otf *o, Glyf *v);
+void print_Glyf(Biobuf *f, int indent, Otf *o, Glyf *v);
struct LongHorMetric {
u16int advanceWidth;
--- a/otf.rkt
+++ b/otf.rkt
@@ -201,53 +201,20 @@
{uint16 numberOfHMetrics ->o}
#:tag "hhea")
-(define simpleGlyphFlags
- #hash((0 . GLYPH_FL_ON_CURVE_POINT)
- (1 . GLYPH_FL_X_SHORT_VECTOR)
- (2 . GLYPH_FL_Y_SHORT_VECTOR)
- (3 . GLYPH_FL_REPEAT)
- (4 . GLYPH_FL_X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR)
- (5 . GLYPH_FL_Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR)
- (6 . GLYPH_FL_OVERLAP_SIMPLE)))
-
-(mkcmplx SimpleGlyph
- {uint16 endPtsOfContours [o->numberOfContours]}
- {uint16 instructionLength}
- {uint8 instructions [instructionLength]}
- {uint8 flags hex (bits simpleGlyphFlags)} ; FIXME this is a (packed) array
- #;{uint8/uint16 xCoordinates [?]}
- #;{uint8/uint16 yCoordinates [?]})
-
-(define compositeGlyphFlags
- #hash((0 . CGLYPH_FL_WORD_ARGS)
- (1 . CGLYPH_FL_SIGNED_XY)
- (2 . CGLYPH_FL_ROUND_TO_GRID_XY)
- (3 . CGLYPH_FL_SCALE)
- (5 . CGLYPH_FL_MORE_COMPONENTS)
- (6 . CGLYPH_FL_SCALE_XY)
- (7 . CGLYPH_FL_2X2_TRANSFORM)
- (8 . CGLYPH_FL_INSTRUCTIONS)
- (9 . CGLYPH_FL_METRICS)
- (10 . CGLYPH_FL_OVERLAP_COMPOUND)
- (11 . CGLYPH_FL_SCALED_COMPONENT_OFFSET)
- (12 . CGLYPH_FL_UNSCALED_COMPONENT_OFFSET)))
-
-(mkcmplx CompositeGlyph
- {uint16 flags hex (bits compositeGlyphFlags)}
- {uint16 glyphIndex}
- #;{uint8/int8/uint16/int16 argument1} ; FIXME are you fucking kidding me
- #;{uint8/int8/uint16/int16 argument2}
- ; FIXME there is more shit here
- )
-
-(mkcmplx GlyfHeader
- {int16 numberOfContours ->o}
- {int16 xMin}
- {int16 yMin}
- {int16 xMax}
- {int16 yMax}
- {SimpleGlyph simpleGlyph (> numberOfContours 0)}
- {CompositeGlyph compositeGlyph (< numberOfContours 0)})
+(mkcmplx
+ Glyf
+ {int16 numberOfContours ->o}
+ {int16 xMin}
+ {int16 yMin}
+ {int16 xMax}
+ {int16 yMax}
+ #:extra
+ (list (cons 'field (list (~a "ComponentGlyph *component;") (~a "SimpleGlyph *simple;")))
+ (cons 'read
+ (list (~a "if(v->numberOfContours < 0 && read_ComponentGlyph(o, &v->component, 0) < 0)")
+ (~a "\tgoto err;")
+ (~a "if(v->numberOfContours > 0 && read_SimpleGlyph(o, &v->simple) < 0)")
+ (~a "\tgoto err;")))))
(mkcmplx LongHorMetric {UFWORD advanceWidth} {FWORD lsb})
--- a/otfpriv.h
+++ b/otfpriv.h
@@ -221,6 +221,195 @@
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