Compare commits

...

18 Commits

Author SHA1 Message Date
Sergey Malenkov
8d2f25483a FractionalMetricsSupport 2020-02-20 16:14:08 +03:00
Anton Tarasov
f45f84d7ed JBR-2148 JCEF: JBR bundle has invalid app structure 2020-02-19 18:23:27 +03:00
Anton Tarasov
06b0d02208 JBR-2146 improve InvokeOnToolkitHelper to cover more generic case 2020-02-18 11:14:46 +03:00
Elena Sayapina
bc09aadadb JBR-1905 java/awt/TextArea/DisposeTest/TestDispose.java: frame is not disposed
- java/awt/TextArea/DisposeTest/TestDispose.java, java/awt/TextField/DisposeTest/TestDispose.java: decreased sub-process timeout
2020-02-17 12:50:54 +07:00
Elena Sayapina
dda7f3d871 JBR-1905 java/awt/TextArea/DisposeTest/TestDispose.java: frame is not disposed
- eliminate erroneously added JetBrains copyrights
2020-02-17 12:41:10 +07:00
Elena Sayapina
7f025f4e16 JBR-1905 java/awt/TextArea/DisposeTest/TestDispose.java: frame is not disposed
- java/awt/TextArea/DisposeTest/TestDispose.java, java/awt/TextField/DisposeTest/TestDispose.java: fixed test frame disposal
- java/awt/Frame/DisposeStressTest/DisposeStressTest.html: decreased test timeout from 2h to 10 min, added minor diagnostic logging
2020-02-17 12:33:44 +07:00
Denis Konoplev
1e904db3b0 JBR-2041: Project view tap fix, recovery? constants & logging 2020-02-14 14:42:36 +03:00
Alexey Ushakov
c013b03300 JBR-2142 Use newer compilers to get better performance and stability of JBR
New docker config is created (jetbrains/runtime:jbr11dev8env) with gcc8.3.1 on board
2020-02-12 16:36:48 +03:00
Elena Sayapina
08aa0852b7 JBR-2041 Update regression test on Linux so it does not need relogin to initialize the test environment 2020-02-12 19:29:19 +07:00
Alexey Ushakov
23f2c1c42d JBR-2135 Use CoreText api to select the font with the most recent version
Corrected java security, parsing issues and native allocations
2020-02-12 03:02:33 +03:00
Dmitry Batrak
53744bf65f JBR-2140 Backport JDK-8236996 from OpenJDK
apply corresponding change from OpenJDK
2020-02-11 13:03:30 +03:00
Dmitry Batrak
430fdb17a8 JBR-2140 Backport JDK-8236996 from OpenJDK
revert original JBR-1879 fix
2020-02-11 13:03:29 +03:00
Anton Tarasov
b37fdd89bf Merge remote-tracking branch 'origin/master' 2020-02-11 12:33:29 +03:00
Anton Tarasov
e57bae4f66 JBR-2139 Idea freeze on dynamic plugin unloading 2020-02-11 12:33:15 +03:00
Alexey Ushakov
0587074d61 Updated CMake projects 2020-02-10 17:49:06 +03:00
Alexey Ushakov
a6e441828a JBR-2137 JetBrainsMono fonts update to v1.0.3 2020-02-10 17:46:20 +03:00
Alexey Ushakov
cbb148dff4 JBR-2135 Use CoreText api to select the font with the most recent version
Added a property to force loading bundled fonts: -Djava2d.font.noVersionCheck=true
2020-02-10 17:36:57 +03:00
Mikhail Grishchenko
1f4ab12fbb JBR-1414: Added regression test for dnd with HiDPI scaling 2020-02-06 17:27:41 +07:00
35 changed files with 1436 additions and 476 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View 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());
}
}

View File

@@ -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);
}
}

View 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;
}

View File

@@ -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.

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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+

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}

Binary file not shown.

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

Binary file not shown.

BIN
src/java.desktop/share/fonts/JetBrainsMono-Regular.ttf Executable file → Normal file

Binary file not shown.

View File

@@ -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) {

View File

@@ -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. */

View File

@@ -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;

View File

@@ -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;

View File

@@ -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>

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View 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();
}
}

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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

View File

@@ -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