fonteditor-core
Version:
fonts (ttf, woff, woff2, eot, svg, otf) parse, write, transform, glyph adjust.
230 lines (217 loc) • 7.26 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _table = _interopRequireDefault(require("./table"));
var _string = _interopRequireDefault(require("../util/string"));
var _encoding = _interopRequireDefault(require("./cff/encoding"));
var _cffStandardStrings = _interopRequireDefault(require("./cff/cffStandardStrings"));
var _parseCFFDict = _interopRequireDefault(require("./cff/parseCFFDict"));
var _parseCFFGlyph = _interopRequireDefault(require("./cff/parseCFFGlyph"));
var _parseCFFCharset = _interopRequireDefault(require("./cff/parseCFFCharset"));
var _parseCFFEncoding = _interopRequireDefault(require("./cff/parseCFFEncoding"));
var _reader = _interopRequireDefault(require("../reader"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @file cff表
* @author mengke01(kekee000@gmail.com)
*
* reference:
* http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5176.CFF.pdf
*
* modify from:
* https://github.com/nodebox/opentype.js/blob/master/src/tables/cff.js
*/
/**
* 获取cff偏移
*
* @param {Reader} reader 读取器
* @param {number} offSize 偏移大小
* @param {number} offset 起始偏移
* @return {number} 偏移
*/
function getOffset(reader, offSize) {
var v = 0;
for (var i = 0; i < offSize; i++) {
v <<= 8;
v += reader.readUint8();
}
return v;
}
/**
* 解析cff表头部
*
* @param {Reader} reader 读取器
* @return {Object} 头部字段
*/
function parseCFFHead(reader) {
var head = {};
head.startOffset = reader.offset;
head.endOffset = head.startOffset + 4;
head.formatMajor = reader.readUint8();
head.formatMinor = reader.readUint8();
head.size = reader.readUint8();
head.offsetSize = reader.readUint8();
return head;
}
/**
* 解析`CFF`表索引
*
* @param {Reader} reader 读取器
* @param {number} offset 偏移
* @param {Funciton} conversionFn 转换函数
* @return {Object} 表对象
*/
function parseCFFIndex(reader, offset, conversionFn) {
if (offset) {
reader.seek(offset);
}
var start = reader.offset;
var offsets = [];
var objects = [];
var count = reader.readUint16();
var i;
var l;
if (count !== 0) {
var offsetSize = reader.readUint8();
for (i = 0, l = count + 1; i < l; i++) {
offsets.push(getOffset(reader, offsetSize));
}
for (i = 0, l = count; i < l; i++) {
var value = reader.readBytes(offsets[i + 1] - offsets[i]);
if (conversionFn) {
value = conversionFn(value);
}
objects.push(value);
}
}
return {
objects: objects,
startOffset: start,
endOffset: reader.offset
};
}
// Subroutines are encoded using the negative half of the number space.
// See type 2 chapter 4.7 "Subroutine operators".
function calcCFFSubroutineBias(subrs) {
var bias;
if (subrs.length < 1240) {
bias = 107;
} else if (subrs.length < 33900) {
bias = 1131;
} else {
bias = 32768;
}
return bias;
}
var _default = exports.default = _table.default.create('cff', [], {
read: function read(reader, font) {
var offset = this.offset;
reader.seek(offset);
var head = parseCFFHead(reader);
var nameIndex = parseCFFIndex(reader, head.endOffset, _string.default.getString);
var topDictIndex = parseCFFIndex(reader, nameIndex.endOffset);
var stringIndex = parseCFFIndex(reader, topDictIndex.endOffset, _string.default.getString);
var globalSubrIndex = parseCFFIndex(reader, stringIndex.endOffset);
var cff = {
head: head
};
// 全局子glyf数据
cff.gsubrs = globalSubrIndex.objects;
cff.gsubrsBias = calcCFFSubroutineBias(globalSubrIndex.objects);
// 顶级字典数据
var dictReader = new _reader.default(new Uint8Array(topDictIndex.objects[0]).buffer);
var topDict = _parseCFFDict.default.parseTopDict(dictReader, 0, dictReader.length, stringIndex.objects);
cff.topDict = topDict;
// 私有字典数据
var privateDictLength = topDict.private[0];
var privateDict = {};
var privateDictOffset;
if (privateDictLength) {
privateDictOffset = offset + topDict.private[1];
privateDict = _parseCFFDict.default.parsePrivateDict(reader, privateDictOffset, privateDictLength, stringIndex.objects);
cff.defaultWidthX = privateDict.defaultWidthX;
cff.nominalWidthX = privateDict.nominalWidthX;
} else {
cff.defaultWidthX = 0;
cff.nominalWidthX = 0;
}
// 私有子glyf数据
if (privateDict.subrs) {
var subrOffset = privateDictOffset + privateDict.subrs;
var subrIndex = parseCFFIndex(reader, subrOffset);
cff.subrs = subrIndex.objects;
cff.subrsBias = calcCFFSubroutineBias(cff.subrs);
} else {
cff.subrs = [];
cff.subrsBias = 0;
}
cff.privateDict = privateDict;
// 解析glyf数据和名字
var charStringsIndex = parseCFFIndex(reader, offset + topDict.charStrings);
var nGlyphs = charStringsIndex.objects.length;
if (topDict.charset < 3) {
// @author: fr33z00
// See end of chapter 13 (p22) of #5176.CFF.pdf :
// Still more optimization is possible by
// observing that many fonts adopt one of 3 common charsets. In
// these cases the operand to the charset operator in the Top DICT
// specifies a predefined charset id, in place of an offset, as shown in table 22
cff.charset = _cffStandardStrings.default;
} else {
cff.charset = (0, _parseCFFCharset.default)(reader, offset + topDict.charset, nGlyphs, stringIndex.objects);
}
// Standard encoding
if (topDict.encoding === 0) {
cff.encoding = _encoding.default.standardEncoding;
}
// Expert encoding
else if (topDict.encoding === 1) {
cff.encoding = _encoding.default.expertEncoding;
} else {
cff.encoding = (0, _parseCFFEncoding.default)(reader, offset + topDict.encoding);
}
cff.glyf = [];
// only parse subset glyphs
var subset = font.readOptions.subset;
if (subset && subset.length > 0) {
// subset map
var subsetMap = {
0: true // 设置.notdef
};
var codes = font.cmap;
// unicode to index
Object.keys(codes).forEach(function (c) {
if (subset.indexOf(+c) > -1) {
var i = codes[c];
subsetMap[i] = true;
}
});
font.subsetMap = subsetMap;
Object.keys(subsetMap).forEach(function (i) {
i = +i;
var glyf = (0, _parseCFFGlyph.default)(charStringsIndex.objects[i], cff, i);
glyf.name = cff.charset[i];
cff.glyf[i] = glyf;
});
}
// parse all
else {
for (var i = 0, l = nGlyphs; i < l; i++) {
var glyf = (0, _parseCFFGlyph.default)(charStringsIndex.objects[i], cff, i);
glyf.name = cff.charset[i];
cff.glyf.push(glyf);
}
}
return cff;
},
// eslint-disable-next-line no-unused-vars
write: function write(writer, font) {
throw new Error('not support write cff table');
},
// eslint-disable-next-line no-unused-vars
size: function size(font) {
throw new Error('not support get cff table size');
}
});