mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-27 03:39:40 +01:00
Compare commits
18 Commits
722
...
malenkov/f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d2f25483a | ||
|
|
f45f84d7ed | ||
|
|
06b0d02208 | ||
|
|
bc09aadadb | ||
|
|
dda7f3d871 | ||
|
|
7f025f4e16 | ||
|
|
1e904db3b0 | ||
|
|
c013b03300 | ||
|
|
08aa0852b7 | ||
|
|
23f2c1c42d | ||
|
|
53744bf65f | ||
|
|
430fdb17a8 | ||
|
|
b37fdd89bf | ||
|
|
e57bae4f66 | ||
|
|
0587074d61 | ||
|
|
a6e441828a | ||
|
|
cbb148dff4 | ||
|
|
1f4ab12fbb |
@@ -1,9 +1,10 @@
|
||||
# jetbrains/runtime:jbr11env
|
||||
# jetbrains/runtime:jbr11dev8env
|
||||
FROM centos:7
|
||||
|
||||
RUN yum -y install zip bzip2 unzip tar wget make autoconf automake libtool gcc gcc-c++ libstdc++-devel alsa-devel cups-devel xorg-x11-devel libjpeg62-devel giflib-devel freetype-devel file which libXtst-devel libXt-devel libXrender-devel alsa-lib-devel fontconfig-devel libXrandr-devel libXi-devel
|
||||
RUN yum -y install centos-release-scl
|
||||
RUN yum -y install devtoolset-8
|
||||
RUN yum -y install zip bzip2 unzip tar wget make autoconf automake libtool alsa-devel cups-devel xorg-x11-devel libjpeg62-devel giflib-devel freetype-devel file which libXtst-devel libXt-devel libXrender-devel alsa-lib-devel fontconfig-devel libXrandr-devel libXi-devel
|
||||
# Install Java 11
|
||||
RUN wget https://bintray.com/jetbrains/intellij-jbr/download_file?file_path=jbrsdk-11_0_3-linux-x64-b360.2.tar.gz \
|
||||
-O - | tar xz -C /
|
||||
ENV JAVA_HOME /jbrsdk
|
||||
ENV PATH $JAVA_HOME/bin:$PATH
|
||||
ENV PATH $JAVA_HOME/bin:/opt/rh/devtoolset-8/root/usr/bin:$PATH
|
||||
|
||||
@@ -495,7 +495,6 @@ set(SOURCE_FILES
|
||||
../../../src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp
|
||||
../../../src/hotspot/cpu/aarch64/relocInfo_aarch64.hpp
|
||||
../../../src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
|
||||
../../../src/hotspot/cpu/aarch64/cpustate_aarch64.hpp
|
||||
../../../src/hotspot/cpu/aarch64/immediate_aarch64.cpp
|
||||
../../../src/hotspot/cpu/aarch64/vmreg_aarch64.cpp
|
||||
../../../src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp
|
||||
@@ -520,7 +519,6 @@ set(SOURCE_FILES
|
||||
../../../src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.hpp
|
||||
../../../src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
|
||||
../../../src/hotspot/cpu/aarch64/vmStructs_aarch64.hpp
|
||||
../../../src/hotspot/cpu/aarch64/decode_aarch64.hpp
|
||||
../../../src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp
|
||||
../../../src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp
|
||||
../../../src/hotspot/cpu/aarch64/codeBuffer_aarch64.hpp
|
||||
@@ -529,7 +527,6 @@ set(SOURCE_FILES
|
||||
../../../src/hotspot/cpu/aarch64/assembler_aarch64.cpp
|
||||
../../../src/hotspot/cpu/aarch64/register_aarch64.cpp
|
||||
../../../src/hotspot/cpu/aarch64/vm_version_ext_aarch64.cpp
|
||||
../../../src/hotspot/cpu/aarch64/aarch64_call.cpp
|
||||
../../../src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
|
||||
../../../src/hotspot/cpu/aarch64/bytecodes_aarch64.hpp
|
||||
../../../src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp
|
||||
@@ -1175,13 +1172,11 @@ set(SOURCE_FILES
|
||||
../../../src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolBuffer.hpp
|
||||
../../../src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp
|
||||
../../../src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp
|
||||
../../../src/hotspot/share/jfr/recorder/repository/jfrChunkSizeNotifier.hpp
|
||||
../../../src/hotspot/share/jfr/recorder/repository/jfrChunkState.hpp
|
||||
../../../src/hotspot/share/jfr/recorder/repository/jfrRepository.cpp
|
||||
../../../src/hotspot/share/jfr/recorder/repository/jfrChunkState.cpp
|
||||
../../../src/hotspot/share/jfr/recorder/repository/jfrRepository.hpp
|
||||
../../../src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.hpp
|
||||
../../../src/hotspot/share/jfr/recorder/repository/jfrChunkSizeNotifier.cpp
|
||||
../../../src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp
|
||||
../../../src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointBlob.hpp
|
||||
../../../src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.cpp
|
||||
@@ -1254,7 +1249,6 @@ set(SOURCE_FILES
|
||||
../../../src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleDescription.hpp
|
||||
../../../src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.hpp
|
||||
../../../src/hotspot/share/jfr/leakprofiler/leakProfiler.hpp
|
||||
../../../src/hotspot/share/jfr/leakprofiler/emitEventOperation.hpp
|
||||
../../../src/hotspot/share/jfr/leakprofiler/sampling/objectSample.hpp
|
||||
../../../src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.hpp
|
||||
../../../src/hotspot/share/jfr/leakprofiler/sampling/sampleList.cpp
|
||||
@@ -1270,7 +1264,6 @@ set(SOURCE_FILES
|
||||
../../../src/hotspot/share/jfr/leakprofiler/utilities/rootType.hpp
|
||||
../../../src/hotspot/share/jfr/leakprofiler/utilities/unifiedOop.hpp
|
||||
../../../src/hotspot/share/jfr/leakprofiler/startOperation.hpp
|
||||
../../../src/hotspot/share/jfr/leakprofiler/emitEventOperation.cpp
|
||||
../../../src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp
|
||||
../../../src/hotspot/share/jfr/leakprofiler/chains/rootSetClosure.cpp
|
||||
../../../src/hotspot/share/jfr/leakprofiler/chains/edge.hpp
|
||||
@@ -1481,7 +1474,6 @@ set(SOURCE_FILES
|
||||
../../../src/hotspot/share/runtime/basicLock.hpp
|
||||
../../../src/hotspot/share/runtime/compilationPolicy.cpp
|
||||
../../../src/hotspot/share/runtime/java.hpp
|
||||
../../../src/hotspot/share/runtime/simpleThresholdPolicy.cpp
|
||||
../../../src/hotspot/share/runtime/objectMonitor.inline.hpp
|
||||
../../../src/hotspot/share/runtime/mutexLocker.cpp
|
||||
../../../src/hotspot/share/runtime/serviceThread.cpp
|
||||
@@ -1524,7 +1516,6 @@ set(SOURCE_FILES
|
||||
../../../src/hotspot/share/runtime/compilationPolicy.hpp
|
||||
../../../src/hotspot/share/runtime/basicLock.cpp
|
||||
../../../src/hotspot/share/runtime/java.cpp
|
||||
../../../src/hotspot/share/runtime/simpleThresholdPolicy.hpp
|
||||
../../../src/hotspot/share/runtime/perfData.inline.hpp
|
||||
../../../src/hotspot/share/runtime/statSampler.hpp
|
||||
../../../src/hotspot/share/runtime/vm_operations.cpp
|
||||
@@ -1557,7 +1548,6 @@ set(SOURCE_FILES
|
||||
../../../src/hotspot/share/runtime/handshake.hpp
|
||||
../../../src/hotspot/share/runtime/thread.inline.hpp
|
||||
../../../src/hotspot/share/runtime/perfMemory.hpp
|
||||
../../../src/hotspot/share/runtime/simpleThresholdPolicy.inline.hpp
|
||||
../../../src/hotspot/share/runtime/javaCalls.cpp
|
||||
../../../src/hotspot/share/runtime/reflection.cpp
|
||||
../../../src/hotspot/share/runtime/icache.cpp
|
||||
|
||||
@@ -1088,7 +1088,6 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
../../../src/java.desktop/macosx/native/libawt_lwawt/awt/CFileDialog.h
|
||||
../../../src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.h
|
||||
../../../src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.h
|
||||
../../../src/java.desktop/macosx/native/libawt_lwawt/awt/CGraphicsConfig.m
|
||||
../../../src/java.desktop/macosx/native/libawt_lwawt/awt/CDesktopPeer.m
|
||||
../../../src/java.desktop/macosx/native/libawt_lwawt/awt/PrintModel.h
|
||||
../../../src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m
|
||||
@@ -1342,7 +1341,6 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin" OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux"
|
||||
../../../src/java.desktop/unix/native/libawt_xawt/awt/multi_font.c
|
||||
../../../src/java.desktop/unix/native/libawt_xawt/awt/multiVis.h
|
||||
../../../src/java.desktop/unix/native/libawt_xawt/awt/awt_Event.c
|
||||
../../../src/java.desktop/unix/native/libawt_xawt/awt/robot_common.c
|
||||
../../../src/java.desktop/unix/native/libawt_xawt/awt/awt_util.c
|
||||
../../../src/java.desktop/unix/native/libawt_xawt/awt/list.h
|
||||
../../../src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h
|
||||
@@ -1355,7 +1353,6 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin" OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux"
|
||||
../../../src/java.desktop/unix/native/libawt_xawt/awt/canvas.h
|
||||
../../../src/java.desktop/unix/native/libawt_xawt/awt/awt_AWTEvent.c
|
||||
../../../src/java.desktop/unix/native/libawt_xawt/awt/multi_font.h
|
||||
../../../src/java.desktop/unix/native/libawt_xawt/awt/robot_common.h
|
||||
../../../src/java.desktop/unix/native/libawt_xawt/awt/sun_awt_X11_GtkFileDialogPeer.c
|
||||
../../../src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c
|
||||
../../../src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c
|
||||
|
||||
@@ -27,7 +27,6 @@ package sun.font;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
@@ -41,6 +40,7 @@ import javax.swing.plaf.FontUIResource;
|
||||
import sun.awt.FontConfiguration;
|
||||
import sun.awt.HeadlessToolkit;
|
||||
import sun.lwawt.macosx.*;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
public final class CFontManager extends SunFontManager {
|
||||
private static Hashtable<String, Font2D> genericFonts = new Hashtable<String, Font2D>();
|
||||
@@ -144,10 +144,39 @@ public final class CFontManager extends SunFontManager {
|
||||
protected void registerJREFonts() {
|
||||
String[] files = AccessController.doPrivileged((PrivilegedAction<String[]>) () ->
|
||||
new File(jreFontDirName).list(getTrueTypeFilter()));
|
||||
|
||||
if (files != null) {
|
||||
PlatformLogger logger = FontUtilities.getLogger();
|
||||
int [] ver = new int[3];
|
||||
for (String f : files) {
|
||||
loadNativeDirFonts(jreFontDirName + File.separator + f);
|
||||
boolean loadFont = true;
|
||||
BundledFontInfo fi = getBundledFontInfo(f);
|
||||
if (versionCheckEnabled) {
|
||||
if (fi != null) {
|
||||
String verStr = getNativeFontVersion(fi.getPsName());
|
||||
if (logger != null) {
|
||||
logger.info("Checking bundled " + fi.getPsName());
|
||||
}
|
||||
if (verStr != null && parseFontVersion(verStr, ver) && !fi.isNewerThan(ver)) {
|
||||
if (logger != null) {
|
||||
logger.info("Skip loading. Newer or same version platform font detected " +
|
||||
fi.getPsName() + " " + verStr);
|
||||
}
|
||||
loadFont = false;
|
||||
}
|
||||
} else {
|
||||
if (logger != null) {
|
||||
FontUtilities.getLogger().warning("JREFonts: No BundledFontInfo for : " + f);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (loadFont) {
|
||||
String fontPath = jreFontDirName + File.separator + f;
|
||||
loadNativeDirFonts(fontPath);
|
||||
if (logger != null && fi != null) {
|
||||
String verStr = getNativeFontVersion(fi.getPsName());
|
||||
logger.info("Loaded " + fi.getPsName() + " (" + verStr + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,6 +200,7 @@ public final class CFontManager extends SunFontManager {
|
||||
|
||||
private native void loadNativeDirFonts(String fontPath);
|
||||
private native void loadNativeFonts();
|
||||
native String getNativeFontVersion(String psName);
|
||||
|
||||
void registerFont(String fontName, String fontFamilyName) {
|
||||
// Use different family for specific font faces
|
||||
|
||||
@@ -63,7 +63,7 @@ import com.apple.laf.ClientPropertyApplicator.Property;
|
||||
import sun.awt.AWTAccessor;
|
||||
import sun.awt.AWTAccessor.ComponentAccessor;
|
||||
import sun.awt.AWTAccessor.WindowAccessor;
|
||||
import sun.awt.InvokeOnToolkitHelper;
|
||||
import sun.awt.AWTThreading;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.opengl.CGLSurfaceData;
|
||||
import sun.lwawt.LWLightweightFramePeer;
|
||||
@@ -331,7 +331,7 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
long nativeWindowPtr = java.security.AccessController.doPrivileged(
|
||||
(PrivilegedAction<Long>) () -> {
|
||||
try {
|
||||
return InvokeOnToolkitHelper.invokeAndBlock(() -> {
|
||||
return AWTThreading.executeWaitToolkit(() -> {
|
||||
AtomicLong ref = new AtomicLong();
|
||||
contentView.execute(viewPtr -> {
|
||||
boolean hasOwnerPtr = false;
|
||||
|
||||
@@ -472,7 +472,7 @@ public final class LWCToolkit extends LWToolkit {
|
||||
public Insets getScreenInsets(final GraphicsConfiguration gc) {
|
||||
CGraphicsDevice gd = ((CGraphicsConfig) gc).getDevice();
|
||||
// Avoid deadlock with input methods
|
||||
return InvokeOnToolkitHelper.invokeAndBlock(gd::getScreenInsets);
|
||||
return AWTThreading.executeWaitToolkit(gd::getScreenInsets);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -726,7 +726,7 @@ public final class LWCToolkit extends LWToolkit {
|
||||
final long mediator = createAWTRunLoopMediator();
|
||||
|
||||
InvocationEvent invocationEvent =
|
||||
new InvocationEvent(component,
|
||||
AWTThreading.createAndTrackInvocationEvent(component,
|
||||
runnable,
|
||||
() -> {
|
||||
if (mediator != 0) {
|
||||
@@ -735,17 +735,16 @@ public final class LWCToolkit extends LWToolkit {
|
||||
},
|
||||
true);
|
||||
|
||||
if (!InvokeOnToolkitHelper.offer(invocationEvent)) {
|
||||
if (component != null) {
|
||||
AppContext appContext = SunToolkit.targetToAppContext(component);
|
||||
SunToolkit.postEvent(appContext, invocationEvent);
|
||||
if (component != null) {
|
||||
AppContext appContext = SunToolkit.targetToAppContext(component);
|
||||
SunToolkit.postEvent(appContext, invocationEvent);
|
||||
|
||||
// 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
|
||||
SunToolkit.flushPendingEvents(appContext);
|
||||
} else {
|
||||
// This should be the equivalent to EventQueue.invokeAndWait
|
||||
((LWCToolkit) Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
|
||||
}
|
||||
// 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
|
||||
SunToolkit.flushPendingEvents(appContext);
|
||||
}
|
||||
else {
|
||||
// This should be the equivalent to EventQueue.invokeAndWait
|
||||
((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
|
||||
}
|
||||
|
||||
doAWTRunLoop(mediator, nonBlockingRunLoop);
|
||||
|
||||
@@ -1402,6 +1402,41 @@ JNF_COCOA_ENTER(env);
|
||||
JNF_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: Java_sun_font_CFontManager_loadNativeDirFonts
|
||||
* Method: getNativeFontVersion
|
||||
* Signature: (Ljava/lang/String;)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT JNICALL jstring
|
||||
Java_sun_font_CFontManager_getNativeFontVersion
|
||||
(JNIEnv *env, jclass clz, jstring psName)
|
||||
{
|
||||
jstring result = NULL;
|
||||
JNF_COCOA_ENTER(env);
|
||||
NSString *psNameStr = JNFJavaToNSString(env, psName);
|
||||
CTFontRef sFont = CTFontCreateWithName(psNameStr, 13, nil);
|
||||
if (sFont != NULL) {
|
||||
CFStringRef sFontPSName = CTFontCopyName(sFont, kCTFontPostScriptNameKey);
|
||||
|
||||
// CTFontCreateWithName always returns some font,
|
||||
// so we need to check if it is right one
|
||||
if (sFontPSName != NULL && [psNameStr isEqualToString:sFontPSName]) {
|
||||
CFStringRef fontVersionStr = CTFontCopyName(sFont,
|
||||
kCTFontVersionNameKey);
|
||||
if (fontVersionStr != NULL) {
|
||||
result = JNFNSToJavaString(env, fontVersionStr);
|
||||
CFRelease(fontVersionStr);
|
||||
}
|
||||
}
|
||||
if (sFontPSName != NULL) {
|
||||
CFRelease(sFontPSName);
|
||||
}
|
||||
CFRelease(sFont);
|
||||
}
|
||||
JNF_COCOA_EXIT(env);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: Java_sun_font_CFontManager_loadNativeDirFonts
|
||||
* Method: loadNativeDirFonts
|
||||
|
||||
@@ -375,6 +375,7 @@ public abstract class JComponent extends Container implements Serializable,
|
||||
* AA text hints.
|
||||
*/
|
||||
private transient Object aaHint;
|
||||
private transient Object fmHint;
|
||||
private transient Object lcdRenderingHint;
|
||||
|
||||
static {
|
||||
@@ -677,6 +678,8 @@ public abstract class JComponent extends Container implements Serializable,
|
||||
// aaText shouldn't persist between look and feels, reset it.
|
||||
aaHint = UIManager.getDefaults().get(
|
||||
RenderingHints.KEY_TEXT_ANTIALIASING);
|
||||
fmHint = UIManager.getDefaults().get(
|
||||
RenderingHints.KEY_FRACTIONALMETRICS);
|
||||
lcdRenderingHint = UIManager.getDefaults().get(
|
||||
RenderingHints.KEY_TEXT_LCD_CONTRAST);
|
||||
ComponentUI oldUI = ui;
|
||||
@@ -4047,6 +4050,8 @@ public abstract class JComponent extends Container implements Serializable,
|
||||
public final Object getClientProperty(Object key) {
|
||||
if (key == RenderingHints.KEY_TEXT_ANTIALIASING) {
|
||||
return aaHint;
|
||||
} else if (key == RenderingHints.KEY_FRACTIONALMETRICS) {
|
||||
return fmHint;
|
||||
} else if (key == RenderingHints.KEY_TEXT_LCD_CONTRAST) {
|
||||
return lcdRenderingHint;
|
||||
}
|
||||
@@ -4091,6 +4096,9 @@ public abstract class JComponent extends Container implements Serializable,
|
||||
if (key == RenderingHints.KEY_TEXT_ANTIALIASING) {
|
||||
aaHint = value;
|
||||
return;
|
||||
} else if (key == RenderingHints.KEY_FRACTIONALMETRICS) {
|
||||
fmHint = value;
|
||||
return;
|
||||
} else if (key == RenderingHints.KEY_TEXT_LCD_CONTRAST) {
|
||||
lcdRenderingHint = value;
|
||||
return;
|
||||
|
||||
207
src/java.desktop/share/classes/sun/awt/AWTThreading.java
Normal file
207
src/java.desktop/share/classes/sun/awt/AWTThreading.java
Normal file
@@ -0,0 +1,207 @@
|
||||
package sun.awt;
|
||||
|
||||
import sun.font.FontUtilities;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.InvocationEvent;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/**
|
||||
* Used to perform a cross threads (EventDispatch, Toolkit) execution so that the execution does not cause a deadlock.
|
||||
*/
|
||||
public class AWTThreading {
|
||||
private ExecutorService executor;
|
||||
// every invokeAndWait() pushes a queue of invocations
|
||||
private final Stack<TrackingQueue> invocations = new Stack<>();
|
||||
|
||||
private int level; // re-entrance level
|
||||
|
||||
// invocations should be dispatched on proper EDT (per AppContext)
|
||||
private static final Map<Thread, AWTThreading> EDT_TO_INSTANCE_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
private static class TrackingQueue extends LinkedBlockingQueue<InvocationEvent> {}
|
||||
|
||||
private AWTThreading() {}
|
||||
|
||||
/**
|
||||
* Executes a callable from EventDispatch thread (EDT). It's assumed the callable either performs a blocking execution on Toolkit
|
||||
* or waits a notification from Toolkit. The method is re-entrant.
|
||||
* <p>
|
||||
* Currently only macOS is supported. The callable can wrap a native obj-c selector. The selector should be executed via
|
||||
* [JNFRunLoop performOnMainThreadWaiting:YES ...] so that doAWTRunLoop on AppKit (which is run in [JNFRunLoop javaRunLoopMode]) accepts it.
|
||||
* The callable should not call any Java code that would normally be called on EDT.
|
||||
* <p>
|
||||
* A deadlock can happen when the callable triggers any blocking invocation from Toolkit to EDT, or when Toolkit already waits in
|
||||
* such blocking invocation. To avoid that:
|
||||
* <ul>
|
||||
* <li>The callback execution is delegated to a dedicated pool thread.
|
||||
* <li>All invocation events, initiated by Toolkit via invokeAndWait(), are tracked via a dedicated queue.
|
||||
* <li>All the tracked invocation events are dispatched on EDT out of order (EventQueue) during the callback execution.
|
||||
* <li>In case of a re-entrant method call, all the tracked invocation events coming after the call are dispatched first.
|
||||
* </ul><p>
|
||||
* When called on non-EDT, or on non-macOS, the method executes the callable just in place.
|
||||
*/
|
||||
public static <T> T executeWaitToolkit(Callable<T> callable) {
|
||||
return executeWaitToolkit(callable, -1, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #executeWaitToolkit(Callable)} except that the method waits no longer than the specified timeout.
|
||||
*/
|
||||
public static <T> T executeWaitToolkit(Callable<T> callable, long timeout, TimeUnit unit) {
|
||||
if (callable == null) return null;
|
||||
|
||||
if (FontUtilities.isMacOSX && EventQueue.isDispatchThread()) {
|
||||
AWTThreading instance = getInstance(Thread.currentThread());
|
||||
if (instance != null) {
|
||||
return instance.execute(callable, timeout, unit);
|
||||
}
|
||||
}
|
||||
// fallback to default
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private <T> T execute(Callable<T> callable, long timeout, TimeUnit unit) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
if (executor == null) {
|
||||
// init on EDT
|
||||
AccessController.doPrivileged((PrivilegedAction<?>)() ->
|
||||
executor = new ThreadPoolExecutor(1, Integer.MAX_VALUE,
|
||||
60L, TimeUnit.SECONDS,
|
||||
new SynchronousQueue<>(),
|
||||
new ThreadFactory() {
|
||||
private final ThreadFactory factory = Executors.privilegedThreadFactory();
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = factory.newThread(r);
|
||||
t.setDaemon(true);
|
||||
t.setName("AWT-" + AWTThreading.class.getSimpleName() + " " + t.getName());
|
||||
return t;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
level++;
|
||||
try {
|
||||
TrackingQueue currentQueue;
|
||||
synchronized (invocations) {
|
||||
if (level == 1 && invocations.size() == 1) {
|
||||
currentQueue = invocations.peek();
|
||||
} else {
|
||||
invocations.push(currentQueue = new TrackingQueue());
|
||||
}
|
||||
}
|
||||
|
||||
FutureTask<T> task = new FutureTask<>(callable) {
|
||||
@Override
|
||||
protected void done() {
|
||||
synchronized (invocations) {
|
||||
invocations.remove(currentQueue);
|
||||
// add dummy event to wake up the queue
|
||||
currentQueue.add(new InvocationEvent(new Object(), () -> {}));
|
||||
}
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
|
||||
try {
|
||||
while (!task.isDone() || !currentQueue.isEmpty()) {
|
||||
InvocationEvent event;
|
||||
if (timeout >= 0 && unit != null) {
|
||||
event = currentQueue.poll(timeout, unit);
|
||||
} else {
|
||||
event = currentQueue.take();
|
||||
}
|
||||
if (event == null) {
|
||||
task.cancel(false);
|
||||
synchronized (invocations) {
|
||||
invocations.remove(currentQueue);
|
||||
}
|
||||
new RuntimeException("Waiting for the invocation event timed out").printStackTrace();
|
||||
break;
|
||||
}
|
||||
event.dispatch();
|
||||
}
|
||||
return task.isCancelled() ? null : task.get();
|
||||
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
level--;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by implementation.
|
||||
* Creates an invocation event and adds it to the tracking queue.
|
||||
* It's assumed the event is then posted to EventQueue.
|
||||
* The following is provided:
|
||||
* <ul>
|
||||
* <li>If the event is first dispatched from EventQueue - it gets removed from the tracking queue.
|
||||
* <li>If the event is first dispatched from the tracking queue - its dispatching on EventQueue will be noop.
|
||||
* <ul>
|
||||
*/
|
||||
public static InvocationEvent createAndTrackInvocationEvent(Object source, Runnable runnable, Runnable listener, boolean catchThrowables) {
|
||||
AWTThreading instance = getInstance(source);
|
||||
if (instance != null) {
|
||||
synchronized (instance.invocations) {
|
||||
if (instance.invocations.isEmpty()) {
|
||||
instance.invocations.push(new TrackingQueue());
|
||||
}
|
||||
final TrackingQueue queue = instance.invocations.peek();
|
||||
InvocationEvent event = new InvocationEvent(source, runnable, listener, catchThrowables) {
|
||||
final SoftReference<TrackingQueue> queueRef = new SoftReference<>(queue);
|
||||
|
||||
@Override
|
||||
public void dispatch() {
|
||||
if (!isDispatched()) {
|
||||
super.dispatch();
|
||||
|
||||
TrackingQueue queue = queueRef.get();
|
||||
if (queue != null) {
|
||||
queue.remove(this);
|
||||
queueRef.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
queue.add(event);
|
||||
return event;
|
||||
}
|
||||
}
|
||||
return new InvocationEvent(source, runnable, listener, catchThrowables);
|
||||
}
|
||||
|
||||
private static AWTThreading getInstance(Object obj) {
|
||||
if (obj == null) return null;
|
||||
|
||||
AppContext appContext = SunToolkit.targetToAppContext(obj);
|
||||
if (appContext == null) return null;
|
||||
|
||||
return getInstance((EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY));
|
||||
}
|
||||
|
||||
private static AWTThreading getInstance(EventQueue eq) {
|
||||
if (eq == null) return null;
|
||||
|
||||
return getInstance(AWTAccessor.getEventQueueAccessor().getDispatchThread(eq));
|
||||
}
|
||||
|
||||
private static AWTThreading getInstance(Thread edt) {
|
||||
if (edt == null) return null;
|
||||
|
||||
return EDT_TO_INSTANCE_MAP.computeIfAbsent(edt, key -> new AWTThreading());
|
||||
}
|
||||
}
|
||||
@@ -1,157 +1,15 @@
|
||||
package sun.awt;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.InvocationEvent;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* Used to perform a blocking invocation on Toolkit thread from EDT, preventing a deadlock.
|
||||
* The deadlock can happen when EDT and Toolkit perform blocking invocations at the same time.
|
||||
* The following is performed to resolve it:
|
||||
* 1) The invoker spins a nested event loop on EDT while waiting for the invocation to complete.
|
||||
* 2) A separate pool thread is used to perform the invocation.
|
||||
* TODO: remove it in JBR 202
|
||||
*
|
||||
* @deprecated
|
||||
* @see AWTThreading
|
||||
*/
|
||||
public class InvokeOnToolkitHelper {
|
||||
private ExecutorService executor;
|
||||
// every invokeAndWait() pushes a queue of invocations
|
||||
private final Stack<LinkedBlockingQueue<InvocationEvent>> invocations = new Stack<>();
|
||||
|
||||
// invocations should be dispatched on proper EDT (per AppContext)
|
||||
private static final Map<Thread, InvokeOnToolkitHelper> edt2invokerMap = new ConcurrentHashMap<>();
|
||||
|
||||
private static final int WAIT_LIMIT_SECONDS = 5;
|
||||
|
||||
private InvokeOnToolkitHelper() {}
|
||||
|
||||
/**
|
||||
* Invokes the callable on Toolkit thread and blocks until the completion. The method is re-entrant.
|
||||
*
|
||||
* On macOS it is assumed the callable wraps a native selector. The selector should be executed via [JNFRunLoop performOnMainThreadWaiting:YES ...]
|
||||
* so that the doAWTRunLoop on AppKit (which is run in [JNFRunLoop javaRunLoopMode]) accepts it. The callable wrapper should not call any Java code
|
||||
* which would normally be called on EDT.
|
||||
* <p>
|
||||
* If Toolkit posts invocation events caused by the callable, those events are intercepted and dispatched on EDT out of order.
|
||||
* <p>
|
||||
* When called on non-EDT, the method invokes the callable in place.
|
||||
*/
|
||||
public static <T> T invokeAndBlock(Callable<T> callable) {
|
||||
if (callable == null) return null;
|
||||
|
||||
if (EventQueue.isDispatchThread()) {
|
||||
InvokeOnToolkitHelper invoker = getInstance(Thread.currentThread());
|
||||
if (invoker != null) {
|
||||
return invoker.invoke(callable);
|
||||
}
|
||||
}
|
||||
// fallback to default
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private <T> T invoke(Callable<T> callable) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
if (executor == null) {
|
||||
// init on EDT
|
||||
AccessController.doPrivileged((PrivilegedAction<?>)() ->
|
||||
executor = new ThreadPoolExecutor(1, Integer.MAX_VALUE,
|
||||
60L, TimeUnit.SECONDS,
|
||||
new SynchronousQueue<>(),
|
||||
new ThreadFactory() {
|
||||
private final ThreadFactory factory = Executors.privilegedThreadFactory();
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = factory.newThread(r);
|
||||
t.setDaemon(true);
|
||||
t.setName("AWT-InvokeOnToolkitHelper " + t.getName());
|
||||
return t;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
LinkedBlockingQueue<InvocationEvent> currentQueue;
|
||||
synchronized (invocations) {
|
||||
invocations.push(currentQueue = new LinkedBlockingQueue<>());
|
||||
}
|
||||
|
||||
FutureTask<T> task = new FutureTask<T>(callable) {
|
||||
@Override
|
||||
protected void done() {
|
||||
synchronized (invocations) {
|
||||
// Done with the current queue, wake it up.
|
||||
invocations.pop().add(new InvocationEvent(executor, () -> {}));
|
||||
}
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
|
||||
try {
|
||||
while (!task.isDone() || !currentQueue.isEmpty()) {
|
||||
InvocationEvent event = currentQueue.poll(WAIT_LIMIT_SECONDS, TimeUnit.SECONDS);
|
||||
if (event == null) {
|
||||
new RuntimeException("Waiting for the invocation event timed out").printStackTrace();
|
||||
break;
|
||||
}
|
||||
event.dispatch();
|
||||
}
|
||||
return task.isDone() ? task.get() : null;
|
||||
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning: the method is used by the implementation and should not be used by a client.
|
||||
*
|
||||
* Checks if there's an active InvokeOnToolkitHelper corresponding to the invocation's AppContext,
|
||||
* adds the invocation to the InvokeOnToolkitHelper's queue and returns true.
|
||||
* Otherwise does nothing and returns false.
|
||||
*/
|
||||
public static boolean offer(InvocationEvent invocation) {
|
||||
Object source = invocation.getSource();
|
||||
|
||||
InvokeOnToolkitHelper invoker = (source instanceof Component) ?
|
||||
getInstance((Component)source) :
|
||||
getInstance(Toolkit.getDefaultToolkit().getSystemEventQueue());
|
||||
|
||||
if (invoker == null) return false;
|
||||
|
||||
synchronized (invoker.invocations) {
|
||||
if (!invoker.invocations.isEmpty()) {
|
||||
invoker.invocations.peek().add(invocation);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static InvokeOnToolkitHelper getInstance(Component comp) {
|
||||
if (comp == null) return null;
|
||||
|
||||
AppContext appContext = SunToolkit.targetToAppContext(comp);
|
||||
if (appContext == null) return null;
|
||||
|
||||
return getInstance((EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY));
|
||||
}
|
||||
|
||||
private static InvokeOnToolkitHelper getInstance(EventQueue eq) {
|
||||
if (eq == null) return null;
|
||||
|
||||
return getInstance(AWTAccessor.getEventQueueAccessor().getDispatchThread(eq));
|
||||
}
|
||||
|
||||
private static InvokeOnToolkitHelper getInstance(Thread edt) {
|
||||
if (edt == null) return null;
|
||||
|
||||
return edt2invokerMap.computeIfAbsent(edt, key -> new InvokeOnToolkitHelper());
|
||||
return AWTThreading.executeWaitToolkit(callable);
|
||||
}
|
||||
}
|
||||
|
||||
21
src/java.desktop/share/classes/sun/awt/event/TouchEvent.java
Normal file
21
src/java.desktop/share/classes/sun/awt/event/TouchEvent.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package sun.awt.event;
|
||||
|
||||
import java.lang.annotation.Native;
|
||||
|
||||
public class TouchEvent {
|
||||
@Native public static final int TOUCH_BEGIN = 2;
|
||||
@Native public static final int TOUCH_UPDATE = 3;
|
||||
@Native public static final int TOUCH_END = 4;
|
||||
|
||||
/**
|
||||
* The allowable difference between coordinates of touch update events
|
||||
* in pixels
|
||||
*/
|
||||
@Native public static final int CLICK_RADIUS = 10;
|
||||
|
||||
/**
|
||||
* Stop owning touch processing after timeout
|
||||
* in ms
|
||||
*/
|
||||
public static final long NO_UPDATE_TIMEOUT = 1000L;
|
||||
}
|
||||
@@ -111,10 +111,6 @@ public abstract class FileFont extends PhysicalFont {
|
||||
return 1; // DEFAULT_CHARSET
|
||||
}
|
||||
|
||||
int getFontDataSize() {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the public interface. The subclasses need to implement
|
||||
* this. The returned block may be longer than the requested length.
|
||||
|
||||
@@ -442,12 +442,8 @@ public class FileFontStrike extends PhysicalStrike {
|
||||
}
|
||||
if (ptr == 0) {
|
||||
boolean fm = desc.fmHint == INTVAL_FRACTIONALMETRICS_ON;
|
||||
ptr = _getGlyphImageFromWindows(family, style, size, glyphCode, fm, rotation, charset,
|
||||
fileFont.getFontDataSize());
|
||||
if (ptr == 0 && FontUtilities.isLogging()) {
|
||||
FontUtilities.getLogger().warning("Failed to render glyph via GDI: code=" + glyphCode
|
||||
+ ", fontFamily=" + family + ", style=" + style + ", size=" + size + ", rotation=" + rotation);
|
||||
}
|
||||
ptr = _getGlyphImageFromWindows(family, style, size, glyphCode, fm,
|
||||
rotation, charset, ((TrueTypeFont)fileFont).fontDataSize);
|
||||
if (ptr != 0 && fm) {
|
||||
Point2D.Float metrics = new Point2D.Float();
|
||||
fileFont.getGlyphMetrics(pScalerContext, glyphCode, metrics);
|
||||
@@ -456,6 +452,12 @@ public class FileFontStrike extends PhysicalStrike {
|
||||
}
|
||||
}
|
||||
if (ptr == 0) {
|
||||
if (FontUtilities.isLogging()) {
|
||||
FontUtilities.getLogger().warning(
|
||||
"Failed to render glyph using GDI: code=" + glyphCode
|
||||
+ ", fontFamily=" + family + ", style=" + style
|
||||
+ ", size=" + size);
|
||||
}
|
||||
ptr = fileFont.getGlyphImage(pScalerContext, glyphCode);
|
||||
}
|
||||
return ptr;
|
||||
|
||||
@@ -64,6 +64,38 @@ import sun.util.logging.PlatformLogger;
|
||||
* methods that have to be implemented by specific implementations.
|
||||
*/
|
||||
public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
|
||||
protected static class BundledFontInfo {
|
||||
private String psName;
|
||||
private int [] version;
|
||||
|
||||
public BundledFontInfo(String psName, int major, int minor, int bugfix) {
|
||||
this.psName = psName;
|
||||
version = new int[3];
|
||||
version[0] = major;
|
||||
version[1] = minor;
|
||||
version[2] = bugfix;
|
||||
}
|
||||
|
||||
public String getPsName() {
|
||||
return psName;
|
||||
}
|
||||
|
||||
public boolean isNewerThan(int[] version) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (this.version[i] < version[i]) {
|
||||
return false;
|
||||
} else if (this.version[i] > version[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return psName + " v" + version[0] + "." + version[1] + "." + version[2];
|
||||
}
|
||||
}
|
||||
|
||||
private static class TTFilter implements FilenameFilter {
|
||||
public boolean accept(File dir,String name) {
|
||||
@@ -187,7 +219,7 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
|
||||
private boolean loaded1dot0Fonts = false;
|
||||
boolean loadedAllFonts = false;
|
||||
boolean loadedAllFontFiles = false;
|
||||
private HashMap<String,String> jreFontMap;
|
||||
private HashMap<String,BundledFontInfo> jreFontMap;
|
||||
private HashSet<String> jreBundledFontFiles;
|
||||
HashMap<String,String> jreFamilyMap;
|
||||
String[] jreOtherFontFiles;
|
||||
@@ -230,6 +262,7 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
|
||||
private Locale lastDefaultLocale;
|
||||
|
||||
public static boolean noType1Font;
|
||||
public static boolean versionCheckEnabled;
|
||||
|
||||
/* Used to indicate required return type from toArray(..); */
|
||||
private static String[] STR_ARRAY = new String[0];
|
||||
@@ -279,60 +312,55 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
|
||||
* are rarely used. Consider removing the other mappings if there's
|
||||
* no evidence they are useful in practice.
|
||||
*/
|
||||
jreFontMap = new HashMap<String, String>();
|
||||
jreFontMap = new HashMap<>();
|
||||
jreBundledFontFiles = new HashSet<String>();
|
||||
jreFamilyMap = new HashMap<>();
|
||||
|
||||
/* Droid Sans Mono Family */
|
||||
jreFontMap.put("droid sans0", "DroidSans.ttf");
|
||||
jreFontMap.put("droid sans1", "DroidSans-Bold.ttf");
|
||||
jreFontMap.put("droid sans bold1", "DroidSans-Bold.ttf");
|
||||
jreFontMap.put("DroidSans.ttf", new BundledFontInfo("DroidSans", 1, 0, 0));
|
||||
jreFontMap.put("DroidSans-Bold.ttf", new BundledFontInfo("DroidSans-Bold", 1, 0, 0));
|
||||
|
||||
/* Droid Sans Mono Family */
|
||||
jreFontMap.put("droid sans mono0", "DroidSansMono.ttf");
|
||||
jreFontMap.put("droid sans mono slashed0",
|
||||
"DroidSansMonoSlashed.ttf");
|
||||
jreFontMap.put("droid sans mono dotted0",
|
||||
"DroidSansMonoDotted.ttf");
|
||||
jreFontMap.put("DroidSansMono.ttf", new BundledFontInfo("DroidSansMono", 1, 0, 0));
|
||||
jreFontMap.put("DroidSansMonoSlashed.ttf", new BundledFontInfo("DroidSansMonoSlashed", 1, 0, 0));
|
||||
jreFontMap.put("DroidSansMonoDotted.ttf", new BundledFontInfo("DroidSansMonoDotted", 1, 0, 0));
|
||||
|
||||
/* Droid Serif Family */
|
||||
jreFontMap.put("droid serif0", "DroidSerif-Regular.ttf");
|
||||
jreFontMap.put("droid serif1", "DroidSerif-Bold.ttf");
|
||||
jreFontMap.put("droid serif2", "DroidSerif-Italic.ttf");
|
||||
jreFontMap.put("droid serif3", "DroidSerif-BoldItalic.ttf");
|
||||
jreFontMap.put("droid serif bold1", "DroidSerif-Bold.ttf");
|
||||
jreFontMap.put("droid serif bold italic3", "DroidSerif-BoldItalic.ttf");
|
||||
jreFontMap.put("DroidSerif-Regular.ttf", new BundledFontInfo("DroidSerif", 1, 0, 0));
|
||||
jreFontMap.put("DroidSerif-Bold.ttf", new BundledFontInfo("DroidSerif-Bold", 1, 0, 0));
|
||||
jreFontMap.put("DroidSerif-Italic.ttf", new BundledFontInfo("DroidSerif-Italic", 1, 0, 0));
|
||||
jreFontMap.put("DroidSerif-BoldItalic.ttf", new BundledFontInfo("DroidSerif-BoldItalic", 1, 0, 0));
|
||||
|
||||
/* Idea bundled fonts */
|
||||
jreFontMap.put("FiraCode bold", "FiraCode-Bold.ttf");
|
||||
jreFontMap.put("FiraCode light", "FiraCode-Light.ttf");
|
||||
jreFontMap.put("FiraCode medium", "FiraCode-Medium.ttf");
|
||||
jreFontMap.put("FiraCode retina", "FiraCode-Retina.ttf");
|
||||
jreFontMap.put("FiraCode regular", "FiraCode-Regular.ttf");
|
||||
jreFontMap.put("FiraCode-Bold.ttf", new BundledFontInfo("FiraCode-Bold", 1, 206, 0));
|
||||
jreFontMap.put("FiraCode-Light.ttf", new BundledFontInfo("FiraCode-Light", 1, 206, 0));
|
||||
jreFontMap.put("FiraCode-Medium.ttf", new BundledFontInfo("FiraCode-Medium", 1, 206, 0));
|
||||
jreFontMap.put("FiraCode-Retina.ttf", new BundledFontInfo("FiraCode-Retina", 1, 206, 0));
|
||||
jreFontMap.put("FiraCode-Regular.ttf", new BundledFontInfo("FiraCode-Regular", 1, 206, 0));
|
||||
|
||||
jreFamilyMap.put("FiraCode-Medium", "Fira Code Medium");
|
||||
jreFamilyMap.put("FiraCode-Retina", "Fira Code Retina");
|
||||
jreFamilyMap.put("FiraCode-Light", "Fira Code Light");
|
||||
|
||||
jreFontMap.put("SourceCodePro bold italic", "SourceCodePro-BoldIt.ttf");
|
||||
jreFontMap.put("SourceCodePro regular", "SourceCodePro-Regular.ttf");
|
||||
jreFontMap.put("SourceCodePro bold", "SourceCodePro-Bold.ttf");
|
||||
jreFontMap.put("SourceCodePro italic", "SourceCodePro-It.ttf");
|
||||
jreFontMap.put("SourceCodePro-BoldIt.ttf", new BundledFontInfo("SourceCodePro-BoldIt", 1, 30, 0));
|
||||
jreFontMap.put("SourceCodePro-Regular.ttf", new BundledFontInfo("SourceCodePro-Regular", 2, 10, 0));
|
||||
jreFontMap.put("SourceCodePro-Bold.ttf", new BundledFontInfo("SourceCodePro-Bold", 2, 10, 0));
|
||||
jreFontMap.put("SourceCodePro-It.ttf", new BundledFontInfo("SourceCodePro-It", 1, 30, 0));
|
||||
|
||||
jreFontMap.put("Inconsolata", "Inconsolata.ttf");
|
||||
jreFontMap.put("Inconsolata.ttf", new BundledFontInfo("Inconsolata", 1, 10, 0));
|
||||
|
||||
jreFontMap.put("Roboto light", "Roboto-Light.ttf");
|
||||
jreFontMap.put("Roboto thin", "Roboto-Thin.ttf");
|
||||
jreFontMap.put("Roboto-Light.ttf", new BundledFontInfo("Roboto-Light", 1, 100141, 0));
|
||||
jreFontMap.put("Roboto-Thin.ttf", new BundledFontInfo("Roboto-Thin", 1, 100141, 0));
|
||||
|
||||
jreFamilyMap.put("Roboto-Light", "Roboto Light");
|
||||
jreFamilyMap.put("Roboto-Thin", "Roboto Thin");
|
||||
|
||||
jreFontMap.put("JetBrains Mono Bold", "JetBrainsMono-Bold.ttf");
|
||||
jreFontMap.put("JetBrains Mono Regular", "JetBrainsMono-Regular.ttf");
|
||||
jreFontMap.put("JetBrains Mono Italic", "JetBrainsMono-Italic.ttf");
|
||||
jreFontMap.put("JetBrains Mono Bold Italic", "JetBrainsMono-Bold-Italic.ttf");
|
||||
jreFontMap.put("JetBrainsMono-Bold.ttf", new BundledFontInfo("JetBrainsMono-Bold", 1, 0, 2));
|
||||
jreFontMap.put("JetBrainsMono-Regular.ttf", new BundledFontInfo("JetBrainsMono-Regular", 1, 0, 2));
|
||||
jreFontMap.put("JetBrainsMono-Italic.ttf", new BundledFontInfo("JetBrainsMono-Italic", 1, 0, 2));
|
||||
jreFontMap.put("JetBrainsMono-Bold-Italic.ttf", new BundledFontInfo("JetBrainsMono-BoldItalic", 1, 0, 2));
|
||||
|
||||
jreBundledFontFiles.addAll(jreFontMap.values());
|
||||
jreBundledFontFiles.addAll(jreFontMap.keySet());
|
||||
}
|
||||
|
||||
static {
|
||||
@@ -353,6 +381,9 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
|
||||
default: throw new RuntimeException("Unexpected address size");
|
||||
}
|
||||
|
||||
versionCheckEnabled =
|
||||
!("true".equals(System.getProperty("java2d.font.noVersionCheck")));
|
||||
|
||||
noType1Font =
|
||||
"true".equals(System.getProperty("sun.java2d.noType1Font"));
|
||||
jreLibDirName =
|
||||
@@ -3887,4 +3918,90 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
|
||||
public boolean areColorGlyphsSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected BundledFontInfo getBundledFontInfo(String fileName) {
|
||||
return jreFontMap.get(fileName);
|
||||
}
|
||||
|
||||
protected static boolean parseFontVersion(String versionString, int[] version) {
|
||||
int i = 0;
|
||||
boolean foundDigit = false;
|
||||
version[0] = version[1] = version[2] = 0;
|
||||
|
||||
// Skip prefix letters
|
||||
while (i < versionString.length() &&
|
||||
!(foundDigit = Character.isDigit(versionString.charAt(i)))) {
|
||||
i++;
|
||||
}
|
||||
if (!foundDigit) {
|
||||
return false;
|
||||
}
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
boolean foundDot = false;
|
||||
// Read major version
|
||||
while (i < versionString.length() &&
|
||||
!(foundDot = (versionString.charAt(i) == '.')) &&
|
||||
Character.isDigit(versionString.charAt(i))) {
|
||||
buf.append(versionString.charAt(i));
|
||||
i++;
|
||||
}
|
||||
try {
|
||||
version[0] = Integer.parseInt(buf.toString());
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!foundDot) {
|
||||
return true;
|
||||
}
|
||||
buf.setLength(0);
|
||||
i++;
|
||||
foundDigit = false;
|
||||
|
||||
// Read minor version
|
||||
while (i < versionString.length() &&
|
||||
!(foundDot = (versionString.charAt(i) == '.')) &&
|
||||
Character.isDigit(versionString.charAt(i))) {
|
||||
buf.append(versionString.charAt(i));
|
||||
foundDigit = true;
|
||||
i++;
|
||||
}
|
||||
if (!foundDigit) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
version[1] = Integer.parseInt(buf.toString());
|
||||
} catch (NumberFormatException e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!foundDot) {
|
||||
return true;
|
||||
}
|
||||
|
||||
buf.setLength(0);
|
||||
i++;
|
||||
foundDigit = false;
|
||||
|
||||
// Read bugfix version
|
||||
while (i < versionString.length() &&
|
||||
!(versionString.charAt(i) == '.') &&
|
||||
Character.isDigit(versionString.charAt(i))) {
|
||||
buf.append(versionString.charAt(i));
|
||||
foundDigit = true;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!foundDigit) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
version[2] = Integer.parseInt(buf.toString());
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +181,15 @@ public class TrueTypeFont extends FileFont {
|
||||
private String localeFullName;
|
||||
|
||||
private Byte supportedCharset;
|
||||
private int fontDataSize;
|
||||
|
||||
/*
|
||||
* Used on Windows to validate the font selected by GDI for (sub-pixel
|
||||
* antialiased) rendering. For 'standalone' fonts it's equal to the font
|
||||
* file size, for collection (TTC, OTC) members it's the number of bytes in
|
||||
* the collection file from the start of this font's offset table till the
|
||||
* end of the file.
|
||||
*/
|
||||
int fontDataSize;
|
||||
|
||||
public TrueTypeFont(String platname, Object nativeNames, int fIndex,
|
||||
boolean javaRasterizer)
|
||||
@@ -1783,11 +1791,6 @@ public class TrueTypeFont extends FileFont {
|
||||
|
||||
private static native void getSupportedCharsetsForFamily(String familyName, Map<String, Byte> supportedCharsets);
|
||||
|
||||
@Override
|
||||
int getFontDataSize() {
|
||||
return fontDataSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "** TrueType Font: Family="+familyName+ " Name="+fullName+
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
package sun.java2d.opengl;
|
||||
|
||||
import sun.awt.AWTThreading;
|
||||
import sun.awt.util.ThreadGroupUtils;
|
||||
import sun.java2d.pipe.RenderBuffer;
|
||||
import sun.java2d.pipe.RenderQueue;
|
||||
@@ -32,6 +33,7 @@ import sun.java2d.pipe.RenderQueue;
|
||||
import static sun.java2d.pipe.BufferedOpCodes.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* OGL-specific implementation of RenderQueue. This class provides a
|
||||
@@ -153,7 +155,7 @@ public class OGLRenderQueue extends RenderQueue {
|
||||
}
|
||||
|
||||
private class QueueFlusher implements Runnable {
|
||||
private boolean needsFlush;
|
||||
private volatile boolean needsFlush;
|
||||
private Runnable task;
|
||||
private Error error;
|
||||
private final Thread thread;
|
||||
@@ -167,28 +169,49 @@ public class OGLRenderQueue extends RenderQueue {
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public synchronized void flushNow() {
|
||||
// wake up the flusher
|
||||
needsFlush = true;
|
||||
notify();
|
||||
public void flushNow() {
|
||||
flushNow(null);
|
||||
}
|
||||
|
||||
// wait for flush to complete
|
||||
while (needsFlush) {
|
||||
private void flushNow(Runnable task) {
|
||||
Error err;
|
||||
synchronized (this) {
|
||||
if (task != null) {
|
||||
this.task = task;
|
||||
}
|
||||
// wake up the flusher
|
||||
needsFlush = true;
|
||||
notifyAll();
|
||||
|
||||
// wait for flush to complete
|
||||
try {
|
||||
wait();
|
||||
wait(100);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
err = error;
|
||||
}
|
||||
if (needsFlush) {
|
||||
// if we still wait for flush then avoid potential deadlock
|
||||
err = AWTThreading.executeWaitToolkit(() -> {
|
||||
synchronized (QueueFlusher.this) {
|
||||
while (needsFlush) {
|
||||
try {
|
||||
QueueFlusher.this.wait();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
}, 5, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
// re-throw any error that may have occurred during the flush
|
||||
if (error != null) {
|
||||
throw error;
|
||||
if (err != null) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void flushAndInvokeNow(Runnable task) {
|
||||
this.task = task;
|
||||
flushNow();
|
||||
public void flushAndInvokeNow(Runnable task) {
|
||||
flushNow(task);
|
||||
}
|
||||
|
||||
public synchronized void run() {
|
||||
@@ -242,7 +265,7 @@ public class OGLRenderQueue extends RenderQueue {
|
||||
task = null;
|
||||
// allow the waiting thread to continue
|
||||
needsFlush = false;
|
||||
notify();
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ import java.text.AttributedCharacterIterator;
|
||||
import java.text.AttributedString;
|
||||
import java.text.BreakIterator;
|
||||
import java.text.CharacterIterator;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -103,9 +104,11 @@ import sun.font.FontUtilities;
|
||||
import sun.java2d.SunGraphicsEnvironment;
|
||||
import sun.print.ProxyPrintGraphics;
|
||||
|
||||
import static java.awt.RenderingHints.KEY_FRACTIONALMETRICS;
|
||||
import static java.awt.RenderingHints.KEY_TEXT_ANTIALIASING;
|
||||
import static java.awt.RenderingHints.KEY_TEXT_LCD_CONTRAST;
|
||||
import static java.awt.RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT;
|
||||
import static java.awt.RenderingHints.VALUE_FRACTIONALMETRICS_OFF;
|
||||
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT;
|
||||
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR;
|
||||
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB;
|
||||
@@ -566,25 +569,9 @@ public class SwingUtilities2 {
|
||||
? null
|
||||
: c.getClientProperty(KEY_TEXT_ANTIALIASING);
|
||||
if (aaHint != null) {
|
||||
Object oldContrast = null;
|
||||
Object oldAAValue = g2.getRenderingHint(KEY_TEXT_ANTIALIASING);
|
||||
if (aaHint != oldAAValue) {
|
||||
g2.setRenderingHint(KEY_TEXT_ANTIALIASING, aaHint);
|
||||
} else {
|
||||
oldAAValue = null;
|
||||
}
|
||||
|
||||
Object lcdContrastHint = c.getClientProperty(
|
||||
KEY_TEXT_LCD_CONTRAST);
|
||||
if (lcdContrastHint != null) {
|
||||
oldContrast = g2.getRenderingHint(KEY_TEXT_LCD_CONTRAST);
|
||||
if (lcdContrastHint.equals(oldContrast)) {
|
||||
oldContrast = null;
|
||||
} else {
|
||||
g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST,
|
||||
lcdContrastHint);
|
||||
}
|
||||
}
|
||||
Object oldAAValue = configureHint(KEY_TEXT_ANTIALIASING, g2, aaHint);
|
||||
Object oldFMValue = configureHint(KEY_FRACTIONALMETRICS, g2, c);
|
||||
Object oldContrast = configureHint(KEY_TEXT_LCD_CONTRAST, g2, c);
|
||||
|
||||
if (needsTextLayout) {
|
||||
TextLayout layout = createTextLayout(c, text, g2.getFont(),
|
||||
@@ -594,12 +581,9 @@ public class SwingUtilities2 {
|
||||
g2.drawString(text, x, y);
|
||||
}
|
||||
|
||||
if (oldAAValue != null) {
|
||||
g2.setRenderingHint(KEY_TEXT_ANTIALIASING, oldAAValue);
|
||||
}
|
||||
if (oldContrast != null) {
|
||||
g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST, oldContrast);
|
||||
}
|
||||
restoreHint(KEY_TEXT_ANTIALIASING, g2, oldAAValue);
|
||||
restoreHint(KEY_FRACTIONALMETRICS, g2, oldFMValue);
|
||||
restoreHint(KEY_TEXT_LCD_CONTRAST, g2, oldContrast);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -905,34 +889,15 @@ public class SwingUtilities2 {
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
if (aaHint != null) {
|
||||
|
||||
Object oldContrast = null;
|
||||
Object oldAAValue = g2.getRenderingHint(KEY_TEXT_ANTIALIASING);
|
||||
if (aaHint != null && aaHint != oldAAValue) {
|
||||
g2.setRenderingHint(KEY_TEXT_ANTIALIASING, aaHint);
|
||||
} else {
|
||||
oldAAValue = null;
|
||||
}
|
||||
|
||||
Object lcdContrastHint = c.getClientProperty(KEY_TEXT_LCD_CONTRAST);
|
||||
if (lcdContrastHint != null) {
|
||||
oldContrast = g2.getRenderingHint(KEY_TEXT_LCD_CONTRAST);
|
||||
if (lcdContrastHint.equals(oldContrast)) {
|
||||
oldContrast = null;
|
||||
} else {
|
||||
g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST,
|
||||
lcdContrastHint);
|
||||
}
|
||||
}
|
||||
Object oldAAValue = configureHint(KEY_TEXT_ANTIALIASING, g2, aaHint);
|
||||
Object oldFMValue = configureHint(KEY_FRACTIONALMETRICS, g2, c);
|
||||
Object oldContrast = configureHint(KEY_TEXT_LCD_CONTRAST, g2, c);
|
||||
|
||||
g2.drawString(new String(data, offset, length), x, y);
|
||||
|
||||
if (oldAAValue != null) {
|
||||
g2.setRenderingHint(KEY_TEXT_ANTIALIASING, oldAAValue);
|
||||
}
|
||||
if (oldContrast != null) {
|
||||
g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST, oldContrast);
|
||||
}
|
||||
restoreHint(KEY_TEXT_ANTIALIASING, g2, oldAAValue);
|
||||
restoreHint(KEY_FRACTIONALMETRICS, g2, oldFMValue);
|
||||
restoreHint(KEY_TEXT_LCD_CONTRAST, g2, oldContrast);
|
||||
}
|
||||
else {
|
||||
g2.drawString(new String(data, offset, length), x, y);
|
||||
@@ -1249,7 +1214,6 @@ public class SwingUtilities2 {
|
||||
*/
|
||||
private static FontRenderContext getFRCProperty(JComponent c) {
|
||||
if (c != null) {
|
||||
|
||||
GraphicsConfiguration gc = c.getGraphicsConfiguration();
|
||||
AffineTransform tx = (gc == null) ? null : gc.getDefaultTransform();
|
||||
if (tx == null && !GraphicsEnvironment.isHeadless()) {
|
||||
@@ -1260,16 +1224,22 @@ public class SwingUtilities2 {
|
||||
.getDefaultTransform();
|
||||
}
|
||||
Object aaHint = c.getClientProperty(KEY_TEXT_ANTIALIASING);
|
||||
return getFRCFromCache(tx, aaHint);
|
||||
if (aaHint == null) aaHint = VALUE_TEXT_ANTIALIAS_DEFAULT;
|
||||
|
||||
Object fmHint = c.getClientProperty(KEY_FRACTIONALMETRICS);
|
||||
if (fmHint == null) fmHint = VALUE_FRACTIONALMETRICS_DEFAULT;
|
||||
|
||||
return getFRCFromCache(tx, aaHint, fmHint);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final Object APP_CONTEXT_FRC_CACHE_KEY = new Object();
|
||||
|
||||
private static FontRenderContext getFRCFromCache(AffineTransform tx,
|
||||
Object aaHint) {
|
||||
if (tx == null && aaHint == null) {
|
||||
private static FontRenderContext getFRCFromCache(AffineTransform tx, Object aaHint, Object fmHint) {
|
||||
if ((tx == null || tx.isIdentity())
|
||||
&& (aaHint == VALUE_TEXT_ANTIALIAS_OFF || aaHint == VALUE_TEXT_ANTIALIAS_DEFAULT)
|
||||
&& (fmHint == VALUE_FRACTIONALMETRICS_OFF || fmHint == VALUE_FRACTIONALMETRICS_DEFAULT)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1283,41 +1253,31 @@ public class SwingUtilities2 {
|
||||
}
|
||||
|
||||
Object key = (tx == null)
|
||||
? aaHint
|
||||
: (aaHint == null ? tx : new KeyPair(tx, aaHint));
|
||||
? new KeyArray(aaHint, fmHint)
|
||||
: new KeyArray(tx, aaHint, fmHint);
|
||||
|
||||
FontRenderContext frc = cache.get(key);
|
||||
if (frc == null) {
|
||||
aaHint = (aaHint == null) ? VALUE_TEXT_ANTIALIAS_OFF : aaHint;
|
||||
frc = new FontRenderContext(tx, aaHint,
|
||||
VALUE_FRACTIONALMETRICS_DEFAULT);
|
||||
cache.put(key, frc);
|
||||
}
|
||||
return frc;
|
||||
return cache.computeIfAbsent(key, k -> new FontRenderContext(tx, aaHint, fmHint));
|
||||
}
|
||||
|
||||
private static class KeyPair {
|
||||
private static class KeyArray {
|
||||
private final Object[] array;
|
||||
|
||||
private final Object key1;
|
||||
private final Object key2;
|
||||
|
||||
public KeyPair(Object key1, Object key2) {
|
||||
this.key1 = key1;
|
||||
this.key2 = key2;
|
||||
KeyArray(Object... array) {
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof KeyPair)) {
|
||||
public boolean equals(Object object) {
|
||||
if (!(object instanceof KeyArray)) {
|
||||
return false;
|
||||
}
|
||||
KeyPair that = (KeyPair) obj;
|
||||
return this.key1.equals(that.key1) && this.key2.equals(that.key2);
|
||||
KeyArray that = (KeyArray) object;
|
||||
return Arrays.equals(that.array, array);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return key1.hashCode() + 37 * key2.hashCode();
|
||||
return Arrays.hashCode(array);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2349,4 +2309,45 @@ public class SwingUtilities2 {
|
||||
var oldTx = oldGC != null ? oldGC.getDefaultTransform() : null;
|
||||
return !Objects.equals(newTx, oldTx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key the key of the hint to be set
|
||||
* @param g the graphics to configure
|
||||
* @param c the component that provides a hint value
|
||||
* @return a value previously set in the given graphics,
|
||||
* or {@code null} if a hint value is not set
|
||||
*/
|
||||
private static Object configureHint(RenderingHints.Key key, Graphics2D g, JComponent c) {
|
||||
if (c == null) return null; // component is not specified
|
||||
|
||||
return configureHint(key, g, c.getClientProperty(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key the key of the hint to be set
|
||||
* @param g the graphics to configure
|
||||
* @param newValue the new value to set
|
||||
* @return a value previously set in the given graphics,
|
||||
* or {@code null} if a hint value is not set
|
||||
*/
|
||||
private static Object configureHint(RenderingHints.Key key, Graphics2D g, Object newValue) {
|
||||
if (newValue == null) return null; // new value is not provided
|
||||
|
||||
Object oldValue = g.getRenderingHint(key);
|
||||
if (newValue.equals(oldValue)) return null; // value is not changed
|
||||
|
||||
g.setRenderingHint(key, newValue);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key the key of the hint to be set
|
||||
* @param g the graphics to configure
|
||||
* @param oldValue the stored value to set
|
||||
*/
|
||||
private static void restoreHint(RenderingHints.Key key, Graphics2D g, Object oldValue) {
|
||||
if (oldValue == null) return; // nothing to restore
|
||||
|
||||
g.setRenderingHint(key, oldValue);
|
||||
}
|
||||
}
|
||||
|
||||
BIN
src/java.desktop/share/fonts/JetBrainsMono-Bold-Italic.ttf
Executable file → Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-Bold-Italic.ttf
Executable file → Normal file
Binary file not shown.
BIN
src/java.desktop/share/fonts/JetBrainsMono-Bold.ttf
Executable file → Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-Bold.ttf
Executable file → Normal file
Binary file not shown.
BIN
src/java.desktop/share/fonts/JetBrainsMono-Italic.ttf
Executable file → Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-Italic.ttf
Executable file → Normal file
Binary file not shown.
BIN
src/java.desktop/share/fonts/JetBrainsMono-Regular.ttf
Executable file → Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-Regular.ttf
Executable file → Normal file
Binary file not shown.
@@ -36,6 +36,7 @@ import sun.awt.AWTAccessor.ComponentAccessor;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import sun.awt.*;
|
||||
import sun.awt.event.TouchEvent;
|
||||
|
||||
import sun.java2d.SunGraphics2D;
|
||||
import sun.java2d.SurfaceData;
|
||||
@@ -46,6 +47,7 @@ class XWindow extends XBaseWindow implements X11ComponentPeer {
|
||||
private static PlatformLogger eventLog = PlatformLogger.getLogger("sun.awt.X11.event.XWindow");
|
||||
private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.X11.focus.XWindow");
|
||||
private static PlatformLogger keyEventLog = PlatformLogger.getLogger("sun.awt.X11.kye.XWindow");
|
||||
private static PlatformLogger touchEventLog = PlatformLogger.getLogger("sun.awt.event.TouchEvent");
|
||||
/* If a motion comes in while a multi-click is pending,
|
||||
* allow a smudge factor so that moving the mouse by a small
|
||||
* amount does not wipe out the multi-click state variables.
|
||||
@@ -57,14 +59,12 @@ class XWindow extends XBaseWindow implements X11ComponentPeer {
|
||||
static long lastButton = 0;
|
||||
static WeakReference<XWindow> lastWindowRef = null;
|
||||
static int clickCount = 0;
|
||||
|
||||
// all touch scrolls are measured in pixels
|
||||
private static int touchBeginX = 0, touchBeginY = 0;
|
||||
private static int trackingId = 0;
|
||||
private static long lastTouchUpdateTime = 0;
|
||||
private static boolean isTouchScroll = false;
|
||||
private static final int TOUCH_CLICK_RADIUS = 10;
|
||||
// all touch scrolls are measured in pixels
|
||||
private static final int TOUCH_BEGIN = 2;
|
||||
private static final int TOUCH_UPDATE = 3;
|
||||
private static final int TOUCH_END = 4;
|
||||
|
||||
// used to check if we need to re-create surfaceData.
|
||||
int oldWidth = -1;
|
||||
@@ -800,42 +800,61 @@ class XWindow extends XBaseWindow implements X11ComponentPeer {
|
||||
x = localXY.x;
|
||||
y = localXY.y;
|
||||
}
|
||||
|
||||
int button = XConstants.buttons[0];
|
||||
int modifiers = getModifiers(dev.get_mods().get_effective(), button, 0);
|
||||
// turning off shift modifier
|
||||
modifiers &= ~InputEvent.SHIFT_DOWN_MASK;
|
||||
int modifiers = getModifiers(dev.get_mods().get_effective(), MouseEvent.BUTTON1, 0);
|
||||
int scrollModifiers = modifiers & ~InputEvent.SHIFT_DOWN_MASK;
|
||||
|
||||
long jWhen = XToolkit.nowMillisUTC_offset(dev.get_time());
|
||||
|
||||
switch (dev.get_evtype()) {
|
||||
case XConstants.XI_TouchBegin:
|
||||
if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) {
|
||||
touchEventLog.finest("Touch Begin at: " + x + ", " + y);
|
||||
}
|
||||
isTouchScroll = false;
|
||||
touchBeginX = x;
|
||||
touchBeginY = y;
|
||||
sendWheelEventFromTouch(dev, jWhen, modifiers, touchBeginX, touchBeginY, TOUCH_BEGIN, 1);
|
||||
lastTouchUpdateTime = jWhen;
|
||||
sendWheelEventFromTouch(dev, jWhen, scrollModifiers, touchBeginX, touchBeginY, TouchEvent.TOUCH_BEGIN, 1);
|
||||
break;
|
||||
case XConstants.XI_TouchUpdate:
|
||||
if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) {
|
||||
touchEventLog.finest("Touch Update at: " + x + ", " + y);
|
||||
}
|
||||
lastTouchUpdateTime = jWhen;
|
||||
|
||||
if (!isTouchScroll && isInsideTouchClickBoundaries(x, y)) {
|
||||
return;
|
||||
}
|
||||
isTouchScroll = true;
|
||||
|
||||
if (lastY - y != 0) {
|
||||
sendWheelEventFromTouch(dev, jWhen, modifiers, x, y, TOUCH_UPDATE, lastY - y);
|
||||
int deltaY = lastY - y;
|
||||
if (deltaY != 0) {
|
||||
if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) {
|
||||
touchEventLog.finest("Vertical touch scroll, delta: " + deltaY);
|
||||
}
|
||||
sendWheelEventFromTouch(dev, jWhen, scrollModifiers, x, y, TouchEvent.TOUCH_UPDATE, deltaY);
|
||||
}
|
||||
// horizontal scroll
|
||||
if (lastX - x != 0) {
|
||||
modifiers |= InputEvent.SHIFT_DOWN_MASK;
|
||||
sendWheelEventFromTouch(dev, jWhen, modifiers, x, y, TOUCH_UPDATE, lastX - x);
|
||||
|
||||
int deltaX = lastX - x;
|
||||
if (deltaX != 0) {
|
||||
if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) {
|
||||
touchEventLog.finest("Horizontal touch scroll, delta: " + deltaX);
|
||||
}
|
||||
int horizontalScrollMods = scrollModifiers | InputEvent.SHIFT_DOWN_MASK;
|
||||
sendWheelEventFromTouch(dev, jWhen, horizontalScrollMods, x, y, TouchEvent.TOUCH_UPDATE, deltaX);
|
||||
}
|
||||
break;
|
||||
case XConstants.XI_TouchEnd:
|
||||
sendWheelEventFromTouch(dev, jWhen, modifiers, x, y, TOUCH_END, 1);
|
||||
if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) {
|
||||
touchEventLog.finest("Touch End at: " + x + ", " + y);
|
||||
}
|
||||
sendWheelEventFromTouch(dev, jWhen, scrollModifiers, x, y, TouchEvent.TOUCH_END, 1);
|
||||
|
||||
if (!isTouchScroll) {
|
||||
sendMouseEventFromTouch(dev, MouseEvent.MOUSE_PRESSED, jWhen, modifiers, touchBeginX, touchBeginY, button);
|
||||
sendMouseEventFromTouch(dev, MouseEvent.MOUSE_RELEASED, jWhen, modifiers, touchBeginX, touchBeginY, button);
|
||||
sendMouseEventFromTouch(dev, MouseEvent.MOUSE_CLICKED, jWhen, modifiers, touchBeginX, touchBeginY, button);
|
||||
if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) {
|
||||
touchEventLog.finest("Touch Press at: " + x + ", " + y);
|
||||
}
|
||||
sendButtonPressFromTouch(dev, jWhen, modifiers, touchBeginX, touchBeginY);
|
||||
}
|
||||
|
||||
// release touch processing
|
||||
@@ -848,8 +867,8 @@ class XWindow extends XBaseWindow implements X11ComponentPeer {
|
||||
}
|
||||
|
||||
private boolean isInsideTouchClickBoundaries(int x, int y) {
|
||||
return Math.abs(touchBeginX - x) <= TOUCH_CLICK_RADIUS &&
|
||||
Math.abs(touchBeginY - y) <= TOUCH_CLICK_RADIUS;
|
||||
return Math.abs(touchBeginX - x) <= TouchEvent.CLICK_RADIUS &&
|
||||
Math.abs(touchBeginY - y) <= TouchEvent.CLICK_RADIUS;
|
||||
}
|
||||
|
||||
private static boolean isOwningTouch(int fingerId) {
|
||||
@@ -857,7 +876,24 @@ class XWindow extends XBaseWindow implements X11ComponentPeer {
|
||||
}
|
||||
|
||||
private static boolean isTouchReleased() {
|
||||
return trackingId == 0;
|
||||
if (trackingId == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// recovery from situation when TOUCH_END event didn't occurred
|
||||
long msFromLastUpdate = Math.abs(System.currentTimeMillis() - lastTouchUpdateTime);
|
||||
if (msFromLastUpdate >= TouchEvent.NO_UPDATE_TIMEOUT) {
|
||||
touchEventLog.warning("Release touch processing, milliseconds from last update: " + msFromLastUpdate);
|
||||
}
|
||||
return msFromLastUpdate >= TouchEvent.NO_UPDATE_TIMEOUT;
|
||||
}
|
||||
|
||||
private void sendButtonPressFromTouch(XIDeviceEvent dev, long jWhen, int modifiers, int x, int y) {
|
||||
sendMouseEventFromTouch(dev, MouseEvent.MOUSE_MOVED, jWhen, modifiers, x, y, MouseEvent.NOBUTTON, 0);
|
||||
sendMouseEventFromTouch(dev, MouseEvent.MOUSE_DRAGGED, jWhen, modifiers, x, y, MouseEvent.BUTTON1, 0);
|
||||
sendMouseEventFromTouch(dev, MouseEvent.MOUSE_PRESSED, jWhen, modifiers, x, y, MouseEvent.BUTTON1, 1);
|
||||
sendMouseEventFromTouch(dev, MouseEvent.MOUSE_RELEASED, jWhen, modifiers, x, y, MouseEvent.BUTTON1, 1);
|
||||
sendMouseEventFromTouch(dev, MouseEvent.MOUSE_CLICKED, jWhen, modifiers, x, y, MouseEvent.BUTTON1, 1);
|
||||
}
|
||||
|
||||
private void sendWheelEventFromTouch(XIDeviceEvent dev, long jWhen, int modifiers, int x, int y, int type, int delta) {
|
||||
@@ -871,15 +907,14 @@ class XWindow extends XBaseWindow implements X11ComponentPeer {
|
||||
1, delta));
|
||||
}
|
||||
|
||||
private void sendMouseEventFromTouch(XIDeviceEvent dev, int type, long jWhen, int modifiers, int x, int y, int button) {
|
||||
private void sendMouseEventFromTouch(XIDeviceEvent dev, int type, long jWhen, int modifiers, int x, int y, int button, int clickCount) {
|
||||
boolean popupTrigger = button == MouseEvent.BUTTON3;
|
||||
postEventToEventQueue(
|
||||
new MouseEvent(getEventSource(), type, jWhen,
|
||||
modifiers,
|
||||
x, y,
|
||||
modifiers, x, y,
|
||||
scaleDown((int) dev.get_root_x()),
|
||||
scaleDown((int) dev.get_root_y()),
|
||||
1,
|
||||
false, button));
|
||||
clickCount, popupTrigger, button));
|
||||
}
|
||||
|
||||
public void handleMotionNotify(XEvent xev) {
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
#include <java_awt_event_InputEvent.h>
|
||||
#include <java_awt_event_ActionEvent.h>
|
||||
#include <java_awt_event_InputMethodEvent.h>
|
||||
#include <sun_awt_event_TouchEvent.h>
|
||||
#include <sun_awt_windows_WInputMethod.h>
|
||||
#include <java_awt_event_MouseEvent.h>
|
||||
#include <java_awt_event_MouseWheelEvent.h>
|
||||
@@ -226,7 +227,7 @@ AwtComponent::AwtComponent()
|
||||
m_mouseButtonClickAllowed = 0;
|
||||
|
||||
m_isTouchScroll = FALSE;
|
||||
m_touchDownPoint = {0, 0};
|
||||
m_touchBeginPoint = {0, 0};
|
||||
m_lastTouchPoint = {0, 0};
|
||||
|
||||
m_callbacksEnabled = FALSE;
|
||||
@@ -2404,8 +2405,8 @@ void AwtComponent::WmTouch(WPARAM wParam, LPARAM lParam) {
|
||||
|
||||
BOOL AwtComponent::IsInsideTouchClickBoundaries(POINT p)
|
||||
{
|
||||
return abs(p.x - m_touchDownPoint.x) <= TOUCH_MOUSE_COORDS_DELTA &&
|
||||
abs(p.y - m_touchDownPoint.y) <= TOUCH_MOUSE_COORDS_DELTA;
|
||||
return abs(p.x - m_touchBeginPoint.x) <= sun_awt_event_TouchEvent_CLICK_RADIUS &&
|
||||
abs(p.y - m_touchBeginPoint.y) <= sun_awt_event_TouchEvent_CLICK_RADIUS;
|
||||
}
|
||||
|
||||
POINT AwtComponent::TouchCoordsToLocal(LONG x, LONG y)
|
||||
@@ -2418,17 +2419,24 @@ POINT AwtComponent::TouchCoordsToLocal(LONG x, LONG y)
|
||||
void AwtComponent::SendMouseWheelEventFromTouch(POINT p, jint modifiers, jint scrollType, jint pixels)
|
||||
{
|
||||
SendMouseWheelEvent(java_awt_event_MouseEvent_MOUSE_WHEEL, ::JVM_CurrentTimeMillis(NULL, 0),
|
||||
p.x, p.y, modifiers, 0, 0, scrollType,
|
||||
/*scrollAmount*/ 1, pixels,
|
||||
p.x, p.y, modifiers, /*clickCount*/ 0, /*popupTrigger*/ JNI_FALSE,
|
||||
scrollType, /*scrollAmount*/ 1, pixels,
|
||||
static_cast<double>(pixels), /*msg*/ nullptr);
|
||||
}
|
||||
|
||||
void AwtComponent::SendMouseEventFromTouch(jint id, POINT p, jint modifiers)
|
||||
void AwtComponent::SendMouseEventFromTouch(jint id, POINT p, jint modifiers, jint clickCount, jint button)
|
||||
{
|
||||
SendMouseEvent(id, ::JVM_CurrentTimeMillis(NULL, 0), p.x, p.y,
|
||||
modifiers, /*clickCount*/ 1, JNI_FALSE,
|
||||
java_awt_event_MouseEvent_BUTTON1,
|
||||
/*msg*/ nullptr, /*causedByTouchEvent*/ TRUE);
|
||||
modifiers, clickCount, /*popupTrigger*/ JNI_FALSE,
|
||||
button, /*msg*/ nullptr, /*causedByTouchEvent*/ TRUE);
|
||||
}
|
||||
|
||||
void AwtComponent::SendButtonPressEventFromTouch(POINT p, jint modifiers)
|
||||
{
|
||||
SendMouseEventFromTouch(java_awt_event_MouseEvent_MOUSE_MOVED, p, modifiers, 0, java_awt_event_MouseEvent_NOBUTTON);
|
||||
SendMouseEventFromTouch(java_awt_event_MouseEvent_MOUSE_PRESSED, p, modifiers, 1, java_awt_event_MouseEvent_BUTTON1);
|
||||
SendMouseEventFromTouch(java_awt_event_MouseEvent_MOUSE_RELEASED, p, modifiers, 1, java_awt_event_MouseEvent_BUTTON1);
|
||||
SendMouseEventFromTouch(java_awt_event_MouseEvent_MOUSE_CLICKED, p, modifiers, 1, java_awt_event_MouseEvent_BUTTON1);
|
||||
}
|
||||
|
||||
void AwtComponent::WmTouchHandler(const TOUCHINPUT& touchInput)
|
||||
@@ -2438,43 +2446,39 @@ void AwtComponent::WmTouchHandler(const TOUCHINPUT& touchInput)
|
||||
return;
|
||||
}
|
||||
|
||||
jint modifiers = GetJavaModifiers();
|
||||
// turn off horizontal
|
||||
modifiers &= ~java_awt_event_InputEvent_SHIFT_DOWN_MASK;
|
||||
const jint modifiers = GetJavaModifiers();
|
||||
const POINT p = TouchCoordsToLocal(touchInput.x, touchInput.y);
|
||||
|
||||
if (touchInput.dwFlags & TOUCHEVENTF_DOWN) {
|
||||
m_touchDownPoint = p;
|
||||
m_lastTouchPoint = p;
|
||||
m_touchBeginPoint = p;
|
||||
m_isTouchScroll = FALSE;
|
||||
SendMouseWheelEventFromTouch(p, modifiers, TOUCH_BEGIN, 1);
|
||||
SendMouseWheelEventFromTouch(p, modifiers, sun_awt_event_TouchEvent_TOUCH_BEGIN, 1);
|
||||
} else if (touchInput.dwFlags & TOUCHEVENTF_MOVE) {
|
||||
if (!m_isTouchScroll && IsInsideTouchClickBoundaries(p)) {
|
||||
return;
|
||||
}
|
||||
m_isTouchScroll = TRUE;
|
||||
|
||||
const int deltaY = ScaleDownY(static_cast<int>(m_lastTouchPoint.y - p.y));
|
||||
if (abs(deltaY) != 0) {
|
||||
SendMouseWheelEventFromTouch(p, modifiers, TOUCH_UPDATE, deltaY);
|
||||
const jint deltaY = ScaleDownY(static_cast<int>(m_lastTouchPoint.y - p.y));
|
||||
if (deltaY != 0) {
|
||||
const jint scrollModifiers = modifiers & ~java_awt_event_InputEvent_SHIFT_DOWN_MASK;
|
||||
SendMouseWheelEventFromTouch(p, scrollModifiers, sun_awt_event_TouchEvent_TOUCH_UPDATE, deltaY);
|
||||
}
|
||||
|
||||
const int deltaX = ScaleDownX(static_cast<int>(m_lastTouchPoint.x - p.x));
|
||||
if (abs(deltaX) != 0) {
|
||||
modifiers |= java_awt_event_InputEvent_SHIFT_DOWN_MASK;
|
||||
SendMouseWheelEventFromTouch(p, modifiers, TOUCH_UPDATE, deltaX);
|
||||
const jint deltaX = ScaleDownX(static_cast<int>(m_lastTouchPoint.x - p.x));
|
||||
if (deltaX != 0) {
|
||||
const jint scrollModifiers = modifiers | java_awt_event_InputEvent_SHIFT_DOWN_MASK;
|
||||
SendMouseWheelEventFromTouch(p, scrollModifiers, sun_awt_event_TouchEvent_TOUCH_UPDATE, deltaX);
|
||||
}
|
||||
|
||||
m_lastTouchPoint = p;
|
||||
} else if (touchInput.dwFlags & TOUCHEVENTF_UP) {
|
||||
SendMouseWheelEventFromTouch(p, modifiers, TOUCH_END, 1);
|
||||
SendMouseWheelEventFromTouch(p, modifiers, sun_awt_event_TouchEvent_TOUCH_END, 1);
|
||||
|
||||
if (!m_isTouchScroll) {
|
||||
SendMouseEventFromTouch(java_awt_event_MouseEvent_MOUSE_PRESSED, p, modifiers);
|
||||
SendMouseEventFromTouch(java_awt_event_MouseEvent_MOUSE_RELEASED, p, modifiers);
|
||||
SendMouseEventFromTouch(java_awt_event_MouseEvent_MOUSE_CLICKED, p, modifiers);
|
||||
SendButtonPressEventFromTouch(p, modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
m_lastTouchPoint = p;
|
||||
}
|
||||
|
||||
/* Double-click variables. */
|
||||
|
||||
@@ -69,14 +69,6 @@ const UINT MAX_ACP_STR_LEN = 7; // ANSI CP identifiers are no longer than this
|
||||
const int ALL_MK_BUTTONS = MK_LBUTTON|MK_MBUTTON|MK_RBUTTON;
|
||||
const int X_BUTTONS = MK_XBUTTON1|MK_XBUTTON2;
|
||||
|
||||
// The allowable difference between coordinates of the WM_TOUCH event and the
|
||||
// corresponding WM_LBUTTONDOWN/WM_LBUTTONUP event letting to associate these
|
||||
// events, when their coordinates are slightly different.
|
||||
const int TOUCH_MOUSE_COORDS_DELTA = 10;
|
||||
const int TOUCH_BEGIN = 2;
|
||||
const int TOUCH_UPDATE = 3;
|
||||
const int TOUCH_END = 4;
|
||||
|
||||
// Whether to check for embedded frame and adjust location
|
||||
#define CHECK_EMBEDDED 0
|
||||
#define DONT_CHECK_EMBEDDED 1
|
||||
@@ -541,7 +533,8 @@ public:
|
||||
BOOL IsInsideTouchClickBoundaries(POINT p);
|
||||
POINT TouchCoordsToLocal(LONG x, LONG y);
|
||||
void SendMouseWheelEventFromTouch(POINT p, jint modifiers, jint scrollType, jint pixels);
|
||||
void SendMouseEventFromTouch(jint id, POINT p, jint modifiers);
|
||||
void SendMouseEventFromTouch(jint id, POINT p, jint modifiers, jint clickCount, jint button);
|
||||
void SendButtonPressEventFromTouch(POINT p, jint modifiers);
|
||||
|
||||
// NB: 64-bit: vkey is wParam of the message, but other API's take
|
||||
// vkey parameters of type UINT, so we do the cast before dispatching.
|
||||
@@ -792,7 +785,7 @@ private:
|
||||
UINT m_mouseButtonClickAllowed;
|
||||
|
||||
BOOL m_isTouchScroll;
|
||||
POINT m_touchDownPoint;
|
||||
POINT m_touchBeginPoint;
|
||||
POINT m_lastTouchPoint;
|
||||
|
||||
BOOL m_bSubclassed;
|
||||
|
||||
@@ -171,8 +171,9 @@ JNIEXPORT jboolean JNICALL
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_font_FileFontStrike__1getGlyphImageFromWindows
|
||||
(JNIEnv *env, jobject unused, jstring fontFamily, jint style, jint size,
|
||||
jint glyphCode, jboolean fm, jint rotation, jbyte charset, jint fontDataSize) {
|
||||
(JNIEnv *env, jobject unused,
|
||||
jstring fontFamily, jint style, jint size, jint glyphCode, jboolean fm,
|
||||
jint rotation, jbyte charset, jint fontDataSize) {
|
||||
|
||||
GLYPHMETRICS glyphMetrics;
|
||||
LOGFONTW lf;
|
||||
@@ -257,10 +258,10 @@ jint glyphCode, jboolean fm, jint rotation, jbyte charset, jint fontDataSize) {
|
||||
oldFont = SelectObject(hMemoryDC, hFont);
|
||||
|
||||
if (fontDataSize > 0) {
|
||||
// We cannot specify via GDI which font file to use,
|
||||
// so we check that it picks the exact font we need by validating font size.
|
||||
// If it doesn't match, we cannot proceed, as same glyph code can correspond
|
||||
// to a completely different glyph in the selected font.
|
||||
// GDI doesn't allow to select a specific font file for drawing, we can
|
||||
// only check that it picks the file we need by validating font size.
|
||||
// If it doesn't match, we cannot proceed, as the same glyph code can
|
||||
// correspond to a completely different glyph in the selected font.
|
||||
actualFontDataSize = GetFontData(hMemoryDC, 0, 0, NULL, 0);
|
||||
if (actualFontDataSize != fontDataSize) {
|
||||
FREE_AND_RETURN;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
@summary Tests that disposing of an empty Frame or a Frame with a MenuBar
|
||||
while it is being created does not crash the VM.
|
||||
@author dpm area=Threads
|
||||
@run applet/timeout=7200 DisposeStressTest.html
|
||||
@run applet/timeout=600 DisposeStressTest.html
|
||||
-->
|
||||
<head>
|
||||
<title>DisposeStressTest</title>
|
||||
|
||||
@@ -83,6 +83,7 @@ public class DisposeStressTest extends Applet
|
||||
public void start ()
|
||||
{
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
System.out.println("i = " + i);
|
||||
Frame f = new Frame();
|
||||
f.setBounds(10, 10, 10, 10);
|
||||
f.show();
|
||||
|
||||
@@ -38,12 +38,15 @@ import java.awt.Frame;
|
||||
import java.awt.TextArea;
|
||||
import java.awt.Robot;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
public class TestDispose {
|
||||
|
||||
public static final int TIMEOUT = 30;
|
||||
|
||||
public static Frame frame = null;
|
||||
public static TextArea textArea = null;
|
||||
public static volatile Process worker = null;
|
||||
@@ -57,33 +60,33 @@ public class TestDispose {
|
||||
ex.printStackTrace();
|
||||
throw new RuntimeException("Unexpected failure");
|
||||
}
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
frame = new JFrame("Test");
|
||||
|
||||
textArea = new TextArea("editable textArea");
|
||||
textArea.setEditable(true);
|
||||
// textArea.setEditable(false); // this testcase passes if textArea is non-editable
|
||||
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
frame = new JFrame("Test");
|
||||
frame.setLayout(new FlowLayout());
|
||||
frame.add(textArea);
|
||||
|
||||
textArea = new TextArea("editable textArea");
|
||||
textArea.setEditable(true);
|
||||
// textArea.setEditable(false); // this testcase passes if textArea is non-editable
|
||||
|
||||
frame.setLayout(new FlowLayout());
|
||||
frame.add(textArea);
|
||||
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
robot.waitForIdle();
|
||||
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
frame.dispose();
|
||||
}
|
||||
});
|
||||
robot.waitForIdle();
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
robot.waitForIdle();
|
||||
} finally {
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
frame.dispose();
|
||||
}
|
||||
});
|
||||
robot.waitForIdle();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception{
|
||||
@@ -94,10 +97,21 @@ public class TestDispose {
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println(System.getProperty("java.home")+"/bin/java TestDispose workprocess");
|
||||
worker = Runtime.getRuntime().exec(System.getProperty("java.home")+"/bin/java TestDispose workprocess");
|
||||
worker.waitFor();
|
||||
return;
|
||||
System.out.println(System.getProperty("java.home") + "/bin/java -cp "
|
||||
+ System.getProperty("java.class.path") + " " + TestDispose.class.getName() + " workprocess");
|
||||
worker = new ProcessBuilder(System.getProperty("java.home")+"/bin/java",
|
||||
"-cp", System.getProperty("java.class.path"), TestDispose.class.getName(), "workprocess")
|
||||
.redirectError(ProcessBuilder.Redirect.INHERIT)
|
||||
.start();
|
||||
if(worker.waitFor(TIMEOUT, TimeUnit.SECONDS)) {
|
||||
if(worker.exitValue() != 0) {
|
||||
throw new RuntimeException("TEST ERROR: subprocess has finished abnormally");
|
||||
}
|
||||
System.out.println("TEST PASSED");
|
||||
return;
|
||||
} else {
|
||||
throw new RuntimeException("TEST FAILED: subprocess has not finished for " + TIMEOUT + " sec");
|
||||
}
|
||||
}
|
||||
|
||||
TestDispose app = new TestDispose();
|
||||
|
||||
@@ -38,12 +38,15 @@ import java.awt.Frame;
|
||||
import java.awt.TextField;
|
||||
import java.awt.Robot;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
public class TestDispose {
|
||||
|
||||
public static final int TIMEOUT = 30;
|
||||
|
||||
public static Frame frame = null;
|
||||
public static TextField textField = null;
|
||||
public static volatile Process worker = null;
|
||||
@@ -58,31 +61,33 @@ public class TestDispose {
|
||||
throw new RuntimeException("Unexpected failure");
|
||||
}
|
||||
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
frame = new JFrame("Test");
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
frame = new JFrame("Test");
|
||||
|
||||
textField = new TextField("editable textArea");
|
||||
textField.setEditable(true);
|
||||
// textField.setEditable(false); // this testcase passes if textField is non-editable
|
||||
textField = new TextField("editable textArea");
|
||||
textField.setEditable(true);
|
||||
// textField.setEditable(false); // this testcase passes if textField is non-editable
|
||||
|
||||
frame.setLayout(new FlowLayout());
|
||||
frame.add(textField);
|
||||
frame.setLayout(new FlowLayout());
|
||||
frame.add(textField);
|
||||
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
robot.waitForIdle();
|
||||
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
frame.dispose();
|
||||
}
|
||||
});
|
||||
robot.waitForIdle();
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
robot.waitForIdle();
|
||||
} finally {
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
frame.dispose();
|
||||
}
|
||||
});
|
||||
robot.waitForIdle();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -94,10 +99,21 @@ public class TestDispose {
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println(System.getProperty("java.home")+"/bin/java TestDispose workprocess");
|
||||
worker = Runtime.getRuntime().exec(System.getProperty("java.home")+"/bin/java TestDispose workprocess");
|
||||
worker.waitFor();
|
||||
return;
|
||||
System.out.println(System.getProperty("java.home") + "/bin/java -cp "
|
||||
+ System.getProperty("java.class.path") + " " + TestDispose.class.getName() + " workprocess");
|
||||
worker = new ProcessBuilder(System.getProperty("java.home")+"/bin/java",
|
||||
"-cp", System.getProperty("java.class.path"), TestDispose.class.getName(), "workprocess")
|
||||
.redirectError(ProcessBuilder.Redirect.INHERIT)
|
||||
.start();
|
||||
if(worker.waitFor(TIMEOUT, TimeUnit.SECONDS)) {
|
||||
if(worker.exitValue() != 0) {
|
||||
throw new RuntimeException("TEST ERROR: subprocess has finished abnormally");
|
||||
}
|
||||
System.out.println("TEST PASSED");
|
||||
return;
|
||||
} else {
|
||||
throw new RuntimeException("TEST FAILED: subprocess has not finished for " + TIMEOUT + " sec");
|
||||
}
|
||||
}
|
||||
|
||||
TestDispose app = new TestDispose();
|
||||
|
||||
140
test/jdk/jb/java/awt/Toolkit/AWTThreadingTest.java
Normal file
140
test/jdk/jb/java/awt/Toolkit/AWTThreadingTest.java
Normal file
@@ -0,0 +1,140 @@
|
||||
import java.awt.*;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import sun.awt.InvokeOnToolkitHelper;
|
||||
import sun.lwawt.macosx.CThreading;
|
||||
import sun.lwawt.macosx.LWCToolkit;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary tests that AWTThreading can manage a stream of cross EDT/AppKit invocation requests
|
||||
* @requires (os.family == "mac")
|
||||
* @compile --add-exports=java.desktop/sun.lwawt.macosx=ALL-UNNAMED --add-exports=java.desktop/sun.awt=ALL-UNNAMED AWTThreadingTest.java
|
||||
* @run main/othervm --add-exports=java.desktop/sun.lwawt.macosx=ALL-UNNAMED --add-exports=java.desktop/sun.awt=ALL-UNNAMED AWTThreadingTest
|
||||
* @author Anton Tarasov
|
||||
*/
|
||||
public class AWTThreadingTest {
|
||||
static final ReentrantLock LOCK = new ReentrantLock();
|
||||
static final Condition COND = LOCK.newCondition();
|
||||
static final CountDownLatch LATCH = new CountDownLatch(1);
|
||||
|
||||
static JFrame frame;
|
||||
static Thread thread;
|
||||
|
||||
final static AtomicBoolean passed = new AtomicBoolean(true);
|
||||
final static AtomicInteger counter = new AtomicInteger(0);
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
EventQueue.invokeLater(AWTThreadingTest::runGui);
|
||||
|
||||
LATCH.await(5, TimeUnit.SECONDS);
|
||||
|
||||
frame.dispose();
|
||||
thread.interrupt();
|
||||
|
||||
if (!passed.get()) {
|
||||
throw new RuntimeException("Test FAILED!");
|
||||
}
|
||||
System.out.println("Test PASSED");
|
||||
}
|
||||
|
||||
static void runGui() {
|
||||
frame = new JFrame("frame");
|
||||
frame.setLocationRelativeTo(null);
|
||||
frame.setSize(200, 200);
|
||||
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
||||
frame.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowOpened(WindowEvent e) {
|
||||
startThread();
|
||||
}
|
||||
});
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
static void startThread() {
|
||||
thread = new Thread(() -> {
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// 1. Execute invokeAndWait() from AppKit to EDT
|
||||
//
|
||||
CThreading.executeOnAppKit(() -> {
|
||||
try {
|
||||
LWCToolkit.invokeAndWait(counter::incrementAndGet, Window.getWindows()[0]);
|
||||
} catch (Exception e) {
|
||||
fail(e);
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// 2. Execute invokeAndBlock() from EDT to AppKit
|
||||
//
|
||||
EventQueue.invokeLater(() -> {
|
||||
passed.set(false);
|
||||
|
||||
Boolean success = InvokeOnToolkitHelper.invokeAndBlock(() -> {
|
||||
try {
|
||||
return CThreading.executeOnAppKit(() -> Boolean.TRUE);
|
||||
} catch (Throwable e) {
|
||||
fail(e);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
System.out.println("Success: " + counter.get() + ": " + success);
|
||||
|
||||
passed.set(Boolean.TRUE.equals(success));
|
||||
|
||||
if (passed.get()) {
|
||||
lock(COND::signal);
|
||||
}
|
||||
else {
|
||||
fail(null);
|
||||
}
|
||||
});
|
||||
|
||||
lock(COND::await);
|
||||
}
|
||||
});
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
static void lock(MyRunnable runnable) {
|
||||
LOCK.lock();
|
||||
try {
|
||||
try {
|
||||
runnable.run();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
LOCK.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
interface MyRunnable {
|
||||
void run() throws Exception;
|
||||
}
|
||||
|
||||
static void fail(Throwable e) {
|
||||
if (e != null) e.printStackTrace();
|
||||
passed.set(false);
|
||||
LATCH.countDown();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,452 @@
|
||||
/*
|
||||
* Copyright 2000-2020 JetBrains s.r.o.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.awt.datatransfer.UnsupportedFlavorException;
|
||||
import java.awt.dnd.*;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Regression test for JBR-1414. DnD on linux (XToolkit) does not honor HIDPI scale
|
||||
* @requires (os.family == "linux") & (jdk.version.major >= 11)
|
||||
* @author mikhail.grishch@gmail.com
|
||||
* @run main/othervm -Dsun.java2d.uiScale=2 DnDScalingWithHIDPITest 1
|
||||
* @run main/othervm -Dsun.java2d.uiScale=1 DnDScalingWithHIDPITest 2
|
||||
* @run main/othervm -Dsun.java2d.uiScale.enabled=false DnDScalingWithHIDPITest DISABLE_SCALING
|
||||
* @run main/othervm/fail -Dsun.java2d.uiScale=2.5 -Dsun.java2d.uiScale.enabled=true DnDScalingWithHIDPITest 0.5
|
||||
* @comment remove /fail option when JBR-1365 will be fixed.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Description
|
||||
* Dnd works incorrect in the case if Source and Target components have different HiDPI scaling.
|
||||
* Scaling is controlled by jvm option (-Dsun.java2d.uiScale) instead of GDK_SCALE env var.
|
||||
*
|
||||
* Test creates frame with transferable panel.
|
||||
* Then it executes another process (DropTargetRunner) which creates frame with Target panel.
|
||||
* Scaling of Target Frame is also controlled by jvm option (-Dsun.java2d.uiScale) which is got from
|
||||
* cmd argument of parent process:
|
||||
* * DISABLE_SCALING - disable scaling (set -Dsun.java2d.uiScale.enabled=false)
|
||||
* * another value (except 0) - scaling factor for Target Frame
|
||||
* Test checks correctness of the dragExit, dragEnter, dragOver and drop actions.
|
||||
* Test runs 4 times with various configurations of source and target scaling.
|
||||
*/
|
||||
|
||||
public class DnDScalingWithHIDPITest {
|
||||
//Timeout of child process must be smaller than timeout of test (default - 120s)
|
||||
private static final int CHILD_PROCESS_TIMEOUT = 60;
|
||||
/**
|
||||
* @param args
|
||||
* arg[0] - scaling factor of DropTargetFrame (must be set!)
|
||||
* * DISABLE_SCALING - disable scaling (set -Dsun.java2d.uiScale.enabled=false)
|
||||
* * another value (except 0) - scaling factor for Target Frame
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
DragSourceFrame sourceFrame = new DragSourceFrame("DRAG");
|
||||
Process process = null;
|
||||
boolean processExit = false;
|
||||
try {
|
||||
var r = new Robot();
|
||||
SwingUtilities.invokeAndWait(sourceFrame::initUI);
|
||||
r.waitForIdle();
|
||||
|
||||
String sourceScaleStr = System.getProperty("sun.java2d.uiScale");
|
||||
float sourceScale = 1;
|
||||
if ("false".equals(System.getProperty("sun.java2d.uiScale.enabled"))) {
|
||||
System.out.println("Scaling disabled on DRAG Frame (-Dsun.java2d.uiScale.enabled=false)");
|
||||
} else if(sourceScaleStr == null) {
|
||||
throw new RuntimeException("Error: Property sun.java2d.uiScale did not set");
|
||||
} else {
|
||||
sourceScale = Float.parseFloat(sourceScaleStr);
|
||||
}
|
||||
|
||||
String vmScalingOption;
|
||||
float targetScale = 1;
|
||||
if (args.length == 0) {
|
||||
throw new RuntimeException("Error: Program argument did not set (Scaling value for DROP Frame can not be specified).");
|
||||
} else if ("DISABLE_SCALING".equals(args[0])) {
|
||||
System.out.println("Scaling disabled on DROP Frame (-Dsun.java2d.uiScale.enabled=false)");
|
||||
vmScalingOption = "-Dsun.java2d.uiScale.enabled=false";
|
||||
} else {
|
||||
vmScalingOption = "-Dsun.java2d.uiScale=" + args[0];
|
||||
String targetScaleStr = args[0];
|
||||
targetScale = "0".equals(targetScaleStr) ? 1 : Float.parseFloat(targetScaleStr);
|
||||
}
|
||||
|
||||
float scalingFactor = sourceScale / targetScale;
|
||||
|
||||
var processBuilder = new ProcessBuilder(
|
||||
System.getProperty("java.home") + "/bin/java",
|
||||
vmScalingOption,
|
||||
"-cp",
|
||||
System.getProperty("java.class.path", "."),
|
||||
"DropTargetRunner",
|
||||
String.valueOf((int) (sourceFrame.getNextLocationX() * scalingFactor)),
|
||||
String.valueOf((int) (sourceFrame.getNextLocationY() * scalingFactor)),
|
||||
String.valueOf((int) (sourceFrame.getDragSourcePointX() * scalingFactor)),
|
||||
String.valueOf((int) (sourceFrame.getDragSourcePointY() * scalingFactor))
|
||||
);
|
||||
|
||||
System.out.println("Starting DropTargetRunner...");
|
||||
processBuilder.command().forEach(s -> System.out.print(s + " "));
|
||||
System.out.println("\n");
|
||||
|
||||
process = processBuilder.start();
|
||||
processExit = process.waitFor(CHILD_PROCESS_TIMEOUT, TimeUnit.SECONDS);
|
||||
|
||||
var inContent = new StringBuilder();
|
||||
var errContent = new StringBuilder();
|
||||
getStreamContent(process.getInputStream(), inContent);
|
||||
getStreamContent(process.getErrorStream(), errContent);
|
||||
|
||||
System.out.println(inContent.toString());
|
||||
|
||||
if(!processExit) {
|
||||
process.destroy();
|
||||
processExit = true;
|
||||
throw new RuntimeException("Error: Timeout. The sub-process hangs.");
|
||||
}
|
||||
|
||||
String errorContentStr = errContent.toString();
|
||||
if (!errorContentStr.isEmpty()) {
|
||||
throw new RuntimeException(errorContentStr);
|
||||
}
|
||||
|
||||
} finally {
|
||||
SwingUtilities.invokeAndWait(sourceFrame::dispose);
|
||||
Thread.sleep(1000);
|
||||
if(process != null && !processExit) {
|
||||
process.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void getStreamContent(InputStream in, StringBuilder content) throws IOException {
|
||||
String tempString;
|
||||
int count = in.available();
|
||||
while (count > 0) {
|
||||
byte[] b = new byte[count];
|
||||
in.read(b);
|
||||
tempString = new String(b);
|
||||
content.append(tempString).append("\n");
|
||||
count = in.available();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DragSourceFrame extends JFrame implements DragGestureListener {
|
||||
private JPanel sourcePanel;
|
||||
|
||||
DragSourceFrame(String frameName) {
|
||||
super(frameName);
|
||||
this.setUndecorated(true);
|
||||
}
|
||||
|
||||
void initUI() {
|
||||
this.setLocation(0, 0);
|
||||
JPanel contentPane = new JPanel(null);
|
||||
contentPane.setPreferredSize(new Dimension(100, 100));
|
||||
|
||||
sourcePanel = new JPanel() {
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
g2.setColor(this.getBackground());
|
||||
g2.fillRect(0, 0, 100, 100);
|
||||
}
|
||||
};
|
||||
sourcePanel.setBounds(0, 0, 100, 100);
|
||||
sourcePanel.setEnabled(true);
|
||||
sourcePanel.setBackground(Color.white);
|
||||
|
||||
var ds = new DragSource();
|
||||
ds.createDefaultDragGestureRecognizer(sourcePanel,
|
||||
DnDConstants.ACTION_COPY, this);
|
||||
|
||||
contentPane.add(sourcePanel);
|
||||
this.setContentPane(contentPane);
|
||||
|
||||
this.pack();
|
||||
this.setVisible(true);
|
||||
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
}
|
||||
|
||||
// returns the X coordinate on which DropTargetFrame will be opened
|
||||
int getNextLocationX() {
|
||||
return getX() + getWidth();
|
||||
}
|
||||
|
||||
// returns the X coordinate on which DropTargetFrame will be opened
|
||||
int getNextLocationY() {
|
||||
return getY();
|
||||
}
|
||||
|
||||
//returns the X coordinate to drag Source panel
|
||||
int getDragSourcePointX() {
|
||||
return (int) sourcePanel.getLocationOnScreen().getX() + (sourcePanel.getWidth() / 2);
|
||||
}
|
||||
|
||||
//returns the Y coordinate to drag Source panel
|
||||
int getDragSourcePointY() {
|
||||
return (int) sourcePanel.getLocationOnScreen().getY() + (sourcePanel.getHeight() / 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dragGestureRecognized(DragGestureEvent event) {
|
||||
var cursor = Cursor.getDefaultCursor();
|
||||
if (event.getDragAction() == DnDConstants.ACTION_COPY) {
|
||||
cursor = DragSource.DefaultCopyDrop;
|
||||
}
|
||||
event.startDrag(cursor, new TransferableElement());
|
||||
}
|
||||
}
|
||||
|
||||
class TransferableElement implements Transferable {
|
||||
private static final DataFlavor[] supportedFlavors = {DataFlavor.stringFlavor};
|
||||
|
||||
public TransferableElement() {
|
||||
}
|
||||
|
||||
public DataFlavor[] getTransferDataFlavors() {
|
||||
return supportedFlavors;
|
||||
}
|
||||
|
||||
public boolean isDataFlavorSupported(DataFlavor flavor) {
|
||||
return flavor.equals(DataFlavor.stringFlavor);
|
||||
}
|
||||
|
||||
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
|
||||
if (flavor.equals(DataFlavor.stringFlavor)) {
|
||||
return "Transferable text";
|
||||
} else {
|
||||
throw new UnsupportedFlavorException(flavor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DropTargetRunner {
|
||||
|
||||
/**
|
||||
* @param args
|
||||
* arg[0] - the X coordinate of DropTargetFrame
|
||||
* arg[1] - the Y coordinate of DropTargetFrame
|
||||
* arg[2] - the X coordinate of source panel which will be dragged
|
||||
* arg[2] - the Y coordinate of source panel which will be dragged
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
Robot r = new Robot();
|
||||
DropTargetFrame targetFrame = new DropTargetFrame("DROP", r);
|
||||
try {
|
||||
int dragSourceX = Integer.parseInt(args[2]);
|
||||
int dragSourceY = Integer.parseInt(args[3]);
|
||||
var targetFrameLocation = new Point(Integer.parseInt(args[0]), Integer.parseInt(args[1]));
|
||||
SwingUtilities.invokeAndWait(() -> targetFrame.initUI(targetFrameLocation));
|
||||
r.waitForIdle();
|
||||
targetFrame.doTest(dragSourceX, dragSourceY);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
SwingUtilities.invokeAndWait(targetFrame::dispose);
|
||||
r.waitForIdle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DropTargetFrame extends JFrame {
|
||||
private Robot robot;
|
||||
private JPanel dtPanel;
|
||||
private boolean dropWasSuccessful = false;
|
||||
private boolean dragEnterWasSuccessful = false;
|
||||
private boolean dragOverWasSuccessful = false;
|
||||
private boolean dragExitWasSuccessful = false;
|
||||
|
||||
DropTargetFrame(String frameName, Robot r) {
|
||||
super(frameName);
|
||||
robot = r;
|
||||
}
|
||||
|
||||
void initUI(Point frameLocation) {
|
||||
this.setLocation(frameLocation);
|
||||
JPanel contentPane = new JPanel(null);
|
||||
contentPane.setPreferredSize(new Dimension(400, 400));
|
||||
|
||||
dtPanel = new JPanel() {
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
g2.setColor(this.getBackground());
|
||||
g2.fillRect(0, 0, 200, 200);
|
||||
}
|
||||
};
|
||||
|
||||
dtPanel.setBounds(100, 100, 200, 200);
|
||||
dtPanel.setEnabled(true);
|
||||
dtPanel.setBackground(Color.white);
|
||||
dtPanel.setDropTarget(new DropTarget(dtPanel, DnDConstants.ACTION_COPY_OR_MOVE, new DropTargetAdapter() {
|
||||
public void dragOver(DropTargetDragEvent dtde) {
|
||||
dragOverWasSuccessful = true;
|
||||
}
|
||||
public void dragExit(DropTargetEvent dte) {
|
||||
dragExitWasSuccessful = true;
|
||||
}
|
||||
public void dragEnter(DropTargetDragEvent dtde) {
|
||||
dragEnterWasSuccessful = true;
|
||||
}
|
||||
@Override
|
||||
public void drop(DropTargetDropEvent dtde) {
|
||||
dropWasSuccessful = true;
|
||||
}
|
||||
|
||||
}, true));
|
||||
|
||||
contentPane.add(dtPanel);
|
||||
this.setContentPane(contentPane);
|
||||
this.pack();
|
||||
this.setVisible(true);
|
||||
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
}
|
||||
|
||||
void doTest(int dragSourceX, int dragSourceY) {
|
||||
int dtPanelX = (int) dtPanel.getLocationOnScreen().getX();
|
||||
int dtPanelY = (int) dtPanel.getLocationOnScreen().getY();
|
||||
|
||||
System.out.print("Check the inner border in the top left corner...\t");
|
||||
dragAndDrop(dragSourceX, dragSourceY, dtPanelX, dtPanelY);
|
||||
checkDragEnter();
|
||||
checkDragOver();
|
||||
checkNotDragExit();
|
||||
checkDropInsidePanel();
|
||||
System.out.println("OK");
|
||||
|
||||
System.out.print("Check the outer border in the top left corner...\t");
|
||||
drag(dragSourceX, dragSourceY, dtPanelX, dtPanelY);
|
||||
mouseMove(dtPanelX, dtPanelY,dtPanelX - 1, dtPanelY - 1);
|
||||
checkDragExit();
|
||||
drop();
|
||||
checkDropOutsidePanel();
|
||||
System.out.println("OK");
|
||||
|
||||
System.out.print("Check the inner border in the bottom right corner...\t");
|
||||
dragAndDrop(dragSourceX, dragSourceY, dtPanelX + dtPanel.getWidth() - 1, dtPanelY + dtPanel.getHeight() - 1);
|
||||
checkDragEnter();
|
||||
checkDragOver();
|
||||
checkNotDragExit();
|
||||
checkDropInsidePanel();
|
||||
System.out.println("OK");
|
||||
|
||||
System.out.print("Check the outer border in the bottom right corner...\t");
|
||||
drag(dragSourceX, dragSourceY, dtPanelX + dtPanel.getWidth() - 1, dtPanelY + dtPanel.getHeight() - 1);
|
||||
mouseMove(dtPanelX + dtPanel.getWidth() - 1, dtPanelY + dtPanel.getHeight() - 1,
|
||||
dtPanelX + dtPanel.getWidth(), dtPanelY + dtPanel.getHeight());
|
||||
checkDragExit();
|
||||
drop();
|
||||
checkDropOutsidePanel();
|
||||
System.out.println("OK");
|
||||
}
|
||||
|
||||
private void drag(int startX, int startY, int finishX, int finishY) {
|
||||
robot.mouseMove(startX, startY);
|
||||
robot.delay(50);
|
||||
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
|
||||
Point p = MouseInfo.getPointerInfo().getLocation();
|
||||
mouseMove(p.x, p.y, finishX, finishY);
|
||||
robot.delay(500);
|
||||
}
|
||||
|
||||
private void drop() {
|
||||
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.delay(500);
|
||||
}
|
||||
|
||||
private void dragAndDrop(int startX, int startY, int finishX, int finishY) {
|
||||
drag(startX, startY, finishX, finishY);
|
||||
drop();
|
||||
}
|
||||
|
||||
private void checkDropInsidePanel() {
|
||||
if (!dropWasSuccessful) {
|
||||
System.out.println("FAILED");
|
||||
throw new RuntimeException("DnD failed: Drop was outside Target panel, but inside is expected");
|
||||
}
|
||||
dropWasSuccessful = false;
|
||||
}
|
||||
|
||||
private void checkDropOutsidePanel() {
|
||||
if (dropWasSuccessful) {
|
||||
System.out.println("FAILED");
|
||||
throw new RuntimeException("DnD failed: Drop was inside Target panel, but outside is expected");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDragExit() {
|
||||
if (!dragExitWasSuccessful) {
|
||||
System.out.println("FAILED");
|
||||
throw new RuntimeException("DnD failed: Drag exit was expected, but did not happened");
|
||||
}
|
||||
dragExitWasSuccessful = false;
|
||||
}
|
||||
|
||||
private void checkNotDragExit() {
|
||||
if (dragExitWasSuccessful) {
|
||||
System.out.println("FAILED");
|
||||
throw new RuntimeException("DnD failed: Unexpected Drag exit");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void checkDragEnter() {
|
||||
if (!dragEnterWasSuccessful) {
|
||||
System.out.println("FAILED");
|
||||
throw new RuntimeException("DnD failed: Drag enter was expected, but did not happened");
|
||||
}
|
||||
dragEnterWasSuccessful = false;
|
||||
}
|
||||
|
||||
private void checkDragOver() {
|
||||
if (!dragOverWasSuccessful) {
|
||||
System.out.println("FAILED");
|
||||
throw new RuntimeException("DnD failed: Drag over was expected, but did not happened");
|
||||
}
|
||||
dragOverWasSuccessful = false;
|
||||
}
|
||||
|
||||
private void mouseMove(int startX, int startY, int finishX, int finishY) {
|
||||
mouseMove(new Point(startX, startY), new Point(finishX, finishY));
|
||||
}
|
||||
|
||||
private void mouseMove(Point start, Point end) {
|
||||
robot.mouseMove(start.x, start.y);
|
||||
for (Point p = new Point(start); !p.equals(end);
|
||||
p.translate(Integer.compare(end.x - p.x, 0),
|
||||
Integer.compare(end.y - p.y, 0))) {
|
||||
robot.mouseMove(p.x, p.y);
|
||||
robot.delay(10);
|
||||
}
|
||||
robot.mouseMove(end.x, end.y);
|
||||
robot.delay(100);
|
||||
}
|
||||
}
|
||||
@@ -25,24 +25,20 @@
|
||||
# password for sudo
|
||||
PASSWORD=${BUPWD}
|
||||
|
||||
echo "Preparing env for the test:"
|
||||
|
||||
echo "> sudo groupadd uinput"
|
||||
echo ${PASSWORD} | sudo -S groupadd uinput
|
||||
echo "result=$?"
|
||||
|
||||
echo "> sudo usermod -a -G uinput `whoami`"
|
||||
echo ${PASSWORD} | sudo -S usermod -a -G uinput `whoami`
|
||||
echo "result=$?"
|
||||
|
||||
echo "> sudo chmod g+rw /dev/uinput"
|
||||
echo ${PASSWORD} | sudo -S chmod g+rw /dev/uinput
|
||||
echo "result=$?"
|
||||
|
||||
echo "> sudo chgrp uinput /dev/uinput"
|
||||
echo ${PASSWORD} | sudo -S chgrp uinput /dev/uinput
|
||||
echo "Allow current user write to /dev/uinput:"
|
||||
echo "> sudo chown `whoami` /dev/uinput"
|
||||
echo ${PASSWORD} | sudo -S chown `whoami` /dev/uinput
|
||||
echo "result=$?"
|
||||
|
||||
echo "Launching TouchScreenEventsTest.java:"
|
||||
echo "> $TESTJAVA/bin/java $TESTVMOPTS -cp $TESTCLASSES TouchScreenEventsTest"
|
||||
$TESTJAVA/bin/java $TESTVMOPTS -cp $TESTCLASSES TouchScreenEventsTest
|
||||
result=$?
|
||||
echo "result=$result"
|
||||
|
||||
echo "Restore permissions for /dev/uinput:"
|
||||
echo "> sudo chown root /dev/uinput"
|
||||
echo ${PASSWORD} | sudo -S chown root /dev/uinput
|
||||
echo "result=$?"
|
||||
|
||||
exit $result
|
||||
|
||||
@@ -6,6 +6,8 @@ import org.cef.CefSettings;
|
||||
import org.cef.handler.CefAppHandlerAdapter;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
@@ -33,7 +35,9 @@ public abstract class JBCefApp {
|
||||
private static final AtomicBoolean ourInitialized = new AtomicBoolean(false);
|
||||
|
||||
private JBCefApp() {
|
||||
CefApp.startup();
|
||||
if (!CefApp.startup()) {
|
||||
throw new RuntimeException("JCEF startup failed!");
|
||||
}
|
||||
CefSettings settings = new CefSettings();
|
||||
settings.windowless_rendering_enabled = false;
|
||||
settings.log_severity = CefSettings.LogSeverity.LOGSEVERITY_ERROR;
|
||||
@@ -66,13 +70,32 @@ public abstract class JBCefApp {
|
||||
private static class JBCefAppMac extends JBCefApp {
|
||||
@Override
|
||||
protected String[] applyPlatformSettings(CefSettings settings) {
|
||||
String JCEF_FRAMEWORKS_PATH = System.getProperty("java.home") + "/Frameworks";
|
||||
String ALT_CEF_FRAMEWORK_DIR = System.getenv("ALT_CEF_FRAMEWORK_DIR");
|
||||
String ALT_CEF_HELPER_DIR = System.getenv("ALT_CEF_HELPER_DIR");
|
||||
if (ALT_CEF_FRAMEWORK_DIR == null || ALT_CEF_HELPER_DIR == null) {
|
||||
String CONTENTS_PATH = System.getProperty("java.home") + "/..";
|
||||
if (ALT_CEF_FRAMEWORK_DIR == null) {
|
||||
ALT_CEF_FRAMEWORK_DIR = CONTENTS_PATH + "/Frameworks/Chromium Embedded Framework.framework";
|
||||
}
|
||||
if (ALT_CEF_HELPER_DIR == null) {
|
||||
ALT_CEF_HELPER_DIR = CONTENTS_PATH + "/Helpers";
|
||||
}
|
||||
}
|
||||
return new String[] {
|
||||
"--framework-dir-path=" + JCEF_FRAMEWORKS_PATH + "/Chromium Embedded Framework.framework",
|
||||
"--browser-subprocess-path=" + JCEF_FRAMEWORKS_PATH + "/jcef Helper.app/Contents/MacOS/jcef Helper",
|
||||
"--framework-dir-path=" + normalize(ALT_CEF_FRAMEWORK_DIR),
|
||||
"--browser-subprocess-path=" + normalize(ALT_CEF_HELPER_DIR) + "/jcef Helper.app/Contents/MacOS/jcef Helper",
|
||||
"--disable-in-process-stack-traces"
|
||||
};
|
||||
}
|
||||
|
||||
// CEF does not accept ".." in path
|
||||
static String normalize(String path) {
|
||||
try {
|
||||
return new File(path).getCanonicalPath();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class JBCefAppWindows extends JBCefApp {
|
||||
|
||||
@@ -197,7 +197,6 @@ java/awt/Focus/WrongKeyTypedConsumedTest/WrongKeyTypedConsumedTest.java
|
||||
java/awt/FontMetrics/FontCrash.java 8198336 windows-all
|
||||
java/awt/FontMetrics/MaxAdvanceIsMax.java 8221304 solaris-all,macosx-all
|
||||
java/awt/Frame/DisposeParentGC/DisposeParentGC.java 8079786,8055833 macosx-all,linux-all
|
||||
java/awt/Frame/DisposeStressTest/DisposeStressTest.html JBR-1905 macosx-all
|
||||
java/awt/Frame/ExceptionOnSetExtendedStateTest/ExceptionOnSetExtendedStateTest.java 8198237 macosx-all
|
||||
java/awt/Frame/FramesGC/FramesGC.java 8079069 macosx-all
|
||||
java/awt/Frame/FrameLocation/FrameLocation.java 8019803 macosx-all
|
||||
@@ -568,10 +567,8 @@ java/awt/Scrollbar/ScrollbarMouseWheelTest/ScrollbarMouseWheelTest.java
|
||||
java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java 8061235,8159592,8134231 macosx-all,windows-all,linux-all
|
||||
java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java 8203004 linux-all
|
||||
java/awt/TextArea/AutoScrollOnSelectAndAppend/AutoScrollOnSelectAndAppend.java 8213120 macosx-all,linux-all, windows-all (windows, linux - time out)
|
||||
java/awt/TextArea/DisposeTest/TestDispose.java JBR-1905 generic-all
|
||||
java/awt/TextArea/TextAreaScrolling/TextAreaScrolling.java 8196300 windows-all
|
||||
java/awt/TextField/SelectionInvisibleTest/SelectionInvisibleTest.java 8169533 macosx-all,windows-all
|
||||
java/awt/TextField/DisposeTest/TestDispose.java JBR-1905 macosx-all
|
||||
java/awt/Toolkit/DesktopProperties/rfe4758438.java 8193547 linux-all
|
||||
java/awt/Toolkit/LockingKeyStateTest/LockingKeyStateTest.java 8208514 windows-all
|
||||
java/awt/Toolkit/RealSync/Test.java 6849383 generic-all
|
||||
@@ -1253,5 +1250,4 @@ javax/swing/LookAndFeel/8146276/NimbusGlueTest.java
|
||||
sanity/client/SwingSet/src/GridBagLayoutDemoTest.java JBR-1977 linux-aarch64
|
||||
|
||||
jb/java/jcef/JCEFStartupTest.java JBR-1996,JBR-2094 macosx-all,linux-i386,windows-x86
|
||||
jb/java/awt/event/TouchScreenEvent/TouchScreenEventsTestLinux.sh generic-all
|
||||
jb/java/awt/event/TouchScreenEvent/TouchScreenEventsTest.java generic-all
|
||||
jb/java/awt/event/TouchScreenEvent/TouchScreenEventsTest.java nobug windows-6.1 not supported on Windows 7
|
||||
|
||||
@@ -32,6 +32,7 @@ java/awt/Focus/RequestFocusAndHideTest/RequestFocusAndHideTest.java
|
||||
java/awt/Focus/RequestFocusByCause/RequestFocusByCauseTest.java nobug linux-all,macosx-all,windows-all reproduced with Adopt, OpenJDK
|
||||
java/awt/Focus/WindowIsFocusableAccessByThreadsTest/WindowIsFocusableAccessByThreadsTest.java nobug macosx-all,windows-all
|
||||
java/awt/Frame/8158918/SetExtendedState.java nobug linux-all
|
||||
java/awt/Frame/DisposeStressTest/DisposeStressTest.html JBR-1905 macosx-all
|
||||
java/awt/Frame/FrameLocation/FrameLocation.java nobug linux-all
|
||||
java/awt/Frame/FrameSize/TestFrameSize.java nobug linux-all,mac-osx
|
||||
java/awt/Frame/MaximizedToIconified/MaximizedToIconified.java nobug linux-all,windows-all
|
||||
|
||||
Reference in New Issue
Block a user