7124282: [macosx] Can't see table cell highlighter when the highlight border is the same color as the cell.

Reviewed-by: psadhukhan, prr
This commit is contained in:
Harshitha Onkar 2022-05-10 06:33:38 +00:00 committed by Prasanta Sadhukhan
parent 9a3cb93038
commit bd6026c10c
6 changed files with 262 additions and 13 deletions
src/java.desktop/macosx
test/jdk/javax/swing/JTable/7124282

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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
@ -25,11 +25,21 @@
package com.apple.laf;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.awt.Color;
import java.awt.Window;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import javax.swing.JComponent;
import javax.swing.JTree;
import javax.swing.JTable;
import javax.swing.JList;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.BorderUIResource;
import javax.swing.plaf.UIResource;
/**
@ -113,22 +123,35 @@ public class AquaFocusHandler implements FocusListener, PropertyChangeListener {
final Color bg = c.getSelectionBackground();
final Color fg = c.getSelectionForeground();
if (!(bg instanceof UIResource) || !(fg instanceof UIResource)) return;
if (Boolean.FALSE.equals(value)) {
setSelectionColors(c, "Table.selectionInactiveForeground", "Table.selectionInactiveBackground");
setSelectionColors(c, "Table.selectionInactiveForeground",
"Table.selectionInactiveBackground");
return;
}
if (Boolean.TRUE.equals(value)) {
setSelectionColors(c, "Table.selectionForeground", "Table.selectionBackground");
setSelectionColors(c, "Table.selectionForeground",
"Table.selectionBackground");
return;
}
}
static void setSelectionColors(final JTable c, final String fgName, final String bgName) {
c.setSelectionForeground(UIManager.getColor(fgName));
c.setSelectionBackground(UIManager.getColor(bgName));
// focus ring changes for on-the-fly accent color changes
Color prominentFocusRing = AquaLookAndFeel.deriveProminentFocusRing(
UIManager.getColor("Table.cellFocusRing"));
BorderUIResource.LineBorderUIResource focusCellHighlightBorder =
new BorderUIResource.LineBorderUIResource(prominentFocusRing, 2);
UIManager.getDefaults().put("Table.focusCellHighlightBorder",
focusCellHighlightBorder);
}
static void swapSelectionColors(final String prefix, final JList<?> c, final Object value) {
@ -139,12 +162,14 @@ public class AquaFocusHandler implements FocusListener, PropertyChangeListener {
if (!(bg instanceof UIResource) || !(fg instanceof UIResource)) return;
if (Boolean.FALSE.equals(value)) {
setSelectionColors(c, "List.selectionInactiveForeground", "List.selectionInactiveBackground");
setSelectionColors(c, "List.selectionInactiveForeground",
"List.selectionInactiveBackground");
return;
}
if (Boolean.TRUE.equals(value)) {
setSelectionColors(c, "List.selectionForeground", "List.selectionBackground");
setSelectionColors(c, "List.selectionForeground",
"List.selectionBackground");
return;
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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
@ -506,6 +506,10 @@ public class AquaImageFactory {
return new SystemColorProxy(LWCToolkit.getAppleColor(LWCToolkit.KEYBOARD_FOCUS_COLOR));
}
public static Color getCellHighlightColorUIResource() {
return new SystemColorProxy(LWCToolkit.getAppleColor(LWCToolkit.CELL_HIGHLIGHT_COLOR));
}
public static Color getSelectionInactiveBackgroundColorUIResource() {
return new SystemColorProxy(LWCToolkit.getAppleColor(LWCToolkit.INACTIVE_SELECTION_BACKGROUND_COLOR));
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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
@ -388,6 +388,9 @@ public class AquaLookAndFeel extends BasicLookAndFeel {
final Color focusRingColor = AquaImageFactory.getFocusRingColorUIResource();
final Border focusCellHighlightBorder = new BorderUIResource.LineBorderUIResource(focusRingColor);
// for table cell highlighter
final Color cellFocusRingColor = AquaImageFactory.getCellHighlightColorUIResource();
final Color windowBackgroundColor = AquaImageFactory.getWindowBackgroundColorUIResource();
final Color panelBackgroundColor = windowBackgroundColor;
final Color tabBackgroundColor = windowBackgroundColor;
@ -889,7 +892,9 @@ public class AquaLookAndFeel extends BasicLookAndFeel {
"Table.gridColor", white, // grid line color
"Table.focusCellBackground", textHighlightText,
"Table.focusCellForeground", textHighlight,
"Table.focusCellHighlightBorder", focusCellHighlightBorder,
"Table.cellFocusRing", cellFocusRingColor,
"Table.focusCellHighlightBorder", new BorderUIResource.LineBorderUIResource(
deriveProminentFocusRing(cellFocusRingColor), 2),
"Table.scrollPaneBorder", scollListBorder,
"Table.ancestorInputMap", aquaKeyBindings.getTableInputMap(),
@ -1122,4 +1127,61 @@ public class AquaLookAndFeel extends BasicLookAndFeel {
};
table.putDefaults(uiDefaults);
}
/**
* Returns a new cell focus ring color by changing saturation
* and setting the brightness to 100% for incoming cellFocusRing.
*
* If the incoming cellFocusRingColor is equal to white/black/grayish,
* the returned cellFocusRingColor is Light Gray. For all other colors,
* new cellFocusRingColor (in the latter case), is obtained by adjusting
* the saturation levels and setting the brightness to 100% of the
* incoming cellFocusRingColor.
*
* @param cellFocusRingColor - the {@code Color} object
* @return the {@code Color} object corresponding to new HSB values
*/
static Color deriveProminentFocusRing(Color cellFocusRingColor) {
// define constants
float satLowerValue = 0.30f;
float satUpperValue = 1.0f;
// saturation threshold for grayish colors
float satGrayScale = 0.10f;
// used to compare with saturation value of original focus ring and
// set it to either lower or upper saturation value
float saturationThreshold = 0.5f;
// brightness always set to 100%
float brightnessValue = 1.0f;
float[] hsbValues = new float[3];
int redValue = cellFocusRingColor.getRed();
int greenValue = cellFocusRingColor.getGreen();
int blueValue = cellFocusRingColor.getBlue();
Color.RGBtoHSB(redValue, greenValue, blueValue, hsbValues);
// if cellFocusRing is White/Black/Grayish
if ((hsbValues[0] == 0 && hsbValues[1] == 0)
|| hsbValues[1] <= satGrayScale) {
return Color.LIGHT_GRAY;
}
// if cellFocusRing color NOT White/Black/Grayish
// saturation adjustment - saturation set to either lower or
// upper saturation value based on current saturation level
hsbValues[1] = hsbValues[1] >= saturationThreshold ?
satLowerValue : satUpperValue;
// brightness adjustment - brightness set to 100%, always return the
// brightest color for the new color
hsbValues[2] = brightnessValue;
//create and return color corresponding to new hsbValues
return Color.getHSBColor(hsbValues[0], hsbValues[1], hsbValues[2]);
}
}

@ -209,16 +209,19 @@ public final class LWCToolkit extends LWToolkit {
/*
* System colors with default initial values, overwritten by toolkit if system values differ and are available.
*/
private static final int NUM_APPLE_COLORS = 4;
private static final int NUM_APPLE_COLORS = 5;
public static final int KEYBOARD_FOCUS_COLOR = 0;
public static final int INACTIVE_SELECTION_BACKGROUND_COLOR = 1;
public static final int INACTIVE_SELECTION_FOREGROUND_COLOR = 2;
public static final int SELECTED_CONTROL_TEXT_COLOR = 3;
public static final int CELL_HIGHLIGHT_COLOR = 4;
private static int[] appleColors = {
0xFF808080, // keyboardFocusColor = Color.gray;
0xFFC0C0C0, // secondarySelectedControlColor
0xFF303030, // controlDarkShadowColor
0xFFFFFFFF, // controlTextColor
0xFF808080, // cellHighlightColor = Color.gray;
};
private native void loadNativeColors(final int[] systemColors, final int[] appleColors);

@ -120,6 +120,12 @@ JNI_COCOA_EXIT(env);
}
}
// added for JTable Focus Ring
if (@available(macOS 10.14, *)) {
appleColors[sun_lwawt_macosx_LWCToolkit_CELL_HIGHLIGHT_COLOR] = [NSColor controlAccentColor];
} else {
appleColors[sun_lwawt_macosx_LWCToolkit_CELL_HIGHLIGHT_COLOR] = [NSColor keyboardFocusIndicatorColor];
}
appleColors[sun_lwawt_macosx_LWCToolkit_KEYBOARD_FOCUS_COLOR] = [NSColor keyboardFocusIndicatorColor];
appleColors[sun_lwawt_macosx_LWCToolkit_INACTIVE_SELECTION_BACKGROUND_COLOR] = [NSColor secondarySelectedControlColor];
appleColors[sun_lwawt_macosx_LWCToolkit_INACTIVE_SELECTION_FOREGROUND_COLOR] = [NSColor controlDarkShadowColor];

@ -0,0 +1,149 @@
/*
* Copyright (c) 2022, 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.
*/
/*
* @test
* @bug 7124282
* @key headful
* @requires (os.family == "mac")
* @summary Checks whether the JTable's focus ring color's RGB color
* diff with selectionBackground is greater in comparison to original
* focus ring (represented by 'Table.cellFocusRing' property in Aqua LAF
* UIDefaults).
* @run main JTableFocusRingTest
*/
import java.awt.Color;
import java.util.Arrays;
import javax.swing.plaf.BorderUIResource.LineBorderUIResource;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class JTableFocusRingTest {
public static void main(String[] args) throws Exception{
try {
UIManager.setLookAndFeel("com.apple.laf.AquaLookAndFeel");
} catch (ClassNotFoundException | InstantiationException |
IllegalAccessException | UnsupportedLookAndFeelException e) {
throw new RuntimeException("Unsupported Look&Feel Class");
}
SwingUtilities.invokeAndWait(() -> {
float[] bckRGB = new float[3];
float[] oldCellRingRGB = new float[3];
float[] newCellRingRGB = new float[3];
Color selectionBck = null;
Color originalRingColor = null;
Color newRingColor = null;
// saturation threshold for grayish colors
float satGrayScale = 0.10f;
if (UIManager.getDefaults().get("Table.selectionBackground") != null
&& UIManager.getDefaults().get("Table.selectionBackground")
instanceof Color) {
selectionBck = (Color) UIManager.getDefaults()
.get("Table.selectionBackground");
}
if (UIManager.getDefaults().get("Table.cellFocusRing") != null
&& UIManager.getDefaults().get("Table.cellFocusRing")
instanceof Color) {
originalRingColor = (Color) UIManager.getDefaults().get("Table.cellFocusRing");
}
if (UIManager.getDefaults()
.get("Table.focusCellHighlightBorder") != null &&
UIManager.getDefaults().get("Table.focusCellHighlightBorder")
instanceof LineBorderUIResource) {
LineBorderUIResource cellFocusBorderObj = (LineBorderUIResource)
UIManager.getDefaults().get("Table.focusCellHighlightBorder");
newRingColor = cellFocusBorderObj.getLineColor();
}
if (selectionBck == null || originalRingColor == null ||
newRingColor == null) {
throw new RuntimeException("One or more color values are null");
}
System.out.println(UIManager.getLookAndFeel().toString());
System.out.println("Selection Background Color: "
+ selectionBck.toString());
System.out.println("Original FocusRing Color: "
+ originalRingColor.toString());
System.out.println("Brighter FocusRing Color: "
+ newRingColor.toString());
int redValue = originalRingColor.getRed();
int greenValue = originalRingColor.getGreen();
int blueValue = originalRingColor.getBlue();
float[] hsbValues = new float[3];
Color.RGBtoHSB(redValue, greenValue, blueValue, hsbValues);
System.out.println("Original Focus Ring Hue, Saturation and" +
" Brightness: "+ Arrays.toString(hsbValues));
// Edge case - Original Focus ring color: WHITE/BLACK/GRAY
if (((hsbValues[0] == 0 && hsbValues[1] == 0)
|| hsbValues[1] <= satGrayScale) &&
newRingColor.equals(Color.LIGHT_GRAY)) {
System.out.println("Original Focus ring color:" +
"WHITE/BLACK/GRAYISH, Cell Focus Ring Color: LIGHT GRAY");
System.out.println("Test case passed");
return;
}
selectionBck.getRGBColorComponents(bckRGB);
originalRingColor.getRGBColorComponents(oldCellRingRGB);
newRingColor.getRGBColorComponents(newCellRingRGB);
float originalRGBDiff = calculateRGBDiff(oldCellRingRGB, bckRGB);
float brighterRGBDiff = calculateRGBDiff(newCellRingRGB, bckRGB);
System.out.println("Original RGB Diff: "+ originalRGBDiff);
System.out.println("Brighter RGB Diff: "+ brighterRGBDiff);
if (brighterRGBDiff <= originalRGBDiff) {
throw new RuntimeException("Cell Focus Ring Not Visible");
}
});
}
/* calculates the difference between individual RGB components of 2 colors
and returns the total difference. A higher RGB difference is preferred
for a prominent cell highlighter */
private static float calculateRGBDiff(float[] focusRingRGB, float[] bckRGB) {
float totalRGBDiff = 0;
for (int i=0; i< focusRingRGB.length; i++) {
totalRGBDiff += Math.abs(focusRingRGB[i] - bckRGB[i]);
}
return totalRGBDiff;
}
}