Search code examples
javaswingpaintcomponentantialiasing

How to get antialiasing mode as used in text components (underlying system/OS setting)


So I'm trying to make a small text preview with line numbers by inheriting from a JTextArea and overwriting paintComponent().

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;

import javax.swing.JFrame;
import javax.swing.JTextArea;

public class PreviewPane extends JTextArea {

    public PreviewPane() {
        setText( "first row\nsecond row\nthird row" );
    }

    @Override
    protected void paintComponent( Graphics graphics ) {
        Graphics2D g = (Graphics2D) graphics;
        int emWidth = g.getFontMetrics().stringWidth( "m" );
        int lineHeight = g.getFontMetrics().getHeight();
        int baseLine = g.getFontMetrics().getAscent();

        g.translate( 2 * emWidth, 0 );
        super.paintComponent( g );

        g.translate( -2 * emWidth, 0 );

        g.setColor( getBackground() );
        g.fillRect( 0, 0, 2 * emWidth - 1, getHeight() - 1 );

        g.setColor( Color.LIGHT_GRAY );
        g.drawLine( 2 * emWidth - 1, 0, 2 * emWidth - 1, getHeight() - 1 );

        g.setColor( Color.BLACK );

        // "guessed" value for antialiasing
        g.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB );
        for ( int i = 1; i <= 3; i++ ) {
            g.drawString( String.valueOf( i ), getMargin().left, getMargin().top + baseLine + ( i - 1 ) * lineHeight );
        }
    }

    public static void main( String[] args ) {
        JFrame frame = new JFrame();
        frame.setBounds( 0, 0, 640, 480 );
        frame.getContentPane().add( new PreviewPane(), BorderLayout.CENTER );
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setVisible( true );
    }
}

In the marked line, I set the antialiasing hint to RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB. This will lead to the exact font rendering as the text area:
Rendering with <code>RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB</code>

Omitting this line just uses the default:
Rendering with default

But this will not work on every system. Querying the FontRenderContext or the originally assigned rendering hints from the graphics object just return Default antialiasing text mode, which cannot be the mode used for rendering the text area.

So my question is: How to obtain the actually used antialiasing mode from the text component/java system?

Note: I'm not trying to implement a fully fledged line numbering editor, so the "inefficiency" of this solution is irrelevant. Also, I came across this issue several times in the past years when directly rendering text in component's paint methods, so this is just an example.


Solution

  • Digging through the Java lib source reveals that font rendering of text area (and presumably the other text components as well) use internal class sun.swing.SwingUtilities2. This holds the desired information internally and queries it from the java.awt.Toolkit.

    So the code to get text antialiasing information from the system is:

    Toolkit tk = Toolkit.getDefaultToolkit();
    Map map = (Map) tk.getDesktopProperty( sun.awt.SunToolkit.DESKTOPFONTHINTS );
    g.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, map.get( RenderingHints.KEY_TEXT_ANTIALIASING ) );
    

    The content of the map is (in my case)

    {Text-specific antialiasing enable key=LCD HRGB antialiasing text mode, Text-specific LCD contrast key=120}
    

    which is the exact information needed.

    Note that sun.awt.SunToolkit.DESKTOPFONTHINTS is forbidden API and therefore should be replaced by "awt.font.desktophints".