mirror of
https://github.com/2234839/web-font.git
synced 2026-09-13 04:15:42 +08:00
GPOS/GSUB 表类 read 原用 reader.readBytes (= new Uint8Array(view.buffer, off, len).slice()), .slice() 拷贝整个表字节(初夏 GPOS 68KB、GSUB 31KB)。V8 中 68KB slice 耗 ~40μs, 而 subarray 零拷贝仅 ~0.3μs(130× 差距)。 GPOS/GSUB 是原始字节透传:subsetGPOS/subsetGSUB 只读 OTReader + 写全新 OTWriter, write 只 writeBytes 只读,optimize 不碰,整个 read→optimize→subset→write 生命周期 从不原地修改底层字节,故可安全返回共享 ArrayBuffer 的 subarray 视图。 初夏 full read 0.124→0.063ms (-49%),readBuffer 0.165→0.098ms。 全基准 SSIM 与输出字节完全不变。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
51 lines
2.4 KiB
TypeScript
51 lines
2.4 KiB
TypeScript
import fs from 'node:fs';
|
|
import * as TTFReaderNS from './vendor/fonteditor-core/lib/ttf/ttfreader.js';
|
|
const TTFReader: any = TTFReaderNS.default.default ?? TTFReaderNS.default;
|
|
const support: any = (await import('./vendor/fonteditor-core/lib/ttf/table/support.js')).default.default ?? (await import('./vendor/fonteditor-core/lib/ttf/table/support.js')).default;
|
|
|
|
const buf = fs.readFileSync('/mnt/d/字体资源/初夏明朝/初夏明朝-Regular.ttf');
|
|
const ab = buf.buffer.slice(buf.byteOffset, buf.byteOffset+buf.byteLength) as ArrayBuffer;
|
|
const cps = Array.from(',。!?、;:“”‘’').map(c => c.codePointAt(0)!);
|
|
|
|
// 先拿到 reader + tables 目录
|
|
const r0 = new (TTFReader as any)({ subset: cps, kerning: true });
|
|
// 手动复刻 readBuffer 前半,拿 reader + tables
|
|
const Reader = (await import('./vendor/fonteditor-core/lib/ttf/reader.js')).default.default ?? (await import('./vendor/fonteditor-core/lib/ttf/reader.js')).default;
|
|
const Directory = (await import('./vendor/fonteditor-core/lib/ttf/directory.js')).default.default ?? (await import('./vendor/fonteditor-core/lib/ttf/directory.js')).default;
|
|
|
|
function makeReader() {
|
|
const reader = new Reader(ab, 0, ab.byteLength, false);
|
|
reader.offset = 12;
|
|
return reader;
|
|
}
|
|
|
|
// 各表独立计时
|
|
function timeTable(tableName: string, iters = 15) {
|
|
const TableClass = support[tableName];
|
|
if (!TableClass) { console.log(` ${tableName}: 无 support 类`); return; }
|
|
// warmup + 计时
|
|
const ts: number[] = [];
|
|
for (let i = 0; i < 5; i++) {
|
|
const reader = makeReader();
|
|
const dir = new Directory(12).read(reader, {});
|
|
if (!dir[tableName]) return;
|
|
const tc = new TableClass(dir[tableName].offset);
|
|
tc.read(reader, { tables: dir, readOptions: { subset: cps, kerning: true } } as any);
|
|
}
|
|
for (let i = 0; i < iters; i++) {
|
|
const reader = makeReader();
|
|
const dir = new Directory(12).read(reader, {});
|
|
const tc = new TableClass(dir[tableName].offset);
|
|
const t0 = performance.now();
|
|
tc.read(reader, { tables: dir, readOptions: { subset: cps, kerning: true } } as any);
|
|
ts.push(performance.now() - t0);
|
|
}
|
|
ts.sort((a,b)=>a-b);
|
|
console.log(` ${tableName}: ${ts[Math.floor(ts.length/2)].toFixed(3)}ms (min ${ts[0].toFixed(3)})`);
|
|
}
|
|
|
|
console.log('=== 初夏标点 各表 read 耗时 ===');
|
|
for (const t of ['head','hhea','maxp','OS/2','name','cmap','hmtx','vmtx','GPOS','GSUB','post']) {
|
|
timeTable(t);
|
|
}
|