网页浏览器如何实现字体替换?

13

我想了解字体替换在字形和渲染堆栈中的位置。换句话说,何时检测到缺失的字形并如何进行替换?

我在此文档中看到FontConfig工具可以基于字形覆盖率透明地进行字体替换。

因此,问题如下:

  1. 这个算法究竟是如何工作的?
  2. 这是大多数浏览器使用的标准算法吗,例如webkit、gecko(可能不包括IE)?
  3. 存在某种字体中缺少字形的字体替换与CSS字体替换有何关联(当完全缺少字体时指定依次使用哪些字体)?

编辑:我找到了这篇文章,它解释了FontConfig的“内容”,但没有解释“如何”。问题1涉及“如何”。

总结一下 - 这篇文章实际上只涉及一件事 - 当字体中缺少字形时,字体替换是如何工作的。

2个回答

16

浏览器中的字体回退(与操作系统不同)基于两个因素:

  1. CSS规范,指定回退使用的字体
  2. 文本引擎,进行文本整形处理。

CSS规范在这方面相对简单,只是给出使用它们的系统名称的字体列表,但有几种可能的“万能”字体,这些字体在从计算机到计算机并没有任何保证(例如,没有理由假设serif映射到TimesTimes New Roman)。

文本引擎使用的回退算法完全取决于引擎,但通常在字形查找步骤中启动: 文本引擎看到一串代码点,并尝试使用字体来整形该字符串。对于序列中的每个点,它都检查字体是否具有匹配的字形(通过咨询CMAP表和子表),或者规则告诉引擎只有更多的代码点跟随时才可能使用字形,通过GSUB机制(例如,一个没有单独字母etc字形但有一个表示序列e+t+c应该被替换为单个字形&的GSUB规则),当它完成了这种“代码点单元”的累积,它将整形文本并将其交给请求它整形文本的任何东西。

如果在字形查找期间,发现字体不包含任何可以让引擎整形特定代码点的内容(即在运行CMAP数据和GSUB规则时仍然显示“没有字形”),那么文本引擎可以做两件事:

  1. 放弃。没有字形,使用定义为字形ID 0的.notdef轮廓,通常会给出带有可爱的空框(字体专业人士称之为“豆腐”)或问号的文本。
  2. 尝试字体回退,其中它将尝试使用另一种字体来查找不支持的代码点的字形。
  3. 在使用回退时,引擎可以按照备选字体列表逐个进行搜索,直到:(a) 找到一个字形或者 (b) 列表用尽,此时引擎必须放弃,并使用 .notdef 字形。无论引擎从原字体还是列表中的最后一个字体中获取 .notdef 字形,都完全取决于引擎(尽管通常为了易读性,它会选择第一个字体)

    目前没有在任何地方定义这个“标准”算法;字体回退基本上是文本引擎作者提供的方便机制,就像浏览器带有书签管理器一样(方便,但不属于任何规范)。就 OpenType 而言,它并没有要求引擎应该仅提供 .notdef 当找不到字形时,或者它是否应该提供它可以处理的部分内容,然后在其他地方查找缺失的字形,以此来呈现文本。CSS 暗示你的文本引擎应该至少具备某种形式的字体回退功能,但它并没有指定它应该如何运作或何时启动。


谢谢 - 这真的很有启发性。我想了解更多关于字体回退在任何浏览器中是如何实现的,以便深入了解该过程。这似乎比“方便”要重要得多 - 很多 Web 内容都依赖于它。我假设回退不仅仅是到 CSS 字体回退列表(还是这样?)。我已经删除了 CSS 标签 - StackOverflow 坚持将其放在第一位,给人一种误导性的强调。我对 CSS 本身并不那么感兴趣 - 正如你指出的那样,与字体回退相比,规范非常微不足道。 - bright
编辑:我之前误解了。我以为CSS规范只处理字体完全缺失的情况下的字体回退。但是仔细阅读规范后,发现它确实涉及到缺失字形的情况。因此,我将接受您的答案。 - bright
它不是浏览器本身,而是“文本引擎”,例如Firefox和Chrome使用[harfbuzz](http://www.freedesktop.org/wiki/Software/HarfBuzz/),我相信IE依赖于[Uniscribe](https://msdn.microsoft.com/en-us/library/windows/desktop/dd317713%28v=vs.85%29.aspx)。是的,这绝对与CSS有关,字体是基于每个字形使用的(谢天谢地=D)。 - Mike 'Pomax' Kamermans
感谢您的回答和此贴文,它最近帮助了我。您知道在XeTeX中是否有希望获得这样的回退吗?目前,使用*TeX进行自动处理(例如,当Pandoc将Markdown转换为PDF时)的一个主要问题是输出中缺少来自意外脚本的字符。ucharclasses包(由您创建!)有所帮助,但由于XeTeX已经使用Harfbuzz,如果回退可以工作,那就太好了。 - ShreevatsaR
我不确定那个问题有多大意义,主要是因为XeTeX是一种排版标记语言。与网页不同,它是一个完全受控的出版链,因此您可以明确地控制使用哪些字体。对于XeTeX,当需要排版不可用于所使用的字体的字形时,您希望事情失败得更加彻底,这样您就可以更新源代码,以确保显式使用适当的替代方案。 - Mike 'Pomax' Kamermans
@ShreevatsaR 也许你正在寻找类似于 https://tex.stackexchange.com/questions/224584/define-fallback-font-for-specific-unicode-characters-in-lualatex 的东西?但即使如此:该解决方案依赖于您成为内容的合适编辑者,并注意使用哪些不在您选择的字体中的字符。当然,指导原则是“如果它不在您选择的字体中,请选择一个更完整的字体”,以保持类型的连贯性。 - Mike 'Pomax' Kamermans

6
在Windows系统中:

Firefox字体回退

Firefox有不同的算法来处理CJK字形和非CJK字形:

非CJK

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

CJK

CJK天生就是复杂的,由于其大量的字形、编码和语言变种。因此Firefox使用动态搜索算法来解决字形问题。

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

该算法目前在GetLangPrefs()中实现。在CJK和非CJK情况下,搜索字体的数量有限制(32)。脚本搜索顺序是硬编码的,因此目前无法由用户进行配置。

Firefox回退算法的优点是由于其动态性质,可以搜索更多的字体,从而最小化用户遇到缺失字形的机会。此外,通过了解搜索顺序,用户可以操作配置以选择缺失字形所需的字体。

缺点是不一致性:由于搜索列表是硬编码的,某些语言的字体会优先考虑所有网页。例如,在缺少标签的韩文网页上可能会使用日文优化字体。此外,由于尝试了更多的字体,性能可能会变差。

Chromium字体回退

与Firefox不同,Chromium选择了一种更静态的方法来搜索字体。Chromium不分CJK和非CJK情况,只为每个脚本硬编码几个“核心”字体,并假设这些字体应始终可用。映射脚本到字体可以在InitializeScriptFontMap()中找到。目前无法对此映射进行用户配置。

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

实现方式可能会在未来发生变化。更多详情请参见https://gist.github.com/CrendKing/c162f5a16507d2163d58ee0cf542e695

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接