shithub: fnt

Download patch

ref: d44ae07e343d91452f7cd0bc8f78024f2ab3883a
parent: 48e1da1dd908852cb62e931b46c92f8d3e987ab4
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Fri Jun 21 12:41:18 EDT 2024

fix custom parsing with offset; handle full blown expressions with references as conditionals

--- a/gen.rkt
+++ b/gen.rkt
@@ -37,6 +37,18 @@
   (define ps (list a b (map f types) ""))
   (string-join (flatten ps) "\n"))
 
+(define (fmt-expr e)
+  (define (fmt e)
+    (cond
+      [#f #f]
+      [(number? e) e]
+      [(list? e)
+       (match e
+         [(list op x y) (~a "(" (fmt x) op (fmt y) ")")])]
+      [(and (symbol? e) (extra-context-ref? e)) (~a e)]
+      [(symbol? e) (~a "v->" e)]))
+  (and e (fmt e)))
+
 (define-generics code
                  (gen-h code) ; generates code for the C header
                  (gen-c code b index) ; generates code for the C source file
@@ -59,14 +71,20 @@
 (define (block stmt lst)
   (if (= (length lst) 1) (list* stmt lst) (list (string-append stmt "{") lst "}")))
 
+(define/contract (fmt-ref ref)
+  (-> symbol? string?)
+  (~a (if (extra-context-ref? ref) "" "v->") ref))
+
 (define (wrap-cond-c cond lst)
-  (define (fmt-ref ref)
-    (if (extra-context-ref? ref) ref (~a "v->" ref)))
   (match cond
     [#f lst]
     [(list op ref n ...)
+     #:when ((listof number?) n)
      (block (~a "if(" (string-join (map (λ (n) (~a (fmt-ref ref) " " op " " n)) n) " || ") ")")
-            (indent lst))]))
+            (indent lst))]
+    [(list op ref e)
+     #:when (list? e)
+     (block (~a "if(" (fmt-expr cond) ")") (indent lst))]))
 
 (define (invert-c op)
   (match op
@@ -199,16 +217,7 @@
 
 (define/contract (field-count f)
   (-> field? (or/c false/c number? string?))
-  (define (fmt-expr e)
-    (cond
-      [(number? e) e]
-      [(list? e)
-       (match e
-         [(list op x y) (~a "(" (fmt-expr x) op (fmt-expr y) ")")])]
-      [(and (symbol? e) (extra-context-ref? e)) (~a e)]
-      [(symbol? e) (~a "v->" e)]))
-  (define e (field-attr f 'count))
-  (and e (fmt-expr e)))
+  (fmt-expr (field-attr f 'count)))
 
 (define (field-test f)
   (filter (λ (t) (eq? (car t) 'test)) (field-attrs f)))
@@ -442,17 +451,18 @@
     [(_ type _ (p:compop vs:number ...+))
      #:fail-when (not (type-comparable? (syntax-e #'type))) "type can't be used in a comparison"
      #''(test p vs ...)]
-    [(_ _ _ (p:compop oref:oref vs:number ...+))
-     #''(cond
-          p
-          oref
-          vs ...)]
     [(_ _ _ (p:compop ref:ref vs:number ...+))
      #''(cond
           p
           ref
           vs ...)]
+    [(_ _ _ (p:compop oref:oref e:expr))
+     #''(cond
+          p
+          oref
+          e)]
     [(_ _ _ {~literal unused}) #''(unused #t)]
+    [(_ _ _ (oref:oref)) #''(count oref)]
     [(_ _ _ (ref:ref))
      #:fail-when (not (type-index? (syntax-e #'ref.type))) "can't be used as index to an array"
      #''(count ref)]
--- a/otf.c
+++ b/otf.c
@@ -18,6 +18,9 @@
 	u16int numGlyphs;
 	u16int firstGlyphIndex;
 	u16int lastGlyphIndex;
+	u16int axisCount;
+	u16int instanceCount;
+	u16int instanceSize;
 };
 
 struct Range {
@@ -1008,7 +1011,7 @@
 read_TableHmtx(Otf *o, TableHmtx *v)
 {
 	u8int *b;
-	if(otfarray(o, &v->hMetrics, read_LongHorMetric, sizeof(LongHorMetric), (o->numberOfHMetrics+0)) < 0){
+	if(otfarray(o, &v->hMetrics, read_LongHorMetric, sizeof(LongHorMetric), o->numberOfHMetrics) < 0){
 		werrstr("%s: %r", "hMetrics");
 		goto err;
 	}
@@ -1026,7 +1029,7 @@
 void
 print_TableHmtx(Biobuf *f, int indent, Otf *o, TableHmtx *v)
 {
-	for(int i = 0; i < (o->numberOfHMetrics+0); i++){
+	for(int i = 0; i < o->numberOfHMetrics; i++){
 		Bprint(f, "%*s%s[%d]:\n", indent, "", "hMetrics", i);
 		print_LongHorMetric(f, indent+indentΔ, o, &v->hMetrics[i]);
 	}
@@ -3702,6 +3705,184 @@
 }
 
 int
+read_VariationAxisRecord(Otf *o, VariationAxisRecord *v)
+{
+	u8int *b;
+	if((b = otfreadn(o, 20)) == nil)
+		goto err;
+	v->axisTag = b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3];
+	v->minValue = (b[4]<<24 | b[5]<<16 | b[6]<<8 | b[7])/65536.0f;
+	v->defaultValue = (b[8]<<24 | b[9]<<16 | b[10]<<8 | b[11])/65536.0f;
+	v->maxValue = (b[12]<<24 | b[13]<<16 | b[14]<<8 | b[15])/65536.0f;
+	v->flags = b[16]<<8 | b[17];
+	v->axisNameID = b[18]<<8 | b[19];
+	return 0;
+err:
+	werrstr("%s: %r", "VariationAxisRecord");
+	return -1;
+}
+
+void
+print_VariationAxisRecord(Biobuf *f, int indent, Otf *o, VariationAxisRecord *v)
+{
+	Bprint(f, "%*s%s: %t\n", indent, "", "axisTag", v->axisTag);
+	Bprint(f, "%*s%s: %g\n", indent, "", "minValue", v->minValue);
+	Bprint(f, "%*s%s: %g\n", indent, "", "defaultValue", v->defaultValue);
+	Bprint(f, "%*s%s: %g\n", indent, "", "maxValue", v->maxValue);
+	Bprint(f, "%*s%s: %ud\n", indent, "", "flags", v->flags);
+	Bprint(f, "%*s%s: %ud\n", indent, "", "axisNameID", v->axisNameID);
+	USED(o);
+}
+
+int
+read_UserTuple(Otf *o, UserTuple *v)
+{
+	u8int *b;
+	if((b = otfreadn(o, o->axisCount*4)) == nil)
+		goto err;
+	v->coordinates = malloc(o->axisCount*sizeof(*v->coordinates));
+	for(int i = 0; i < o->axisCount; i++)
+		v->coordinates[i] = (b[0+i*4]<<24 | b[1+i*4]<<16 | b[2+i*4]<<8 | b[3+i*4])/65536.0f;
+	return 0;
+err:
+	werrstr("%s: %r", "UserTuple");
+	return -1;
+}
+
+void
+print_UserTuple(Biobuf *f, int indent, Otf *o, UserTuple *v)
+{
+	for(int i = 0; i < o->axisCount; i++)
+		Bprint(f, "%*s%s[%d]: %g\n", indent, "", "coordinates", i, v->coordinates[i]);
+	USED(o);
+}
+
+int
+read_InstanceRecord(Otf *o, InstanceRecord *v)
+{
+	u8int *b;
+	if((b = otfreadn(o, 4)) == nil)
+		goto err;
+	v->subfamilyNameID = b[0]<<8 | b[1];
+	v->flags = b[2]<<8 | b[3];
+	if(read_UserTuple(o, &v->coordinates) < 0){
+		werrstr("%s: %r", "coordinates");
+		goto err;
+	}
+	if((o->instanceSize==((o->axisCount*4)+6))){
+		if((b = otfreadn(o, 2)) == nil)
+			goto err;
+		v->postScriptNameID = b[0]<<8 | b[1];
+	}
+	return 0;
+err:
+	werrstr("%s: %r", "InstanceRecord");
+	return -1;
+}
+
+void
+print_InstanceRecord(Biobuf *f, int indent, Otf *o, InstanceRecord *v)
+{
+	Bprint(f, "%*s%s: %ud\n", indent, "", "subfamilyNameID", v->subfamilyNameID);
+	Bprint(f, "%*s%s: %ud\n", indent, "", "flags", v->flags);
+	Bprint(f, "%*s%s:\n", indent, "", "coordinates");
+	print_UserTuple(f, indent+indentΔ, o, &v->coordinates);
+	if((o->instanceSize==((o->axisCount*4)+6)))
+		Bprint(f, "%*s%s: %ud\n", indent, "", "postScriptNameID", v->postScriptNameID);
+	USED(o);
+}
+
+int
+read_AxisInstances(Otf *o, AxisInstances *v)
+{
+	u8int *b;
+	if(otfarray(o, &v->axes, read_VariationAxisRecord, sizeof(VariationAxisRecord), o->axisCount) < 0){
+		werrstr("%s: %r", "axes");
+		goto err;
+	}
+	if(otfarray(o, &v->instaces, read_InstanceRecord, sizeof(InstanceRecord), o->instanceCount) < 0){
+		werrstr("%s: %r", "instaces");
+		goto err;
+	}
+	return 0;
+err:
+	werrstr("%s: %r", "AxisInstances");
+	return -1;
+}
+
+void
+print_AxisInstances(Biobuf *f, int indent, Otf *o, AxisInstances *v)
+{
+	for(int i = 0; i < o->axisCount; i++){
+		Bprint(f, "%*s%s[%d]:\n", indent, "", "axes", i);
+		print_VariationAxisRecord(f, indent+indentΔ, o, &v->axes[i]);
+	}
+	for(int i = 0; i < o->instanceCount; i++){
+		Bprint(f, "%*s%s[%d]:\n", indent, "", "instaces", i);
+		print_InstanceRecord(f, indent+indentΔ, o, &v->instaces[i]);
+	}
+	USED(o);
+}
+
+int
+read_TableFvar(Otf *o, TableFvar *v)
+{
+	u8int *b;
+	if((b = otfreadn(o, 16)) == nil)
+		goto err;
+	u16int majorVersion = b[0]<<8 | b[1];
+	if(majorVersion != 1){
+		werrstr("%s: invalid value: %d (0x%ux)", "majorVersion", majorVersion, majorVersion);
+		goto err;
+	}
+	u16int minorVersion = b[2]<<8 | b[3];
+	if(minorVersion != 0){
+		werrstr("%s: invalid value: %d (0x%ux)", "minorVersion", minorVersion, minorVersion);
+		goto err;
+	}
+	v->axesArrayOffset = b[4]<<8 | b[5];
+	v->axisCount = b[8]<<8 | b[9];
+	o->axisCount = v->axisCount;
+	u16int axisSize = b[10]<<8 | b[11];
+	if(axisSize != 20){
+		werrstr("%s: invalid value: %d (0x%ux)", "axisSize", axisSize, axisSize);
+		goto err;
+	}
+	v->instanceCount = b[12]<<8 | b[13];
+	o->instanceCount = v->instanceCount;
+	v->instanceSize = b[14]<<8 | b[15];
+	o->instanceSize = v->instanceSize;
+	if(v->axesArrayOffset != 0){
+		if(otfpushrange(o, v->axesArrayOffset, -1) < 0)
+			goto err;
+		v->axisInstances = calloc(1, sizeof(*v->axisInstances));
+		if(read_AxisInstances(o, v->axisInstances) < 0){
+			werrstr("%s: %r", "axisInstances");
+			goto err;
+		}
+		if(otfpoprange(o) < 0)
+			goto err;
+	}
+	return 0;
+err:
+	werrstr("%s: %r", "TableFvar");
+	return -1;
+}
+
+void
+print_TableFvar(Biobuf *f, int indent, Otf *o, TableFvar *v)
+{
+	Bprint(f, "%*s%s: %ud\n", indent, "", "axesArrayOffset", v->axesArrayOffset);
+	Bprint(f, "%*s%s: %ud\n", indent, "", "axisCount", v->axisCount);
+	Bprint(f, "%*s%s: %ud\n", indent, "", "instanceCount", v->instanceCount);
+	Bprint(f, "%*s%s: %ud\n", indent, "", "instanceSize", v->instanceSize);
+	Bprint(f, "%*s%s:\n", indent, "", "axisInstances");
+	if(v->axisInstances != nil)
+		print_AxisInstances(f, indent+indentΔ, o, v->axisInstances);
+	USED(o);
+}
+
+int
 read_TableFFTM(Otf *o, TableFFTM *v)
 {
 	u8int *b;
@@ -4207,6 +4388,17 @@
 				}
 				rec->parsed = v->loca;
 				rec->print = (void*)print_TableLoca;
+				break;
+			case (u32int)('f'<<24|'v'<<16|'a'<<8|'r'):
+				if(v->fvar != nil)
+					break;
+				v->fvar = calloc(1, sizeof(TableFvar));
+				if(read_TableFvar(o, v->fvar) < 0){
+					free(v->fvar);
+					goto err;
+				}
+				rec->parsed = v->fvar;
+				rec->print = (void*)print_TableFvar;
 				break;
 			case (u32int)('F'<<24|'F'<<16|'T'<<8|'M'):
 				if(v->fftm != nil)
--- a/otf.h
+++ b/otf.h
@@ -87,6 +87,11 @@
 typedef struct KernSubtable KernSubtable;
 typedef struct TableKern TableKern;
 typedef struct TableLoca TableLoca;
+typedef struct VariationAxisRecord VariationAxisRecord;
+typedef struct UserTuple UserTuple;
+typedef struct InstanceRecord InstanceRecord;
+typedef struct AxisInstances AxisInstances;
+typedef struct TableFvar TableFvar;
 typedef struct TableFFTM TableFFTM;
 typedef struct SignatureBlock1 SignatureBlock1;
 typedef struct SignatureRecord SignatureRecord;
@@ -1045,6 +1050,58 @@
 int read_TableLoca(Otf *o, TableLoca *v);
 void print_TableLoca(Biobuf *f, int indent, Otf *o, TableLoca *v);
 
+struct VariationAxisRecord {
+	u32int axisTag;
+	float minValue;
+	float defaultValue;
+	float maxValue;
+	u16int flags;
+	u16int axisNameID;
+};
+
+int read_VariationAxisRecord(Otf *o, VariationAxisRecord *v);
+void print_VariationAxisRecord(Biobuf *f, int indent, Otf *o, VariationAxisRecord *v);
+
+struct UserTuple {
+	float *coordinates;
+};
+
+int read_UserTuple(Otf *o, UserTuple *v);
+void print_UserTuple(Biobuf *f, int indent, Otf *o, UserTuple *v);
+
+struct InstanceRecord {
+	u16int subfamilyNameID;
+	u16int flags;
+	UserTuple coordinates;
+	u16int postScriptNameID;
+};
+
+int read_InstanceRecord(Otf *o, InstanceRecord *v);
+void print_InstanceRecord(Biobuf *f, int indent, Otf *o, InstanceRecord *v);
+
+struct AxisInstances {
+	VariationAxisRecord *axes;
+	InstanceRecord *instaces;
+};
+
+int read_AxisInstances(Otf *o, AxisInstances *v);
+void print_AxisInstances(Biobuf *f, int indent, Otf *o, AxisInstances *v);
+
+struct TableFvar {
+	// u16int majorVersion;
+	// u16int minorVersion;
+	u16int axesArrayOffset;
+	// u16int reserved;
+	u16int axisCount;
+	// u16int axisSize;
+	u16int instanceCount;
+	u16int instanceSize;
+	AxisInstances *axisInstances;
+};
+
+int read_TableFvar(Otf *o, TableFvar *v);
+void print_TableFvar(Biobuf *f, int indent, Otf *o, TableFvar *v);
+
 struct TableFFTM {
 	u32int version;
 	s64int fontforge;
@@ -1164,6 +1221,7 @@
 	TableMATH *math;
 	TableKern *kern;
 	TableLoca *loca;
+	TableFvar *fvar;
 	TableFFTM *fftm;
 	TableDSIG *dsig;
 	TableOS∕2 *os∕2;
--- a/otf.rkt
+++ b/otf.rkt
@@ -26,19 +26,23 @@
         64
         s64int
         "%T"
-        (λ (b index) (~a "(" ((autoparse 64 's64int) b index) ") - 2082844800LL")))
+        (λ (b index [offset #f]) (~a "(" ((autoparse 64 's64int) b index offset) ") - 2082844800LL")))
 (mktype Tag 32 u32int "%t")
 (mktype Offset16 16 u16int "%ud")
 (mktype Offset24 24 u32int "%ud")
 (mktype Offset32 32 u32int "%ud")
 (mktype Version16Dot16 32 u32int "%V")
-(mktype Fixed 32 float "%g" (λ (b index) (~a "(" ((type-parse int32) b index) ")/65536.0f")))
+(mktype Fixed
+        32
+        float
+        "%g"
+        (λ (b index [offset #f]) (~a "(" ((type-parse int32) b index offset) ")/65536.0f")))
 (mktype F2DOT14
         16
         float
         "%g"
-        (λ (b index)
-          (define x (~a ((type-parse int16) b index)))
+        (λ (b index [offset #f])
+          (define x (~a ((type-parse int16) b index offset)))
           (~a "(" x ">>14)+(" x "&((1<<14)-1))/16384.0")))
 
 (mkcmplx SubHeader {uint16 firstCode} {uint16 entryCode} {int16 idDelta} {uint16 idRangeOffset})
@@ -190,7 +194,7 @@
          #:tag "maxp")
 
 (mkcmplx TableHmtx
-         {LongHorMetric hMetrics [+ o->numberOfHMetrics 0]}
+         {LongHorMetric hMetrics [o->numberOfHMetrics]}
          {FWORD leftSideBearings [- o->numGlyphs o->numberOfHMetrics]}
          #:tag "hmtx"
          #:after (list TableHhea TableMaxp))
@@ -603,6 +607,38 @@
          {Offset32 longOffsets [+ o->numGlyphs 1] (== o->indexToLocFormat 1)}
          #:tag "loca"
          #:after (list TableHead))
+
+(mkcmplx VariationAxisRecord
+         {Tag axisTag}
+         {Fixed minValue}
+         {Fixed defaultValue}
+         {Fixed maxValue}
+         {uint16 flags}
+         {uint16 axisNameID})
+
+(mkcmplx UserTuple {Fixed coordinates [o->axisCount]})
+
+(mkcmplx InstanceRecord
+         {uint16 subfamilyNameID}
+         {uint16 flags}
+         {UserTuple coordinates}
+         {uint16 postScriptNameID (== o->instanceSize (+ (* o->axisCount 4) 6))})
+
+(mkcmplx AxisInstances
+         {VariationAxisRecord axes [o->axisCount]}
+         {InstanceRecord instaces [o->instanceCount]})
+
+(mkcmplx TableFvar
+         {uint16 majorVersion (== 1) unused}
+         {uint16 minorVersion (== 0) unused}
+         {Offset16 axesArrayOffset}
+         {uint16 reserved unused}
+         {uint16 axisCount ->o}
+         {uint16 axisSize (== 20) unused}
+         {uint16 instanceCount ->o}
+         {uint16 instanceSize ->o}
+         {AxisInstances axisInstances (at axesArrayOffset)}
+         #:tag "fvar")
 
 (mkcmplx TableFFTM
          {uint32 version}