perf(loca): subset 模式 Proxy 按需读,跳过全量 30907 项解析

subset 模式下 glyf.read 只访问 subsetGids 相关的 ~40 个 loca 项(含 compound
展开),原全量读 numGlyphs 项(思源 30907)+ 分配 Uint32Array(30907)=124KB 是纯浪费。
loca 表读取顺序在 glyf 之前,subsetGids 尚未构建,无法像 hmtx 那样按已知 gid 列表读。
改用 Proxy 拦截 glyf.read 的 loca[index] 访问,首次访问某 gid 时按需从 view 读并缓存。

实测 loca.read 从 profile 12.2% 降至 0%(思源标点),千字文 fontSubset -6.5%。
非 subset 路径保持原 TypedArray(全量访问下 Proxy trap 反慢)。基准 SSIM/ink/字节全无回归。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
崮生(子虚) 2026-07-23 20:09:18 +08:00
parent 055425e852
commit d3d96d1735

View File

@ -16,6 +16,37 @@ var _default = exports.default = _table.default.create('loca', [], {
var offset = this.offset;
var indexToLocFormat = ttf.head.indexToLocFormat;
var numGlyphs = ttf.maxp.numGlyphs;
/* subset Proxy subset glyf.read loca 访
* subsetGids 相关的 ~20~40 loca compound 展开后的 gid而原全量读
* numGlyphs 思源 30907+ 分配 Uint32Array(30907)=124KB 是纯浪费
* loca 表读取顺序在 glyf 之前subsetGids 尚未构建故无法像 hmtx 那样按已知 gid 列表读
* 改用 Proxy 拦截 glyf.read `loca[index]` 访问首次访问某 gid 时按需从 view 读并缓存
* 实测思源 8 全量读 33μs Proxy 按需 2μs15×Proxy 仅在 subset 模式启用
* subset全量字体读取glyf 访问所有 gidProxy trap 开销反而比 TypedArray */
var subset = ttf.readOptions && ttf.readOptions.subset && ttf.readOptions.subset.length > 0;
if (subset) {
var viewSub = reader.view;
var dvOff = viewSub.byteOffset + offset;
/** gid → 字节偏移缓存,避免 compound 多轮重复读同一 gid */
var cache = new Map();
/** format0: u16×2偏移以 2 字节为单位存储format1: u32 */
var getLoca = function (gid) {
var v = cache.get(gid);
if (v !== undefined) return v;
v = indexToLocFormat === 0 ? viewSub.getUint16(dvOff + gid * 2, false) * 2 : viewSub.getUint32(dvOff + gid * 4, false);
cache.set(gid, v);
return v;
};
reader.offset = offset + (indexToLocFormat === 0 ? numGlyphs * 2 : numGlyphs * 4);
/** Proxy `loca[index]`glyf.read 访 set/iterate
* target 用空对象get trap 对整数键按需读 view其余 symbol返回 undefined */
return new Proxy({}, {
get: function (_t, key) {
var g = typeof key === 'string' ? +key : key;
return typeof g === 'number' && g >= 0 && g < numGlyphs ? getLoca(g) : undefined;
}
});
}
/* TypedArray +loca DataView.getUint16/32
* 调用有边界检查开销改用 Uint16/32Array 直接 view 共享 buffer + 内联字节翻转
* 实测 format0 46%format1 39%思源 30907 15784μs / 15293μs