idDelta 和 idRangeOffset 在 TrueType 字体中都可以是非零吗?

Can idDelta and idRangeOffset both be non zero in TrueType fonts?

是否有可能在 TrueType 字体的 cmap 格式 4 中,段的 idDelta 和 idRangeOffset 都非零?如果是,为什么?

如果从 glyphIndexArray 获取的字形索引可以是字体制造商想要的任何值,为什么还需要添加 idDelta?

根据 https://docs.microsoft.com/en-us/typography/opentype/otspec140/cmap#format-4-segment-mapping-to-delta-values,这没有意义,因为非零的 idRangeOffset 意味着解析器需要参考 glyphIdArray,这不涉及 idDelta 值,而 idRangeOffset:0 表示段的字形 ID 基于将 idDelta 添加到字符代码偏移量,并且 而不是 使用 glyphIdArray.

所以回答你的问题:“如果从 glyphIndexArray 中获取的字形索引可以是字体制造商想要的任何字形索引,你为什么需要添加 idDelta?”,原因是“因为这根本不是发生的事情”。

引用规范:

If the idRangeOffset value for the segment is not 0, the mapping of character codes relies on glyphIdArray. The character code offset from startCode is added to the idRangeOffset value. This sum is used as an offset from the current location within idRangeOffset itself to index out the correct glyphIdArray value. This obscure indexing trick works because glyphIdArray immediately follows idRangeOffset in the font file. The C expression that yields the glyph index is:

*(idRangeOffset[i]/2 + (c - startCount[i]) + &idRangeOffset[i])

The value c is the character code in question, and i is the segment index in which c appears. If the value obtained from the indexing operation is not 0 (which indicates missingGlyph), idDelta[i] is added to it to get the glyph index. The idDelta arithmetic is modulo 65536.

If the idRangeOffset is 0, the idDelta value is added directly to the character code offset (i.e. idDelta[i] + c) to get the corresponding glyph index. Again, the idDelta arithmetic is modulo 65536.

虽然规范假设您知道 C 的工作原理,但现在的人却不知道:前面的 * 意味着我们正在计算相对于文件开头的字节偏移量。 & 的意思是“这个东西的内存位置”(虽然在这种情况下它意味着字节偏移到我们的字体文件中),所以我们在字节位置添加一个数字(idRangeOffset[i]/2 + (c - startCount[i])) ith 范围偏移量 (&idRangeOffset[i]),这给了我们一个新的偏移量。如果我们从与该数字对应的字节偏移量开始读取字体字节,我们将在正确的位置读取我们的字形 ID。

是的。非零 idRangeOffset 标识 glyphIdArray 的一个元素,从中获取字形索引。注意晦涩的措辞。如果该元素包含 0,则字形 ID 为 0,即缺失的字形。否则,将 idDelta 添加到元素中的值以获得字形 ID。这允许不同的段使用具有不同结果的 glyphIdArray 的相同部分,从而产生更紧凑的子表。

不过有一个问题。 2020 年 6 月,我发现 iPhone 6 和 7,运行 iOS 12.4.6,如果 idRangeOffset 不为零,则假定 idDelta 为零。子表与 Windows 和 HarfBuzz 渲染器一起正常工作。不知道iOS12.5.5的解释是否固定,MacOS的情况也没有。这样的错误会持续这么久表明这种优化很少被应用——它只在不寻常的情况下可用。