cal*_*edo 7 java fonts swing kerning ligature
在 java 17 上玩 swing 时,我遇到了一些奇怪的故障:当启用字体连字并切换到连字重字体时,例如Fira Code,选择部分连字文本会产生以下效果:
当考虑字距调整密集型字体(例如Microsoft Windows 11 的新默认字体Segoe UI或 )时,会发生以下故障:Segoe UI Variable
这种行为似乎至少从 Java 1.8 开始就表现出来了,我节省了时间和硬盘空间检查以前的版本。而且不同的 LAF 似乎不会以任何方式影响故障。我认为罪魁祸首似乎是java.desktop/javax.swing.text.PlainView,尤其是其将文本视为可分割片段的方式,仅重新渲染“损坏”的文本updateDamage#668及其更改边界框的计算。
我发现一直有效的唯一一致的解决方法是停用字距调整和连字。我还尝试将我自己的 PlainView 类挂接到 swing 中,但其架构积极尝试阻止此类修复。
最后我想问一些问题,这对于理解问题非常有帮助:
感谢您的帮助!我在下面附上了源代码以及我当前的机器配置。
编辑:
该问题似乎也存在于 Mac OSX Big Sur 和 Java 17 上,导致使用字距调整和连字时出现伪影。为了重现,我使用了默认Helvetica字体。这可能暗示了 jdk 故障的原因。
import javax.swing.*;
import java.awt.*;
import java.awt.font.*;
import java.util.*;
/**
Tested on: Edition Windows 11 Pro
Version 22H2
OS build 22623.875
Experience Windows Feature Experience Pack 1000.22636.1000.0
openjdk 17.0.4.1 2022-08-12
OpenJDK Runtime Environment Temurin-17.0.4.1+1 (build 17.0.4.1+1)
OpenJDK 64-Bit Server VM Temurin-17.0.4.1+1 (build 17.0.4.1+1, mixed mode, sharing)
**/
public class Main {
private static final boolean TEST_KERNING = true;
private static final boolean TEST_LIGATURES = true;
private static final String TEST_FONT = "Segoe UI Variable";
private static final Number TEST_FONT_SIZE = 40;
private static final Number TEST_FONT_WIDTH = TextAttribute.WEIGHT_BOLD;
public static void main(String[] args) throws Exception {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
Map<TextAttribute, Object> textAttributes = new HashMap<>();
textAttributes.put(TextAttribute.FAMILY, TEST_FONT);
textAttributes.put(TextAttribute.SIZE, TEST_FONT_SIZE);
textAttributes.put(TextAttribute.WEIGHT, TEST_FONT_WIDTH);
if(TEST_KERNING)
textAttributes.put(TextAttribute.KERNING, TextAttribute.KERNING_ON);
if(TEST_LIGATURES)
textAttributes.put(TextAttribute.LIGATURES, TextAttribute.LIGATURES_ON);
Font font = Font.getFont(textAttributes);
JTextField txtInput = new JTextField();
txtInput.setFont(font);
JFrame frame = new JFrame("Demo");
frame.setSize(400, 100);
frame.add(txtInput);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
SwingUtilities.invokeAndWait(() ->
frame.setVisible(true)
);
}
}
Run Code Online (Sandbox Code Playgroud)