perf(gsub-subset): format3 预检用 readCoverageRemapped 保证判定一致

opt317 的 format3 预检用 coverageAllOutOfSubset 内联判定,其 COV_RANGE
累积超限逻辑与 parseChainFormat3 实际用的 readCoverageRemapped 不一致,
导致 FiraCode 13 个 format3 预检未跳过却深度解析失败(0.328ms/call 浪费)。

预检改用 readCoverageRemapped(与深度解析同一判定函数 + 共享 covCache),
精确保证「预检跳过 ⟺ 深度解析失败」,输出完全一致(都是空 subtable)。
readCoverageRemapped 触碰 covCache 无副作用(gids 留 EMPTY_GIDS 占位,
readCoverageGids 命中按 miss 重算,已有逻辑)。

另:writeEmptySubtable 的 coverageOffset 恒为 6,改直接写常量,
省 reserveOffset16 的 patches push + 闭包分配。

FiraCode subsetGSUB 1.049→0.768ms(-27%),fontSubset 2.49→2.27ms(-9%)。
GSUB/woff2 字节 cmp 全绿,30 项基准 SSIM 零变化(FiraCode 0.9923、
千字文 0.9986、初夏纯标点 0.9920、otf 0.9681/0.9310 均不变)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
崮生(子虚) 2026-07-24 10:14:38 +08:00
parent 1da81eb0c0
commit dd4f7ba55a

View File

@ -386,11 +386,15 @@ function serializeSingleSubst(
* /
*/
function writeEmptySubtable(w: Writer, effectiveType: number): void {
const subStart = w.length;
/** SingleSubst 用 format2其余类型用 format1避免 LigatureSubst 等报 unknown format:2 */
const format = effectiveType === LT_SINGLE ? 2 : 1;
w.writeUint16(format);
w.reserveOffset16(subStart, () => subStart + 6);
/**
* subtable format(2) + coverageOffset(2) + count(2) + coverage(format1 + count0 4 )
* coverageOffset subtable 6 count coverage
* reserveOffset16 patches push + FiraCode 259 /call subtable
*/
w.writeUint16(6);
w.writeUint16(0);
/** 空 coverageformat1 + count0 */
w.writeUint16(1);
@ -1019,6 +1023,7 @@ function isSubtableSkipableByCoverage(
off: number,
type: number,
gidLookup: GidLookup,
covCache: CoverageCache,
): boolean {
const dv = r.dv;
const len = dv.byteLength;
@ -1030,14 +1035,16 @@ function isSubtableSkipableByCoverage(
if (chainFmt === 2) return false; /** format2 class 驱动,不预检 */
if (chainFmt === 3) {
/**
* 317format3
* 317+318format3
* format3 backtrack/input/lookahead coverage gid
* coverage
*
* coverage (grpOrigNonEmpty && !grpHasInSubset)
* coverage gid时
* parseChainFormat3 coverage null
* FiraCode 16 format3 0.094ms/ GSUB 69%
* 318 readCoverageRemapped parseChainFormat3 + covCache
* subtable
* coverageAllOutOfSubset COV_RANGE readCoverageRemapped
* FiraCode 13 format3 0.328ms/call
* readCoverageRemapped covCache entry gids EMPTY_GIDS
* readCoverageGids miss
*/
let p = off + 2;
for (let grp = 0; grp < 3; grp++) {
@ -1047,7 +1054,7 @@ function isSubtableSkipableByCoverage(
for (let k = 0; k < cnt; k++) {
if (p + 2 > len) return false;
const covOff = off + dv.getUint16(p + k * 2, false);
if (coverageAllOutOfSubset(dv, covOff, len, gidLookup) === true) return true;
if (readCoverageRemapped(r, covOff, gidLookup, covCache) === null) return true;
}
p += cnt * 2;
}
@ -1124,7 +1131,7 @@ function serializeSubtable(
/** coverage fmt3 coverage subtable
* FiraCode 403 lookup ~330 type1-4 + fmt1 + fmt3
* format2 class coverage */
if (isSubtableSkipableByCoverage(r, off, type, gidLookup)) return false;
if (isSubtableSkipableByCoverage(r, off, type, gidLookup, covCache)) return false;
let ok: boolean;
switch (type) {
case LT_SINGLE: