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