热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

macOSRetina显示屏上OpenJDK11Swing等宽字体渲染问题的解决方案

本文探讨了在macOSRetina显示屏上使用OpenJDK11开发代码编辑器时遇到的等宽字体渲染问题,并提供了详细的分析和可能的解决方案。

在开发一个代码编辑器时,我遇到了一个仅在 macOS Retina 显示屏上使用 OpenJDK 11 时出现的等宽字体渲染问题。以下是两个屏幕截图的对比,顶部是使用 OpenJDK 11(版本 11.0.5 HotSpot),底部是使用 JDK 8(可能是 Apple / Oracle JDK 8):

macOS Retina 显示屏上 OpenJDK 11 Swing 等宽字体渲染问题

从图中可以看出,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 时:

enter image description here

此时,根据 FontRenderContext#getStringBounds 计算的字体进度为 17.0(通过灰色矩形可视化),但实际渲染略窄。当字体大小为 33 时:

enter image description here

这进一步证实了问题的复杂性。目前,我正在寻找一种不改变整个实现的解决方案,比如通过设置某些系统属性来解决问题。如果您有任何建议或遇到类似问题,请分享您的经验。


推荐阅读
  • 主要用了2个类来实现的,话不多说,直接看运行结果,然后在奉上源代码1.Index.javaimportjava.awt.Color;im ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 导航栏样式练习:项目实例解析
    本文详细介绍了如何创建一个具有动态效果的导航栏,包括HTML、CSS和JavaScript代码的实现,并附有详细的说明和效果图。 ... [详细]
  • 使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
    本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ... [详细]
  • 在前两篇文章中,我们探讨了 ControllerDescriptor 和 ActionDescriptor 这两个描述对象,分别对应控制器和操作方法。本文将基于 MVC3 源码进一步分析 ParameterDescriptor,即用于描述 Action 方法参数的对象,并详细介绍其工作原理。 ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • 在使用 DataGridView 时,如果在当前单元格中输入内容但光标未移开,点击保存按钮后,输入的内容可能无法保存。只有当光标离开单元格后,才能成功保存数据。本文将探讨如何通过调用 DataGridView 的内置方法解决此问题。 ... [详细]
  • MySQL索引详解与优化
    本文深入探讨了MySQL中的索引机制,包括索引的基本概念、优势与劣势、分类及其实现原理,并详细介绍了索引的使用场景和优化技巧。通过具体示例,帮助读者更好地理解和应用索引以提升数据库性能。 ... [详细]
  • 探讨如何从数据库中按分组获取最大N条记录的方法,并分享新年祝福。本文提供多种解决方案,适用于不同数据库系统,如MySQL、Oracle等。 ... [详细]
  • 在Oracle数据库中,使用Dbms_Output.Put_Line进行输出调试时,若单行字符超过255个,则会遇到ORA-20000错误。本文介绍了一种有效的方法来处理这种情况,通过创建自定义包和视图,实现对长字符串的分割和正确输出。 ... [详细]
author-avatar
晓志1998_809
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有