Web 浏览器如何实现字体回退?

How do web browsers implement font fallback?

我想知道字体后备在字体 shaping/rendering 堆栈中的位置。换句话说,在什么时候检测到丢失的字形以及如何替换它们?

我在 this 文档中看到 FontConfig 工具执行字体回退 "based on glyph coverage transparently."

所以问题是:

  1. 这个算法究竟是如何工作的?
  2. 这是大多数浏览器使用的标准算法吗 - webkit、gecko(可能不是 IE)?
  3. 基于确实存在的字体中缺失字形的字体回退与 CSS 字体回退(指定在字体完全缺失时依次使用哪些字体)有何关系?

编辑:我找到了 this 文档,它解释了 FontConfig 的 "what",但没有 "how." 问题 1 是关于 "how."

总而言之 - 这个 post 实际上只与一件事有关 - 当字体中缺少字形时字体回退如何工作。

浏览器中的字体回退(相对于 OS 中的字体回退)基于两件事:

  1. CSS 规范,它给出了用于回退的字体,并且
  2. 进行文本整形的文本引擎。

CSS 规范在这方面相当简单,只是使用系统名称给出了字体列表,但无法保证几种可能的 "catch all" 字体与来自计算机到计算机(例如,没有理由假设 serif 映射到 TimesTimes New Roman)。

文本引擎使用的回退算法完全取决于引擎,但通常在字形查找步骤中启动:文本引擎看到一串代码点,并尝试使用字体来塑造该字符串。对于序列中的每个点,它检查字体是否有匹配的字形(通过查询 CMAP table 和 subtables),或者告诉引擎可能有一个字形的规则仅当通过 GSUB 机制遵循更多代码点时才使用(例如,单个字母 etc 没有字形的字体,但带有字形 & 和一个 GSUB 规则,说明序列 e+t+c 应该在文本中替换为单个字形 &),当它完成累积时有点像 "unit of points",它塑造文本并将其交还给任何要求它塑造文本的人。

如果在字形查找期间发现字体不包含任何让引擎塑造特定代码点的内容(即 运行 通过 CMAP 数据以及 GSUB 规则仍然显示 "there is no glyph") 那么文本引擎可以做两件事:

  1. 放弃。没有字形,而是使用定义为字形 ID 0 的 .notdef 轮廓,并且通常会为您提供带有可爱的空框(字体人亲切地称为 "tofu")或问号的文本。
  2. 尝试字体回退,它将尝试另一种字体来为不支持的代码点找到字形。

使用回退时,引擎可以查找备选字体列表,直到:(a) 找到字形,或 (b) 列表耗尽,此时引擎 放弃,将使用 .notdef 字形。引擎是从原始字体还是从列表中的最后一个字体中获取 .notdef 字形,完全取决于引擎(尽管通常它会与第一个字体一起使用,以便于阅读)

在任何地方都没有为此定义的"standard"算法;字体回退基本上是文本引擎作者提供的一种便利机制,就像浏览器如何带有书签管理器一样(方便,不属于任何规范)。就 OpenType 而言,对于引擎是否应该在未找到字形时提供 .notdef 服务,或者它是否应该提供它可以塑造的部分,然后在其他地方找到丢失的字形,没有任何要求,并以这种方式呈现文本。 CSS 暗示您的文本引擎应该至少有某种形式的字体回退,但它没有指定它应该如何工作,或者它应该何时启动。

在 Windows:

Firefox 字体回退

Firefox 对 CJK 字形和 non-CJK 字形有不同的算法:

non-CJK

non-CJK 算法非常简单:尝试给定 html 语言的所有配置字体。这些包括配置 font.name.{generic}.{language} 和配置列表 font.name-list.{generic}.{language}.

中日韩文

由于字形、编码和语言变体的数量众多,CJK 本质上很复杂。 Firefox 使用动态搜索算法来解析字形。

  1. 使用给定 html 语言的配置字体。
  2. 使用配置的 日语 (ja) 字体。
  3. 使用配置的 韩文 (ko) 字体。
  4. 使用配置的简体中文 (zh-CN)字体。
  5. 使用配置的繁体中文(香港) (zh-HK) 字体。
  6. 使用配置的繁体中文(台湾) (zh-TW) 字体。

该算法目前在 GetLangPrefs(). In both CJK and non-CJK cases, there is a limit of how many fonts to be searched (32) 中实现。脚本搜索顺序是硬编码的,因此目前无法由用户配置。

Firefox 回退算法的优势在于,由于其动态特性,可以搜索更多字体,从而最大限度地减少用户遇到丢失字形的机会。此外,通过了解搜索顺序,用户可以操纵配置来为缺失的字形选择所需的字体。

缺点是不一致:因为搜索列表是硬编码的,所以所有网页都优先使用某些语言的字体。例如,tag-missing 韩文网页中可能会使用日文优化字体。另外,由于尝试了更多的字体,性能可能会下降。

Chromium 字体回退

与 Firefox 不同,Chromium 选择了一种更静态的方法来搜索字体。 Chromium 没有将 CJK 大小写和浏览字体列表,而是为每个脚本硬编码了几种 "core" 字体。 Chromium 假定这些字体应该始终可用,因此只搜索这些字体。脚本到字体的映射可以在 InitializeScriptFontMap() 中找到。目前无法由用户配置此映射。

该算法的优点是简单性、一致性和性能,但代价是灵活性和可配置性。

实施方式将来可能会发生变化。 https://gist.github.com/CrendKing/c162f5a16507d2163d58ee0cf542e695.

中有更多详细信息