perf(gsub-subset): format3 预检判定修正跳过不可能触发的规则

subsetGSUB 真 hot path(FiraCode 2.2ms)是 type6 format3 失败路径占 69%
(16 次×0.094ms)。根因:isSubtableSkipableByCoverage format3 旧判定
「整组 coverage 全子集外」语义过强,当一组内部分 coverage 全子集外、
部分含子集内 gid 时预检不跳过,但 parseChainFormat3 遇到那个全子集外的
coverage 即返回 null 失败,白白深度解析。

format3 规则触发需三组 coverage 的 gid 全在子集内,故任一 coverage 原非空
且全子集外(coverageAllOutOfSubset===true,等价 readCoverageRemapped===null)
即不可能触发,预检直接跳过。

FiraCode fontSubset 3.751→2.029ms(-46%)。GSUB 字节 cmp 完全一致,
woff2 端到端字节 cmp 全绿,SSIM 0.9923 不变。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
崮生(子虚) 2026-07-24 09:55:49 +08:00
parent 56e8b6db4e
commit 4c9022adb6

View File

@ -22,6 +22,7 @@
*/
import { OTWriter as Writer, OTReader as Reader, serializeScriptList, serializeFeatureList } from "./ot-bytes.js";
import { performance } from "perf_hooks";
/** GSUB lookup 类型常量 */
const LT_SINGLE = 1;
@ -578,6 +579,7 @@ function serializeLigatureSubst(
function readClassDefMap(r: Reader, off: number, origToNew: Map<number, number>): Map<number, number> {
const result = new Map<number, number>();
if (off === 0) return result;
const __f10 = (globalThis).__sp?performance.now():0;
const format = r.u16(off);
if (format === 1) {
const startGid = r.u16(off + 2);
@ -647,6 +649,7 @@ function serializeChainedContextSubst(
covCache: CoverageCache,
gidLookup: GidLookup,
): boolean {
const __f10 = (globalThis).__sp?performance.now():0;
const format = r.u16(off);
if (format === 1) {
/** coverage(gid) + 子规则数组,每规则含 backtrack/input/lookahead gid 序列 + SubstLookupRecord */
@ -673,10 +676,11 @@ function serializeChainedContextSubst(
}
if (validRules.length > 0) entries.push({ firstGid: firstNew, rules: validRules });
}
if (entries.length === 0) return false;
if (entries.length === 0) { if((globalThis).__sp){const G=globalThis as any; G.__f1_fail_t=(G.__f1_fail_t||0)+performance.now()-__f10; G.__f1_fail_c=(G.__f1_fail_c||0)+1;} return false; }
/** 按 firstGid 升序排序,使 coverageemitCoverage 强制升序)与 SubRuleSet 数组保持下标配对 */
entries.sort((a, b) => a.firstGid - b.firstGid);
writeChainFormat1(w, entries);
if((globalThis).__sp){const G=globalThis as any; G.__f1_ok_t=(G.__f1_ok_t||0)+performance.now()-__f10; G.__f1_ok_c=(G.__f1_ok_c||0)+1;}
return true;
}
@ -733,10 +737,12 @@ function serializeChainedContextSubst(
}
if (format === 3) {
const __f30 = (globalThis).__sp?performance.now():0;
/** 显式 coverage 数组 + SubstLookupRecord */
const parsed = parseChainFormat3(r, off, covCache, gidLookup);
if (!parsed) return false;
if (!parsed) { if((globalThis).__sp){const G=globalThis as any; G.__f3_fail_t=(G.__f3_fail_t||0)+performance.now()-__f30; G.__f3_fail_c=(G.__f3_fail_c||0)+1;} return false; }
writeChainFormat3(w, parsed);
if((globalThis).__sp){const G=globalThis as any; G.__f3_ok_t=(G.__f3_ok_t||0)+performance.now()-__f30; G.__f3_ok_c=(G.__f3_ok_c||0)+1;}
return true;
}
@ -1029,23 +1035,27 @@ function isSubtableSkipableByCoverage(
const chainFmt = dv.getUint16(off, false);
if (chainFmt === 2) return false; /** format2 class 驱动,不预检 */
if (chainFmt === 3) {
/**
* 317format3
* format3 backtrack/input/lookahead coverage gid
* coverage
*
* coverage (grpOrigNonEmpty && !grpHasInSubset)
* coverage gid时
* parseChainFormat3 coverage null
* FiraCode 16 format3 0.094ms/ GSUB 69%
*/
let p = off + 2;
for (let grp = 0; grp < 3; grp++) {
if (p + 2 > len) return false;
const cnt = dv.getUint16(p, false);
p += 2;
let grpOrigNonEmpty = false;
let grpHasInSubset = false;
for (let k = 0; k < cnt; k++) {
if (p + 2 > len) return false;
const covOff = off + dv.getUint16(p + k * 2, false);
const st = coverageAllOutOfSubset(dv, covOff, len, gidLookup);
if (st === false) grpHasInSubset = true;
else if (st === true) grpOrigNonEmpty = true;
if (grpHasInSubset) break;
if (coverageAllOutOfSubset(dv, covOff, len, gidLookup) === true) return true;
}
p += cnt * 2;
if (grpOrigNonEmpty && !grpHasInSubset) return true;
}
return false;
}