作者:晓志1998_809 | 来源:互联网 | 2024-11-18 09:38
在开发一个代码编辑器时,我遇到了一个仅在 macOS Retina 显示屏上使用 OpenJDK 11 时出现的等宽字体渲染问题。以下是两个屏幕截图的对比,顶部是使用 OpenJDK 11(版本 11.0.5 HotSpot),底部是使用 JDK 8(可能是 Apple / Oracle JDK 8):
从图中可以看出,OpenJDK 11 渲染的字体比 JDK 8 更宽。这是一个严重的问题,因为我在计算等宽列的宽度时使用了 FontRenderContext#getStringBounds
方法。使用默认的等宽字体(看起来像是 Menlo)和字体大小 14,每个字符的宽度应该是 8 像素,这在 JDK 8 上是正确的,但在 OpenJDK 11 上却变成了 8.5 像素。例如,第一行非注释行包含 38 个字符,在 JDK 8 上需要 38 * 8 * 2 = 608 像素,但在 OpenJDK 11 上则需要约 646 像素。
更奇怪的是,这个问题似乎是由使用 AttributedText
渲染 Graphics2D#drawString
实例引起的。如果我改为使用纯文本并调用 g.setFont
,OpenJDK 11 的渲染结果与 JDK 8 完全一致。因此,问题可能出在渲染 AttributedCharacterIterator
的特定实现上。
为了找到解决方案,我进行了进一步的调试。我发现差异出现在 ExtendedTextSourceLabel#createGV
和更深层次的 SunLayoutEngine#layout
调用中,最终调用了本机代码。虽然字体描述符相同,但在 JDK 8 中,字形数据中的 _positions
被设置为整数值,而在 OpenJDK 11 中,它们被设置为小数值(且不一定是 0.5 的倍数),这表明问题可能与 macOS 本机字体支持有关。
此外,我还发现这个问题取决于字体大小,而不仅仅是字体是否“本机”或捆绑在一起。例如,使用类路径上的 Inconsolata.ttf 字体,当字体大小为 32 时:
此时,根据 FontRenderContext#getStringBounds
计算的字体进度为 17.0(通过灰色矩形可视化),但实际渲染略窄。当字体大小为 33 时:
这进一步证实了问题的复杂性。目前,我正在寻找一种不改变整个实现的解决方案,比如通过设置某些系统属性来解决问题。如果您有任何建议或遇到类似问题,请分享您的经验。