« Scala Puzzlers, part... | Main | PDF/DOC/PPT in-brows... »

Making anti-aliasing in Java work

Feb 17 2009, 12:45 MSK |  [  Java  ]

Today I had quite a bad (although, eventually successful) experience of trying to fix anti-aliasing in JDK. The problem is that it is not on by default (at least for those members of the fringe who use something slick like XMonad instead of monstrosities like Gnome) and to turn it on one needs to set the awt.useSystemAAFontSettings Java VM property to one of the supported values (e.g. gasp, or lcd).

Now, I'm not really keen on changing the code of every Java application I happen to run on my machine, nor can I add -Dawt.useSystemAAFontSettings=lcd to every Java command line (did they really mean it?!). I started to look for a method to set properties globally, and of course I found suggestions of using swing.properties file. In retrospect, that wasn't a smart thing to try: I wanted to set AWT property, not Swing one, so eventually (by reading JDK source code) I found out that Java wasn't loading all the properties from the file, only those few which it knew, and it was obscure about the one I needed.

Fast-forward several hours, I found out that there is another interesting file: accessibility.properties. Although JDK only sets the properties that thinks can appear in the file (which isn't very helpful), one of the properties there is really a big step towards the solution, its key is assistive_technologies. This property value is a class name which gets instantiated some time during AWT initialization. Now, if only we could create a class which sets the abominable anti-aliasing property when instantiated, it would solve the problem once and for all... Or would it?

We need one more piece of the puzzle: suppose we have the class compiled, how do we make JRE see it, so that it could load it. If JRE doesn't have it in its classpath, an AWTError would be thrown during assistive technologies initialization. Setting classpath on the command line is not going to help us: we specificially wanted to do without changing Java command lines. Setting CLASSPATH environment variable won't help either: as per java(1) man, if classpath is set on the command line, it overrides the CLASSPATH variable completely. And putting the class/jar file into JRE lib directory doesn't make it visible to the system classloader — bummer!

Good news: we have the JDK source code and if one knows what to look for, its usually not that hard to find. The thing I was looking for was the list of initial classpath elements. Actually, I could just append my anti-aliasing workaround class into rt.jar, but that's not very flexible. So I found the list, and after a list of JRE jars there was a directory: "classes/"! Since the search is done starting from the JRE home directory, I could just create the classes directory there and put my class there.

My workaround class code follows:

package hacks;

public class AntialiasingHack {
  public AntialiasingHack() {
    System.setProperty("awt.useSystemAAFontSettings", "lcd_hrgb");
  }
}

Contents of jre/lib/accessibility.properties (or ~/.accessibility.properties) file:

assistive_technologies=hacks.AntialiasingHack

PS: If you have a more clean solution (other than filing an RFE for a generic startup properties file loader, arguing that it won't make the system more insecure than it already is, and waiting for several yearsjiffies to get it actually implemented and delivered in the next version of JDK), please-please-pretty-please tell me!

Comments:

what about the lib/ext-directory ?
put your class in a (hacks.)jar in that directory

if that works it wouldn't be a that big hack - it would be the documented way for extension.

Posted by kurt on February 17, 2009 at 03:24 PM MSK #

From my reading of http://java.sun.com/javase/6/docs/technotes/guides/2d/flags.html#aaFonts the flag defaults to true which should result in the system anti-alias setting being used.

Is the problem that you want a setting different than the system setting or that XMonad doesn't support the system flag (presumably something from fontconfig or other odg standard)?

Posted by Mike Duigou on February 17, 2009 at 09:30 PM MSK #

The problem is that it's not XMonad which doesn't follow some predefined rules for setting a flag (for one, it's a window manager, not a desktop environment, thus it shouldn't deal with anything except windows). The problem is that AWT only supports Gnome (and probably has some small hack for KDE), and unless you follow some obscure rules for setting their anti-aliasing properties, you won't get anti-aliasing working.

There is a different setting: in fontconfig, but AWT doesn't respect it.

Posted by Ivan Tarasov on February 17, 2009 at 09:46 PM MSK #

/**
* Enable antialiasing for every JComponent in the application. Do this at
* the start of an application. Swing lead Scott Violet has said,
* "swing.aatext is not a documented or supported property. It's meant for
* internal testing and may go away at any point."
* <p/>
* See http://www.javalobby.org/forums/thread.jspa?forumID=61&threadID=14179
*
* @param state true to enable
*/
public static void enableAntiAliasing(boolean state)
{
System.setProperty("swing.aatext", String.valueOf(state));
}

The doc says awt.useSystemAAFontSettings was introduced in 1.6. The above will work pre 1.6

Posted by Jonathan Johnson on February 17, 2009 at 10:39 PM MSK #

what's more interesting, it seems that it's possible to set swing.aatext using swing.properties file, but it's impossible to set awt.useSystemAAFontSettings there, so the functionality was actually crippled in some sense :-)

Posted by Ivan Tarasov on February 17, 2009 at 11:32 PM MSK #

cat /usr/local/bin/java
#!/bin/sh
/opt/jre/bin/java -Dawt.useSystemAAFontSettings=lcd $*

This solution works for me without troubles.

Posted by Aekold Helbrass on February 18, 2009 at 01:13 PM MSK #

Post a Comment:
  • HTML Syntax: NOT allowed