Current File : /home/tradevaly/www/node_modules/fontkit/src/tables/aat.js |
import r from 'restructure';
class UnboundedArrayAccessor {
constructor(type, stream, parent) {
this.type = type;
this.stream = stream;
this.parent = parent;
this.base = this.stream.pos;
this._items = [];
}
getItem(index) {
if (this._items[index] == null) {
let pos = this.stream.pos;
this.stream.pos = this.base + this.type.size(null, this.parent) * index;
this._items[index] = this.type.decode(this.stream, this.parent);
this.stream.pos = pos;
}
return this._items[index];
}
inspect() {
return `[UnboundedArray ${this.type.constructor.name}]`;
}
}
export class UnboundedArray extends r.Array {
constructor(type) {
super(type, 0);
}
decode(stream, parent) {
return new UnboundedArrayAccessor(this.type, stream, parent);
}
}
export let LookupTable = function(ValueType = r.uint16) {
// Helper class that makes internal structures invisible to pointers
class Shadow {
constructor(type) {
this.type = type;
}
decode(stream, ctx) {
ctx = ctx.parent.parent;
return this.type.decode(stream, ctx);
}
size(val, ctx) {
ctx = ctx.parent.parent;
return this.type.size(val, ctx);
}
encode(stream, val, ctx) {
ctx = ctx.parent.parent;
return this.type.encode(stream, val, ctx);
}
}
ValueType = new Shadow(ValueType);
let BinarySearchHeader = new r.Struct({
unitSize: r.uint16,
nUnits: r.uint16,
searchRange: r.uint16,
entrySelector: r.uint16,
rangeShift: r.uint16
});
let LookupSegmentSingle = new r.Struct({
lastGlyph: r.uint16,
firstGlyph: r.uint16,
value: ValueType
});
let LookupSegmentArray = new r.Struct({
lastGlyph: r.uint16,
firstGlyph: r.uint16,
values: new r.Pointer(r.uint16, new r.Array(ValueType, t => t.lastGlyph - t.firstGlyph + 1), {type: 'parent'})
});
let LookupSingle = new r.Struct({
glyph: r.uint16,
value: ValueType
});
return new r.VersionedStruct(r.uint16, {
0: {
values: new UnboundedArray(ValueType) // length == number of glyphs maybe?
},
2: {
binarySearchHeader: BinarySearchHeader,
segments: new r.Array(LookupSegmentSingle, t => t.binarySearchHeader.nUnits)
},
4: {
binarySearchHeader: BinarySearchHeader,
segments: new r.Array(LookupSegmentArray, t => t.binarySearchHeader.nUnits)
},
6: {
binarySearchHeader: BinarySearchHeader,
segments: new r.Array(LookupSingle, t => t.binarySearchHeader.nUnits)
},
8: {
firstGlyph: r.uint16,
count: r.uint16,
values: new r.Array(ValueType, 'count')
}
});
};
export function StateTable(entryData = {}, lookupType = r.uint16) {
let entry = Object.assign({
newState: r.uint16,
flags: r.uint16
}, entryData);
let Entry = new r.Struct(entry);
let StateArray = new UnboundedArray(new r.Array(r.uint16, t => t.nClasses));
let StateHeader = new r.Struct({
nClasses: r.uint32,
classTable: new r.Pointer(r.uint32, new LookupTable(lookupType)),
stateArray: new r.Pointer(r.uint32, StateArray),
entryTable: new r.Pointer(r.uint32, new UnboundedArray(Entry))
});
return StateHeader;
}
// This is the old version of the StateTable structure
export function StateTable1(entryData = {}, lookupType = r.uint16) {
let ClassLookupTable = new r.Struct({
version() { return 8; }, // simulate LookupTable
firstGlyph: r.uint16,
values: new r.Array(r.uint8, r.uint16)
});
let entry = Object.assign({
newStateOffset: r.uint16,
// convert offset to stateArray index
newState: t => (t.newStateOffset - (t.parent.stateArray.base - t.parent._startOffset)) / t.parent.nClasses,
flags: r.uint16
}, entryData);
let Entry = new r.Struct(entry);
let StateArray = new UnboundedArray(new r.Array(r.uint8, t => t.nClasses));
let StateHeader1 = new r.Struct({
nClasses: r.uint16,
classTable: new r.Pointer(r.uint16, ClassLookupTable),
stateArray: new r.Pointer(r.uint16, StateArray),
entryTable: new r.Pointer(r.uint16, new UnboundedArray(Entry))
});
return StateHeader1;
}