perf(cff): collectSubrRefs 用 stackLen+lastVal 替代 stack:number[]

仅需栈长度(HSTEM 算 stemCount)与栈顶值(CALLSUBR/CALLGSUBR 取调用编号),
无需完整栈数组。消除每 operand 的 push(装箱)与 length=0 重置。

otf-思源8字 subsetOTF min 0.319→0.297ms(-7%),p50 0.401→0.390ms。
输出逐字节相同。与 rewriteCharstring/replaceDictOffsets 累计 otf-思源 -19%。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
崮生(子虚) 2026-07-25 02:53:41 +08:00
parent efe24d9312
commit 94f89ddbb8

View File

@ -226,56 +226,67 @@ export function collectSubrRefs(
localRefs: Set<number>,
gsubrRefs: Set<number>,
): void {
/**
* stackLen + lastVal stack: number[]
* HSTEM stemCountCALLSUBR/CALLGSUBR
* operand push stack.length=0
* lastVal stackLen>0 CALLSUBR operand push
*/
let p = start;
const stack: number[] = [];
let stackLen = 0;
let lastVal = NaN;
let stemCount = 0;
while (p < end) {
const b0 = b[p++];
if (b0 === 255) {
/** fixed point坐标4 字节,不入栈编号判定 */
stack.push(NaN);
lastVal = NaN;
stackLen++;
p += 4;
} else if (b0 === 28) {
stack.push(((b[p] << 24) | (b[p + 1] << 16)) >> 16);
lastVal = ((b[p] << 24) | (b[p + 1] << 16)) >> 16;
stackLen++;
p += 2;
} else if (b0 === 29) {
stack.push(((b[p] << 24) | (b[p + 1] << 16) | (b[p + 2] << 8) | b[p + 3]) | 0);
lastVal = ((b[p] << 24) | (b[p + 1] << 16) | (b[p + 2] << 8) | b[p + 3]) | 0;
stackLen++;
p += 4;
} else if (b0 >= 32 && b0 <= 246) {
stack.push(b0 - 139);
lastVal = b0 - 139;
stackLen++;
} else if (b0 >= 247 && b0 <= 250) {
stack.push((b0 - 247) * 256 + b[p] + 108);
lastVal = (b0 - 247) * 256 + b[p] + 108;
stackLen++;
p += 1;
} else if (b0 >= 251 && b0 <= 254) {
stack.push(-(b0 - 251) * 256 - b[p] - 108);
lastVal = -(b0 - 251) * 256 - b[p] - 108;
stackLen++;
p += 1;
} else {
/** 操作码b0 <= 27含 12 双字节) */
if (b0 === 12) {
p += 1;
stack.length = 0;
stackLen = 0;
} else if (b0 === T2_HSTEM || b0 === T2_VSTEM || b0 === T2_HSTEMHM || b0 === T2_VSTEMHM) {
stemCount += stack.length >> 1;
stack.length = 0;
stemCount += stackLen >> 1;
stackLen = 0;
} else if (b0 === T2_HINTMASK || b0 === T2_CNTRMASK) {
p += (stemCount + 7) >>> 3;
stack.length = 0;
stackLen = 0;
} else if (b0 === T2_CALLSUBR) {
const arg = stack[stack.length - 1];
if (Number.isInteger(arg)) {
const sn = arg + localBias;
if (Number.isInteger(lastVal)) {
const sn = lastVal + localBias;
if (sn >= 0 && sn < localCount) localRefs.add(sn);
}
stack.length = 0;
stackLen = 0;
} else if (b0 === T2_CALLGSUBR) {
const arg = stack[stack.length - 1];
if (Number.isInteger(arg)) gsubrRefs.add(arg);
stack.length = 0;
if (Number.isInteger(lastVal)) gsubrRefs.add(lastVal);
stackLen = 0;
} else if (b0 === T2_ENDCHAR) {
break;
} else {
/** 其余操作码(运动/曲线等)消费栈 */
stack.length = 0;
stackLen = 0;
}
}
}