热门标签 | 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

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


推荐阅读
  • java文本编辑器,java文本编辑器设计思路
    java文本编辑器,java文本编辑器设计思路 ... [详细]
  • ListView简单使用
    先上效果:主要实现了Listview的绑定和点击事件。项目资源结构如下:先创建一个动物类,用来装载数据:Animal类如下:packagecom.example.simplelis ... [详细]
  • 软件工程课堂测试2
    要做一个简单的保存网页界面,首先用jsp写出保存界面,本次界面比较简单,首先是三个提示语,后面是三个输入框,然 ... [详细]
  • 本文详细探讨了Java中的ClassLoader类加载器的工作原理,包括其如何将class文件加载至JVM中,以及JVM启动时的动态加载策略。文章还介绍了JVM内置的三种类加载器及其工作方式,并解释了类加载器的继承关系和双亲委托机制。 ... [详细]
  • 当unique验证运到图片上传时
    2019独角兽企业重金招聘Python工程师标准model:public$imageFile;publicfunctionrules(){return[[[na ... [详细]
  • springMVC JRS303验证 ... [详细]
  • 本文探讨了如何利用HTML5和JavaScript在浏览器中进行本地文件的读取和写入操作,并介绍了获取本地文件路径的方法。HTML5提供了一系列API,使得这些操作变得更加简便和安全。 ... [详细]
  • Django 使用slug field时遇到的问题 ... [详细]
  • 本文详细探讨了 PHP 中常见的 '未定义索引' 错误,包括其原因、解决方案及最佳实践。通过实例和代码片段,帮助开发者更好地理解和处理这一常见问题。 ... [详细]
  • 本文介绍如何在Grafana配置面板时,使用JSONNet获取数组中特定元素的位置,并将其应用于动态服务查询。 ... [详细]
  • Python3 中使用 lxml 模块解析 XPath 数据详解
    XPath 是一种用于在 XML 文档中查找信息的路径语言,同样适用于 HTML 文件的搜索。本文将详细介绍如何利用 Python 的 lxml 模块通过 XPath 技术高效地解析和抓取网页数据。 ... [详细]
  • 本文深入探讨了UNIX/Linux系统中的进程间通信(IPC)机制,包括消息传递、同步和共享内存等。详细介绍了管道(Pipe)、有名管道(FIFO)、Posix和System V消息队列、互斥锁与条件变量、读写锁、信号量以及共享内存的使用方法和应用场景。 ... [详细]
  • 本文探讨了如何通过一系列技术手段提升Spring Boot项目的并发处理能力,解决生产环境中因慢请求导致的系统性能下降问题。 ... [详细]
  • 本文提供了多种方法来计算给定年份和月份的起始日和结束日,并进一步探讨了如何根据年、月、周获取特定周的起始日和结束日。 ... [详细]
  • 本文深入探讨了 Delphi 中类对象成员的核心概念,包括 System 单元的基础知识、TObject 类的定义及其方法、TClass 的作用以及对象的消息处理机制。文章不仅解释了这些概念的基本原理,还提供了丰富的补充和专业解答,帮助读者全面理解 Delphi 的面向对象编程。 ... [详细]
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社区 版权所有