refactor(cff): origFd→privInfo 查找改 fdRemap 下标 O(1)

subsetCFF 重建 CharStrings 循环里,原用 usedFds 线性扫描找 origFd 对应的
privInfo(O(glyphs×FDs))。改为复用已有的 fdRemap(origFd→newFdIndex) 直接
下标取 fdInfos[fdIdx].priv(O(1))。gidOrigFids 与 fdRemap 同源构建,每个 fd
必命中;缺失则 null 走透传(与原线性扫描未命中等价)。

字节一致(思源/白狐 3 OTF 用例 sha 全同)。基准无性能收益(思源 usedFds 仅
1-2 个 FD,线性扫描 break 在第一步),纯清理 + 对未来多 FD CID 字体严格更优。

otf-subset.ts: buildSubsetGids 补充 gidToNewGid Map vs Int32Array 边界判据注释
(CID 字体 numGlyphs=65535 致 fill 成本远超 Map 低频查询),防未来重复尝试。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
崮生(子虚) 2026-07-25 12:54:41 +08:00
parent cda0215b36
commit 2a224b1df7
2 changed files with 10 additions and 7 deletions

View File

@ -864,12 +864,11 @@ export function subsetCFF(cffBytes: Uint8Array, subsetGids: number[]): Uint8Arra
for (let gi = 0; gi < newSubsetNumGlyphs; gi++) {
const r = charStringRanges[gi];
const origFd = gidOrigFds[gi];
/** 该 gid 所属原 FD 对应的 Private 信息(经 privSegCache 去重,按 privOrigOff 查) */
let privInfo: PrivInfo | null = null;
/** usedFds 顺序与 fdInfos 一致,反查 origFd→privInfo */
for (let fi = 0; fi < usedFds.length; fi++) {
if (usedFds[fi] === origFd) { privInfo = fdInfos[fi].priv; break; }
}
/** O(1) gid FD Private fdRemap(origFdnewFdIndex) fdInfos
* usedFds 线 FD O(glyphs×FDs)O(glyphs)gidOrigFds fd
* fdRemap fdRemap null 线 */
const fdIdx = fdRemap.get(origFd);
const privInfo: PrivInfo | null = fdIdx !== undefined ? fdInfos[fdIdx].priv : null;
if (privInfo && privInfo.localRemap && gidHasSubr[gi]) {
const rewritten = rewriteCharstring(b, r.start, r.end, privInfo.localBias, privInfo.localRemap, privInfo.newLocalCount);
newCharStringObjects.push({ bytes: rewritten, start: 0, len: rewritten.length });

View File

@ -143,7 +143,11 @@ function buildSubsetGids(
/** origGid 集合(保持插入顺序,新 gid = 数组 index */
const subsetGids: number[] = [0];
/** gid gidsubsetGids subsetGids.indexOf(gid) O(n) 线
* indexOf codepoint subsetGidsO(N×M)退 O(N²) */
* indexOf codepoint subsetGidsO(N×M)退 O(N²)
* Map vs Int32Array = codePoints ~200 numGlyphs 65535CID
* Int32Array(numGlyphs).fill 65535 Map 200 get Map
* [[gpos-gidlookup-int32array]] GSUB/GPOS + Int32Array
* + Map [[gpos-gidlookup-negative]] */
const gidToNewGid = new Map<number, number>([[0, 0]]);
const cpToNewGid = new Map<number, number>();
for (const cp of codePoints) {