perf(gsub/gpos): lookup 偏移槽改 writeUint16 占位 + writeInt16At 回填

subsetGSUB/subsetGPOS 的 lookup 偏移槽(lookupCount 个)与 gsub unsupported
分支的 subtable 偏移槽,从 reserveOffset16 闭包模式改为 writeUint16(0) 占位 +
记录 slot 起点 + 序列化后 writeInt16At 回填——与已做的 subtable 槽优化329、
writeChainFormat3 coverage 槽(gsub-writechainformat3)统一。

消除 lookupCount 个 per-lookup 闭包 + patch 对象分配。思源 GSUB 56 lookup、
FiraCode/霞鹜同。gsub unsupported 分支 subtable 槽也随之统一(原仅 supported
分支用优化329)。

收益不可测(FiraCode min 1.8346 vs 1.8439、思源 1.505 vs 1.479 均噪声内)——
lookupCount 级闭包非瓶颈,被 brotli/glyf transform 淹没。但消除语义冗余 +
统一两侧偏移槽写法。基准测试全 SSIM 一致、输出字节 IDENTICAL。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
崮生(子虚) 2026-07-25 08:05:55 +08:00
parent 67d2eb5fa5
commit 71105374ee
2 changed files with 27 additions and 11 deletions

View File

@ -259,12 +259,15 @@ export function subsetGPOS(
const lookupListAbs = w.length;
lookupListAbsHolder.push(lookupListAbs);
w.writeUint16(lookupCount);
/** 预留各 lookup 的 Offset16 槽(相对 LookupList 起始) */
const lookupAbsPositions: number[] = new Array(lookupCount);
/**
* 优化333: lookup writeUint16(0) + slot writeInt16At
* reserveOffset16 per-lookup + patch push329 subtable
*/
const lookupSlotsStart = w.length;
for (let i = 0; i < lookupCount; i++) {
const slotIdx = i;
w.reserveOffset16(lookupListAbs, () => lookupAbsPositions[slotIdx]);
w.writeUint16(0);
}
const lookupAbsPositions: number[] = new Array(lookupCount);
/** 逐个 lookup 序列化 */
for (let i = 0; i < lookupCount; i++) {
@ -358,6 +361,8 @@ export function subsetGPOS(
writeEmptyPosSubtable(w, lk.effectiveType);
w.writeInt16At(subtableSlotsStart, subtablePos - lookupStart);
}
/** 优化333: 回填 lookup 偏移槽(相对 LookupList 起始) */
w.writeInt16At(lookupSlotsStart + i * 2, lookupAbsPositions[i] - lookupListAbs);
}
w.flush();

View File

@ -1623,12 +1623,18 @@ export function subsetGSUB(
/** LookupList 重写 */
lookupListAbsHolder[0] = w.length;
const lookupListAbs = lookupListAbsHolder[0];
w.writeUint16(lookupCount);
const lookupAbsPositions: number[] = new Array(lookupCount);
/**
* 优化333: lookup writeUint16(0) + slot writeInt16At
* reserveOffset16 per-lookup + patch push329 subtable
* GSUB 56 lookup 56 + patch
*/
const lookupSlotsStart = w.length;
for (let i = 0; i < lookupCount; i++) {
const slotIdx = i;
w.reserveOffset16(lookupListAbsHolder[0], () => lookupAbsPositions[slotIdx]);
w.writeUint16(0);
}
const lookupAbsPositions: number[] = new Array(lookupCount);
/** 逐 lookup 序列化 */
for (let i = 0; i < lookupCount; i++) {
@ -1694,19 +1700,24 @@ export function subsetGSUB(
w.writeUint16(lookupFlag);
w.writeUint16(lk.subtableAbsOffs.length);
const lookupStart = w.length - 6;
const subtableAbsPositions: number[] = new Array(lk.subtableAbsOffs.length);
/**
* 334 supported 329 unsupported lookup subtable
* writeUint16(0) + slot + writeInt16At reserveOffset16
*/
const subtableSlotsStart = w.length;
for (let j = 0; j < lk.subtableAbsOffs.length; j++) {
const slotIdx = j;
w.reserveOffset16(lookupStart, () => subtableAbsPositions[slotIdx]);
w.writeUint16(0);
}
if (useMarkFilteringSet) {
w.writeUint16(r.u16(lk.origLookupOff + 6 + lk.subtableAbsOffs.length * 2));
}
for (let j = 0; j < lk.subtableAbsOffs.length; j++) {
subtableAbsPositions[j] = w.length;
w.writeInt16At(subtableSlotsStart + j * 2, w.length - lookupStart);
writeEmptySubtable(w, lk.effectiveType);
}
}
/** 优化333: 回填 lookup 偏移槽(相对 LookupList 起始) */
w.writeInt16At(lookupSlotsStart + i * 2, lookupAbsPositions[i] - lookupListAbs);
}
w.flush();