From 6b28ba3d74cd79866442497de39a43316e3a12fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B4=AE=E7=94=9F=EF=BC=88=E5=AD=90=E8=99=9A=EF=BC=89?= <2234839456@qq.com> Date: Fri, 24 Jul 2026 09:27:19 +0800 Subject: [PATCH] =?UTF-8?q?perf(glyf):=20subset=20=E5=BF=AB=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E5=88=A0=20endPtsOfContours=20=E6=95=B0=E7=BB=84?= =?UTF-8?q?=E5=88=86=E9=85=8D=EF=BC=8C=E7=9B=B4=E6=8E=A5=E8=AF=BB=E6=9C=80?= =?UTF-8?q?=E5=90=8E=20endPt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化310 快路径下 endPtsOfContours 数组仅用于算 _totalPoints(供 maxPoints metrics), 下游 optimizettf 快路径分支、sizeof/write 原始字节拷贝均不消费它。 直接读最后一个 endPt(vOff+10+(numContours-1)*2)算 _totalPoints, 省掉每个 simple 字形的 Array 分配 + numContours 次 getUint16 循环。 千字文 ttf 0.252→0.246ms,ttf 字节输出 cmp 完全一致,SSIM 全部不变。 Co-Authored-By: Claude Opus 4.8 (1M context) --- _cmpttf.entry.ts | 8 ++++++++ _cmpttf2.entry.ts | 8 ++++++++ _prof_stage.entry.ts | 21 ++++++++++++++++++++ _prof_v8.entry.ts | 18 +++++++++++++++++ vendor/fonteditor-core/lib/ttf/table/glyf.js | 14 ++++++------- 5 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 _cmpttf.entry.ts create mode 100644 _cmpttf2.entry.ts create mode 100644 _prof_stage.entry.ts create mode 100644 _prof_v8.entry.ts diff --git a/_cmpttf.entry.ts b/_cmpttf.entry.ts new file mode 100644 index 0000000..16956d7 --- /dev/null +++ b/_cmpttf.entry.ts @@ -0,0 +1,8 @@ +import { readFileSync, writeFileSync } from 'fs'; +import { fontSubset } from './backend/font_util/font.js'; +const buf = readFileSync('font/令东齐伋复刻体.ttf'); +const ab = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); +const text = '天地玄黄宇宙洪荒日月盈昃辰宿列张寒来暑往秋收冬藏闰余成岁律吕调阳云腾致雨露结为霜金生丽水玉出昆冈剑号巨阙珠称夜光果珍李柰菜重芥姜海咸河淡鳞潜羽翔'; +const out = fontSubset(ab, text, {sourceType:'ttf',outType:'ttf'}); +writeFileSync('/tmp/ttf_opt313.bin', out); +console.log('len', out.length); diff --git a/_cmpttf2.entry.ts b/_cmpttf2.entry.ts new file mode 100644 index 0000000..af488bd --- /dev/null +++ b/_cmpttf2.entry.ts @@ -0,0 +1,8 @@ +import { readFileSync, writeFileSync } from 'fs'; +import { fontSubset } from './backend/font_util/font.js'; +const buf = readFileSync('font/令东齐伋复刻体.ttf'); +const ab = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); +const text = '天地玄黄宇宙洪荒日月盈昃辰宿列张寒来暑往秋收冬藏闰余成岁律吕调阳云腾致雨露结为霜金生丽水玉出昆冈剑号巨阙珠称夜光果珍李柰菜重芥姜海咸河淡鳞潜羽翔'; +const out = fontSubset(ab, text, {sourceType:'ttf',outType:'ttf'}); +writeFileSync('/tmp/ttf_clean.bin', out); +console.log('len', out.length); diff --git a/_prof_stage.entry.ts b/_prof_stage.entry.ts new file mode 100644 index 0000000..11bf97a --- /dev/null +++ b/_prof_stage.entry.ts @@ -0,0 +1,21 @@ +import { fontSubset } from './backend/font_util/font.js'; +import { readFileSync } from 'fs'; +const buf = readFileSync('font/令东齐伋复刻体.ttf'); +const ab = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); +const text = '天地玄黄宇宙洪荒日月盈昃辰宿列张寒来暑往秋收冬藏闰余成岁律吕调阳云腾致雨露结为霜金生丽水玉出昆冈剑号巨阙珠称夜光果珍李柰菜重芥姜海咸河淡鳞潜羽翔'; +const g:any = globalThis; +const N=300; +fontSubset(ab, text, {sourceType:'ttf',outType:'woff2'}); // warmup +g.__wt.flagDecode=0; g.__wt.xDecode=0; g.__wt.yTriplet=0; +import('perf_hooks').then(({performance})=>{ + const t0=performance.now(); + for(let i=0;i{ + for(let i=0;i<50;i++) fontSubset(ab, text, opt); + const s = new Session(); + s.connect(); + await new Promise(r=>s.post('Profiler.enable',()=>r())); + await new Promise(r=>s.post('Profiler.start',()=>r())); + for(let i=0;i<2000;i++) fontSubset(ab, text, opt); + const prof:any = await new Promise(r=>s.post('Profiler.stop',(_,v)=>r(v))); + writeFileSync('/tmp/prof.json', JSON.stringify(prof)); + console.log('profile written, samples=', prof.profile.samples.length); +})(); diff --git a/vendor/fonteditor-core/lib/ttf/table/glyf.js b/vendor/fonteditor-core/lib/ttf/table/glyf.js index 20186b0..fc3b0e6 100644 --- a/vendor/fonteditor-core/lib/ttf/table/glyf.js +++ b/vendor/fonteditor-core/lib/ttf/table/glyf.js @@ -95,8 +95,10 @@ var _default = exports.default = _table.default.create('glyf', [], { var numberOfContours = view.getInt16(vOff, false); /** 非(component 引用的) simple 字形走快路径;compound 及 component 走完整 parse */ if (numberOfContours >= 0 && !componentGids[index]) { - /** 优化310: 快路径——读 header(bbox) + endPtsOfContours(供 metrics),存原始字节引用, - * 跳过 instructions/flags/坐标解码(省 parseSimpleGlyf,glyph.read 第一热点)。 */ + /** 优化310+313: 快路径——读 header(bbox) + 最后一个 endPt(算 _totalPoints 供 metrics), + * 存原始字节引用,跳过 instructions/flags/坐标解码(省 parseSimpleGlyf,glyph.read 第一热点)。 + * 优化313: 不再分配 endPtsOfContours 数组——下游(optimizettf 快路径分支、sizeof/write 拷贝 + * 原始字节)均不消费它,_totalPoints 只需最后一个 endPt 即可算出。 */ var glyfObj = {}; glyfObj.xMin = view.getInt16(vOff + 2, false); glyfObj.yMin = view.getInt16(vOff + 4, false); @@ -104,13 +106,9 @@ var _default = exports.default = _table.default.create('glyf', [], { glyfObj.yMax = view.getInt16(vOff + 8, false); glyfObj._origGlyfRef = { buffer: fullBuf, byteOffset: fullBufOff + gStart, length: gEnd - gStart }; if (numberOfContours > 0) { - var endPts = new Array(numberOfContours); - for (var ei2 = 0; ei2 < numberOfContours; ei2++) { - endPts[ei2] = view.getUint16(vOff + 10 + ei2 * 2, false); - } - glyfObj.endPtsOfContours = endPts; glyfObj._numContours = numberOfContours; - glyfObj._totalPoints = endPts[numberOfContours - 1] + 1; + /** 最后一个 endPt 在 vOff + 10 + (numContours-1)*2,+1 即总点数 */ + glyfObj._totalPoints = view.getUint16(vOff + 10 + (numberOfContours - 1) * 2, false) + 1; } else { glyfObj._numContours = 0; glyfObj._totalPoints = 0;