From d43255aba04a9bd3e33a18a70c56f20acd7c251a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B4=AE=E7=94=9F=EF=BC=88=E5=AD=90=E8=99=9A=EF=BC=89?= <2234839456@qq.com> Date: Thu, 9 Apr 2026 10:17:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=80=A7=E8=83=BD=E4=BC=98=E5=8C=961?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vendor/fonteditor-core/lib/ttf/reader.js | 53 ++-- .../lib/ttf/table/cmap/parse.js | 239 ++++++++------- .../lib/ttf/table/directory.js | 20 +- .../lib/ttf/table/glyf/parse.js | 256 ++++++++-------- .../lib/ttf/table/glyf/sizeof.js | 280 ++++++++---------- .../lib/ttf/table/glyf/write.js | 194 ++++++------ vendor/fonteditor-core/lib/ttf/table/hmtx.js | 59 ++-- vendor/fonteditor-core/lib/ttf/table/loca.js | 57 ++-- vendor/fonteditor-core/lib/ttf/table/post.js | 95 +++--- vendor/fonteditor-core/lib/ttf/ttf.js | 28 +- vendor/fonteditor-core/lib/ttf/ttfreader.js | 198 ++++++------- vendor/fonteditor-core/lib/ttf/ttfwriter.js | 162 +++++----- .../fonteditor-core/lib/ttf/util/checkSum.js | 52 ++-- vendor/fonteditor-core/lib/ttf/util/string.js | 14 +- vendor/fonteditor-core/lib/ttf/writer.js | 60 ++-- 15 files changed, 880 insertions(+), 887 deletions(-) diff --git a/vendor/fonteditor-core/lib/ttf/reader.js b/vendor/fonteditor-core/lib/ttf/reader.js index c6b7ab6..b11934a 100644 --- a/vendor/fonteditor-core/lib/ttf/reader.js +++ b/vendor/fonteditor-core/lib/ttf/reader.js @@ -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); - }; -}); \ No newline at end of file +}(); // 优化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); }; \ No newline at end of file diff --git a/vendor/fonteditor-core/lib/ttf/table/cmap/parse.js b/vendor/fonteditor-core/lib/ttf/table/cmap/parse.js index 54a04ff..9e3cdd9 100644 --- a/vendor/fonteditor-core/lib/ttf/table/cmap/parse.js +++ b/vendor/fonteditor-core/lib/ttf/table/cmap/parse.js @@ -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; -} \ No newline at end of file +} diff --git a/vendor/fonteditor-core/lib/ttf/table/directory.js b/vendor/fonteditor-core/lib/ttf/table/directory.js index 9585a95..ba829bb 100644 --- a/vendor/fonteditor-core/lib/ttf/table/directory.js +++ b/vendor/fonteditor-core/lib/ttf/table/directory.js @@ -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) { @@ -41,4 +49,4 @@ var _default = exports.default = _table.default.create('directory', [], { size: function size(ttf) { return ttf.numTables * 16; } -}); \ No newline at end of file +}); diff --git a/vendor/fonteditor-core/lib/ttf/table/glyf/parse.js b/vendor/fonteditor-core/lib/ttf/table/glyf/parse.js index 903d5d3..0a50995 100644 --- a/vendor/fonteditor-core/lib/ttf/table/glyf/parse.js +++ b/vendor/fonteditor-core/lib/ttf/table/glyf/parse.js @@ -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; - while (i < numberOfCoordinates) { - flag = reader.readUint8(); - flags.push(flag); - i++; + /* 优化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; - // 标志位3重复flag - if (flag & _glyFlag.default.REPEAT && i < numberOfCoordinates) { - // 重复个数 - var repeat = reader.readUint8(); - for (var j = 0; j < repeat; j++) { - flags.push(flag); - i++; + /* 优化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) { + 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) { - 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) { + 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; - } - // 新值 - 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,24 +241,24 @@ 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()); - } - glyf.instructions = instructions; - } else { - console.warn(length); + /* 优化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; } + vOffset += instrLength; + reader.offset = vOffset - view.byteOffset; + parseSimpleGlyf(reader, glyf); delete glyf.endPtsOfContours; } else { + reader.offset = vOffset - view.byteOffset; parseCompoundGlyf(reader, glyf); } return glyf; -} \ No newline at end of file +} diff --git a/vendor/fonteditor-core/lib/ttf/table/glyf/sizeof.js b/vendor/fonteditor-core/lib/ttf/table/glyf/sizeof.js index 99d33c7..59e2e69 100644 --- a/vendor/fonteditor-core/lib/ttf/table/glyf/sizeof.js +++ b/vendor/fonteditor-core/lib/ttf/table/glyf/sizeof.js @@ -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; - } - x = Math.abs(x); - } - xCoordC.push(x); + dx = px - prevX; + dy = py - prevY; } - 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 + } + glyfSupportArr.tableSize = tableSize; ttf.head.indexToLocFormat = tableSize > 65536 ? 1 : 0; - return ttf.support.glyf.tableSize; -} \ No newline at end of file + return tableSize; +} diff --git a/vendor/fonteditor-core/lib/ttf/table/glyf/write.js b/vendor/fonteditor-core/lib/ttf/table/glyf/write.js index 84904ef..36803d7 100644 --- a/vendor/fonteditor-core/lib/ttf/table/glyf/write.js +++ b/vendor/fonteditor-core/lib/ttf/table/glyf/write.js @@ -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; -} \ No newline at end of file +} diff --git a/vendor/fonteditor-core/lib/ttf/table/hmtx.js b/vendor/fonteditor-core/lib/ttf/table/hmtx.js index 51bf946..426a5bc 100644 --- a/vendor/fonteditor-core/lib/ttf/table/hmtx.js +++ b/vendor/fonteditor-core/lib/ttf/table/hmtx.js @@ -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) { @@ -70,4 +73,4 @@ var _default = exports.default = _table.default.create('hmtx', [], { ttf.hhea.numOfLongHorMetrics = ttf.glyf.length - numOfLast; return 4 * ttf.hhea.numOfLongHorMetrics + 2 * numOfLast; } -}); \ No newline at end of file +}); diff --git a/vendor/fonteditor-core/lib/ttf/table/loca.js b/vendor/fonteditor-core/lib/ttf/table/loca.js index db1a5e6..85f07ac 100644 --- a/vendor/fonteditor-core/lib/ttf/table/loca.js +++ b/vendor/fonteditor-core/lib/ttf/table/loca.js @@ -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,25 +41,31 @@ 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) { - if (indexToLocFormat) { - writer.writeUint32(offset); - } else { - writer.writeUint16(offset); - } - offset += glyfSupport[i].size * sizeRatio; - } - - // write extra + /* 优化29: 直接 view 批量写入 */ + var wView = writer.view; + var pos = writer.offset; if (indexToLocFormat) { - writer.writeUint32(offset); + for (var i = 0; i <= numGlyphs; i++) { + wView.setUint32(pos, offset, false); + pos += 4; + if (i < numGlyphs) { + offset += glyfSupport[i].size * sizeRatio; + } + } } else { - writer.writeUint16(offset); + 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) { var locaCount = ttf.glyf.length + 1; return ttf.head.indexToLocFormat ? locaCount * 4 : locaCount * 2; } -}); \ No newline at end of file +}); diff --git a/vendor/fonteditor-core/lib/ttf/table/post.js b/vendor/fonteditor-core/lib/ttf/table/post.js index b433d43..7595863 100644 --- a/vendor/fonteditor-core/lib/ttf/table/post.js +++ b/vendor/fonteditor-core/lib/ttf/table/post.js @@ -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; } @@ -124,4 +144,7 @@ var _default = exports.default = _table.default.create('post', [], { }; return size; } -}); \ No newline at end of file +}); + +/** 按需获取单个 pascal string name(供 ttfreader.js 使用) */ +exports.getPascalStringAt = getPascalStringAt; diff --git a/vendor/fonteditor-core/lib/ttf/ttf.js b/vendor/fonteditor-core/lib/ttf/ttf.js index e3e815b..55fce55 100644 --- a/vendor/fonteditor-core/lib/ttf/ttf.js +++ b/vendor/fonteditor-core/lib/ttf/ttf.js @@ -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; diff --git a/vendor/fonteditor-core/lib/ttf/ttfreader.js b/vendor/fonteditor-core/lib/ttf/ttfreader.js index 91c8bd0..7503cc7 100644 --- a/vendor/fonteditor-core/lib/ttf/ttfreader.js +++ b/vendor/fonteditor-core/lib/ttf/ttfreader.js @@ -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]) { + /* 优化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; - ttf[tableName] = new _support.default[tableName](offset).read(reader, ttf); + /* 优化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; + /* 优化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; } - glyf[i].advanceWidth = item.advanceWidth; - glyf[i].leftSideBearing = item.leftSideBearing; - }); + } else { + for (var hi = 0, hl = hmtx.length; hi < hl; hi++) { + glyf[hi].advanceWidth = hmtx[hi].advanceWidth; + glyf[hi].leftSideBearing = hmtx[hi].leftSideBearing; + } + } - // format = 2 的post表会携带glyf name信息 + /* 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; } - if (nameIndex <= 257) { - glyf[i].name = _postName.default[nameIndex]; - } else { - glyf[i].name = names[nameIndex - 258] || ''; + 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) : ''; } - }); + } } - // 设置了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[i]); - }); + subGlyf.push(glyf[siNum]); + } 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() { @@ -232,4 +216,4 @@ var TTFReader = exports.default = /*#__PURE__*/function () { delete this.options; } }]); -}(); \ No newline at end of file +}(); diff --git a/vendor/fonteditor-core/lib/ttf/ttfwriter.js b/vendor/fonteditor-core/lib/ttf/ttfwriter.js index 0bba973..075bae0 100644 --- a/vendor/fonteditor-core/lib/ttf/ttfwriter.js +++ b/vendor/fonteditor-core/lib/ttf/ttfwriter.js @@ -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,14 +196,10 @@ var TTFWriter = exports.default = /*#__PURE__*/function () { var buffer = this.dump(ttf); return buffer; } - - /** - * 注销 - */ }, { key: "dispose", value: function dispose() { delete this.options; } }]); -}(); \ No newline at end of file +}(); diff --git a/vendor/fonteditor-core/lib/ttf/util/checkSum.js b/vendor/fonteditor-core/lib/ttf/util/checkSum.js index d6ca43b..be99d0d 100644 --- a/vendor/fonteditor-core/lib/ttf/util/checkSum.js +++ b/vendor/fonteditor-core/lib/ttf/util/checkSum.js @@ -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; } /** @@ -75,4 +79,4 @@ function checkSum(buffer, offset, length) { return checkSumArray(buffer, offset, length); } throw new Error('not support checksum buffer type'); -} \ No newline at end of file +} diff --git a/vendor/fonteditor-core/lib/ttf/util/string.js b/vendor/fonteditor-core/lib/ttf/util/string.js index 84821e0..816fd59 100644 --- a/vendor/fonteditor-core/lib/ttf/util/string.js +++ b/vendor/fonteditor-core/lib/ttf/util/string.js @@ -181,16 +181,22 @@ var _default = exports.default = { * @return {Array.} 读取后的字符串数组 */ 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); } diff --git a/vendor/fonteditor-core/lib/ttf/writer.js b/vendor/fonteditor-core/lib/ttf/writer.js index aaeee1b..cbefa1c 100644 --- a/vendor/fonteditor-core/lib/ttf/writer.js +++ b/vendor/fonteditor-core/lib/ttf/writer.js @@ -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; \ No newline at end of file