mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-12 20:39:38 +01:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1cc12bf142 | ||
|
|
133cbf0d09 | ||
|
|
7d1cddedcb | ||
|
|
a41a41f4dd | ||
|
|
788c2f747c | ||
|
|
ccfff09407 | ||
|
|
1399ebeda8 | ||
|
|
d115e7845f | ||
|
|
5ee1e80568 |
@@ -40,6 +40,9 @@ fi
|
|||||||
if test -d $EXPLODED/$BUILD_NAME/Contents/Home/Frameworks; then
|
if test -d $EXPLODED/$BUILD_NAME/Contents/Home/Frameworks; then
|
||||||
mv $EXPLODED/$BUILD_NAME/Contents/Home/Frameworks $BACKUP_JMODS
|
mv $EXPLODED/$BUILD_NAME/Contents/Home/Frameworks $BACKUP_JMODS
|
||||||
fi
|
fi
|
||||||
|
if test -f $EXPLODED/$BUILD_NAME/Contents/MacOS/libjli.dylib; then
|
||||||
|
mv $EXPLODED/$BUILD_NAME/Contents/MacOS/libjli.dylib $BACKUP_JMODS
|
||||||
|
fi
|
||||||
|
|
||||||
#log "$INPUT_FILE unzipped and removed"
|
#log "$INPUT_FILE unzipped and removed"
|
||||||
log "$INPUT_FILE extracted and removed"
|
log "$INPUT_FILE extracted and removed"
|
||||||
@@ -125,6 +128,9 @@ log "Zipping $BUILD_NAME to $INPUT_FILE ..."
|
|||||||
(
|
(
|
||||||
#cd "$EXPLODED"
|
#cd "$EXPLODED"
|
||||||
#ditto -c -k --sequesterRsrc --keepParent "$BUILD_NAME" "../$INPUT_FILE"
|
#ditto -c -k --sequesterRsrc --keepParent "$BUILD_NAME" "../$INPUT_FILE"
|
||||||
|
if test ! -z $(ls $BACKUP_JMODS/libjli.dylib); then
|
||||||
|
mv $BACKUP_JMODS/libjli.dylib $EXPLODED/$BUILD_NAME/Contents/MacOS
|
||||||
|
fi
|
||||||
if test -d $BACKUP_JMODS/jmods; then
|
if test -d $BACKUP_JMODS/jmods; then
|
||||||
mv $BACKUP_JMODS/jmods $EXPLODED/$BUILD_NAME/Contents/Home
|
mv $BACKUP_JMODS/jmods $EXPLODED/$BUILD_NAME/Contents/Home
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -61,15 +61,17 @@ ifeq ($(OPENJDK_TARGET_OS), macosx)
|
|||||||
FILES := $(call CacheFind, $(JRE_IMAGE_DIR)), \
|
FILES := $(call CacheFind, $(JRE_IMAGE_DIR)), \
|
||||||
))
|
))
|
||||||
|
|
||||||
$(eval $(call SetupCopyFiles, COPY_LIBJLI_JDK, \
|
$(JDK_MACOSX_CONTENTS_DIR)/MacOS/libjli.dylib:
|
||||||
FILES := $(JDK_IMAGE_DIR)/lib/jli/libjli.dylib, \
|
$(call LogInfo, Creating link $(patsubst $(OUTPUTDIR)/%,%,$@))
|
||||||
DEST := $(JDK_MACOSX_CONTENTS_DIR)/MacOS, \
|
$(MKDIR) -p $(@D)
|
||||||
))
|
$(RM) $@
|
||||||
|
$(LN) -s ../Home/lib/jli/libjli.dylib $@
|
||||||
|
|
||||||
$(eval $(call SetupCopyFiles, COPY_LIBJLI_JRE, \
|
$(JRE_MACOSX_CONTENTS_DIR)/MacOS/libjli.dylib:
|
||||||
FILES := $(JRE_IMAGE_DIR)/lib/jli/libjli.dylib, \
|
$(call LogInfo, Creating link $(patsubst $(OUTPUTDIR)/%,%,$@))
|
||||||
DEST := $(JRE_MACOSX_CONTENTS_DIR)/MacOS, \
|
$(MKDIR) -p $(@D)
|
||||||
))
|
$(RM) $@
|
||||||
|
$(LN) -s ../Home/lib/jli/libjli.dylib $@
|
||||||
|
|
||||||
$(eval $(call SetupTextFileProcessing, BUILD_JDK_PLIST, \
|
$(eval $(call SetupTextFileProcessing, BUILD_JDK_PLIST, \
|
||||||
SOURCE_FILES := $(MACOSX_PLIST_SRC)/JDK-Info.plist, \
|
SOURCE_FILES := $(MACOSX_PLIST_SRC)/JDK-Info.plist, \
|
||||||
@@ -95,19 +97,13 @@ ifeq ($(OPENJDK_TARGET_OS), macosx)
|
|||||||
@@VENDOR@@ => $(BUNDLE_VENDOR) , \
|
@@VENDOR@@ => $(BUNDLE_VENDOR) , \
|
||||||
))
|
))
|
||||||
|
|
||||||
$(SUPPORT_OUTPUTDIR)/images/_jdk_bundle_attribute_set: $(COPY_JDK_IMAGE)
|
jdk-bundle: $(COPY_JDK_IMAGE) $(JDK_MACOSX_CONTENTS_DIR)/MacOS/libjli.dylib \
|
||||||
|
$(BUILD_JDK_PLIST)
|
||||||
$(SETFILE) -a B $(dir $(JDK_MACOSX_CONTENTS_DIR))
|
$(SETFILE) -a B $(dir $(JDK_MACOSX_CONTENTS_DIR))
|
||||||
$(TOUCH) $@
|
|
||||||
|
|
||||||
$(SUPPORT_OUTPUTDIR)/images/_jre_bundle_attribute_set: $(COPY_JRE_IMAGE)
|
jre-bundle: $(COPY_JRE_IMAGE) $(JRE_MACOSX_CONTENTS_DIR)/MacOS/libjli.dylib \
|
||||||
|
$(BUILD_JRE_PLIST)
|
||||||
$(SETFILE) -a B $(dir $(JRE_MACOSX_CONTENTS_DIR))
|
$(SETFILE) -a B $(dir $(JRE_MACOSX_CONTENTS_DIR))
|
||||||
$(TOUCH) $@
|
|
||||||
|
|
||||||
jdk-bundle: $(COPY_JDK_IMAGE) $(COPY_LIBJLI_JDK) \
|
|
||||||
$(BUILD_JDK_PLIST) $(SUPPORT_OUTPUTDIR)/images/_jdk_bundle_attribute_set
|
|
||||||
|
|
||||||
jre-bundle: $(COPY_JRE_IMAGE) $(COPY_LIBJLI_JRE) \
|
|
||||||
$(BUILD_JRE_PLIST) $(SUPPORT_OUTPUTDIR)/images/_jre_bundle_attribute_set
|
|
||||||
|
|
||||||
else # Not macosx
|
else # Not macosx
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ package sun.font;
|
|||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FilenameFilter;
|
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -41,6 +40,7 @@ import javax.swing.plaf.FontUIResource;
|
|||||||
import sun.awt.FontConfiguration;
|
import sun.awt.FontConfiguration;
|
||||||
import sun.awt.HeadlessToolkit;
|
import sun.awt.HeadlessToolkit;
|
||||||
import sun.lwawt.macosx.*;
|
import sun.lwawt.macosx.*;
|
||||||
|
import sun.util.logging.PlatformLogger;
|
||||||
|
|
||||||
public final class CFontManager extends SunFontManager {
|
public final class CFontManager extends SunFontManager {
|
||||||
private static Hashtable<String, Font2D> genericFonts = new Hashtable<String, Font2D>();
|
private static Hashtable<String, Font2D> genericFonts = new Hashtable<String, Font2D>();
|
||||||
@@ -144,10 +144,39 @@ public final class CFontManager extends SunFontManager {
|
|||||||
protected void registerJREFonts() {
|
protected void registerJREFonts() {
|
||||||
String[] files = AccessController.doPrivileged((PrivilegedAction<String[]>) () ->
|
String[] files = AccessController.doPrivileged((PrivilegedAction<String[]>) () ->
|
||||||
new File(jreFontDirName).list(getTrueTypeFilter()));
|
new File(jreFontDirName).list(getTrueTypeFilter()));
|
||||||
|
|
||||||
if (files != null) {
|
if (files != null) {
|
||||||
|
PlatformLogger logger = FontUtilities.getLogger();
|
||||||
|
int [] ver = new int[3];
|
||||||
for (String f : files) {
|
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 loadNativeDirFonts(String fontPath);
|
||||||
private native void loadNativeFonts();
|
private native void loadNativeFonts();
|
||||||
|
native String getNativeFontVersion(String psName);
|
||||||
|
|
||||||
void registerFont(String fontName, String fontFamilyName) {
|
void registerFont(String fontName, String fontFamilyName) {
|
||||||
// Use different family for specific font faces
|
// Use different family for specific font faces
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ import com.apple.laf.ClientPropertyApplicator.Property;
|
|||||||
import sun.awt.AWTAccessor;
|
import sun.awt.AWTAccessor;
|
||||||
import sun.awt.AWTAccessor.ComponentAccessor;
|
import sun.awt.AWTAccessor.ComponentAccessor;
|
||||||
import sun.awt.AWTAccessor.WindowAccessor;
|
import sun.awt.AWTAccessor.WindowAccessor;
|
||||||
import sun.awt.InvokeOnToolkitHelper;
|
import sun.awt.AWTThreading;
|
||||||
import sun.java2d.SurfaceData;
|
import sun.java2d.SurfaceData;
|
||||||
import sun.java2d.opengl.CGLSurfaceData;
|
import sun.java2d.opengl.CGLSurfaceData;
|
||||||
import sun.lwawt.LWLightweightFramePeer;
|
import sun.lwawt.LWLightweightFramePeer;
|
||||||
@@ -331,7 +331,7 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
|||||||
long nativeWindowPtr = java.security.AccessController.doPrivileged(
|
long nativeWindowPtr = java.security.AccessController.doPrivileged(
|
||||||
(PrivilegedAction<Long>) () -> {
|
(PrivilegedAction<Long>) () -> {
|
||||||
try {
|
try {
|
||||||
return InvokeOnToolkitHelper.invokeAndBlock(() -> {
|
return AWTThreading.executeWaitToolkit(() -> {
|
||||||
AtomicLong ref = new AtomicLong();
|
AtomicLong ref = new AtomicLong();
|
||||||
contentView.execute(viewPtr -> {
|
contentView.execute(viewPtr -> {
|
||||||
boolean hasOwnerPtr = false;
|
boolean hasOwnerPtr = false;
|
||||||
|
|||||||
@@ -472,7 +472,7 @@ public final class LWCToolkit extends LWToolkit {
|
|||||||
public Insets getScreenInsets(final GraphicsConfiguration gc) {
|
public Insets getScreenInsets(final GraphicsConfiguration gc) {
|
||||||
CGraphicsDevice gd = ((CGraphicsConfig) gc).getDevice();
|
CGraphicsDevice gd = ((CGraphicsConfig) gc).getDevice();
|
||||||
// Avoid deadlock with input methods
|
// Avoid deadlock with input methods
|
||||||
return InvokeOnToolkitHelper.invokeAndBlock(gd::getScreenInsets);
|
return AWTThreading.executeWaitToolkit(gd::getScreenInsets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -726,7 +726,7 @@ public final class LWCToolkit extends LWToolkit {
|
|||||||
final long mediator = createAWTRunLoopMediator();
|
final long mediator = createAWTRunLoopMediator();
|
||||||
|
|
||||||
InvocationEvent invocationEvent =
|
InvocationEvent invocationEvent =
|
||||||
new InvocationEvent(component,
|
AWTThreading.createAndTrackInvocationEvent(component,
|
||||||
runnable,
|
runnable,
|
||||||
() -> {
|
() -> {
|
||||||
if (mediator != 0) {
|
if (mediator != 0) {
|
||||||
@@ -735,17 +735,16 @@ public final class LWCToolkit extends LWToolkit {
|
|||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
|
|
||||||
if (!InvokeOnToolkitHelper.offer(invocationEvent)) {
|
if (component != null) {
|
||||||
if (component != null) {
|
AppContext appContext = SunToolkit.targetToAppContext(component);
|
||||||
AppContext appContext = SunToolkit.targetToAppContext(component);
|
SunToolkit.postEvent(appContext, invocationEvent);
|
||||||
SunToolkit.postEvent(appContext, invocationEvent);
|
|
||||||
|
|
||||||
// 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
|
// 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
|
||||||
SunToolkit.flushPendingEvents(appContext);
|
SunToolkit.flushPendingEvents(appContext);
|
||||||
} else {
|
}
|
||||||
// This should be the equivalent to EventQueue.invokeAndWait
|
else {
|
||||||
((LWCToolkit) Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
|
// This should be the equivalent to EventQueue.invokeAndWait
|
||||||
}
|
((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
doAWTRunLoop(mediator, nonBlockingRunLoop);
|
doAWTRunLoop(mediator, nonBlockingRunLoop);
|
||||||
|
|||||||
@@ -1402,6 +1402,41 @@ JNF_COCOA_ENTER(env);
|
|||||||
JNF_COCOA_EXIT(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
|
* Class: Java_sun_font_CFontManager_loadNativeDirFonts
|
||||||
* Method: loadNativeDirFonts
|
* Method: loadNativeDirFonts
|
||||||
|
|||||||
207
src/java.desktop/share/classes/sun/awt/AWTThreading.java
Normal file
207
src/java.desktop/share/classes/sun/awt/AWTThreading.java
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
package sun.awt;
|
||||||
|
|
||||||
|
import sun.font.FontUtilities;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.InvocationEvent;
|
||||||
|
import java.lang.ref.SoftReference;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Stack;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to perform a cross threads (EventDispatch, Toolkit) execution so that the execution does not cause a deadlock.
|
||||||
|
*/
|
||||||
|
public class AWTThreading {
|
||||||
|
private ExecutorService executor;
|
||||||
|
// every invokeAndWait() pushes a queue of invocations
|
||||||
|
private final Stack<TrackingQueue> invocations = new Stack<>();
|
||||||
|
|
||||||
|
private int level; // re-entrance level
|
||||||
|
|
||||||
|
// invocations should be dispatched on proper EDT (per AppContext)
|
||||||
|
private static final Map<Thread, AWTThreading> EDT_TO_INSTANCE_MAP = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private static class TrackingQueue extends LinkedBlockingQueue<InvocationEvent> {}
|
||||||
|
|
||||||
|
private AWTThreading() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a callable from EventDispatch thread (EDT). It's assumed the callable either performs a blocking execution on Toolkit
|
||||||
|
* or waits a notification from Toolkit. The method is re-entrant.
|
||||||
|
* <p>
|
||||||
|
* Currently only macOS is supported. The callable can wrap a native obj-c selector. The selector should be executed via
|
||||||
|
* [JNFRunLoop performOnMainThreadWaiting:YES ...] so that doAWTRunLoop on AppKit (which is run in [JNFRunLoop javaRunLoopMode]) accepts it.
|
||||||
|
* The callable should not call any Java code that would normally be called on EDT.
|
||||||
|
* <p>
|
||||||
|
* A deadlock can happen when the callable triggers any blocking invocation from Toolkit to EDT, or when Toolkit already waits in
|
||||||
|
* such blocking invocation. To avoid that:
|
||||||
|
* <ul>
|
||||||
|
* <li>The callback execution is delegated to a dedicated pool thread.
|
||||||
|
* <li>All invocation events, initiated by Toolkit via invokeAndWait(), are tracked via a dedicated queue.
|
||||||
|
* <li>All the tracked invocation events are dispatched on EDT out of order (EventQueue) during the callback execution.
|
||||||
|
* <li>In case of a re-entrant method call, all the tracked invocation events coming after the call are dispatched first.
|
||||||
|
* </ul><p>
|
||||||
|
* When called on non-EDT, or on non-macOS, the method executes the callable just in place.
|
||||||
|
*/
|
||||||
|
public static <T> T executeWaitToolkit(Callable<T> callable) {
|
||||||
|
return executeWaitToolkit(callable, -1, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as {@link #executeWaitToolkit(Callable)} except that the method waits no longer than the specified timeout.
|
||||||
|
*/
|
||||||
|
public static <T> T executeWaitToolkit(Callable<T> callable, long timeout, TimeUnit unit) {
|
||||||
|
if (callable == null) return null;
|
||||||
|
|
||||||
|
if (FontUtilities.isMacOSX && EventQueue.isDispatchThread()) {
|
||||||
|
AWTThreading instance = getInstance(Thread.currentThread());
|
||||||
|
if (instance != null) {
|
||||||
|
return instance.execute(callable, timeout, unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fallback to default
|
||||||
|
try {
|
||||||
|
return callable.call();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T execute(Callable<T> callable, long timeout, TimeUnit unit) {
|
||||||
|
assert EventQueue.isDispatchThread();
|
||||||
|
if (executor == null) {
|
||||||
|
// init on EDT
|
||||||
|
AccessController.doPrivileged((PrivilegedAction<?>)() ->
|
||||||
|
executor = new ThreadPoolExecutor(1, Integer.MAX_VALUE,
|
||||||
|
60L, TimeUnit.SECONDS,
|
||||||
|
new SynchronousQueue<>(),
|
||||||
|
new ThreadFactory() {
|
||||||
|
private final ThreadFactory factory = Executors.privilegedThreadFactory();
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable r) {
|
||||||
|
Thread t = factory.newThread(r);
|
||||||
|
t.setDaemon(true);
|
||||||
|
t.setName("AWT-" + AWTThreading.class.getSimpleName() + " " + t.getName());
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
level++;
|
||||||
|
try {
|
||||||
|
TrackingQueue currentQueue;
|
||||||
|
synchronized (invocations) {
|
||||||
|
if (level == 1 && invocations.size() == 1) {
|
||||||
|
currentQueue = invocations.peek();
|
||||||
|
} else {
|
||||||
|
invocations.push(currentQueue = new TrackingQueue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FutureTask<T> task = new FutureTask<>(callable) {
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
synchronized (invocations) {
|
||||||
|
invocations.remove(currentQueue);
|
||||||
|
// add dummy event to wake up the queue
|
||||||
|
currentQueue.add(new InvocationEvent(new Object(), () -> {}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
executor.execute(task);
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (!task.isDone() || !currentQueue.isEmpty()) {
|
||||||
|
InvocationEvent event;
|
||||||
|
if (timeout >= 0 && unit != null) {
|
||||||
|
event = currentQueue.poll(timeout, unit);
|
||||||
|
} else {
|
||||||
|
event = currentQueue.take();
|
||||||
|
}
|
||||||
|
if (event == null) {
|
||||||
|
task.cancel(false);
|
||||||
|
synchronized (invocations) {
|
||||||
|
invocations.remove(currentQueue);
|
||||||
|
}
|
||||||
|
new RuntimeException("Waiting for the invocation event timed out").printStackTrace();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
event.dispatch();
|
||||||
|
}
|
||||||
|
return task.isCancelled() ? null : task.get();
|
||||||
|
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
level--;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by implementation.
|
||||||
|
* Creates an invocation event and adds it to the tracking queue.
|
||||||
|
* It's assumed the event is then posted to EventQueue.
|
||||||
|
* The following is provided:
|
||||||
|
* <ul>
|
||||||
|
* <li>If the event is first dispatched from EventQueue - it gets removed from the tracking queue.
|
||||||
|
* <li>If the event is first dispatched from the tracking queue - its dispatching on EventQueue will be noop.
|
||||||
|
* <ul>
|
||||||
|
*/
|
||||||
|
public static InvocationEvent createAndTrackInvocationEvent(Object source, Runnable runnable, Runnable listener, boolean catchThrowables) {
|
||||||
|
AWTThreading instance = getInstance(source);
|
||||||
|
if (instance != null) {
|
||||||
|
synchronized (instance.invocations) {
|
||||||
|
if (instance.invocations.isEmpty()) {
|
||||||
|
instance.invocations.push(new TrackingQueue());
|
||||||
|
}
|
||||||
|
final TrackingQueue queue = instance.invocations.peek();
|
||||||
|
InvocationEvent event = new InvocationEvent(source, runnable, listener, catchThrowables) {
|
||||||
|
final SoftReference<TrackingQueue> queueRef = new SoftReference<>(queue);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispatch() {
|
||||||
|
if (!isDispatched()) {
|
||||||
|
super.dispatch();
|
||||||
|
|
||||||
|
TrackingQueue queue = queueRef.get();
|
||||||
|
if (queue != null) {
|
||||||
|
queue.remove(this);
|
||||||
|
queueRef.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
queue.add(event);
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new InvocationEvent(source, runnable, listener, catchThrowables);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AWTThreading getInstance(Object obj) {
|
||||||
|
if (obj == null) return null;
|
||||||
|
|
||||||
|
AppContext appContext = SunToolkit.targetToAppContext(obj);
|
||||||
|
if (appContext == null) return null;
|
||||||
|
|
||||||
|
return getInstance((EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AWTThreading getInstance(EventQueue eq) {
|
||||||
|
if (eq == null) return null;
|
||||||
|
|
||||||
|
return getInstance(AWTAccessor.getEventQueueAccessor().getDispatchThread(eq));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AWTThreading getInstance(Thread edt) {
|
||||||
|
if (edt == null) return null;
|
||||||
|
|
||||||
|
return EDT_TO_INSTANCE_MAP.computeIfAbsent(edt, key -> new AWTThreading());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,157 +1,15 @@
|
|||||||
package sun.awt;
|
package sun.awt;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.util.concurrent.Callable;
|
||||||
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.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to perform a blocking invocation on Toolkit thread from EDT, preventing a deadlock.
|
* TODO: remove it in JBR 202
|
||||||
* The deadlock can happen when EDT and Toolkit perform blocking invocations at the same time.
|
*
|
||||||
* The following is performed to resolve it:
|
* @deprecated
|
||||||
* 1) The invoker spins a nested event loop on EDT while waiting for the invocation to complete.
|
* @see AWTThreading
|
||||||
* 2) A separate pool thread is used to perform the invocation.
|
|
||||||
*/
|
*/
|
||||||
public class InvokeOnToolkitHelper {
|
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) {
|
public static <T> T invokeAndBlock(Callable<T> callable) {
|
||||||
if (callable == null) return null;
|
return AWTThreading.executeWaitToolkit(callable);
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,10 +111,6 @@ public abstract class FileFont extends PhysicalFont {
|
|||||||
return 1; // DEFAULT_CHARSET
|
return 1; // DEFAULT_CHARSET
|
||||||
}
|
}
|
||||||
|
|
||||||
int getFontDataSize() {
|
|
||||||
return fileSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the public interface. The subclasses need to implement
|
* This is the public interface. The subclasses need to implement
|
||||||
* this. The returned block may be longer than the requested length.
|
* this. The returned block may be longer than the requested length.
|
||||||
|
|||||||
@@ -442,12 +442,8 @@ public class FileFontStrike extends PhysicalStrike {
|
|||||||
}
|
}
|
||||||
if (ptr == 0) {
|
if (ptr == 0) {
|
||||||
boolean fm = desc.fmHint == INTVAL_FRACTIONALMETRICS_ON;
|
boolean fm = desc.fmHint == INTVAL_FRACTIONALMETRICS_ON;
|
||||||
ptr = _getGlyphImageFromWindows(family, style, size, glyphCode, fm, rotation, charset,
|
ptr = _getGlyphImageFromWindows(family, style, size, glyphCode, fm,
|
||||||
fileFont.getFontDataSize());
|
rotation, charset, ((TrueTypeFont)fileFont).fontDataSize);
|
||||||
if (ptr == 0 && FontUtilities.isLogging()) {
|
|
||||||
FontUtilities.getLogger().warning("Failed to render glyph via GDI: code=" + glyphCode
|
|
||||||
+ ", fontFamily=" + family + ", style=" + style + ", size=" + size + ", rotation=" + rotation);
|
|
||||||
}
|
|
||||||
if (ptr != 0 && fm) {
|
if (ptr != 0 && fm) {
|
||||||
Point2D.Float metrics = new Point2D.Float();
|
Point2D.Float metrics = new Point2D.Float();
|
||||||
fileFont.getGlyphMetrics(pScalerContext, glyphCode, metrics);
|
fileFont.getGlyphMetrics(pScalerContext, glyphCode, metrics);
|
||||||
@@ -456,6 +452,12 @@ public class FileFontStrike extends PhysicalStrike {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ptr == 0) {
|
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);
|
ptr = fileFont.getGlyphImage(pScalerContext, glyphCode);
|
||||||
}
|
}
|
||||||
return ptr;
|
return ptr;
|
||||||
|
|||||||
@@ -64,6 +64,38 @@ import sun.util.logging.PlatformLogger;
|
|||||||
* methods that have to be implemented by specific implementations.
|
* methods that have to be implemented by specific implementations.
|
||||||
*/
|
*/
|
||||||
public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
|
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 {
|
private static class TTFilter implements FilenameFilter {
|
||||||
public boolean accept(File dir,String name) {
|
public boolean accept(File dir,String name) {
|
||||||
@@ -187,7 +219,7 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
|
|||||||
private boolean loaded1dot0Fonts = false;
|
private boolean loaded1dot0Fonts = false;
|
||||||
boolean loadedAllFonts = false;
|
boolean loadedAllFonts = false;
|
||||||
boolean loadedAllFontFiles = false;
|
boolean loadedAllFontFiles = false;
|
||||||
private HashMap<String,String> jreFontMap;
|
private HashMap<String,BundledFontInfo> jreFontMap;
|
||||||
private HashSet<String> jreBundledFontFiles;
|
private HashSet<String> jreBundledFontFiles;
|
||||||
HashMap<String,String> jreFamilyMap;
|
HashMap<String,String> jreFamilyMap;
|
||||||
String[] jreOtherFontFiles;
|
String[] jreOtherFontFiles;
|
||||||
@@ -230,6 +262,7 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
|
|||||||
private Locale lastDefaultLocale;
|
private Locale lastDefaultLocale;
|
||||||
|
|
||||||
public static boolean noType1Font;
|
public static boolean noType1Font;
|
||||||
|
public static boolean versionCheckEnabled;
|
||||||
|
|
||||||
/* Used to indicate required return type from toArray(..); */
|
/* Used to indicate required return type from toArray(..); */
|
||||||
private static String[] STR_ARRAY = new String[0];
|
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
|
* are rarely used. Consider removing the other mappings if there's
|
||||||
* no evidence they are useful in practice.
|
* no evidence they are useful in practice.
|
||||||
*/
|
*/
|
||||||
jreFontMap = new HashMap<String, String>();
|
jreFontMap = new HashMap<>();
|
||||||
jreBundledFontFiles = new HashSet<String>();
|
jreBundledFontFiles = new HashSet<String>();
|
||||||
jreFamilyMap = new HashMap<>();
|
jreFamilyMap = new HashMap<>();
|
||||||
|
|
||||||
/* Droid Sans Mono Family */
|
/* Droid Sans Mono Family */
|
||||||
jreFontMap.put("droid sans0", "DroidSans.ttf");
|
jreFontMap.put("DroidSans.ttf", new BundledFontInfo("DroidSans", 1, 0, 0));
|
||||||
jreFontMap.put("droid sans1", "DroidSans-Bold.ttf");
|
jreFontMap.put("DroidSans-Bold.ttf", new BundledFontInfo("DroidSans-Bold", 1, 0, 0));
|
||||||
jreFontMap.put("droid sans bold1", "DroidSans-Bold.ttf");
|
|
||||||
|
|
||||||
/* Droid Sans Mono Family */
|
/* Droid Sans Mono Family */
|
||||||
jreFontMap.put("droid sans mono0", "DroidSansMono.ttf");
|
jreFontMap.put("DroidSansMono.ttf", new BundledFontInfo("DroidSansMono", 1, 0, 0));
|
||||||
jreFontMap.put("droid sans mono slashed0",
|
jreFontMap.put("DroidSansMonoSlashed.ttf", new BundledFontInfo("DroidSansMonoSlashed", 1, 0, 0));
|
||||||
"DroidSansMonoSlashed.ttf");
|
jreFontMap.put("DroidSansMonoDotted.ttf", new BundledFontInfo("DroidSansMonoDotted", 1, 0, 0));
|
||||||
jreFontMap.put("droid sans mono dotted0",
|
|
||||||
"DroidSansMonoDotted.ttf");
|
|
||||||
|
|
||||||
/* Droid Serif Family */
|
/* Droid Serif Family */
|
||||||
jreFontMap.put("droid serif0", "DroidSerif-Regular.ttf");
|
jreFontMap.put("DroidSerif-Regular.ttf", new BundledFontInfo("DroidSerif", 1, 0, 0));
|
||||||
jreFontMap.put("droid serif1", "DroidSerif-Bold.ttf");
|
jreFontMap.put("DroidSerif-Bold.ttf", new BundledFontInfo("DroidSerif-Bold", 1, 0, 0));
|
||||||
jreFontMap.put("droid serif2", "DroidSerif-Italic.ttf");
|
jreFontMap.put("DroidSerif-Italic.ttf", new BundledFontInfo("DroidSerif-Italic", 1, 0, 0));
|
||||||
jreFontMap.put("droid serif3", "DroidSerif-BoldItalic.ttf");
|
jreFontMap.put("DroidSerif-BoldItalic.ttf", new BundledFontInfo("DroidSerif-BoldItalic", 1, 0, 0));
|
||||||
jreFontMap.put("droid serif bold1", "DroidSerif-Bold.ttf");
|
|
||||||
jreFontMap.put("droid serif bold italic3", "DroidSerif-BoldItalic.ttf");
|
|
||||||
|
|
||||||
/* Idea bundled fonts */
|
/* Idea bundled fonts */
|
||||||
jreFontMap.put("FiraCode bold", "FiraCode-Bold.ttf");
|
jreFontMap.put("FiraCode-Bold.ttf", new BundledFontInfo("FiraCode-Bold", 1, 206, 0));
|
||||||
jreFontMap.put("FiraCode light", "FiraCode-Light.ttf");
|
jreFontMap.put("FiraCode-Light.ttf", new BundledFontInfo("FiraCode-Light", 1, 206, 0));
|
||||||
jreFontMap.put("FiraCode medium", "FiraCode-Medium.ttf");
|
jreFontMap.put("FiraCode-Medium.ttf", new BundledFontInfo("FiraCode-Medium", 1, 206, 0));
|
||||||
jreFontMap.put("FiraCode retina", "FiraCode-Retina.ttf");
|
jreFontMap.put("FiraCode-Retina.ttf", new BundledFontInfo("FiraCode-Retina", 1, 206, 0));
|
||||||
jreFontMap.put("FiraCode regular", "FiraCode-Regular.ttf");
|
jreFontMap.put("FiraCode-Regular.ttf", new BundledFontInfo("FiraCode-Regular", 1, 206, 0));
|
||||||
|
|
||||||
jreFamilyMap.put("FiraCode-Medium", "Fira Code Medium");
|
jreFamilyMap.put("FiraCode-Medium", "Fira Code Medium");
|
||||||
jreFamilyMap.put("FiraCode-Retina", "Fira Code Retina");
|
jreFamilyMap.put("FiraCode-Retina", "Fira Code Retina");
|
||||||
jreFamilyMap.put("FiraCode-Light", "Fira Code Light");
|
jreFamilyMap.put("FiraCode-Light", "Fira Code Light");
|
||||||
|
|
||||||
jreFontMap.put("SourceCodePro bold italic", "SourceCodePro-BoldIt.ttf");
|
jreFontMap.put("SourceCodePro-BoldIt.ttf", new BundledFontInfo("SourceCodePro-BoldIt", 1, 30, 0));
|
||||||
jreFontMap.put("SourceCodePro regular", "SourceCodePro-Regular.ttf");
|
jreFontMap.put("SourceCodePro-Regular.ttf", new BundledFontInfo("SourceCodePro-Regular", 2, 10, 0));
|
||||||
jreFontMap.put("SourceCodePro bold", "SourceCodePro-Bold.ttf");
|
jreFontMap.put("SourceCodePro-Bold.ttf", new BundledFontInfo("SourceCodePro-Bold", 2, 10, 0));
|
||||||
jreFontMap.put("SourceCodePro italic", "SourceCodePro-It.ttf");
|
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-Light.ttf", new BundledFontInfo("Roboto-Light", 1, 100141, 0));
|
||||||
jreFontMap.put("Roboto thin", "Roboto-Thin.ttf");
|
jreFontMap.put("Roboto-Thin.ttf", new BundledFontInfo("Roboto-Thin", 1, 100141, 0));
|
||||||
|
|
||||||
jreFamilyMap.put("Roboto-Light", "Roboto Light");
|
jreFamilyMap.put("Roboto-Light", "Roboto Light");
|
||||||
jreFamilyMap.put("Roboto-Thin", "Roboto Thin");
|
jreFamilyMap.put("Roboto-Thin", "Roboto Thin");
|
||||||
|
|
||||||
jreFontMap.put("JetBrains Mono Bold", "JetBrainsMono-Bold.ttf");
|
jreFontMap.put("JetBrainsMono-Bold.ttf", new BundledFontInfo("JetBrainsMono-Bold", 1, 0, 2));
|
||||||
jreFontMap.put("JetBrains Mono Regular", "JetBrainsMono-Regular.ttf");
|
jreFontMap.put("JetBrainsMono-Regular.ttf", new BundledFontInfo("JetBrainsMono-Regular", 1, 0, 2));
|
||||||
jreFontMap.put("JetBrains Mono Italic", "JetBrainsMono-Italic.ttf");
|
jreFontMap.put("JetBrainsMono-Italic.ttf", new BundledFontInfo("JetBrainsMono-Italic", 1, 0, 2));
|
||||||
jreFontMap.put("JetBrains Mono Bold Italic", "JetBrainsMono-Bold-Italic.ttf");
|
jreFontMap.put("JetBrainsMono-Bold-Italic.ttf", new BundledFontInfo("JetBrainsMono-BoldItalic", 1, 0, 2));
|
||||||
|
|
||||||
jreBundledFontFiles.addAll(jreFontMap.values());
|
jreBundledFontFiles.addAll(jreFontMap.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@@ -353,6 +381,9 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
|
|||||||
default: throw new RuntimeException("Unexpected address size");
|
default: throw new RuntimeException("Unexpected address size");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
versionCheckEnabled =
|
||||||
|
!("true".equals(System.getProperty("java2d.font.noVersionCheck")));
|
||||||
|
|
||||||
noType1Font =
|
noType1Font =
|
||||||
"true".equals(System.getProperty("sun.java2d.noType1Font"));
|
"true".equals(System.getProperty("sun.java2d.noType1Font"));
|
||||||
jreLibDirName =
|
jreLibDirName =
|
||||||
@@ -3887,4 +3918,90 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
|
|||||||
public boolean areColorGlyphsSupported() {
|
public boolean areColorGlyphsSupported() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected BundledFontInfo getBundledFontInfo(String fileName) {
|
||||||
|
return jreFontMap.get(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static boolean parseFontVersion(String versionString, int[] version) {
|
||||||
|
int i = 0;
|
||||||
|
boolean foundDigit = false;
|
||||||
|
version[0] = version[1] = version[2] = 0;
|
||||||
|
|
||||||
|
// Skip prefix letters
|
||||||
|
while (i < versionString.length() &&
|
||||||
|
!(foundDigit = Character.isDigit(versionString.charAt(i)))) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (!foundDigit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
|
||||||
|
boolean foundDot = false;
|
||||||
|
// Read major version
|
||||||
|
while (i < versionString.length() &&
|
||||||
|
!(foundDot = (versionString.charAt(i) == '.')) &&
|
||||||
|
Character.isDigit(versionString.charAt(i))) {
|
||||||
|
buf.append(versionString.charAt(i));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
version[0] = Integer.parseInt(buf.toString());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundDot) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
buf.setLength(0);
|
||||||
|
i++;
|
||||||
|
foundDigit = false;
|
||||||
|
|
||||||
|
// Read minor version
|
||||||
|
while (i < versionString.length() &&
|
||||||
|
!(foundDot = (versionString.charAt(i) == '.')) &&
|
||||||
|
Character.isDigit(versionString.charAt(i))) {
|
||||||
|
buf.append(versionString.charAt(i));
|
||||||
|
foundDigit = true;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (!foundDigit) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
version[1] = Integer.parseInt(buf.toString());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundDot) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.setLength(0);
|
||||||
|
i++;
|
||||||
|
foundDigit = false;
|
||||||
|
|
||||||
|
// Read bugfix version
|
||||||
|
while (i < versionString.length() &&
|
||||||
|
!(versionString.charAt(i) == '.') &&
|
||||||
|
Character.isDigit(versionString.charAt(i))) {
|
||||||
|
buf.append(versionString.charAt(i));
|
||||||
|
foundDigit = true;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundDigit) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
version[2] = Integer.parseInt(buf.toString());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,7 +181,15 @@ public class TrueTypeFont extends FileFont {
|
|||||||
private String localeFullName;
|
private String localeFullName;
|
||||||
|
|
||||||
private Byte supportedCharset;
|
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,
|
public TrueTypeFont(String platname, Object nativeNames, int fIndex,
|
||||||
boolean javaRasterizer)
|
boolean javaRasterizer)
|
||||||
@@ -1783,11 +1791,6 @@ public class TrueTypeFont extends FileFont {
|
|||||||
|
|
||||||
private static native void getSupportedCharsetsForFamily(String familyName, Map<String, Byte> supportedCharsets);
|
private static native void getSupportedCharsetsForFamily(String familyName, Map<String, Byte> supportedCharsets);
|
||||||
|
|
||||||
@Override
|
|
||||||
int getFontDataSize() {
|
|
||||||
return fontDataSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "** TrueType Font: Family="+familyName+ " Name="+fullName+
|
return "** TrueType Font: Family="+familyName+ " Name="+fullName+
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
package sun.java2d.opengl;
|
package sun.java2d.opengl;
|
||||||
|
|
||||||
|
import sun.awt.AWTThreading;
|
||||||
import sun.awt.util.ThreadGroupUtils;
|
import sun.awt.util.ThreadGroupUtils;
|
||||||
import sun.java2d.pipe.RenderBuffer;
|
import sun.java2d.pipe.RenderBuffer;
|
||||||
import sun.java2d.pipe.RenderQueue;
|
import sun.java2d.pipe.RenderQueue;
|
||||||
@@ -32,6 +33,7 @@ import sun.java2d.pipe.RenderQueue;
|
|||||||
import static sun.java2d.pipe.BufferedOpCodes.*;
|
import static sun.java2d.pipe.BufferedOpCodes.*;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OGL-specific implementation of RenderQueue. This class provides a
|
* OGL-specific implementation of RenderQueue. This class provides a
|
||||||
@@ -153,7 +155,7 @@ public class OGLRenderQueue extends RenderQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class QueueFlusher implements Runnable {
|
private class QueueFlusher implements Runnable {
|
||||||
private boolean needsFlush;
|
private volatile boolean needsFlush;
|
||||||
private Runnable task;
|
private Runnable task;
|
||||||
private Error error;
|
private Error error;
|
||||||
private final Thread thread;
|
private final Thread thread;
|
||||||
@@ -167,28 +169,49 @@ public class OGLRenderQueue extends RenderQueue {
|
|||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void flushNow() {
|
public void flushNow() {
|
||||||
// wake up the flusher
|
flushNow(null);
|
||||||
needsFlush = true;
|
}
|
||||||
notify();
|
|
||||||
|
|
||||||
// wait for flush to complete
|
private void flushNow(Runnable task) {
|
||||||
while (needsFlush) {
|
Error err;
|
||||||
|
synchronized (this) {
|
||||||
|
if (task != null) {
|
||||||
|
this.task = task;
|
||||||
|
}
|
||||||
|
// wake up the flusher
|
||||||
|
needsFlush = true;
|
||||||
|
notifyAll();
|
||||||
|
|
||||||
|
// wait for flush to complete
|
||||||
try {
|
try {
|
||||||
wait();
|
wait(100);
|
||||||
} catch (InterruptedException e) {
|
} 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
|
// re-throw any error that may have occurred during the flush
|
||||||
if (error != null) {
|
if (err != null) {
|
||||||
throw error;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void flushAndInvokeNow(Runnable task) {
|
public void flushAndInvokeNow(Runnable task) {
|
||||||
this.task = task;
|
flushNow(task);
|
||||||
flushNow();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void run() {
|
public synchronized void run() {
|
||||||
@@ -242,7 +265,7 @@ public class OGLRenderQueue extends RenderQueue {
|
|||||||
task = null;
|
task = null;
|
||||||
// allow the waiting thread to continue
|
// allow the waiting thread to continue
|
||||||
needsFlush = false;
|
needsFlush = false;
|
||||||
notify();
|
notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
src/java.desktop/share/fonts/JetBrainsMono-Bold-Italic.ttf
Executable file → Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-Bold-Italic.ttf
Executable file → Normal file
Binary file not shown.
BIN
src/java.desktop/share/fonts/JetBrainsMono-Bold.ttf
Executable file → Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-Bold.ttf
Executable file → Normal file
Binary file not shown.
BIN
src/java.desktop/share/fonts/JetBrainsMono-Italic.ttf
Executable file → Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-Italic.ttf
Executable file → Normal file
Binary file not shown.
BIN
src/java.desktop/share/fonts/JetBrainsMono-Regular.ttf
Executable file → Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-Regular.ttf
Executable file → Normal file
Binary file not shown.
@@ -171,8 +171,9 @@ JNIEXPORT jboolean JNICALL
|
|||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jlong JNICALL
|
||||||
Java_sun_font_FileFontStrike__1getGlyphImageFromWindows
|
Java_sun_font_FileFontStrike__1getGlyphImageFromWindows
|
||||||
(JNIEnv *env, jobject unused, jstring fontFamily, jint style, jint size,
|
(JNIEnv *env, jobject unused,
|
||||||
jint glyphCode, jboolean fm, jint rotation, jbyte charset, jint fontDataSize) {
|
jstring fontFamily, jint style, jint size, jint glyphCode, jboolean fm,
|
||||||
|
jint rotation, jbyte charset, jint fontDataSize) {
|
||||||
|
|
||||||
GLYPHMETRICS glyphMetrics;
|
GLYPHMETRICS glyphMetrics;
|
||||||
LOGFONTW lf;
|
LOGFONTW lf;
|
||||||
@@ -257,10 +258,10 @@ jint glyphCode, jboolean fm, jint rotation, jbyte charset, jint fontDataSize) {
|
|||||||
oldFont = SelectObject(hMemoryDC, hFont);
|
oldFont = SelectObject(hMemoryDC, hFont);
|
||||||
|
|
||||||
if (fontDataSize > 0) {
|
if (fontDataSize > 0) {
|
||||||
// We cannot specify via GDI which font file to use,
|
// GDI doesn't allow to select a specific font file for drawing, we can
|
||||||
// so we check that it picks the exact font we need by validating font size.
|
// only check that it picks the file we need by validating font size.
|
||||||
// If it doesn't match, we cannot proceed, as same glyph code can correspond
|
// If it doesn't match, we cannot proceed, as the same glyph code can
|
||||||
// to a completely different glyph in the selected font.
|
// correspond to a completely different glyph in the selected font.
|
||||||
actualFontDataSize = GetFontData(hMemoryDC, 0, 0, NULL, 0);
|
actualFontDataSize = GetFontData(hMemoryDC, 0, 0, NULL, 0);
|
||||||
if (actualFontDataSize != fontDataSize) {
|
if (actualFontDataSize != fontDataSize) {
|
||||||
FREE_AND_RETURN;
|
FREE_AND_RETURN;
|
||||||
|
|||||||
142
test/jdk/jb/java/awt/Toolkit/AWTThreadingTest.java
Normal file
142
test/jdk/jb/java/awt/Toolkit/AWTThreadingTest.java
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
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 ReentrantLock LOCK_2 = new ReentrantLock();
|
||||||
|
static final Condition COND_2 = LOCK_2.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();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user