mirror of
https://github.com/2234839/web-font.git
synced 2026-06-06 01:28:18 +08:00
性能优化1
This commit is contained in:
parent
765a301649
commit
d43255aba0
53
vendor/fonteditor-core/lib/ttf/reader.js
vendored
53
vendor/fonteditor-core/lib/ttf/reader.js
vendored
@ -72,23 +72,28 @@ var Reader = exports.default = /*#__PURE__*/function () {
|
||||
return _createClass(Reader, [{
|
||||
key: "read",
|
||||
value: function read(type, offset, littleEndian) {
|
||||
// 使用当前位移
|
||||
if (undefined === offset) {
|
||||
offset = this.offset;
|
||||
}
|
||||
|
||||
// 使用小尾
|
||||
if (undefined === littleEndian) {
|
||||
littleEndian = this.littleEndian;
|
||||
}
|
||||
|
||||
// 扩展方法
|
||||
if (undefined === dataType[type]) {
|
||||
return this['read' + type](offset, littleEndian);
|
||||
}
|
||||
var size = dataType[type];
|
||||
this.offset = offset + size;
|
||||
return this.view['get' + type](offset, littleEndian);
|
||||
/* 优化20: switch 直接分发,避免动态属性查找 */
|
||||
switch (type) {
|
||||
case 'Int8': return this.view.getInt8(offset, littleEndian);
|
||||
case 'Uint8': return this.view.getUint8(offset, littleEndian);
|
||||
case 'Int16': return this.view.getInt16(offset, littleEndian);
|
||||
case 'Uint16': return this.view.getUint16(offset, littleEndian);
|
||||
case 'Int32': return this.view.getInt32(offset, littleEndian);
|
||||
case 'Uint32': return this.view.getUint32(offset, littleEndian);
|
||||
case 'Float32': return this.view.getFloat32(offset, littleEndian);
|
||||
case 'Float64': return this.view.getFloat64(offset, littleEndian);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,12 +114,10 @@ var Reader = exports.default = /*#__PURE__*/function () {
|
||||
if (length < 0 || offset + length > this.length) {
|
||||
_error.default.raise(10001, this.length, offset + length);
|
||||
}
|
||||
var buffer = [];
|
||||
for (var i = 0; i < length; ++i) {
|
||||
buffer.push(this.view.getUint8(offset + i));
|
||||
}
|
||||
/* 优化68: Uint8Array.slice 批量读取,替代逐字节 push */
|
||||
var bytes = new Uint8Array(this.view.buffer, this.view.byteOffset + offset, length).slice();
|
||||
this.offset = offset + length;
|
||||
return buffer;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -135,13 +138,15 @@ var Reader = exports.default = /*#__PURE__*/function () {
|
||||
if (length < 0 || offset + length > this.length) {
|
||||
_error.default.raise(10001, this.length, offset + length);
|
||||
}
|
||||
var value = '';
|
||||
/* 优化22: 批量读取字节后构建字符串,替代逐字节 readUint8 */
|
||||
var chars = new Array(length);
|
||||
var viewOffset = this.view.byteOffset + offset;
|
||||
var buf = this.view.buffer;
|
||||
for (var i = 0; i < length; ++i) {
|
||||
var c = this.readUint8(offset + i);
|
||||
value += String.fromCharCode(c);
|
||||
chars[i] = buf.charCodeAt ? String.fromCharCode(buf.charCodeAt(viewOffset + i)) : String.fromCharCode(new Uint8Array(buf, viewOffset + i, 1)[0]);
|
||||
}
|
||||
this.offset = offset + length;
|
||||
return value;
|
||||
return chars.join('');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -238,12 +243,12 @@ var Reader = exports.default = /*#__PURE__*/function () {
|
||||
delete this.view;
|
||||
}
|
||||
}]);
|
||||
}(); // 直接支持的数据类型 — 直接绑定,避免 curry 闭包开销
|
||||
Object.keys(dataType).forEach(function (type) {
|
||||
var size = dataType[type];
|
||||
Reader.prototype['read' + type] = function (offset) {
|
||||
if (offset === undefined) offset = this.offset;
|
||||
this.offset = offset + size;
|
||||
return this.view['get' + type](offset, this.littleEndian);
|
||||
};
|
||||
});
|
||||
}(); // 优化19+20: 直接绑定方法 + switch 分发,避免 curry 闭包和动态属性查找
|
||||
Reader.prototype.readInt8 = function(offset) { if (offset === undefined) offset = this.offset; this.offset = offset + 1; return this.view.getInt8(offset, this.littleEndian); };
|
||||
Reader.prototype.readUint8 = function(offset) { if (offset === undefined) offset = this.offset; this.offset = offset + 1; return this.view.getUint8(offset, this.littleEndian); };
|
||||
Reader.prototype.readInt16 = function(offset) { if (offset === undefined) offset = this.offset; this.offset = offset + 2; return this.view.getInt16(offset, this.littleEndian); };
|
||||
Reader.prototype.readUint16 = function(offset) { if (offset === undefined) offset = this.offset; this.offset = offset + 2; return this.view.getUint16(offset, this.littleEndian); };
|
||||
Reader.prototype.readInt32 = function(offset) { if (offset === undefined) offset = this.offset; this.offset = offset + 4; return this.view.getInt32(offset, this.littleEndian); };
|
||||
Reader.prototype.readUint32 = function(offset) { if (offset === undefined) offset = this.offset; this.offset = offset + 4; return this.view.getUint32(offset, this.littleEndian); };
|
||||
Reader.prototype.readFloat32 = function(offset) { if (offset === undefined) offset = this.offset; this.offset = offset + 4; return this.view.getFloat32(offset, this.littleEndian); };
|
||||
Reader.prototype.readFloat64 = function(offset) { if (offset === undefined) offset = this.offset; this.offset = offset + 8; return this.view.getFloat64(offset, this.littleEndian); };
|
||||
237
vendor/fonteditor-core/lib/ttf/table/cmap/parse.js
vendored
237
vendor/fonteditor-core/lib/ttf/table/cmap/parse.js
vendored
@ -20,165 +20,159 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
||||
* @param {number} cmapOffset 子表的偏移
|
||||
*/
|
||||
function readSubTable(reader, ttf, subTable, cmapOffset) {
|
||||
var i;
|
||||
var l;
|
||||
var glyphIdArray;
|
||||
var startOffset = cmapOffset + subTable.offset;
|
||||
var glyphCount;
|
||||
subTable.format = reader.readUint16(startOffset);
|
||||
/* 优化59: 直接 view 批量读取,避免逐个 readUint8/readUint16/readUint32 */
|
||||
var view = reader.view;
|
||||
var vOffset = view.byteOffset + startOffset;
|
||||
subTable.format = view.getUint16(vOffset, false);
|
||||
vOffset += 2;
|
||||
|
||||
// 0~256 紧凑排列
|
||||
if (subTable.format === 0) {
|
||||
var format0 = subTable;
|
||||
// 跳过format字段
|
||||
format0.length = reader.readUint16();
|
||||
format0.language = reader.readUint16();
|
||||
glyphIdArray = [];
|
||||
for (i = 0, l = format0.length - 6; i < l; i++) {
|
||||
glyphIdArray.push(reader.readUint8());
|
||||
format0.length = view.getUint16(vOffset, false); vOffset += 2;
|
||||
format0.language = view.getUint16(vOffset, false); vOffset += 2;
|
||||
var glyphCount = format0.length - 6;
|
||||
var glyphIdArray = new Array(glyphCount);
|
||||
for (var i = 0; i < glyphCount; i++) {
|
||||
glyphIdArray[i] = view.getUint8(vOffset + i);
|
||||
}
|
||||
format0.glyphIdArray = glyphIdArray;
|
||||
} else if (subTable.format === 2) {
|
||||
var format2 = subTable;
|
||||
// 跳过format字段
|
||||
format2.length = reader.readUint16();
|
||||
format2.language = reader.readUint16();
|
||||
var subHeadKeys = [];
|
||||
var maxSubHeadKey = 0; // 最大索引
|
||||
var maxPos = -1; // 最大位置
|
||||
for (var _i = 0, _l = 256; _i < _l; _i++) {
|
||||
subHeadKeys[_i] = reader.readUint16() / 8;
|
||||
format2.length = view.getUint16(vOffset, false); vOffset += 2;
|
||||
format2.language = view.getUint16(vOffset, false); vOffset += 2;
|
||||
var subHeadKeys = new Array(256);
|
||||
var maxSubHeadKey = 0;
|
||||
var maxPos = -1;
|
||||
for (var _i = 0; _i < 256; _i++) {
|
||||
subHeadKeys[_i] = view.getUint16(vOffset, false) / 8;
|
||||
if (subHeadKeys[_i] > maxSubHeadKey) {
|
||||
maxSubHeadKey = subHeadKeys[_i];
|
||||
maxPos = _i;
|
||||
}
|
||||
vOffset += 2;
|
||||
}
|
||||
var subHeads = [];
|
||||
for (i = 0; i <= maxSubHeadKey; i++) {
|
||||
subHeads[i] = {
|
||||
firstCode: reader.readUint16(),
|
||||
entryCount: reader.readUint16(),
|
||||
idDelta: reader.readUint16(),
|
||||
idRangeOffset: (reader.readUint16() - (maxSubHeadKey - i) * 8 - 2) / 2
|
||||
var subHeads = new Array(maxSubHeadKey + 1);
|
||||
for (var j = 0; j <= maxSubHeadKey; j++) {
|
||||
subHeads[j] = {
|
||||
firstCode: view.getUint16(vOffset, false),
|
||||
entryCount: view.getUint16(vOffset + 2, false),
|
||||
idDelta: view.getUint16(vOffset + 4, false),
|
||||
idRangeOffset: (view.getUint16(vOffset + 6, false) - (maxSubHeadKey - j) * 8 - 2) / 2
|
||||
};
|
||||
vOffset += 8;
|
||||
}
|
||||
glyphCount = (startOffset + format2.length - reader.offset) / 2;
|
||||
var glyphs = [];
|
||||
for (i = 0; i < glyphCount; i++) {
|
||||
glyphs[i] = reader.readUint16();
|
||||
var glyphCount2 = (startOffset + format2.length - (vOffset - view.byteOffset)) / 2;
|
||||
var glyphs = new Array(glyphCount2);
|
||||
for (var k = 0; k < glyphCount2; k++) {
|
||||
glyphs[k] = view.getUint16(vOffset, false);
|
||||
vOffset += 2;
|
||||
}
|
||||
format2.subHeadKeys = subHeadKeys;
|
||||
format2.maxPos = maxPos;
|
||||
format2.subHeads = subHeads;
|
||||
format2.glyphs = glyphs;
|
||||
}
|
||||
// 双字节编码,非紧凑排列
|
||||
else if (subTable.format === 4) {
|
||||
var format4 = subTable;
|
||||
// 跳过format字段
|
||||
format4.length = reader.readUint16();
|
||||
format4.language = reader.readUint16();
|
||||
format4.segCountX2 = reader.readUint16();
|
||||
format4.searchRange = reader.readUint16();
|
||||
format4.entrySelector = reader.readUint16();
|
||||
format4.rangeShift = reader.readUint16();
|
||||
format4.length = view.getUint16(vOffset, false); vOffset += 2;
|
||||
format4.language = view.getUint16(vOffset, false); vOffset += 2;
|
||||
format4.segCountX2 = view.getUint16(vOffset, false); vOffset += 2;
|
||||
format4.searchRange = view.getUint16(vOffset, false); vOffset += 2;
|
||||
format4.entrySelector = view.getUint16(vOffset, false); vOffset += 2;
|
||||
format4.rangeShift = view.getUint16(vOffset, false); vOffset += 2;
|
||||
var segCount = format4.segCountX2 / 2;
|
||||
|
||||
// end code
|
||||
var endCode = [];
|
||||
for (i = 0; i < segCount; ++i) {
|
||||
endCode.push(reader.readUint16());
|
||||
var endCode = new Array(segCount);
|
||||
for (var e = 0; e < segCount; e++) {
|
||||
endCode[e] = view.getUint16(vOffset, false);
|
||||
vOffset += 2;
|
||||
}
|
||||
format4.endCode = endCode;
|
||||
format4.reservedPad = reader.readUint16();
|
||||
format4.reservedPad = view.getUint16(vOffset, false); vOffset += 2;
|
||||
|
||||
// start code
|
||||
var startCode = [];
|
||||
for (i = 0; i < segCount; ++i) {
|
||||
startCode.push(reader.readUint16());
|
||||
var startCode = new Array(segCount);
|
||||
for (var s = 0; s < segCount; s++) {
|
||||
startCode[s] = view.getUint16(vOffset, false);
|
||||
vOffset += 2;
|
||||
}
|
||||
format4.startCode = startCode;
|
||||
|
||||
// idDelta
|
||||
var idDelta = [];
|
||||
for (i = 0; i < segCount; ++i) {
|
||||
idDelta.push(reader.readUint16());
|
||||
var idDelta = new Array(segCount);
|
||||
for (var d = 0; d < segCount; d++) {
|
||||
idDelta[d] = view.getUint16(vOffset, false);
|
||||
vOffset += 2;
|
||||
}
|
||||
format4.idDelta = idDelta;
|
||||
format4.idRangeOffsetOffset = reader.offset;
|
||||
format4.idRangeOffsetOffset = vOffset - view.byteOffset;
|
||||
|
||||
// idRangeOffset
|
||||
var idRangeOffset = [];
|
||||
for (i = 0; i < segCount; ++i) {
|
||||
idRangeOffset.push(reader.readUint16());
|
||||
var idRangeOffset = new Array(segCount);
|
||||
for (var r = 0; r < segCount; r++) {
|
||||
idRangeOffset[r] = view.getUint16(vOffset, false);
|
||||
vOffset += 2;
|
||||
}
|
||||
format4.idRangeOffset = idRangeOffset;
|
||||
|
||||
// 总长度 - glyphIdArray起始偏移/2
|
||||
glyphCount = (format4.length - (reader.offset - startOffset)) / 2;
|
||||
var glyphCount4 = (format4.length - (vOffset - view.byteOffset - startOffset)) / 2;
|
||||
format4.glyphIdArrayOffset = vOffset - view.byteOffset;
|
||||
|
||||
// 记录array offset
|
||||
format4.glyphIdArrayOffset = reader.offset;
|
||||
|
||||
// glyphIdArray
|
||||
glyphIdArray = [];
|
||||
for (i = 0; i < glyphCount; ++i) {
|
||||
glyphIdArray.push(reader.readUint16());
|
||||
var glyphIdArray4 = new Array(glyphCount4);
|
||||
for (var g = 0; g < glyphCount4; g++) {
|
||||
glyphIdArray4[g] = view.getUint16(vOffset, false);
|
||||
vOffset += 2;
|
||||
}
|
||||
format4.glyphIdArray = glyphIdArray;
|
||||
format4.glyphIdArray = glyphIdArray4;
|
||||
} else if (subTable.format === 6) {
|
||||
var format6 = subTable;
|
||||
format6.length = reader.readUint16();
|
||||
format6.language = reader.readUint16();
|
||||
format6.firstCode = reader.readUint16();
|
||||
format6.entryCount = reader.readUint16();
|
||||
|
||||
// 记录array offset
|
||||
format6.glyphIdArrayOffset = reader.offset;
|
||||
var glyphIndexArray = [];
|
||||
format6.length = view.getUint16(vOffset, false); vOffset += 2;
|
||||
format6.language = view.getUint16(vOffset, false); vOffset += 2;
|
||||
format6.firstCode = view.getUint16(vOffset, false); vOffset += 2;
|
||||
format6.entryCount = view.getUint16(vOffset, false); vOffset += 2;
|
||||
format6.glyphIdArrayOffset = vOffset - view.byteOffset;
|
||||
var entryCount = format6.entryCount;
|
||||
// 读取字符分组
|
||||
for (i = 0; i < entryCount; ++i) {
|
||||
glyphIndexArray.push(reader.readUint16());
|
||||
var glyphIndexArray = new Array(entryCount);
|
||||
for (var f = 0; f < entryCount; f++) {
|
||||
glyphIndexArray[f] = view.getUint16(vOffset, false);
|
||||
vOffset += 2;
|
||||
}
|
||||
format6.glyphIdArray = glyphIndexArray;
|
||||
}
|
||||
// defines segments for sparse representation in 4-byte character space
|
||||
else if (subTable.format === 12) {
|
||||
var format12 = subTable;
|
||||
format12.reserved = reader.readUint16();
|
||||
format12.length = reader.readUint32();
|
||||
format12.language = reader.readUint32();
|
||||
format12.nGroups = reader.readUint32();
|
||||
var groups = [];
|
||||
format12.reserved = view.getUint16(vOffset, false); vOffset += 2;
|
||||
format12.length = view.getUint32(vOffset, false); vOffset += 4;
|
||||
format12.language = view.getUint32(vOffset, false); vOffset += 4;
|
||||
format12.nGroups = view.getUint32(vOffset, false); vOffset += 4;
|
||||
var nGroups = format12.nGroups;
|
||||
// 读取字符分组
|
||||
for (i = 0; i < nGroups; ++i) {
|
||||
var group = {};
|
||||
group.start = reader.readUint32();
|
||||
group.end = reader.readUint32();
|
||||
group.startId = reader.readUint32();
|
||||
groups.push(group);
|
||||
var groups = new Array(nGroups);
|
||||
for (var h = 0; h < nGroups; h++) {
|
||||
groups[h] = {
|
||||
start: view.getUint32(vOffset, false),
|
||||
end: view.getUint32(vOffset + 4, false),
|
||||
startId: view.getUint32(vOffset + 8, false)
|
||||
};
|
||||
vOffset += 12;
|
||||
}
|
||||
format12.groups = groups;
|
||||
}
|
||||
// format 14
|
||||
else if (subTable.format === 14) {
|
||||
var format14 = subTable;
|
||||
format14.length = reader.readUint32();
|
||||
var numVarSelectorRecords = reader.readUint32();
|
||||
format14.length = view.getUint32(vOffset, false); vOffset += 4;
|
||||
var numVarSelectorRecords = view.getUint32(vOffset, false); vOffset += 4;
|
||||
var _groups = [];
|
||||
var offset = reader.offset;
|
||||
for (var _i2 = 0; _i2 < numVarSelectorRecords; _i2++) {
|
||||
var varSelector = reader.readUint24(offset);
|
||||
var defaultUVSOffset = reader.readUint32(offset + 3);
|
||||
var nonDefaultUVSOffset = reader.readUint32(offset + 7);
|
||||
offset += 11;
|
||||
var absOffset = vOffset;
|
||||
for (var vs = 0; vs < numVarSelectorRecords; vs++) {
|
||||
var varSelector = (view.getUint8(absOffset) << 16) + (view.getUint8(absOffset + 1) << 8) + view.getUint8(absOffset + 2);
|
||||
var defaultUVSOffset = view.getUint32(absOffset + 3, false);
|
||||
var nonDefaultUVSOffset = view.getUint32(absOffset + 7, false);
|
||||
absOffset += 11;
|
||||
if (defaultUVSOffset) {
|
||||
var numUnicodeValueRanges = reader.readUint32(startOffset + defaultUVSOffset);
|
||||
for (var j = 0; j < numUnicodeValueRanges; j++) {
|
||||
var startUnicode = reader.readUint24();
|
||||
var additionalCount = reader.readUint8();
|
||||
var numUnicodeValueRanges = view.getUint32(view.byteOffset + startOffset + defaultUVSOffset, false);
|
||||
var duvsOffset = view.byteOffset + startOffset + defaultUVSOffset + 4;
|
||||
for (var dj = 0; dj < numUnicodeValueRanges; dj++) {
|
||||
var startUnicode = (view.getUint8(duvsOffset) << 16) + (view.getUint8(duvsOffset + 1) << 8) + view.getUint8(duvsOffset + 2);
|
||||
var additionalCount = view.getUint8(duvsOffset + 3);
|
||||
duvsOffset += 4;
|
||||
_groups.push({
|
||||
start: startUnicode,
|
||||
end: startUnicode + additionalCount,
|
||||
@ -187,10 +181,12 @@ function readSubTable(reader, ttf, subTable, cmapOffset) {
|
||||
}
|
||||
}
|
||||
if (nonDefaultUVSOffset) {
|
||||
var numUVSMappings = reader.readUint32(startOffset + nonDefaultUVSOffset);
|
||||
for (var _j = 0; _j < numUVSMappings; _j++) {
|
||||
var unicode = reader.readUint24();
|
||||
var glyphId = reader.readUint16();
|
||||
var numUVSMappings = view.getUint32(view.byteOffset + startOffset + nonDefaultUVSOffset, false);
|
||||
var nuvsOffset = view.byteOffset + startOffset + nonDefaultUVSOffset + 4;
|
||||
for (var nj = 0; nj < numUVSMappings; nj++) {
|
||||
var unicode = (view.getUint8(nuvsOffset) << 16) + (view.getUint8(nuvsOffset + 1) << 8) + view.getUint8(nuvsOffset + 2);
|
||||
var glyphId = view.getUint16(nuvsOffset + 3, false);
|
||||
nuvsOffset += 5;
|
||||
_groups.push({
|
||||
unicode: unicode,
|
||||
glyphId: glyphId,
|
||||
@ -204,27 +200,28 @@ function readSubTable(reader, ttf, subTable, cmapOffset) {
|
||||
console.warn('not support cmap format:' + subTable.format);
|
||||
}
|
||||
}
|
||||
|
||||
function parse(reader, ttf) {
|
||||
var tcmap = {};
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
var cmapOffset = this.offset;
|
||||
reader.seek(cmapOffset);
|
||||
tcmap.version = reader.readUint16(); // 编码方式
|
||||
var numberSubtables = tcmap.numberSubtables = reader.readUint16(); // 表个数
|
||||
tcmap.version = reader.readUint16();
|
||||
var numberSubtables = tcmap.numberSubtables = reader.readUint16();
|
||||
|
||||
var subTables = tcmap.tables = []; // 名字表
|
||||
var offset = reader.offset;
|
||||
|
||||
// 使用offset读取,以便于查找
|
||||
for (var i = 0, l = numberSubtables; i < l; i++) {
|
||||
var subTables = tcmap.tables = [];
|
||||
/* 优化59: 直接 view 读取子表目录 */
|
||||
var view = reader.view;
|
||||
var dirOffset = view.byteOffset + reader.offset;
|
||||
for (var i = 0; i < numberSubtables; i++) {
|
||||
var subTable = {};
|
||||
subTable.platformID = reader.readUint16(offset);
|
||||
subTable.encodingID = reader.readUint16(offset + 2);
|
||||
subTable.offset = reader.readUint32(offset + 4);
|
||||
subTable.platformID = view.getUint16(dirOffset, false);
|
||||
subTable.encodingID = view.getUint16(dirOffset + 2, false);
|
||||
subTable.offset = view.getUint32(dirOffset + 4, false);
|
||||
readSubTable(reader, ttf, subTable, cmapOffset);
|
||||
subTables.push(subTable);
|
||||
offset += 8;
|
||||
dirOffset += 8;
|
||||
}
|
||||
reader.offset = dirOffset - view.byteOffset;
|
||||
var cmap = (0, _readWindowsAllCodes.default)(subTables, ttf);
|
||||
return cmap;
|
||||
}
|
||||
@ -17,15 +17,23 @@ var _default = exports.default = _table.default.create('directory', [], {
|
||||
var tables = {};
|
||||
var numTables = ttf.numTables;
|
||||
var offset = this.offset;
|
||||
for (var i = offset, l = numTables * 16; i < l; i += 16) {
|
||||
var name = reader.readString(i, 4).trim();
|
||||
/* 优化26: 直接 view 批量读取 */
|
||||
var view = reader.view;
|
||||
var vOffset = view.byteOffset + offset;
|
||||
for (var i = 0; i < numTables; i++) {
|
||||
var name = String.fromCharCode(
|
||||
view.getUint8(vOffset), view.getUint8(vOffset + 1),
|
||||
view.getUint8(vOffset + 2), view.getUint8(vOffset + 3)
|
||||
).trim();
|
||||
tables[name] = {
|
||||
name: name,
|
||||
checkSum: reader.readUint32(i + 4),
|
||||
offset: reader.readUint32(i + 8),
|
||||
length: reader.readUint32(i + 12)
|
||||
checkSum: view.getUint32(vOffset + 4, false),
|
||||
offset: view.getUint32(vOffset + 8, false),
|
||||
length: view.getUint32(vOffset + 12, false)
|
||||
};
|
||||
vOffset += 16;
|
||||
}
|
||||
reader.offset = offset + numTables * 16;
|
||||
return tables;
|
||||
},
|
||||
write: function write(writer, ttf) {
|
||||
|
||||
252
vendor/fonteditor-core/lib/ttf/table/glyf/parse.js
vendored
252
vendor/fonteditor-core/lib/ttf/table/glyf/parse.js
vendored
@ -12,113 +12,101 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*/
|
||||
|
||||
var MAX_INSTRUCTION_LENGTH = 5000; // 设置instructions阈值防止读取错误
|
||||
var MAX_NUMBER_OF_COORDINATES = 20000; // 设置坐标最大个数阈值,防止glyf读取错误
|
||||
var MAX_INSTRUCTION_LENGTH = 5000;
|
||||
var MAX_NUMBER_OF_COORDINATES = 20000;
|
||||
|
||||
/**
|
||||
* 读取简单字形
|
||||
*
|
||||
* @param {Reader} reader Reader对象
|
||||
* @param {Object} glyf 空glyf
|
||||
* @return {Object} 解析后的glyf
|
||||
* 优化9+12+34+41+42: parseSimpleGlyf 消除中间数组,直接 view 批量读取
|
||||
*/
|
||||
function parseSimpleGlyf(reader, glyf) {
|
||||
var offset = reader.offset;
|
||||
|
||||
// 轮廓点个数
|
||||
var numberOfCoordinates = glyf.endPtsOfContours[glyf.endPtsOfContours.length - 1] + 1;
|
||||
|
||||
// 判断坐标是否超过最大个数
|
||||
if (numberOfCoordinates > MAX_NUMBER_OF_COORDINATES) {
|
||||
console.warn('error read glyf coordinates:' + offset);
|
||||
return glyf;
|
||||
}
|
||||
|
||||
// 获取flag标志
|
||||
var i;
|
||||
var length;
|
||||
var flags = [];
|
||||
var flag;
|
||||
i = 0;
|
||||
/* 优化34: 缓存 glyFlag 常量 */
|
||||
var REPEAT = _glyFlag.default.REPEAT;
|
||||
var XSHORT = _glyFlag.default.XSHORT;
|
||||
var XSAME = _glyFlag.default.XSAME;
|
||||
var YSHORT = _glyFlag.default.YSHORT;
|
||||
var YSAME = _glyFlag.default.YSAME;
|
||||
var ONCURVE = _glyFlag.default.ONCURVE;
|
||||
|
||||
/* 优化34+42: 直接 view 读取 flags */
|
||||
var view = reader.view;
|
||||
var vOffset = view.byteOffset + reader.offset;
|
||||
var flags = new Array(numberOfCoordinates);
|
||||
var i = 0;
|
||||
while (i < numberOfCoordinates) {
|
||||
flag = reader.readUint8();
|
||||
flags.push(flag);
|
||||
i++;
|
||||
|
||||
// 标志位3重复flag
|
||||
if (flag & _glyFlag.default.REPEAT && i < numberOfCoordinates) {
|
||||
// 重复个数
|
||||
var repeat = reader.readUint8();
|
||||
for (var j = 0; j < repeat; j++) {
|
||||
flags.push(flag);
|
||||
i++;
|
||||
var flag = view.getUint8(vOffset++);
|
||||
flags[i++] = flag;
|
||||
if (flag & REPEAT && i < numberOfCoordinates) {
|
||||
var repeat = view.getUint8(vOffset++);
|
||||
for (var j = 0; j < repeat && i < numberOfCoordinates; j++) {
|
||||
flags[i++] = flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 坐标集合
|
||||
var coordinates = [];
|
||||
var xCoordinates = [];
|
||||
/* 优化9+34: 直接构建扁平坐标数组,消除中间对象创建 */
|
||||
var xArr = new Array(numberOfCoordinates);
|
||||
var prevX = 0;
|
||||
var x;
|
||||
for (i = 0, length = flags.length; i < length; ++i) {
|
||||
for (var xi = 0; xi < numberOfCoordinates; xi++) {
|
||||
var x = 0;
|
||||
var xflag = flags[xi];
|
||||
if (xflag & XSHORT) {
|
||||
x = view.getUint8(vOffset++);
|
||||
x = (xflag & XSAME) ? x : -x;
|
||||
} else if (xflag & XSAME) {
|
||||
x = 0;
|
||||
flag = flags[i];
|
||||
|
||||
// 标志位1
|
||||
// If set, the corresponding y-coordinate is 1 byte long, not 2
|
||||
if (flag & _glyFlag.default.XSHORT) {
|
||||
x = reader.readUint8();
|
||||
|
||||
// 标志位5
|
||||
x = flag & _glyFlag.default.XSAME ? x : -1 * x;
|
||||
}
|
||||
// 与上一值一致
|
||||
else if (flag & _glyFlag.default.XSAME) {
|
||||
x = 0;
|
||||
}
|
||||
// 新值
|
||||
else {
|
||||
x = reader.readInt16();
|
||||
} else {
|
||||
x = view.getInt16(vOffset);
|
||||
vOffset += 2;
|
||||
}
|
||||
prevX += x;
|
||||
xCoordinates[i] = prevX;
|
||||
coordinates[i] = {
|
||||
x: prevX,
|
||||
y: 0
|
||||
};
|
||||
if (flag & _glyFlag.default.ONCURVE) {
|
||||
coordinates[i].onCurve = true;
|
||||
}
|
||||
}
|
||||
var yCoordinates = [];
|
||||
var prevY = 0;
|
||||
var y;
|
||||
for (i = 0, length = flags.length; i < length; i++) {
|
||||
y = 0;
|
||||
flag = flags[i];
|
||||
if (flag & _glyFlag.default.YSHORT) {
|
||||
y = reader.readUint8();
|
||||
y = flag & _glyFlag.default.YSAME ? y : -1 * y;
|
||||
} else if (flag & _glyFlag.default.YSAME) {
|
||||
y = 0;
|
||||
} else {
|
||||
y = reader.readInt16();
|
||||
}
|
||||
prevY += y;
|
||||
yCoordinates[i] = prevY;
|
||||
if (coordinates[i]) {
|
||||
coordinates[i].y = prevY;
|
||||
}
|
||||
xArr[xi] = prevX;
|
||||
}
|
||||
|
||||
// 计算轮廓集合
|
||||
if (coordinates.length) {
|
||||
var yArr = new Array(numberOfCoordinates);
|
||||
var prevY = 0;
|
||||
for (var yi = 0; yi < numberOfCoordinates; yi++) {
|
||||
var y = 0;
|
||||
var yflag = flags[yi];
|
||||
if (yflag & YSHORT) {
|
||||
y = view.getUint8(vOffset++);
|
||||
y = (yflag & YSAME) ? y : -y;
|
||||
} else if (yflag & YSAME) {
|
||||
y = 0;
|
||||
} else {
|
||||
y = view.getInt16(vOffset);
|
||||
vOffset += 2;
|
||||
}
|
||||
prevY += y;
|
||||
yArr[yi] = prevY;
|
||||
}
|
||||
|
||||
reader.offset = vOffset - view.byteOffset;
|
||||
|
||||
/* 优化9: 一次遍历构建 contours,消除中间数组 */
|
||||
if (numberOfCoordinates > 0) {
|
||||
var endPtsOfContours = glyf.endPtsOfContours;
|
||||
var contours = [];
|
||||
contours.push(coordinates.slice(0, endPtsOfContours[0] + 1));
|
||||
for (i = 1, length = endPtsOfContours.length; i < length; i++) {
|
||||
contours.push(coordinates.slice(endPtsOfContours[i - 1] + 1, endPtsOfContours[i] + 1));
|
||||
var contours = new Array(endPtsOfContours.length);
|
||||
var start = 0;
|
||||
for (var ci = 0, cl = endPtsOfContours.length; ci < cl; ci++) {
|
||||
var end = endPtsOfContours[ci] + 1;
|
||||
var contour = new Array(end - start);
|
||||
for (var pi = start; pi < end; pi++) {
|
||||
contour[pi - start] = {
|
||||
x: xArr[pi],
|
||||
y: yArr[pi],
|
||||
onCurve: !!(flags[pi] & ONCURVE)
|
||||
};
|
||||
}
|
||||
contours[ci] = contour;
|
||||
start = end;
|
||||
}
|
||||
glyf.contours = contours;
|
||||
}
|
||||
@ -127,18 +115,23 @@ function parseSimpleGlyf(reader, glyf) {
|
||||
|
||||
/**
|
||||
* 读取复合字形
|
||||
*
|
||||
* @param {Reader} reader Reader对象
|
||||
* @param {Object} glyf glyf对象
|
||||
* @return {Object} glyf对象
|
||||
*/
|
||||
function parseCompoundGlyf(reader, glyf) {
|
||||
glyf.compound = true;
|
||||
glyf.glyfs = [];
|
||||
var flags;
|
||||
var g;
|
||||
var ARG_1_AND_2_ARE_WORDS = _componentFlag.default.ARG_1_AND_2_ARE_WORDS;
|
||||
var ROUND_XY_TO_GRID = _componentFlag.default.ROUND_XY_TO_GRID;
|
||||
var WE_HAVE_A_SCALE = _componentFlag.default.WE_HAVE_A_SCALE;
|
||||
var WE_HAVE_AN_X_AND_Y_SCALE = _componentFlag.default.WE_HAVE_AN_X_AND_Y_SCALE;
|
||||
var WE_HAVE_A_TWO_BY_TWO = _componentFlag.default.WE_HAVE_A_TWO_BY_TWO;
|
||||
var ARGS_ARE_XY_VALUES = _componentFlag.default.ARGS_ARE_XY_VALUES;
|
||||
var USE_MY_METRICS = _componentFlag.default.USE_MY_METRICS;
|
||||
var OVERLAP_COMPOUND = _componentFlag.default.OVERLAP_COMPOUND;
|
||||
var MORE_COMPONENTS = _componentFlag.default.MORE_COMPONENTS;
|
||||
var WE_HAVE_INSTRUCTIONS = _componentFlag.default.WE_HAVE_INSTRUCTIONS;
|
||||
|
||||
// 读取复杂字形
|
||||
do {
|
||||
flags = reader.readUint16();
|
||||
g = {};
|
||||
@ -150,32 +143,32 @@ function parseCompoundGlyf(reader, glyf) {
|
||||
var scaleY = 16384;
|
||||
var scale01 = 0;
|
||||
var scale10 = 0;
|
||||
if (_componentFlag.default.ARG_1_AND_2_ARE_WORDS & flags) {
|
||||
if (ARG_1_AND_2_ARE_WORDS & flags) {
|
||||
arg1 = reader.readInt16();
|
||||
arg2 = reader.readInt16();
|
||||
} else {
|
||||
arg1 = reader.readInt8();
|
||||
arg2 = reader.readInt8();
|
||||
}
|
||||
if (_componentFlag.default.ROUND_XY_TO_GRID & flags) {
|
||||
if (ROUND_XY_TO_GRID & flags) {
|
||||
arg1 = Math.round(arg1);
|
||||
arg2 = Math.round(arg2);
|
||||
}
|
||||
if (_componentFlag.default.WE_HAVE_A_SCALE & flags) {
|
||||
if (WE_HAVE_A_SCALE & flags) {
|
||||
scaleX = reader.readInt16();
|
||||
scaleY = scaleX;
|
||||
} else if (_componentFlag.default.WE_HAVE_AN_X_AND_Y_SCALE & flags) {
|
||||
} else if (WE_HAVE_AN_X_AND_Y_SCALE & flags) {
|
||||
scaleX = reader.readInt16();
|
||||
scaleY = reader.readInt16();
|
||||
} else if (_componentFlag.default.WE_HAVE_A_TWO_BY_TWO & flags) {
|
||||
} else if (WE_HAVE_A_TWO_BY_TWO & flags) {
|
||||
scaleX = reader.readInt16();
|
||||
scale01 = reader.readInt16();
|
||||
scale10 = reader.readInt16();
|
||||
scaleY = reader.readInt16();
|
||||
}
|
||||
if (_componentFlag.default.ARGS_ARE_XY_VALUES & flags) {
|
||||
g.useMyMetrics = !!flags & _componentFlag.default.USE_MY_METRICS;
|
||||
g.overlapCompound = !!flags & _componentFlag.default.OVERLAP_COMPOUND;
|
||||
if (ARGS_ARE_XY_VALUES & flags) {
|
||||
g.useMyMetrics = !!(flags & USE_MY_METRICS);
|
||||
g.overlapCompound = !!(flags & OVERLAP_COMPOUND);
|
||||
g.transform = {
|
||||
a: Math.round(10000 * scaleX / 16384) / 10000,
|
||||
b: Math.round(10000 * scale01 / 16384) / 10000,
|
||||
@ -196,13 +189,13 @@ function parseCompoundGlyf(reader, glyf) {
|
||||
};
|
||||
}
|
||||
glyf.glyfs.push(g);
|
||||
} while (_componentFlag.default.MORE_COMPONENTS & flags);
|
||||
if (_componentFlag.default.WE_HAVE_INSTRUCTIONS & flags) {
|
||||
} while (MORE_COMPONENTS & flags);
|
||||
if (WE_HAVE_INSTRUCTIONS & flags) {
|
||||
var length = reader.readUint16();
|
||||
if (length < MAX_INSTRUCTION_LENGTH) {
|
||||
var instructions = [];
|
||||
var instructions = new Array(length);
|
||||
for (var i = 0; i < length; ++i) {
|
||||
instructions.push(reader.readUint8());
|
||||
instructions[i] = reader.readUint8();
|
||||
}
|
||||
glyf.instructions = instructions;
|
||||
} else {
|
||||
@ -213,36 +206,33 @@ function parseCompoundGlyf(reader, glyf) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析glyf轮廓
|
||||
*
|
||||
* @param {Reader} reader 读取器
|
||||
* @param {Object} ttf ttf对象
|
||||
* @param {number=} offset 偏移
|
||||
* @return {Object} glyf对象
|
||||
* 优化41: header 和 endPtsOfContours 直接 view 批量读取
|
||||
* 优化12: 非 hinting 模式跳过 instructions
|
||||
*/
|
||||
function parseGlyf(reader, ttf, offset) {
|
||||
if (null != offset) {
|
||||
reader.seek(offset);
|
||||
}
|
||||
var glyf = {};
|
||||
var i;
|
||||
var length;
|
||||
var instructions;
|
||||
var hinting = ttf.readOptions ? ttf.readOptions.hinting : false;
|
||||
|
||||
// 边界值
|
||||
var numberOfContours = reader.readInt16();
|
||||
glyf.xMin = reader.readInt16();
|
||||
glyf.yMin = reader.readInt16();
|
||||
glyf.xMax = reader.readInt16();
|
||||
glyf.yMax = reader.readInt16();
|
||||
/* 优化41: 直接 view 读取 header 的 10 字节 */
|
||||
var view = reader.view;
|
||||
var vOffset = view.byteOffset + reader.offset;
|
||||
var numberOfContours = view.getInt16(vOffset, false);
|
||||
glyf.xMin = view.getInt16(vOffset + 2, false);
|
||||
glyf.yMin = view.getInt16(vOffset + 4, false);
|
||||
glyf.xMax = view.getInt16(vOffset + 6, false);
|
||||
glyf.yMax = view.getInt16(vOffset + 8, false);
|
||||
vOffset += 10;
|
||||
|
||||
// 读取简单字形
|
||||
if (numberOfContours >= 0) {
|
||||
// endPtsOfConturs
|
||||
glyf.endPtsOfContours = [];
|
||||
/* 优化41: endPtsOfContours 预分配 + 直接 view 读取 */
|
||||
if (numberOfContours > 0) {
|
||||
for (i = 0; i < numberOfContours; i++) {
|
||||
glyf.endPtsOfContours.push(reader.readUint16());
|
||||
glyf.endPtsOfContours = new Array(numberOfContours);
|
||||
for (var i = 0; i < numberOfContours; i++) {
|
||||
glyf.endPtsOfContours[i] = view.getUint16(vOffset, false);
|
||||
vOffset += 2;
|
||||
}
|
||||
} else {
|
||||
delete glyf.xMin;
|
||||
@ -251,23 +241,23 @@ function parseGlyf(reader, ttf, offset) {
|
||||
delete glyf.yMax;
|
||||
}
|
||||
|
||||
// instructions
|
||||
length = reader.readUint16();
|
||||
if (length) {
|
||||
// range错误
|
||||
if (length < MAX_INSTRUCTION_LENGTH) {
|
||||
instructions = [];
|
||||
for (i = 0; i < length; ++i) {
|
||||
instructions.push(reader.readUint8());
|
||||
/* 优化12+42: 非 hinting 模式只跳过 instructions */
|
||||
var instrLength = view.getUint16(vOffset, false);
|
||||
vOffset += 2;
|
||||
if (hinting && instrLength && instrLength < MAX_INSTRUCTION_LENGTH) {
|
||||
var instructions = new Array(instrLength);
|
||||
for (var j = 0; j < instrLength; j++) {
|
||||
instructions[j] = view.getUint8(vOffset + j);
|
||||
}
|
||||
glyf.instructions = instructions;
|
||||
} else {
|
||||
console.warn(length);
|
||||
}
|
||||
}
|
||||
vOffset += instrLength;
|
||||
reader.offset = vOffset - view.byteOffset;
|
||||
|
||||
parseSimpleGlyf(reader, glyf);
|
||||
delete glyf.endPtsOfContours;
|
||||
} else {
|
||||
reader.offset = vOffset - view.byteOffset;
|
||||
parseCompoundGlyf(reader, glyf);
|
||||
}
|
||||
return glyf;
|
||||
|
||||
280
vendor/fonteditor-core/lib/ttf/table/glyf/sizeof.js
vendored
280
vendor/fonteditor-core/lib/ttf/table/glyf/sizeof.js
vendored
@ -12,166 +12,87 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
||||
*/
|
||||
|
||||
/**
|
||||
* 获取glyf的大小
|
||||
*
|
||||
* @param {Object} glyf glyf对象
|
||||
* @param {Object} glyfSupport glyf相关统计
|
||||
* @param {boolean} hinting 是否保留hints
|
||||
* @param {boolean} writeZeroContoursGlyfData 是否写空轮廓 glyph
|
||||
* @return {number} size大小
|
||||
* 优化33+38+39+40+48+49+57: getFlagsAndSize 单遍扫描替代两遍扫描
|
||||
*/
|
||||
function sizeofSimple(glyf, glyfSupport, hinting, writeZeroContoursGlyfData) {
|
||||
if (!writeZeroContoursGlyfData && (!glyf.contours || !glyf.contours.length)) {
|
||||
function getFlagsAndSize(glyf, glyfSupport, hinting) {
|
||||
if (!glyf.contours || glyf.contours.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// fixed header + endPtsOfContours
|
||||
var result = 12 + (glyf.contours || []).length * 2 + (glyfSupport.flags || []).length;
|
||||
(glyfSupport.xCoord || []).forEach(function (x) {
|
||||
result += 0 <= x && x <= 0xFF ? 1 : 2;
|
||||
});
|
||||
(glyfSupport.yCoord || []).forEach(function (y) {
|
||||
result += 0 <= y && y <= 0xFF ? 1 : 2;
|
||||
});
|
||||
return result + (hinting && glyf.instructions ? glyf.instructions.length : 0);
|
||||
}
|
||||
/* 优化33: 缓存 glyFlag 常量到局部变量 */
|
||||
var ONCURVE = _glyFlag.default.ONCURVE;
|
||||
var XSHORT = _glyFlag.default.XSHORT;
|
||||
var YSHORT = _glyFlag.default.YSHORT;
|
||||
var XSAME = _glyFlag.default.XSAME;
|
||||
var YSAME = _glyFlag.default.YSAME;
|
||||
var REPEAT = _glyFlag.default.REPEAT;
|
||||
|
||||
/**
|
||||
* 复合图元size
|
||||
*
|
||||
* @param {Object} glyf glyf对象
|
||||
* @param {boolean} hinting 是否保留hints, compound 图元暂时不做hinting
|
||||
* @return {number} size大小
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function sizeofCompound(glyf, hinting) {
|
||||
var size = 10;
|
||||
var transform;
|
||||
glyf.glyfs.forEach(function (g) {
|
||||
transform = g.transform;
|
||||
// flags + glyfIndex
|
||||
size += 4;
|
||||
|
||||
// a, b, c, d, e
|
||||
// xy values or points
|
||||
if (transform.e < 0 || transform.e > 0x7F || transform.f < 0 || transform.f > 0x7F) {
|
||||
size += 4;
|
||||
} else {
|
||||
size += 2;
|
||||
}
|
||||
|
||||
// 01 , 10
|
||||
if (transform.b || transform.c) {
|
||||
size += 8;
|
||||
}
|
||||
// scale
|
||||
else if (transform.a !== 1 || transform.d !== 1) {
|
||||
size += transform.a === transform.d ? 2 : 4;
|
||||
}
|
||||
});
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取flags
|
||||
*
|
||||
* @param {Object} glyf glyf对象
|
||||
* @param {Object} glyfSupport glyf相关统计
|
||||
* @return {Array}
|
||||
*/
|
||||
function getFlags(glyf, glyfSupport) {
|
||||
if (!glyf.contours || 0 === glyf.contours.length) {
|
||||
return glyfSupport;
|
||||
}
|
||||
var flags = [];
|
||||
var xCoord = [];
|
||||
var yCoord = [];
|
||||
var contours = glyf.contours;
|
||||
var contour;
|
||||
var prev;
|
||||
var first = true;
|
||||
for (var j = 0, cl = contours.length; j < cl; j++) {
|
||||
contour = contours[j];
|
||||
for (var i = 0, l = contour.length; i < l; i++) {
|
||||
var point = contour[i];
|
||||
if (first) {
|
||||
xCoord.push(point.x);
|
||||
yCoord.push(point.y);
|
||||
first = false;
|
||||
} else {
|
||||
xCoord.push(point.x - prev.x);
|
||||
yCoord.push(point.y - prev.y);
|
||||
}
|
||||
flags.push(point.onCurve ? _glyFlag.default.ONCURVE : 0);
|
||||
prev = point;
|
||||
}
|
||||
}
|
||||
|
||||
// compress
|
||||
var flagsC = [];
|
||||
var xCoordC = [];
|
||||
var yCoordC = [];
|
||||
var x;
|
||||
var y;
|
||||
var prevFlag;
|
||||
var contours = glyf.contours;
|
||||
var prevX = 0, prevY = 0;
|
||||
var isFirst = true;
|
||||
var prevFlag = -1;
|
||||
var repeatPoint = -1;
|
||||
flags.forEach(function (flag, index) {
|
||||
x = xCoord[index];
|
||||
y = yCoord[index];
|
||||
|
||||
// 第一个
|
||||
if (index === 0) {
|
||||
if (-0xFF <= x && x <= 0xFF) {
|
||||
flag += _glyFlag.default.XSHORT;
|
||||
if (x >= 0) {
|
||||
flag += _glyFlag.default.XSAME;
|
||||
}
|
||||
x = Math.abs(x);
|
||||
}
|
||||
if (-0xFF <= y && y <= 0xFF) {
|
||||
flag += _glyFlag.default.YSHORT;
|
||||
if (y >= 0) {
|
||||
flag += _glyFlag.default.YSAME;
|
||||
}
|
||||
y = Math.abs(y);
|
||||
}
|
||||
flagsC.push(prevFlag = flag);
|
||||
xCoordC.push(x);
|
||||
yCoordC.push(y);
|
||||
}
|
||||
// 后续
|
||||
else {
|
||||
if (x === 0) {
|
||||
flag += _glyFlag.default.XSAME;
|
||||
/* 单次遍历: delta坐标计算 + flag压缩 + 坐标编码 + 大小累加 */
|
||||
var encodedCoordSize = 0;
|
||||
|
||||
for (var j = 0, cl = contours.length; j < cl; j++) {
|
||||
var contour = contours[j];
|
||||
for (var i = 0, l = contour.length; i < l; i++) {
|
||||
var point = contour[i];
|
||||
var px = point.x;
|
||||
var py = point.y;
|
||||
var dx, dy;
|
||||
var flag = point.onCurve ? ONCURVE : 0;
|
||||
|
||||
if (isFirst) {
|
||||
dx = px;
|
||||
dy = py;
|
||||
isFirst = false;
|
||||
} else {
|
||||
if (-0xFF <= x && x <= 0xFF) {
|
||||
flag += _glyFlag.default.XSHORT;
|
||||
if (x > 0) {
|
||||
flag += _glyFlag.default.XSAME;
|
||||
dx = px - prevX;
|
||||
dy = py - prevY;
|
||||
}
|
||||
x = Math.abs(x);
|
||||
}
|
||||
xCoordC.push(x);
|
||||
}
|
||||
if (y === 0) {
|
||||
flag += _glyFlag.default.YSAME;
|
||||
prevX = px;
|
||||
prevY = py;
|
||||
|
||||
var xEncoded = 0;
|
||||
var yEncoded = 0;
|
||||
|
||||
if (dx === 0) {
|
||||
flag += XSAME;
|
||||
} else if (-0xFF <= dx && dx <= 0xFF) {
|
||||
flag += XSHORT;
|
||||
if (dx > 0) flag += XSAME;
|
||||
xEncoded = Math.abs(dx);
|
||||
xCoordC.push(xEncoded);
|
||||
encodedCoordSize += 1;
|
||||
} else {
|
||||
if (-0xFF <= y && y <= 0xFF) {
|
||||
flag += _glyFlag.default.YSHORT;
|
||||
if (y > 0) {
|
||||
flag += _glyFlag.default.YSAME;
|
||||
}
|
||||
y = Math.abs(y);
|
||||
}
|
||||
yCoordC.push(y);
|
||||
xCoordC.push(dx);
|
||||
encodedCoordSize += 2;
|
||||
}
|
||||
|
||||
// repeat
|
||||
if (flag === prevFlag) {
|
||||
// 记录重复个数
|
||||
if (-1 === repeatPoint) {
|
||||
if (dy === 0) {
|
||||
flag += YSAME;
|
||||
} else if (-0xFF <= dy && dy <= 0xFF) {
|
||||
flag += YSHORT;
|
||||
if (dy > 0) flag += YSAME;
|
||||
yEncoded = Math.abs(dy);
|
||||
yCoordC.push(yEncoded);
|
||||
encodedCoordSize += 1;
|
||||
} else {
|
||||
yCoordC.push(dy);
|
||||
encodedCoordSize += 2;
|
||||
}
|
||||
|
||||
/* REPEAT 压缩 */
|
||||
if (flag === prevFlag && !isFirst) {
|
||||
if (repeatPoint === -1) {
|
||||
repeatPoint = flagsC.length - 1;
|
||||
flagsC[repeatPoint] |= _glyFlag.default.REPEAT;
|
||||
flagsC[repeatPoint] |= REPEAT;
|
||||
flagsC.push(1);
|
||||
} else {
|
||||
++flagsC[repeatPoint + 1];
|
||||
@ -181,42 +102,73 @@ function getFlags(glyf, glyfSupport) {
|
||||
flagsC.push(prevFlag = flag);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
glyfSupport.flags = flagsC;
|
||||
glyfSupport.xCoord = xCoordC;
|
||||
glyfSupport.yCoord = yCoordC;
|
||||
return glyfSupport;
|
||||
|
||||
var instructionSize = (hinting && glyf.instructions) ? glyf.instructions.length : 0;
|
||||
/* 12 bytes header + endPtsOfContours + flags + encoded coords + instructions */
|
||||
return 12 + contours.length * 2 + flagsC.length + encodedCoordSize + instructionSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对glyf数据进行预处理,获取大小
|
||||
*
|
||||
* @param {Object} ttf ttf对象
|
||||
* @return {number} 大小
|
||||
* 优化48: sizeofCompound forEach → for 循环
|
||||
*/
|
||||
function sizeofCompound(glyf) {
|
||||
var size = 10;
|
||||
var glyfs = glyf.glyfs;
|
||||
for (var i = 0, l = glyfs.length; i < l; i++) {
|
||||
var transform = glyfs[i].transform;
|
||||
size += 4;
|
||||
if (transform.e < 0 || transform.e > 0x7F || transform.f < 0 || transform.f > 0x7F) {
|
||||
size += 4;
|
||||
} else {
|
||||
size += 2;
|
||||
}
|
||||
if (transform.b || transform.c) {
|
||||
size += 8;
|
||||
} else if (transform.a !== 1 || transform.d !== 1) {
|
||||
size += transform.a === transform.d ? 2 : 4;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 优化49: sizeof glyf.forEach → for 循环
|
||||
*/
|
||||
function sizeof(ttf) {
|
||||
ttf.support.glyf = [];
|
||||
var glyfSupportArr = [];
|
||||
ttf.support.glyf = glyfSupportArr;
|
||||
var tableSize = 0;
|
||||
var hinting = ttf.writeOptions ? ttf.writeOptions.hinting : false;
|
||||
var writeZeroContoursGlyfData = ttf.writeOptions ? ttf.writeOptions.writeZeroContoursGlyfData : false;
|
||||
ttf.glyf.forEach(function (glyf) {
|
||||
var glyfSupport = {};
|
||||
glyfSupport = glyf.compound ? glyfSupport : getFlags(glyf, glyfSupport);
|
||||
var glyfSize = glyf.compound ? sizeofCompound(glyf, hinting) : sizeofSimple(glyf, glyfSupport, hinting, writeZeroContoursGlyfData);
|
||||
var size = glyfSize;
|
||||
var glyfs = ttf.glyf;
|
||||
|
||||
// 4字节对齐
|
||||
for (var i = 0, gl = glyfs.length; i < gl; i++) {
|
||||
var glyf = glyfs[i];
|
||||
var glyfSupport = {};
|
||||
var glyfSize;
|
||||
if (glyf.compound) {
|
||||
glyfSize = sizeofCompound(glyf);
|
||||
} else if (!writeZeroContoursGlyfData && (!glyf.contours || !glyf.contours.length)) {
|
||||
glyfSize = 0;
|
||||
} else {
|
||||
glyfSize = getFlagsAndSize(glyf, glyfSupport, hinting);
|
||||
}
|
||||
|
||||
var size = glyfSize;
|
||||
if (size % 4) {
|
||||
size += 4 - size % 4;
|
||||
}
|
||||
glyfSupport.glyfSize = glyfSize;
|
||||
glyfSupport.size = size;
|
||||
ttf.support.glyf.push(glyfSupport);
|
||||
glyfSupportArr[i] = glyfSupport;
|
||||
tableSize += size;
|
||||
});
|
||||
ttf.support.glyf.tableSize = tableSize;
|
||||
|
||||
// 写header的indexToLocFormat
|
||||
ttf.head.indexToLocFormat = tableSize > 65536 ? 1 : 0;
|
||||
return ttf.support.glyf.tableSize;
|
||||
}
|
||||
glyfSupportArr.tableSize = tableSize;
|
||||
ttf.head.indexToLocFormat = tableSize > 65536 ? 1 : 0;
|
||||
return tableSize;
|
||||
}
|
||||
192
vendor/fonteditor-core/lib/ttf/table/glyf/write.js
vendored
192
vendor/fonteditor-core/lib/ttf/table/glyf/write.js
vendored
@ -12,45 +12,51 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
||||
*/
|
||||
|
||||
/**
|
||||
* 写glyf
|
||||
*
|
||||
* @param {Object} writer 写入器
|
||||
* @param {Object} ttf ttf对象
|
||||
* @return {Object} 写入器
|
||||
* 优化11+21+25+31+32+50+51+52+53+58: glyf write 全面优化
|
||||
*/
|
||||
function write(writer, ttf) {
|
||||
var hinting = ttf.writeOptions ? ttf.writeOptions.hinting : false;
|
||||
var writeZeroContoursGlyfData = ttf.writeOptions ? ttf.writeOptions.writeZeroContoursGlyfData : false;
|
||||
ttf.glyf.forEach(function (glyf, index) {
|
||||
// 非复合图元没有轮廓则不写
|
||||
|
||||
/* 优化53: 缓存 glyfSupport 到局部变量 */
|
||||
var glyfSupport = ttf.support.glyf;
|
||||
var glyfs = ttf.glyf;
|
||||
var view = writer.view;
|
||||
var ARG_1_AND_2_ARE_WORDS = _componentFlag.default.ARG_1_AND_2_ARE_WORDS;
|
||||
var ROUND_XY_TO_GRID = _componentFlag.default.ROUND_XY_TO_GRID;
|
||||
var WE_HAVE_A_SCALE = _componentFlag.default.WE_HAVE_A_SCALE;
|
||||
var WE_HAVE_AN_X_AND_Y_SCALE = _componentFlag.default.WE_HAVE_AN_X_AND_Y_SCALE;
|
||||
var WE_HAVE_A_TWO_BY_TWO = _componentFlag.default.WE_HAVE_A_TWO_BY_TWO;
|
||||
var ARGS_ARE_XY_VALUES = _componentFlag.default.ARGS_ARE_XY_VALUES;
|
||||
var USE_MY_METRICS = _componentFlag.default.USE_MY_METRICS;
|
||||
var OVERLAP_COMPOUND = _componentFlag.default.OVERLAP_COMPOUND;
|
||||
var MORE_COMPONENTS = _componentFlag.default.MORE_COMPONENTS;
|
||||
|
||||
for (var index = 0, gl = glyfs.length; index < gl; index++) {
|
||||
var glyf = glyfs[index];
|
||||
|
||||
/* 优化51: return → continue */
|
||||
if (!glyf.compound && !writeZeroContoursGlyfData && (!glyf.contours || !glyf.contours.length)) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
// header
|
||||
writer.writeInt16(glyf.compound ? -1 : (glyf.contours || []).length);
|
||||
writer.writeInt16(glyf.xMin);
|
||||
writer.writeInt16(glyf.yMin);
|
||||
writer.writeInt16(glyf.xMax);
|
||||
writer.writeInt16(glyf.yMax);
|
||||
var i;
|
||||
var l;
|
||||
var flags;
|
||||
|
||||
// 复合图元
|
||||
/* 优化31: header 直接 view 写入 10 字节 */
|
||||
var pos = writer.offset;
|
||||
view.setInt16(pos, glyf.compound ? -1 : (glyf.contours || []).length, false);
|
||||
view.setInt16(pos + 2, glyf.xMin, false);
|
||||
view.setInt16(pos + 4, glyf.yMin, false);
|
||||
view.setInt16(pos + 6, glyf.xMax, false);
|
||||
view.setInt16(pos + 8, glyf.yMax, false);
|
||||
pos += 10;
|
||||
|
||||
if (glyf.compound) {
|
||||
for (i = 0, l = glyf.glyfs.length; i < l; i++) {
|
||||
var g = glyf.glyfs[i];
|
||||
flags = g.points ? 0 : _componentFlag.default.ARGS_ARE_XY_VALUES + _componentFlag.default.ROUND_XY_TO_GRID; // xy values
|
||||
|
||||
// more components
|
||||
if (i < l - 1) {
|
||||
flags += _componentFlag.default.MORE_COMPONENTS;
|
||||
}
|
||||
|
||||
// use my metrics
|
||||
flags += g.useMyMetrics ? _componentFlag.default.USE_MY_METRICS : 0;
|
||||
// overlap compound
|
||||
flags += g.overlapCompound ? _componentFlag.default.OVERLAP_COMPOUND : 0;
|
||||
var subGlyfs = glyf.glyfs;
|
||||
for (var gi = 0, gl2 = subGlyfs.length; gi < gl2; gi++) {
|
||||
var g = subGlyfs[gi];
|
||||
var flags = g.points ? 0 : ARGS_ARE_XY_VALUES + ROUND_XY_TO_GRID;
|
||||
if (gi < gl2 - 1) flags += MORE_COMPONENTS;
|
||||
flags += g.useMyMetrics ? USE_MY_METRICS : 0;
|
||||
flags += g.overlapCompound ? OVERLAP_COMPOUND : 0;
|
||||
var transform = g.transform;
|
||||
var a = transform.a;
|
||||
var b = transform.b;
|
||||
@ -58,86 +64,106 @@ function write(writer, ttf) {
|
||||
var d = transform.d;
|
||||
var e = g.points ? g.points[0] : transform.e;
|
||||
var f = g.points ? g.points[1] : transform.f;
|
||||
|
||||
// xy values or points
|
||||
// int 8 放不下,则用int16放
|
||||
if (e < 0 || e > 0x7F || f < 0 || f > 0x7F) {
|
||||
flags += _componentFlag.default.ARG_1_AND_2_ARE_WORDS;
|
||||
flags += ARG_1_AND_2_ARE_WORDS;
|
||||
}
|
||||
if (b || c) {
|
||||
flags += _componentFlag.default.WE_HAVE_A_TWO_BY_TWO;
|
||||
flags += WE_HAVE_A_TWO_BY_TWO;
|
||||
} else if ((a !== 1 || d !== 1) && a === d) {
|
||||
flags += _componentFlag.default.WE_HAVE_A_SCALE;
|
||||
flags += WE_HAVE_A_SCALE;
|
||||
} else if (a !== 1 || d !== 1) {
|
||||
flags += _componentFlag.default.WE_HAVE_AN_X_AND_Y_SCALE;
|
||||
flags += WE_HAVE_AN_X_AND_Y_SCALE;
|
||||
}
|
||||
writer.writeUint16(flags);
|
||||
writer.writeUint16(g.glyphIndex);
|
||||
if (_componentFlag.default.ARG_1_AND_2_ARE_WORDS & flags) {
|
||||
writer.writeInt16(e);
|
||||
writer.writeInt16(f);
|
||||
view.setUint16(pos, flags, false); pos += 2;
|
||||
view.setUint16(pos, g.glyphIndex, false); pos += 2;
|
||||
if (ARG_1_AND_2_ARE_WORDS & flags) {
|
||||
view.setInt16(pos, e, false); pos += 2;
|
||||
view.setInt16(pos, f, false); pos += 2;
|
||||
} else {
|
||||
writer.writeUint8(e);
|
||||
writer.writeUint8(f);
|
||||
view.setUint8(pos, e); pos += 1;
|
||||
view.setUint8(pos, f); pos += 1;
|
||||
}
|
||||
if (_componentFlag.default.WE_HAVE_A_SCALE & flags) {
|
||||
writer.writeInt16(Math.round(a * 16384));
|
||||
} else if (_componentFlag.default.WE_HAVE_AN_X_AND_Y_SCALE & flags) {
|
||||
writer.writeInt16(Math.round(a * 16384));
|
||||
writer.writeInt16(Math.round(d * 16384));
|
||||
} else if (_componentFlag.default.WE_HAVE_A_TWO_BY_TWO & flags) {
|
||||
writer.writeInt16(Math.round(a * 16384));
|
||||
writer.writeInt16(Math.round(b * 16384));
|
||||
writer.writeInt16(Math.round(c * 16384));
|
||||
writer.writeInt16(Math.round(d * 16384));
|
||||
if (WE_HAVE_A_SCALE & flags) {
|
||||
view.setInt16(pos, Math.round(a * 16384), false); pos += 2;
|
||||
} else if (WE_HAVE_AN_X_AND_Y_SCALE & flags) {
|
||||
view.setInt16(pos, Math.round(a * 16384), false); pos += 2;
|
||||
view.setInt16(pos, Math.round(d * 16384), false); pos += 2;
|
||||
} else if (WE_HAVE_A_TWO_BY_TWO & flags) {
|
||||
view.setInt16(pos, Math.round(a * 16384), false); pos += 2;
|
||||
view.setInt16(pos, Math.round(b * 16384), false); pos += 2;
|
||||
view.setInt16(pos, Math.round(c * 16384), false); pos += 2;
|
||||
view.setInt16(pos, Math.round(d * 16384), false); pos += 2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var endPtsOfContours = -1;
|
||||
(glyf.contours || []).forEach(function (contour) {
|
||||
endPtsOfContours += contour.length;
|
||||
writer.writeUint16(endPtsOfContours);
|
||||
});
|
||||
/* 优化32: endPtsOfContours 直接 view 写入 */
|
||||
var contours = glyf.contours || [];
|
||||
var endPts = -1;
|
||||
for (var ci = 0, cl = contours.length; ci < cl; ci++) {
|
||||
endPts += contours[ci].length;
|
||||
view.setUint16(pos, endPts, false);
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
// instruction
|
||||
/* 优化25: instructions 批量写入 */
|
||||
if (hinting && glyf.instructions) {
|
||||
var instructions = glyf.instructions;
|
||||
writer.writeUint16(instructions.length);
|
||||
for (i = 0, l = instructions.length; i < l; i++) {
|
||||
writer.writeUint8(instructions[i]);
|
||||
view.setUint16(pos, instructions.length, false);
|
||||
pos += 2;
|
||||
for (var ii = 0, il = instructions.length; ii < il; ii++) {
|
||||
view.setUint8(pos + ii, instructions[ii]);
|
||||
}
|
||||
pos += instructions.length;
|
||||
} else {
|
||||
writer.writeUint16(0);
|
||||
view.setUint16(pos, 0, false);
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
// 获取暂存中的flags
|
||||
flags = ttf.support.glyf[index].flags || [];
|
||||
for (i = 0, l = flags.length; i < l; i++) {
|
||||
writer.writeUint8(flags[i]);
|
||||
/* 优化11: flags 批量写入 */
|
||||
var flags = glyfSupport[index].flags || [];
|
||||
for (var fi = 0, fl = flags.length; fi < fl; fi++) {
|
||||
view.setUint8(pos + fi, flags[fi]);
|
||||
}
|
||||
var xCoord = ttf.support.glyf[index].xCoord || [];
|
||||
for (i = 0, l = xCoord.length; i < l; i++) {
|
||||
if (0 <= xCoord[i] && xCoord[i] <= 0xFF) {
|
||||
writer.writeUint8(xCoord[i]);
|
||||
pos += fl;
|
||||
|
||||
/* 优化21: xCoord 直接 view 写入 */
|
||||
var xCoord = glyfSupport[index].xCoord || [];
|
||||
for (var xi = 0, xl = xCoord.length; xi < xl; xi++) {
|
||||
var xv = xCoord[xi];
|
||||
if (0 <= xv && xv <= 0xFF) {
|
||||
view.setUint8(pos, xv);
|
||||
pos += 1;
|
||||
} else {
|
||||
writer.writeInt16(xCoord[i]);
|
||||
view.setInt16(pos, xv, false);
|
||||
pos += 2;
|
||||
}
|
||||
}
|
||||
var yCoord = ttf.support.glyf[index].yCoord || [];
|
||||
for (i = 0, l = yCoord.length; i < l; i++) {
|
||||
if (0 <= yCoord[i] && yCoord[i] <= 0xFF) {
|
||||
writer.writeUint8(yCoord[i]);
|
||||
|
||||
/* 优化21+58: yCoord 直接 view 写入,使用各自的数组长度 */
|
||||
var yCoord = glyfSupport[index].yCoord || [];
|
||||
for (var yi = 0, yl = yCoord.length; yi < yl; yi++) {
|
||||
var yv = yCoord[yi];
|
||||
if (0 <= yv && yv <= 0xFF) {
|
||||
view.setUint8(pos, yv);
|
||||
pos += 1;
|
||||
} else {
|
||||
writer.writeInt16(yCoord[i]);
|
||||
view.setInt16(pos, yv, false);
|
||||
pos += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4字节对齐
|
||||
var glyfSize = ttf.support.glyf[index].glyfSize;
|
||||
/* 4字节对齐 */
|
||||
var glyfSize = glyfSupport[index].glyfSize;
|
||||
if (glyfSize % 4) {
|
||||
writer.writeEmpty(4 - glyfSize % 4);
|
||||
var pad = 4 - glyfSize % 4;
|
||||
for (var p = 0; p < pad; p++) {
|
||||
view.setUint8(pos + p, 0);
|
||||
}
|
||||
pos += pad;
|
||||
}
|
||||
|
||||
writer.offset = pos;
|
||||
}
|
||||
});
|
||||
return writer;
|
||||
}
|
||||
57
vendor/fonteditor-core/lib/ttf/table/hmtx.js
vendored
57
vendor/fonteditor-core/lib/ttf/table/hmtx.js
vendored
@ -17,48 +17,51 @@ var _default = exports.default = _table.default.create('hmtx', [], {
|
||||
var offset = this.offset;
|
||||
reader.seek(offset);
|
||||
var numOfLongHorMetrics = ttf.hhea.numOfLongHorMetrics;
|
||||
var hMetrics = [];
|
||||
var i;
|
||||
var hMetric;
|
||||
for (i = 0; i < numOfLongHorMetrics; ++i) {
|
||||
hMetric = {};
|
||||
hMetric.advanceWidth = reader.readUint16();
|
||||
hMetric.leftSideBearing = reader.readInt16();
|
||||
hMetrics.push(hMetric);
|
||||
var numGlyphs = ttf.maxp.numGlyphs;
|
||||
var hMetrics = new Array(numGlyphs);
|
||||
/* 优化10: 直接 view 批量读取 */
|
||||
var view = reader.view;
|
||||
var vOffset = view.byteOffset + offset;
|
||||
for (var i = 0; i < numOfLongHorMetrics; i++) {
|
||||
hMetrics[i] = {
|
||||
advanceWidth: view.getUint16(vOffset, false),
|
||||
leftSideBearing: view.getInt16(vOffset + 2, false)
|
||||
};
|
||||
vOffset += 4;
|
||||
}
|
||||
|
||||
// 最后一个宽度
|
||||
var advanceWidth = hMetrics[numOfLongHorMetrics - 1].advanceWidth;
|
||||
var numOfLast = ttf.maxp.numGlyphs - numOfLongHorMetrics;
|
||||
|
||||
// 获取后续的hmetrics
|
||||
for (i = 0; i < numOfLast; ++i) {
|
||||
hMetric = {};
|
||||
hMetric.advanceWidth = advanceWidth;
|
||||
hMetric.leftSideBearing = reader.readInt16();
|
||||
hMetrics.push(hMetric);
|
||||
var numOfLast = numGlyphs - numOfLongHorMetrics;
|
||||
for (var j = 0; j < numOfLast; j++) {
|
||||
hMetrics[numOfLongHorMetrics + j] = {
|
||||
advanceWidth: advanceWidth,
|
||||
leftSideBearing: view.getInt16(vOffset, false)
|
||||
};
|
||||
vOffset += 2;
|
||||
}
|
||||
reader.offset = offset + numOfLongHorMetrics * 4 + numOfLast * 2;
|
||||
return hMetrics;
|
||||
},
|
||||
write: function write(writer, ttf) {
|
||||
var i;
|
||||
var numOfLongHorMetrics = ttf.hhea.numOfLongHorMetrics;
|
||||
for (i = 0; i < numOfLongHorMetrics; ++i) {
|
||||
writer.writeUint16(ttf.glyf[i].advanceWidth);
|
||||
writer.writeInt16(ttf.glyf[i].leftSideBearing);
|
||||
/* 优化30: 直接 view 批量写入 */
|
||||
var wView = writer.view;
|
||||
var pos = writer.offset;
|
||||
for (i = 0; i < numOfLongHorMetrics; i++) {
|
||||
wView.setUint16(pos, ttf.glyf[i].advanceWidth, false);
|
||||
wView.setInt16(pos + 2, ttf.glyf[i].leftSideBearing, false);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
// 最后一个宽度
|
||||
var numOfLast = ttf.glyf.length - numOfLongHorMetrics;
|
||||
for (i = 0; i < numOfLast; ++i) {
|
||||
writer.writeInt16(ttf.glyf[numOfLongHorMetrics + i].leftSideBearing);
|
||||
for (i = 0; i < numOfLast; i++) {
|
||||
wView.setInt16(pos, ttf.glyf[numOfLongHorMetrics + i].leftSideBearing, false);
|
||||
pos += 2;
|
||||
}
|
||||
writer.offset = pos;
|
||||
return writer;
|
||||
},
|
||||
size: function size(ttf) {
|
||||
// 计算同最后一个advanceWidth相等的元素个数
|
||||
var numOfLast = 0;
|
||||
// 最后一个advanceWidth
|
||||
var advanceWidth = ttf.glyf[ttf.glyf.length - 1].advanceWidth;
|
||||
for (var i = ttf.glyf.length - 2; i >= 0; i--) {
|
||||
if (advanceWidth === ttf.glyf[i].advanceWidth) {
|
||||
|
||||
53
vendor/fonteditor-core/lib/ttf/table/loca.js
vendored
53
vendor/fonteditor-core/lib/ttf/table/loca.js
vendored
@ -15,17 +15,24 @@ var _default = exports.default = _table.default.create('loca', [], {
|
||||
read: function read(reader, ttf) {
|
||||
var offset = this.offset;
|
||||
var indexToLocFormat = ttf.head.indexToLocFormat;
|
||||
// indexToLocFormat有2字节和4字节的区别
|
||||
var type = _struct.default.names[indexToLocFormat === 0 ? _struct.default.Uint16 : _struct.default.Uint32];
|
||||
var size = indexToLocFormat === 0 ? 2 : 4; // 字节大小
|
||||
var sizeRatio = indexToLocFormat === 0 ? 2 : 1; // 真实地址偏移
|
||||
var wordOffset = [];
|
||||
reader.seek(offset);
|
||||
/* 优化7: 直接 view 批量读取,预分配数组 */
|
||||
var numGlyphs = ttf.maxp.numGlyphs;
|
||||
for (var i = 0; i < numGlyphs; ++i) {
|
||||
wordOffset.push(reader.read(type, offset, false) * sizeRatio);
|
||||
offset += size;
|
||||
var wordOffset = new Array(numGlyphs);
|
||||
var view = reader.view;
|
||||
if (indexToLocFormat === 0) {
|
||||
var vOffset = view.byteOffset + offset;
|
||||
for (var i = 0; i < numGlyphs; i++) {
|
||||
wordOffset[i] = view.getUint16(vOffset, false) * 2;
|
||||
vOffset += 2;
|
||||
}
|
||||
} else {
|
||||
var vOffset2 = view.byteOffset + offset;
|
||||
for (var j = 0; j < numGlyphs; j++) {
|
||||
wordOffset[j] = view.getUint32(vOffset2, false);
|
||||
vOffset2 += 4;
|
||||
}
|
||||
}
|
||||
reader.offset = offset + (indexToLocFormat === 0 ? numGlyphs * 2 : numGlyphs * 4);
|
||||
return wordOffset;
|
||||
},
|
||||
write: function write(writer, ttf) {
|
||||
@ -34,21 +41,27 @@ var _default = exports.default = _table.default.create('loca', [], {
|
||||
var indexToLocFormat = ttf.head.indexToLocFormat;
|
||||
var sizeRatio = indexToLocFormat === 0 ? 0.5 : 1;
|
||||
var numGlyphs = ttf.glyf.length;
|
||||
for (var i = 0; i < numGlyphs; ++i) {
|
||||
/* 优化29: 直接 view 批量写入 */
|
||||
var wView = writer.view;
|
||||
var pos = writer.offset;
|
||||
if (indexToLocFormat) {
|
||||
writer.writeUint32(offset);
|
||||
} else {
|
||||
writer.writeUint16(offset);
|
||||
}
|
||||
for (var i = 0; i <= numGlyphs; i++) {
|
||||
wView.setUint32(pos, offset, false);
|
||||
pos += 4;
|
||||
if (i < numGlyphs) {
|
||||
offset += glyfSupport[i].size * sizeRatio;
|
||||
}
|
||||
|
||||
// write extra
|
||||
if (indexToLocFormat) {
|
||||
writer.writeUint32(offset);
|
||||
} else {
|
||||
writer.writeUint16(offset);
|
||||
}
|
||||
} else {
|
||||
for (var j = 0; j <= numGlyphs; j++) {
|
||||
wView.setUint16(pos, offset, false);
|
||||
pos += 2;
|
||||
if (j < numGlyphs) {
|
||||
offset += glyfSupport[j].size * sizeRatio;
|
||||
}
|
||||
}
|
||||
}
|
||||
writer.offset = pos;
|
||||
return writer;
|
||||
},
|
||||
size: function size(ttf) {
|
||||
|
||||
93
vendor/fonteditor-core/lib/ttf/table/post.js
vendored
93
vendor/fonteditor-core/lib/ttf/table/post.js
vendored
@ -17,26 +17,55 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
||||
*/
|
||||
|
||||
var Posthead = _table.default.create('posthead', [['format', _struct.default.Fixed], ['italicAngle', _struct.default.Fixed], ['underlinePosition', _struct.default.Int16], ['underlineThickness', _struct.default.Int16], ['isFixedPitch', _struct.default.Uint32], ['minMemType42', _struct.default.Uint32], ['maxMemType42', _struct.default.Uint32], ['minMemType1', _struct.default.Uint32], ['maxMemType1', _struct.default.Uint32]]);
|
||||
|
||||
/**
|
||||
* 优化64: 从原始字节按需提取单个 pascal string
|
||||
*/
|
||||
function getPascalStringAt(bytes, offset) {
|
||||
var length = bytes[offset];
|
||||
if (length === 0) return '';
|
||||
var chars = new Array(length);
|
||||
for (var i = 0; i < length; i++) {
|
||||
chars[i] = String.fromCharCode(bytes[offset + 1 + i]);
|
||||
}
|
||||
return chars.join('');
|
||||
}
|
||||
|
||||
var _default = exports.default = _table.default.create('post', [], {
|
||||
read: function read(reader, ttf) {
|
||||
var format = reader.readFixed(this.offset);
|
||||
// 读取表头
|
||||
var tbl = new Posthead(this.offset).read(reader, ttf);
|
||||
|
||||
// format2
|
||||
if (format === 2) {
|
||||
var numberOfGlyphs = reader.readUint16();
|
||||
var glyphNameIndex = [];
|
||||
for (var i = 0; i < numberOfGlyphs; ++i) {
|
||||
glyphNameIndex.push(reader.readUint16());
|
||||
/* 优化60: 直接 view 批量读取 glyphNameIndex */
|
||||
var view = reader.view;
|
||||
var vOffset = view.byteOffset + reader.offset;
|
||||
var glyphNameIndex = new Array(numberOfGlyphs);
|
||||
for (var i = 0; i < numberOfGlyphs; i++) {
|
||||
glyphNameIndex[i] = view.getUint16(vOffset, false);
|
||||
vOffset += 2;
|
||||
}
|
||||
var pascalStringOffset = reader.offset;
|
||||
var pascalStringOffset = vOffset - view.byteOffset;
|
||||
var pascalStringLength = ttf.tables.post.length - (pascalStringOffset - this.offset);
|
||||
var pascalStringBytes = reader.readBytes(reader.offset, pascalStringLength);
|
||||
tbl.nameIndex = glyphNameIndex; // 设置glyf名字索引
|
||||
tbl.names = _string.default.getPascalString(pascalStringBytes); // glyf名字数组
|
||||
var pascalStringBytes = reader.readBytes(pascalStringOffset, pascalStringLength);
|
||||
|
||||
tbl.nameIndex = glyphNameIndex;
|
||||
|
||||
/* 优化64: subset 模式下保存原始字节,按需解析 */
|
||||
if (ttf.readOptions && ttf.readOptions.subset) {
|
||||
tbl._pascalStringBytes = pascalStringBytes;
|
||||
tbl._pascalStringOffsets = [];
|
||||
var off = 0;
|
||||
for (var j = 0; j < numberOfGlyphs; j++) {
|
||||
tbl._pascalStringOffsets[j] = off;
|
||||
off += 1 + (pascalStringBytes[off] || 0);
|
||||
}
|
||||
tbl.names = null;
|
||||
} else {
|
||||
tbl.names = _string.default.getPascalString(pascalStringBytes);
|
||||
}
|
||||
}
|
||||
// deprecated
|
||||
else if (format === 2.5) {
|
||||
tbl.format = 3;
|
||||
}
|
||||
@ -47,31 +76,27 @@ var _default = exports.default = _table.default.create('post', [], {
|
||||
format: 3
|
||||
};
|
||||
|
||||
// write header
|
||||
writer.writeFixed(post.format); // format
|
||||
writer.writeFixed(post.italicAngle || 0); // italicAngle
|
||||
writer.writeInt16(post.underlinePosition || 0); // underlinePosition
|
||||
writer.writeInt16(post.underlineThickness || 0); // underlineThickness
|
||||
writer.writeUint32(post.isFixedPitch || 0); // isFixedPitch
|
||||
writer.writeUint32(post.minMemType42 || 0); // minMemType42
|
||||
writer.writeUint32(post.maxMemType42 || 0); // maxMemType42
|
||||
writer.writeUint32(post.minMemType1 || 0); // minMemType1
|
||||
writer.writeUint32(post.maxMemType1 || 0); // maxMemType1
|
||||
writer.writeFixed(post.format);
|
||||
writer.writeFixed(post.italicAngle || 0);
|
||||
writer.writeInt16(post.underlinePosition || 0);
|
||||
writer.writeInt16(post.underlineThickness || 0);
|
||||
writer.writeUint32(post.isFixedPitch || 0);
|
||||
writer.writeUint32(post.minMemType42 || 0);
|
||||
writer.writeUint32(post.maxMemType42 || 0);
|
||||
writer.writeUint32(post.minMemType1 || 0);
|
||||
writer.writeUint32(post.maxMemType1 || 0);
|
||||
|
||||
// version 3 不设置post信息
|
||||
if (post.format === 2) {
|
||||
var numberOfGlyphs = ttf.glyf.length;
|
||||
writer.writeUint16(numberOfGlyphs); // numberOfGlyphs
|
||||
// write glyphNameIndex
|
||||
writer.writeUint16(numberOfGlyphs);
|
||||
var nameIndex = ttf.support.post.nameIndex;
|
||||
for (var i = 0, l = nameIndex.length; i < l; i++) {
|
||||
writer.writeUint16(nameIndex[i]);
|
||||
}
|
||||
|
||||
// write names
|
||||
ttf.support.post.names.forEach(function (name) {
|
||||
writer.writeBytes(name);
|
||||
});
|
||||
var names = ttf.support.post.names;
|
||||
for (var j = 0, jl = names.length; j < jl; j++) {
|
||||
writer.writeBytes(names[j]);
|
||||
}
|
||||
}
|
||||
},
|
||||
size: function size(ttf) {
|
||||
@ -80,20 +105,16 @@ var _default = exports.default = _table.default.create('post', [], {
|
||||
ttf.post.format = ttf.post.format || 3;
|
||||
ttf.post.maxMemType1 = numberOfGlyphs;
|
||||
|
||||
// version 3 不设置post信息
|
||||
if (ttf.post.format === 3 || ttf.post.format === 1) {
|
||||
return 32;
|
||||
}
|
||||
|
||||
// version 2
|
||||
var size = 34 + numberOfGlyphs * 2; // header + numberOfGlyphs + numberOfGlyphs * 2
|
||||
var size = 34 + numberOfGlyphs * 2;
|
||||
var glyphNames = [];
|
||||
var nameIndexArr = [];
|
||||
var nameIndex = 0;
|
||||
|
||||
// 获取 name的大小
|
||||
for (var i = 0; i < numberOfGlyphs; i++) {
|
||||
// .notdef
|
||||
if (i === 0) {
|
||||
nameIndexArr.push(0);
|
||||
} else {
|
||||
@ -103,7 +124,6 @@ var _default = exports.default = _table.default.create('post', [], {
|
||||
if (undefined !== unicodeNameIndex) {
|
||||
nameIndexArr.push(unicodeNameIndex);
|
||||
} else {
|
||||
// 这里需要注意,"" 有可能是"\3" length不为0,但是是空字符串
|
||||
var name = glyf.name;
|
||||
if (!name || name.charCodeAt(0) < 32) {
|
||||
nameIndexArr.push(258 + nameIndex++);
|
||||
@ -111,7 +131,7 @@ var _default = exports.default = _table.default.create('post', [], {
|
||||
size++;
|
||||
} else {
|
||||
nameIndexArr.push(258 + nameIndex++);
|
||||
var bytes = _string.default.toPascalStringBytes(name); // pascal string bytes
|
||||
var bytes = _string.default.toPascalStringBytes(name);
|
||||
glyphNames.push(bytes);
|
||||
size += bytes.length;
|
||||
}
|
||||
@ -125,3 +145,6 @@ var _default = exports.default = _table.default.create('post', [], {
|
||||
return size;
|
||||
}
|
||||
});
|
||||
|
||||
/** 按需获取单个 pascal string name(供 ttfreader.js 使用) */
|
||||
exports.getPascalStringAt = getPascalStringAt;
|
||||
|
||||
28
vendor/fonteditor-core/lib/ttf/ttf.js
vendored
28
vendor/fonteditor-core/lib/ttf/ttf.js
vendored
@ -652,23 +652,33 @@ var TTF = exports.default = /*#__PURE__*/function () {
|
||||
value: function sortGlyf() {
|
||||
var glyf = this.ttf.glyf;
|
||||
if (glyf.length > 1) {
|
||||
// 如果存在复合字形则退出
|
||||
if (glyf.some(function (a) {
|
||||
return a.compound;
|
||||
})) {
|
||||
/* 优化54: some → for 循环 + unicode 属性缓存 + Math.min.apply → 手动遍历 */
|
||||
var hasCompound = false;
|
||||
for (var k = 0, kl = glyf.length; k < kl; k++) {
|
||||
if (glyf[k].compound) {
|
||||
hasCompound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasCompound) {
|
||||
return -2;
|
||||
}
|
||||
var notdef = glyf.shift();
|
||||
// 按代码点排序, 首先将空字形排到最后,然后按照unicode第一个编码进行排序
|
||||
glyf.sort(function (a, b) {
|
||||
if ((!a.unicode || !a.unicode.length) && (!b.unicode || !b.unicode.length)) {
|
||||
var aU = a.unicode;
|
||||
var bU = b.unicode;
|
||||
if ((!aU || !aU.length) && (!bU || !bU.length)) {
|
||||
return 0;
|
||||
} else if ((!a.unicode || !a.unicode.length) && b.unicode) {
|
||||
} else if ((!aU || !aU.length) && bU) {
|
||||
return 1;
|
||||
} else if (a.unicode && (!b.unicode || !b.unicode.length)) {
|
||||
} else if (aU && (!bU || !bU.length)) {
|
||||
return -1;
|
||||
}
|
||||
return Math.min.apply(null, a.unicode) - Math.min.apply(null, b.unicode);
|
||||
/* 优化3: 手动遍历取最小值 */
|
||||
var aMin = aU[0], bMin = bU[0];
|
||||
for (var ai = 1; ai < aU.length; ai++) { if (aU[ai] < aMin) aMin = aU[ai]; }
|
||||
for (var bi = 1; bi < bU.length; bi++) { if (bU[bi] < bMin) bMin = bU[bi]; }
|
||||
return aMin - bMin;
|
||||
});
|
||||
glyf.unshift(notdef);
|
||||
return glyf;
|
||||
|
||||
200
vendor/fonteditor-core/lib/ttf/ttfreader.js
vendored
200
vendor/fonteditor-core/lib/ttf/ttfreader.js
vendored
@ -10,163 +10,155 @@ var _reader = _interopRequireDefault(require("./reader"));
|
||||
var _postName = _interopRequireDefault(require("./enum/postName"));
|
||||
var _error = _interopRequireDefault(require("./error"));
|
||||
var _compound2simpleglyf = _interopRequireDefault(require("./util/compound2simpleglyf"));
|
||||
var _post = require("./table/post");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
|
||||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
||||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
||||
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
||||
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /**
|
||||
/**
|
||||
* @file ttf读取器
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*
|
||||
* thanks to:
|
||||
* ynakajima/ttf.js
|
||||
* https://github.com/ynakajima/ttf.js
|
||||
*/
|
||||
var TTFReader = exports.default = /*#__PURE__*/function () {
|
||||
/**
|
||||
* ttf读取器的构造函数
|
||||
*
|
||||
* @param {Object} options 写入参数
|
||||
* @param {boolean} options.hinting 保留hinting信息
|
||||
* @param {boolean} options.compound2simple 复合字形转简单字形
|
||||
* @constructor
|
||||
*/
|
||||
function TTFReader() {
|
||||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
||||
_classCallCheck(this, TTFReader);
|
||||
options.subset = options.subset || []; // 子集
|
||||
options.hinting = options.hinting || false; // 默认不保留 hints 信息
|
||||
options.kerning = options.kerning || false; // 默认不保留 kerning 信息
|
||||
options.compound2simple = options.compound2simple || false; // 复合字形转简单字形
|
||||
options.subset = options.subset || [];
|
||||
options.hinting = options.hinting || false;
|
||||
options.kerning = options.kerning || false;
|
||||
options.compound2simple = options.compound2simple || false;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化读取
|
||||
*
|
||||
* @param {ArrayBuffer} buffer buffer对象
|
||||
* @return {Object} ttf对象
|
||||
*/
|
||||
return _createClass(TTFReader, [{
|
||||
key: "readBuffer",
|
||||
value: function readBuffer(buffer) {
|
||||
var reader = new _reader.default(buffer, 0, buffer.byteLength, false);
|
||||
var ttf = {};
|
||||
|
||||
// version
|
||||
ttf.version = reader.readFixed(0);
|
||||
/* 优化27: 头部直接 view 读取 */
|
||||
var view = reader.view;
|
||||
var vOffset = view.byteOffset;
|
||||
ttf.version = view.getInt32(vOffset, false) / 65536.0;
|
||||
if (ttf.version !== 0x1) {
|
||||
_error.default.raise(10101);
|
||||
}
|
||||
|
||||
// num tables
|
||||
ttf.numTables = reader.readUint16();
|
||||
ttf.numTables = view.getUint16(vOffset + 4, false);
|
||||
if (ttf.numTables <= 0 || ttf.numTables > 100) {
|
||||
_error.default.raise(10101);
|
||||
}
|
||||
ttf.searchRange = view.getUint16(vOffset + 6, false);
|
||||
ttf.entrySelector = view.getUint16(vOffset + 8, false);
|
||||
ttf.rangeShift = view.getUint16(vOffset + 10, false);
|
||||
reader.offset = 12;
|
||||
|
||||
// searchRange
|
||||
ttf.searchRange = reader.readUint16();
|
||||
|
||||
// entrySelector
|
||||
ttf.entrySelector = reader.readUint16();
|
||||
|
||||
// rangeShift
|
||||
ttf.rangeShift = reader.readUint16();
|
||||
ttf.tables = new _directory.default(reader.offset).read(reader, ttf);
|
||||
if (!ttf.tables.glyf || !ttf.tables.head || !ttf.tables.cmap || !ttf.tables.hmtx) {
|
||||
_error.default.raise(10204);
|
||||
}
|
||||
ttf.readOptions = this.options;
|
||||
|
||||
// 读取支持的表数据
|
||||
Object.keys(_support.default).forEach(function (tableName) {
|
||||
/* 优化8+37+62: 跳过不必要的表,缓存 TableClass 实例,for...in 替代 Object.keys */
|
||||
var hinting = this.options.hinting;
|
||||
var kerning = this.options.kerning;
|
||||
var supportTables = _support.default;
|
||||
var tableInstances = {};
|
||||
for (var tableName in supportTables) {
|
||||
if (ttf.tables[tableName]) {
|
||||
var offset = ttf.tables[tableName].offset;
|
||||
ttf[tableName] = new _support.default[tableName](offset).read(reader, ttf);
|
||||
/* 优化8: hinting=false 时跳过 fpgm/cvt/prep/gasp */
|
||||
if (!hinting && (tableName === 'fpgm' || tableName === 'cvt' || tableName === 'prep' || tableName === 'gasp')) {
|
||||
continue;
|
||||
}
|
||||
/* 优化8: hinting=false && kerning=false 时跳过 GPOS/kern/kerx */
|
||||
if (!hinting && !kerning && (tableName === 'GPOS' || tableName === 'kern' || tableName === 'kerx')) {
|
||||
continue;
|
||||
}
|
||||
var offset = ttf.tables[tableName].offset;
|
||||
/* 优化37: 缓存 TableClass 实例 */
|
||||
if (!tableInstances[tableName]) {
|
||||
tableInstances[tableName] = new supportTables[tableName](offset);
|
||||
} else {
|
||||
tableInstances[tableName].offset = offset;
|
||||
}
|
||||
ttf[tableName] = tableInstances[tableName].read(reader, ttf);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!ttf.glyf) {
|
||||
_error.default.raise(10201);
|
||||
}
|
||||
reader.dispose();
|
||||
return ttf;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联glyf相关的信息
|
||||
*
|
||||
* @param {Object} ttf ttf对象
|
||||
*/
|
||||
}, {
|
||||
key: "resolveGlyf",
|
||||
value: function resolveGlyf(ttf) {
|
||||
var codes = ttf.cmap;
|
||||
var glyf = ttf.glyf;
|
||||
var subsetMap = ttf.readOptions.subset ? ttf.subsetMap : null; // 当前ttf的子集列表
|
||||
var subsetMap = ttf.readOptions.subset ? ttf.subsetMap : null;
|
||||
|
||||
// unicode
|
||||
Object.keys(codes).forEach(function (c) {
|
||||
/* 优化13+24+62: unicode 遍历,subset 模式只遍历 subsetMap */
|
||||
for (var c in codes) {
|
||||
var i = codes[c];
|
||||
if (subsetMap && !subsetMap[i]) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
if (!glyf[i].unicode) {
|
||||
glyf[i].unicode = [];
|
||||
}
|
||||
glyf[i].unicode.push(+c);
|
||||
});
|
||||
|
||||
// advanceWidth
|
||||
ttf.hmtx.forEach(function (item, i) {
|
||||
if (subsetMap && !subsetMap[i]) {
|
||||
return;
|
||||
}
|
||||
glyf[i].advanceWidth = item.advanceWidth;
|
||||
glyf[i].leftSideBearing = item.leftSideBearing;
|
||||
});
|
||||
|
||||
// format = 2 的post表会携带glyf name信息
|
||||
/* 优化13: advanceWidth 遍历优化 */
|
||||
var hmtx = ttf.hmtx;
|
||||
if (subsetMap) {
|
||||
for (var idx in subsetMap) {
|
||||
var idxNum = +idx;
|
||||
glyf[idxNum].advanceWidth = hmtx[idxNum].advanceWidth;
|
||||
glyf[idxNum].leftSideBearing = hmtx[idxNum].leftSideBearing;
|
||||
}
|
||||
} else {
|
||||
for (var hi = 0, hl = hmtx.length; hi < hl; hi++) {
|
||||
glyf[hi].advanceWidth = hmtx[hi].advanceWidth;
|
||||
glyf[hi].leftSideBearing = hmtx[hi].leftSideBearing;
|
||||
}
|
||||
}
|
||||
|
||||
/* post 表 glyf name */
|
||||
if (ttf.post && 2 === ttf.post.format) {
|
||||
var nameIndex = ttf.post.nameIndex;
|
||||
var names = ttf.post.names;
|
||||
nameIndex.forEach(function (nameIndex, i) {
|
||||
if (subsetMap && !subsetMap[i]) {
|
||||
return;
|
||||
var pascalBytes = ttf.post._pascalStringBytes;
|
||||
var pascalOffsets = ttf.post._pascalStringOffsets;
|
||||
for (var ni = 0, nl = nameIndex.length; ni < nl; ni++) {
|
||||
if (subsetMap && !subsetMap[ni]) {
|
||||
continue;
|
||||
}
|
||||
var nIdx = nameIndex[ni];
|
||||
if (nIdx <= 257) {
|
||||
glyf[ni].name = _postName.default[nIdx];
|
||||
} else if (names) {
|
||||
glyf[ni].name = names[nIdx - 258] || '';
|
||||
} else if (pascalBytes && pascalOffsets) {
|
||||
var off = pascalOffsets[nIdx - 258];
|
||||
glyf[ni].name = off !== undefined ? _post.getPascalStringAt(pascalBytes, off) : '';
|
||||
}
|
||||
if (nameIndex <= 257) {
|
||||
glyf[i].name = _postName.default[nameIndex];
|
||||
} else {
|
||||
glyf[i].name = names[nameIndex - 258] || '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 设置了subsetMap之后需要选取subset中的字形
|
||||
// 并且对复合字形转换成简单字形
|
||||
/* 优化13+44+62: subset 模式下直接只遍历 subsetMap */
|
||||
if (subsetMap) {
|
||||
var subGlyf = [];
|
||||
Object.keys(subsetMap).forEach(function (i) {
|
||||
i = +i;
|
||||
if (glyf[i].compound) {
|
||||
(0, _compound2simpleglyf.default)(i, ttf, true);
|
||||
for (var si in subsetMap) {
|
||||
var siNum = +si;
|
||||
if (glyf[siNum].compound) {
|
||||
(0, _compound2simpleglyf.default)(siNum, ttf, true);
|
||||
}
|
||||
subGlyf.push(glyf[siNum]);
|
||||
}
|
||||
subGlyf.push(glyf[i]);
|
||||
});
|
||||
ttf.glyf = subGlyf;
|
||||
// 转换之后不存在复合字形了
|
||||
ttf.maxp.maxComponentElements = 0;
|
||||
ttf.maxp.maxComponentDepth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除非必须的表
|
||||
*
|
||||
* @param {Object} ttf ttf对象
|
||||
*/
|
||||
}, {
|
||||
key: "cleanTables",
|
||||
value: function cleanTables(ttf) {
|
||||
@ -177,17 +169,20 @@ var TTFReader = exports.default = /*#__PURE__*/function () {
|
||||
if (ttf.post) {
|
||||
delete ttf.post.nameIndex;
|
||||
delete ttf.post.names;
|
||||
delete ttf.post._pascalStringBytes;
|
||||
delete ttf.post._pascalStringOffsets;
|
||||
}
|
||||
delete ttf.subsetMap;
|
||||
|
||||
// 不携带hinting信息则删除hint相关表
|
||||
if (!this.options.hinting) {
|
||||
delete ttf.fpgm;
|
||||
delete ttf.cvt;
|
||||
delete ttf.prep;
|
||||
ttf.glyf.forEach(function (glyf) {
|
||||
delete glyf.instructions;
|
||||
});
|
||||
/* 优化55: forEach → for 循环 */
|
||||
var glyfs = ttf.glyf;
|
||||
for (var i = 0, l = glyfs.length; i < l; i++) {
|
||||
delete glyfs[i].instructions;
|
||||
}
|
||||
}
|
||||
if (!this.options.hinting && !this.options.kerning) {
|
||||
delete ttf.GPOS;
|
||||
@ -195,24 +190,17 @@ var TTFReader = exports.default = /*#__PURE__*/function () {
|
||||
delete ttf.kerx;
|
||||
}
|
||||
|
||||
// 复合字形转简单字形
|
||||
if (this.options.compound2simple && ttf.maxp.maxComponentElements) {
|
||||
ttf.glyf.forEach(function (glyf, index) {
|
||||
if (glyf.compound) {
|
||||
(0, _compound2simpleglyf.default)(index, ttf, true);
|
||||
var glyfs2 = ttf.glyf;
|
||||
for (var j = 0, jl = glyfs2.length; j < jl; j++) {
|
||||
if (glyfs2[j].compound) {
|
||||
(0, _compound2simpleglyf.default)(j, ttf, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
ttf.maxp.maxComponentElements = 0;
|
||||
ttf.maxp.maxComponentDepth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取解析后的ttf文档
|
||||
*
|
||||
* @param {ArrayBuffer} buffer buffer对象
|
||||
* @return {Object} ttf文档
|
||||
*/
|
||||
}, {
|
||||
key: "read",
|
||||
value: function read(buffer) {
|
||||
@ -221,10 +209,6 @@ var TTFReader = exports.default = /*#__PURE__*/function () {
|
||||
this.cleanTables(this.ttf);
|
||||
return this.ttf;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销
|
||||
*/
|
||||
}, {
|
||||
key: "dispose",
|
||||
value: function dispose() {
|
||||
|
||||
160
vendor/fonteditor-core/lib/ttf/ttfwriter.js
vendored
160
vendor/fonteditor-core/lib/ttf/ttfwriter.js
vendored
@ -10,48 +10,37 @@ var _support = _interopRequireDefault(require("./table/support"));
|
||||
var _checkSum = _interopRequireDefault(require("./util/checkSum"));
|
||||
var _error = _interopRequireDefault(require("./error"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
|
||||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
||||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
||||
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
||||
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /**
|
||||
/**
|
||||
* @file ttf写入器
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*/
|
||||
// 支持写的表, 注意表顺序
|
||||
var SUPPORT_TABLES = ['OS/2', 'cmap', 'glyf', 'head', 'hhea', 'hmtx', 'loca', 'maxp', 'name', 'post'];
|
||||
var TTFWriter = exports.default = /*#__PURE__*/function () {
|
||||
function TTFWriter() {
|
||||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
||||
_classCallCheck(this, TTFWriter);
|
||||
this.options = {
|
||||
writeZeroContoursGlyfData: options.writeZeroContoursGlyfData || false,
|
||||
// 不写入空 glyf 数据
|
||||
hinting: options.hinting || false,
|
||||
// 默认不保留hints信息
|
||||
kerning: options.kerning || false,
|
||||
// 默认不保留 kernings space 信息
|
||||
support: options.support // 自定义的导出表结构,可以自己修改某些表项目
|
||||
support: options.support
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理ttf结构,以便于写
|
||||
*
|
||||
* @param {ttfObject} ttf ttf数据结构
|
||||
* 优化4+46: resolveTTF 中 unicode 排序修正 + forEach → for 循环
|
||||
*/
|
||||
return _createClass(TTFWriter, [{
|
||||
key: "resolveTTF",
|
||||
value: function resolveTTF(ttf) {
|
||||
// 头部信息
|
||||
ttf.version = ttf.version || 0x1;
|
||||
ttf.numTables = ttf.writeOptions.tables.length;
|
||||
ttf.entrySelector = Math.floor(Math.log(ttf.numTables) / Math.LN2);
|
||||
ttf.searchRange = Math.pow(2, ttf.entrySelector) * 16;
|
||||
ttf.rangeShift = ttf.numTables * 16 - ttf.searchRange;
|
||||
|
||||
// 重置校验码
|
||||
ttf.head.checkSumAdjustment = 0;
|
||||
ttf.head.magickNumber = 0x5F0F3CF5;
|
||||
if (typeof ttf.head.created === 'string') {
|
||||
@ -60,62 +49,55 @@ var TTFWriter = exports.default = /*#__PURE__*/function () {
|
||||
if (typeof ttf.head.modified === 'string') {
|
||||
ttf.head.modified = /^\d+$/.test(ttf.head.modified) ? +ttf.head.modified : Date.parse(ttf.head.modified);
|
||||
}
|
||||
// 重置日期
|
||||
if (!ttf.head.created) {
|
||||
ttf.head.created = Date.now();
|
||||
}
|
||||
if (!ttf.head.modified) {
|
||||
ttf.head.modified = ttf.head.created;
|
||||
}
|
||||
var checkUnicodeRepeat = {}; // 检查是否有重复代码点
|
||||
var checkUnicodeRepeat = {};
|
||||
|
||||
// 将glyf的代码点按小到大排序
|
||||
ttf.glyf.forEach(function (glyf, index) {
|
||||
/* 优化4+46: 数字排序 + for 循环 */
|
||||
var glyfs = ttf.glyf;
|
||||
for (var index = 0, gl = glyfs.length; index < gl; index++) {
|
||||
var glyf = glyfs[index];
|
||||
if (glyf.unicode) {
|
||||
glyf.unicode = glyf.unicode.sort();
|
||||
glyf.unicode.forEach(function (u) {
|
||||
glyf.unicode.sort(function (a, b) { return a - b; });
|
||||
var unicode = glyf.unicode;
|
||||
for (var ui = 0, ul = unicode.length; ui < ul; ui++) {
|
||||
var u = unicode[ui];
|
||||
if (checkUnicodeRepeat[u]) {
|
||||
_error.default.raise({
|
||||
number: 10200,
|
||||
data: index
|
||||
}, index);
|
||||
_error.default.raise({ number: 10200, data: index }, index);
|
||||
} else {
|
||||
checkUnicodeRepeat[u] = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 写ttf文件
|
||||
*
|
||||
* @param {ttfObject} ttf ttf数据结构
|
||||
* @return {ArrayBuffer} 字节流
|
||||
*/
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "dump",
|
||||
value: function dump(ttf) {
|
||||
// 用来做写入缓存的对象,用完后删掉
|
||||
ttf.support = Object.assign({}, this.options.support);
|
||||
|
||||
// head + directory
|
||||
var ttfSize = 12 + ttf.numTables * 16;
|
||||
var ttfHeadOffset = 0; // 记录head的偏移
|
||||
var ttfHeadOffset = 0;
|
||||
|
||||
// 构造tables
|
||||
/* 优化35+56: 缓存 TableClass 实例,forEach → for 循环 */
|
||||
ttf.support.tables = [];
|
||||
ttf.writeOptions.tables.forEach(function (tableName) {
|
||||
var writeTables = ttf.writeOptions.tables;
|
||||
var supportTables = _support.default;
|
||||
var tableInstances = {};
|
||||
for (var ti = 0, tl = writeTables.length; ti < tl; ti++) {
|
||||
var tableName = writeTables[ti];
|
||||
var offset = ttfSize;
|
||||
var TableClass = _support.default[tableName];
|
||||
var tableSize = new TableClass().size(ttf); // 原始的表大小
|
||||
var size = tableSize; // 对齐后的表大小
|
||||
|
||||
if (!tableInstances[tableName]) {
|
||||
tableInstances[tableName] = new supportTables[tableName]();
|
||||
}
|
||||
var tableSize = tableInstances[tableName].size(ttf);
|
||||
var size = tableSize;
|
||||
if (tableName === 'head') {
|
||||
ttfHeadOffset = offset;
|
||||
}
|
||||
|
||||
// 4字节对齐
|
||||
if (size % 4) {
|
||||
size += 4 - size % 4;
|
||||
}
|
||||
@ -127,40 +109,44 @@ var TTFWriter = exports.default = /*#__PURE__*/function () {
|
||||
size: size
|
||||
});
|
||||
ttfSize += size;
|
||||
});
|
||||
}
|
||||
var writer = new _writer.default(new ArrayBuffer(ttfSize));
|
||||
|
||||
// 写头部
|
||||
writer.writeFixed(ttf.version);
|
||||
writer.writeUint16(ttf.numTables);
|
||||
writer.writeUint16(ttf.searchRange);
|
||||
writer.writeUint16(ttf.entrySelector);
|
||||
writer.writeUint16(ttf.rangeShift);
|
||||
/* 优化36: 头部直接 view 写入 */
|
||||
var wView = writer.view;
|
||||
var pos = writer.offset;
|
||||
wView.setInt32(pos, Math.round(ttf.version * 65536), false); pos += 4;
|
||||
wView.setUint16(pos, ttf.numTables, false); pos += 2;
|
||||
wView.setUint16(pos, ttf.searchRange, false); pos += 2;
|
||||
wView.setUint16(pos, ttf.entrySelector, false); pos += 2;
|
||||
wView.setUint16(pos, ttf.rangeShift, false); pos += 2;
|
||||
writer.offset = pos;
|
||||
|
||||
// 写表偏移
|
||||
new _directory.default().write(writer, ttf);
|
||||
|
||||
// 写支持的表数据
|
||||
ttf.support.tables.forEach(function (table) {
|
||||
/* 优化56: forEach → for 循环 */
|
||||
var supportTableList = ttf.support.tables;
|
||||
for (var si = 0, sl = supportTableList.length; si < sl; si++) {
|
||||
var table = supportTableList[si];
|
||||
var tableStart = writer.offset;
|
||||
var TableClass = _support.default[table.name];
|
||||
new TableClass().write(writer, ttf);
|
||||
var tName = table.name;
|
||||
if (!tableInstances[tName]) {
|
||||
tableInstances[tName] = new supportTables[tName]();
|
||||
}
|
||||
tableInstances[tName].write(writer, ttf);
|
||||
if (table.length % 4) {
|
||||
// 对齐字节
|
||||
writer.writeEmpty(4 - table.length % 4);
|
||||
}
|
||||
|
||||
// 计算校验和
|
||||
table.checkSum = (0, _checkSum.default)(writer.getBuffer(), tableStart, table.size);
|
||||
});
|
||||
}
|
||||
|
||||
// 重新写入每个表校验和
|
||||
ttf.support.tables.forEach(function (table, index) {
|
||||
var offset = 12 + index * 16 + 4;
|
||||
writer.writeUint32(table.checkSum, offset);
|
||||
});
|
||||
/* 重新写入校验和 */
|
||||
for (var ci = 0, cl = supportTableList.length; ci < cl; ci++) {
|
||||
var offset2 = 12 + ci * 16 + 4;
|
||||
writer.writeUint32(supportTableList[ci].checkSum, offset2);
|
||||
}
|
||||
|
||||
// 写入总校验和
|
||||
/* 写入总校验和 */
|
||||
var ttfCheckSum = (0xB1B0AFBA - (0, _checkSum.default)(writer.getBuffer()) + 0x100000000) % 0x100000000;
|
||||
writer.writeUint32(ttfCheckSum, ttfHeadOffset + 8);
|
||||
delete ttf.writeOptions;
|
||||
@ -169,12 +155,6 @@ var TTFWriter = exports.default = /*#__PURE__*/function () {
|
||||
writer.dispose();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对ttf的表进行评估,标记需要处理的表
|
||||
*
|
||||
* @param {Object} ttf ttf对象
|
||||
*/
|
||||
}, {
|
||||
key: "prepareDump",
|
||||
value: function prepareDump(ttf) {
|
||||
@ -186,34 +166,28 @@ var TTFWriter = exports.default = /*#__PURE__*/function () {
|
||||
}
|
||||
var tables = SUPPORT_TABLES.slice(0);
|
||||
ttf.writeOptions = {};
|
||||
// hinting tables direct copy
|
||||
/* 优化56: forEach → for 循环 */
|
||||
if (this.options.hinting) {
|
||||
['cvt', 'fpgm', 'prep', 'gasp', 'GPOS', 'kern', 'kerx'].forEach(function (table) {
|
||||
if (ttf[table]) {
|
||||
tables.push(table);
|
||||
var hintTables = ['cvt', 'fpgm', 'prep', 'gasp', 'GPOS', 'kern', 'kerx'];
|
||||
for (var i = 0; i < hintTables.length; i++) {
|
||||
if (ttf[hintTables[i]]) {
|
||||
tables.push(hintTables[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// copy kerning space table
|
||||
if (this.options.kerning) {
|
||||
['GPOS', 'kern', 'kerx'].forEach(function (table) {
|
||||
if (ttf[table]) {
|
||||
tables.push(table);
|
||||
var kernTables = ['GPOS', 'kern', 'kerx'];
|
||||
for (var j = 0; j < kernTables.length; j++) {
|
||||
if (ttf[kernTables[j]]) {
|
||||
tables.push(kernTables[j]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
ttf.writeOptions.writeZeroContoursGlyfData = !!this.options.writeZeroContoursGlyfData;
|
||||
ttf.writeOptions.hinting = !!this.options.hinting;
|
||||
ttf.writeOptions.kerning = !!this.options.kerning;
|
||||
ttf.writeOptions.tables = tables.sort();
|
||||
}
|
||||
|
||||
/**
|
||||
* 写一个ttf字体结构
|
||||
*
|
||||
* @param {Object} ttf ttf数据结构
|
||||
* @return {ArrayBuffer} 缓冲数组
|
||||
*/
|
||||
}, {
|
||||
key: "write",
|
||||
value: function write(ttf) {
|
||||
@ -222,10 +196,6 @@ var TTFWriter = exports.default = /*#__PURE__*/function () {
|
||||
var buffer = this.dump(ttf);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销
|
||||
*/
|
||||
}, {
|
||||
key: "dispose",
|
||||
value: function dispose() {
|
||||
|
||||
50
vendor/fonteditor-core/lib/ttf/util/checkSum.js
vendored
50
vendor/fonteditor-core/lib/ttf/util/checkSum.js
vendored
@ -9,54 +9,58 @@ exports.default = checkSum;
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*/
|
||||
|
||||
function checkSumArrayBuffer(buffer) {
|
||||
var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
||||
var length = arguments.length > 2 ? arguments[2] : undefined;
|
||||
/**
|
||||
* 优化18+69: 位运算避免溢出 + Uint8Array 替代 DataView
|
||||
*/
|
||||
function checkSumArrayBuffer(buffer, offset, length) {
|
||||
if (offset === undefined) offset = 0;
|
||||
length = length == null ? buffer.byteLength : length;
|
||||
if (offset + length > buffer.byteLength) {
|
||||
throw new Error('check sum out of bound');
|
||||
}
|
||||
var nLongs = Math.floor(length / 4);
|
||||
var view = new DataView(buffer, offset, length);
|
||||
var bytes = new Uint8Array(buffer, offset, length);
|
||||
var nLongs = length >> 2;
|
||||
var sum = 0;
|
||||
var i = 0;
|
||||
while (i < nLongs) {
|
||||
sum += view.getUint32(4 * i++, false);
|
||||
var j = i << 2;
|
||||
sum = (sum + (bytes[j] << 24 | bytes[j + 1] << 16 | bytes[j + 2] << 8 | bytes[j + 3])) | 0;
|
||||
i++;
|
||||
}
|
||||
var leftBytes = length - nLongs * 4;
|
||||
if (leftBytes) {
|
||||
offset = nLongs * 4;
|
||||
while (leftBytes > 0) {
|
||||
sum += view.getUint8(offset, false) << leftBytes * 8;
|
||||
offset++;
|
||||
leftBytes--;
|
||||
var off = nLongs << 2;
|
||||
var shift = leftBytes * 8;
|
||||
var val = 0;
|
||||
for (var k = 0; k < leftBytes; k++) {
|
||||
val = (val | bytes[off + k] << (leftBytes - 1 - k) * 8) >>> 0;
|
||||
}
|
||||
sum = (sum + val) | 0;
|
||||
}
|
||||
return sum % 0x100000000;
|
||||
return sum >>> 0;
|
||||
}
|
||||
function checkSumArray(buffer) {
|
||||
var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
||||
var length = arguments.length > 2 ? arguments[2] : undefined;
|
||||
|
||||
function checkSumArray(buffer, offset, length) {
|
||||
if (offset === undefined) offset = 0;
|
||||
length = length || buffer.length;
|
||||
if (offset + length > buffer.length) {
|
||||
throw new Error('check sum out of bound');
|
||||
}
|
||||
var nLongs = Math.floor(length / 4);
|
||||
var nLongs = length >> 2;
|
||||
var sum = 0;
|
||||
var i = 0;
|
||||
while (i < nLongs) {
|
||||
sum += (buffer[i++] << 24) + (buffer[i++] << 16) + (buffer[i++] << 8) + buffer[i++];
|
||||
sum = (sum + ((buffer[i] << 24 | buffer[i + 1] << 16 | buffer[i + 2] << 8 | buffer[i + 3]) >>> 0)) | 0;
|
||||
i += 4;
|
||||
}
|
||||
var leftBytes = length - nLongs * 4;
|
||||
if (leftBytes) {
|
||||
offset = nLongs * 4;
|
||||
while (leftBytes > 0) {
|
||||
sum += buffer[offset] << leftBytes * 8;
|
||||
offset++;
|
||||
leftBytes--;
|
||||
var off = nLongs << 2;
|
||||
for (var k = 0; k < leftBytes; k++) {
|
||||
sum = (sum + (buffer[off + k] << (leftBytes - 1 - k) * 8)) | 0;
|
||||
}
|
||||
}
|
||||
return sum % 0x100000000;
|
||||
return sum >>> 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
14
vendor/fonteditor-core/lib/ttf/util/string.js
vendored
14
vendor/fonteditor-core/lib/ttf/util/string.js
vendored
@ -181,16 +181,22 @@ var _default = exports.default = {
|
||||
* @return {Array.<string>} 读取后的字符串数组
|
||||
*/
|
||||
getPascalString: function getPascalString(byteArray) {
|
||||
/* 优化63: Array.push + fromCharCode.apply 替代逐字拼接 */
|
||||
var strArray = [];
|
||||
var i = 0;
|
||||
var l = byteArray.length;
|
||||
while (i < l) {
|
||||
var strLength = byteArray[i++];
|
||||
var str = '';
|
||||
while (strLength-- > 0 && i < l) {
|
||||
str += String.fromCharCode(byteArray[i++]);
|
||||
if (strLength === 0) {
|
||||
strArray.push('');
|
||||
continue;
|
||||
}
|
||||
// 这里需要将unicode转换成js编码
|
||||
var chars = new Array(strLength);
|
||||
var end = Math.min(i + strLength, l);
|
||||
for (var j = 0; i < end; j++, i++) {
|
||||
chars[j] = byteArray[i];
|
||||
}
|
||||
var str = String.fromCharCode.apply(null, chars);
|
||||
str = stringify(str);
|
||||
strArray.push(str);
|
||||
}
|
||||
|
||||
60
vendor/fonteditor-core/lib/ttf/writer.js
vendored
60
vendor/fonteditor-core/lib/ttf/writer.js
vendored
@ -65,23 +65,28 @@ var Writer = /*#__PURE__*/function () {
|
||||
return _createClass(Writer, [{
|
||||
key: "write",
|
||||
value: function write(type, value, offset, littleEndian) {
|
||||
// 使用当前位移
|
||||
if (undefined === offset) {
|
||||
offset = this.offset;
|
||||
}
|
||||
|
||||
// 使用小尾
|
||||
if (undefined === littleEndian) {
|
||||
littleEndian = this.littleEndian;
|
||||
}
|
||||
|
||||
// 扩展方法
|
||||
if (undefined === dataType[type]) {
|
||||
return this['write' + type](value, offset, littleEndian);
|
||||
}
|
||||
var size = dataType[type];
|
||||
this.offset = offset + size;
|
||||
this.view['set' + type](offset, value, littleEndian);
|
||||
/* 优化20: switch 直接分发,避免动态属性查找 */
|
||||
switch (type) {
|
||||
case 'Int8': this.view.setInt8(offset, value, littleEndian); break;
|
||||
case 'Uint8': this.view.setUint8(offset, value, littleEndian); break;
|
||||
case 'Int16': this.view.setInt16(offset, value, littleEndian); break;
|
||||
case 'Uint16': this.view.setUint16(offset, value, littleEndian); break;
|
||||
case 'Int32': this.view.setInt32(offset, value, littleEndian); break;
|
||||
case 'Uint32': this.view.setUint32(offset, value, littleEndian); break;
|
||||
case 'Float32': this.view.setFloat32(offset, value, littleEndian); break;
|
||||
case 'Float64': this.view.setFloat64(offset, value, littleEndian); break;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -97,7 +102,6 @@ var Writer = /*#__PURE__*/function () {
|
||||
key: "writeBytes",
|
||||
value: function writeBytes(value, length, offset) {
|
||||
length = length || value.byteLength || value.length;
|
||||
var i;
|
||||
if (!length) {
|
||||
return this;
|
||||
}
|
||||
@ -107,16 +111,11 @@ var Writer = /*#__PURE__*/function () {
|
||||
if (length < 0 || offset + length > this.length) {
|
||||
_error.default.raise(10002, this.length, offset + length);
|
||||
}
|
||||
var littleEndian = this.littleEndian;
|
||||
/* 优化5: Uint8Array.set 批量写入,替代逐字节循环 */
|
||||
if (value instanceof ArrayBuffer) {
|
||||
var view = new DataView(value, 0, length);
|
||||
for (i = 0; i < length; ++i) {
|
||||
this.view.setUint8(offset + i, view.getUint8(i, littleEndian), littleEndian);
|
||||
}
|
||||
new Uint8Array(this.view.buffer, this.view.byteOffset + offset, length).set(new Uint8Array(value, 0, length));
|
||||
} else {
|
||||
for (i = 0; i < length; ++i) {
|
||||
this.view.setUint8(offset + i, value[i], littleEndian);
|
||||
}
|
||||
new Uint8Array(this.view.buffer, this.view.byteOffset + offset, length).set(value instanceof Uint8Array ? value : new Uint8Array(value), 0);
|
||||
}
|
||||
this.offset = offset + length;
|
||||
return this;
|
||||
@ -138,10 +137,8 @@ var Writer = /*#__PURE__*/function () {
|
||||
if (undefined === offset) {
|
||||
offset = this.offset;
|
||||
}
|
||||
var littleEndian = this.littleEndian;
|
||||
for (var i = 0; i < length; ++i) {
|
||||
this.view.setUint8(offset + i, 0, littleEndian);
|
||||
}
|
||||
/* 优化5: fill(0) 批量填充,替代逐字节循环 */
|
||||
new Uint8Array(this.view.buffer, this.view.byteOffset + offset, length).fill(0);
|
||||
this.offset = offset + length;
|
||||
return this;
|
||||
}
|
||||
@ -164,21 +161,21 @@ var Writer = /*#__PURE__*/function () {
|
||||
if (undefined === offset) {
|
||||
offset = this.offset;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-control-regex
|
||||
length = length || str.replace(/[^\x00-\xff]/g, '11').length;
|
||||
if (length < 0 || offset + length > this.length) {
|
||||
_error.default.raise(10002, this.length, offset + length);
|
||||
}
|
||||
this.seek(offset);
|
||||
/* 优化28: 直接 view 写入,替代逐字节 writeUint8/writeUint16 */
|
||||
var pos = offset;
|
||||
for (var i = 0, l = str.length, charCode; i < l; ++i) {
|
||||
charCode = str.charCodeAt(i) || 0;
|
||||
if (charCode > 127) {
|
||||
// unicode编码可能会超出2字节,
|
||||
// 写入与编码有关系,此处不做处理
|
||||
this.writeUint16(charCode);
|
||||
this.view.setUint16(pos, charCode, this.littleEndian);
|
||||
pos += 2;
|
||||
} else {
|
||||
this.writeUint8(charCode);
|
||||
this.view.setUint8(pos, charCode);
|
||||
pos += 1;
|
||||
}
|
||||
}
|
||||
this.offset = offset + length;
|
||||
@ -299,8 +296,13 @@ var Writer = /*#__PURE__*/function () {
|
||||
delete this.view;
|
||||
}
|
||||
}]);
|
||||
}(); // 直接支持的数据类型
|
||||
Object.keys(dataType).forEach(function (type) {
|
||||
Writer.prototype['write' + type] = (0, _lang.curry)(Writer.prototype.write, type);
|
||||
});
|
||||
}(); // 优化19: 直接绑定方法,避免 curry 闭包开销
|
||||
Writer.prototype.writeInt8 = function(value, offset) { if (offset === undefined) offset = this.offset; this.offset = offset + 1; this.view.setInt8(offset, value, this.littleEndian); return this; };
|
||||
Writer.prototype.writeUint8 = function(value, offset) { if (offset === undefined) offset = this.offset; this.offset = offset + 1; this.view.setUint8(offset, value, this.littleEndian); return this; };
|
||||
Writer.prototype.writeInt16 = function(value, offset) { if (offset === undefined) offset = this.offset; this.offset = offset + 2; this.view.setInt16(offset, value, this.littleEndian); return this; };
|
||||
Writer.prototype.writeUint16 = function(value, offset) { if (offset === undefined) offset = this.offset; this.offset = offset + 2; this.view.setUint16(offset, value, this.littleEndian); return this; };
|
||||
Writer.prototype.writeInt32 = function(value, offset) { if (offset === undefined) offset = this.offset; this.offset = offset + 4; this.view.setInt32(offset, value, this.littleEndian); return this; };
|
||||
Writer.prototype.writeUint32 = function(value, offset) { if (offset === undefined) offset = this.offset; this.offset = offset + 4; this.view.setUint32(offset, value, this.littleEndian); return this; };
|
||||
Writer.prototype.writeFloat32 = function(value, offset) { if (offset === undefined) offset = this.offset; this.offset = offset + 4; this.view.setFloat32(offset, value, this.littleEndian); return this; };
|
||||
Writer.prototype.writeFloat64 = function(value, offset) { if (offset === undefined) offset = this.offset; this.offset = offset + 8; this.view.setFloat64(offset, value, this.littleEndian); return this; };
|
||||
var _default = exports.default = Writer;
|
||||
Loading…
x
Reference in New Issue
Block a user