test/jdk/javax/swing/UIDefaults/6302464/bug6302464.java
author serb
Fri, 16 Feb 2018 12:24:38 -0800
changeset 49090 82c1fe23c469
parent 47216 71c04702a3d5
permissions -rw-r--r--
8196196: Headful tests should not be run in headless mode Reviewed-by: prr

/*
 * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

import java.util.Map;
import java.util.HashSet;
import java.awt.Color;
import java.awt.Toolkit;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.image.BufferedImage;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIDefaults;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.plaf.basic.BasicLookAndFeel;
import static java.awt.RenderingHints.KEY_TEXT_ANTIALIASING;
import static java.awt.RenderingHints.KEY_TEXT_LCD_CONTRAST;
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_GASP;
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR;
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB;
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR;
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB;
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_OFF;

/**
 * @test
 * @bug 6302464
 * @author Alexandr Scherbatiy
 * @summary Allow programmatic enabling of subpixel anti-aliasing in Swing
 */
public class bug6302464 {

    public static void main(String[] args) throws Exception {
        SwingUtilities.invokeAndWait(bug6302464::testAntialiasingProperties);
    }

    private static void testAntialiasingProperties() {
        testCustomLAF();
        testFontRenderingContext();
        testAntialiasingHints();
        testLAFAAHints();
    }

    private static void testCustomLAF() {
        try {
            testCustomLAF(false);
            testCustomLAF(true);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static void testCustomLAF(boolean useAAHints) throws Exception {
        CustomLookAndFeel customLAF = new CustomLookAndFeel(useAAHints);
        UIManager.setLookAndFeel(customLAF);

        JLabel label = new JLabel();
        Object aaHint = label.getClientProperty(KEY_TEXT_ANTIALIASING);
        Object lcdContrastHint = label.getClientProperty(KEY_TEXT_LCD_CONTRAST);

        if (aaHint != customLAF.getAAHint()) {
            throw new RuntimeException("AA hint from custom L&F is not set");
        }

        if (lcdContrastHint != customLAF.getLCDContarstHint()) {
            throw new RuntimeException("AA hint from custom L&F is not set");
        }
    }

    private static final Object[] ANTIALIASING_HINTS = {
        VALUE_TEXT_ANTIALIAS_GASP,
        VALUE_TEXT_ANTIALIAS_LCD_HRGB,
        VALUE_TEXT_ANTIALIAS_LCD_HBGR,
        VALUE_TEXT_ANTIALIAS_LCD_VRGB,
        VALUE_TEXT_ANTIALIAS_LCD_VBGR
    };

    private static void testFontRenderingContext() {
        for (Object aaHint : ANTIALIASING_HINTS) {
            testFontRenderingContext(aaHint);
        }
    }

    private static void testFontRenderingContext(Object aaHint) {

        JLabel label = new JLabel("Test");
        label.putClientProperty(KEY_TEXT_ANTIALIASING, aaHint);
        FontRenderContext frc = label.getFontMetrics(
                label.getFont()).getFontRenderContext();

        if (!aaHint.equals(frc.getAntiAliasingHint())) {
            throw new RuntimeException("Wrong aa hint in FontRenderContext");
        }
    }

    private static void testAntialiasingHints() {
        setMetalLookAndFeel();

        HashSet colorsAAOff = getAntialiasedColors(VALUE_TEXT_ANTIALIAS_OFF, 100);

        if (colorsAAOff.size() > 2) {
            throw new RuntimeException("Wrong number of antialiased colors.");
        }

        HashSet colorsAAOnLCD100 = getAntialiasedColors(
                VALUE_TEXT_ANTIALIAS_LCD_HRGB, 100);

        if (colorsAAOnLCD100.size() <= 2) {
            throw new RuntimeException("Wrong number of antialiased colors.");
        }

        HashSet colorsAAOnLCD250 = getAntialiasedColors(
                VALUE_TEXT_ANTIALIAS_LCD_HRGB, 250);

        if (colorsAAOnLCD250.size() <= 2) {
            throw new RuntimeException("Wrong number of antialiased colors.");
        }

        if (colorsAAOnLCD100.equals(colorsAAOnLCD250)) {
            throw new RuntimeException("LCD contarst is not used.");
        }
    }

    private static HashSet getAntialiasedColors(Object aaHint, int lcdContrast) {

        JLabel label = new JLabel("ABCD");
        label.setSize(label.getPreferredSize());
        label.putClientProperty(KEY_TEXT_ANTIALIASING, aaHint);
        label.putClientProperty(KEY_TEXT_LCD_CONTRAST, lcdContrast);

        int w = label.getWidth();
        int h = label.getHeight();

        BufferedImage buffImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = buffImage.createGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, w, h);
        label.paint(g);
        g.dispose();

        HashSet<Color> colors = new HashSet<>();

        for (int i = 0; i < w; i++) {
            for (int j = 0; j < h; j++) {
                Color color = new Color(buffImage.getRGB(i, j));
                colors.add(color);
            }
        }

        return colors;
    }

    private static void setMetalLookAndFeel() {
        setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
    }

    private static void setLookAndFeel(String lafClass) {
        try {
            UIManager.setLookAndFeel(lafClass);
        } catch (final UnsupportedLookAndFeelException ignored) {
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static void testLAFAAHints() {

        for (LookAndFeelInfo lafInfo : UIManager.getInstalledLookAndFeels()) {
            testLAFAAHints(lafInfo);
        }
    }

    private static final String[] EXCLUDED_LAFS = {"CDE/Motif"};

    private static boolean isExcludedLAF(LookAndFeelInfo lafInfo) {
        for (String excludedLaf : EXCLUDED_LAFS) {
            if (lafInfo.getName().equals(excludedLaf)) {
                return true;
            }
        }
        return false;
    }

    private static void testLAFAAHints(LookAndFeelInfo lafInfo) {
        setLookAndFeel(lafInfo.getClassName());

        Object uiAAHint = UIManager.getDefaults().get(KEY_TEXT_ANTIALIASING);
        Object uiLCDContrastHint = UIManager.getDefaults().get(
                KEY_TEXT_LCD_CONTRAST);

        Object aaHints = Toolkit.getDefaultToolkit().
                getDesktopProperty("awt.font.desktophints");

        if (isExcludedLAF(lafInfo)) {
            if (uiAAHint != null || uiLCDContrastHint != null) {
                throw new RuntimeException("Rendering hints set for excluded L&F");
            }
        } else if (aaHints instanceof Map) {
            Map map = (Map) aaHints;

            if (uiAAHint != map.get(KEY_TEXT_ANTIALIASING)) {
                throw new RuntimeException("UI defaults contains wrong aa hint");
            }

            if (uiLCDContrastHint != map.get(KEY_TEXT_LCD_CONTRAST)) {
                throw new RuntimeException("UI defaults contains wrong"
                        + "lcd contrast hint");
            }
        } else if (uiAAHint != null || uiLCDContrastHint != null) {
            throw new RuntimeException("Rendering hints set for empty desktop"
                    + "properties");
        }
    }

    private static class CustomLookAndFeel extends BasicLookAndFeel {

        private final boolean useAAHints;

        public CustomLookAndFeel(boolean useAAHints) {
            this.useAAHints = useAAHints;
        }

        @Override
        public String getDescription() {
            return getName();
        }

        @Override
        public String getName() {
            return "Custom L&F";
        }

        @Override
        public String getID() {
            return getName();
        }

        @Override
        public boolean isNativeLookAndFeel() {
            return false;
        }

        @Override
        public boolean isSupportedLookAndFeel() {
            return true;
        }

        @Override
        protected void initClassDefaults(UIDefaults table) {
            super.initClassDefaults(table);
            table.put(KEY_TEXT_ANTIALIASING, getAAHint());
            table.put(KEY_TEXT_LCD_CONTRAST, getLCDContarstHint());
        }

        private Object getAAHint() {
            return useAAHints ? VALUE_TEXT_ANTIALIAS_GASP : null;
        }

        private Object getLCDContarstHint() {
            return useAAHints ? 115 : null;
        }
    }
}