Current File : /home/tradevaly/www/node_modules/fontkit/src/cff/CFFFont.js |
import r from 'restructure';
import CFFIndex from './CFFIndex';
import CFFTop from './CFFTop';
import CFFPrivateDict from './CFFPrivateDict';
import standardStrings from './CFFStandardStrings';
class CFFFont {
constructor(stream) {
this.stream = stream;
this.decode();
}
static decode(stream) {
return new CFFFont(stream);
}
decode() {
let start = this.stream.pos;
let top = CFFTop.decode(this.stream);
for (let key in top) {
let val = top[key];
this[key] = val;
}
if (this.version < 2) {
if (this.topDictIndex.length !== 1) {
throw new Error("Only a single font is allowed in CFF");
}
this.topDict = this.topDictIndex[0];
}
this.isCIDFont = this.topDict.ROS != null;
return this;
}
string(sid) {
if (this.version >= 2) {
return null;
}
if (sid < standardStrings.length) {
return standardStrings[sid];
}
return this.stringIndex[sid - standardStrings.length];
}
get postscriptName() {
if (this.version < 2) {
return this.nameIndex[0];
}
return null;
}
get fullName() {
return this.string(this.topDict.FullName);
}
get familyName() {
return this.string(this.topDict.FamilyName);
}
getCharString(glyph) {
this.stream.pos = this.topDict.CharStrings[glyph].offset;
return this.stream.readBuffer(this.topDict.CharStrings[glyph].length);
}
getGlyphName(gid) {
// CFF2 glyph names are in the post table.
if (this.version >= 2) {
return null;
}
// CID-keyed fonts don't have glyph names
if (this.isCIDFont) {
return null;
}
let { charset } = this.topDict;
if (Array.isArray(charset)) {
return charset[gid];
}
if (gid === 0) {
return '.notdef';
}
gid -= 1;
switch (charset.version) {
case 0:
return this.string(charset.glyphs[gid]);
case 1:
case 2:
for (let i = 0; i < charset.ranges.length; i++) {
let range = charset.ranges[i];
if (range.offset <= gid && gid <= range.offset + range.nLeft) {
return this.string(range.first + (gid - range.offset));
}
}
break;
}
return null;
}
fdForGlyph(gid) {
if (!this.topDict.FDSelect) {
return null;
}
switch (this.topDict.FDSelect.version) {
case 0:
return this.topDict.FDSelect.fds[gid];
case 3:
case 4:
let { ranges } = this.topDict.FDSelect;
let low = 0;
let high = ranges.length - 1;
while (low <= high) {
let mid = (low + high) >> 1;
if (gid < ranges[mid].first) {
high = mid - 1;
} else if (mid < high && gid >= ranges[mid + 1].first) {
low = mid + 1;
} else {
return ranges[mid].fd;
}
}
default:
throw new Error(`Unknown FDSelect version: ${this.topDict.FDSelect.version}`);
}
}
privateDictForGlyph(gid) {
if (this.topDict.FDSelect) {
let fd = this.fdForGlyph(gid);
if (this.topDict.FDArray[fd]) {
return this.topDict.FDArray[fd].Private;
}
return null;
}
if (this.version < 2) {
return this.topDict.Private;
}
return this.topDict.FDArray[0].Private;
}
}
export default CFFFont;