oss

HarfBuzz 二十年:可读文字背后的那一次小小塑形调用

9 条来源 6 条一手来源 已翻译 2026年7月26号

正文
一页 16 世纪波斯纳斯塔利克体书法,黑色墨迹四周环绕粉色、金色与花卉纹样的边框。

Muhammad Husayn al-Tabrizi 写于 16 世纪的一叶纳斯塔利克体书法。彼此连缀的字母形态与层层叠放的附标,让软件进入叙述之前的塑形问题清晰可见。[9]

视频模式

本文包含 1 个可跳转的视频片段。

  1. 1 Behdad Esfahbod 在 Web Engines Hackfest 2026 上讲述 HarfBuzz 二十年 YouTube 视频

一串 Unicode 码位还没有成为可读文字。像素出现之前,软件要从字体中选出字形,依照书写系统的规则将它们组合、重排,再算出每个字形的进距与偏移。应用程序若把这项工作当成从字符查找图片,很快便会遇到连字、上下文变体、组合附标、可变字体轴、emoji,以及视觉顺序与存储顺序不同的文字系统。

HarfBuzz 为浏览器、操作系统、工具包、设计应用和游戏引擎完成中间这一步转换。它对外开放的塑形入口简短得近乎寻常,入口背后的规则与兼容预期却横跨众多字体和书写系统。这种反差贯穿 Behdad Esfahbod 在 2026 年 A Coruña Web Engines Hackfest 上录制的演讲 HarfBuzz at 20!。[1][2][3]

这场演讲也是一份格外清楚的开源维护研究。Esfahbod 把稳定的 C API 与数千项输出测试、Rust 移植、浏览器规模的性能工作和实验性的字体可编程能力连在一起。他从个人经历讲起,将项目追溯到一项持续多年的工作:让波斯文在开源系统中得到良好呈现;更早的一篇独立历史文章则解释了,这个眼前的问题如何长成共享基础设施。[7][8] 演示适合在视频中观看,下面的注解则把镜头转向演示所依赖的契约。

图片说明:题图翻拍自一叶 16 世纪波斯纳斯塔利克体书法。它呈现了上下文连写与附标定位的实物形态,性质是历史材料,与 HarfBuzz 的输出示例有所区别。[9]

0:46:一个小 API,命名了一次庞大的转换

Esfahbod 将 HarfBuzz 描述为一套字体平台,它包括 C 语言库 API、命令行工具,以及以核心塑形器为中心组织的若干部件。[1] 塑形器的基本契约可以准确表述:调用方提供一个 hb_font_t、一个装有 Unicode 码位的缓冲区,以及可选的排版特性。缓冲区还带有方向、文字系统和语言属性。hb_shape() 返回后,同一个缓冲区中保存的内容变为视觉顺序下的字形标识符与定位信息,包括水平、垂直进距和 x/y 偏移。[3]

这次原地修改本身就是契约的一部分。调用发生前,缓冲区表达编码文本;调用结束后,它成了针对某一字体的显示方案。客户端仍要负责选择和载入字体、按一致的属性切分 run、组织行与段落,以及绘制返回的字形。HarfBuzz 有意把职责收在完整文本排版引擎之前。[3][5] 因此,有用的集成图会把职责分界画清楚:

Unicode text → itemize and choose font → shape one run → position lines → draw glyphs

多数应用开发者适合经由平台或 UI 工具包接入这条流水线。团队若直接调用 HarfBuzz,也会接手各环节的接缝:字体回退、段落级双向文字处理、run 切分、断行,以及源文本与字形流之间的关系。拉丁字母的 “hello” 成功显示时,这些接缝几乎都还没有经受测试。一套最低限度的严肃测试样例应包括组合附标、一种从右向左的文字、连字、混合方向、可变设置、缺失字形,以及靠近已塑形序列的断行点。

约在 2:17,Esfahbod 强调 C API 与 ABI 在项目漫长的生命期内一直保持稳定。[1] 仓库对公共头文件明确给出了范围更窄的保证,同时允许源代码和内部数据组织继续演进。[5] 这里出现了第一条维护经验:调用方使用的词汇应当保持精简,复杂度则留在 API 之后消化。不过,符号层的稳定性只兑现了承诺的一半。塑形器可以保留全部函数签名,同时移动附标、改选连字,或返回让选择功能失效的 cluster。

5:23:兼容性成为一项经验标准

演讲对互操作历史的回顾始于与各平台塑形器逐项比对。Microsoft、Apple 与开源塑形器得出不同结果时,项目会比较输出,只有理由充分才采取不同处理。到 6:25,Esfahbod 说测试套件已经包含 6,000 多项塑形测试,浏览器与独立研究人员也在持续对引擎做模糊测试。[1] LWN 更早的报道补上了社会背景:各家塑形器曾经给出彼此不同的结果,而桌面端的广泛采用,让 HarfBuzz 成为共同处理文字系统与字体行为的地方。[7]

由此形成的反馈循环超出了版本号能够描述的范围。浏览器部署会暴露字体表、书写系统和畸形输入之间罕见的组合,问题报告随后缩减成测试用例。字体制作者会针对读者实际使用的塑形器做测试,这些字体又继续扩大实际生效的兼容范围。HarfBuzz 依然依据已发布的格式和塑形模型工作,而部署中的行为也成了证据,表明下游软件正在期待某一种具体答案。[1][5]

工程上的后果十分具体。替代版本的门槛落在真实输入与输出上的差分测试:字形 ID、顺序、位置、cluster、flag、错误和性能都要纳入比较。每次触发缺陷的字体和文本也应保留,因为简化成 ASCII 代用品,往往正好会删去触发问题的条件。模糊测试覆盖另一条轴线:解析器与塑形器会读取来源不可信的二进制字体,所以即使输入没有有效的视觉解释,“不崩溃,也没有内存错误”仍是一项必要性质。

广泛采用也让优化收益变得不对称。8:29 时,Esfahbod 讲到某些塑形负载取得了数倍提升,其中一部分工作源于 Chromium 基准测试。[1] 浏览器规模下的速度当然重要,可是一项优化若悄悄损害较少进入基准测试的文字系统,花掉的便是别人的正确性预算。他在结尾问答中的回应很有分量:阿拉伯文、天城文以及其他必须完成的工作,也要进入基准测试。性能套件会写入产品优先级;一套具有代表性的套件,能让高频路径之外的路径也得到保护。

Cluster 保存了返回文本的路线

字形塑形里的输入字符和输出字形没有一一对应关系。多个码位可以合成一个连字,一个字符也可以产生多个字形;附标会移动,字形还会重排。HarfBuzz 为每个输入码位携带一个 cluster 值,并在拆分、合并和重排的过程中传递这些值。cluster 文档仔细区分了这种记账单位与 Unicode 字素簇:它是字符流和字形流之间的映射,具体行为由缓冲区的 cluster level 控制。[4]

正是这份映射,让编辑操作能够贴合读者眼前所见。排版客户端用它放置光标、扩展选择范围、传递颜色及其他字符属性、从 PDF 提取文本,并判断一行可以在哪里安全断开。HarfBuzz 还能把某些字形位置标为不安全断点,因为单独塑形一个片段时,结果会与整段塑形不同。[3][4] 集成层若在绘制后丢弃 cluster 值,页面外观仍可保持正确,光标、搜索高亮、复制粘贴或自动换行却会继续出错。

因此,cluster 值值得进入一等测试。先塑形一个 run,再从每个候选断点切开,分别重塑各片段,并在预期可以安全断开的地方比较拼合结果。沿两个逻辑方向逐一移动光标,选择参与连字的文本,也选择带有多个组合附标的文本;还要确认界面采用的 cluster level 与编辑模型相符。虽然错误藏在控件层以下,这些不变量都会直接落到用户眼前。

这一区别也厘清了职责归属。HarfBuzz 报告分析已塑形 run 所需的信息,产品则决定自己的光标策略。代码编辑器、终端和出版系统可以选择不同的移动与选择行为。三者的具体做法可以各异,同时依照同一套映射工作;字形几何不承担重建映射的任务。

从 9:29 开始,HarfRust 继承了一项判定基准

Rust 部分原本很容易写成一次语言迁移,台上的叙述却把重点放在语义延续上。Esfahbod 回顾了几次以安全 Rust 完成塑形的尝试,接着解释 HarfRust 如何从 RustyBuzz 的一个分支发展而来,并进入范围更广的 Rust 字体工具链工作。12:30 时,他报告说早期的性能差距已经大幅缩小,余下差异仍以现有语料库为准衡量。13:33 时,一项 Servo 实验让 C++ 与 Rust 塑形器并行运行,并报告两者的差异。[1]

这种并行安排才是重要的架构。成熟的 C++ 版本成为 oracle,也就是判定基准,移植版本则继续积累信任。在字体字节、缓冲区属性、特性和文本完全相同的前提下,两个后端应当输出可以比较的字形序列、位置、cluster 和 flag。于是,每一处不一致都能成为规模小、可复现的调查,省去追着截图查问题的过程。这套方法也适用于字体排版之外:解析器、数据库、编译器或协议栈开展语义迁移时,让新旧版本同时影子处理具有生产特征的输入,会使迁移过程更安全。

当前 HarfRust 仓库直截了当地说明了自身范围。它以匹配 HarfBuzz 塑形器和 Unicode 功能为目标,并报告已通过大部分上游测试与模糊测试;其覆盖范围小于完整的 C++ 项目。系统集成、Graphite 塑形、阿拉伯文回退塑形器和其他一些部件尚未收入其中,字体解析则交给 read-fonts 工具链。README 还公开了已知差异与性能预期,内容保持原有颗粒度,没有把它们抹平成一枚“兼容”徽章。[6]

这种透明度会改变上线规划。团队在宣布替换之前,应先清点实际使用的 HarfBuzz 功能范围。接下来可以对代表性流量做影子运行、比较输出、设定明确的例外预算、按文字系统和字体测试性能,并在未解释差异仍然存在时保留回退方案。新版本带来了宝贵的内存安全属性;视觉兼容性、错误行为和延迟仍需分别验收。

这项移植也回应了约 2:47 提出的项目健康问题,当时 Esfahbod 谈到维护工作集中在少数人身上,bus factor 很低。[1] 第二套代码带来的维护者增长没有自动保障,平行代码库还会增加评审负担。不过,它可以把过去隐含的行为变成可移植的测试样例,吸引另一门语言的开发者参与,并显露哪些模块曾与某一解析器或平台紧密耦合。从长远看,迁移留下的成果既包括移植版本,也包括兼容性检验装置。

16:37:可编程字体移动了信任边界

演讲中最具探索意味的一节,设想把经过沙箱隔离的 WebAssembly 放进字体,让字体自行携带固定表格难以表达的塑形逻辑。[1] 演示把动机讲得很具体:复杂的阿拉伯文附标定位、递归组合的埃及象形文字,以及鲁格阿体书法的视觉定位,都在考验“通用塑形器解释静态表格”这一模型。若让专门逻辑跟随字体分发,字体设计师便能直接编码行为,少等数年才迎来新的表格格式与各引擎的共同支持。

这仍是一项研究方向,距离部署建议还有很长一段路。字体会从来源不可信的结构化数据,变成来源不可信的数据与程序行为的组合。任何生产设计都要严格限制内存和指令,规定确定性输出、稳定的宿主调用、缓存规则与版本协商,同时处理拒绝服务防护,并说明字符回映射如何服务无障碍功能。沙箱只能削减部分风险;页面可索取多少工作量、结果如何跨引擎复现,还要另行规定。

尽管如此,这项提议照亮了整场演讲。HarfBuzz 的成功,一部分来自它把持续变化的文字系统与字体知识集中在稳定的职责分界之后。HarfRust 检验这些知识能否在两套代码之间迁移,同时保持答案不变。可编程字体又提出下一步问题:其中一部分知识能否再次移动,从共享引擎进入字体专属的沙箱。每一次移动,都会改变谁可以创新、谁要负责标准化,以及兼容性测试应当在哪里运行。

对工程团队来说,眼前可做的事很朴素。把塑形作为语义子系统纳入工程管理,相关要求高于普通渲染辅助函数。明确保留各项输入属性,让 cluster 与安全 flag 一直传递到排版环节。使用真实的文字系统和字体测试输出,也纳入畸形输入。在性能工作中测量复杂文字系统。替换成熟基础设施时,先建立差分 oracle,再安排切换。HarfBuzz 最小的函数调用之所以宝贵,在于它的结果背后站着二十年积累下来的证据。

来源

  1. Web Engines Hackfest,“HarfBuzz at 20!”:Behdad Esfahbod 在 2026 年的演讲,本文嵌入的会议视频。
  2. Igalia,“Web Engines Hackfest 2026”:官方活动回顾、议程背景与演讲出处。
  3. HarfBuzz Manual,“Getting started with HarfBuzz”:塑形流水线、缓冲区属性、字形输出、定位与 flag 的官方说明。
  4. HarfBuzz Manual,“Clusters”:字符到字形的映射、cluster level、重排与编辑用途的官方说明。
  5. HarfBuzz 仓库:项目范围、公共 API 稳定性、部件、使用者、测试与安全指南的官方资料。
  6. HarfRust 仓库:兼容状态、架构、性能说明、已知差异与缺失集成的官方资料。
  7. LWN,“HarfBuzz brings professional typography to the desktop”(2017):独立撰写的项目历史与采用背景。
  8. Behdad Esfahbod 的个人项目历史与 2026 年演讲索引:作者出处,以及 HarfBuzz 背后的波斯文动机。
  9. Smithsonian Institution,“Page of calligraphy by Muhammad Husayn al-Tabrizi”,Wikimedia Commons:题图的来源与版权页面。
Previous OpenMRS 先是一套临床语法,才是一款医院应用

Recommended In oss

Matched by subject and format