
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 Subset from './Subset';
import CFFTop from '../cff/CFFTop';
import CFFPrivateDict from '../cff/CFFPrivateDict';
import standardStrings from '../cff/CFFStandardStrings';
export default class CFFSubset extends Subset {
constructor(font) {
super(font);
this.cff = this.font['CFF '];
if (!this.cff) {
throw new Error('Not a CFF Font');
}
}
subsetCharstrings() {
this.charstrings = [];
let gsubrs = {};
for (let gid of this.glyphs) {
this.charstrings.push(this.cff.getCharString(gid));
let glyph = this.font.getGlyph(gid);
let path = glyph.path; // this causes the glyph to be parsed
for (let subr in glyph._usedGsubrs) {
gsubrs[subr] = true;
}
}
this.gsubrs = this.subsetSubrs(this.cff.globalSubrIndex, gsubrs);
}
subsetSubrs(subrs, used) {
let res = [];
for (let i = 0; i < subrs.length; i++) {
let subr = subrs[i];
if (used[i]) {
this.cff.stream.pos = subr.offset;
res.push(this.cff.stream.readBuffer(subr.length));
} else {
res.push(Buffer.from([11])); // return
}
}
return res;
}
subsetFontdict(topDict) {
topDict.FDArray = [];
topDict.FDSelect = {
version: 0,
fds: []
};
let used_fds = {};
let used_subrs = [];
let fd_select = {};
for (let gid of this.glyphs) {
let fd = this.cff.fdForGlyph(gid);
if (fd == null) {
continue;
}
if (!used_fds[fd]) {
topDict.FDArray.push(Object.assign({}, this.cff.topDict.FDArray[fd]));
used_subrs.push({});
fd_select[fd] = topDict.FDArray.length - 1;
}
used_fds[fd] = true;
topDict.FDSelect.fds.push(fd_select[fd]);
let glyph = this.font.getGlyph(gid);
let path = glyph.path; // this causes the glyph to be parsed
for (let subr in glyph._usedSubrs) {
used_subrs[fd_select[fd]][subr] = true;
}
}
for (let i = 0; i < topDict.FDArray.length; i++) {
let dict = topDict.FDArray[i];
delete dict.FontName;
if (dict.Private && dict.Private.Subrs) {
dict.Private = Object.assign({}, dict.Private);
dict.Private.Subrs = this.subsetSubrs(dict.Private.Subrs, used_subrs[i]);
}
}
return;
}
createCIDFontdict(topDict) {
let used_subrs = {};
for (let gid of this.glyphs) {
let glyph = this.font.getGlyph(gid);
let path = glyph.path; // this causes the glyph to be parsed
for (let subr in glyph._usedSubrs) {
used_subrs[subr] = true;
}
}
let privateDict = Object.assign({}, this.cff.topDict.Private);
if (this.cff.topDict.Private && this.cff.topDict.Private.Subrs) {
privateDict.Subrs = this.subsetSubrs(this.cff.topDict.Private.Subrs, used_subrs);
}
topDict.FDArray = [{ Private: privateDict }];
return topDict.FDSelect = {
version: 3,
nRanges: 1,
ranges: [{ first: 0, fd: 0 }],
sentinel: this.charstrings.length
};
}
addString(string) {
if (!string) {
return null;
}
if (!this.strings) {
this.strings = [];
}
this.strings.push(string);
return standardStrings.length + this.strings.length - 1;
}
encode(stream) {
this.subsetCharstrings();
let charset = {
version: this.charstrings.length > 255 ? 2 : 1,
ranges: [{ first: 1, nLeft: this.charstrings.length - 2 }]
};
let topDict = Object.assign({}, this.cff.topDict);
topDict.Private = null;
topDict.charset = charset;
topDict.Encoding = null;
topDict.CharStrings = this.charstrings;
for (let key of ['version', 'Notice', 'Copyright', 'FullName', 'FamilyName', 'Weight', 'PostScript', 'BaseFontName', 'FontName']) {
topDict[key] = this.addString(this.cff.string(topDict[key]));
}
topDict.ROS = [this.addString('Adobe'), this.addString('Identity'), 0];
topDict.CIDCount = this.charstrings.length;
if (this.cff.isCIDFont) {
this.subsetFontdict(topDict);
} else {
this.createCIDFontdict(topDict);
}
let top = {
version: 1,
hdrSize: this.cff.hdrSize,
offSize: 4,
header: this.cff.header,
nameIndex: [this.cff.postscriptName],
topDictIndex: [topDict],
stringIndex: this.strings,
globalSubrIndex: this.gsubrs
};
CFFTop.encode(stream, top);
}
}