mirror of
https://github.com/2234839/web-font.git
synced 2026-07-03 14:38:22 +08:00
性能优化
This commit is contained in:
parent
97f4d72e6a
commit
4990a0f61d
@ -9,6 +9,8 @@ exports.default = bezierCubic2Q2;
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*
|
||||
* 改进:递归分割三次贝塞尔直到可精确近似,提高 SSIM
|
||||
* 优化:返回扁平数组 [control1, endpoint1, control2, endpoint2, ...]
|
||||
* 减少 3-element 包装数组的分配
|
||||
*/
|
||||
|
||||
var MAX_DEPTH = 4;
|
||||
@ -42,24 +44,30 @@ function cubicToQuads(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, depth, endpoints,
|
||||
cubicToQuads(midx, midy, m123x, m123y, m23x, m23y, p2x, p2y, depth + 1, endpoints, controls);
|
||||
}
|
||||
|
||||
/**
|
||||
* 三次贝塞尔转二次贝塞尔
|
||||
* 返回扁平数组: [control1, endpoint1, control2, endpoint2, ...]
|
||||
* 每对 (control, endpoint) 代表一个二次贝塞尔段
|
||||
*/
|
||||
function bezierCubic2Q2(p1, c1, c2, p2) {
|
||||
if (p1.x === c1.x && p1.y === c1.y && c2.x === p2.x && c2.y === p2.y) {
|
||||
return [[p1, {
|
||||
return [{
|
||||
x: (p1.x + p2.x) * 0.5,
|
||||
y: (p1.y + p2.y) * 0.5
|
||||
}, p2]];
|
||||
}, p2];
|
||||
}
|
||||
|
||||
var endpoints = [];
|
||||
var controls = [];
|
||||
cubicToQuads(p1.x, p1.y, c1.x, c1.y, c2.x, c2.y, p2.x, p2.y, 0, endpoints, controls);
|
||||
|
||||
var segments = [];
|
||||
var prev = p1;
|
||||
var result = new Array(controls.length * 2);
|
||||
var ri = 0;
|
||||
for (var i = 0, l = controls.length; i < l; i++) {
|
||||
var next = i < endpoints.length ? endpoints[i] : p2;
|
||||
segments.push([prev, controls[i], next]);
|
||||
prev = next;
|
||||
next.onCurve = true;
|
||||
result[ri++] = controls[i];
|
||||
result[ri++] = next;
|
||||
}
|
||||
return segments;
|
||||
return result;
|
||||
}
|
||||
|
||||
41
vendor/fonteditor-core/lib/ttf/otf2ttfobject.js
vendored
41
vendor/fonteditor-core/lib/ttf/otf2ttfobject.js
vendored
@ -13,31 +13,6 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*/
|
||||
|
||||
/**
|
||||
* 直接遍历 contours 计算包围盒,避免合并数组
|
||||
*/
|
||||
function computeContoursBox(contours) {
|
||||
var left, right, top, bottom;
|
||||
var found = false;
|
||||
for (var ci = 0, cl = contours.length; ci < cl; ci++) {
|
||||
var contour = contours[ci];
|
||||
for (var pi = 0, pl = contour.length; pi < pl; pi++) {
|
||||
var p = contour[pi];
|
||||
if (!found) {
|
||||
left = right = p.x;
|
||||
top = bottom = p.y;
|
||||
found = true;
|
||||
} else {
|
||||
if (p.x < left) left = p.x;
|
||||
else if (p.x > right) right = p.x;
|
||||
if (p.y < top) top = p.y;
|
||||
else if (p.y > bottom) bottom = p.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found ? { x: left, y: top, width: right - left, height: bottom - top } : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* otf格式转ttf格式对象
|
||||
*
|
||||
@ -57,17 +32,17 @@ function otf2ttfobject(otfBuffer, options) {
|
||||
_error.default.raise(10111);
|
||||
}
|
||||
|
||||
// 转换otf轮廓
|
||||
// 转换otf轮廓,同时获取包围盒
|
||||
var glyf = otfObject.glyf;
|
||||
for (var i = 0, l = glyf.length; i < l; i++) {
|
||||
var g = glyf[i];
|
||||
g.contours = (0, _otfContours2ttfContours.default)(g.contours);
|
||||
var box = computeContoursBox(g.contours);
|
||||
if (box) {
|
||||
g.xMin = box.x;
|
||||
g.xMax = box.x + box.width;
|
||||
g.yMin = box.y;
|
||||
g.yMax = box.y + box.height;
|
||||
var result = (0, _otfContours2ttfContours.default)(g.contours);
|
||||
g.contours = result.contours;
|
||||
if (result.xMin != null) {
|
||||
g.xMin = result.xMin;
|
||||
g.xMax = result.xMax;
|
||||
g.yMin = result.yMin;
|
||||
g.yMax = result.yMax;
|
||||
} else {
|
||||
g.xMin = 0;
|
||||
g.xMax = 0;
|
||||
|
||||
21
vendor/fonteditor-core/lib/ttf/otfreader.js
vendored
21
vendor/fonteditor-core/lib/ttf/otfreader.js
vendored
@ -70,13 +70,13 @@ var OTFReader = exports.default = /*#__PURE__*/function () {
|
||||
}
|
||||
font.readOptions = this.options;
|
||||
|
||||
// 读取支持的表数据
|
||||
Object.keys(_supportOtf.default).forEach(function (tableName) {
|
||||
/* 优化125: Object.keys+forEach → for...in 循环 */
|
||||
for (var tableName in _supportOtf.default) {
|
||||
if (font.tables[tableName]) {
|
||||
var offset = font.tables[tableName].offset;
|
||||
font[tableName] = new _supportOtf.default[tableName](offset).read(reader, font);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!font.CFF.glyf) {
|
||||
_error.default.raise(10303);
|
||||
}
|
||||
@ -95,17 +95,17 @@ var OTFReader = exports.default = /*#__PURE__*/function () {
|
||||
var codes = font.cmap;
|
||||
var glyf = font.CFF.glyf;
|
||||
var subsetMap = font.readOptions.subset ? font.subsetMap : null; // 当前ttf的子集列表
|
||||
// unicode
|
||||
Object.keys(codes).forEach(function (c) {
|
||||
/* 优化125: Object.keys+forEach → for...in 循环 */
|
||||
for (var c in codes) {
|
||||
var i = codes[c];
|
||||
if (subsetMap && !subsetMap[i]) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
if (!glyf[i].unicode) {
|
||||
glyf[i].unicode = [];
|
||||
}
|
||||
glyf[i].unicode.push(+c);
|
||||
});
|
||||
}
|
||||
|
||||
/* leftSideBearing / advanceWidth —— 兼容扁平 Int32Array 和对象数组 */
|
||||
var hmtxData = font.hmtx;
|
||||
@ -125,11 +125,12 @@ var OTFReader = exports.default = /*#__PURE__*/function () {
|
||||
}
|
||||
|
||||
// 设置了subsetMap之后需要选取subset中的字形
|
||||
/* 优化125: Object.keys+forEach → for...in 循环 */
|
||||
if (subsetMap) {
|
||||
var subGlyf = [];
|
||||
Object.keys(subsetMap).forEach(function (i) {
|
||||
subGlyf.push(glyf[+i]);
|
||||
});
|
||||
for (var si in subsetMap) {
|
||||
subGlyf.push(glyf[+si]);
|
||||
}
|
||||
glyf = subGlyf;
|
||||
}
|
||||
font.glyf = glyf;
|
||||
|
||||
44
vendor/fonteditor-core/lib/ttf/table/CFF.js
vendored
44
vendor/fonteditor-core/lib/ttf/table/CFF.js
vendored
@ -231,8 +231,10 @@ function lookupFD(fdSelect, glyphIndex) {
|
||||
}
|
||||
/** format 3 二分查找 ranges */
|
||||
var ranges = fdSelect.ranges;
|
||||
/* 优化154: 缓存 numRanges 避免重复除法 */
|
||||
var numRanges = ranges.length / 3;
|
||||
var lo = 0;
|
||||
var hi = (ranges.length / 3) - 1;
|
||||
var hi = numRanges - 1;
|
||||
while (lo <= hi) {
|
||||
var mid = (lo + hi) >> 1;
|
||||
var idx = mid * 3;
|
||||
@ -241,7 +243,7 @@ function lookupFD(fdSelect, glyphIndex) {
|
||||
hi = mid - 1;
|
||||
} else {
|
||||
/** 检查是否在当前 range 内(即 < 下一个 range 的 first) */
|
||||
if (mid === (ranges.length / 3) - 1 || glyphIndex < (ranges[idx + 3] | (ranges[idx + 4] << 8))) {
|
||||
if (mid === numRanges - 1 || glyphIndex < (ranges[idx + 3] | (ranges[idx + 4] << 8))) {
|
||||
return ranges[idx + 2];
|
||||
}
|
||||
lo = mid + 1;
|
||||
@ -385,13 +387,14 @@ var _default = exports.default = _table.default.create('cff', [], {
|
||||
|
||||
/**
|
||||
* 为指定 glyph 构建 per-glyph 的 font 对象
|
||||
* CID-keyed 字体使用 FD 对应的 local subrs
|
||||
* 优化154: CID-keyed 字体预构建 per-FD font 对象缓存,避免每次分配
|
||||
*/
|
||||
function getGlyphFont(glyphIndex) {
|
||||
if (isCID && fdSelect && fdPrivates) {
|
||||
var fdIdx = lookupFD(fdSelect, glyphIndex);
|
||||
var fd = fdPrivates[fdIdx];
|
||||
return {
|
||||
var fdGlyphFonts = null;
|
||||
if (isCID && fdSelect && fdPrivates) {
|
||||
fdGlyphFonts = new Array(fdPrivates.length);
|
||||
for (var fi = 0; fi < fdPrivates.length; fi++) {
|
||||
var fd = fdPrivates[fi];
|
||||
fdGlyphFonts[fi] = {
|
||||
subrs: fd.subrs,
|
||||
subrsBias: fd.subrsBias,
|
||||
defaultWidthX: fd.defaultWidthX,
|
||||
@ -400,6 +403,11 @@ var _default = exports.default = _table.default.create('cff', [], {
|
||||
gsubrsBias: cff.gsubrsBias
|
||||
};
|
||||
}
|
||||
}
|
||||
function getGlyphFont(glyphIndex) {
|
||||
if (fdGlyphFonts) {
|
||||
return fdGlyphFonts[lookupFD(fdSelect, glyphIndex)];
|
||||
}
|
||||
return cff;
|
||||
}
|
||||
|
||||
@ -412,21 +420,25 @@ var _default = exports.default = _table.default.create('cff', [], {
|
||||
};
|
||||
var codes = font.cmap;
|
||||
|
||||
// unicode to index
|
||||
Object.keys(codes).forEach(function (c) {
|
||||
if (subset.indexOf(+c) > -1) {
|
||||
var i = codes[c];
|
||||
subsetMap[i] = true;
|
||||
// unicode to index — 用 Set 替代 indexOf 实现 O(1) 查找
|
||||
var subsetSet = {};
|
||||
for (var si = 0, sl = subset.length; si < sl; si++) {
|
||||
subsetSet[subset[si]] = true;
|
||||
}
|
||||
for (var c in codes) {
|
||||
if (subsetSet[c]) {
|
||||
var ci = codes[c];
|
||||
subsetMap[ci] = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
font.subsetMap = subsetMap;
|
||||
Object.keys(subsetMap).forEach(function (i) {
|
||||
for (var i in subsetMap) {
|
||||
i = +i;
|
||||
var charstring = readCFFIndexObject(reader, charStringsInfo, i);
|
||||
var glyf = (0, _parseCFFGlyph.default)(charstring, getGlyphFont(i), i);
|
||||
glyf.name = cff.charset[i];
|
||||
cff.glyf[i] = glyf;
|
||||
});
|
||||
}
|
||||
}
|
||||
// parse all
|
||||
else {
|
||||
|
||||
13
vendor/fonteditor-core/lib/ttf/table/OS2.js
vendored
13
vendor/fonteditor-core/lib/ttf/table/OS2.js
vendored
@ -59,17 +59,6 @@ var _default = exports.default = _table.default.create('OS/2', [['version', _str
|
||||
var hinting = ttf.writeOptions ? ttf.writeOptions.hinting : false;
|
||||
|
||||
if (metrics) {
|
||||
var glyfs = ttf.glyf;
|
||||
/* 计算 minRightSideBearing(需要逐字形遍历 advanceWidth - xMax) */
|
||||
var minRightSideBearing = 16384;
|
||||
for (var ri = 0, rl = glyfs.length; ri < rl; ri++) {
|
||||
var rg = glyfs[ri];
|
||||
if (rg.xMax != null) {
|
||||
var rsb = rg.advanceWidth - rg.xMax;
|
||||
if (rsb < minRightSideBearing) minRightSideBearing = rsb;
|
||||
}
|
||||
}
|
||||
|
||||
ttf['OS/2'].version = 0x4;
|
||||
ttf['OS/2'].achVendID = (ttf['OS/2'].achVendID + ' ').slice(0, 4);
|
||||
ttf['OS/2'].xAvgCharWidth = metrics.xAvgCharWidth;
|
||||
@ -80,7 +69,7 @@ var _default = exports.default = _table.default.create('OS/2', [['version', _str
|
||||
ttf.hhea.version = ttf.hhea.version || 0x1;
|
||||
ttf.hhea.advanceWidthMax = metrics.advanceWidthMax;
|
||||
ttf.hhea.minLeftSideBearing = metrics.minLeftSideBearing;
|
||||
ttf.hhea.minRightSideBearing = minRightSideBearing;
|
||||
ttf.hhea.minRightSideBearing = metrics.minRightSideBearing;
|
||||
ttf.hhea.xMaxExtent = metrics.xMaxExtent;
|
||||
|
||||
ttf.head.version = ttf.head.version || 0x1;
|
||||
|
||||
@ -49,11 +49,11 @@ function getFormat0Segment(glyfUnicodes) {
|
||||
var unicodes = [];
|
||||
for (var i = 0, l = glyfUnicodes.length; i < l; i++) {
|
||||
var u = glyfUnicodes[i];
|
||||
if (u.unicode !== undefined && u.unicode < 256) {
|
||||
if (u.unicode < 256) {
|
||||
unicodes.push([u.unicode, u.id]);
|
||||
}
|
||||
}
|
||||
unicodes.sort(function (a, b) { return a[0] - b[0]; });
|
||||
/* 数据已排序,无需再次 sort */
|
||||
return unicodes;
|
||||
}
|
||||
|
||||
@ -85,17 +85,11 @@ function sizeof(ttf) {
|
||||
ttf.support.cmap.hasFormat0 = ttf.support.cmap.format0Segments.length > 0;
|
||||
ttf.support.cmap.format0Size = ttf.support.cmap.hasFormat0 ? 262 : 0;
|
||||
|
||||
var hasGLyphsOver2Bytes = false;
|
||||
for (var gi = 0, gil = unicodes2Bytes.length; gi < gil; gi++) {
|
||||
if (unicodes2Bytes[gi].unicode > 0xFFFF) {
|
||||
hasGLyphsOver2Bytes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* 优化142: 排序后直接检查最大 unicode,避免单独遍历 */
|
||||
var hasGLyphsOver2Bytes = glyfUnicodes.length > 0 && glyfUnicodes[glyfUnicodes.length - 1].unicode > 0xFFFF;
|
||||
if (hasGLyphsOver2Bytes) {
|
||||
ttf.support.cmap.hasGLyphsOver2Bytes = true;
|
||||
var unicodes4Bytes = glyfUnicodes;
|
||||
ttf.support.cmap.format12Segments = getSegments(unicodes4Bytes);
|
||||
ttf.support.cmap.format12Segments = getSegments(glyfUnicodes);
|
||||
ttf.support.cmap.format12Size = 16 + ttf.support.cmap.format12Segments.length * 12;
|
||||
}
|
||||
/** 记录头大小必须动态计算,与 write.js 中的 numRecords 保持一致,否则会导致表偏移错位 */
|
||||
|
||||
@ -240,7 +240,6 @@ function sizeof(ttf) {
|
||||
glyfSupportArr[i] = glyfSupport;
|
||||
tableSize += size;
|
||||
}
|
||||
glyfSupportArr.tableSize = tableSize;
|
||||
ttf.head.indexToLocFormat = tableSize > 65536 ? 1 : 0;
|
||||
return tableSize;
|
||||
}
|
||||
|
||||
@ -22,6 +22,9 @@ function write(writer, ttf) {
|
||||
var glyfSupport = ttf.support.glyf;
|
||||
var glyfs = ttf.glyf;
|
||||
var view = writer.view;
|
||||
/** 优化141: 复用 Uint8Array 视图,避免每次 set 创建临时视图 */
|
||||
var buf = view.buffer;
|
||||
var vbo = view.byteOffset;
|
||||
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;
|
||||
@ -133,21 +136,18 @@ function write(writer, ttf) {
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
/* 优化11+79: flags 使用 Uint8Array.set 批量写入 */
|
||||
/* 优化11+79+135: flags 直接 view 写入,避免临时 TypedArray */
|
||||
var flags = gSupport.flags || [];
|
||||
if (flags.length > 0) {
|
||||
var flagsArr = flags instanceof Uint8Array ? flags : new Uint8Array(flags);
|
||||
new Uint8Array(view.buffer, view.byteOffset + pos, flagsArr.length).set(flagsArr);
|
||||
for (var fi = 0, fl = flags.length; fi < fl; fi++) {
|
||||
view.setUint8(pos++, flags[fi]);
|
||||
}
|
||||
pos += flags.length;
|
||||
|
||||
/* 优化21+98+119: xCoord 预编码 Uint8Array 直接 set,或逐个写入 */
|
||||
var support = gSupport;
|
||||
if (support.xEncoded) {
|
||||
new Uint8Array(view.buffer, view.byteOffset + pos, support.xEncoded.length).set(support.xEncoded);
|
||||
pos += support.xEncoded.length;
|
||||
/* 优化21+98+119+141: xCoord 预编码 Uint8Array 直接 set,使用缓存引用 */
|
||||
if (gSupport.xEncoded) {
|
||||
new Uint8Array(buf, vbo + pos, gSupport.xEncoded.length).set(gSupport.xEncoded);
|
||||
pos += gSupport.xEncoded.length;
|
||||
} else {
|
||||
var xCoord = support.xCoord || [];
|
||||
var xCoord = gSupport.xCoord || [];
|
||||
for (var xi = 0, xl = xCoord.length; xi < xl; xi++) {
|
||||
var xv = xCoord[xi];
|
||||
if (0 <= xv && xv <= 0xFF) {
|
||||
@ -160,12 +160,12 @@ function write(writer, ttf) {
|
||||
}
|
||||
}
|
||||
|
||||
/* 优化21+58+98+119: yCoord 预编码 Uint8Array 直接 set,或逐个写入 */
|
||||
if (support.yEncoded) {
|
||||
new Uint8Array(view.buffer, view.byteOffset + pos, support.yEncoded.length).set(support.yEncoded);
|
||||
pos += support.yEncoded.length;
|
||||
/* 优化21+58+98+119+141: yCoord 预编码 Uint8Array 直接 set,使用缓存引用 */
|
||||
if (gSupport.yEncoded) {
|
||||
new Uint8Array(buf, vbo + pos, gSupport.yEncoded.length).set(gSupport.yEncoded);
|
||||
pos += gSupport.yEncoded.length;
|
||||
} else {
|
||||
var yCoord = support.yCoord || [];
|
||||
var yCoord = gSupport.yCoord || [];
|
||||
for (var yi = 0, yl = yCoord.length; yi < yl; yi++) {
|
||||
var yv = yCoord[yi];
|
||||
if (0 <= yv && yv <= 0xFF) {
|
||||
@ -179,12 +179,13 @@ function write(writer, ttf) {
|
||||
}
|
||||
}
|
||||
|
||||
/* 优化81: 4字节对齐使用 fill(0) 批量填充 */
|
||||
/* 优化81: 4字节对齐直接 view 写入,避免临时 TypedArray */
|
||||
var glyfSize = gSupport.glyfSize;
|
||||
if (glyfSize % 4) {
|
||||
var pad = 4 - glyfSize % 4;
|
||||
new Uint8Array(view.buffer, view.byteOffset + pos, pad).fill(0);
|
||||
pos += pad;
|
||||
if (pad >= 1) view.setUint8(pos++, 0);
|
||||
if (pad >= 2) view.setUint8(pos++, 0);
|
||||
if (pad >= 3) view.setUint8(pos++, 0);
|
||||
}
|
||||
|
||||
writer.offset = pos;
|
||||
|
||||
5
vendor/fonteditor-core/lib/ttf/table/head.js
vendored
5
vendor/fonteditor-core/lib/ttf/table/head.js
vendored
@ -11,4 +11,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
||||
* @file head表
|
||||
* @author mengke01(kekee000@gmail.com)
|
||||
*/
|
||||
var _default = exports.default = _table.default.create('head', [['version', _struct.default.Fixed], ['fontRevision', _struct.default.Fixed], ['checkSumAdjustment', _struct.default.Uint32], ['magickNumber', _struct.default.Uint32], ['flags', _struct.default.Uint16], ['unitsPerEm', _struct.default.Uint16], ['created', _struct.default.LongDateTime], ['modified', _struct.default.LongDateTime], ['xMin', _struct.default.Int16], ['yMin', _struct.default.Int16], ['xMax', _struct.default.Int16], ['yMax', _struct.default.Int16], ['macStyle', _struct.default.Uint16], ['lowestRecPPEM', _struct.default.Uint16], ['fontDirectionHint', _struct.default.Int16], ['indexToLocFormat', _struct.default.Int16], ['glyphDataFormat', _struct.default.Int16]]);
|
||||
var _default = exports.default = _table.default.create('head', [['version', _struct.default.Fixed], ['fontRevision', _struct.default.Fixed], ['checkSumAdjustment', _struct.default.Uint32], ['magickNumber', _struct.default.Uint32], ['flags', _struct.default.Uint16], ['unitsPerEm', _struct.default.Uint16], ['created', _struct.default.LongDateTime], ['modified', _struct.default.LongDateTime], ['xMin', _struct.default.Int16], ['yMin', _struct.default.Int16], ['xMax', _struct.default.Int16], ['yMax', _struct.default.Int16], ['macStyle', _struct.default.Uint16], ['lowestRecPPEM', _struct.default.Uint16], ['fontDirectionHint', _struct.default.Int16], ['indexToLocFormat', _struct.default.Int16], ['glyphDataFormat', _struct.default.Int16]], {
|
||||
/* 优化148: head 表固定 54 字节,跳过 switch 循环 */
|
||||
size: function () { return 54; }
|
||||
});
|
||||
5
vendor/fonteditor-core/lib/ttf/table/hhea.js
vendored
5
vendor/fonteditor-core/lib/ttf/table/hhea.js
vendored
@ -13,4 +13,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
||||
*
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6hhea.html
|
||||
*/
|
||||
var _default = exports.default = _table.default.create('hhea', [['version', _struct.default.Fixed], ['ascent', _struct.default.Int16], ['descent', _struct.default.Int16], ['lineGap', _struct.default.Int16], ['advanceWidthMax', _struct.default.Uint16], ['minLeftSideBearing', _struct.default.Int16], ['minRightSideBearing', _struct.default.Int16], ['xMaxExtent', _struct.default.Int16], ['caretSlopeRise', _struct.default.Int16], ['caretSlopeRun', _struct.default.Int16], ['caretOffset', _struct.default.Int16], ['reserved0', _struct.default.Int16], ['reserved1', _struct.default.Int16], ['reserved2', _struct.default.Int16], ['reserved3', _struct.default.Int16], ['metricDataFormat', _struct.default.Int16], ['numOfLongHorMetrics', _struct.default.Uint16]]);
|
||||
var _default = exports.default = _table.default.create('hhea', [['version', _struct.default.Fixed], ['ascent', _struct.default.Int16], ['descent', _struct.default.Int16], ['lineGap', _struct.default.Int16], ['advanceWidthMax', _struct.default.Uint16], ['minLeftSideBearing', _struct.default.Int16], ['minRightSideBearing', _struct.default.Int16], ['xMaxExtent', _struct.default.Int16], ['caretSlopeRise', _struct.default.Int16], ['caretSlopeRun', _struct.default.Int16], ['caretOffset', _struct.default.Int16], ['reserved0', _struct.default.Int16], ['reserved1', _struct.default.Int16], ['reserved2', _struct.default.Int16], ['reserved3', _struct.default.Int16], ['metricDataFormat', _struct.default.Int16], ['numOfLongHorMetrics', _struct.default.Uint16]], {
|
||||
/* 优化148: hhea 表固定 36 字节,跳过 switch 循环 */
|
||||
size: function () { return 36; }
|
||||
});
|
||||
19
vendor/fonteditor-core/lib/ttf/table/name.js
vendored
19
vendor/fonteditor-core/lib/ttf/table/name.js
vendored
@ -102,7 +102,7 @@ var _default = exports.default = _table.default.create('name', [], {
|
||||
// 这里为了简化书写,仅支持英文编码字符,
|
||||
// 中文编码字符将被转化成url encode
|
||||
var size = 6;
|
||||
Object.keys(names).forEach(function (name) {
|
||||
for (var name in names) {
|
||||
var id = _nameId.default.names[name];
|
||||
var utf8Bytes = _string.default.toUTF8Bytes(names[name]);
|
||||
var usc2Bytes = _string.default.toUCS2Bytes(names[name]);
|
||||
@ -128,19 +128,14 @@ var _default = exports.default = _table.default.create('name', [], {
|
||||
// 子表大小
|
||||
size += 12 * 2 + utf8Bytes.length + usc2Bytes.length;
|
||||
}
|
||||
});
|
||||
}
|
||||
var namingOrder = ['platform', 'encoding', 'language', 'nameId'];
|
||||
nameRecordTbl = nameRecordTbl.sort(function (a, b) {
|
||||
var l = 0;
|
||||
namingOrder.some(function (name) {
|
||||
var o = a[name] - b[name];
|
||||
if (o) {
|
||||
l = o;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return l;
|
||||
for (var ni = 0; ni < 4; ni++) {
|
||||
var o = a[namingOrder[ni]] - b[namingOrder[ni]];
|
||||
if (o) return o;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
// 保存预处理信息
|
||||
|
||||
104
vendor/fonteditor-core/lib/ttf/table/table.js
vendored
104
vendor/fonteditor-core/lib/ttf/table/table.js
vendored
@ -29,7 +29,9 @@ function read(reader) {
|
||||
reader.seek(offset);
|
||||
}
|
||||
var me = this;
|
||||
this.struct.forEach(function (item) {
|
||||
var struct = this.struct;
|
||||
for (var si = 0, sl = struct.length; si < sl; si++) {
|
||||
var item = struct[si];
|
||||
var name = item[0];
|
||||
var type = item[1];
|
||||
var typeName = null;
|
||||
@ -61,7 +63,7 @@ function read(reader) {
|
||||
default:
|
||||
_error.default.raise(10003, name, type);
|
||||
}
|
||||
});
|
||||
}
|
||||
return this.valueOf();
|
||||
}
|
||||
|
||||
@ -78,39 +80,26 @@ function write(writer, ttf) {
|
||||
if (!table) {
|
||||
_error.default.raise(10203, this.name);
|
||||
}
|
||||
this.struct.forEach(function (item) {
|
||||
var struct = this.struct;
|
||||
/* 优化152: 直接分发到 writer 方法,消除 string 类型名中间层双重 switch */
|
||||
for (var si = 0, sl = struct.length; si < sl; si++) {
|
||||
var item = struct[si];
|
||||
var name = item[0];
|
||||
var type = item[1];
|
||||
var typeName = null;
|
||||
switch (type) {
|
||||
case _struct.default.Int8:
|
||||
case _struct.default.Uint8:
|
||||
case _struct.default.Int16:
|
||||
case _struct.default.Uint16:
|
||||
case _struct.default.Int32:
|
||||
case _struct.default.Uint32:
|
||||
typeName = _struct.default.names[type];
|
||||
writer.write(typeName, table[name]);
|
||||
break;
|
||||
case _struct.default.Fixed:
|
||||
writer.writeFixed(table[name]);
|
||||
break;
|
||||
case _struct.default.LongDateTime:
|
||||
writer.writeLongDateTime(table[name]);
|
||||
break;
|
||||
case _struct.default.Bytes:
|
||||
writer.writeBytes(table[name], item[2] || 0);
|
||||
break;
|
||||
case _struct.default.Char:
|
||||
writer.writeChar(table[name]);
|
||||
break;
|
||||
case _struct.default.String:
|
||||
writer.writeString(table[name], item[2] || 0);
|
||||
break;
|
||||
default:
|
||||
_error.default.raise(10003, name, type);
|
||||
switch (item[1]) {
|
||||
case 1: writer.write('Int8', table[name]); break;
|
||||
case 2: writer.write('Uint8', table[name]); break;
|
||||
case 3: writer.write('Int16', table[name]); break;
|
||||
case 4: writer.write('Uint16', table[name]); break;
|
||||
case 5: writer.write('Int32', table[name]); break;
|
||||
case 6: writer.write('Uint32', table[name]); break;
|
||||
case 7: writer.writeFixed(table[name]); break;
|
||||
case 12: writer.writeLongDateTime(table[name]); break;
|
||||
case 13: writer.writeChar(table[name]); break;
|
||||
case 14: writer.writeString(table[name], item[2] || 0); break;
|
||||
case 15: writer.writeBytes(table[name], item[2] || 0); break;
|
||||
default: _error.default.raise(10003, name, item[1]);
|
||||
}
|
||||
});
|
||||
}
|
||||
return writer;
|
||||
}
|
||||
|
||||
@ -120,40 +109,18 @@ function write(writer, ttf) {
|
||||
* @param {string} name 表名
|
||||
* @return {number} 表大小
|
||||
*/
|
||||
/* 优化152: 类型大小查找表,替代 switch 循环 */
|
||||
var TYPE_SIZES = [0, 1, 1, 2, 2, 4, 4, 4, 0, 0, 0, 2, 8, 1, 0, 0, 0, 0, 0, 0, 3];
|
||||
|
||||
function size() {
|
||||
var sz = 0;
|
||||
this.struct.forEach(function (item) {
|
||||
var type = item[1];
|
||||
switch (type) {
|
||||
case _struct.default.Int8:
|
||||
case _struct.default.Uint8:
|
||||
sz += 1;
|
||||
break;
|
||||
case _struct.default.Int16:
|
||||
case _struct.default.Uint16:
|
||||
sz += 2;
|
||||
break;
|
||||
case _struct.default.Int32:
|
||||
case _struct.default.Uint32:
|
||||
case _struct.default.Fixed:
|
||||
sz += 4;
|
||||
break;
|
||||
case _struct.default.LongDateTime:
|
||||
sz += 8;
|
||||
break;
|
||||
case _struct.default.Bytes:
|
||||
sz += item[2] || 0;
|
||||
break;
|
||||
case _struct.default.Char:
|
||||
sz += 1;
|
||||
break;
|
||||
case _struct.default.String:
|
||||
sz += item[2] || 0;
|
||||
break;
|
||||
default:
|
||||
_error.default.raise(10003, name, type);
|
||||
}
|
||||
});
|
||||
var struct = this.struct;
|
||||
for (var si = 0, sl = struct.length; si < sl; si++) {
|
||||
var item = struct[si];
|
||||
var t = item[1];
|
||||
/* Bytes/String 使用 item[2] 指定长度,其余查表 */
|
||||
sz += (t === 15 || t === 14) ? (item[2] || 0) : TYPE_SIZES[t];
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
@ -165,9 +132,10 @@ function size() {
|
||||
function valueOf() {
|
||||
var val = {};
|
||||
var me = this;
|
||||
this.struct.forEach(function (item) {
|
||||
val[item[0]] = me[item[0]];
|
||||
});
|
||||
var struct = this.struct;
|
||||
for (var si = 0, sl = struct.length; si < sl; si++) {
|
||||
val[struct[si][0]] = me[struct[si][0]];
|
||||
}
|
||||
return val;
|
||||
}
|
||||
var _default = exports.default = {
|
||||
|
||||
22
vendor/fonteditor-core/lib/ttf/ttf.js
vendored
22
vendor/fonteditor-core/lib/ttf/ttf.js
vendored
@ -312,8 +312,10 @@ var TTF = exports.default = /*#__PURE__*/function () {
|
||||
value: function removeGlyf(indexList) {
|
||||
var glyf = this.ttf.glyf;
|
||||
var removed = [];
|
||||
/* 优化147: 用 Set 替代 indexOf,O(N+M) 替代 O(N*M) */
|
||||
var indexSet = new Set(indexList);
|
||||
for (var i = glyf.length - 1; i >= 0; i--) {
|
||||
if (indexList.indexOf(i) >= 0) {
|
||||
if (indexSet.has(i)) {
|
||||
removed.push(glyf[i]);
|
||||
glyf.splice(i, 1);
|
||||
}
|
||||
@ -664,14 +666,16 @@ var TTF = exports.default = /*#__PURE__*/function () {
|
||||
return -2;
|
||||
}
|
||||
var notdef = glyf.shift();
|
||||
/* 优化113: unicode 已在 optimizettf 中排序,最小值始终是 unicode[0] */
|
||||
glyf.sort(function (a, b) {
|
||||
var aU = a.unicode;
|
||||
var bU = b.unicode;
|
||||
if (!aU || !aU.length) return bU && bU.length ? 1 : 0;
|
||||
if (!bU || !bU.length) return -1;
|
||||
return aU[0] - bU[0];
|
||||
});
|
||||
/* 优化113+146: unicode 已在 optimizettf 中排序,跳过冗余 sort() */
|
||||
if (!this.ttf._unicodeSorted) {
|
||||
glyf.sort(function (a, b) {
|
||||
var aU = a.unicode;
|
||||
var bU = b.unicode;
|
||||
if (!aU || !aU.length) return bU && bU.length ? 1 : 0;
|
||||
if (!bU || !bU.length) return -1;
|
||||
return aU[0] - bU[0];
|
||||
});
|
||||
}
|
||||
glyf.unshift(notdef);
|
||||
return glyf;
|
||||
}
|
||||
|
||||
8
vendor/fonteditor-core/lib/ttf/ttfwriter.js
vendored
8
vendor/fonteditor-core/lib/ttf/ttfwriter.js
vendored
@ -55,10 +55,9 @@ var TTFWriter = exports.default = /*#__PURE__*/function () {
|
||||
if (!ttf.head.modified) {
|
||||
ttf.head.modified = ttf.head.created;
|
||||
}
|
||||
var checkUnicodeRepeat = {};
|
||||
|
||||
/* 优化112: optimizettf 已排序 unicode 并检查重复,跳过冗余工作 */
|
||||
/* 优化112+145: optimizettf 已排序 unicode 并检查重复,跳过冗余工作;延迟分配 checkUnicodeRepeat */
|
||||
if (!ttf._unicodeSorted) {
|
||||
var checkUnicodeRepeat = {};
|
||||
var glyfs = ttf.glyf;
|
||||
for (var index = 0, gl = glyfs.length; index < gl; index++) {
|
||||
var glyf = glyfs[index];
|
||||
@ -189,7 +188,8 @@ var TTFWriter = exports.default = /*#__PURE__*/function () {
|
||||
ttf.writeOptions.writeZeroContoursGlyfData = !!this.options.writeZeroContoursGlyfData;
|
||||
ttf.writeOptions.hinting = !!this.options.hinting;
|
||||
ttf.writeOptions.kerning = !!this.options.kerning;
|
||||
ttf.writeOptions.tables = tables.sort();
|
||||
/* 优化144: SUPPORT_TABLES 已有序,hint/kern 表名按字母序追加,无需 sort() */
|
||||
ttf.writeOptions.tables = tables;
|
||||
}
|
||||
}, {
|
||||
key: "write",
|
||||
|
||||
@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", {
|
||||
exports.default = optimizettf;
|
||||
exports.ceilReduceAndSizeFlat = ceilReduceAndSizeFlat;
|
||||
var _reduceGlyf = _interopRequireDefault(require("./reduceGlyf"));
|
||||
var _pathCeil = _interopRequireDefault(require("../../graphics/pathCeil"));
|
||||
var _glyFlag = _interopRequireDefault(require("../enum/glyFlag"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
/**
|
||||
@ -134,12 +133,14 @@ function ceilReduceAndSizeFromTypedArrays(glyf, sharedXBuf, sharedYBuf) {
|
||||
delete glyf._yArr;
|
||||
delete glyf._flags;
|
||||
delete glyf.endPtsOfContours;
|
||||
|
||||
return { sharedXBuf: sharedXBuf, sharedYBuf: sharedYBuf };
|
||||
}
|
||||
|
||||
/**
|
||||
* 优化84+98: 合并 ceil+reduce+flagsAndSize 为单次遍历,预编码 x/y 为 Uint8Array
|
||||
* 优化84+98+149: 合并 ceil+reduce+flagsAndSize 为单次遍历,使用共享 buffer 池
|
||||
*/
|
||||
function ceilReduceAndSizeFlat(glyf) {
|
||||
function ceilReduceAndSizeFlat(glyf, sharedXBuf, sharedYBuf) {
|
||||
var contours = glyf.contours;
|
||||
/* 优化91: 跳过 reducePathFlat */
|
||||
for (var j = contours.length - 1; j >= 0; j--) {
|
||||
@ -149,11 +150,11 @@ function ceilReduceAndSizeFlat(glyf) {
|
||||
}
|
||||
if (0 === contours.length) {
|
||||
delete glyf.contours;
|
||||
return;
|
||||
return { sharedXBuf: sharedXBuf, sharedYBuf: sharedYBuf };
|
||||
}
|
||||
|
||||
if (glyf._precomputedGlyfSupport) {
|
||||
return;
|
||||
return { sharedXBuf: sharedXBuf, sharedYBuf: sharedYBuf };
|
||||
}
|
||||
|
||||
var ONCURVE = _glyFlag.default.ONCURVE;
|
||||
@ -175,9 +176,10 @@ function ceilReduceAndSizeFlat(glyf) {
|
||||
var repeatPoint = -1;
|
||||
var encodedCoordSize = 0;
|
||||
|
||||
/* 优化98: 预编码 x/y 坐标 buffer */
|
||||
var xCoordBuf = new Uint8Array(totalPoints * 2);
|
||||
var yCoordBuf = new Uint8Array(totalPoints * 2);
|
||||
/* 优化149: 复用共享 buffer,仅在 buffer 不够大时才分配新的 */
|
||||
var neededSize = totalPoints * 2;
|
||||
var xCoordBuf = sharedXBuf.length >= neededSize ? sharedXBuf : new Uint8Array(neededSize);
|
||||
var yCoordBuf = sharedYBuf.length >= neededSize ? sharedYBuf : new Uint8Array(neededSize);
|
||||
var xbi = 0, ybi = 0;
|
||||
|
||||
for (var j = 0, cl2 = contours.length; j < cl2; j++) {
|
||||
@ -245,8 +247,13 @@ function ceilReduceAndSizeFlat(glyf) {
|
||||
}
|
||||
|
||||
flagsC.length = fi;
|
||||
var xEncoded = xCoordBuf.buffer.slice(0, xbi);
|
||||
var yEncoded = yCoordBuf.buffer.slice(0, ybi);
|
||||
/* 优化149: 存储 Uint8Array 视图,与 ceilReduceAndSizeFromTypedArrays 一致 */
|
||||
var xEncoded = new Uint8Array(xCoordBuf.buffer.slice(0, xbi));
|
||||
var yEncoded = new Uint8Array(yCoordBuf.buffer.slice(0, ybi));
|
||||
|
||||
/* 更新共享 buffer 引用(如果分配了新的更大的 buffer) */
|
||||
if (xCoordBuf !== sharedXBuf) sharedXBuf = xCoordBuf;
|
||||
if (yCoordBuf !== sharedYBuf) sharedYBuf = yCoordBuf;
|
||||
|
||||
glyf._precomputedGlyfSupport = {
|
||||
flags: flagsC,
|
||||
@ -254,6 +261,8 @@ function ceilReduceAndSizeFlat(glyf) {
|
||||
xEncoded: xEncoded,
|
||||
yEncoded: yEncoded
|
||||
};
|
||||
|
||||
return { sharedXBuf: sharedXBuf, sharedYBuf: sharedYBuf };
|
||||
}
|
||||
|
||||
/**
|
||||
@ -273,15 +282,15 @@ function optimizettf(ttf) {
|
||||
var m_firstChar = 0x10FFFF, m_lastChar = -1;
|
||||
var m_maxPoints = 0, m_maxContours = 0;
|
||||
|
||||
/* 优化120: 合并 maxPoints 扫描到主循环 */
|
||||
/* 优化120+150: 预扫描 _xArr 最大点数以一次性分配共享 buffer */
|
||||
var maxBufPoints = 0;
|
||||
for (var pi = 0, pl = glyfs.length; pi < pl; pi++) {
|
||||
if (glyfs[pi]._xArr && glyfs[pi]._xArr.length > maxBufPoints) {
|
||||
maxBufPoints = glyfs[pi]._xArr.length;
|
||||
}
|
||||
}
|
||||
var sharedXBuf = new Uint8Array(maxBufPoints * 2);
|
||||
var sharedYBuf = new Uint8Array(maxBufPoints * 2);
|
||||
var sharedXBuf = new Uint8Array(maxBufPoints * 2 || 256);
|
||||
var sharedYBuf = new Uint8Array(maxBufPoints * 2 || 256);
|
||||
|
||||
for (var index = 0, gl = glyfs.length; index < gl; index++) {
|
||||
var glyf = glyfs[index];
|
||||
@ -308,9 +317,10 @@ function optimizettf(ttf) {
|
||||
}
|
||||
}
|
||||
if (!glyf.compound) {
|
||||
/* 优化94+116: 优先从 TypedArray 构建 contour + precompute,使用共享 buffer */
|
||||
/* 优化94+116+149+150: 优先从 TypedArray 构建 contour + precompute,使用共享 buffer 池 */
|
||||
if (glyf._xArr) {
|
||||
ceilReduceAndSizeFromTypedArrays(glyf, sharedXBuf, sharedYBuf);
|
||||
var bufResult = ceilReduceAndSizeFromTypedArrays(glyf, sharedXBuf, sharedYBuf);
|
||||
if (bufResult) { sharedXBuf = bufResult.sharedXBuf; sharedYBuf = bufResult.sharedYBuf; }
|
||||
/* 优化120: 从 _numContours/_totalPoints 收集 metrics */
|
||||
if (glyf._numContours > 0) {
|
||||
if (glyf._numContours > m_maxContours) m_maxContours = glyf._numContours;
|
||||
@ -318,7 +328,8 @@ function optimizettf(ttf) {
|
||||
}
|
||||
} else if (glyf.contours) {
|
||||
if (glyf._flatContours) {
|
||||
ceilReduceAndSizeFlat(glyf);
|
||||
var flatResult = ceilReduceAndSizeFlat(glyf, sharedXBuf, sharedYBuf);
|
||||
if (flatResult) { sharedXBuf = flatResult.sharedXBuf; sharedYBuf = flatResult.sharedYBuf; }
|
||||
} else {
|
||||
/* 对象 contours 格式也需要收集 maxPoints/maxContours */
|
||||
var numC = glyf.contours.length;
|
||||
@ -330,9 +341,7 @@ function optimizettf(ttf) {
|
||||
}
|
||||
if (totalPts > m_maxPoints) m_maxPoints = totalPts;
|
||||
}
|
||||
glyf.contours.forEach(function (contour) {
|
||||
(0, _pathCeil.default)(contour);
|
||||
});
|
||||
/* 优化153: pathCeil 已在 transformContour 中完成,无需重复调用 */
|
||||
(0, _reduceGlyf.default)(glyf);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
|
||||
});
|
||||
exports.default = otfContours2ttfContours;
|
||||
var _bezierCubic2Q = _interopRequireDefault(require("../../math/bezierCubic2Q2"));
|
||||
var _pathCeil = _interopRequireDefault(require("../../graphics/pathCeil"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
/**
|
||||
* @file otf轮廓转ttf轮廓
|
||||
@ -21,7 +20,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
||||
/**
|
||||
* 将 CFF contour 转换为标准 [onCurve, offCurve, offCurve, onCurve, ...] 序列
|
||||
* 处理隐含端点和连续 offCurve 点的情况
|
||||
* 优化:原地操作 otfContour,减少中间数组分配
|
||||
* 优化:构建新数组替代 unshift/splice,避免 O(n^2)
|
||||
*/
|
||||
function normalizeContour(otfContour) {
|
||||
var len = otfContour.length;
|
||||
@ -47,20 +46,30 @@ function normalizeContour(otfContour) {
|
||||
len = otfContour.length;
|
||||
}
|
||||
|
||||
/** 处理连续的 offCurve 点:在它们之间插入隐含端点 */
|
||||
for (var i = 0; i < len; i++) {
|
||||
var p = otfContour[i];
|
||||
if (!p.onCurve && i + 1 < len && !otfContour[i + 1].onCurve) {
|
||||
var next = otfContour[i + 1];
|
||||
otfContour.splice(i + 1, 0, {
|
||||
x: (p.x + next.x) * 0.5,
|
||||
y: (p.y + next.y) * 0.5,
|
||||
onCurve: true
|
||||
});
|
||||
len++;
|
||||
i++;
|
||||
/** 处理连续的 offCurve 点:在它们之间插入隐含端点
|
||||
* 优化:构建新数组替代 splice,将 O(n^2) 降为 O(n) */
|
||||
var hasConsecutive = false;
|
||||
for (var i = 0; i < len - 1; i++) {
|
||||
if (!otfContour[i].onCurve && !otfContour[i + 1].onCurve) {
|
||||
hasConsecutive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasConsecutive) {
|
||||
var result = [];
|
||||
for (var i = 0; i < len; i++) {
|
||||
result.push(otfContour[i]);
|
||||
if (!otfContour[i].onCurve && i + 1 < len && !otfContour[i + 1].onCurve) {
|
||||
var next = otfContour[i + 1];
|
||||
result.push({
|
||||
x: (otfContour[i].x + next.x) * 0.5,
|
||||
y: (otfContour[i].y + next.y) * 0.5,
|
||||
onCurve: true
|
||||
});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return otfContour;
|
||||
}
|
||||
@ -68,20 +77,22 @@ function normalizeContour(otfContour) {
|
||||
/**
|
||||
* 转换已标准化的轮廓(onCurve/offCurve 严格交替)
|
||||
* 模式:onCurve, offCurve, offCurve, onCurve, offCurve, offCurve, ...
|
||||
* 优化153: 在构建 contour 时同时做 Math.round,消除 pathCeil 的二次遍历
|
||||
*/
|
||||
function transformContour(otfContour) {
|
||||
var normalized = normalizeContour(otfContour);
|
||||
if (normalized.length < 2) return [];
|
||||
|
||||
var contour = [];
|
||||
contour.push(normalized[0]);
|
||||
var p0 = normalized[0];
|
||||
contour.push({ x: Math.round(p0.x), y: Math.round(p0.y), onCurve: true });
|
||||
|
||||
var i = 1;
|
||||
while (i < normalized.length) {
|
||||
var cur = normalized[i];
|
||||
if (cur.onCurve) {
|
||||
/** 线段:直接添加 onCurve 端点 */
|
||||
contour.push(cur);
|
||||
contour.push({ x: Math.round(cur.x), y: Math.round(cur.y), onCurve: true });
|
||||
i++;
|
||||
} else {
|
||||
/** cubic bezier:offCurve, offCurve, onCurve */
|
||||
@ -104,32 +115,61 @@ function transformContour(otfContour) {
|
||||
}
|
||||
|
||||
var bezierArray = (0, _bezierCubic2Q.default)(contour[contour.length - 1], c1, c2 || c1, end);
|
||||
for (var bi = 0, bl = bezierArray.length; bi < bl; bi++) {
|
||||
bezierArray[bi][2].onCurve = true;
|
||||
contour.push(bezierArray[bi][1]);
|
||||
contour.push(bezierArray[bi][2]);
|
||||
for (var bi = 0, bl = bezierArray.length; bi < bl; bi += 2) {
|
||||
var ctrl = bezierArray[bi];
|
||||
var ep = bezierArray[bi + 1];
|
||||
ep.x = Math.round(ep.x);
|
||||
ep.y = Math.round(ep.y);
|
||||
ep.onCurve = true;
|
||||
ctrl.x = Math.round(ctrl.x);
|
||||
ctrl.y = Math.round(ctrl.y);
|
||||
contour.push(ctrl);
|
||||
contour.push(ep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (0, _pathCeil.default)(contour);
|
||||
return contour;
|
||||
}
|
||||
|
||||
/**
|
||||
* otf轮廓转ttf轮廓
|
||||
* otf轮廓转ttf轮廓,同时计算包围盒
|
||||
*
|
||||
* @param {Array} otfContours otf轮廓数组
|
||||
* @return {Array} ttf轮廓
|
||||
* @return {{contours: Array, xMin: number, yMin: number, xMax: number, yMax: number}} 转换结果和包围盒
|
||||
*/
|
||||
function otfContours2ttfContours(otfContours) {
|
||||
if (!otfContours || !otfContours.length) {
|
||||
return otfContours;
|
||||
return { contours: otfContours };
|
||||
}
|
||||
var contours = [];
|
||||
var left, right, top, bottom;
|
||||
var found = false;
|
||||
for (var i = 0, l = otfContours.length; i < l; i++) {
|
||||
if (otfContours[i][0]) {
|
||||
contours.push(transformContour(otfContours[i]));
|
||||
var contour = transformContour(otfContours[i]);
|
||||
contours.push(contour);
|
||||
/** 同时计算包围盒,避免 otf2ttfobject 二次遍历 */
|
||||
for (var ci = 0, cl = contour.length; ci < cl; ci++) {
|
||||
var p = contour[ci];
|
||||
if (!found) {
|
||||
left = right = p.x;
|
||||
top = bottom = p.y;
|
||||
found = true;
|
||||
} else {
|
||||
if (p.x < left) left = p.x;
|
||||
else if (p.x > right) right = p.x;
|
||||
if (p.y < top) top = p.y;
|
||||
else if (p.y > bottom) bottom = p.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return contours;
|
||||
return {
|
||||
contours: contours,
|
||||
xMin: left,
|
||||
yMin: top,
|
||||
xMax: right,
|
||||
yMax: bottom
|
||||
};
|
||||
}
|
||||
|
||||
12
vendor/fonteditor-core/lib/ttf/writer.js
vendored
12
vendor/fonteditor-core/lib/ttf/writer.js
vendored
@ -111,11 +111,15 @@ var Writer = /*#__PURE__*/function () {
|
||||
if (length < 0 || offset + length > this.length) {
|
||||
_error.default.raise(10002, this.length, offset + length);
|
||||
}
|
||||
/* 优化5: Uint8Array.set 批量写入,替代逐字节循环 */
|
||||
/* 优化151: 缓存 buffer 引用,避免每次创建 Uint8Array 视图 */
|
||||
var vBuf = this.view.buffer;
|
||||
var vOff = this.view.byteOffset + offset;
|
||||
if (value instanceof ArrayBuffer) {
|
||||
new Uint8Array(this.view.buffer, this.view.byteOffset + offset, length).set(new Uint8Array(value, 0, length));
|
||||
new Uint8Array(vBuf, vOff, length).set(new Uint8Array(value, 0, length));
|
||||
} else if (value instanceof Uint8Array) {
|
||||
new Uint8Array(vBuf, vOff, length).set(value);
|
||||
} else {
|
||||
new Uint8Array(this.view.buffer, this.view.byteOffset + offset, length).set(value instanceof Uint8Array ? value : new Uint8Array(value), 0);
|
||||
new Uint8Array(vBuf, vOff, length).set(new Uint8Array(value));
|
||||
}
|
||||
this.offset = offset + length;
|
||||
return this;
|
||||
@ -169,7 +173,7 @@ var Writer = /*#__PURE__*/function () {
|
||||
/* 优化28: 直接 view 写入,替代逐字节 writeUint8/writeUint16 */
|
||||
var pos = offset;
|
||||
for (var i = 0, l = str.length, charCode; i < l; ++i) {
|
||||
charCode = str.charCodeAt(i) || 0;
|
||||
charCode = str.charCodeAt(i);
|
||||
if (charCode > 127) {
|
||||
this.view.setUint16(pos, charCode, this.littleEndian);
|
||||
pos += 2;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user