|
|
import r from 'restructure';
|
|
|
|
|
|
let KernPair = new r.Struct({
|
|
|
left: r.uint16,
|
|
|
right: r.uint16,
|
|
|
value: r.int16
|
|
|
});
|
|
|
|
|
|
let ClassTable = new r.Struct({
|
|
|
firstGlyph: r.uint16,
|
|
|
nGlyphs: r.uint16,
|
|
|
offsets: new r.Array(r.uint16, 'nGlyphs'),
|
|
|
max: t => t.offsets.length && Math.max.apply(Math, t.offsets)
|
|
|
});
|
|
|
|
|
|
let Kern2Array = new r.Struct({
|
|
|
off: t => t._startOffset - t.parent.parent._startOffset,
|
|
|
len: t => (((t.parent.leftTable.max - t.off) / t.parent.rowWidth) + 1) * (t.parent.rowWidth / 2),
|
|
|
values: new r.LazyArray(r.int16, 'len')
|
|
|
});
|
|
|
|
|
|
let KernSubtable = new r.VersionedStruct('format', {
|
|
|
0: {
|
|
|
nPairs: r.uint16,
|
|
|
searchRange: r.uint16,
|
|
|
entrySelector: r.uint16,
|
|
|
rangeShift: r.uint16,
|
|
|
pairs: new r.Array(KernPair, 'nPairs')
|
|
|
},
|
|
|
|
|
|
2: {
|
|
|
rowWidth: r.uint16,
|
|
|
leftTable: new r.Pointer(r.uint16, ClassTable, {type: 'parent'}),
|
|
|
rightTable: new r.Pointer(r.uint16, ClassTable, {type: 'parent'}),
|
|
|
array: new r.Pointer(r.uint16, Kern2Array, {type: 'parent'})
|
|
|
},
|
|
|
|
|
|
3: {
|
|
|
glyphCount: r.uint16,
|
|
|
kernValueCount: r.uint8,
|
|
|
leftClassCount: r.uint8,
|
|
|
rightClassCount: r.uint8,
|
|
|
flags: r.uint8,
|
|
|
kernValue: new r.Array(r.int16, 'kernValueCount'),
|
|
|
leftClass: new r.Array(r.uint8, 'glyphCount'),
|
|
|
rightClass: new r.Array(r.uint8, 'glyphCount'),
|
|
|
kernIndex: new r.Array(r.uint8, t => t.leftClassCount * t.rightClassCount)
|
|
|
}
|
|
|
});
|
|
|
|
|
|
let KernTable = new r.VersionedStruct('version', {
|
|
|
0: { // Microsoft uses this format
|
|
|
subVersion: r.uint16, // Microsoft has an extra sub-table version number
|
|
|
length: r.uint16, // Length of the subtable, in bytes
|
|
|
format: r.uint8, // Format of subtable
|
|
|
coverage: new r.Bitfield(r.uint8, [
|
|
|
'horizontal', // 1 if table has horizontal data, 0 if vertical
|
|
|
'minimum', // If set to 1, the table has minimum values. If set to 0, the table has kerning values.
|
|
|
'crossStream', // If set to 1, kerning is perpendicular to the flow of the text
|
|
|
'override' // If set to 1 the value in this table replaces the accumulated value
|
|
|
]),
|
|
|
subtable: KernSubtable,
|
|
|
padding: new r.Reserved(r.uint8, t => t.length - t._currentOffset)
|
|
|
},
|
|
|
1: { // Apple uses this format
|
|
|
length: r.uint32,
|
|
|
coverage: new r.Bitfield(r.uint8, [
|
|
|
null, null, null, null, null,
|
|
|
'variation', // Set if table has variation kerning values
|
|
|
'crossStream', // Set if table has cross-stream kerning values
|
|
|
'vertical' // Set if table has vertical kerning values
|
|
|
]),
|
|
|
format: r.uint8,
|
|
|
tupleIndex: r.uint16,
|
|
|
subtable: KernSubtable,
|
|
|
padding: new r.Reserved(r.uint8, t => t.length - t._currentOffset)
|
|
|
}
|
|
|
});
|
|
|
|
|
|
export default new r.VersionedStruct(r.uint16, {
|
|
|
0: { // Microsoft Version
|
|
|
nTables: r.uint16,
|
|
|
tables: new r.Array(KernTable, 'nTables')
|
|
|
},
|
|
|
|
|
|
1: { // Apple Version
|
|
|
reserved: new r.Reserved(r.uint16), // the other half of the version number
|
|
|
nTables: r.uint32,
|
|
|
tables: new r.Array(KernTable, 'nTables')
|
|
|
}
|
|
|
});
|
|
|
|