1 /*
2  * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.apple.laf;
27 
28 import java.awt.*;
29 import java.awt.image.BufferedImage;
30 import java.security.PrivilegedAction;
31 
32 import javax.swing.*;
33 import javax.swing.plaf.*;
34 
35 import sun.lwawt.macosx.LWCToolkit;
36 import apple.laf.JRSUIConstants.AlignmentHorizontal;
37 import apple.laf.JRSUIConstants.AlignmentVertical;
38 import apple.laf.JRSUIConstants.Direction;
39 import apple.laf.JRSUIConstants.State;
40 import apple.laf.JRSUIConstants.Widget;
41 import apple.laf.*;
42 
43 import com.apple.eio.FileManager;
44 import com.apple.laf.AquaIcon.InvertableIcon;
45 import com.apple.laf.AquaIcon.JRSUIControlSpec;
46 import com.apple.laf.AquaIcon.SystemIcon;
47 import com.apple.laf.AquaUtils.RecyclableObject;
48 import com.apple.laf.AquaUtils.RecyclableSingleton;
49 import sun.awt.image.MultiResolutionCachedImage;
50 import sun.lwawt.macosx.CImage;
51 
52 public class AquaImageFactory {
getConfirmImageIcon()53     public static IconUIResource getConfirmImageIcon() {
54         // public, because UIDefaults.ProxyLazyValue uses reflection to get this value
55 
56         return new IconUIResource(new AquaIcon.CachingScalingIcon(kAlertIconSize, kAlertIconSize) {
57             Image createImage() {
58                 return getGenericJavaIcon();
59             }
60         });
61     }
62 
63     public static IconUIResource getCautionImageIcon() {
64         // public, because UIDefaults.ProxyLazyValue uses reflection to get this value
65         return getAppIconCompositedOn(AquaIcon.SystemIcon.getCautionIcon());
66     }
67 
68     public static IconUIResource getStopImageIcon() {
69         // public, because UIDefaults.ProxyLazyValue uses reflection to get this value
70         return getAppIconCompositedOn(AquaIcon.SystemIcon.getStopIcon());
71     }
72 
73     public static IconUIResource getLockImageIcon() {
74         // public, because UIDefaults.ProxyLazyValue uses reflection to get this value
75         if (JRSUIUtils.Images.shouldUseLegacySecurityUIPath()) {
76             final Image lockIcon = CImage.createImageFromFile("/System/Library/CoreServices/SecurityAgent.app/Contents/Resources/Security.icns", kAlertIconSize, kAlertIconSize);
77             return getAppIconCompositedOn(lockIcon);
78         }
79 
80         final Image lockIcon = Toolkit.getDefaultToolkit().getImage("NSImage://NSSecurity");
81         return getAppIconCompositedOn(lockIcon);
82     }
83 
84     static Image getGenericJavaIcon() {
85         return java.security.AccessController.doPrivileged(new PrivilegedAction<Image>() {
86             public Image run() {
87                 return com.apple.eawt.Application.getApplication().getDockIconImage();
88             }
89         });
90     }
91 
92     static String getPathToThisApplication() {
93         return java.security.AccessController.doPrivileged(new PrivilegedAction<String>() {
94             public String run() {
95                 return FileManager.getPathToApplicationBundle();
96             }
97         });
98     }
99 
100     static IconUIResource getAppIconCompositedOn(final SystemIcon systemIcon) {
101         systemIcon.setSize(kAlertIconSize, kAlertIconSize);
102         return getAppIconCompositedOn(systemIcon.createImage());
103     }
104 
105     private static final int kAlertIconSize = 64;
106     static IconUIResource getAppIconCompositedOn(final Image background) {
107 
108         if (background instanceof MultiResolutionCachedImage) {
109             int width = background.getWidth(null);
110             Image mrIconImage = ((MultiResolutionCachedImage) background).map(
111                     rv -> getAppIconImageCompositedOn(rv, rv.getWidth(null) / width));
112             return new IconUIResource(new ImageIcon(mrIconImage));
113         }
114 
115         BufferedImage iconImage = getAppIconImageCompositedOn(background, 1);
116         return new IconUIResource(new ImageIcon(iconImage));
117     }
118 
119     static BufferedImage getAppIconImageCompositedOn(final Image background, int scaleFactor) {
120 
121         final int scaledAlertIconSize = kAlertIconSize * scaleFactor;
122         final int kAlertSubIconSize = (int) (scaledAlertIconSize * 0.5);
123         final int kAlertSubIconInset = scaledAlertIconSize - kAlertSubIconSize;
124         final Icon smallAppIconScaled = new AquaIcon.CachingScalingIcon(
125                 kAlertSubIconSize, kAlertSubIconSize) {
126                     Image createImage() {
127                         return getGenericJavaIcon();
128                     }
129                 };
130 
131         final BufferedImage image = new BufferedImage(scaledAlertIconSize,
132                 scaledAlertIconSize, BufferedImage.TYPE_INT_ARGB_PRE);
133         final Graphics g = image.getGraphics();
134         g.drawImage(background, 0, 0,
135                 scaledAlertIconSize, scaledAlertIconSize, null);
136         if (g instanceof Graphics2D) {
137             // improves icon rendering quality in Quartz
138             ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING,
139                     RenderingHints.VALUE_RENDER_QUALITY);
140         }
141 
142         smallAppIconScaled.paintIcon(null, g,
143                 kAlertSubIconInset, kAlertSubIconInset);
144         g.dispose();
145 
146         return image;
147     }
148 
149     public static IconUIResource getTreeFolderIcon() {
150         // public, because UIDefaults.ProxyLazyValue uses reflection to get this value
151         return AquaIcon.SystemIcon.getFolderIconUIResource();
152     }
153 
154     public static IconUIResource getTreeOpenFolderIcon() {
155         // public, because UIDefaults.ProxyLazyValue uses reflection to get this value
156         return AquaIcon.SystemIcon.getOpenFolderIconUIResource();
157     }
158 
159     public static IconUIResource getTreeDocumentIcon() {
160         // public, because UIDefaults.ProxyLazyValue uses reflection to get this value
161         return AquaIcon.SystemIcon.getDocumentIconUIResource();
162     }
163 
164     public static UIResource getTreeExpandedIcon() {
165         // public, because UIDefaults.ProxyLazyValue uses reflection to get this value
166         return AquaIcon.getIconFor(new JRSUIControlSpec() {
167             public void initIconPainter(final AquaPainter<? extends JRSUIState> painter) {
168                 painter.state.set(Widget.DISCLOSURE_TRIANGLE);
169                 painter.state.set(State.ACTIVE);
170                 painter.state.set(Direction.DOWN);
171                 painter.state.set(AlignmentHorizontal.CENTER);
172                 painter.state.set(AlignmentVertical.CENTER);
173             }
174         }, 20, 20);
175     }
176 
177     public static UIResource getTreeCollapsedIcon() {
178         // public, because UIDefaults.ProxyLazyValue uses reflection to get this value
179         return AquaIcon.getIconFor(new JRSUIControlSpec() {
180             public void initIconPainter(final AquaPainter<? extends JRSUIState> painter) {
181                 painter.state.set(Widget.DISCLOSURE_TRIANGLE);
182                 painter.state.set(State.ACTIVE);
183                 painter.state.set(Direction.RIGHT);
184                 painter.state.set(AlignmentHorizontal.CENTER);
185                 painter.state.set(AlignmentVertical.CENTER);
186             }
187         }, 20, 20);
188     }
189 
190     public static UIResource getTreeRightToLeftCollapsedIcon() {
191         // public, because UIDefaults.ProxyLazyValue uses reflection to get this value
192         return AquaIcon.getIconFor(new JRSUIControlSpec() {
193             public void initIconPainter(final AquaPainter<? extends JRSUIState> painter) {
194                 painter.state.set(Widget.DISCLOSURE_TRIANGLE);
195                 painter.state.set(State.ACTIVE);
196                 painter.state.set(Direction.LEFT);
197                 painter.state.set(AlignmentHorizontal.CENTER);
198                 painter.state.set(AlignmentVertical.CENTER);
199             }
200         }, 20, 20);
201     }
202 
203     static class NamedImageSingleton extends RecyclableSingleton<Image> {
204         final String namedImage;
205 
206         NamedImageSingleton(final String namedImage) {
207             this.namedImage = namedImage;
208         }
209 
210         @Override
211         protected Image getInstance() {
212             return getNSIcon(namedImage);
213         }
214     }
215 
216     static class IconUIResourceSingleton extends RecyclableSingleton<IconUIResource> {
217         final NamedImageSingleton holder;
218 
219         public IconUIResourceSingleton(final NamedImageSingleton holder) {
220             this.holder = holder;
221         }
222 
223         @Override
224         protected IconUIResource getInstance() {
225             return new IconUIResource(new ImageIcon(holder.get()));
226         }
227     }
228 
229     @SuppressWarnings("serial") // Superclass is not serializable across versions
230     static class InvertableImageIcon extends ImageIcon implements InvertableIcon, UIResource {
231         Icon invertedImage;
232         public InvertableImageIcon(final Image image) {
233             super(image);
234         }
235 
236         @Override
237         public Icon getInvertedIcon() {
238             if (invertedImage != null) return invertedImage;
239             return invertedImage = new IconUIResource(new ImageIcon(AquaUtils.generateLightenedImage(getImage(), 100)));
240         }
241     }
242 
243     private static final NamedImageSingleton northArrow = new NamedImageSingleton("NSMenuScrollUp");
244     private static final IconUIResourceSingleton northArrowIcon = new IconUIResourceSingleton(northArrow);
245     private static final NamedImageSingleton southArrow = new NamedImageSingleton("NSMenuScrollDown");
246     private static final IconUIResourceSingleton southArrowIcon = new IconUIResourceSingleton(southArrow);
247     private static final NamedImageSingleton westArrow = new NamedImageSingleton("NSMenuSubmenuLeft");
248     private static final IconUIResourceSingleton westArrowIcon = new IconUIResourceSingleton(westArrow);
249     private static final NamedImageSingleton eastArrow = new NamedImageSingleton("NSMenuSubmenu");
250     private static final IconUIResourceSingleton eastArrowIcon = new IconUIResourceSingleton(eastArrow);
251 
252     static Image getArrowImageForDirection(final int direction) {
253         switch(direction) {
254             case SwingConstants.NORTH: return northArrow.get();
255             case SwingConstants.SOUTH: return southArrow.get();
256             case SwingConstants.EAST: return eastArrow.get();
257             case SwingConstants.WEST: return westArrow.get();
258         }
259         return null;
260     }
261 
262     static Icon getArrowIconForDirection(int direction) {
263         switch(direction) {
264             case SwingConstants.NORTH: return northArrowIcon.get();
265             case SwingConstants.SOUTH: return southArrowIcon.get();
266             case SwingConstants.EAST: return eastArrowIcon.get();
267             case SwingConstants.WEST: return westArrowIcon.get();
268         }
269         return null;
270     }
271 
272     public static Icon getMenuArrowIcon() {
273         return new InvertableImageIcon(AquaUtils.generateLightenedImage(eastArrow.get(), 25));
274     }
275 
276     public static Icon getMenuItemCheckIcon() {
277         return new InvertableImageIcon(AquaUtils.generateLightenedImage(
278                 getNSIcon("NSMenuItemSelection"), 25));
279     }
280 
281     public static Icon getMenuItemDashIcon() {
282         return new InvertableImageIcon(AquaUtils.generateLightenedImage(
283                 getNSIcon("NSMenuMixedState"), 25));
284     }
285 
286     private static Image getNSIcon(String imageName) {
287         Image icon = Toolkit.getDefaultToolkit()
288                 .getImage("NSImage://" + imageName);
289         return icon;
290     }
291 
292     public static class NineSliceMetrics {
293         public final int wCut, eCut, nCut, sCut;
294         public final int minW, minH;
295         public final boolean showMiddle, stretchH, stretchV;
296 
297         public NineSliceMetrics(final int minWidth, final int minHeight, final int westCut, final int eastCut, final int northCut, final int southCut) {
298             this(minWidth, minHeight, westCut, eastCut, northCut, southCut, true);
299         }
300 
301         public NineSliceMetrics(final int minWidth, final int minHeight, final int westCut, final int eastCut, final int northCut, final int southCut, final boolean showMiddle) {
302             this(minWidth, minHeight, westCut, eastCut, northCut, southCut, showMiddle, true, true);
303         }
304 
305         public NineSliceMetrics(final int minWidth, final int minHeight, final int westCut, final int eastCut, final int northCut, final int southCut, final boolean showMiddle, final boolean stretchHorizontally, final boolean stretchVertically) {
306             this.wCut = westCut; this.eCut = eastCut; this.nCut = northCut; this.sCut = southCut;
307             this.minW = minWidth; this.minH = minHeight;
308             this.showMiddle = showMiddle; this.stretchH = stretchHorizontally; this.stretchV = stretchVertically;
309         }
310     }
311 
312     /*
313      * A "paintable" which holds nine images, which represent a sliced up initial
314      * image that can be streched from its middles.
315      */
316     public static class SlicedImageControl {
317         final BufferedImage NW, N, NE;
318         final BufferedImage W, C, E;
319         final BufferedImage SW, S, SE;
320 
321         final NineSliceMetrics metrics;
322 
323         final int totalWidth, totalHeight;
324         final int centerColWidth, centerRowHeight;
325 
326         public SlicedImageControl(final Image img, final int westCut, final int eastCut, final int northCut, final int southCut) {
327             this(img, westCut, eastCut, northCut, southCut, true);
328         }
329 
330         public SlicedImageControl(final Image img, final int westCut, final int eastCut, final int northCut, final int southCut, final boolean useMiddle) {
331             this(img, westCut, eastCut, northCut, southCut, useMiddle, true, true);
332         }
333 
334         public SlicedImageControl(final Image img, final int westCut, final int eastCut, final int northCut, final int southCut, final boolean useMiddle, final boolean stretchHorizontally, final boolean stretchVertically) {
335             this(img, new NineSliceMetrics(img.getWidth(null), img.getHeight(null), westCut, eastCut, northCut, southCut, useMiddle, stretchHorizontally, stretchVertically));
336         }
337 
338         public SlicedImageControl(final Image img, final NineSliceMetrics metrics) {
339             this.metrics = metrics;
340 
341             if (img.getWidth(null) != metrics.minW || img.getHeight(null) != metrics.minH) {
342                 throw new IllegalArgumentException("SlicedImageControl: template image and NineSliceMetrics don't agree on minimum dimensions");
343             }
344 
345             totalWidth = metrics.minW;
346             totalHeight = metrics.minH;
347             centerColWidth = totalWidth - metrics.wCut - metrics.eCut;
348             centerRowHeight = totalHeight - metrics.nCut - metrics.sCut;
349 
350             NW = createSlice(img, 0, 0, metrics.wCut, metrics.nCut);
351             N = createSlice(img, metrics.wCut, 0, centerColWidth, metrics.nCut);
352             NE = createSlice(img, totalWidth - metrics.eCut, 0, metrics.eCut, metrics.nCut);
353             W = createSlice(img, 0, metrics.nCut, metrics.wCut, centerRowHeight);
354             C = metrics.showMiddle ? createSlice(img, metrics.wCut, metrics.nCut, centerColWidth, centerRowHeight) : null;
355             E = createSlice(img, totalWidth - metrics.eCut, metrics.nCut, metrics.eCut, centerRowHeight);
356             SW = createSlice(img, 0, totalHeight - metrics.sCut, metrics.wCut, metrics.sCut);
357             S = createSlice(img, metrics.wCut, totalHeight - metrics.sCut, centerColWidth, metrics.sCut);
358             SE = createSlice(img, totalWidth - metrics.eCut, totalHeight - metrics.sCut, metrics.eCut, metrics.sCut);
359         }
360 
361         static BufferedImage createSlice(final Image img, final int x, final int y, final int w, final int h) {
362             if (w == 0 || h == 0) return null;
363 
364             final BufferedImage slice = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE);
365             final Graphics2D g2d = slice.createGraphics();
366             g2d.drawImage(img, 0, 0, w, h, x, y, x + w, y + h, null);
367             g2d.dispose();
368 
369             return slice;
370         }
371 
372         public void paint(final Graphics g, final int x, final int y, final int w, final int h) {
373             g.translate(x, y);
374 
375             if (w < totalWidth || h < totalHeight) {
376                 paintCompressed(g, w, h);
377             } else {
378                 paintStretchedMiddles(g, w, h);
379             }
380 
381             g.translate(-x, -y);
382         }
383 
384         void paintStretchedMiddles(final Graphics g, final int w, final int h) {
385             int baseX = metrics.stretchH ? 0 : ((w / 2) - (totalWidth / 2));
386             int baseY = metrics.stretchV ? 0 : ((h / 2) - (totalHeight / 2));
387             int adjustedWidth = metrics.stretchH ? w : totalWidth;
388             int adjustedHeight = metrics.stretchV ? h : totalHeight;
389 
390             if (NW != null) g.drawImage(NW, baseX, baseY, null);
391             if (N != null) g.drawImage(N, baseX + metrics.wCut, baseY, adjustedWidth - metrics.eCut - metrics.wCut, metrics.nCut, null);
392             if (NE != null) g.drawImage(NE, baseX + adjustedWidth - metrics.eCut, baseY, null);
393             if (W != null) g.drawImage(W, baseX, baseY + metrics.nCut, metrics.wCut, adjustedHeight - metrics.nCut - metrics.sCut, null);
394             if (C != null) g.drawImage(C, baseX + metrics.wCut, baseY + metrics.nCut, adjustedWidth - metrics.eCut - metrics.wCut, adjustedHeight - metrics.nCut - metrics.sCut, null);
395             if (E != null) g.drawImage(E, baseX + adjustedWidth - metrics.eCut, baseY + metrics.nCut, metrics.eCut, adjustedHeight - metrics.nCut - metrics.sCut, null);
396             if (SW != null) g.drawImage(SW, baseX, baseY + adjustedHeight - metrics.sCut, null);
397             if (S != null) g.drawImage(S, baseX + metrics.wCut, baseY + adjustedHeight - metrics.sCut, adjustedWidth - metrics.eCut - metrics.wCut, metrics.sCut, null);
398             if (SE != null) g.drawImage(SE, baseX + adjustedWidth - metrics.eCut, baseY + adjustedHeight - metrics.sCut, null);
399 
400             /*
401             if (NW != null) {g.setColor(Color.GREEN); g.fillRect(baseX, baseY, NW.getWidth(), NW.getHeight());}
402             if (N != null) {g.setColor(Color.RED); g.fillRect(baseX + metrics.wCut, baseY, adjustedWidth - metrics.eCut - metrics.wCut, metrics.nCut);}
403             if (NE != null) {g.setColor(Color.BLUE); g.fillRect(baseX + adjustedWidth - metrics.eCut, baseY, NE.getWidth(), NE.getHeight());}
404             if (W != null) {g.setColor(Color.PINK); g.fillRect(baseX, baseY + metrics.nCut, metrics.wCut, adjustedHeight - metrics.nCut - metrics.sCut);}
405             if (C != null) {g.setColor(Color.ORANGE); g.fillRect(baseX + metrics.wCut, baseY + metrics.nCut, adjustedWidth - metrics.eCut - metrics.wCut, adjustedHeight - metrics.nCut - metrics.sCut);}
406             if (E != null) {g.setColor(Color.CYAN); g.fillRect(baseX + adjustedWidth - metrics.eCut, baseY + metrics.nCut, metrics.eCut, adjustedHeight - metrics.nCut - metrics.sCut);}
407             if (SW != null) {g.setColor(Color.MAGENTA); g.fillRect(baseX, baseY + adjustedHeight - metrics.sCut, SW.getWidth(), SW.getHeight());}
408             if (S != null) {g.setColor(Color.DARK_GRAY); g.fillRect(baseX + metrics.wCut, baseY + adjustedHeight - metrics.sCut, adjustedWidth - metrics.eCut - metrics.wCut, metrics.sCut);}
409             if (SE != null) {g.setColor(Color.YELLOW); g.fillRect(baseX + adjustedWidth - metrics.eCut, baseY + adjustedHeight - metrics.sCut, SE.getWidth(), SE.getHeight());}
410             */
411         }
412 
413         void paintCompressed(final Graphics g, final int w, final int h) {
414             final double heightRatio = h > totalHeight ? 1.0 : (double)h / (double)totalHeight;
415             final double widthRatio = w > totalWidth ? 1.0 : (double)w / (double)totalWidth;
416 
417             final int northHeight = (int)(metrics.nCut * heightRatio);
418             final int southHeight = (int)(metrics.sCut * heightRatio);
419             final int centerHeight = h - northHeight - southHeight;
420 
421             final int westWidth = (int)(metrics.wCut * widthRatio);
422             final int eastWidth = (int)(metrics.eCut * widthRatio);
423             final int centerWidth = w - westWidth - eastWidth;
424 
425             if (NW != null) g.drawImage(NW, 0, 0, westWidth, northHeight, null);
426             if (N != null) g.drawImage(N, westWidth, 0, centerWidth, northHeight, null);
427             if (NE != null) g.drawImage(NE, w - eastWidth, 0, eastWidth, northHeight, null);
428             if (W != null) g.drawImage(W, 0, northHeight, westWidth, centerHeight, null);
429             if (C != null) g.drawImage(C, westWidth, northHeight, centerWidth, centerHeight, null);
430             if (E != null) g.drawImage(E, w - eastWidth, northHeight, eastWidth, centerHeight, null);
431             if (SW != null) g.drawImage(SW, 0, h - southHeight, westWidth, southHeight, null);
432             if (S != null) g.drawImage(S, westWidth, h - southHeight, centerWidth, southHeight, null);
433             if (SE != null) g.drawImage(SE, w - eastWidth, h - southHeight, eastWidth, southHeight, null);
434         }
435     }
436 
437     public abstract static class RecyclableSlicedImageControl extends RecyclableObject<SlicedImageControl> {
438         final NineSliceMetrics metrics;
439 
440         public RecyclableSlicedImageControl(final NineSliceMetrics metrics) {
441             this.metrics = metrics;
442         }
443 
444         @Override
445         protected SlicedImageControl create() {
446             return new SlicedImageControl(createTemplateImage(metrics.minW, metrics.minH), metrics);
447         }
448 
449         protected abstract Image createTemplateImage(final int width, final int height);
450     }
451 
452     // when we use SystemColors, we need to proxy the color with something that implements UIResource,
453     // so that it will be uninstalled when the look and feel is changed.
454     @SuppressWarnings("serial") // JDK implementation class
455     private static class SystemColorProxy extends Color implements UIResource {
456         final Color color;
457         public SystemColorProxy(final Color color) {
458             super(color.getRGB());
459             this.color = color;
460         }
461 
462         public int getRGB() {
463             return color.getRGB();
464         }
465     }
466 
467     public static Color getWindowBackgroundColorUIResource() {
468         //return AquaNativeResources.getWindowBackgroundColorUIResource();
469         return new SystemColorProxy(SystemColor.window);
470     }
471 
472     public static Color getTextSelectionBackgroundColorUIResource() {
473         return new SystemColorProxy(SystemColor.textHighlight);
474     }
475 
476     public static Color getTextSelectionForegroundColorUIResource() {
477         return new SystemColorProxy(SystemColor.textHighlightText);
478     }
479 
480     public static Color getSelectionBackgroundColorUIResource() {
481         return new SystemColorProxy(SystemColor.controlHighlight);
482     }
483 
484     public static Color getSelectionForegroundColorUIResource() {
485         return new SystemColorProxy(SystemColor.controlLtHighlight);
486     }
487 
488     public static Color getFocusRingColorUIResource() {
489         return new SystemColorProxy(LWCToolkit.getAppleColor(LWCToolkit.KEYBOARD_FOCUS_COLOR));
490     }
491 
492     public static Color getSelectionInactiveBackgroundColorUIResource() {
493         return new SystemColorProxy(LWCToolkit.getAppleColor(LWCToolkit.INACTIVE_SELECTION_BACKGROUND_COLOR));
494     }
495 
496     public static Color getSelectionInactiveForegroundColorUIResource() {
497         return new SystemColorProxy(LWCToolkit.getAppleColor(LWCToolkit.INACTIVE_SELECTION_FOREGROUND_COLOR));
498     }
499 }
500