perf(hmtx): subset 模式按需读 subsetGids 项,跳过全量 30888 项解析

subset 模式下 glyf.read(表顺序在 hmtx 之前)已构建 subsetGids,
resolveGlyf 也只访问 subsetGids 对应位置。原实现全量解析 numOfLongHorMetrics
项(思源 30888)对小子集是纯浪费。改为只读 subsetGids 需要的项,
其余位置保持 0(不被访问)。

实测 hmtx.read 0.21→0.032ms(6.5×),基准 SSIM/ink/字节全无回归。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
崮生(子虚) 2026-07-23 19:46:42 +08:00
parent 6ea19550a1
commit b4f8d7a522

View File

@ -22,6 +22,32 @@ var _default = exports.default = _table.default.create('hmtx', [], {
var hMetrics = new Int32Array(numGlyphs * 2);
var view = reader.view;
var vOffset = view.byteOffset + offset;
/* subset subset ttf.subsetGids glyf.read hmtx
* resolveGlyf 也只访问 subsetGids 对应的 hmtx[gid*2]/[gid*2+1]
* 原实现全量解析 numOfLongHorMetrics 思源 30888 Font.create ~10% 8 字子集是纯浪费
* 改为只读 subsetGids 需要的项其余位置保持 0不会被访问 */
var subsetGids = ttf.readOptions && ttf.readOptions.subset && ttf.readOptions.subset.length > 0 ? ttf.subsetGids : null;
if (subsetGids) {
/* Last 段gid >= numOfLongHorMetrics的起始字节偏移共享 advW = 最后一个 LongHorMetric 的 advW */
var lastSegOff = vOffset + numOfLongHorMetrics * 4;
var lastAdvWOff = vOffset + (numOfLongHorMetrics - 1) * 4;
for (var si = 0, sl = subsetGids.length; si < sl; si++) {
var gid = subsetGids[si];
var idx = gid * 2;
if (gid < numOfLongHorMetrics) {
/* LongHorMetric 段advW + lsb 各 2 字节 */
var gOff = vOffset + gid * 4;
hMetrics[idx] = view.getUint16(gOff, false);
hMetrics[idx + 1] = view.getInt16(gOff + 2, false);
} else {
/* Last 段advW 复用最后一个 LongHorMetric 的值lsb 在 lastSegOff + (gid-num)*2 */
hMetrics[idx] = view.getUint16(lastAdvWOff, false);
hMetrics[idx + 1] = view.getInt16(lastSegOff + (gid - numOfLongHorMetrics) * 2, false);
}
}
reader.offset = offset + numOfLongHorMetrics * 4 + (numGlyphs - numOfLongHorMetrics) * 2;
return hMetrics;
}
/* TypedArray +hmtx DataView.getUint16/getInt16
* 有边界检查开销LongHorMetric 每项 u16 advW + i16 lsb Uint16Array view 共享 buffer
* 读取后内联翻转实测思源黑体30888 2×19898μsoffset 2 字节对齐