mirror of
https://github.com/2234839/web-font.git
synced 2026-09-11 11:15:51 +08:00
perf(woff2): calcTripletAndWrite inline 到主循环,消除每点函数调用
千字文 woff2(54350 点)transformGlyfAndLoca 的 calcTripletAndWrite 占 31.8% CPU (V8 --prof 实测)。手动 inline 到 triplet 循环消除 54350 次/call 调用开销, 让 V8 做循环内寄存器分配与公共子表达式消除。原独立函数删除(避免死代码)。 输出字节逐字节完全一致(千字文/思源黑体/FiraCode 三组 IDENTICAL 验证)。 微基准 encodeTTFToWOFF2 千字文 4.84→4.38ms(-9.5%)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d68551d23e
commit
8fd11fc859
113
vendor/fonteditor-core/woff2/woff2-encode.js
vendored
113
vendor/fonteditor-core/woff2/woff2-encode.js
vendored
@ -182,67 +182,6 @@ for (let i = 84; i < 120; i++) TRIPLET_DATA_SIZES[i] = 2;
|
||||
for (let i = 120; i < 124; i++) TRIPLET_DATA_SIZES[i] = 3;
|
||||
for (let i = 124; i < 128; i++) TRIPLET_DATA_SIZES[i] = 4;
|
||||
|
||||
/**
|
||||
* 仅计算 triplet flag 字节,不写入数据
|
||||
* 优化: Pass 1 只需要 flag,数据写入由 Pass 2 的 writePointDataByFlag 完成
|
||||
*/
|
||||
/**
|
||||
* 计算 triplet flag 并同时写入数据字节,消除重复的 absDx/absDy 计算和二次分支判断
|
||||
* 优化291: 合并 calcTripletFlag + writePointDataByFlag 为单一函数
|
||||
*/
|
||||
function calcTripletAndWrite(curveBit, dx, dy, buf, offset) {
|
||||
/** 优化302: Math.abs 替代三元 `x < 0 ? -x : x`,V8 内建编译为单条 neg 指令(3.5x) */
|
||||
const absDx = Math.abs(dx);
|
||||
const absDy = Math.abs(dy);
|
||||
const xSignBit = dx >= 0 ? 1 : 0;
|
||||
const ySignBit = dy >= 0 ? 1 : 0;
|
||||
const xySignBits = xSignBit + 2 * ySignBit;
|
||||
|
||||
/* dx=0, Y 单轴 1 数据字节 (flag 0-9) */
|
||||
if (dx === 0 && absDy < 1280) {
|
||||
buf[offset] = absDy & 0xFF;
|
||||
return curveBit + ((absDy & 0xF00) >> 7) + ySignBit;
|
||||
}
|
||||
|
||||
/* dy=0, dx≠0, X 单轴 1 数据字节 (flag 10-19) */
|
||||
if (dy === 0 && dx !== 0 && absDx < 1280) {
|
||||
buf[offset] = absDx & 0xFF;
|
||||
return curveBit + 10 + ((absDx & 0xF00) >> 7) + xSignBit;
|
||||
}
|
||||
|
||||
/* 双轴 1 数据字节 (flag 20-83): 1 ≤ |dx| ≤ 64, 1 ≤ |dy| ≤ 64 */
|
||||
if (dx !== 0 && dy !== 0 && absDx < 65 && absDy < 65) {
|
||||
const ax = absDx - 1;
|
||||
const ay = absDy - 1;
|
||||
buf[offset] = ((ax & 0xF) << 4) | (ay & 0xF);
|
||||
return curveBit + 20 + (ax & 0x30) + ((ay & 0x30) >> 2) + xySignBits;
|
||||
}
|
||||
|
||||
/* 双轴 2 数据字节 (flag 84-119): 1 ≤ |dx| ≤ 768, 1 ≤ |dy| ≤ 768 */
|
||||
if (dx !== 0 && dy !== 0 && absDx < 769 && absDy < 769) {
|
||||
const ax = absDx - 1;
|
||||
const ay = absDy - 1;
|
||||
buf[offset] = ax & 0xFF;
|
||||
buf[offset + 1] = ay & 0xFF;
|
||||
return curveBit + 84 + 12 * ((ax & 0x300) >> 8) + ((ay & 0x300) >> 6) + xySignBits;
|
||||
}
|
||||
|
||||
/* 双轴 3 数据字节 (flag 120-123) */
|
||||
if (absDx < 4096 && absDy < 4096) {
|
||||
buf[offset] = absDx >> 4;
|
||||
buf[offset + 1] = ((absDx & 0xF) << 4) | (absDy >> 8);
|
||||
buf[offset + 2] = absDy & 0xFF;
|
||||
return curveBit + 120 + xySignBits;
|
||||
}
|
||||
|
||||
/* 兜底 4 数据字节 (flag 124-127) */
|
||||
buf[offset] = (absDx >> 8) & 0xFF;
|
||||
buf[offset + 1] = absDx & 0xFF;
|
||||
buf[offset + 2] = (absDy >> 8) & 0xFF;
|
||||
buf[offset + 3] = absDy & 0xFF;
|
||||
return curveBit + 124 + xySignBits;
|
||||
}
|
||||
|
||||
/* ======== glyf + loca 表变换 ======== */
|
||||
|
||||
/**
|
||||
@ -564,6 +503,14 @@ function transformGlyfAndLoca(glyfData, locaData, indexFormat, numGlyphs) {
|
||||
const gsBase = glyphAccumLen;
|
||||
let gsbi = 0;
|
||||
let prevX = 0, prevY = 0;
|
||||
/**
|
||||
* 优化303: calcTripletAndWrite 手动 inline 到主循环(消除 54350 次/call 函数调用开销)。
|
||||
* 千字文 54350 点场景,calcTripletAndWrite 占 transformGlyfAndLoca 31.8% CPU(prof 实测),
|
||||
* 函数调用与无法 inline 的参数装箱是主因。inline 后 V8 可在循环内做寄存器分配 +
|
||||
* 公共子表达式消除(absDx/absDy/curveBit 跨分支复用)。语义与原 calcTripletAndWrite 完全一致。
|
||||
* 分支顺序保持原样(特例 yOnly/xOnly 优先),千字文 78% 命中 1B 双轴分支。
|
||||
*/
|
||||
const _gs = glyphAccum;
|
||||
for (let pi = 0; pi < numPoints; pi++) {
|
||||
const cx = xCoords[pi];
|
||||
const cy = yCoords[pi];
|
||||
@ -571,7 +518,49 @@ function transformGlyfAndLoca(glyfData, locaData, indexFormat, numGlyphs) {
|
||||
const curveBit = ((flagAccum[flagWriteBase + pi] & 1) ^ 1) << 7;
|
||||
const dx = cx - prevX;
|
||||
const dy = cy - prevY;
|
||||
const flag = calcTripletAndWrite(curveBit, dx, dy, glyphAccum, gsBase + gsbi);
|
||||
const absDx = dx < 0 ? -dx : dx;
|
||||
const absDy = dy < 0 ? -dy : dy;
|
||||
const wpos = gsBase + gsbi;
|
||||
/** triplet flag(写入 flagAccum + 索引 TRIPLET_DATA_SIZES)。
|
||||
* 默认值仅占位,每个分支都会覆盖。 */
|
||||
let flag;
|
||||
if (dx === 0 && absDy < 1280) {
|
||||
_gs[wpos] = absDy & 0xFF;
|
||||
flag = curveBit + ((absDy & 0xF00) >> 7) + (dy >= 0 ? 1 : 0);
|
||||
} else if (dy === 0 && dx !== 0 && absDx < 1280) {
|
||||
_gs[wpos] = absDx & 0xFF;
|
||||
flag = curveBit + 10 + ((absDx & 0xF00) >> 7) + (dx >= 0 ? 1 : 0);
|
||||
} else if (dx !== 0 && dy !== 0 && absDx < 65 && absDy < 65) {
|
||||
const ax = absDx - 1;
|
||||
const ay = absDy - 1;
|
||||
_gs[wpos] = ((ax & 0xF) << 4) | (ay & 0xF);
|
||||
const xSignBit = dx >= 0 ? 1 : 0;
|
||||
const ySignBit = dy >= 0 ? 1 : 0;
|
||||
flag = curveBit + 20 + (ax & 0x30) + ((ay & 0x30) >> 2) + xSignBit + 2 * ySignBit;
|
||||
} else if (dx !== 0 && dy !== 0 && absDx < 769 && absDy < 769) {
|
||||
const ax = absDx - 1;
|
||||
const ay = absDy - 1;
|
||||
_gs[wpos] = ax & 0xFF;
|
||||
_gs[wpos + 1] = ay & 0xFF;
|
||||
const xSignBit = dx >= 0 ? 1 : 0;
|
||||
const ySignBit = dy >= 0 ? 1 : 0;
|
||||
flag = curveBit + 84 + 12 * ((ax & 0x300) >> 8) + ((ay & 0x300) >> 6) + xSignBit + 2 * ySignBit;
|
||||
} else if (absDx < 4096 && absDy < 4096) {
|
||||
_gs[wpos] = absDx >> 4;
|
||||
_gs[wpos + 1] = ((absDx & 0xF) << 4) | (absDy >> 8);
|
||||
_gs[wpos + 2] = absDy & 0xFF;
|
||||
const xSignBit = dx >= 0 ? 1 : 0;
|
||||
const ySignBit = dy >= 0 ? 1 : 0;
|
||||
flag = curveBit + 120 + xSignBit + 2 * ySignBit;
|
||||
} else {
|
||||
_gs[wpos] = (absDx >> 8) & 0xFF;
|
||||
_gs[wpos + 1] = absDx & 0xFF;
|
||||
_gs[wpos + 2] = (absDy >> 8) & 0xFF;
|
||||
_gs[wpos + 3] = absDy & 0xFF;
|
||||
const xSignBit = dx >= 0 ? 1 : 0;
|
||||
const ySignBit = dy >= 0 ? 1 : 0;
|
||||
flag = curveBit + 124 + xSignBit + 2 * ySignBit;
|
||||
}
|
||||
/** triplet flag 回写到 flagAccum(flagStream 存 triplet flag 而非原始 flag) */
|
||||
flagAccum[flagWriteBase + pi] = flag;
|
||||
gsbi += TRIPLET_DATA_SIZES[flag & 0x7F];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user