
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
import r from '@foliojs-fork/restructure';
import {ScriptList, FeatureList, LookupList, Coverage, ClassDef, Device, Context, ChainingContext} from './opentype';
import {FeatureVariations} from './variations';
let ValueFormat = new r.Bitfield(r.uint16, [
'xPlacement', 'yPlacement',
'xAdvance', 'yAdvance',
'xPlaDevice', 'yPlaDevice',
'xAdvDevice', 'yAdvDevice'
]);
let types = {
xPlacement: r.int16,
yPlacement: r.int16,
xAdvance: r.int16,
yAdvance: r.int16,
xPlaDevice: new r.Pointer(r.uint16, Device, { type: 'global', relativeTo: ctx => ctx.rel }),
yPlaDevice: new r.Pointer(r.uint16, Device, { type: 'global', relativeTo: ctx => ctx.rel }),
xAdvDevice: new r.Pointer(r.uint16, Device, { type: 'global', relativeTo: ctx => ctx.rel }),
yAdvDevice: new r.Pointer(r.uint16, Device, { type: 'global', relativeTo: ctx => ctx.rel })
};
class ValueRecord {
constructor(key = 'valueFormat') {
this.key = key;
}
buildStruct(parent) {
let struct = parent;
while (!struct[this.key] && struct.parent) {
struct = struct.parent;
}
if (!struct[this.key]) return;
let fields = {};
fields.rel = () => struct._startOffset;
let format = struct[this.key];
for (let key in format) {
if (format[key]) {
fields[key] = types[key];
}
}
return new r.Struct(fields);
}
size(val, ctx) {
return this.buildStruct(ctx).size(val, ctx);
}
decode(stream, parent) {
let res = this.buildStruct(parent).decode(stream, parent);
delete res.rel;
return res;
}
}
let PairValueRecord = new r.Struct({
secondGlyph: r.uint16,
value1: new ValueRecord('valueFormat1'),
value2: new ValueRecord('valueFormat2')
});
let PairSet = new r.Array(PairValueRecord, r.uint16);
let Class2Record = new r.Struct({
value1: new ValueRecord('valueFormat1'),
value2: new ValueRecord('valueFormat2')
});
let Anchor = new r.VersionedStruct(r.uint16, {
1: { // Design units only
xCoordinate: r.int16,
yCoordinate: r.int16
},
2: { // Design units plus contour point
xCoordinate: r.int16,
yCoordinate: r.int16,
anchorPoint: r.uint16
},
3: { // Design units plus Device tables
xCoordinate: r.int16,
yCoordinate: r.int16,
xDeviceTable: new r.Pointer(r.uint16, Device),
yDeviceTable: new r.Pointer(r.uint16, Device)
}
});
let EntryExitRecord = new r.Struct({
entryAnchor: new r.Pointer(r.uint16, Anchor, {type: 'parent'}),
exitAnchor: new r.Pointer(r.uint16, Anchor, {type: 'parent'})
});
let MarkRecord = new r.Struct({
class: r.uint16,
markAnchor: new r.Pointer(r.uint16, Anchor, {type: 'parent'})
});
let MarkArray = new r.Array(MarkRecord, r.uint16);
let BaseRecord = new r.Array(new r.Pointer(r.uint16, Anchor), t => t.parent.classCount);
let BaseArray = new r.Array(BaseRecord, r.uint16);
let ComponentRecord = new r.Array(new r.Pointer(r.uint16, Anchor), t => t.parent.parent.classCount);
let LigatureAttach = new r.Array(ComponentRecord, r.uint16);
let LigatureArray = new r.Array(new r.Pointer(r.uint16, LigatureAttach), r.uint16);
let GPOSLookup = new r.VersionedStruct('lookupType', {
1: new r.VersionedStruct(r.uint16, { // Single Adjustment
1: { // Single positioning value
coverage: new r.Pointer(r.uint16, Coverage),
valueFormat: ValueFormat,
value: new ValueRecord()
},
2: {
coverage: new r.Pointer(r.uint16, Coverage),
valueFormat: ValueFormat,
valueCount: r.uint16,
values: new r.LazyArray(new ValueRecord(), 'valueCount')
}
}),
2: new r.VersionedStruct(r.uint16, { // Pair Adjustment Positioning
1: { // Adjustments for glyph pairs
coverage: new r.Pointer(r.uint16, Coverage),
valueFormat1: ValueFormat,
valueFormat2: ValueFormat,
pairSetCount: r.uint16,
pairSets: new r.LazyArray(new r.Pointer(r.uint16, PairSet), 'pairSetCount')
},
2: { // Class pair adjustment
coverage: new r.Pointer(r.uint16, Coverage),
valueFormat1: ValueFormat,
valueFormat2: ValueFormat,
classDef1: new r.Pointer(r.uint16, ClassDef),
classDef2: new r.Pointer(r.uint16, ClassDef),
class1Count: r.uint16,
class2Count: r.uint16,
classRecords: new r.LazyArray(new r.LazyArray(Class2Record, 'class2Count'), 'class1Count')
}
}),
3: { // Cursive Attachment Positioning
format: r.uint16,
coverage: new r.Pointer(r.uint16, Coverage),
entryExitCount: r.uint16,
entryExitRecords: new r.Array(EntryExitRecord, 'entryExitCount')
},
4: { // MarkToBase Attachment Positioning
format: r.uint16,
markCoverage: new r.Pointer(r.uint16, Coverage),
baseCoverage: new r.Pointer(r.uint16, Coverage),
classCount: r.uint16,
markArray: new r.Pointer(r.uint16, MarkArray),
baseArray: new r.Pointer(r.uint16, BaseArray)
},
5: { // MarkToLigature Attachment Positioning
format: r.uint16,
markCoverage: new r.Pointer(r.uint16, Coverage),
ligatureCoverage: new r.Pointer(r.uint16, Coverage),
classCount: r.uint16,
markArray: new r.Pointer(r.uint16, MarkArray),
ligatureArray: new r.Pointer(r.uint16, LigatureArray)
},
6: { // MarkToMark Attachment Positioning
format: r.uint16,
mark1Coverage: new r.Pointer(r.uint16, Coverage),
mark2Coverage: new r.Pointer(r.uint16, Coverage),
classCount: r.uint16,
mark1Array: new r.Pointer(r.uint16, MarkArray),
mark2Array: new r.Pointer(r.uint16, BaseArray)
},
7: Context, // Contextual positioning
8: ChainingContext, // Chaining contextual positioning
9: { // Extension Positioning
posFormat: r.uint16,
lookupType: r.uint16, // cannot also be 9
extension: new r.Pointer(r.uint32, GPOSLookup)
}
});
// Fix circular reference
GPOSLookup.versions[9].extension.type = GPOSLookup;
export default new r.VersionedStruct(r.uint32, {
header: {
scriptList: new r.Pointer(r.uint16, ScriptList),
featureList: new r.Pointer(r.uint16, FeatureList),
lookupList: new r.Pointer(r.uint16, new LookupList(GPOSLookup))
},
0x00010000: {},
0x00010001: {
featureVariations: new r.Pointer(r.uint32, FeatureVariations)
}
});
// export GPOSLookup for JSTF table
export { GPOSLookup };