mirror of
https://github.com/2234839/web-font.git
synced 2026-09-04 23:02:27 +08:00
perf(gsub-subset): parseChainRuleFormat1or2 边读边 remap 提前失败
原实现对 back/input/look 先读到 backRaw/inputRaw/lookRaw 三个临时数组, 再二次遍历 remapSeq 重映射,format1 含子集外 gid 时规则失效(return null), 但 raw 数组已分配——FiraCode 多数 fmt1 规则因 input gid 不在子集而失效,raw 分配纯浪费。 改为 readSeq 边读边重映射(format1):遇子集外 gid 立即返回 null,省掉三个 临时数组与二次遍历。format2(class index 始终有效)原样读取不重映射,行为不变。 subsetGSUB min(checksum 与改动前完全一致): - FiraCode 0.296→0.290ms(-2%) - 初夏纯标点 0.075→0.071ms(-5%) 全字体 SSIM/输出字节均不变。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7b5d03391f
commit
6c59c3e7e6
@ -837,22 +837,42 @@ function parseChainRuleFormat1or2(
|
||||
/** count 异常大(偏移错位读到垃圾值)则放弃该规则,返回 null。实际规则序列长度很小(<256) */
|
||||
if (backCount > 255) return null;
|
||||
let p = ruleOff + 2;
|
||||
const backRaw: number[] = [];
|
||||
for (let k = 0; k < backCount; k++) backRaw.push(r.u16(p + k * 2));
|
||||
/**
|
||||
* format1(gid 序列):边读边重映射,遇子集外 gid 立即返回 null——避免先收集 backRaw/inputRaw/lookRaw
|
||||
* 三个临时数组再二次遍历 remap(子集外规则的 raw 数组分配纯浪费,FiraCode 多数 fmt1 规则因 input gid
|
||||
* 不在子集而失效)。format2(class index):始终有效,原样读取不重映射。
|
||||
*/
|
||||
const readSeq = (count: number): number[] | null => {
|
||||
if (count === 0) return [];
|
||||
if (isGidFormat) {
|
||||
const out: number[] = [];
|
||||
for (let k = 0; k < count; k++) {
|
||||
const m = remapGid(origToNew, r.u16(p + k * 2));
|
||||
if (m === null) return null;
|
||||
out.push(m);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
const out2: number[] = [];
|
||||
for (let k = 0; k < count; k++) out2.push(r.u16(p + k * 2));
|
||||
return out2;
|
||||
};
|
||||
const back = readSeq(backCount);
|
||||
if (back === null) return null;
|
||||
p += backCount * 2;
|
||||
const inputCount = r.u16(p);
|
||||
/** inputCount 为 0 是异常(ChainSubRule 至少含第一分量,inputCount>=1),返回 null 跳过该规则 */
|
||||
if (inputCount === 0 || inputCount > 255) return null;
|
||||
p += 2;
|
||||
/** input 序列不含第一分量(第一分量由 coverage/class 决定) */
|
||||
const inputRaw: number[] = [];
|
||||
for (let k = 0; k < inputCount - 1; k++) inputRaw.push(r.u16(p + k * 2));
|
||||
const input = readSeq(inputCount - 1);
|
||||
if (input === null) return null;
|
||||
p += (inputCount - 1) * 2;
|
||||
const lookCount = r.u16(p);
|
||||
if (lookCount > 255) return null;
|
||||
p += 2;
|
||||
const lookRaw: number[] = [];
|
||||
for (let k = 0; k < lookCount; k++) lookRaw.push(r.u16(p + k * 2));
|
||||
const look = readSeq(lookCount);
|
||||
if (look === null) return null;
|
||||
p += lookCount * 2;
|
||||
const seqCount = r.u16(p);
|
||||
if (seqCount > 255) return null;
|
||||
@ -861,23 +881,6 @@ function parseChainRuleFormat1or2(
|
||||
for (let k = 0; k < seqCount; k++) {
|
||||
records.push({ seq: r.u16(p + k * 4), lookup: r.u16(p + k * 4 + 2) });
|
||||
}
|
||||
|
||||
/** format1:gid 重映射,子集外 gid 则规则失效;format2:class index 原样保留 */
|
||||
const remapSeq = (arr: number[]): number[] | null => {
|
||||
if (!isGidFormat) return arr.slice();
|
||||
const out: number[] = [];
|
||||
for (const v of arr) {
|
||||
const m = remapGid(origToNew, v);
|
||||
if (m === null) return null;
|
||||
out.push(m);
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
const back = remapSeq(backRaw);
|
||||
const input = remapSeq(inputRaw);
|
||||
const look = remapSeq(lookRaw);
|
||||
if (back === null || input === null || look === null) return null;
|
||||
return { back, input, look, records };
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user