扯闲篇
首发于扯闲篇

Windows 对字体 `cmap` table 兼容性的问题

`cmap` 是字体中负责字符编码映射的表, 它可以含有多个子表, 这些子表的功能与格式定义各不相同.

Windows 中默认使用的是 [cmap_format_4 platformID="3" platEncID="1"] 这个子表. 由于该子表采用 UCS-2 存储编码, 所以它只能支持 U+0000 - U+FFFF 的编码, Unicode 将这一段称为 BMP (Basic Multilingual Plane, 基本多文种平面).

后来 Unicode 收录的字符越来越多, BMP 不够用了, 于是 format 4 也相应的进化出了扩展版本: [cmap_format_12 platformID="3" platEncID="10"]. 它采用 UCS-4 存储编码, 编码范围为 U+00000000 - U+7FFFFFFF. 比如现在常用的 emoji 字符的编码范围在 U+1FXXX, 如果使用旧的 format 4 是无法支持的.

微软文档中对此的描述是:

Fonts providing Unicode encoded UCS-4 character support for Windows 2000 and later, need to have a subtable with platform ID 3, platform specific encoding ID 1 in format 4; and in addition, need to have a subtable for platform ID 3, platform specific encoding ID 10 in format 12. Please note, that the content of format 12 subtable, needs to be a super set of the content in the format 4 subtable. The format 4 subtable needs to be in the cmap table to enable backward compatibility needs.

苹果的描述是:

If a font has a 3/10 cmap (Windows, UCS-4), it should also have a 3/1 (Windows, BMP-only) cmap as well for backwards compatibility with Windows XP. The two should have identical mappings for Unicode's Basic Multilingual Plane.

也就是说, format 4 记录 BMP 内的部分, 而 format 12 作为 format 4 的超集, 不但包含了前者的内容, 还记录了超出 BMP 的部分, 不过要同时保留 format 4 以向下兼容. 因此对于含有超出 BMP 范围字符的字体, 往往同时包含 format 4 与 format 12 两个子表.

但奇怪的是, 虽然文档中说保留 format 4 是为了向下兼容, 但是在新的 Windows 系统中 (甚至 Windows 10), 如果一个字体没有 format 4 只有 format 12 的话, 是无法使用的. Apple 与 Google 等厂商显然认为同时包含两个子表是一种脱裤子放屁的行为, 所以一些较新的字体, 比如 OS X El Capitan 附带的 Hiragino Sans 系列字体, 或是 Android 附带的 Noto Color Emoji 字体, 都是不包含 format 4 的, 这使得这些字体在 Windows 中无法使用, 就像那样:

虽然之前通过 Windows 10 的官方渠道反映过这个问题然并卵, 望帮转.

编辑于 2015-07-06

文章被以下专栏收录