mirror of
https://github.com/2234839/web-font.git
synced 2026-09-12 20:11:51 +08:00
perf(os2): read 改用直接 DataView 批量读取
OS/2.read 原走 struct 通用 read(逐字段 switch 分发 + reader.read 调用), 与已优化的 write(优化176 直接 view)不对称。改为手写每个字段的 view 直读, 按 version(0/1/2+)决定读到哪,补默认值逻辑不变。 字段值完全一致(version/achVendID/sxHeight 验证),OS/2.read 微基准 思源 6.2→1.7μs(-73%)、令东 5.5→0.6μs(-89%),端到端约 -1% (readBuffer 占比小),与 write 对称后可推广到其他 struct 通用 read 表。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d575d55540
commit
d6d94e201e
84
vendor/fonteditor-core/lib/ttf/table/OS2.js
vendored
84
vendor/fonteditor-core/lib/ttf/table/OS2.js
vendored
@ -92,28 +92,72 @@ var _default = exports.default = _table.default.create('OS/2', [['version', _str
|
||||
return writer;
|
||||
},
|
||||
read: function read(reader, ttf) {
|
||||
var format = reader.readUint16(this.offset);
|
||||
/**
|
||||
* 优化309: 按 format 缓存 os2head 表类。
|
||||
* 原实现每次 read 都 struct.slice + _table.create 动态建类(_createClass + Object.assign prototype),
|
||||
* 是 OS/2 parse 的主开销(prof 实测 ObjectAssign 占稳态 4.2%)。
|
||||
* format 仅 0/1/2+ 三种,struct 切片固定,表类按 format 缓存复用。
|
||||
* 另:去掉 Object.assign(os2Fields, tbl),直接在 tbl 上补默认字段。
|
||||
* 优化322: 直接 DataView 批量读取 OS/2 全部字段,绕过 struct 通用 read 的逐字段 switch 分发。
|
||||
* 与 write 对称——write 已用直接 view(优化176),read 同样手读。
|
||||
* OS/2 read 是思源/令东 readBuffer 内前列热点(思源 9.4μs),通用 struct read 每字段一次 switch + reader.read 调用,
|
||||
* 直接 view 读 46 个字段省掉全部分发开销。
|
||||
* 字段顺序与 struct 定义严格对应(version → ... → usMaxContext),按 format 决定读到哪。
|
||||
*/
|
||||
var OS2Head = _os2HeadCache[format];
|
||||
if (!OS2Head) {
|
||||
var struct = this.struct;
|
||||
if (format === 0) {
|
||||
struct = struct.slice(0, 39);
|
||||
} else if (format === 1) {
|
||||
struct = struct.slice(0, 41);
|
||||
}
|
||||
OS2Head = _table.default.create('os2head', struct);
|
||||
_os2HeadCache[format] = OS2Head;
|
||||
var view = reader.view;
|
||||
var p = view.byteOffset + this.offset;
|
||||
var tbl = {};
|
||||
tbl.version = view.getUint16(p, false); p += 2;
|
||||
tbl.xAvgCharWidth = view.getInt16(p, false); p += 2;
|
||||
tbl.usWeightClass = view.getUint16(p, false); p += 2;
|
||||
tbl.usWidthClass = view.getUint16(p, false); p += 2;
|
||||
tbl.fsType = view.getUint16(p, false); p += 2;
|
||||
tbl.ySubscriptXSize = view.getUint16(p, false); p += 2;
|
||||
tbl.ySubscriptYSize = view.getUint16(p, false); p += 2;
|
||||
tbl.ySubscriptXOffset = view.getUint16(p, false); p += 2;
|
||||
tbl.ySubscriptYOffset = view.getUint16(p, false); p += 2;
|
||||
tbl.ySuperscriptXSize = view.getUint16(p, false); p += 2;
|
||||
tbl.ySuperscriptYSize = view.getUint16(p, false); p += 2;
|
||||
tbl.ySuperscriptXOffset = view.getUint16(p, false); p += 2;
|
||||
tbl.ySuperscriptYOffset = view.getUint16(p, false); p += 2;
|
||||
tbl.yStrikeoutSize = view.getUint16(p, false); p += 2;
|
||||
tbl.yStrikeoutPosition = view.getUint16(p, false); p += 2;
|
||||
tbl.sFamilyClass = view.getUint16(p, false); p += 2;
|
||||
/* Panose 10 字节 */
|
||||
tbl.bFamilyType = view.getUint8(p); p += 1;
|
||||
tbl.bSerifStyle = view.getUint8(p); p += 1;
|
||||
tbl.bWeight = view.getUint8(p); p += 1;
|
||||
tbl.bProportion = view.getUint8(p); p += 1;
|
||||
tbl.bContrast = view.getUint8(p); p += 1;
|
||||
tbl.bStrokeVariation = view.getUint8(p); p += 1;
|
||||
tbl.bArmStyle = view.getUint8(p); p += 1;
|
||||
tbl.bLetterform = view.getUint8(p); p += 1;
|
||||
tbl.bMidline = view.getUint8(p); p += 1;
|
||||
tbl.bXHeight = view.getUint8(p); p += 1;
|
||||
/* unicode range 4×Uint32 */
|
||||
tbl.ulUnicodeRange1 = view.getUint32(p, false); p += 4;
|
||||
tbl.ulUnicodeRange2 = view.getUint32(p, false); p += 4;
|
||||
tbl.ulUnicodeRange3 = view.getUint32(p, false); p += 4;
|
||||
tbl.ulUnicodeRange4 = view.getUint32(p, false); p += 4;
|
||||
/* achVendID 4 字节 */
|
||||
tbl.achVendID = String.fromCharCode(view.getUint8(p), view.getUint8(p + 1), view.getUint8(p + 2), view.getUint8(p + 3));
|
||||
p += 4;
|
||||
tbl.fsSelection = view.getUint16(p, false); p += 2;
|
||||
tbl.usFirstCharIndex = view.getUint16(p, false); p += 2;
|
||||
tbl.usLastCharIndex = view.getUint16(p, false); p += 2;
|
||||
tbl.sTypoAscender = view.getInt16(p, false); p += 2;
|
||||
tbl.sTypoDescender = view.getInt16(p, false); p += 2;
|
||||
tbl.sTypoLineGap = view.getInt16(p, false); p += 2;
|
||||
tbl.usWinAscent = view.getUint16(p, false); p += 2;
|
||||
tbl.usWinDescent = view.getUint16(p, false); p += 2;
|
||||
/* version 0 到此(39 字段,p 推进 78 字节)*/
|
||||
if (tbl.version >= 1) {
|
||||
tbl.ulCodePageRange1 = view.getUint32(p, false); p += 4;
|
||||
tbl.ulCodePageRange2 = view.getUint32(p, false); p += 4;
|
||||
}
|
||||
var tbl = new OS2Head(this.offset).read(reader, ttf);
|
||||
|
||||
// 补齐其他 version 的字段(直接在 tbl 上赋值,避免 Object.assign 创建 os2Fields 中间对象)
|
||||
if (tbl.version >= 2) {
|
||||
tbl.sxHeight = view.getInt16(p, false); p += 2;
|
||||
tbl.sCapHeight = view.getInt16(p, false); p += 2;
|
||||
tbl.usDefaultChar = view.getUint16(p, false); p += 2;
|
||||
tbl.usBreakChar = view.getUint16(p, false); p += 2;
|
||||
tbl.usMaxContext = view.getUint16(p, false); p += 2;
|
||||
}
|
||||
/* 补齐缺失字段的默认值(与原逻辑一致,供 size/write 使用)*/
|
||||
if (tbl.ulCodePageRange1 === undefined) tbl.ulCodePageRange1 = 1;
|
||||
if (tbl.ulCodePageRange2 === undefined) tbl.ulCodePageRange2 = 0;
|
||||
if (tbl.sxHeight === undefined) tbl.sxHeight = 0;
|
||||
@ -121,6 +165,8 @@ var _default = exports.default = _table.default.create('OS/2', [['version', _str
|
||||
if (tbl.usDefaultChar === undefined) tbl.usDefaultChar = 0;
|
||||
if (tbl.usBreakChar === undefined) tbl.usBreakChar = 32;
|
||||
if (tbl.usMaxContext === undefined) tbl.usMaxContext = 0;
|
||||
/* 同步推进 reader.offset(与 struct read 行为一致:read 完最后一个字段后 reader.offset 在表末尾)*/
|
||||
reader.offset = p - view.byteOffset;
|
||||
return tbl;
|
||||
},
|
||||
size: function size(ttf) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user