From 45bdd40dce2d529916aedd0bbccc640bcc2d814a Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Mon, 8 Jan 2024 20:12:26 +0100 Subject: [PATCH] Viewport: use method handle, instead of reflection, to get view UI faster --- .../java/com/formdev/flatlaf/FlatLaf.java | 43 +-------- .../formdev/flatlaf/ui/FlatViewportUI.java | 12 +-- .../flatlaf/ui/JavaCompatibility2.java | 91 +++++++++++++++++++ 3 files changed, 99 insertions(+), 47 deletions(-) create mode 100644 flatlaf-core/src/main/java/com/formdev/flatlaf/ui/JavaCompatibility2.java diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java index c7fde411..5ba4c830 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java @@ -30,9 +30,6 @@ import java.awt.image.ImageProducer; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; @@ -78,6 +75,7 @@ import com.formdev.flatlaf.ui.FlatNativeWindowBorder; import com.formdev.flatlaf.ui.FlatPopupFactory; import com.formdev.flatlaf.ui.FlatRootPaneUI; import com.formdev.flatlaf.ui.FlatUIUtils; +import com.formdev.flatlaf.ui.JavaCompatibility2; import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI; import com.formdev.flatlaf.util.FontUtils; import com.formdev.flatlaf.util.GrayFilter; @@ -1289,8 +1287,8 @@ public abstract class FlatLaf * @since 2.5 */ public static Map> getStyleableInfos( JComponent c ) { - StyleableUI ui = getStyleableUI( c ); - return (ui != null) ? ui.getStyleableInfos( c ) : null; + ComponentUI ui = JavaCompatibility2.getUI( c ); + return (ui instanceof StyleableUI) ? ((StyleableUI)ui).getStyleableInfos( c ) : null; } /** @@ -1302,41 +1300,10 @@ public abstract class FlatLaf */ @SuppressWarnings( "unchecked" ) public static T getStyleableValue( JComponent c, String key ) { - StyleableUI ui = getStyleableUI( c ); - return (ui != null) ? (T) ui.getStyleableValue( c, key ) : null; + ComponentUI ui = JavaCompatibility2.getUI( c ); + return (ui instanceof StyleableUI) ? (T) ((StyleableUI)ui).getStyleableValue( c, key ) : null; } - private static StyleableUI getStyleableUI( JComponent c ) { - if( !getUIMethodInitialized ) { - getUIMethodInitialized = true; - - if( SystemInfo.isJava_9_orLater ) { - try { - // JComponent.getUI() is available since Java 9 - getUIMethod = MethodHandles.lookup().findVirtual( JComponent.class, "getUI", - MethodType.methodType( ComponentUI.class ) ); - } catch( Exception ex ) { - // ignore - } - } - } - - try { - Object ui; - if( getUIMethod != null ) - ui = getUIMethod.invoke( c ); - else - ui = c.getClass().getMethod( "getUI" ).invoke( c ); - return (ui instanceof StyleableUI) ? (StyleableUI) ui : null; - } catch( Throwable ex ) { - // ignore - return null; - } - } - - private static boolean getUIMethodInitialized; - private static MethodHandle getUIMethod; - /** * Returns the preferred font family to be used for (nearly) all fonts; or {@code null}. * diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatViewportUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatViewportUI.java index d844725e..8923c05c 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatViewportUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatViewportUI.java @@ -18,7 +18,6 @@ package com.formdev.flatlaf.ui; import java.awt.Component; import java.awt.Graphics; -import java.lang.reflect.Method; import javax.swing.JComponent; import javax.swing.JViewport; import javax.swing.plaf.ComponentUI; @@ -48,14 +47,9 @@ public class FlatViewportUI Component view = ((JViewport)c).getView(); if( view instanceof JComponent ) { - try { - Method m = view.getClass().getMethod( "getUI" ); - Object ui = m.invoke( view ); - if( ui instanceof ViewportPainter ) - ((ViewportPainter)ui).paintViewport( g, (JComponent) view, (JViewport) c ); - } catch( Exception ex ) { - // ignore - } + ComponentUI ui = JavaCompatibility2.getUI( (JComponent) view ); + if( ui instanceof ViewportPainter ) + ((ViewportPainter)ui).paintViewport( g, (JComponent) view, (JViewport) c ); } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/JavaCompatibility2.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/JavaCompatibility2.java new file mode 100644 index 00000000..070e5268 --- /dev/null +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/JavaCompatibility2.java @@ -0,0 +1,91 @@ +/* + * Copyright 2024 FormDev Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.formdev.flatlaf.ui; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Method; +import javax.swing.JComponent; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.JTree; +import javax.swing.plaf.ComponentUI; +import javax.swing.text.JTextComponent; +import com.formdev.flatlaf.util.LoggingFacade; +import com.formdev.flatlaf.util.SystemInfo; + +/** + * Provides Java version compatibility methods. + *

+ * WARNING: This is private API and may change. + * + * @author Karl Tauber + * @since 3.3 + */ +public class JavaCompatibility2 +{ + private static boolean getUIMethodInitialized; + private static MethodHandle getUIMethod; + + /** + * Java 8: getUI() method on various components (e.g. JButton, JList, etc) + *
+ * Java 9: javax.swing.JComponent.getUI() + */ + public static ComponentUI getUI( JComponent c ) { + try { + // Java 9+ + if( SystemInfo.isJava_9_orLater ) { + if( !getUIMethodInitialized ) { + getUIMethodInitialized = true; + + try { + MethodType mt = MethodType.methodType( ComponentUI.class, new Class[0] ); + getUIMethod = MethodHandles.publicLookup().findVirtual( JComponent.class, "getUI", mt ); + } catch( Exception ex ) { + // ignore + LoggingFacade.INSTANCE.logSevere( null, ex ); + } + } + + if( getUIMethod != null ) + return (ComponentUI) getUIMethod.invoke( c ); + } + + // components often used (e.g. as view in scroll panes) + if( c instanceof JPanel ) + return ((JPanel)c).getUI(); + if( c instanceof JList ) + return ((JList)c).getUI(); + if( c instanceof JTable ) + return ((JTable)c).getUI(); + if( c instanceof JTree ) + return ((JTree)c).getUI(); + if( c instanceof JTextComponent ) + return ((JTextComponent)c).getUI(); + + // Java 8 and fallback + Method m = c.getClass().getMethod( "getUI" ); + return (ComponentUI) m.invoke( c ); + } catch( Throwable ex ) { + // ignore + return null; + } + } +}