
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 { resolveLength } from '@foliojs-fork/restructure/src/utils';
import CFFDict from './CFFDict';
import CFFIndex from './CFFIndex';
import CFFPointer from './CFFPointer';
import CFFPrivateDict from './CFFPrivateDict';
import StandardStrings from './CFFStandardStrings';
import { StandardEncoding, ExpertEncoding } from './CFFEncodings';
import { ISOAdobeCharset, ExpertCharset, ExpertSubsetCharset } from './CFFCharsets';
import { ItemVariationStore } from '../tables/variations';
// Checks if an operand is an index of a predefined value,
// otherwise delegates to the provided type.
class PredefinedOp {
constructor(predefinedOps, type) {
this.predefinedOps = predefinedOps;
this.type = type;
}
decode(stream, parent, operands) {
if (this.predefinedOps[operands[0]]) {
return this.predefinedOps[operands[0]];
}
return this.type.decode(stream, parent, operands);
}
size(value, ctx) {
return this.type.size(value, ctx);
}
encode(stream, value, ctx) {
let index = this.predefinedOps.indexOf(value);
if (index !== -1) {
return index;
}
return this.type.encode(stream, value, ctx);
}
}
class CFFEncodingVersion extends r.Number {
constructor() {
super('UInt8');
}
decode(stream) {
return r.uint8.decode(stream) & 0x7f;
}
}
let Range1 = new r.Struct({
first: r.uint16,
nLeft: r.uint8
});
let Range2 = new r.Struct({
first: r.uint16,
nLeft: r.uint16
});
let CFFCustomEncoding = new r.VersionedStruct(new CFFEncodingVersion(), {
0: {
nCodes: r.uint8,
codes: new r.Array(r.uint8, 'nCodes')
},
1: {
nRanges: r.uint8,
ranges: new r.Array(Range1, 'nRanges')
}
// TODO: supplement?
});
let CFFEncoding = new PredefinedOp([ StandardEncoding, ExpertEncoding ], new CFFPointer(CFFCustomEncoding, { lazy: true }));
// Decodes an array of ranges until the total
// length is equal to the provided length.
class RangeArray extends r.Array {
decode(stream, parent) {
let length = resolveLength(this.length, stream, parent);
let count = 0;
let res = [];
while (count < length) {
let range = this.type.decode(stream, parent);
range.offset = count;
count += range.nLeft + 1;
res.push(range);
}
return res;
}
}
let CFFCustomCharset = new r.VersionedStruct(r.uint8, {
0: {
glyphs: new r.Array(r.uint16, t => t.parent.CharStrings.length - 1)
},
1: {
ranges: new RangeArray(Range1, t => t.parent.CharStrings.length - 1)
},
2: {
ranges: new RangeArray(Range2, t => t.parent.CharStrings.length - 1)
}
});
let CFFCharset = new PredefinedOp([ ISOAdobeCharset, ExpertCharset, ExpertSubsetCharset ], new CFFPointer(CFFCustomCharset, {lazy: true}));
let FDRange3 = new r.Struct({
first: r.uint16,
fd: r.uint8
});
let FDRange4 = new r.Struct({
first: r.uint32,
fd: r.uint16
});
let FDSelect = new r.VersionedStruct(r.uint8, {
0: {
fds: new r.Array(r.uint8, t => t.parent.CharStrings.length)
},
3: {
nRanges: r.uint16,
ranges: new r.Array(FDRange3, 'nRanges'),
sentinel: r.uint16
},
4: {
nRanges: r.uint32,
ranges: new r.Array(FDRange4, 'nRanges'),
sentinel: r.uint32
}
});
let ptr = new CFFPointer(CFFPrivateDict);
class CFFPrivateOp {
decode(stream, parent, operands) {
parent.length = operands[0];
return ptr.decode(stream, parent, [operands[1]]);
}
size(dict, ctx) {
return [CFFPrivateDict.size(dict, ctx, false), ptr.size(dict, ctx)[0]];
}
encode(stream, dict, ctx) {
return [CFFPrivateDict.size(dict, ctx, false), ptr.encode(stream, dict, ctx)[0]];
}
}
let FontDict = new CFFDict([
// key name type(s) default
[18, 'Private', new CFFPrivateOp, null],
[[12, 38], 'FontName', 'sid', null],
[[12, 7], 'FontMatrix', 'array', [0.001, 0, 0, 0.001, 0, 0]],
[[12, 5], 'PaintType', 'number', 0],
]);
let CFFTopDict = new CFFDict([
// key name type(s) default
[[12, 30], 'ROS', ['sid', 'sid', 'number'], null],
[0, 'version', 'sid', null],
[1, 'Notice', 'sid', null],
[[12, 0], 'Copyright', 'sid', null],
[2, 'FullName', 'sid', null],
[3, 'FamilyName', 'sid', null],
[4, 'Weight', 'sid', null],
[[12, 1], 'isFixedPitch', 'boolean', false],
[[12, 2], 'ItalicAngle', 'number', 0],
[[12, 3], 'UnderlinePosition', 'number', -100],
[[12, 4], 'UnderlineThickness', 'number', 50],
[[12, 5], 'PaintType', 'number', 0],
[[12, 6], 'CharstringType', 'number', 2],
[[12, 7], 'FontMatrix', 'array', [0.001, 0, 0, 0.001, 0, 0]],
[13, 'UniqueID', 'number', null],
[5, 'FontBBox', 'array', [0, 0, 0, 0]],
[[12, 8], 'StrokeWidth', 'number', 0],
[14, 'XUID', 'array', null],
[15, 'charset', CFFCharset, ISOAdobeCharset],
[16, 'Encoding', CFFEncoding, StandardEncoding],
[17, 'CharStrings', new CFFPointer(new CFFIndex), null],
[18, 'Private', new CFFPrivateOp, null],
[[12, 20], 'SyntheticBase', 'number', null],
[[12, 21], 'PostScript', 'sid', null],
[[12, 22], 'BaseFontName', 'sid', null],
[[12, 23], 'BaseFontBlend', 'delta', null],
// CID font specific
[[12, 31], 'CIDFontVersion', 'number', 0],
[[12, 32], 'CIDFontRevision', 'number', 0],
[[12, 33], 'CIDFontType', 'number', 0],
[[12, 34], 'CIDCount', 'number', 8720],
[[12, 35], 'UIDBase', 'number', null],
[[12, 37], 'FDSelect', new CFFPointer(FDSelect), null],
[[12, 36], 'FDArray', new CFFPointer(new CFFIndex(FontDict)), null],
[[12, 38], 'FontName', 'sid', null]
]);
let VariationStore = new r.Struct({
length: r.uint16,
itemVariationStore: ItemVariationStore
})
let CFF2TopDict = new CFFDict([
[[12, 7], 'FontMatrix', 'array', [0.001, 0, 0, 0.001, 0, 0]],
[17, 'CharStrings', new CFFPointer(new CFFIndex), null],
[[12, 37], 'FDSelect', new CFFPointer(FDSelect), null],
[[12, 36], 'FDArray', new CFFPointer(new CFFIndex(FontDict)), null],
[24, 'vstore', new CFFPointer(VariationStore), null],
[25, 'maxstack', 'number', 193]
]);
let CFFTop = new r.VersionedStruct(r.fixed16, {
1: {
hdrSize: r.uint8,
offSize: r.uint8,
nameIndex: new CFFIndex(new r.String('length')),
topDictIndex: new CFFIndex(CFFTopDict),
stringIndex: new CFFIndex(new r.String('length')),
globalSubrIndex: new CFFIndex
},
2: {
hdrSize: r.uint8,
length: r.uint16,
topDict: CFF2TopDict,
globalSubrIndex: new CFFIndex
}
});
export default CFFTop;