November 26, 2014

Java Swing <3 fontconfig == true?

Actually, false. But it can be true!

The out of box experience of Java Swing applications can be a little bit like rolling a 6-sided dice expecting a number between 2 and 4,25. Actually rolling a 4,25 is very unlikely, but then again having Swing fit perfectly in with native tool-kits is also not really possible. Even so, you have a 36 chance to roll a number that is within your range of “acceptable” numbers. The same is true of Swing, for the most part, it works quite all right. However font rendering can be an issue.

I have had Swing draw bad fonts on Windows XP/7, Mac OS, Free BSD and GNU/Linux. I have also had Swing draw beautifully on all platforms. It really seems to be a bit of a gamble. Provided your font settings are set just so, and the planets align, Swing will look amazing. But when Swing gets confused, it can get really confused.

In my current setup neither OpenJDK nor Oracle’s JDK wanted to pick up my settings properly, leading either to blurred, distorted or what must be the spawn of Dagon trying to write a love letter to the moon.

Luckily there are a number of fixes. If you are running on Oracle’s JDK or OpenJDK chances are you can fix your fonts by adding the following either to _JAVA_OPTIONS or to your supplied as start-up arguments for your app:

-Dawt.useSystemAAFOntSettings=foo

Where foo is one of:

  • off, false or default - No anti-aliasing
  • on - Full anti-aliasing
  • gasp - Use the font’s built-in hinting instructions
  • LCD or lcd_hrgb - Anti-aliasing tuned for LCD monitors
  • lcd_hbgr - Alternative LCD monitor setting
  • lcd_vrgb - Alternative LCD monitor setting
  • lcd_vbgr - Alternative LCD monitor setting

source: ArchWiki: Java Fonts - Sun JRE

If that still doesn’t fix it, and you have a GTK configuration:

-Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel

Unfortunately, neither of the above fixed it for me and I had to resort to other methods, hacks and Viking voodoo.

The problem for me is that the JDK does it’s own font rendering using a built-in version of fontconfig, and since I use the Infinality patches I really need the JDK to use my system configuration for fontconfig.

Luckily, there is a solution. If you are on Ubuntu you can find a patched version in Launchpad. Arch users find it in AUR. Fedora users…? Didn’t find a ready package so I built my own.

1. Download rpm sources for OpenJDK

$ yumdownloader --source java-1.8.0-openjdk

2. Grab freefont patches

I downloaded this file from the AUR jdk8-openjdk-infinality. Which contains the two patches I am interested in.

  • 004_add-fontconfig.patch
  • 005_enable-infinality.patch

If we take a quick glance in the patches we find:

004_add-fontconfig.patch:
	+    LDFLAGS_SUFFIX_linux := -lfontconfig -lawt $(LIBM)

005_enable-infinality.patch:
	+/* Use Infinality patches as default */
	+#define INFINALITY
	+
	 #include "jni.h"
	 #include "jni_util.h"
	 #include "jlong.h"
	@@ -38,6 +41,10 @@
	 #include FT_SIZES_H
	 #include FT_OUTLINE_H
	 #include FT_SYNTHESIS_H
	+#ifdef INFINALITY
	+#include FT_LCD_FILTER_H
	+#include <fontconfig/fontconfig.h>
	+#endif

We are linking to system fontconfig and add in LCD filtering. The rest of 005 are just instructions for fontconfig to respect system settings with regards to anti-aliasing, LCD filtering and the auto-hinter.

3. Patch RPM .spec file

All we need to do is copy the two patch files to ~/rpmbuild/SOURCES and tell the .spec file that we would like these applied to the OpenJDK source code before building.

First add the patch files:

# Infinality patch
Patch3263: java-1.8.0-openjdk-infinality-add-fontconfig.patch
Patch3264: java-1.8.0-openjdk-infinality-enable-infinality.patch

Then to apply them:

%patch3263
%patch3264

Where these should end up is not that big of a mystery, OpenJDK comes with a couple of patches by default. The numbers 3263 and 3264 were chosen “randomly”, so as to not interfere with any pre-existing numbers.

4. Build!

$ rpmbuild -ba ~/rpmbuild/SPECS/java-1.8.0-openjdk-infinality.spec

After running this, you might as well go have a cup of coffee, as it could take a couple of minutes.

Whenever it is done though, all that is needed is to install the fixed JDK:

$ yum reinstall ~/rpmbuild/RPMS/java-*.rpm

Your mileage may vary, we at cozy labs take no responsibility.

© Sebastian Hörberg 2018

Powered by Hugo & Kiss.