perf(gsub): 全空 lookup 折叠 subCount=1(补齐 GPOS 优化330)

GSUB supported lookup 全空(allEmpty)时,把 N 个空 subtable 折叠为 subCount=1
的单个空 subtable,与 subsetGPOS 优化330 同类。feature 仅按 lookup index 引用,
subCount 改变不影响 feature;浏览器遍历 subtable 查 coverage,单个空 subtable
与 N 个全空 subtable 渲染语义等价(都查不到字形跳过)。

与 gsub-lookup-deletion-failed-fira 区别:不删 lookup(index 不变、feature 不受影响),
仅把全空 lookup 内的 N 个空 subtable 折叠为 1 个。

体积(30 用例 SSIM 全不变,总体积 -4520B):
- otf-思源黑体 ttf -3204B / woff2 -532B(GSUB 全空 lookup 多)
- 初夏纯标点 woff2 -520B / FiraCode woff2 -124B
FiraCode SSIM 0.9923 不变(连字字形完整保留,ink 3856/3695 一致)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
崮生(子虚) 2026-07-25 13:13:07 +08:00
parent 2a224b1df7
commit 665a089019

View File

@ -1667,30 +1667,40 @@ export function subsetGSUB(
/** 输出用 effectiveTypeextension 解包后内嵌,不再用 extension 包裹) */
w.writeUint16(lk.effectiveType);
w.writeUint16(lookupFlag);
w.writeUint16(lk.subtableAbsOffs.length);
const lookupStart = w.length - 6;
/**
* 329 subsetGPOS subtable writeUint16(0) + slot
* writeInt16At reserveOffset16 per-slot + patch push
* GSUB 56 lookup × 323 subtable 323
*/
const subtableSlotsStart = w.length;
for (let j = 0; j < lk.subtableAbsOffs.length; j++) {
w.writeUint16(0);
}
if (useMarkFilteringSet) {
w.writeUint16(r.u16(lk.origLookupOff + 6 + lk.subtableAbsOffs.length * 2));
}
if (lk.allEmpty) {
/** 331 lookup subtable serializeSubtable
* writeEmptySubtable N
* + + rollback subCount lookup */
for (let j = 0; j < lk.subtableAbsOffs.length; j++) {
/** subtable 起点writeEmpty 前)回填到偏移槽(相对 lookupStart */
w.writeInt16At(subtableSlotsStart + j * 2, w.length - lookupStart);
writeEmptySubtable(w, lk.effectiveType);
/** 337 subsetGPOS 330 lookup subCount=1 subtable
* feature lookup index subCount feature subtable coverage
* subtable N subtable FiraCode 403 lookup
* 235 58% (N-1)×10 /lookup 2 + subtable 8
* [[gsub-lookup-deletion-failed-fira]] lookupindex feature
* lookup N subtable 1 */
w.writeUint16(1);
const lookupStart = w.length - 6;
const subtableSlotsStart = w.length;
w.writeUint16(0);
if (useMarkFilteringSet) {
/** markFilteringSet 读原 N 位置(原 lookup 头布局),写到新 1 槽之后(输出布局) */
w.writeUint16(r.u16(lk.origLookupOff + 6 + lk.subtableAbsOffs.length * 2));
}
const subtablePos = w.length;
writeEmptySubtable(w, lk.effectiveType);
w.writeInt16At(subtableSlotsStart, subtablePos - lookupStart);
} else {
w.writeUint16(lk.subtableAbsOffs.length);
const lookupStart = w.length - 6;
/**
* 329 subsetGPOS subtable writeUint16(0) + slot
* writeInt16At reserveOffset16 per-slot + patch push
* GSUB 56 lookup × 323 subtable 323
*/
const subtableSlotsStart = w.length;
for (let j = 0; j < lk.subtableAbsOffs.length; j++) {
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++) {
/** 单个 subtable 重映射失败coverage gid 全不在子集 /
* 退 subtable coverage