6302464: Allow programmatic enabling of subpixel anti-aliasing in Swing on ANY platform

Reviewed-by: serb, azvegint
This commit is contained in:
Alexander Scherbatiy 2015-08-24 16:06:36 +04:00
parent 49091ccf1d
commit d14c028db9
10 changed files with 387 additions and 132 deletions

View File

@ -991,9 +991,7 @@ public class AquaLookAndFeel extends BasicLookAndFeel {
"Tree.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[]{"ESCAPE", "cancel"}),};
table.putDefaults(defaults);
Object aaTextInfo = SwingUtilities2.AATextInfo.getAATextInfo(true);
table.put(SwingUtilities2.AA_TEXT_PROPERTY_KEY, aaTextInfo);
SwingUtilities2.putAATextInfo(true, table);
}
protected void initSystemColorDefaults(final UIDefaults table) {

View File

@ -26,7 +26,6 @@
package com.sun.java.swing.plaf.gtk;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.io.File;
import java.lang.ref.*;
@ -41,6 +40,8 @@ import javax.swing.text.DefaultEditorKit;
import com.sun.java.swing.plaf.gtk.GTKConstants.PositionType;
import com.sun.java.swing.plaf.gtk.GTKConstants.StateType;
import java.util.HashMap;
import java.util.Map;
import sun.awt.SunToolkit;
import sun.awt.UNIXToolkit;
import sun.awt.OSInfo;
@ -61,7 +62,7 @@ public class GTKLookAndFeel extends SynthLookAndFeel {
* We should assume ON - or some variation of ON as no GTK desktop
* ships with it OFF.
*/
static Object aaTextInfo;
static Map<Object, Object> aaTextInfo;
/**
* Solaris, or Linux with Sun JDS in a CJK Locale.
@ -1337,7 +1338,9 @@ public class GTKLookAndFeel extends SynthLookAndFeel {
if (fallbackFont != null) {
table.put("TitledBorder.font", fallbackFont);
}
table.put(SwingUtilities2.AA_TEXT_PROPERTY_KEY, aaTextInfo);
if (aaTextInfo != null) {
table.putAll(aaTextInfo);
}
}
protected void initSystemColorDefaults(UIDefaults table) {
@ -1477,7 +1480,8 @@ public class GTKLookAndFeel extends SynthLookAndFeel {
* XRender.
*/
gtkAAFontSettingsCond = !isSunCJK && SwingUtilities2.isLocalDisplay();
aaTextInfo = SwingUtilities2.AATextInfo.getAATextInfo(gtkAAFontSettingsCond);
aaTextInfo = new HashMap<>(2);
SwingUtilities2.putAATextInfo(gtkAAFontSettingsCond, aaTextInfo);
}
static ReferenceQueue<GTKLookAndFeel> queue = new ReferenceQueue<GTKLookAndFeel>();

View File

@ -39,6 +39,8 @@ import sun.swing.SwingUtilities2;
import sun.swing.plaf.synth.SynthIcon;
import com.sun.java.swing.plaf.gtk.GTKEngine.WidgetType;
import static java.awt.RenderingHints.KEY_TEXT_ANTIALIASING;
import static java.awt.RenderingHints.KEY_TEXT_LCD_CONTRAST;
/**
*
@ -115,10 +117,12 @@ class GTKStyle extends SynthStyle implements GTKConstants {
@Override
public void installDefaults(SynthContext context) {
super.installDefaults(context);
if (!context.getRegion().isSubregion()) {
context.getComponent().putClientProperty(
SwingUtilities2.AA_TEXT_PROPERTY_KEY,
GTKLookAndFeel.aaTextInfo);
Map<Object, Object> aaTextInfo = GTKLookAndFeel.aaTextInfo;
if (aaTextInfo != null && !context.getRegion().isSubregion()) {
context.getComponent().putClientProperty(KEY_TEXT_ANTIALIASING,
aaTextInfo.get(KEY_TEXT_ANTIALIASING));
context.getComponent().putClientProperty(KEY_TEXT_LCD_CONTRAST,
aaTextInfo.get(KEY_TEXT_LCD_CONTRAST));
}
}

View File

@ -556,8 +556,7 @@ public class WindowsLookAndFeel extends BasicLookAndFeel
* for both client property and UIDefaults.
* Also need to set up listeners for changes in these settings.
*/
Object aaTextInfo = SwingUtilities2.AATextInfo.getAATextInfo(true);
table.put(SwingUtilities2.AA_TEXT_PROPERTY_KEY, aaTextInfo);
SwingUtilities2.putAATextInfo(true, table);
this.aaSettings =
new FontDesktopProperty(SunToolkit.DESKTOPFONTHINTS);
}
@ -2402,9 +2401,8 @@ public class WindowsLookAndFeel extends BasicLookAndFeel
}
protected void updateUI() {
Object aaTextInfo = SwingUtilities2.AATextInfo.getAATextInfo(true);
UIDefaults defaults = UIManager.getLookAndFeelDefaults();
defaults.put(SwingUtilities2.AA_TEXT_PROPERTY_KEY, aaTextInfo);
SwingUtilities2.putAATextInfo(true, defaults);
super.updateUI();
}
}

View File

@ -377,7 +377,8 @@ public abstract class JComponent extends Container implements Serializable,
/**
* AA text hints.
*/
transient private Object aaTextInfo;
transient private Object aaHint;
transient private Object lcdRenderingHint;
static Graphics safelyGetGraphics(Component c) {
return safelyGetGraphics(c, SwingUtilities.getRoot(c));
@ -655,8 +656,10 @@ public abstract class JComponent extends Container implements Serializable,
uninstallUIAndProperties();
// aaText shouldn't persist between look and feels, reset it.
aaTextInfo =
UIManager.getDefaults().get(SwingUtilities2.AA_TEXT_PROPERTY_KEY);
aaHint = UIManager.getDefaults().get(
RenderingHints.KEY_TEXT_ANTIALIASING);
lcdRenderingHint = UIManager.getDefaults().get(
RenderingHints.KEY_TEXT_LCD_CONTRAST);
ComponentUI oldUI = ui;
ui = newUI;
if (ui != null) {
@ -4048,8 +4051,10 @@ public abstract class JComponent extends Container implements Serializable,
* @see #putClientProperty
*/
public final Object getClientProperty(Object key) {
if (key == SwingUtilities2.AA_TEXT_PROPERTY_KEY) {
return aaTextInfo;
if (key == RenderingHints.KEY_TEXT_ANTIALIASING) {
return aaHint;
} else if (key == RenderingHints.KEY_TEXT_LCD_CONTRAST) {
return lcdRenderingHint;
} else if (key == SwingUtilities2.COMPONENT_UI_PROPERTY_KEY) {
return ui;
}
@ -4091,8 +4096,11 @@ public abstract class JComponent extends Container implements Serializable,
* @see #addPropertyChangeListener
*/
public final void putClientProperty(Object key, Object value) {
if (key == SwingUtilities2.AA_TEXT_PROPERTY_KEY) {
aaTextInfo = value;
if (key == RenderingHints.KEY_TEXT_ANTIALIASING) {
aaHint = value;
return;
} else if (key == RenderingHints.KEY_TEXT_LCD_CONTRAST) {
lcdRenderingHint = value;
return;
}
if (value == null && clientProperties == null) {

View File

@ -35,11 +35,11 @@ import javax.swing.event.InternalFrameEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import static java.awt.RenderingHints.KEY_TEXT_ANTIALIASING;
import static java.awt.RenderingHints.KEY_TEXT_LCD_CONTRAST;
import sun.swing.DefaultLookup;
import static sun.swing.SwingUtilities2.AA_TEXT_PROPERTY_KEY;
/**
* The class that manages a basic title bar
* <p>
@ -217,8 +217,10 @@ public class BasicInternalFrameTitlePane extends JComponent
}
private void updateProperties() {
final Object aaTextInfo = frame.getClientProperty(AA_TEXT_PROPERTY_KEY);
putClientProperty(AA_TEXT_PROPERTY_KEY, aaTextInfo);
putClientProperty(KEY_TEXT_ANTIALIASING,
frame.getClientProperty(KEY_TEXT_ANTIALIASING));
putClientProperty(KEY_TEXT_LCD_CONTRAST,
frame.getClientProperty(KEY_TEXT_LCD_CONTRAST));
}
/**

View File

@ -1514,8 +1514,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
flushUnreferenced(); // Remove old listeners
boolean lafCond = SwingUtilities2.isLocalDisplay();
Object aaTextInfo = SwingUtilities2.AATextInfo.getAATextInfo(lafCond);
table.put(SwingUtilities2.AA_TEXT_PROPERTY_KEY, aaTextInfo);
SwingUtilities2.putAATextInfo(lafCond, table);
new AATextListener(this);
}
@ -2204,9 +2203,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
}
UIDefaults defaults = UIManager.getLookAndFeelDefaults();
boolean lafCond = SwingUtilities2.isLocalDisplay();
Object aaTextInfo =
SwingUtilities2.AATextInfo.getAATextInfo(lafCond);
defaults.put(SwingUtilities2.AA_TEXT_PROPERTY_KEY, aaTextInfo);
SwingUtilities2.putAATextInfo(lafCond, defaults);
updateUI();
}

View File

@ -688,8 +688,7 @@ public class SynthLookAndFeel extends BasicLookAndFeel {
// enabled antialiasing depending on desktop settings
flushUnreferenced();
Object aaTextInfo = getAATextInfo();
table.put(SwingUtilities2.AA_TEXT_PROPERTY_KEY, aaTextInfo);
SwingUtilities2.putAATextInfo(useLAFConditions(), table);
new AATextListener(this);
if (defaultsMap != null) {
@ -794,7 +793,7 @@ public class SynthLookAndFeel extends BasicLookAndFeel {
*
* @return the text antialiasing information associated to the desktop
*/
private static Object getAATextInfo() {
private static boolean useLAFConditions() {
String language = Locale.getDefault().getLanguage();
String desktop =
AccessController.doPrivileged(new GetPropertyAction("sun.desktop"));
@ -805,10 +804,7 @@ public class SynthLookAndFeel extends BasicLookAndFeel {
boolean isGnome = "gnome".equals(desktop);
boolean isLocal = SwingUtilities2.isLocalDisplay();
boolean setAA = isLocal && (!isGnome || !isCjkLocale);
Object aaTextInfo = SwingUtilities2.AATextInfo.getAATextInfo(setAA);
return aaTextInfo;
return isLocal && (!isGnome || !isCjkLocale);
}
private static ReferenceQueue<LookAndFeel> queue = new ReferenceQueue<LookAndFeel>();
@ -844,8 +840,7 @@ public class SynthLookAndFeel extends BasicLookAndFeel {
return;
}
Object aaTextInfo = getAATextInfo();
defaults.put(SwingUtilities2.AA_TEXT_PROPERTY_KEY, aaTextInfo);
SwingUtilities2.putAATextInfo(useLAFConditions(), defaults);
updateUI();
}

View File

@ -102,14 +102,6 @@ public class SwingUtilities2 {
public static final FontRenderContext DEFAULT_FRC =
new FontRenderContext(null, false, false);
/**
* A JComponent client property is used to determine text aa settings.
* To avoid having this property persist between look and feels changes
* the value of the property is set to null in JComponent.setUI
*/
public static final Object AA_TEXT_PROPERTY_KEY =
new StringBuffer("AATextInfoPropertyKey");
/**
* Attribute key for the content elements. If it is set on an element, the
* element is considered to be a line break.
@ -123,58 +115,23 @@ public class SwingUtilities2 {
private static final StringBuilder SKIP_CLICK_COUNT =
new StringBuilder("skipClickCount");
/* Presently this class assumes default fractional metrics.
* This may need to change to emulate future platform L&Fs.
*/
public static class AATextInfo {
@SuppressWarnings("unchecked")
public static void putAATextInfo(boolean lafCondition,
Map<Object, Object> map) {
SunToolkit.setAAFontSettingsCondition(lafCondition);
Toolkit tk = Toolkit.getDefaultToolkit();
Object desktopHints = tk.getDesktopProperty(SunToolkit.DESKTOPFONTHINTS);
private static AATextInfo getAATextInfoFromMap(Map<java.awt.RenderingHints.Key, Object> hints) {
Object aaHint = hints.get(KEY_TEXT_ANTIALIASING);
Object contHint = hints.get(KEY_TEXT_LCD_CONTRAST);
if (aaHint == null ||
aaHint == VALUE_TEXT_ANTIALIAS_OFF ||
aaHint == VALUE_TEXT_ANTIALIAS_DEFAULT) {
return null;
} else {
return new AATextInfo(aaHint, (Integer)contHint);
if (desktopHints instanceof Map) {
Map<Object, Object> hints = (Map<Object, Object>) desktopHints;
Object aaHint = hints.get(KEY_TEXT_ANTIALIASING);
if (aaHint == null
|| aaHint == VALUE_TEXT_ANTIALIAS_OFF
|| aaHint == VALUE_TEXT_ANTIALIAS_DEFAULT) {
return;
}
}
@SuppressWarnings("unchecked")
public static AATextInfo getAATextInfo(boolean lafCondition) {
SunToolkit.setAAFontSettingsCondition(lafCondition);
Toolkit tk = Toolkit.getDefaultToolkit();
Object map = tk.getDesktopProperty(SunToolkit.DESKTOPFONTHINTS);
if (map instanceof Map) {
return getAATextInfoFromMap((Map<java.awt.RenderingHints.Key, Object>)map);
} else {
return null;
}
}
Object aaHint;
Integer lcdContrastHint;
FontRenderContext frc;
/* These are rarely constructed objects, and only when a complete
* UI is being updated, so the cost of the tests here is minimal
* and saves tests elsewhere.
* We test that the values are ones we support/expect.
*/
public AATextInfo(Object aaHint, Integer lcdContrastHint) {
if (aaHint == null) {
throw new InternalError("null not allowed here");
}
if (aaHint == VALUE_TEXT_ANTIALIAS_OFF ||
aaHint == VALUE_TEXT_ANTIALIAS_DEFAULT) {
throw new InternalError("AA must be on");
}
this.aaHint = aaHint;
this.lcdContrastHint = lcdContrastHint;
this.frc = new FontRenderContext(null, aaHint,
VALUE_FRACTIONALMETRICS_DEFAULT);
map.put(KEY_TEXT_ANTIALIASING, aaHint);
map.put(KEY_TEXT_LCD_CONTRAST, hints.get(KEY_TEXT_LCD_CONTRAST));
}
}
@ -240,22 +197,6 @@ public class SwingUtilities2 {
// need to gracefully handle null.
//
/**
* Returns whether or not text should be drawn antialiased.
*
* @param c JComponent to test.
* @return Whether or not text should be drawn antialiased for the
* specified component.
*/
public static AATextInfo drawTextAntialiased(JComponent c) {
if (c != null) {
/* a non-null property implies some form of AA requested */
return (AATextInfo)c.getClientProperty(AA_TEXT_PROPERTY_KEY);
}
// No component, assume aa is off
return null;
}
/**
* Returns the left side bearing of the first character of string. The
* left side bearing is calculated from the passed in
@ -530,7 +471,6 @@ public class SwingUtilities2 {
// If we get here we're not printing
if (g instanceof Graphics2D) {
AATextInfo info = drawTextAntialiased(c);
Graphics2D g2 = (Graphics2D)g;
boolean needsTextLayout = ((c != null) &&
@ -543,21 +483,25 @@ public class SwingUtilities2 {
}
}
if (info != null) {
Object aaHint = c.getClientProperty(KEY_TEXT_ANTIALIASING);
if (aaHint != null) {
Object oldContrast = null;
Object oldAAValue = g2.getRenderingHint(KEY_TEXT_ANTIALIASING);
if (info.aaHint != oldAAValue) {
g2.setRenderingHint(KEY_TEXT_ANTIALIASING, info.aaHint);
if (aaHint != oldAAValue) {
g2.setRenderingHint(KEY_TEXT_ANTIALIASING, aaHint);
} else {
oldAAValue = null;
}
if (info.lcdContrastHint != null) {
Object lcdContrastHint = c.getClientProperty(
KEY_TEXT_LCD_CONTRAST);
if (lcdContrastHint != null) {
oldContrast = g2.getRenderingHint(KEY_TEXT_LCD_CONTRAST);
if (info.lcdContrastHint.equals(oldContrast)) {
if (lcdContrastHint.equals(oldContrast)) {
oldContrast = null;
} else {
g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST,
info.lcdContrastHint);
lcdContrastHint);
}
}
@ -821,24 +765,26 @@ public class SwingUtilities2 {
}
// Assume we're not printing if we get here, or that we are invoked
// via Swing text printing which is laid out for the printer.
AATextInfo info = drawTextAntialiased(c);
if (info != null && (g instanceof Graphics2D)) {
Object aaHint = c.getClientProperty(KEY_TEXT_ANTIALIASING);
if (aaHint != null && (g instanceof Graphics2D)) {
Graphics2D g2 = (Graphics2D)g;
Object oldContrast = null;
Object oldAAValue = g2.getRenderingHint(KEY_TEXT_ANTIALIASING);
if (info.aaHint != null && info.aaHint != oldAAValue) {
g2.setRenderingHint(KEY_TEXT_ANTIALIASING, info.aaHint);
if (aaHint != null && aaHint != oldAAValue) {
g2.setRenderingHint(KEY_TEXT_ANTIALIASING, aaHint);
} else {
oldAAValue = null;
}
if (info.lcdContrastHint != null) {
Object lcdContrastHint = c.getClientProperty(KEY_TEXT_LCD_CONTRAST);
if (lcdContrastHint != null) {
oldContrast = g2.getRenderingHint(KEY_TEXT_LCD_CONTRAST);
if (info.lcdContrastHint.equals(oldContrast)) {
if (lcdContrastHint.equals(oldContrast)) {
oldContrast = null;
} else {
g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST,
info.lcdContrastHint);
lcdContrastHint);
}
}
@ -1117,15 +1063,35 @@ public class SwingUtilities2 {
*/
private static FontRenderContext getFRCProperty(JComponent c) {
if (c != null) {
AATextInfo info =
(AATextInfo)c.getClientProperty(AA_TEXT_PROPERTY_KEY);
if (info != null) {
return info.frc;
Object aaHint = c.getClientProperty(KEY_TEXT_ANTIALIASING);
if (aaHint != null) {
return getFRCFromCache(aaHint);
}
}
return null;
}
private static final Object APP_CONTEXT_FRC_CACHE_KEY = new Object();
private static FontRenderContext getFRCFromCache(Object aaHint) {
@SuppressWarnings("unchecked")
Map<Object, FontRenderContext> cache = (Map<Object, FontRenderContext>)
AppContext.getAppContext().get(APP_CONTEXT_FRC_CACHE_KEY);
if (cache == null) {
cache = new HashMap<>();
AppContext.getAppContext().put(APP_CONTEXT_FRC_CACHE_KEY, cache);
}
FontRenderContext frc = cache.get(aaHint);
if (frc == null) {
frc = new FontRenderContext(null, aaHint,
VALUE_FRACTIONALMETRICS_DEFAULT);
cache.put(aaHint, frc);
}
return frc;
}
/*
* returns true if the Graphics is print Graphics
* false otherwise

View File

@ -0,0 +1,283 @@
/*
* Copyright (c) 2015, 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.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 (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;
}
}
}