OpenType 字体的 Firefox 呈现与字体规范不匹配
Firefox rendering of OpenType font does not match the font specification
我正在通过 Google 字体 API / CSS.
加载 OpenType 网络字体 Open Sans
在 Chrome43 (Linux+Windows) 和 Internet Explorer 11 (Windows) 中,浏览器完全按照字体中指定的方式呈现文本。但是,在 Firefox 38.0.5 中,某些字符的文本宽度 and/or 间距呈现不同。所有字体变体均为默认值 ("normal")。
例如,我们可以使用字符 1
、a
、b
和 i
。 Open Sans "unitsPerEm"是2048,所以在18.0px的字号下,根据1/u * p * c * w where u = 2048,上面每个字符的30个字符的宽度应该是这样的, p = 18.0, c = 30, w为每个字符的前进宽度(Wolfram Alpha equation).
+----------------------------------------+-----------+
| char | font(px) | numChars | advance | width(px) |
+------+----------+----------+-----------+-----------+
| 1 | 18.0 | 30 | 1171 | 308.76 |
| a | 18.0 | 30 | 1139 | 300.322 |
| b | 18.0 | 30 | 1255 | 330.908 |
| i | 18.0 | 30 | 518 | 136.582 |
+----------------------------------------+-----------+
本(JSFiddle)使用canvas方法measureText
输出1
、a
各30个字符的像素宽度, b
,和 i
。
Chrome 文本长度与预期值完全匹配:
Firefox Linux 文本长度与除 a
以外的任何字符都不匹配,即使在考虑到 Firefox 不提供亚像素精度这一事实后也是如此:
我已经确认 canvas 报告的宽度确实是 Chrome 和 Firefox 输出的宽度 -- 下图显示红色背景,带有 Chrome 的黑色文本,Firefox 的白色文本——根据 Gimp "Measure" 工具,宽度与上面的输出相匹配。 Firefox 的 b
和 i
太宽,1
太窄:
附带说明一下,Firefox Windows 文本长度甚至与 Firefox Linux 不一致——a
和 b
宽度现在符合预期,但 1
和 i
仍然不正确:
这是一个干净的 Firefox 配置文件,具有默认设置且未安装任何扩展。
谁能解释一下这是怎么回事,以及如何强制 Firefox 根据字体规范呈现字体?
UPDATE:在 Windows 上,将首选项 gfx.font_rendering.directwrite.enabled
设置为 true
可以解决问题(我认为这是 Firefox 默认设置硬件加速可用,即使硬件加速不可用,此设置也会强制启用它,例如在我的测试 VMWare 系统上)。 DirectWrite 已成为 Windows 上 Chrome 中的默认设置 since version 37. The Linux behavior is still unexplained. This blog post 在 Windows 上解释了有关 Firefox 中 DirectWrite 渲染的更多信息。
(这个答案总结了问题评论中提出的要点,以及问题发布后所做的一系列额外研究。)
由于 various and complex 原因,并非所有 browser/OS/font 大小组合都以相同的方式呈现到屏幕上,它们也不总是遵循字体规范。因此,一般来说,应以避免需要对文本进行像素完美定位的方式创建应用程序。
亚像素文本渲染配置
关于配置特定 browser/OS 组合以支持子像素文本渲染的一些评论:
Windows
- 支持和启用 DirectWrite(相对于旧的 GDI 方法)的浏览器确实倾向于支持线性、无提示、亚像素文本定位,因此能够(并且通常会)遵循字体前进宽度规范.这包括 Chrome 37+ and Firefox 4+。
- 当硬件加速不可用时,Firefox 默认禁用 DirectWrite,但可以通过将配置 属性
gfx.font_rendering.directwrite.enabled
设置为 true
. 来启用它
- Chrome 37+ DirectWrite 默认开启,但可以通过设置标志
Disable DirectWrite
. 禁用
- Internet Explorer (9+?) DirectWrite 默认开启,但可以通过设置兼容模式禁用。
Linux
Configure your display for anti-aliasing and sub-pixel text rendering by setting up fontconfig for subpixel rendering (usually via Gnome or KDE display manager settings, but can be done manually via fontconfig config files), installing freetype-freeworld (freetype with non-free subpixel rendering support), and adding Xft.lcdfilter: lcddefault
into ~/.Xresources
for applications without fontconfig support. Set the correct type of subpixel rendering based on your LCD display type.
- 即使底层显示器支持并配置为子像素渲染,浏览器行为似乎也不一致。
- Chrome 的最新版本(44 个测试)似乎支持线性、无提示、子像素文本定位,因此通常遵循字体规范。在启用 RGB 子像素文本渲染的 KDE 4.14 上测试。
- Firefox(38.0.5 测试)似乎进行非线性提示定位,因此不遵循字体规范,即使显示器配置为子像素渲染。我还没有找到强制 Firefox 使用亚像素文本渲染的方法。
Mac OS/X
暂无该平台的信息。
像素级完美定位
如果尽管困难重重,但要构建一个需要像素完美文本定位和检查的应用程序,那么通常有两种方法可以解决:
1) 基于 Canvas 或 DOM 的文本 width/height 测量:参见 Mike Kamermans (Pomax) 的 Calculate text width with JavaScript. See also Font.js。
2) 使用OpenType.js从源字体确定文本尺寸,这比上面的方法有效时更快,但并非在所有情况下都有效。
我正在通过 Google 字体 API / CSS.
加载 OpenType 网络字体Open Sans
在 Chrome43 (Linux+Windows) 和 Internet Explorer 11 (Windows) 中,浏览器完全按照字体中指定的方式呈现文本。但是,在 Firefox 38.0.5 中,某些字符的文本宽度 and/or 间距呈现不同。所有字体变体均为默认值 ("normal")。
例如,我们可以使用字符 1
、a
、b
和 i
。 Open Sans "unitsPerEm"是2048,所以在18.0px的字号下,根据1/u * p * c * w where u = 2048,上面每个字符的30个字符的宽度应该是这样的, p = 18.0, c = 30, w为每个字符的前进宽度(Wolfram Alpha equation).
+----------------------------------------+-----------+ | char | font(px) | numChars | advance | width(px) | +------+----------+----------+-----------+-----------+ | 1 | 18.0 | 30 | 1171 | 308.76 | | a | 18.0 | 30 | 1139 | 300.322 | | b | 18.0 | 30 | 1255 | 330.908 | | i | 18.0 | 30 | 518 | 136.582 | +----------------------------------------+-----------+
本(JSFiddle)使用canvas方法measureText
输出1
、a
各30个字符的像素宽度, b
,和 i
。
Chrome 文本长度与预期值完全匹配:
Firefox Linux 文本长度与除 a
以外的任何字符都不匹配,即使在考虑到 Firefox 不提供亚像素精度这一事实后也是如此:
我已经确认 canvas 报告的宽度确实是 Chrome 和 Firefox 输出的宽度 -- 下图显示红色背景,带有 Chrome 的黑色文本,Firefox 的白色文本——根据 Gimp "Measure" 工具,宽度与上面的输出相匹配。 Firefox 的 b
和 i
太宽,1
太窄:
附带说明一下,Firefox Windows 文本长度甚至与 Firefox Linux 不一致——a
和 b
宽度现在符合预期,但 1
和 i
仍然不正确:
这是一个干净的 Firefox 配置文件,具有默认设置且未安装任何扩展。
谁能解释一下这是怎么回事,以及如何强制 Firefox 根据字体规范呈现字体?
UPDATE:在 Windows 上,将首选项 gfx.font_rendering.directwrite.enabled
设置为 true
可以解决问题(我认为这是 Firefox 默认设置硬件加速可用,即使硬件加速不可用,此设置也会强制启用它,例如在我的测试 VMWare 系统上)。 DirectWrite 已成为 Windows 上 Chrome 中的默认设置 since version 37. The Linux behavior is still unexplained. This blog post 在 Windows 上解释了有关 Firefox 中 DirectWrite 渲染的更多信息。
(这个答案总结了问题评论中提出的要点,以及问题发布后所做的一系列额外研究。)
由于 various and complex 原因,并非所有 browser/OS/font 大小组合都以相同的方式呈现到屏幕上,它们也不总是遵循字体规范。因此,一般来说,应以避免需要对文本进行像素完美定位的方式创建应用程序。
亚像素文本渲染配置
关于配置特定 browser/OS 组合以支持子像素文本渲染的一些评论:
Windows
- 支持和启用 DirectWrite(相对于旧的 GDI 方法)的浏览器确实倾向于支持线性、无提示、亚像素文本定位,因此能够(并且通常会)遵循字体前进宽度规范.这包括 Chrome 37+ and Firefox 4+。
- 当硬件加速不可用时,Firefox 默认禁用 DirectWrite,但可以通过将配置 属性
gfx.font_rendering.directwrite.enabled
设置为true
. 来启用它
- Chrome 37+ DirectWrite 默认开启,但可以通过设置标志
Disable DirectWrite
. 禁用
- Internet Explorer (9+?) DirectWrite 默认开启,但可以通过设置兼容模式禁用。
- 当硬件加速不可用时,Firefox 默认禁用 DirectWrite,但可以通过将配置 属性
Linux
Configure your display for anti-aliasing and sub-pixel text rendering by setting up fontconfig for subpixel rendering (usually via Gnome or KDE display manager settings, but can be done manually via fontconfig config files), installing freetype-freeworld (freetype with non-free subpixel rendering support), and adding Xft.lcdfilter: lcddefault
into ~/.Xresources
for applications without fontconfig support. Set the correct type of subpixel rendering based on your LCD display type.
- 即使底层显示器支持并配置为子像素渲染,浏览器行为似乎也不一致。
- Chrome 的最新版本(44 个测试)似乎支持线性、无提示、子像素文本定位,因此通常遵循字体规范。在启用 RGB 子像素文本渲染的 KDE 4.14 上测试。
- Firefox(38.0.5 测试)似乎进行非线性提示定位,因此不遵循字体规范,即使显示器配置为子像素渲染。我还没有找到强制 Firefox 使用亚像素文本渲染的方法。
Mac OS/X
暂无该平台的信息。
像素级完美定位
如果尽管困难重重,但要构建一个需要像素完美文本定位和检查的应用程序,那么通常有两种方法可以解决:
1) 基于 Canvas 或 DOM 的文本 width/height 测量:参见 Mike Kamermans (Pomax) 的 Calculate text width with JavaScript. See also Font.js。
2) 使用OpenType.js从源字体确定文本尺寸,这比上面的方法有效时更快,但并非在所有情况下都有效。