mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2026-01-25 09:50:48 +01:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07b83bad84 | ||
|
|
703e87cc3a | ||
|
|
dabd52c312 | ||
|
|
574c6d97e9 | ||
|
|
8ff96bc79f | ||
|
|
f600c73328 | ||
|
|
94d6344b43 | ||
|
|
3834f6c24e | ||
|
|
a4e4430a5a | ||
|
|
f85dae83df | ||
|
|
6b64fe9b77 | ||
|
|
85fb38c9a9 | ||
|
|
bcd4b38663 | ||
|
|
77bccaf640 |
12
jb/generate-wakefield.sh
Executable file
12
jb/generate-wakefield.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ -z "$1" ]]; then
|
||||
SCANNER=wayland-scanner
|
||||
else
|
||||
SCANNER="$1"
|
||||
fi
|
||||
|
||||
set -ex
|
||||
|
||||
"$SCANNER" client-header src/java.desktop/share/native/libwakefield/protocol/wakefield.xml src/java.desktop/unix/native/libawt_wlawt/wakefield-client-protocol.h
|
||||
"$SCANNER" private-code src/java.desktop/share/native/libwakefield/protocol/wakefield.xml src/java.desktop/unix/native/libawt_wlawt/wakefield-client-protocol.c
|
||||
@@ -660,12 +660,10 @@ ifeq ($(call isTargetOs, windows), true)
|
||||
else ifeq ($(call isTargetOs, macosx), true)
|
||||
LIBFONTMANAGER_EXCLUDE_FILES += X11FontScaler.c \
|
||||
X11TextRenderer.c \
|
||||
fontpath.c \
|
||||
lcdglyph.c \
|
||||
lcdglyphDW.cpp
|
||||
else
|
||||
LIBFONTMANAGER_EXCLUDE_FILES += fontpath.c \
|
||||
lcdglyph.c \
|
||||
LIBFONTMANAGER_EXCLUDE_FILES += lcdglyph.c \
|
||||
lcdglyphDW.cpp
|
||||
endif
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ public class AquaCaret extends DefaultCaret
|
||||
public void deinstall(final JTextComponent c) {
|
||||
c.removePropertyChangeListener(this);
|
||||
super.deinstall(c);
|
||||
mFocused = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -51,7 +51,6 @@ public class CInputMethod extends InputMethodAdapter {
|
||||
private volatile Component fAwtFocussedComponent;
|
||||
private LWComponentPeer<?, ?> fAwtFocussedComponentPeer;
|
||||
private boolean isActive;
|
||||
private boolean isTemporarilyDeactivated;
|
||||
|
||||
private static Map<TextAttribute, Integer>[] sHighlightStyles;
|
||||
|
||||
@@ -236,12 +235,10 @@ public class CInputMethod extends InputMethodAdapter {
|
||||
*/
|
||||
public void activate() {
|
||||
isActive = true;
|
||||
isTemporarilyDeactivated = false;
|
||||
}
|
||||
|
||||
public void deactivate(boolean isTemporary) {
|
||||
isActive = false;
|
||||
isTemporarilyDeactivated = isTemporary;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,7 +266,7 @@ public class CInputMethod extends InputMethodAdapter {
|
||||
public void removeNotify() {
|
||||
if (fAwtFocussedComponentPeer != null) {
|
||||
long modelPtr = getNativeViewPtr(fAwtFocussedComponentPeer);
|
||||
nativeEndComposition(modelPtr);
|
||||
nativeEndComposition(modelPtr, fAwtFocussedComponent);
|
||||
nativeNotifyPeer(modelPtr, null);
|
||||
}
|
||||
|
||||
@@ -284,10 +281,10 @@ public class CInputMethod extends InputMethodAdapter {
|
||||
* to talk to when responding to key events.
|
||||
*/
|
||||
protected void setAWTFocussedComponent(Component component) {
|
||||
if ((isTemporarilyDeactivated && component == null) || component == fAwtFocussedComponent) {
|
||||
if (component == null || component == fAwtFocussedComponent) {
|
||||
// Sometimes input happens for the natively unfocused window
|
||||
// (e.g. in case of system emoji picker),
|
||||
// so we don't reset last focused component on temporary focus lost.
|
||||
// so we don't reset last focused component on focus lost.
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -355,7 +352,7 @@ public class CInputMethod extends InputMethodAdapter {
|
||||
*/
|
||||
public void endComposition() {
|
||||
if (fAwtFocussedComponentPeer != null)
|
||||
nativeEndComposition(getNativeViewPtr(fAwtFocussedComponentPeer));
|
||||
nativeEndComposition(getNativeViewPtr(fAwtFocussedComponentPeer), fAwtFocussedComponent);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -563,18 +560,21 @@ public class CInputMethod extends InputMethodAdapter {
|
||||
/**
|
||||
* Frequent callbacks from NSTextInput. I think we're supposed to commit it here?
|
||||
*/
|
||||
private synchronized void unmarkText() {
|
||||
if (fCurrentText == null || fAwtFocussedComponent == null) return;
|
||||
private synchronized void unmarkText(Component component) {
|
||||
if (component == null) {
|
||||
component = fAwtFocussedComponent;
|
||||
}
|
||||
if (fCurrentText == null || component == null) return;
|
||||
|
||||
TextHitInfo theCaret = TextHitInfo.afterOffset(fCurrentTextLength);
|
||||
TextHitInfo visiblePosition = theCaret;
|
||||
InputMethodEvent event = new InputMethodEvent(fAwtFocussedComponent,
|
||||
InputMethodEvent event = new InputMethodEvent(component,
|
||||
InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
|
||||
fCurrentText.getIterator(),
|
||||
fCurrentTextLength,
|
||||
theCaret,
|
||||
visiblePosition);
|
||||
LWCToolkit.postEvent(LWCToolkit.targetToAppContext(fAwtFocussedComponent), event);
|
||||
LWCToolkit.postEvent(LWCToolkit.targetToAppContext(component), event);
|
||||
fCurrentText = null;
|
||||
fCurrentTextAsString = null;
|
||||
fCurrentTextLength = 0;
|
||||
@@ -807,7 +807,7 @@ public class CInputMethod extends InputMethodAdapter {
|
||||
// Note that if nativePeer isn't something that normally accepts keystrokes (i.e., a CPanel)
|
||||
// these calls will be ignored.
|
||||
private native void nativeNotifyPeer(long nativePeer, CInputMethod imInstance);
|
||||
private native void nativeEndComposition(long nativePeer);
|
||||
private native void nativeEndComposition(long nativePeer, Component component);
|
||||
private native void nativeHandleEvent(LWComponentPeer<?, ?> peer, AWTEvent event);
|
||||
|
||||
// Returns the locale of the active input method.
|
||||
|
||||
@@ -67,6 +67,6 @@
|
||||
|
||||
// Input method-related events
|
||||
- (void)setInputMethod:(jobject)inputMethod;
|
||||
- (void)abandonInput;
|
||||
- (void)abandonInput:(jobject) component;
|
||||
|
||||
@end
|
||||
|
||||
@@ -393,7 +393,7 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
|
||||
case kVK_End:
|
||||
// Abandon input to reset IM and unblock input after
|
||||
// canceling input accented symbols
|
||||
[self abandonInput];
|
||||
[self abandonInput:nil];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1157,7 +1157,7 @@ static jclass jc_CInputMethod = NULL;
|
||||
// Abandon input to reset IM and unblock input after entering accented
|
||||
// symbols
|
||||
|
||||
[self abandonInput];
|
||||
[self abandonInput:nil];
|
||||
}
|
||||
|
||||
+ (void)keyboardInputSourceChanged:(NSNotification *)notification
|
||||
@@ -1251,7 +1251,11 @@ static jclass jc_CInputMethod = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
- (void) unmarkText
|
||||
- (void) unmarkText {
|
||||
[self unmarkText:nil];
|
||||
}
|
||||
|
||||
- (void) unmarkText:(jobject) component
|
||||
{
|
||||
#ifdef IM_DEBUG
|
||||
fprintf(stderr, "AWTView InputMethod Selector Called : [unmarkText]\n");
|
||||
@@ -1264,8 +1268,8 @@ static jclass jc_CInputMethod = NULL;
|
||||
// unmarkText cancels any input in progress and commits it to the text field.
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
GET_CIM_CLASS();
|
||||
DECLARE_METHOD(jm_unmarkText, jc_CInputMethod, "unmarkText", "()V");
|
||||
(*env)->CallVoidMethod(env, fInputMethodLOCKABLE, jm_unmarkText);
|
||||
DECLARE_METHOD(jm_unmarkText, jc_CInputMethod, "unmarkText", "(Ljava/awt/Component;)V");
|
||||
(*env)->CallVoidMethod(env, fInputMethodLOCKABLE, jm_unmarkText, component);
|
||||
CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
@@ -1526,14 +1530,14 @@ static jclass jc_CInputMethod = NULL;
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)abandonInput
|
||||
- (void)abandonInput:(jobject) component
|
||||
{
|
||||
#ifdef IM_DEBUG
|
||||
fprintf(stderr, "AWTView InputMethod Selector Called : [abandonInput]\n");
|
||||
#endif // IM_DEBUG
|
||||
|
||||
[ThreadUtilities performOnMainThread:@selector(markedTextAbandoned:) on:[NSInputManager currentInputManager] withObject:self waitUntilDone:YES];
|
||||
[self unmarkText];
|
||||
[self unmarkText:component];
|
||||
}
|
||||
|
||||
/******************************** END NSTextInputClient Protocol ********************************/
|
||||
|
||||
@@ -118,13 +118,6 @@ static void initializeInputMethodController() {
|
||||
[view setInputMethod:inputMethod]; // inputMethod is a GlobalRef or null to disable.
|
||||
}
|
||||
|
||||
+ (void) _nativeEndComposition:(AWTView *)view {
|
||||
if (view == nil) return;
|
||||
|
||||
[view abandonInput];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
/*
|
||||
@@ -186,16 +179,21 @@ JNI_COCOA_EXIT(env);
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_CInputMethod
|
||||
* Method: nativeEndComposition
|
||||
* Signature: (J)V
|
||||
* Signature: (JLjava/awt/Component;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CInputMethod_nativeEndComposition
|
||||
(JNIEnv *env, jobject this, jlong nativePeer)
|
||||
(JNIEnv *env, jobject this, jlong nativePeer, jobject component)
|
||||
{
|
||||
JNI_COCOA_ENTER(env);
|
||||
AWTView *view = (AWTView *)jlong_to_ptr(nativePeer);
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:NO block:^(){
|
||||
[CInputMethod _nativeEndComposition:view];
|
||||
AWTView *view = (AWTView *)jlong_to_ptr(nativePeer);
|
||||
if (!view) return;
|
||||
jobject componentRef = (*env)->NewGlobalRef(env, component);
|
||||
[ThreadUtilities performOnMainThreadWaiting:NO block:^(){
|
||||
[view abandonInput:componentRef];
|
||||
if (componentRef) {
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
(*env)->DeleteGlobalRef(env, componentRef);
|
||||
}
|
||||
}];
|
||||
|
||||
JNI_COCOA_EXIT(env);
|
||||
|
||||
@@ -62,7 +62,7 @@ public class JBRApiModule {
|
||||
.withStatic("deriveFontWithFeatures", "deriveFont", "java.awt.Font")
|
||||
.withStatic("getFeaturesAsString", "getFeaturesAsString", "com.jetbrains.desktop.FontExtensions")
|
||||
.clientProxy("java.awt.Font$Features", "com.jetbrains.FontExtensions$Features")
|
||||
.service("com.jetbrains.WindowMove", "sun.awt.X11.XWindowPeer$WindowMoveService")
|
||||
.service("com.jetbrains.WindowMove", "java.awt.Window$WindowMoveService")
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
@@ -4257,6 +4258,67 @@ public class Window extends Container implements Accessible {
|
||||
}
|
||||
}
|
||||
|
||||
private interface WindowMovePeer {
|
||||
void startMovingWindowTogetherWithMouse(Window window, int mouseButton);
|
||||
}
|
||||
|
||||
private interface WindowMovePeerX11 extends WindowMovePeer {
|
||||
WindowMovePeerX11 INSTANCE = (WindowMovePeerX11) JBRApi.internalServiceBuilder(MethodHandles.lookup())
|
||||
.withStatic("startMovingWindowTogetherWithMouse",
|
||||
"startMovingWindowTogetherWithMouse",
|
||||
"sun.awt.X11.XWindowPeer")
|
||||
.build();
|
||||
}
|
||||
|
||||
private interface WindowMovePeerWayland extends WindowMovePeer {
|
||||
WindowMovePeerWayland INSTANCE = (WindowMovePeerWayland) JBRApi.internalServiceBuilder(MethodHandles.lookup())
|
||||
.withStatic("startMovingWindowTogetherWithMouse",
|
||||
"startMovingWindowTogetherWithMouse",
|
||||
"sun.awt.wl.WLComponentPeer")
|
||||
.build();
|
||||
}
|
||||
|
||||
private static class WindowMoveService {
|
||||
WindowMovePeer windowMovePeer;
|
||||
|
||||
WindowMoveService() {
|
||||
var toolkit = Toolkit.getDefaultToolkit();
|
||||
var ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
if (toolkit == null || ge == null) {
|
||||
throw new JBRApi.ServiceNotAvailableException("Supported only with a Toolkit present");
|
||||
}
|
||||
|
||||
boolean isWayland = objectIsInstanceOf(toolkit, "sun.awt.wl.WLToolkit");
|
||||
if (isWayland) {
|
||||
if (!objectIsInstanceOf(ge,"sun.awt.wl.WLGraphicsEnvironment")) {
|
||||
throw new JBRApi.ServiceNotAvailableException("On Wayland, supported only with WLGraphicsEnvironment");
|
||||
}
|
||||
} else {
|
||||
if (!objectIsInstanceOf(toolkit, "sun.awt.X11.XToolkit")
|
||||
|| !objectIsInstanceOf(ge, "sun.awt.X11GraphicsEnvironment")) {
|
||||
throw new JBRApi.ServiceNotAvailableException("Supported only with XToolkit and X11GraphicsEnvironment");
|
||||
}
|
||||
}
|
||||
|
||||
if (isWayland) {
|
||||
windowMovePeer = WindowMovePeerWayland.INSTANCE;
|
||||
} else {
|
||||
// This will throw if the service is not supported by the underlying WM
|
||||
windowMovePeer = WindowMovePeerX11.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
boolean objectIsInstanceOf(Object o, String className) {
|
||||
Objects.requireNonNull(o);
|
||||
return o.getClass().getName().equals(className);
|
||||
}
|
||||
|
||||
void startMovingTogetherWithMouse(Window window, int mouseButton) {
|
||||
Objects.requireNonNull(window);
|
||||
windowMovePeer.startMovingWindowTogetherWithMouse(window, mouseButton);
|
||||
}
|
||||
}
|
||||
|
||||
// ************************** JBR stuff *******************************
|
||||
|
||||
private volatile boolean ignoreMouseEvents;
|
||||
|
||||
@@ -478,6 +478,16 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement
|
||||
y = 0 - yOffset - pmSize.height; // Otherwise drop 'up'
|
||||
}
|
||||
}
|
||||
// Note that the y position may be later adjusted to fit the menu into the screen if possible.
|
||||
// However, the code that does it (JPopupMenu.adjustPopupLocationToFitScreen) has no idea which screen
|
||||
// to fit into, and determines it by the position calculated here, so we need to make sure it's on
|
||||
// the correct screen, otherwise the menu may appear on the wrong screen (JDK-6415065).
|
||||
if (position.y + y < screenBounds.y) { // Above the current screen?
|
||||
y = screenBounds.y - position.y; // Fit into the screen, relative to our origin.
|
||||
}
|
||||
if (position.y + y >= screenBounds.y + screenBounds.height) { // Below the current screen?
|
||||
y = screenBounds.y + screenBounds.height - 1 - position.y; // Fit into the screen, relative to our origin.
|
||||
}
|
||||
return new Point(x,y);
|
||||
}
|
||||
|
||||
|
||||
@@ -1010,7 +1010,11 @@ public class SwingUtilities2 {
|
||||
} else {
|
||||
layout = new TextLayout(iterator, frc);
|
||||
}
|
||||
layout.draw(g2d, x, y);
|
||||
if (Boolean.TRUE.equals(Toolkit.getDefaultToolkit().getDesktopProperty("jb.swing.avoid.text.layout"))) {
|
||||
g2d.drawString(iterator, x, y);
|
||||
} else {
|
||||
layout.draw(g2d, x, y);
|
||||
}
|
||||
retVal = layout.getAdvance();
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -67,12 +67,8 @@
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_FONTCONFIG
|
||||
/* Use bundled fontconfig.h for now */
|
||||
#include "fontconfig.h"
|
||||
#endif
|
||||
|
||||
#ifndef FC_LCD_FILTER
|
||||
#define FC_LCD_FILTER "lcdfilter"
|
||||
#include "fontconfigmanager.h"
|
||||
#include <fontconfig/fontconfig.h>
|
||||
#endif
|
||||
|
||||
#ifndef FC_LCD_NONE
|
||||
@@ -100,16 +96,8 @@
|
||||
#define FT26Dot6ToIntRound(x) (((int)(x + (1 << 5))) >> 6)
|
||||
#define FT26Dot6ToIntCeil(x) (((int)(x - 1 + (1 << 6))) >> 6)
|
||||
#define IntToFT26Dot6(x) (((FT_Fixed)(x)) << 6)
|
||||
#define DEFAULT_DPI 72
|
||||
#define MAX_DPI 1024
|
||||
#define ADJUST_FONT_SIZE(X, DPI) (((X)*DEFAULT_DPI + ((DPI)>>1))/(DPI))
|
||||
#define FLOOR_DIV(X, Y) ((X) >= 0 ? (X) / (Y) : ((X) - (Y) + 1) / (Y))
|
||||
|
||||
#ifndef DISABLE_FONTCONFIG
|
||||
#define FONTCONFIG_DLL JNI_LIB_NAME("fontconfig")
|
||||
#define FONTCONFIG_DLL_VERSIONED VERSIONED_JNI_LIB_NAME("fontconfig", "1")
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
@@ -215,78 +203,14 @@ static jmethodID invalidateScalerMID;
|
||||
static jboolean debugFonts; // Stores the value of FontUtilities.debugFonts()
|
||||
static jmethodID getDefaultToolkitMID;
|
||||
static jclass tkClass;
|
||||
static jmethodID getScreenResolutionMID;
|
||||
static jfieldID platNameFID;
|
||||
static jfieldID familyNameFID;
|
||||
|
||||
#ifndef DISABLE_FONTCONFIG
|
||||
typedef FcBool (*FcPatternAddPtrType) (FcPattern *p, const char *object, FcValue value, FcBool append);
|
||||
typedef FcBool (*FcPatternAddBoolPtrType) (FcPattern *p, const char *object, FcBool b);
|
||||
typedef FcBool (*FcPatternAddDoublePtrType) (FcPattern *p, const char *object, double d);
|
||||
typedef FcBool (*FcConfigSubstitutePtrType) (FcConfig *config, FcPattern *p, FcMatchKind kind);
|
||||
typedef void (*FcDefaultSubstitutePtrType) (FcPattern *pattern);
|
||||
typedef FcPattern* (*FcPatternCreatePtrType) ();
|
||||
typedef FcPattern* (*FcFontMatchPtrType) (FcConfig *config, FcPattern *p, FcResult *result);
|
||||
typedef void (*FcPatternDestroyPtrType) (FcPattern *p);
|
||||
typedef FcResult (*FcPatternGetBoolPtrType) (const FcPattern *p, const char *object, int n, FcBool *b);
|
||||
typedef FcResult (*FcPatternGetIntegerPtrType) (const FcPattern *p, const char *object, int n, int *i);
|
||||
typedef FT_Error (*FtLibrarySetLcdFilterPtrType) (FT_Library library, FT_LcdFilter filter);
|
||||
typedef FcBool (*FcConfigParseAndLoadPtrType) (FcConfig *config, const FcChar8 *file, FcBool complain);
|
||||
typedef FcBool (*FcConfigSetCurrentPtrType) (FcConfig *config);
|
||||
typedef FcConfig * (*FcInitLoadConfigAndFontsPtrType)();
|
||||
typedef int (*FcGetVersionPtrType)();
|
||||
#endif
|
||||
|
||||
static void *libFontConfig = NULL;
|
||||
static jboolean logFC = JNI_FALSE;
|
||||
static jboolean logFFS = JNI_FALSE;
|
||||
|
||||
#ifndef DISABLE_FONTCONFIG
|
||||
static FcPatternAddPtrType FcPatternAddPtr;
|
||||
static FcPatternAddBoolPtrType FcPatternAddBoolPtr;
|
||||
static FcPatternAddDoublePtrType FcPatternAddDoublePtr;
|
||||
static FcConfigSubstitutePtrType FcConfigSubstitutePtr;
|
||||
static FcDefaultSubstitutePtrType FcDefaultSubstitutePtr;
|
||||
static FcPatternCreatePtrType FcPatternCreatePtr;
|
||||
static FcFontMatchPtrType FcFontMatchPtr;
|
||||
static FcPatternDestroyPtrType FcPatternDestroyPtr;
|
||||
static FcPatternGetBoolPtrType FcPatternGetBoolPtr;
|
||||
static FcPatternGetIntegerPtrType FcPatternGetIntegerPtr;
|
||||
static FcConfigParseAndLoadPtrType FcConfigParseAndLoadPtr;
|
||||
static FcConfigSetCurrentPtrType FcConfigSetCurrentPtr;
|
||||
static FcInitLoadConfigAndFontsPtrType FcInitLoadConfigAndFontsPtr;
|
||||
static FcGetVersionPtrType FcGetVersionPtr;
|
||||
#endif
|
||||
|
||||
static FT_UnitVector subpixelGlyphResolution;
|
||||
|
||||
static void* openFontConfig() {
|
||||
void* libfontconfig = NULL;
|
||||
#ifndef DISABLE_FONTCONFIG
|
||||
char *fcLogEnabled = getenv("OPENJDK_FFS_LOG_FC");
|
||||
|
||||
if (fcLogEnabled != NULL && !strcmp(fcLogEnabled, "yes")) {
|
||||
logFC = JNI_TRUE;
|
||||
}
|
||||
|
||||
char *useFC = getenv("OPENJDK_FFS_USE_FC");
|
||||
if (useFC != NULL && !strcmp(useFC, "no")) {
|
||||
if (logFC) fprintf(stderr, "FC_LOG: fontconfig disabled in freetypescaler\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
libfontconfig = dlopen(FONTCONFIG_DLL_VERSIONED, RTLD_LOCAL | RTLD_LAZY);
|
||||
if (libfontconfig == NULL) {
|
||||
libfontconfig = dlopen(FONTCONFIG_DLL, RTLD_LOCAL | RTLD_LAZY);
|
||||
if (libfontconfig == NULL) {
|
||||
if (logFC) fprintf(stderr, "FC_LOG: cannot open %s\n", FONTCONFIG_DLL);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return libfontconfig;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_font_FreetypeFontScaler_initIDs(
|
||||
JNIEnv *env, jobject scaler, jclass FFSClass, jclass TKClass,
|
||||
@@ -315,57 +239,14 @@ Java_sun_font_FreetypeFontScaler_initIDs(
|
||||
getDefaultToolkitMID =
|
||||
(*env)->GetStaticMethodID(env, TKClass, "getDefaultToolkit",
|
||||
"()Ljava/awt/Toolkit;");
|
||||
getScreenResolutionMID =
|
||||
(*env)->GetMethodID(env, TKClass, "getScreenResolution", "()I");
|
||||
tkClass = (*env)->NewGlobalRef(env, TKClass);
|
||||
platNameFID = (*env)->GetFieldID(env, PFClass, "platName", "Ljava/lang/String;");
|
||||
familyNameFID = (*env)->GetFieldID(env, PFClass, "familyName", "Ljava/lang/String;");
|
||||
libFontConfig = openFontConfig();
|
||||
#ifndef DISABLE_FONTCONFIG
|
||||
if (libFontConfig) {
|
||||
FcConfig* fcConfig;
|
||||
FcBool result;
|
||||
FcPatternAddPtr = (FcPatternAddPtrType) dlsym(libFontConfig, "FcPatternAdd");
|
||||
FcPatternAddBoolPtr = (FcPatternAddBoolPtrType) dlsym(libFontConfig, "FcPatternAddBool");
|
||||
FcPatternAddDoublePtr = (FcPatternAddDoublePtrType) dlsym(libFontConfig, "FcPatternAddDouble");
|
||||
FcConfigSubstitutePtr = (FcConfigSubstitutePtrType) dlsym(libFontConfig, "FcConfigSubstitute");
|
||||
FcDefaultSubstitutePtr = (FcDefaultSubstitutePtrType) dlsym(libFontConfig, "FcDefaultSubstitute");
|
||||
FcPatternCreatePtr = (FcPatternCreatePtrType) dlsym(libFontConfig, "FcPatternCreate");
|
||||
FcFontMatchPtr = (FcFontMatchPtrType) dlsym(libFontConfig, "FcFontMatch");
|
||||
FcPatternDestroyPtr = (FcPatternDestroyPtrType) dlsym(libFontConfig, "FcPatternDestroy");
|
||||
FcPatternGetBoolPtr = (FcPatternGetBoolPtrType) dlsym(libFontConfig, "FcPatternGetBool");
|
||||
FcPatternGetIntegerPtr = (FcPatternGetIntegerPtrType) dlsym(libFontConfig, "FcPatternGetInteger");
|
||||
FcConfigParseAndLoadPtr = (FcConfigParseAndLoadPtrType) dlsym(libFontConfig, "FcConfigParseAndLoad");
|
||||
FcConfigSetCurrentPtr = (FcConfigSetCurrentPtrType) dlsym(libFontConfig, "FcConfigSetCurrent");
|
||||
FcInitLoadConfigAndFontsPtr = (FcInitLoadConfigAndFontsPtrType) dlsym(libFontConfig, "FcInitLoadConfigAndFonts");
|
||||
FcGetVersionPtr = (FcGetVersionPtrType) dlsym(libFontConfig, "FcGetVersion");
|
||||
|
||||
|
||||
if (logFC) fprintf(stderr, "FC_LOG: fontconfig version %d \n", (*FcGetVersionPtr)());
|
||||
fcConfig = (*FcInitLoadConfigAndFontsPtr)();
|
||||
if (fcConfig != NULL && fontConf != NULL) {
|
||||
result = (*FcConfigParseAndLoadPtr)(fcConfig, (const FcChar8 *) fontConf, FcFalse);
|
||||
if (logFC) fprintf(stderr, "FC_LOG: FcConfigParseAndLoad %d \n", result);
|
||||
result = (*FcConfigSetCurrentPtr)(fcConfig);
|
||||
if (logFC) fprintf(stderr, "FC_LOG: FcConfigSetCurrent %d \n", result);
|
||||
}
|
||||
else {
|
||||
if (logFC) {
|
||||
if (fontConf) {
|
||||
fprintf(stderr, "FC_LOG: FcInitLoadConfigAndFonts failed\n");
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "FC_LOG: FcInitLoadConfigAndFonts disabled\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (fontConf) {
|
||||
(*env)->ReleaseStringUTFChars(env, jreFontConfName, fontConf);
|
||||
}
|
||||
}
|
||||
|
||||
typedef FT_Error (*FtLibrarySetLcdFilterPtrType) (FT_Library library, FT_LcdFilter filter);
|
||||
|
||||
static FT_Error FT_Library_SetLcdFilter_Proxy(FT_Library library, FT_LcdFilter filter) {
|
||||
#ifndef DISABLE_FONTCONFIG
|
||||
static FtLibrarySetLcdFilterPtrType FtLibrarySetLcdFilterPtr = NULL;
|
||||
@@ -388,46 +269,6 @@ static FT_Error FT_Library_SetLcdFilter_Proxy(FT_Library library, FT_LcdFilter
|
||||
#endif
|
||||
}
|
||||
|
||||
static int getScreenResolution(JNIEnv *env) {
|
||||
/*
|
||||
* Actual screen dpi is necessary only for fontconfig requests
|
||||
*/
|
||||
#ifndef DISABLE_FONTCONFIG
|
||||
jthrowable exc;
|
||||
jclass tk = (*env)->CallStaticObjectMethod(
|
||||
env, tkClass, getDefaultToolkitMID);
|
||||
exc = (*env)->ExceptionOccurred(env);
|
||||
if (exc) {
|
||||
(*env)->ExceptionClear(env);
|
||||
return DEFAULT_DPI;
|
||||
}
|
||||
int dpi = (*env)->CallIntMethod(env, tk, getScreenResolutionMID);
|
||||
|
||||
/* Test if there is no exception here (can get java.awt.HeadlessException)
|
||||
* Fallback to default DPI otherwise
|
||||
*/
|
||||
exc = (*env)->ExceptionOccurred(env);
|
||||
if (exc) {
|
||||
(*env)->ExceptionClear(env);
|
||||
return DEFAULT_DPI;
|
||||
}
|
||||
|
||||
/* Some configurations report invalid dpi settings */
|
||||
if (dpi > MAX_DPI) {
|
||||
if (logFFS) {
|
||||
fprintf(stderr, "FFS_LOG: Invalid dpi reported (%d) replaced with default (%d)\n", dpi, DEFAULT_DPI);
|
||||
}
|
||||
return DEFAULT_DPI;
|
||||
}
|
||||
if (logFFS) {
|
||||
fprintf(stderr, "FFS_LOG: Screen Resolution (%d) dpi\n", dpi);
|
||||
}
|
||||
return dpi;
|
||||
#else
|
||||
return DEFAULT_DPI;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void freeNativeResources(JNIEnv *env, FTScalerInfo* scalerInfo) {
|
||||
|
||||
if (scalerInfo == NULL)
|
||||
@@ -928,25 +769,33 @@ static void setDefaultScalerSettings(FTScalerContext *context) {
|
||||
context->renderFlags = FT_LOAD_TARGET_MODE(context->loadFlags);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_FONTCONFIG
|
||||
static FcBool getRenderingSettingsField(int *target, int value) {
|
||||
*target = value;
|
||||
return (value != -1) ? FcTrue : FcFalse;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int setupFTContext(JNIEnv *env, jobject font2D, FTScalerInfo *scalerInfo, FTScalerContext *context,
|
||||
FT_Bool configureFont) {
|
||||
FT_Matrix matrix;
|
||||
int errCode = 0;
|
||||
scalerInfo->env = env;
|
||||
scalerInfo->font2D = font2D;
|
||||
const char *cfontFamilyName = NULL;
|
||||
const char *cfontPath = NULL;
|
||||
jstring jfontFamilyName = NULL;
|
||||
jstring jfontPath = NULL;
|
||||
|
||||
if (context != NULL) {
|
||||
context->colorFont = FT_HAS_COLOR(scalerInfo->face) || !FT_IS_SCALABLE(scalerInfo->face);
|
||||
|
||||
setupTransform(&matrix, context);
|
||||
FT_Set_Transform(scalerInfo->face, &matrix, NULL);
|
||||
FT_UInt dpi = (FT_UInt) getScreenResolution(env);
|
||||
|
||||
if (FT_IS_SCALABLE(scalerInfo->face)) { // Standard scalable face
|
||||
context->fixedSizeIndex = -1;
|
||||
errCode = FT_Set_Char_Size(scalerInfo->face, 0,
|
||||
ADJUST_FONT_SIZE(context->ptsz, dpi),
|
||||
dpi, dpi);
|
||||
errCode = FT_Set_Char_Size(scalerInfo->face, 0, context->ptsz, 72, 72);
|
||||
} else { // Non-scalable face (that should only be bitmap faces)
|
||||
const int ptsz = context->ptsz;
|
||||
// Best size is smallest, but not smaller than requested
|
||||
@@ -963,35 +812,33 @@ static int setupFTContext(JNIEnv *env, jobject font2D, FTScalerInfo *scalerInfo,
|
||||
}
|
||||
}
|
||||
context->fixedSizeIndex = bestSizeIndex;
|
||||
errCode = FT_Set_Char_Size(scalerInfo->face, 0,
|
||||
ADJUST_FONT_SIZE(bestSize, dpi),
|
||||
dpi, dpi);
|
||||
errCode = FT_Set_Char_Size(scalerInfo->face, 0, bestSize, 72, 72);
|
||||
}
|
||||
|
||||
if (errCode) return errCode;
|
||||
|
||||
errCode = FT_Activate_Size(scalerInfo->face->size);
|
||||
if (errCode) return errCode;
|
||||
|
||||
if (configureFont) {
|
||||
context->renderFlags = FT_RENDER_MODE_NORMAL;
|
||||
context->lcdFilter = FT_LCD_FILTER_NONE;
|
||||
context->loadFlags = FT_LOAD_DEFAULT;
|
||||
|
||||
if (libFontConfig == NULL) {
|
||||
setDefaultScalerSettings(context);
|
||||
return 0;
|
||||
}
|
||||
#ifndef DISABLE_FONTCONFIG
|
||||
jstring jfontFamilyName = (*env)->GetObjectField(env, font2D, familyNameFID);
|
||||
const char *cfontFamilyName = (*env)->GetStringUTFChars(env, jfontFamilyName, NULL);
|
||||
#ifdef DISABLE_FONTCONFIG
|
||||
setDefaultScalerSettings(context);
|
||||
return 0;
|
||||
#else
|
||||
jfontFamilyName = (*env)->GetObjectField(env, font2D, familyNameFID);
|
||||
cfontFamilyName = (*env)->GetStringUTFChars(env, jfontFamilyName, NULL);
|
||||
jfontPath = (*env)->GetObjectField(env, font2D, platNameFID);
|
||||
cfontPath = (*env)->GetStringUTFChars(env, jfontPath, NULL);
|
||||
|
||||
if (logFC) {
|
||||
jstring jfontPath = (*env)->GetObjectField(env, font2D, platNameFID);
|
||||
char *cfontPath = (char*)(*env)->GetStringUTFChars(env, jfontPath, NULL);
|
||||
fprintf(stderr, "FC_LOG: %s %s ", cfontFamilyName, cfontPath);
|
||||
(*env)->ReleaseStringUTFChars(env, jfontPath, cfontPath);
|
||||
}
|
||||
|
||||
double fcSize = FT26Dot6ToDouble(ADJUST_FONT_SIZE(context->ptsz, dpi));
|
||||
double fcSize = FT26Dot6ToDouble(context->ptsz);
|
||||
if (logFC) fprintf(stderr, " size=%f", fcSize);
|
||||
|
||||
// Find cached value
|
||||
@@ -1005,55 +852,33 @@ static int setupFTContext(JNIEnv *env, jobject font2D, FTScalerInfo *scalerInfo,
|
||||
}
|
||||
|
||||
if (cachedMatch.fcSize == 0) {
|
||||
cachedMatch.fcSize = fcSize;
|
||||
clock_t begin = logFC ? clock() : 0;
|
||||
// Setup query
|
||||
FcPattern *fcPattern = 0;
|
||||
fcPattern = (*FcPatternCreatePtr)();
|
||||
FcValue fcValue;
|
||||
fcValue.type = FcTypeString;
|
||||
|
||||
fcValue.u.s = (const FcChar8 *) cfontFamilyName;
|
||||
(*FcPatternAddPtr)(fcPattern, FC_FAMILY, fcValue, FcTrue);
|
||||
(*FcPatternAddBoolPtr)(fcPattern, FC_SCALABLE, FcTrue);
|
||||
(*FcPatternAddDoublePtr)(fcPattern, FC_SIZE, fcSize);
|
||||
|
||||
(*FcConfigSubstitutePtr)(0, fcPattern, FcMatchPattern);
|
||||
(*FcDefaultSubstitutePtr)(fcPattern);
|
||||
FcResult matchResult = FcResultNoMatch;
|
||||
// Match on pattern
|
||||
FcPattern *resultPattern = 0;
|
||||
resultPattern = (*FcFontMatchPtr)(0, fcPattern, &matchResult);
|
||||
|
||||
if (logFC) {
|
||||
clock_t end = clock();
|
||||
double time_spent = (double)(end - begin) * 1000.0 / CLOCKS_PER_SEC;
|
||||
fprintf(stderr, " in %f ms", time_spent);
|
||||
}
|
||||
|
||||
if (matchResult != FcResultMatch) {
|
||||
(*FcPatternDestroyPtr)(fcPattern);
|
||||
if (logFC) fprintf(stderr, " - NOT FOUND\n");
|
||||
RenderingFontHints renderingFontHints;
|
||||
int status = setupRenderingFontHints(cfontFamilyName, NULL, fcSize, &renderingFontHints);
|
||||
if (status != 0) {
|
||||
if (cfontPath) {
|
||||
(*env)->ReleaseStringUTFChars(env, jfontPath, cfontPath);
|
||||
}
|
||||
if (cfontFamilyName) {
|
||||
(*env)->ReleaseStringUTFChars(env, jfontFamilyName, cfontFamilyName);
|
||||
}
|
||||
setDefaultScalerSettings(context);
|
||||
return 0;
|
||||
}
|
||||
(*FcPatternDestroyPtr)(fcPattern);
|
||||
FcPattern *pattern = resultPattern;
|
||||
|
||||
// Extract values from result
|
||||
cachedMatch.fcHintingSet = (*FcPatternGetBoolPtr)(pattern, FC_HINTING, 0, &cachedMatch.fcHinting) == FcResultMatch;
|
||||
cachedMatch.fcSize = fcSize;
|
||||
|
||||
cachedMatch.fcHintingSet =
|
||||
getRenderingSettingsField(&cachedMatch.fcHinting, renderingFontHints.fcHinting);
|
||||
cachedMatch.fcHintStyleSet =
|
||||
(*FcPatternGetIntegerPtr)(pattern, FC_HINT_STYLE, 0, &cachedMatch.fcHintStyle) == FcResultMatch;
|
||||
|
||||
cachedMatch.fcAntialiasSet = (*FcPatternGetBoolPtr)(pattern, FC_ANTIALIAS, 0, &cachedMatch.fcAntialias) == FcResultMatch;
|
||||
cachedMatch.fcAutohintSet = (*FcPatternGetBoolPtr)(pattern, FC_AUTOHINT, 0, &cachedMatch.fcAutohint) == FcResultMatch;
|
||||
getRenderingSettingsField(&cachedMatch.fcHintStyle, renderingFontHints.fcHintStyle);
|
||||
cachedMatch.fcAntialiasSet =
|
||||
getRenderingSettingsField(&cachedMatch.fcAntialias, renderingFontHints.fcAntialias);
|
||||
cachedMatch.fcAutohintSet =
|
||||
getRenderingSettingsField(&cachedMatch.fcAutohint, renderingFontHints.fcAutohint);
|
||||
cachedMatch.fcLCDFilterSet =
|
||||
(*FcPatternGetIntegerPtr)(pattern, FC_LCD_FILTER, 0, &cachedMatch.fcLCDFilter) == FcResultMatch;
|
||||
|
||||
cachedMatch.fcRGBASet = (*FcPatternGetIntegerPtr)(pattern, FC_RGBA, 0, &cachedMatch.fcRGBA) == FcResultMatch;
|
||||
|
||||
(*FcPatternDestroyPtr)(pattern);
|
||||
getRenderingSettingsField(&cachedMatch.fcRGBA, renderingFontHints.fcRGBA);
|
||||
cachedMatch.fcRGBASet =
|
||||
getRenderingSettingsField(&cachedMatch.fcLCDFilter, renderingFontHints.fcLCDFilter);
|
||||
|
||||
if (NUM_CACHED_VALUES > 0) {
|
||||
int nextCacheIdx = scalerInfo->nextCacheIdx;
|
||||
@@ -1205,8 +1030,14 @@ static int setupFTContext(JNIEnv *env, jobject font2D, FTScalerInfo *scalerInfo,
|
||||
}
|
||||
}
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, jfontFamilyName, cfontFamilyName);
|
||||
if (logFC) fprintf(stderr, "\n");
|
||||
|
||||
if (cfontPath) {
|
||||
(*env)->ReleaseStringUTFChars(env, jfontPath, cfontPath);
|
||||
}
|
||||
if (cfontFamilyName) {
|
||||
(*env)->ReleaseStringUTFChars(env, jfontFamilyName, cfontFamilyName);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2723,13 +2554,4 @@ Java_sun_font_FreetypeFontScaler_getGlyphPointNative(
|
||||
|
||||
return (*env)->NewObject(env, sunFontIDs.pt2DFloatClass,
|
||||
sunFontIDs.pt2DFloatCtr, x, y);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JNI_OnUnload(JavaVM *vm, void *reserved) {
|
||||
if (libFontConfig != NULL) {
|
||||
#ifndef DISABLE_FONTCONFIG
|
||||
dlclose(libFontConfig);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,6 +84,37 @@
|
||||
<arg name="error_code" type="uint" enum="error"/>
|
||||
</event>
|
||||
|
||||
<request name="send_key">
|
||||
<description summary="facilitates implementation of Robot.keyPress/Robot.keyRelease">
|
||||
This requests an emulation of a key press by its Linux event key code.
|
||||
</description>
|
||||
<arg name="key" type="uint" />
|
||||
<arg name="state" type="uint" />
|
||||
</request>
|
||||
|
||||
<request name="send_cursor">
|
||||
<description summary="facilitates implementation of Robot.mouseMove">
|
||||
This requests an emulation of the mouse cursor being moved to the specified screen coordinates.
|
||||
</description>
|
||||
<arg name="x" type="int" />
|
||||
<arg name="y" type="int" />
|
||||
</request>
|
||||
|
||||
<request name="send_button">
|
||||
<description summary="facilitates implementation of Robot.mousePress/Robot.mouseRelease">
|
||||
This requests an emulation of a mouse button press by its Linux event code.
|
||||
</description>
|
||||
<arg name="button" type="uint" />
|
||||
<arg name="state" type="uint" />
|
||||
</request>
|
||||
|
||||
<request name="send_wheel">
|
||||
<description summary="facilitates implementation of Robot.mouseWheel">
|
||||
This requests an emulation of a rotation of a mouse scroll wheel.
|
||||
</description>
|
||||
<arg name="amount" type="int" />
|
||||
</request>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="no_error" value="0" summary="error code 0 reserved for the absence of error"/>
|
||||
<entry name="invalid_coordinates" value="1" summary="supplied absolute coordinates point
|
||||
|
||||
@@ -44,6 +44,37 @@ struct wakefield {
|
||||
struct weston_log_scope *log;
|
||||
};
|
||||
|
||||
#define DEFAULT_AXIS_STEP_DISTANCE 10
|
||||
|
||||
// These functions are part of Weston's private backend API (libweston/backend.h)
|
||||
void
|
||||
notify_axis(struct weston_seat *seat, const struct timespec *time,
|
||||
struct weston_pointer_axis_event *event);
|
||||
|
||||
void
|
||||
notify_axis_source(struct weston_seat *seat, uint32_t source);
|
||||
|
||||
void
|
||||
notify_button(struct weston_seat *seat, const struct timespec *time,
|
||||
int32_t button, enum wl_pointer_button_state state);
|
||||
|
||||
void
|
||||
notify_key(struct weston_seat *seat, const struct timespec *time, uint32_t key,
|
||||
enum wl_keyboard_key_state state,
|
||||
enum weston_key_state_update update_state);
|
||||
|
||||
void
|
||||
notify_motion(struct weston_seat *seat, const struct timespec *time,
|
||||
struct weston_pointer_motion_event *event);
|
||||
|
||||
void
|
||||
notify_motion_absolute(struct weston_seat *seat, const struct timespec *time,
|
||||
double x, double y);
|
||||
|
||||
void
|
||||
notify_pointer_frame(struct weston_seat *seat);
|
||||
|
||||
|
||||
static struct weston_output*
|
||||
get_output_for_point(struct wakefield* wakefield, int32_t x, int32_t y)
|
||||
{
|
||||
@@ -482,11 +513,96 @@ wakefield_capture_create(struct wl_client *client,
|
||||
wakefield_send_capture_ready(resource, buffer_resource, WAKEFIELD_ERROR_NO_ERROR);
|
||||
}
|
||||
|
||||
static void
|
||||
wakefield_send_key(struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t key,
|
||||
uint32_t state)
|
||||
{
|
||||
struct wakefield *wakefield = wl_resource_get_user_data(resource);
|
||||
struct weston_compositor *compositor = wakefield->compositor;
|
||||
|
||||
struct timespec time;
|
||||
weston_compositor_get_time(&time);
|
||||
|
||||
struct weston_seat *seat;
|
||||
wl_list_for_each(seat, &compositor->seat_list, link) {
|
||||
notify_key(seat, &time, key,
|
||||
state ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED,
|
||||
STATE_UPDATE_AUTOMATIC);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void wakefield_send_cursor(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t x, int32_t y)
|
||||
{
|
||||
struct wakefield *wakefield = wl_resource_get_user_data(resource);
|
||||
struct weston_compositor *compositor = wakefield->compositor;
|
||||
|
||||
struct timespec time;
|
||||
weston_compositor_get_time(&time);
|
||||
|
||||
struct weston_seat *seat;
|
||||
wl_list_for_each(seat, &compositor->seat_list, link) {
|
||||
notify_motion_absolute(seat, &time, (double)x, (double)y);
|
||||
notify_pointer_frame(seat);
|
||||
}
|
||||
}
|
||||
|
||||
static void wakefield_send_button(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
uint32_t button,
|
||||
uint32_t state)
|
||||
{
|
||||
struct wakefield *wakefield = wl_resource_get_user_data(resource);
|
||||
struct weston_compositor *compositor = wakefield->compositor;
|
||||
|
||||
struct timespec time;
|
||||
weston_compositor_get_time(&time);
|
||||
|
||||
struct weston_seat *seat;
|
||||
wl_list_for_each(seat, &compositor->seat_list, link) {
|
||||
notify_button(seat, &time, (int32_t)button,
|
||||
state ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED);
|
||||
notify_pointer_frame(seat);
|
||||
}
|
||||
}
|
||||
|
||||
static void wakefield_send_wheel(struct wl_client* client,
|
||||
struct wl_resource* resource,
|
||||
int32_t amount)
|
||||
{
|
||||
struct wakefield *wakefield = wl_resource_get_user_data(resource);
|
||||
struct weston_compositor *compositor = wakefield->compositor;
|
||||
|
||||
struct timespec time;
|
||||
weston_compositor_get_time(&time);
|
||||
|
||||
struct weston_pointer_axis_event event = {
|
||||
.axis = WL_POINTER_AXIS_VERTICAL_SCROLL,
|
||||
.value = DEFAULT_AXIS_STEP_DISTANCE * amount,
|
||||
.has_discrete = true,
|
||||
.discrete = amount
|
||||
};
|
||||
|
||||
struct weston_seat *seat;
|
||||
wl_list_for_each(seat, &compositor->seat_list, link) {
|
||||
notify_axis(seat, &time, &event);
|
||||
notify_pointer_frame(seat);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wakefield_interface wakefield_implementation = {
|
||||
.get_surface_location = wakefield_get_surface_location,
|
||||
.move_surface = wakefield_move_surface,
|
||||
.get_pixel_color = wakefield_get_pixel_color,
|
||||
.capture_create = wakefield_capture_create
|
||||
.capture_create = wakefield_capture_create,
|
||||
.send_key = wakefield_send_key,
|
||||
.send_cursor = wakefield_send_cursor,
|
||||
.send_button = wakefield_send_button,
|
||||
.send_wheel = wakefield_send_wheel,
|
||||
};
|
||||
|
||||
static void
|
||||
|
||||
@@ -1423,7 +1423,14 @@ abstract class XDecoratedPeer extends XWindowPeer {
|
||||
if (syncSizeOnly && dimensions != null) {
|
||||
dimensions.setSize(r.width, r.height);
|
||||
dimensions.setInsets(ins);
|
||||
xSetSize(r.width, r.height);
|
||||
boolean isMaximized = target instanceof Frame f && (f.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0;
|
||||
// When a window is maximized, affirming its size through an explicit request to the X server
|
||||
// may make the window fullscreen, which has undesirable consequences. Also, when a window
|
||||
// already has the maximized attributes, it is already properly sized, so no need to
|
||||
// resize explicitly.
|
||||
if (!isMaximized) {
|
||||
xSetSize(r.width, r.height);
|
||||
}
|
||||
} else {
|
||||
dimensions = new WindowDimensions(r, ins, false);
|
||||
xSetBounds(r.x, r.y, r.width, r.height);
|
||||
|
||||
@@ -2655,6 +2655,16 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||
XWM.getWM().startMovingWindowTogetherWithMouse(getParentTopLevel().getWindow(), getLastButtonPressAbsLocation(), mouseButton);
|
||||
}
|
||||
|
||||
private static void startMovingWindowTogetherWithMouse(Window window, int mouseButton) {
|
||||
final AWTAccessor.ComponentAccessor acc = AWTAccessor.getComponentAccessor();
|
||||
ComponentPeer peer = acc.getPeer(window);
|
||||
if (peer instanceof XWindowPeer xWindowPeer) {
|
||||
xWindowPeer.startMovingTogetherWithMouse(mouseButton);
|
||||
} else {
|
||||
throw new IllegalArgumentException("AWT window must have XWindowPeer as its peer");
|
||||
}
|
||||
}
|
||||
|
||||
private static class WindowMoveService {
|
||||
WindowMoveService() {
|
||||
final var toolkit = Toolkit.getDefaultToolkit();
|
||||
|
||||
@@ -1132,4 +1132,15 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
WLToolkit.awtLock();
|
||||
}
|
||||
}
|
||||
|
||||
private static void startMovingWindowTogetherWithMouse(Window window, int mouseButton)
|
||||
{
|
||||
final AWTAccessor.ComponentAccessor acc = AWTAccessor.getComponentAccessor();
|
||||
ComponentPeer peer = acc.getPeer(window);
|
||||
if (peer instanceof WLComponentPeer wlComponentPeer) {
|
||||
wlComponentPeer.startDrag();
|
||||
} else {
|
||||
throw new IllegalArgumentException("AWT window must have WLComponentPeer as its peer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ package sun.awt.wl;
|
||||
* @param pointerButtonPressedEvent null or the latest PointerButtonEvent such that getIsButtonPressed() == true
|
||||
* @param modifiers a bit set of modifiers reflecting currently pressed keys (@see WLInputState.getNewModifiers())
|
||||
* @param surfaceForKeyboardInput represents 'struct wl_surface*' that keyboards events should go to
|
||||
* @param lockingKeyState a bit set of locking modifiers currently active
|
||||
*/
|
||||
record WLInputState(WLPointerEvent eventWithSurface,
|
||||
WLPointerEvent eventWithSerial,
|
||||
@@ -46,7 +47,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
PointerButtonEvent pointerButtonPressedEvent,
|
||||
int modifiers,
|
||||
long surfaceForKeyboardInput,
|
||||
boolean isPointerOverSurface) {
|
||||
boolean isPointerOverSurface,
|
||||
int lockingKeyState) {
|
||||
/**
|
||||
* Groups together information about a mouse pointer button event.
|
||||
* @param surface 'struct wl_surface*' the button was pressed over
|
||||
@@ -60,7 +62,7 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
|
||||
static WLInputState initialState() {
|
||||
return new WLInputState(null, null, null, null,
|
||||
null, 0, 0, false);
|
||||
null, 0, 0, false, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +94,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
newPointerButtonEvent,
|
||||
newModifiers,
|
||||
surfaceForKeyboardInput,
|
||||
newPointerOverSurface);
|
||||
newPointerOverSurface,
|
||||
lockingKeyState);
|
||||
}
|
||||
|
||||
public WLInputState updatedFromKeyboardEnterEvent(long serial, long surfacePtr) {
|
||||
@@ -105,10 +108,11 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
pointerButtonPressedEvent,
|
||||
modifiers,
|
||||
surfacePtr,
|
||||
isPointerOverSurface);
|
||||
isPointerOverSurface,
|
||||
lockingKeyState);
|
||||
}
|
||||
|
||||
public WLInputState updatedFromKeyboardModifiersEvent(long serial, int keyboardModifiers) {
|
||||
public WLInputState updatedFromKeyboardModifiersEvent(long serial, int keyboardModifiers, int newLockingKeyState) {
|
||||
// "The compositor must send the wl_keyboard.modifiers event after this event".
|
||||
final int oldPointerModifiers = modifiers & WLPointerEvent.PointerButtonCodes.combinedMask();
|
||||
final int newModifiers = oldPointerModifiers | keyboardModifiers;
|
||||
@@ -120,7 +124,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
pointerButtonPressedEvent,
|
||||
newModifiers,
|
||||
surfaceForKeyboardInput,
|
||||
isPointerOverSurface);
|
||||
isPointerOverSurface,
|
||||
newLockingKeyState);
|
||||
}
|
||||
|
||||
public WLInputState updatedFromKeyboardLeaveEvent(long serial, long surfacePtr) {
|
||||
@@ -135,7 +140,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
pointerButtonPressedEvent,
|
||||
newModifiers,
|
||||
0,
|
||||
isPointerOverSurface);
|
||||
isPointerOverSurface,
|
||||
lockingKeyState);
|
||||
}
|
||||
|
||||
public WLInputState resetPointerState() {
|
||||
@@ -147,7 +153,8 @@ record WLInputState(WLPointerEvent eventWithSurface,
|
||||
pointerButtonPressedEvent,
|
||||
0,
|
||||
surfaceForKeyboardInput,
|
||||
false);
|
||||
false,
|
||||
lockingKeyState);
|
||||
}
|
||||
|
||||
private PointerButtonEvent getNewPointerButtonEvent(WLPointerEvent pointerEvent,
|
||||
|
||||
@@ -42,32 +42,56 @@ public class WLRobotPeer implements RobotPeer {
|
||||
|
||||
@Override
|
||||
public void mouseMove(int x, int y) {
|
||||
throw new UnsupportedOperationException("Not implemented: WLRobotPeer.mouseMove()");
|
||||
checkExtensionPresent();
|
||||
|
||||
synchronized (WLRobotPeer.class) {
|
||||
mouseMoveImpl(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePress(int buttons) {
|
||||
throw new UnsupportedOperationException("Not implemented: WLRobotPeer.mousePress()");
|
||||
checkExtensionPresent();
|
||||
|
||||
synchronized (WLRobotPeer.class) {
|
||||
sendMouseButtonImpl(buttons, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseRelease(int buttons) {
|
||||
throw new UnsupportedOperationException("Not implemented: WLRobotPeer.mouseRelease()");
|
||||
checkExtensionPresent();
|
||||
|
||||
synchronized (WLRobotPeer.class) {
|
||||
sendMouseButtonImpl(buttons, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseWheel(int wheelAmt) {
|
||||
throw new UnsupportedOperationException("Not implemented: WLRobotPeer.mouseWheel()");
|
||||
checkExtensionPresent();
|
||||
|
||||
synchronized (WLRobotPeer.class) {
|
||||
mouseWheelImpl(wheelAmt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPress(int keycode) {
|
||||
throw new UnsupportedOperationException("Not implemented: WLRobotPeer.keyPress()");
|
||||
checkExtensionPresent();
|
||||
|
||||
synchronized (WLRobotPeer.class) {
|
||||
sendJavaKeyImpl(keycode, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyRelease(int keycode) {
|
||||
throw new UnsupportedOperationException("Not implemented: WLRobotPeer.keyRelease()");
|
||||
checkExtensionPresent();
|
||||
|
||||
synchronized (WLRobotPeer.class) {
|
||||
sendJavaKeyImpl(keycode, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -139,4 +163,8 @@ public class WLRobotPeer implements RobotPeer {
|
||||
private static native int[] getRGBPixelsImpl(int x, int y, int width, int height);
|
||||
private static native Point getLocationOfWLSurfaceImpl(long wlSurfacePtr);
|
||||
private static native void setLocationOfWLSurfaceImpl(long wlSurfacePtr, int x, int y);
|
||||
private static native void sendJavaKeyImpl(int javaKeyCode, boolean pressed);
|
||||
private static native void mouseMoveImpl(int x, int y);
|
||||
private static native void sendMouseButtonImpl(int buttons, boolean pressed);
|
||||
private static native void mouseWheelImpl(int amount);
|
||||
}
|
||||
|
||||
@@ -133,6 +133,9 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
private static final int MOUSE_BUTTONS_COUNT = 3;
|
||||
private static final int AWT_MULTICLICK_DEFAULT_TIME_MS = 500;
|
||||
|
||||
private static final int CAPS_LOCK_MASK = 0x01;
|
||||
private static final int NUM_LOCK_MASK = 0x02;
|
||||
|
||||
private static boolean initialized = false;
|
||||
|
||||
private static native void initIDs();
|
||||
@@ -451,7 +454,9 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
boolean isShiftActive,
|
||||
boolean isAltActive,
|
||||
boolean isCtrlActive,
|
||||
boolean isMetaActive) {
|
||||
boolean isMetaActive,
|
||||
boolean isCapsActive,
|
||||
boolean isNumActive) {
|
||||
// Invoked from the native code
|
||||
assert EventQueue.isDispatchThread();
|
||||
|
||||
@@ -460,12 +465,17 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
| (isAltActive ? InputEvent.ALT_DOWN_MASK : 0)
|
||||
| (isCtrlActive ? InputEvent.CTRL_DOWN_MASK : 0)
|
||||
| (isMetaActive ? InputEvent.META_DOWN_MASK : 0);
|
||||
|
||||
final int newLockingKeyState =
|
||||
(isCapsActive ? CAPS_LOCK_MASK : 0)
|
||||
| (isNumActive ? NUM_LOCK_MASK : 0);
|
||||
|
||||
if (logKeys.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
logKeys.fine("dispatchKeyboardModifiersEvent: new modifiers 0x"
|
||||
+ Integer.toHexString(newModifiers));
|
||||
}
|
||||
|
||||
inputState = inputState.updatedFromKeyboardModifiersEvent(serial, newModifiers);
|
||||
inputState = inputState.updatedFromKeyboardModifiersEvent(serial, newModifiers, newLockingKeyState);
|
||||
}
|
||||
|
||||
private static void dispatchKeyboardEnterEvent(long serial, long surfacePtr) {
|
||||
@@ -760,8 +770,13 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
}
|
||||
@Override
|
||||
public boolean getLockingKeyState(int key) {
|
||||
log.info("Not implemented: WLToolkit.getLockingKeyState()");
|
||||
return false;
|
||||
return switch (key) {
|
||||
case KeyEvent.VK_CAPS_LOCK -> (inputState.lockingKeyState() & CAPS_LOCK_MASK) != 0;
|
||||
case KeyEvent.VK_NUM_LOCK -> (inputState.lockingKeyState() & NUM_LOCK_MASK) != 0;
|
||||
case KeyEvent.VK_SCROLL_LOCK, KeyEvent.VK_KANA_LOCK ->
|
||||
throw new UnsupportedOperationException("getting locking key state is not supported for this key");
|
||||
default -> throw new IllegalArgumentException("invalid key for Toolkit.getLockingKeyState");
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -128,7 +128,7 @@ public class FontConfigManager {
|
||||
if (FontUtilities.isWindows) {
|
||||
return null;
|
||||
} else {
|
||||
int hint = getFontConfigAASettings(getFCLocaleStr(), fcFamily);
|
||||
int hint = getFontConfigAASettings(fcFamily);
|
||||
if (hint < 0) {
|
||||
return null;
|
||||
} else {
|
||||
@@ -188,7 +188,7 @@ public class FontConfigManager {
|
||||
fontArr[i].jdkName = FontUtilities.mapFcName(fontArr[i].fcFamily);
|
||||
fontArr[i].style = i % 4; // depends on array order.
|
||||
}
|
||||
getFontConfig(getFCLocaleStr(), fcInfo, fontArr, includeFallbacks);
|
||||
setupFontConfigFonts(getFCLocaleStr(), fcInfo, fontArr, includeFallbacks);
|
||||
FontConfigFont anyFont = null;
|
||||
/* If don't find anything (eg no libfontconfig), then just return */
|
||||
for (int i = 0; i< fontArr.length; i++) {
|
||||
@@ -432,10 +432,12 @@ public class FontConfigManager {
|
||||
return fontConfigFonts;
|
||||
}
|
||||
|
||||
public static native String getFontProperty(String name, String pattern);
|
||||
|
||||
/* Return an array of FcCompFont structs describing the primary
|
||||
* font located for each of fontconfig/GTK/Pango's logical font names.
|
||||
*/
|
||||
private static native void getFontConfig(String locale,
|
||||
private static native void setupFontConfigFonts(String locale,
|
||||
FontConfigInfo fcInfo,
|
||||
FcCompFont[] fonts,
|
||||
boolean includeFallbacks);
|
||||
@@ -454,7 +456,9 @@ public class FontConfigManager {
|
||||
return fcInfo;
|
||||
}
|
||||
|
||||
private static native int getFontConfigAASettings(String locale, String fcFamily);
|
||||
private static native int getFontConfigAASettings(String fcFamily, String locale);
|
||||
|
||||
public static native String getFontProperty(String name, String pattern);
|
||||
private static int getFontConfigAASettings(String fcFamily) {
|
||||
return getFontConfigAASettings(fcFamily, getFCLocaleStr());
|
||||
}
|
||||
}
|
||||
|
||||
44
src/java.desktop/unix/native/common/awt/fontconfigmanager.h
Normal file
44
src/java.desktop/unix/native/common/awt/fontconfigmanager.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef JETBRAINSRUNTIME_FONTCONFIGMANAGER_H
|
||||
#define JETBRAINSRUNTIME_FONTCONFIGMANAGER_H
|
||||
|
||||
typedef struct RenderingFontHints {
|
||||
int fcHinting;
|
||||
int fcHintStyle;
|
||||
int fcAntialias;
|
||||
int fcAutohint;
|
||||
int fcRGBA;
|
||||
int fcLCDFilter;
|
||||
} RenderingFontHints;
|
||||
|
||||
void openFontConfig();
|
||||
char **getFontConfigLocations();
|
||||
int setupRenderingFontHints(const char* fcName, const char* locale, double size, RenderingFontHints *renderingFontHints);
|
||||
|
||||
#endif //JETBRAINSRUNTIME_FONTCONFIGMANAGER_H
|
||||
@@ -35,6 +35,8 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "fontconfigmanager.h"
|
||||
|
||||
#include <jni.h>
|
||||
#include <jni_util.h>
|
||||
#include <jvm_md.h>
|
||||
@@ -89,8 +91,6 @@ static char *fullAixFontPath[] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
static char **getFontConfigLocations();
|
||||
|
||||
typedef struct {
|
||||
const char *name[MAXFDIRS];
|
||||
int num;
|
||||
@@ -384,933 +384,3 @@ JNIEXPORT jstring JNICALL Java_sun_awt_FcFontManager_getFontPathNative
|
||||
ret = (*env)->NewStringUTF(env, ptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <fontconfig/fontconfig.h>
|
||||
|
||||
|
||||
static void* openFontConfig() {
|
||||
|
||||
char *homeEnv;
|
||||
static char *homeEnvStr = "HOME="; /* must be static */
|
||||
void* libfontconfig = NULL;
|
||||
|
||||
/* Private workaround to not use fontconfig library.
|
||||
* May be useful during testing/debugging
|
||||
*/
|
||||
char *useFC = getenv("USE_J2D_FONTCONFIG");
|
||||
if (useFC != NULL && !strcmp(useFC, "no")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(_AIX)
|
||||
/* On AIX, fontconfig is not a standard package supported by IBM.
|
||||
* instead it has to be installed from the "AIX Toolbox for Linux Applications"
|
||||
* site http://www-03.ibm.com/systems/power/software/aix/linux/toolbox/alpha.html
|
||||
* and will be installed under /opt/freeware/lib/libfontconfig.a.
|
||||
* Notice that the archive contains the real 32- and 64-bit shared libraries.
|
||||
* We first try to load 'libfontconfig.so' from the default library path in the
|
||||
* case the user has installed a private version of the library and if that
|
||||
* doesn't succeed, we try the version from /opt/freeware/lib/libfontconfig.a
|
||||
*/
|
||||
libfontconfig = dlopen("libfontconfig.so", RTLD_LOCAL|RTLD_LAZY);
|
||||
if (libfontconfig == NULL) {
|
||||
libfontconfig = dlopen("/opt/freeware/lib/libfontconfig.a(libfontconfig.so.1)", RTLD_MEMBER|RTLD_LOCAL|RTLD_LAZY);
|
||||
if (libfontconfig == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* 64 bit sparc should pick up the right version from the lib path.
|
||||
* New features may be added to libfontconfig, this is expected to
|
||||
* be compatible with old features, but we may need to start
|
||||
* distinguishing the library version, to know whether to expect
|
||||
* certain symbols - and functionality - to be available.
|
||||
* Also add explicit search for .so.1 in case .so symlink doesn't exist.
|
||||
*/
|
||||
libfontconfig = dlopen(FONTCONFIG_DLL_VERSIONED, RTLD_LOCAL|RTLD_LAZY);
|
||||
if (libfontconfig == NULL) {
|
||||
libfontconfig = dlopen(FONTCONFIG_DLL, RTLD_LOCAL|RTLD_LAZY);
|
||||
if (libfontconfig == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Version 1.0 of libfontconfig crashes if HOME isn't defined in
|
||||
* the environment. This should generally never happen, but we can't
|
||||
* control it, and can't control the version of fontconfig, so iff
|
||||
* its not defined we set it to an empty value which is sufficient
|
||||
* to prevent a crash. I considered unsetting it before exit, but
|
||||
* it doesn't appear to work on Solaris, so I will leave it set.
|
||||
*/
|
||||
homeEnv = getenv("HOME");
|
||||
if (homeEnv == NULL) {
|
||||
putenv(homeEnvStr);
|
||||
}
|
||||
|
||||
return libfontconfig;
|
||||
}
|
||||
|
||||
typedef void* (FcFiniFuncType)();
|
||||
|
||||
static void closeFontConfig(void* libfontconfig, jboolean fcFini) {
|
||||
|
||||
/* NB FcFini is not in (eg) the Solaris 10 version of fontconfig. Its not
|
||||
* clear if this means we are really leaking resources in those cases
|
||||
* but it seems we should call this function when its available.
|
||||
* But since the Swing GTK code may be still accessing the lib, its probably
|
||||
* safest for now to just let this "leak" rather than potentially
|
||||
* concurrently free global data still in use by other code.
|
||||
*/
|
||||
#if 0
|
||||
if (fcFini) { /* release resources */
|
||||
FcFiniFuncType FcFini = (FcFiniFuncType)dlsym(libfontconfig, "FcFini");
|
||||
|
||||
if (FcFini != NULL) {
|
||||
(*FcFini)();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
dlclose(libfontconfig);
|
||||
}
|
||||
|
||||
typedef FcConfig* (*FcInitLoadConfigFuncType)();
|
||||
typedef FcPattern* (*FcPatternBuildFuncType)(FcPattern *orig, ...);
|
||||
typedef FcObjectSet* (*FcObjectSetFuncType)(const char *first, ...);
|
||||
typedef FcFontSet* (*FcFontListFuncType)(FcConfig *config,
|
||||
FcPattern *p,
|
||||
FcObjectSet *os);
|
||||
typedef FcResult (*FcPatternGetBoolFuncType)(const FcPattern *p,
|
||||
const char *object,
|
||||
int n,
|
||||
FcBool *b);
|
||||
typedef FcResult (*FcPatternGetIntegerFuncType)(const FcPattern *p,
|
||||
const char *object,
|
||||
int n,
|
||||
int *i);
|
||||
typedef FcResult (*FcPatternGetStringFuncType)(const FcPattern *p,
|
||||
const char *object,
|
||||
int n,
|
||||
FcChar8 ** s);
|
||||
typedef FcChar8* (*FcStrDirnameFuncType)(const FcChar8 *file);
|
||||
typedef void (*FcPatternDestroyFuncType)(FcPattern *p);
|
||||
typedef void (*FcObjectSetDestroyFuncType)(FcObjectSet *os);
|
||||
typedef void (*FcFontSetDestroyFuncType)(FcFontSet *s);
|
||||
typedef FcPattern* (*FcNameParseFuncType)(const FcChar8 *name);
|
||||
typedef FcBool (*FcPatternAddStringFuncType)(FcPattern *p,
|
||||
const char *object,
|
||||
const FcChar8 *s);
|
||||
typedef void (*FcDefaultSubstituteFuncType)(FcPattern *p);
|
||||
typedef FcBool (*FcConfigSubstituteFuncType)(FcConfig *config,
|
||||
FcPattern *p,
|
||||
FcMatchKind kind);
|
||||
typedef FcPattern* (*FcFontMatchFuncType)(FcConfig *config,
|
||||
FcPattern *p,
|
||||
FcResult *result);
|
||||
typedef FcFontSet* (*FcFontSetCreateFuncType)();
|
||||
typedef FcBool (*FcFontSetAddFuncType)(FcFontSet *s, FcPattern *font);
|
||||
typedef void (*FcStrFreeFuncType)(FcChar8 *str);
|
||||
|
||||
typedef FcResult (*FcPatternGetCharSetFuncType)(FcPattern *p,
|
||||
const char *object,
|
||||
int n,
|
||||
FcCharSet **c);
|
||||
typedef FcFontSet* (*FcFontSortFuncType)(FcConfig *config,
|
||||
FcPattern *p,
|
||||
FcBool trim,
|
||||
FcCharSet **csp,
|
||||
FcResult *result);
|
||||
typedef FcCharSet* (*FcCharSetUnionFuncType)(const FcCharSet *a,
|
||||
const FcCharSet *b);
|
||||
typedef FcCharSet* (*FcCharSetDestroyFuncType)(FcCharSet *fcs);
|
||||
typedef FcChar32 (*FcCharSetSubtractCountFuncType)(const FcCharSet *a,
|
||||
const FcCharSet *b);
|
||||
|
||||
typedef int (*FcGetVersionFuncType)();
|
||||
|
||||
typedef FcStrList* (*FcConfigGetCacheDirsFuncType)(FcConfig *config);
|
||||
typedef FcChar8* (*FcStrListNextFuncType)(FcStrList *list);
|
||||
typedef FcChar8* (*FcStrListDoneFuncType)(FcStrList *list);
|
||||
|
||||
typedef unsigned int (*FcFreeTypeQueryAllFuncType)(const FcChar8 *file, unsigned int id, FcBlanks *blanks,
|
||||
int *count, FcFontSet *set);
|
||||
|
||||
typedef FcChar8* (*FcPatternFormatFuncType)(FcPattern *pat, const FcChar8 *format);
|
||||
|
||||
static char **getFontConfigLocations() {
|
||||
|
||||
char **fontdirs;
|
||||
int numdirs = 0;
|
||||
FcInitLoadConfigFuncType FcInitLoadConfig;
|
||||
FcPatternBuildFuncType FcPatternBuild;
|
||||
FcObjectSetFuncType FcObjectSetBuild;
|
||||
FcFontListFuncType FcFontList;
|
||||
FcPatternGetStringFuncType FcPatternGetString;
|
||||
FcStrDirnameFuncType FcStrDirname;
|
||||
FcPatternDestroyFuncType FcPatternDestroy;
|
||||
FcObjectSetDestroyFuncType FcObjectSetDestroy;
|
||||
FcFontSetDestroyFuncType FcFontSetDestroy;
|
||||
|
||||
FcConfig *fontconfig;
|
||||
FcPattern *pattern;
|
||||
FcObjectSet *objset;
|
||||
FcFontSet *fontSet;
|
||||
FcStrList *strList;
|
||||
FcChar8 *str;
|
||||
int i, f, found, len=0;
|
||||
char **fontPath;
|
||||
|
||||
void* libfontconfig = openFontConfig();
|
||||
|
||||
if (libfontconfig == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FcPatternBuild =
|
||||
(FcPatternBuildFuncType)dlsym(libfontconfig, "FcPatternBuild");
|
||||
FcObjectSetBuild =
|
||||
(FcObjectSetFuncType)dlsym(libfontconfig, "FcObjectSetBuild");
|
||||
FcFontList =
|
||||
(FcFontListFuncType)dlsym(libfontconfig, "FcFontList");
|
||||
FcPatternGetString =
|
||||
(FcPatternGetStringFuncType)dlsym(libfontconfig, "FcPatternGetString");
|
||||
FcStrDirname =
|
||||
(FcStrDirnameFuncType)dlsym(libfontconfig, "FcStrDirname");
|
||||
FcPatternDestroy =
|
||||
(FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");
|
||||
FcObjectSetDestroy =
|
||||
(FcObjectSetDestroyFuncType)dlsym(libfontconfig, "FcObjectSetDestroy");
|
||||
FcFontSetDestroy =
|
||||
(FcFontSetDestroyFuncType)dlsym(libfontconfig, "FcFontSetDestroy");
|
||||
|
||||
if (FcPatternBuild == NULL ||
|
||||
FcObjectSetBuild == NULL ||
|
||||
FcPatternGetString == NULL ||
|
||||
FcFontList == NULL ||
|
||||
FcStrDirname == NULL ||
|
||||
FcPatternDestroy == NULL ||
|
||||
FcObjectSetDestroy == NULL ||
|
||||
FcFontSetDestroy == NULL) { /* problem with the library: return. */
|
||||
closeFontConfig(libfontconfig, JNI_FALSE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make calls into the fontconfig library to build a search for
|
||||
* outline fonts, and to get the set of full file paths from the matches.
|
||||
* This set is returned from the call to FcFontList(..)
|
||||
* We allocate an array of char* pointers sufficient to hold all
|
||||
* the matches + 1 extra which ensures there will be a NULL after all
|
||||
* valid entries.
|
||||
* We call FcStrDirname strip the file name from the path, and
|
||||
* check if we have yet seen this directory. If not we add a pointer to
|
||||
* it into our array of char*. Note that FcStrDirname returns newly
|
||||
* allocated storage so we can use this in the return char** value.
|
||||
* Finally we clean up, freeing allocated resources, and return the
|
||||
* array of unique directories.
|
||||
*/
|
||||
pattern = (*FcPatternBuild)(NULL, FC_OUTLINE, FcTypeBool, FcTrue, NULL);
|
||||
objset = (*FcObjectSetBuild)(FC_FILE, NULL);
|
||||
fontSet = (*FcFontList)(NULL, pattern, objset);
|
||||
if (fontSet == NULL) {
|
||||
/* FcFontList() may return NULL if fonts are not installed. */
|
||||
fontdirs = NULL;
|
||||
} else {
|
||||
fontdirs = (char**)calloc(fontSet->nfont+1, sizeof(char*));
|
||||
if (fontdirs == NULL) {
|
||||
(*FcFontSetDestroy)(fontSet);
|
||||
goto cleanup;
|
||||
}
|
||||
for (f=0; f < fontSet->nfont; f++) {
|
||||
FcChar8 *file;
|
||||
FcChar8 *dir;
|
||||
if ((*FcPatternGetString)(fontSet->fonts[f], FC_FILE, 0, &file) ==
|
||||
FcResultMatch) {
|
||||
dir = (*FcStrDirname)(file);
|
||||
found = 0;
|
||||
for (i=0;i<numdirs; i++) {
|
||||
if (strcmp(fontdirs[i], (char*)dir) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
fontdirs[numdirs++] = (char*)dir;
|
||||
} else {
|
||||
free((char*)dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Free fontset if one was returned */
|
||||
(*FcFontSetDestroy)(fontSet);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/* Free memory and close the ".so" */
|
||||
(*FcObjectSetDestroy)(objset);
|
||||
(*FcPatternDestroy)(pattern);
|
||||
closeFontConfig(libfontconfig, JNI_TRUE);
|
||||
return fontdirs;
|
||||
}
|
||||
|
||||
/* These are copied from sun.awt.SunHints.
|
||||
* Consider initialising them as ints using JNI for more robustness.
|
||||
*/
|
||||
#define TEXT_AA_OFF 1
|
||||
#define TEXT_AA_ON 2
|
||||
#define TEXT_AA_LCD_HRGB 4
|
||||
#define TEXT_AA_LCD_HBGR 5
|
||||
#define TEXT_AA_LCD_VRGB 6
|
||||
#define TEXT_AA_LCD_VBGR 7
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_font_FontConfigManager_getFontConfigAASettings
|
||||
(JNIEnv *env, jclass obj, jstring localeStr, jstring fcNameStr) {
|
||||
|
||||
FcNameParseFuncType FcNameParse;
|
||||
FcPatternAddStringFuncType FcPatternAddString;
|
||||
FcConfigSubstituteFuncType FcConfigSubstitute;
|
||||
FcDefaultSubstituteFuncType FcDefaultSubstitute;
|
||||
FcFontMatchFuncType FcFontMatch;
|
||||
FcPatternGetBoolFuncType FcPatternGetBool;
|
||||
FcPatternGetIntegerFuncType FcPatternGetInteger;
|
||||
FcPatternDestroyFuncType FcPatternDestroy;
|
||||
|
||||
FcPattern *pattern, *matchPattern;
|
||||
FcResult result;
|
||||
FcBool antialias = FcFalse;
|
||||
int rgba = 0;
|
||||
const char *locale=NULL, *fcName=NULL;
|
||||
void* libfontconfig;
|
||||
|
||||
if (fcNameStr == NULL || localeStr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0);
|
||||
if (fcName == NULL) {
|
||||
return -1;
|
||||
}
|
||||
locale = (*env)->GetStringUTFChars(env, localeStr, 0);
|
||||
|
||||
if ((libfontconfig = openFontConfig()) == NULL) {
|
||||
(*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);
|
||||
if (locale) {
|
||||
(*env)->ReleaseStringUTFChars(env, localeStr,(const char*)locale);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
FcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse");
|
||||
FcPatternAddString =
|
||||
(FcPatternAddStringFuncType)dlsym(libfontconfig, "FcPatternAddString");
|
||||
FcConfigSubstitute =
|
||||
(FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute");
|
||||
FcDefaultSubstitute = (FcDefaultSubstituteFuncType)
|
||||
dlsym(libfontconfig, "FcDefaultSubstitute");
|
||||
FcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch");
|
||||
FcPatternGetBool = (FcPatternGetBoolFuncType)
|
||||
dlsym(libfontconfig, "FcPatternGetBool");
|
||||
FcPatternGetInteger = (FcPatternGetIntegerFuncType)
|
||||
dlsym(libfontconfig, "FcPatternGetInteger");
|
||||
FcPatternDestroy =
|
||||
(FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");
|
||||
|
||||
if (FcNameParse == NULL ||
|
||||
FcPatternAddString == NULL ||
|
||||
FcConfigSubstitute == NULL ||
|
||||
FcDefaultSubstitute == NULL ||
|
||||
FcFontMatch == NULL ||
|
||||
FcPatternGetBool == NULL ||
|
||||
FcPatternGetInteger == NULL ||
|
||||
FcPatternDestroy == NULL) { /* problem with the library: return. */
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);
|
||||
if (locale) {
|
||||
(*env)->ReleaseStringUTFChars(env, localeStr,(const char*)locale);
|
||||
}
|
||||
closeFontConfig(libfontconfig, JNI_FALSE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
pattern = (*FcNameParse)((FcChar8 *)fcName);
|
||||
if (locale != NULL) {
|
||||
(*FcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale);
|
||||
}
|
||||
(*FcConfigSubstitute)(NULL, pattern, FcMatchPattern);
|
||||
(*FcDefaultSubstitute)(pattern);
|
||||
matchPattern = (*FcFontMatch)(NULL, pattern, &result);
|
||||
/* Perhaps should call FcFontRenderPrepare() here as some pattern
|
||||
* elements might change as a result of that call, but I'm not seeing
|
||||
* any difference in testing.
|
||||
*/
|
||||
if (matchPattern) {
|
||||
(*FcPatternGetBool)(matchPattern, FC_ANTIALIAS, 0, &antialias);
|
||||
(*FcPatternGetInteger)(matchPattern, FC_RGBA, 0, &rgba);
|
||||
(*FcPatternDestroy)(matchPattern);
|
||||
}
|
||||
(*FcPatternDestroy)(pattern);
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);
|
||||
if (locale) {
|
||||
(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
|
||||
}
|
||||
closeFontConfig(libfontconfig, JNI_TRUE);
|
||||
|
||||
if (antialias == FcFalse) {
|
||||
return TEXT_AA_OFF;
|
||||
} else if (rgba <= FC_RGBA_UNKNOWN || rgba >= FC_RGBA_NONE) {
|
||||
return TEXT_AA_ON;
|
||||
} else {
|
||||
switch (rgba) {
|
||||
case FC_RGBA_RGB : return TEXT_AA_LCD_HRGB;
|
||||
case FC_RGBA_BGR : return TEXT_AA_LCD_HBGR;
|
||||
case FC_RGBA_VRGB : return TEXT_AA_LCD_VRGB;
|
||||
case FC_RGBA_VBGR : return TEXT_AA_LCD_VBGR;
|
||||
default : return TEXT_AA_LCD_HRGB; // should not get here.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_font_FontConfigManager_getFontConfigVersion
|
||||
(JNIEnv *env, jclass obj) {
|
||||
|
||||
void* libfontconfig;
|
||||
FcGetVersionFuncType FcGetVersion;
|
||||
int version = 0;
|
||||
|
||||
if ((libfontconfig = openFontConfig()) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
FcGetVersion = (FcGetVersionFuncType)dlsym(libfontconfig, "FcGetVersion");
|
||||
|
||||
if (FcGetVersion == NULL) {
|
||||
closeFontConfig(libfontconfig, JNI_FALSE);
|
||||
return 0;
|
||||
}
|
||||
version = (*FcGetVersion)();
|
||||
closeFontConfig(libfontconfig, JNI_FALSE);
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_sun_font_FontConfigManager_getFontProperty
|
||||
(JNIEnv *env, jclass obj, jstring query, jstring property) {
|
||||
|
||||
void* libfontconfig = NULL;
|
||||
FcNameParseFuncType FcNameParse;
|
||||
FcPatternFormatFuncType FcPatternFormat;
|
||||
FcConfigSubstituteFuncType FcConfigSubstitute;
|
||||
FcDefaultSubstituteFuncType FcDefaultSubstitute;
|
||||
FcFontMatchFuncType FcFontMatch;
|
||||
FcStrFreeFuncType FcStrFree;
|
||||
|
||||
const char *queryPtr = NULL;
|
||||
const char *propertyPtr = NULL;
|
||||
FcChar8 *fontFamily = NULL;
|
||||
FcChar8 *fontPath = NULL;
|
||||
jstring res = NULL;
|
||||
|
||||
if ((libfontconfig = openFontConfig()) == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
FcPatternFormat = (FcPatternFormatFuncType)dlsym(libfontconfig, "FcPatternFormat");
|
||||
FcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse");
|
||||
FcConfigSubstitute = (FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute");
|
||||
FcDefaultSubstitute = (FcDefaultSubstituteFuncType)dlsym(libfontconfig, "FcDefaultSubstitute");
|
||||
FcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch");
|
||||
FcStrFree = (FcStrFreeFuncType)dlsym(libfontconfig, "FcStrFree");
|
||||
|
||||
queryPtr = (*env)->GetStringUTFChars(env, query, 0);
|
||||
propertyPtr = (*env)->GetStringUTFChars(env, property, 0);
|
||||
if (queryPtr == NULL || propertyPtr == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
FcPattern *pattern = (*FcNameParse)((FcChar8 *) queryPtr);
|
||||
if (pattern == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
(*FcConfigSubstitute)(NULL, pattern, FcMatchScan);
|
||||
(*FcDefaultSubstitute)(pattern);
|
||||
|
||||
FcResult fcResult;
|
||||
FcPattern *match = (*FcFontMatch)(0, pattern, &fcResult);
|
||||
if (match == NULL || fcResult != FcResultMatch) {
|
||||
goto cleanup;
|
||||
}
|
||||
fontFamily = (FcPatternFormat)(match, (FcChar8*) "%{family}");
|
||||
if (fontFamily == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
// result of foundFontName could be set of families, so we left only first family
|
||||
char *commaPos = strchr((char *) fontFamily, ',');
|
||||
if (commaPos != NULL) {
|
||||
*commaPos = '\0';
|
||||
}
|
||||
if (strstr(queryPtr, (char *) fontFamily) == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fontPath = (FcPatternFormat)(match, (FcChar8*) propertyPtr);
|
||||
if (fontPath == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
res = (*env)->NewStringUTF(env, (char *) fontPath);
|
||||
|
||||
cleanup:
|
||||
if (fontPath) {
|
||||
(FcStrFree)(fontPath);
|
||||
}
|
||||
if (fontFamily) {
|
||||
(FcStrFree)(fontFamily);
|
||||
}
|
||||
if (propertyPtr) {
|
||||
(*env)->ReleaseStringUTFChars(env, property, (const char*)propertyPtr);
|
||||
}
|
||||
if (queryPtr) {
|
||||
(*env)->ReleaseStringUTFChars(env, query, (const char*)queryPtr);
|
||||
}
|
||||
if (libfontconfig) {
|
||||
closeFontConfig(libfontconfig, JNI_FALSE);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_font_FontConfigManager_getFontConfig
|
||||
(JNIEnv *env, jclass obj, jstring localeStr, jobject fcInfoObj,
|
||||
jobjectArray fcCompFontArray, jboolean includeFallbacks) {
|
||||
|
||||
FcNameParseFuncType FcNameParse;
|
||||
FcPatternAddStringFuncType FcPatternAddString;
|
||||
FcConfigSubstituteFuncType FcConfigSubstitute;
|
||||
FcDefaultSubstituteFuncType FcDefaultSubstitute;
|
||||
FcFontMatchFuncType FcFontMatch;
|
||||
FcPatternGetStringFuncType FcPatternGetString;
|
||||
FcPatternDestroyFuncType FcPatternDestroy;
|
||||
FcPatternGetCharSetFuncType FcPatternGetCharSet;
|
||||
FcFontSortFuncType FcFontSort;
|
||||
FcFontSetDestroyFuncType FcFontSetDestroy;
|
||||
FcCharSetUnionFuncType FcCharSetUnion;
|
||||
FcCharSetDestroyFuncType FcCharSetDestroy;
|
||||
FcCharSetSubtractCountFuncType FcCharSetSubtractCount;
|
||||
FcGetVersionFuncType FcGetVersion;
|
||||
FcConfigGetCacheDirsFuncType FcConfigGetCacheDirs;
|
||||
FcStrListNextFuncType FcStrListNext;
|
||||
FcStrListDoneFuncType FcStrListDone;
|
||||
|
||||
int i, arrlen;
|
||||
jobject fcCompFontObj;
|
||||
jstring fcNameStr, jstr;
|
||||
const char *locale, *fcName;
|
||||
FcPattern *pattern;
|
||||
FcResult result;
|
||||
void* libfontconfig;
|
||||
jfieldID fcNameID, fcFirstFontID, fcAllFontsID, fcVersionID, fcCacheDirsID;
|
||||
jfieldID familyNameID, styleNameID, fullNameID, fontFileID;
|
||||
jmethodID fcFontCons;
|
||||
char* debugMinGlyphsStr = getenv("J2D_DEBUG_MIN_GLYPHS");
|
||||
jclass fcInfoClass;
|
||||
jclass fcCompFontClass;
|
||||
jclass fcFontClass;
|
||||
|
||||
CHECK_NULL(fcInfoObj);
|
||||
CHECK_NULL(fcCompFontArray);
|
||||
|
||||
fcInfoClass =
|
||||
(*env)->FindClass(env, "sun/font/FontConfigManager$FontConfigInfo");
|
||||
CHECK_NULL(fcInfoClass);
|
||||
fcCompFontClass =
|
||||
(*env)->FindClass(env, "sun/font/FontConfigManager$FcCompFont");
|
||||
CHECK_NULL(fcCompFontClass);
|
||||
fcFontClass =
|
||||
(*env)->FindClass(env, "sun/font/FontConfigManager$FontConfigFont");
|
||||
CHECK_NULL(fcFontClass);
|
||||
|
||||
|
||||
CHECK_NULL(fcVersionID = (*env)->GetFieldID(env, fcInfoClass, "fcVersion", "I"));
|
||||
CHECK_NULL(fcCacheDirsID = (*env)->GetFieldID(env, fcInfoClass, "cacheDirs",
|
||||
"[Ljava/lang/String;"));
|
||||
CHECK_NULL(fcNameID = (*env)->GetFieldID(env, fcCompFontClass,
|
||||
"fcName", "Ljava/lang/String;"));
|
||||
CHECK_NULL(fcFirstFontID = (*env)->GetFieldID(env, fcCompFontClass, "firstFont",
|
||||
"Lsun/font/FontConfigManager$FontConfigFont;"));
|
||||
CHECK_NULL(fcAllFontsID = (*env)->GetFieldID(env, fcCompFontClass, "allFonts",
|
||||
"[Lsun/font/FontConfigManager$FontConfigFont;"));
|
||||
CHECK_NULL(fcFontCons = (*env)->GetMethodID(env, fcFontClass, "<init>", "()V"));
|
||||
CHECK_NULL(familyNameID = (*env)->GetFieldID(env, fcFontClass,
|
||||
"familyName", "Ljava/lang/String;"));
|
||||
CHECK_NULL(styleNameID = (*env)->GetFieldID(env, fcFontClass,
|
||||
"styleStr", "Ljava/lang/String;"));
|
||||
CHECK_NULL(fullNameID = (*env)->GetFieldID(env, fcFontClass,
|
||||
"fullName", "Ljava/lang/String;"));
|
||||
CHECK_NULL(fontFileID = (*env)->GetFieldID(env, fcFontClass,
|
||||
"fontFile", "Ljava/lang/String;"));
|
||||
|
||||
if ((libfontconfig = openFontConfig()) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
FcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse");
|
||||
FcPatternAddString =
|
||||
(FcPatternAddStringFuncType)dlsym(libfontconfig, "FcPatternAddString");
|
||||
FcConfigSubstitute =
|
||||
(FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute");
|
||||
FcDefaultSubstitute = (FcDefaultSubstituteFuncType)
|
||||
dlsym(libfontconfig, "FcDefaultSubstitute");
|
||||
FcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch");
|
||||
FcPatternGetString =
|
||||
(FcPatternGetStringFuncType)dlsym(libfontconfig, "FcPatternGetString");
|
||||
FcPatternDestroy =
|
||||
(FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");
|
||||
FcPatternGetCharSet =
|
||||
(FcPatternGetCharSetFuncType)dlsym(libfontconfig,
|
||||
"FcPatternGetCharSet");
|
||||
FcFontSort =
|
||||
(FcFontSortFuncType)dlsym(libfontconfig, "FcFontSort");
|
||||
FcFontSetDestroy =
|
||||
(FcFontSetDestroyFuncType)dlsym(libfontconfig, "FcFontSetDestroy");
|
||||
FcCharSetUnion =
|
||||
(FcCharSetUnionFuncType)dlsym(libfontconfig, "FcCharSetUnion");
|
||||
FcCharSetDestroy =
|
||||
(FcCharSetDestroyFuncType)dlsym(libfontconfig, "FcCharSetDestroy");
|
||||
FcCharSetSubtractCount =
|
||||
(FcCharSetSubtractCountFuncType)dlsym(libfontconfig,
|
||||
"FcCharSetSubtractCount");
|
||||
FcGetVersion = (FcGetVersionFuncType)dlsym(libfontconfig, "FcGetVersion");
|
||||
|
||||
if (FcNameParse == NULL ||
|
||||
FcPatternAddString == NULL ||
|
||||
FcConfigSubstitute == NULL ||
|
||||
FcDefaultSubstitute == NULL ||
|
||||
FcFontMatch == NULL ||
|
||||
FcPatternGetString == NULL ||
|
||||
FcPatternDestroy == NULL ||
|
||||
FcPatternGetCharSet == NULL ||
|
||||
FcFontSetDestroy == NULL ||
|
||||
FcCharSetUnion == NULL ||
|
||||
FcCharSetDestroy == NULL ||
|
||||
FcGetVersion == NULL ||
|
||||
FcCharSetSubtractCount == NULL) {/* problem with the library: return.*/
|
||||
closeFontConfig(libfontconfig, JNI_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
(*env)->SetIntField(env, fcInfoObj, fcVersionID, (*FcGetVersion)());
|
||||
|
||||
/* Optionally get the cache dir locations. This isn't
|
||||
* available until v 2.4.x, but this is OK since on those later versions
|
||||
* we can check the time stamps on the cache dirs to see if we
|
||||
* are out of date. There are a couple of assumptions here. First
|
||||
* that the time stamp on the directory changes when the contents are
|
||||
* updated. Secondly that the locations don't change. The latter is
|
||||
* most likely if a new version of fontconfig is installed, but we also
|
||||
* invalidate the cache if we detect that. Arguably even that is "rare",
|
||||
* and most likely is tied to an OS upgrade which gets a new file anyway.
|
||||
*/
|
||||
FcConfigGetCacheDirs =
|
||||
(FcConfigGetCacheDirsFuncType)dlsym(libfontconfig,
|
||||
"FcConfigGetCacheDirs");
|
||||
FcStrListNext =
|
||||
(FcStrListNextFuncType)dlsym(libfontconfig, "FcStrListNext");
|
||||
FcStrListDone =
|
||||
(FcStrListDoneFuncType)dlsym(libfontconfig, "FcStrListDone");
|
||||
if (FcStrListNext != NULL && FcStrListDone != NULL &&
|
||||
FcConfigGetCacheDirs != NULL) {
|
||||
|
||||
FcStrList* cacheDirs;
|
||||
FcChar8* cacheDir;
|
||||
int cnt = 0;
|
||||
jobject cacheDirArray =
|
||||
(*env)->GetObjectField(env, fcInfoObj, fcCacheDirsID);
|
||||
int max = (*env)->GetArrayLength(env, cacheDirArray);
|
||||
|
||||
cacheDirs = (*FcConfigGetCacheDirs)(NULL);
|
||||
if (cacheDirs != NULL) {
|
||||
while ((cnt < max) && (cacheDir = (*FcStrListNext)(cacheDirs))) {
|
||||
jstr = (*env)->NewStringUTF(env, (const char*)cacheDir);
|
||||
if (IS_NULL(jstr)) {
|
||||
(*FcStrListDone)(cacheDirs);
|
||||
return;
|
||||
}
|
||||
(*env)->SetObjectArrayElement(env, cacheDirArray, cnt++, jstr);
|
||||
(*env)->DeleteLocalRef(env, jstr);
|
||||
}
|
||||
(*FcStrListDone)(cacheDirs);
|
||||
}
|
||||
}
|
||||
|
||||
locale = (*env)->GetStringUTFChars(env, localeStr, 0);
|
||||
if (locale == NULL) {
|
||||
(*env)->ExceptionClear(env);
|
||||
JNU_ThrowOutOfMemoryError(env, "Could not create locale");
|
||||
return;
|
||||
}
|
||||
|
||||
arrlen = (*env)->GetArrayLength(env, fcCompFontArray);
|
||||
for (i=0; i<arrlen; i++) {
|
||||
FcFontSet* fontset;
|
||||
int fn, j, fontCount, nfonts;
|
||||
unsigned int minGlyphs;
|
||||
FcChar8 **family, **styleStr, **fullname, **file;
|
||||
jarray fcFontArr = NULL;
|
||||
FcCharSet *unionCharset = NULL;
|
||||
FcCharSet *prevUnionCharset = NULL;
|
||||
|
||||
fcCompFontObj = (*env)->GetObjectArrayElement(env, fcCompFontArray, i);
|
||||
fcNameStr =
|
||||
(jstring)((*env)->GetObjectField(env, fcCompFontObj, fcNameID));
|
||||
fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0);
|
||||
if (fcName == NULL) {
|
||||
(*env)->DeleteLocalRef(env, fcCompFontObj);
|
||||
(*env)->DeleteLocalRef(env, fcNameStr);
|
||||
continue;
|
||||
}
|
||||
pattern = (*FcNameParse)((FcChar8 *)fcName);
|
||||
(*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);
|
||||
(*env)->DeleteLocalRef(env, fcNameStr);
|
||||
if (pattern == NULL) {
|
||||
closeFontConfig(libfontconfig, JNI_FALSE);
|
||||
if (locale) {
|
||||
(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* locale may not usually be necessary as fontconfig appears to apply
|
||||
* this anyway based on the user's environment. However we want
|
||||
* to use the value of the JDK startup locale so this should take
|
||||
* care of it.
|
||||
*/
|
||||
if (locale != NULL) {
|
||||
(*FcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale);
|
||||
}
|
||||
(*FcConfigSubstitute)(NULL, pattern, FcMatchPattern);
|
||||
(*FcDefaultSubstitute)(pattern);
|
||||
fontset = (*FcFontSort)(NULL, pattern, FcTrue, NULL, &result);
|
||||
if (fontset == NULL) {
|
||||
(*FcPatternDestroy)(pattern);
|
||||
closeFontConfig(libfontconfig, JNI_FALSE);
|
||||
if (locale) {
|
||||
(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* fontconfig returned us "nfonts". If we are just getting the
|
||||
* first font, we set nfont to zero. Otherwise we use "nfonts".
|
||||
* Next create separate C arrays of length nfonts for family file etc.
|
||||
* Inspect the returned fonts and the ones we like (adds enough glyphs)
|
||||
* are added to the arrays and we increment 'fontCount'.
|
||||
*/
|
||||
nfonts = fontset->nfont;
|
||||
family = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
|
||||
styleStr = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
|
||||
fullname = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
|
||||
file = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
|
||||
if (family == NULL || styleStr == NULL ||
|
||||
fullname == NULL || file == NULL) {
|
||||
if (family != NULL) {
|
||||
free(family);
|
||||
}
|
||||
if (styleStr != NULL) {
|
||||
free(styleStr);
|
||||
}
|
||||
if (fullname != NULL) {
|
||||
free(fullname);
|
||||
}
|
||||
if (file != NULL) {
|
||||
free(file);
|
||||
}
|
||||
(*FcPatternDestroy)(pattern);
|
||||
(*FcFontSetDestroy)(fontset);
|
||||
closeFontConfig(libfontconfig, JNI_FALSE);
|
||||
if (locale) {
|
||||
(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
|
||||
}
|
||||
return;
|
||||
}
|
||||
fontCount = 0;
|
||||
minGlyphs = 20;
|
||||
if (debugMinGlyphsStr != NULL) {
|
||||
int val = minGlyphs;
|
||||
sscanf(debugMinGlyphsStr, "%5d", &val);
|
||||
if (val >= 0 && val <= 65536) {
|
||||
minGlyphs = val;
|
||||
}
|
||||
}
|
||||
|
||||
for (j=0; j<nfonts; j++) {
|
||||
FcPattern *fontPattern = fontset->fonts[j];
|
||||
FcChar8 *fontformat;
|
||||
FcCharSet *charset = NULL;
|
||||
|
||||
fontformat = NULL;
|
||||
(*FcPatternGetString)(fontPattern, FC_FONTFORMAT, 0, &fontformat);
|
||||
/* We only want TrueType fonts but some Linuxes still depend
|
||||
* on Type 1 fonts for some Locale support, so we'll allow
|
||||
* them there.
|
||||
*/
|
||||
if (fontformat != NULL
|
||||
&& (strcmp((char*)fontformat, "TrueType") != 0)
|
||||
#if defined(__linux__) || defined(_AIX)
|
||||
&& (strcmp((char*)fontformat, "Type 1") != 0)
|
||||
&& (strcmp((char*)fontformat, "CFF") != 0)
|
||||
#endif
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
result = (*FcPatternGetCharSet)(fontPattern,
|
||||
FC_CHARSET, 0, &charset);
|
||||
if (result != FcResultMatch) {
|
||||
free(family);
|
||||
free(fullname);
|
||||
free(styleStr);
|
||||
free(file);
|
||||
(*FcPatternDestroy)(pattern);
|
||||
(*FcFontSetDestroy)(fontset);
|
||||
if (prevUnionCharset != NULL) {
|
||||
(*FcCharSetDestroy)(prevUnionCharset);
|
||||
}
|
||||
closeFontConfig(libfontconfig, JNI_FALSE);
|
||||
if (locale) {
|
||||
(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* We don't want 20 or 30 fonts, so once we hit 10 fonts,
|
||||
* then require that they really be adding value. Too many
|
||||
* adversely affects load time for minimal value-add.
|
||||
* This is still likely far more than we've had in the past.
|
||||
*/
|
||||
if (j==10) {
|
||||
minGlyphs = 50;
|
||||
}
|
||||
if (unionCharset == NULL) {
|
||||
unionCharset = charset;
|
||||
} else {
|
||||
if ((*FcCharSetSubtractCount)(charset, unionCharset)
|
||||
> minGlyphs) {
|
||||
unionCharset = (* FcCharSetUnion)(unionCharset, charset);
|
||||
if (prevUnionCharset != NULL) {
|
||||
(*FcCharSetDestroy)(prevUnionCharset);
|
||||
}
|
||||
prevUnionCharset = unionCharset;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
fontCount++; // found a font we will use.
|
||||
(*FcPatternGetString)(fontPattern, FC_FILE, 0, &file[j]);
|
||||
(*FcPatternGetString)(fontPattern, FC_FAMILY, 0, &family[j]);
|
||||
(*FcPatternGetString)(fontPattern, FC_STYLE, 0, &styleStr[j]);
|
||||
(*FcPatternGetString)(fontPattern, FC_FULLNAME, 0, &fullname[j]);
|
||||
if (!includeFallbacks) {
|
||||
break;
|
||||
}
|
||||
if (fontCount == 254) {
|
||||
break; // CompositeFont will only use up to 254 slots from here.
|
||||
}
|
||||
}
|
||||
|
||||
// Release last instance of CharSet union
|
||||
if (prevUnionCharset != NULL) {
|
||||
(*FcCharSetDestroy)(prevUnionCharset);
|
||||
}
|
||||
|
||||
/* Once we get here 'fontCount' is the number of returned fonts
|
||||
* we actually want to use, so we create 'fcFontArr' of that length.
|
||||
* The non-null entries of "family[]" etc are those fonts.
|
||||
* Then loop again over all nfonts adding just those non-null ones
|
||||
* to 'fcFontArr'. If its null (we didn't want the font)
|
||||
* then we don't enter the main body.
|
||||
* So we should never get more than 'fontCount' entries.
|
||||
*/
|
||||
if (includeFallbacks) {
|
||||
fcFontArr =
|
||||
(*env)->NewObjectArray(env, fontCount, fcFontClass, NULL);
|
||||
if (IS_NULL(fcFontArr)) {
|
||||
free(family);
|
||||
free(fullname);
|
||||
free(styleStr);
|
||||
free(file);
|
||||
(*FcPatternDestroy)(pattern);
|
||||
(*FcFontSetDestroy)(fontset);
|
||||
closeFontConfig(libfontconfig, JNI_FALSE);
|
||||
if (locale) {
|
||||
(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
|
||||
}
|
||||
return;
|
||||
}
|
||||
(*env)->SetObjectField(env,fcCompFontObj, fcAllFontsID, fcFontArr);
|
||||
}
|
||||
fn=0;
|
||||
|
||||
for (j=0;j<nfonts;j++) {
|
||||
if (family[j] != NULL) {
|
||||
jobject fcFont =
|
||||
(*env)->NewObject(env, fcFontClass, fcFontCons);
|
||||
if (IS_NULL(fcFont)) break;
|
||||
jstr = (*env)->NewStringUTF(env, (const char*)family[j]);
|
||||
if (IS_NULL(jstr)) break;
|
||||
(*env)->SetObjectField(env, fcFont, familyNameID, jstr);
|
||||
(*env)->DeleteLocalRef(env, jstr);
|
||||
if (file[j] != NULL) {
|
||||
jstr = (*env)->NewStringUTF(env, (const char*)file[j]);
|
||||
if (IS_NULL(jstr)) break;
|
||||
(*env)->SetObjectField(env, fcFont, fontFileID, jstr);
|
||||
(*env)->DeleteLocalRef(env, jstr);
|
||||
}
|
||||
if (styleStr[j] != NULL) {
|
||||
jstr = (*env)->NewStringUTF(env, (const char*)styleStr[j]);
|
||||
if (IS_NULL(jstr)) break;
|
||||
(*env)->SetObjectField(env, fcFont, styleNameID, jstr);
|
||||
(*env)->DeleteLocalRef(env, jstr);
|
||||
}
|
||||
if (fullname[j] != NULL) {
|
||||
jstr = (*env)->NewStringUTF(env, (const char*)fullname[j]);
|
||||
if (IS_NULL(jstr)) break;
|
||||
(*env)->SetObjectField(env, fcFont, fullNameID, jstr);
|
||||
(*env)->DeleteLocalRef(env, jstr);
|
||||
}
|
||||
if (fn==0) {
|
||||
(*env)->SetObjectField(env, fcCompFontObj,
|
||||
fcFirstFontID, fcFont);
|
||||
}
|
||||
if (includeFallbacks) {
|
||||
(*env)->SetObjectArrayElement(env, fcFontArr, fn++,fcFont);
|
||||
} else {
|
||||
(*env)->DeleteLocalRef(env, fcFont);
|
||||
break;
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, fcFont);
|
||||
}
|
||||
}
|
||||
if (includeFallbacks) {
|
||||
(*env)->DeleteLocalRef(env, fcFontArr);
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, fcCompFontObj);
|
||||
(*FcFontSetDestroy)(fontset);
|
||||
(*FcPatternDestroy)(pattern);
|
||||
free(family);
|
||||
free(styleStr);
|
||||
free(fullname);
|
||||
free(file);
|
||||
}
|
||||
|
||||
/* release resources and close the ".so" */
|
||||
|
||||
if (locale) {
|
||||
(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
|
||||
}
|
||||
closeFontConfig(libfontconfig, JNI_TRUE);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,15 @@
|
||||
#include <jvm.h>
|
||||
#include "gdefs.h"
|
||||
#include "sun_awt_PlatformGraphicsInfo.h"
|
||||
|
||||
#if defined(_WIN32) || defined(MACOSX)
|
||||
#define DISABLE_FONTCONFIG
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_FONTCONFIG
|
||||
#include "fontconfigmanager.h"
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
@@ -196,5 +205,8 @@ AWT_OnLoad(JavaVM *vm, void *reserved)
|
||||
JNIEXPORT jint JNICALL
|
||||
DEF_JNI_OnLoad(JavaVM *vm, void *reserved)
|
||||
{
|
||||
#ifndef DISABLE_FONTCONFIG
|
||||
openFontConfig();
|
||||
#endif
|
||||
return AWT_OnLoad(vm, reserved);
|
||||
}
|
||||
|
||||
884
src/java.desktop/unix/native/libawt/awt/fontconfigmanager.c
Normal file
884
src/java.desktop/unix/native/libawt/awt/fontconfigmanager.c
Normal file
@@ -0,0 +1,884 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include <jni_util.h>
|
||||
#include <jvm_md.h>
|
||||
#include <sizecalc.h>
|
||||
|
||||
#if defined(MACOSX)
|
||||
#define DISABLE_FONTCONFIG
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_FONTCONFIG
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <string.h>
|
||||
#endif /* __linux__ */
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <fontconfig/fontconfig.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "fontconfigmanager.h"
|
||||
|
||||
#ifndef HEADLESS
|
||||
#include <awt.h>
|
||||
#else
|
||||
/* locks ought to be included from awt.h */
|
||||
#define AWT_LOCK()
|
||||
#define AWT_UNLOCK()
|
||||
#endif /* !HEADLESS */
|
||||
|
||||
#define FONTCONFIG_DLL_VERSIONED VERSIONED_JNI_LIB_NAME("fontconfig", "1")
|
||||
#define FONTCONFIG_DLL JNI_LIB_NAME("fontconfig")
|
||||
|
||||
#if defined( __linux__)
|
||||
/* All the known interesting locations we have discovered on
|
||||
* various flavors of Linux
|
||||
*/
|
||||
static char *fullLinuxFontPath[] = {
|
||||
"/usr/X11R6/lib/X11/fonts/TrueType", /* RH 7.1+ */
|
||||
"/usr/X11R6/lib/X11/fonts/truetype", /* SuSE */
|
||||
"/usr/X11R6/lib/X11/fonts/tt",
|
||||
"/usr/X11R6/lib/X11/fonts/TTF",
|
||||
"/usr/X11R6/lib/X11/fonts/OTF", /* RH 9.0 (but empty!) */
|
||||
"/usr/share/fonts/ja/TrueType", /* RH 7.2+ */
|
||||
"/usr/share/fonts/truetype",
|
||||
"/usr/share/fonts/ko/TrueType", /* RH 9.0 */
|
||||
"/usr/share/fonts/zh_CN/TrueType", /* RH 9.0 */
|
||||
"/usr/share/fonts/zh_TW/TrueType", /* RH 9.0 */
|
||||
"/var/lib/defoma/x-ttcidfont-conf.d/dirs/TrueType", /* Debian */
|
||||
"/usr/X11R6/lib/X11/fonts/Type1",
|
||||
"/usr/share/fonts/default/Type1", /* RH 9.0 */
|
||||
NULL, /* terminates the list */
|
||||
};
|
||||
#elif defined(_AIX)
|
||||
static char *fullAixFontPath[] = {
|
||||
"/usr/lpp/X11/lib/X11/fonts/Type1", /* from X11.fnt.iso_T1 */
|
||||
"/usr/lpp/X11/lib/X11/fonts/TrueType", /* from X11.fnt.ucs.ttf */
|
||||
NULL, /* terminates the list */
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef FcConfig* (*FcInitLoadConfigFuncType)();
|
||||
typedef FcPattern* (*FcPatternBuildFuncType)(FcPattern *orig, ...);
|
||||
typedef FcObjectSet* (*FcObjectSetFuncType)(const char *first, ...);
|
||||
typedef FcFontSet* (*FcFontListFuncType)(FcConfig *config, FcPattern *p, FcObjectSet *os);
|
||||
typedef FcResult (*FcPatternGetBoolFuncType)(const FcPattern *p, const char *object, int n, FcBool *b);
|
||||
typedef FcResult (*FcPatternGetIntegerFuncType)(const FcPattern *p, const char *object, int n, int *i);
|
||||
typedef FcResult (*FcPatternGetStringFuncType)(const FcPattern *p, const char *object, int n, FcChar8 ** s);
|
||||
typedef FcChar8* (*FcStrDirnameFuncType)(const FcChar8 *file);
|
||||
typedef void (*FcPatternDestroyFuncType)(FcPattern *p);
|
||||
typedef void (*FcObjectSetDestroyFuncType)(FcObjectSet *os);
|
||||
typedef void (*FcFontSetDestroyFuncType)(FcFontSet *s);
|
||||
typedef FcPattern* (*FcNameParseFuncType)(const FcChar8 *name);
|
||||
typedef FcBool (*FcPatternAddStringFuncType)(FcPattern *p, const char *object, const FcChar8 *s);
|
||||
typedef FcBool (*FcPatternAddDoubleFuncType)(FcPattern *p, const char *object, double v);
|
||||
typedef void (*FcDefaultSubstituteFuncType)(FcPattern *p);
|
||||
typedef FcBool (*FcConfigSubstituteFuncType)(FcConfig *config, FcPattern *p, FcMatchKind kind);
|
||||
typedef FcPattern* (*FcFontMatchFuncType)(FcConfig *config, FcPattern *p, FcResult *result);
|
||||
typedef FcFontSet* (*FcFontSetCreateFuncType)();
|
||||
typedef FcBool (*FcFontSetAddFuncType)(FcFontSet *s, FcPattern *font);
|
||||
typedef FcResult (*FcPatternGetCharSetFuncType)(FcPattern *p, const char *object, int n, FcCharSet **c);
|
||||
typedef FcFontSet* (*FcFontSortFuncType)(FcConfig *config, FcPattern *p, FcBool trim, FcCharSet **csp, FcResult *result);
|
||||
typedef FcCharSet* (*FcCharSetUnionFuncType)(const FcCharSet *a, const FcCharSet *b);
|
||||
typedef FcCharSet* (*FcCharSetDestroyFuncType)(FcCharSet *fcs);
|
||||
typedef FcChar32 (*FcCharSetSubtractCountFuncType)(const FcCharSet *a, const FcCharSet *b);
|
||||
typedef int (*FcGetVersionFuncType)();
|
||||
typedef FcStrList* (*FcConfigGetCacheDirsFuncType)(FcConfig *config);
|
||||
typedef FcChar8* (*FcStrListNextFuncType)(FcStrList *list);
|
||||
typedef FcChar8* (*FcStrListDoneFuncType)(FcStrList *list);
|
||||
typedef FcChar8* (*FcPatternFormatFuncType)(FcPattern *pat, const FcChar8 *format);
|
||||
typedef void (*FcStrFreeFuncType)(FcChar8 *str);
|
||||
|
||||
static FcInitLoadConfigFuncType fcInitLoadConfig;
|
||||
static FcPatternBuildFuncType fcPatternBuild;
|
||||
static FcObjectSetFuncType fcObjectSetBuild;
|
||||
static FcFontListFuncType fcFontList;
|
||||
static FcStrDirnameFuncType fcStrDirname;
|
||||
static FcObjectSetDestroyFuncType fcObjectSetDestroy;
|
||||
static FcPatternGetBoolFuncType fcPatternGetBool;
|
||||
static FcPatternGetIntegerFuncType fcPatternGetInteger;
|
||||
static FcNameParseFuncType fcNameParse;
|
||||
static FcPatternAddStringFuncType fcPatternAddString;
|
||||
static FcPatternAddDoubleFuncType fcPatternAddDouble;
|
||||
static FcConfigSubstituteFuncType fcConfigSubstitute;
|
||||
static FcDefaultSubstituteFuncType fcDefaultSubstitute;
|
||||
static FcFontMatchFuncType fcFontMatch;
|
||||
static FcPatternGetStringFuncType fcPatternGetString;
|
||||
static FcPatternDestroyFuncType fcPatternDestroy;
|
||||
static FcPatternGetCharSetFuncType fcPatternGetCharSet;
|
||||
static FcFontSortFuncType fcFontSort;
|
||||
static FcFontSetDestroyFuncType fcFontSetDestroy;
|
||||
static FcCharSetUnionFuncType fcCharSetUnion;
|
||||
static FcCharSetDestroyFuncType fcCharSetDestroy;
|
||||
static FcCharSetSubtractCountFuncType fcCharSetSubtractCount;
|
||||
static FcGetVersionFuncType fcGetVersion;
|
||||
static FcConfigGetCacheDirsFuncType fcConfigGetCacheDirs;
|
||||
static FcStrListNextFuncType fcStrListNext;
|
||||
static FcStrListDoneFuncType fcStrListDone;
|
||||
static FcPatternFormatFuncType fcPatternFormat;
|
||||
static FcStrFreeFuncType fcStrFree;
|
||||
|
||||
static void *libfontconfig = NULL;
|
||||
|
||||
static void closeFontConfig() {
|
||||
|
||||
if (libfontconfig != NULL) {
|
||||
dlclose(libfontconfig);
|
||||
libfontconfig = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void openFontConfig() {
|
||||
|
||||
char *homeEnv;
|
||||
static char *homeEnvStr = "HOME="; /* must be static */
|
||||
|
||||
/* Private workaround to not use fontconfig library.
|
||||
* May be useful during testing/debugging
|
||||
*/
|
||||
char *useFC = getenv("USE_J2D_FONTCONFIG");
|
||||
if (useFC != NULL && !strcmp(useFC, "no")) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(_AIX)
|
||||
/* On AIX, fontconfig is not a standard package supported by IBM.
|
||||
* instead it has to be installed from the "AIX Toolbox for Linux Applications"
|
||||
* site http://www-03.ibm.com/systems/power/software/aix/linux/toolbox/alpha.html
|
||||
* and will be installed under /opt/freeware/lib/libfontconfig.a.
|
||||
* Notice that the archive contains the real 32- and 64-bit shared libraries.
|
||||
* We first try to load 'libfontconfig.so' from the default library path in the
|
||||
* case the user has installed a private version of the library and if that
|
||||
* doesn't succeed, we try the version from /opt/freeware/lib/libfontconfig.a
|
||||
*/
|
||||
libfontconfig = dlopen("libfontconfig.so", RTLD_LOCAL|RTLD_LAZY);
|
||||
if (libfontconfig == NULL) {
|
||||
libfontconfig = dlopen("/opt/freeware/lib/libfontconfig.a(libfontconfig.so.1)", RTLD_MEMBER|RTLD_LOCAL|RTLD_LAZY);
|
||||
if (libfontconfig == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* 64 bit sparc should pick up the right version from the lib path.
|
||||
* New features may be added to libfontconfig, this is expected to
|
||||
* be compatible with old features, but we may need to start
|
||||
* distinguishing the library version, to know whether to expect
|
||||
* certain symbols - and functionality - to be available.
|
||||
* Also add explicit search for .so.1 in case .so symlink doesn't exist.
|
||||
*/
|
||||
libfontconfig = dlopen(FONTCONFIG_DLL_VERSIONED, RTLD_LOCAL|RTLD_LAZY);
|
||||
if (libfontconfig == NULL) {
|
||||
libfontconfig = dlopen(FONTCONFIG_DLL, RTLD_LOCAL|RTLD_LAZY);
|
||||
if (libfontconfig == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Version 1.0 of libfontconfig crashes if HOME isn't defined in
|
||||
* the environment. This should generally never happen, but we can't
|
||||
* control it, and can't control the version of fontconfig, so iff
|
||||
* its not defined we set it to an empty value which is sufficient
|
||||
* to prevent a crash. I considered unsetting it before exit, but
|
||||
* it doesn't appear to work on Solaris, so I will leave it set.
|
||||
*/
|
||||
homeEnv = getenv("HOME");
|
||||
if (homeEnv == NULL) {
|
||||
putenv(homeEnvStr);
|
||||
}
|
||||
|
||||
fcPatternBuild = (FcPatternBuildFuncType)dlsym(libfontconfig, "FcPatternBuild");
|
||||
fcObjectSetBuild = (FcObjectSetFuncType)dlsym(libfontconfig, "FcObjectSetBuild");
|
||||
fcFontList = (FcFontListFuncType)dlsym(libfontconfig, "FcFontList");
|
||||
fcStrDirname = (FcStrDirnameFuncType)dlsym(libfontconfig, "FcStrDirname");
|
||||
fcObjectSetDestroy = (FcObjectSetDestroyFuncType)dlsym(libfontconfig, "FcObjectSetDestroy");
|
||||
fcPatternGetBool = (FcPatternGetBoolFuncType) dlsym(libfontconfig, "FcPatternGetBool");
|
||||
fcPatternGetInteger = (FcPatternGetIntegerFuncType)dlsym(libfontconfig, "FcPatternGetInteger");
|
||||
fcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse");
|
||||
fcPatternAddString = (FcPatternAddStringFuncType)dlsym(libfontconfig, "FcPatternAddString");
|
||||
fcPatternAddDouble = (FcPatternAddDoubleFuncType)dlsym(libfontconfig, "FcPatternAddDouble");
|
||||
fcConfigSubstitute = (FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute");
|
||||
fcDefaultSubstitute = (FcDefaultSubstituteFuncType)dlsym(libfontconfig, "FcDefaultSubstitute");
|
||||
fcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch");
|
||||
fcPatternGetString = (FcPatternGetStringFuncType)dlsym(libfontconfig, "FcPatternGetString");
|
||||
fcPatternDestroy = (FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");
|
||||
fcPatternGetCharSet = (FcPatternGetCharSetFuncType)dlsym(libfontconfig, "FcPatternGetCharSet");
|
||||
fcFontSort = (FcFontSortFuncType)dlsym(libfontconfig, "FcFontSort");
|
||||
fcFontSetDestroy = (FcFontSetDestroyFuncType)dlsym(libfontconfig, "FcFontSetDestroy");
|
||||
fcCharSetUnion = (FcCharSetUnionFuncType)dlsym(libfontconfig, "FcCharSetUnion");
|
||||
fcCharSetDestroy = (FcCharSetDestroyFuncType)dlsym(libfontconfig, "FcCharSetDestroy");
|
||||
fcCharSetSubtractCount = (FcCharSetSubtractCountFuncType)dlsym(libfontconfig, "FcCharSetSubtractCount");
|
||||
fcGetVersion = (FcGetVersionFuncType)dlsym(libfontconfig, "FcGetVersion");
|
||||
fcConfigGetCacheDirs = (FcConfigGetCacheDirsFuncType)dlsym(libfontconfig, "FcConfigGetCacheDirs");
|
||||
fcStrListNext = (FcStrListNextFuncType)dlsym(libfontconfig, "FcStrListNext");
|
||||
fcStrListDone = (FcStrListDoneFuncType)dlsym(libfontconfig, "FcStrListDone");
|
||||
fcPatternFormat = (FcPatternFormatFuncType)dlsym(libfontconfig, "FcPatternFormat");
|
||||
fcStrFree = (FcStrFreeFuncType)dlsym(libfontconfig, "FcStrFree");
|
||||
|
||||
if (fcPatternBuild == NULL || fcObjectSetBuild == NULL || fcFontList == NULL || fcStrDirname == NULL ||
|
||||
fcObjectSetDestroy == NULL || fcPatternGetBool == NULL || fcPatternGetInteger == NULL || fcNameParse == NULL ||
|
||||
fcPatternAddString == NULL || fcConfigSubstitute == NULL || fcDefaultSubstitute == NULL || fcFontMatch == NULL ||
|
||||
fcPatternGetString == NULL || fcPatternDestroy == NULL || fcPatternGetCharSet == NULL || fcFontSort == NULL ||
|
||||
fcFontSetDestroy == NULL || fcCharSetUnion == NULL || fcCharSetDestroy == NULL || fcCharSetSubtractCount == NULL ||
|
||||
fcGetVersion == NULL || fcConfigGetCacheDirs == NULL || fcStrListNext == NULL || fcStrListDone == NULL ||
|
||||
fcPatternAddDouble == NULL || fcPatternFormat == NULL || fcStrFree == NULL) {
|
||||
closeFontConfig();
|
||||
}
|
||||
}
|
||||
|
||||
static bool usingFontConfig() {
|
||||
return (libfontconfig != NULL) ? true : false;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JNI_OnUnload(JavaVM *vm, void *reserved) {
|
||||
closeFontConfig();
|
||||
}
|
||||
|
||||
/* These are copied from sun.awt.SunHints.
|
||||
* Consider initialising them as ints using JNI for more robustness.
|
||||
*/
|
||||
#define TEXT_AA_OFF 1
|
||||
#define TEXT_AA_ON 2
|
||||
#define TEXT_AA_LCD_HRGB 4
|
||||
#define TEXT_AA_LCD_HBGR 5
|
||||
#define TEXT_AA_LCD_VRGB 6
|
||||
#define TEXT_AA_LCD_VBGR 7
|
||||
|
||||
static void setRenderingFontHintsField(FcPattern* matchPattern, const char* property, int* value) {
|
||||
if (FcResultMatch != (*fcPatternGetBool)(matchPattern, property, 0, value)) {
|
||||
*value = -1;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT int setupRenderingFontHints
|
||||
(const char* fcName, const char* locale, double size, RenderingFontHints *renderingFontHints) {
|
||||
|
||||
FcPattern *pattern, *matchPattern;
|
||||
FcResult result;
|
||||
|
||||
if (fcName == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pattern = (*fcNameParse)((FcChar8 *)fcName);
|
||||
if (locale != NULL) {
|
||||
(*fcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale);
|
||||
}
|
||||
if (size != 0) {
|
||||
(*fcPatternAddDouble)(pattern, FC_SIZE, size);
|
||||
}
|
||||
(*fcConfigSubstitute)(NULL, pattern, FcMatchPattern);
|
||||
(*fcDefaultSubstitute)(pattern);
|
||||
matchPattern = (*fcFontMatch)(NULL, pattern, &result);
|
||||
/* Perhaps should call FcFontRenderPrepare() here as some pattern
|
||||
* elements might change as a result of that call, but I'm not seeing
|
||||
* any difference in testing.
|
||||
*/
|
||||
if (matchPattern) {
|
||||
// Extract values from result
|
||||
setRenderingFontHintsField(matchPattern, FC_HINTING, &renderingFontHints->fcHinting);
|
||||
setRenderingFontHintsField(matchPattern, FC_HINT_STYLE, &renderingFontHints->fcHintStyle);
|
||||
setRenderingFontHintsField(matchPattern, FC_ANTIALIAS, &renderingFontHints->fcAntialias);
|
||||
setRenderingFontHintsField(matchPattern, FC_AUTOHINT, &renderingFontHints->fcAutohint);
|
||||
setRenderingFontHintsField(matchPattern, FC_LCD_FILTER, &renderingFontHints->fcRGBA);
|
||||
setRenderingFontHintsField(matchPattern, FC_RGBA, &renderingFontHints->fcLCDFilter);
|
||||
|
||||
(*fcPatternDestroy)(matchPattern);
|
||||
}
|
||||
(*fcPatternDestroy)(pattern);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
JNIEXPORT char **getFontConfigLocations() {
|
||||
|
||||
#ifdef DISABLE_FONTCONFIG
|
||||
return NULL;
|
||||
#else
|
||||
if (usingFontConfig() == false) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char **fontdirs;
|
||||
int numdirs = 0;
|
||||
|
||||
FcPattern *pattern;
|
||||
FcObjectSet *objset;
|
||||
FcFontSet *fontSet;
|
||||
int i, f, found;
|
||||
|
||||
/* Make calls into the fontconfig library to build a search for
|
||||
* outline fonts, and to get the set of full file paths from the matches.
|
||||
* This set is returned from the call to fcFontList(..)
|
||||
* We allocate an array of char* pointers sufficient to hold all
|
||||
* the matches + 1 extra which ensures there will be a NULL after all
|
||||
* valid entries.
|
||||
* We call fcStrDirname strip the file name from the path, and
|
||||
* check if we have yet seen this directory. If not we add a pointer to
|
||||
* it into our array of char*. Note that fcStrDirname returns newly
|
||||
* allocated storage so we can use this in the return char** value.
|
||||
* Finally we clean up, freeing allocated resources, and return the
|
||||
* array of unique directories.
|
||||
*/
|
||||
pattern = (*fcPatternBuild)(NULL, FC_OUTLINE, FcTypeBool, FcTrue, NULL);
|
||||
objset = (*fcObjectSetBuild)(FC_FILE, NULL);
|
||||
fontSet = (*fcFontList)(NULL, pattern, objset);
|
||||
if (fontSet == NULL) {
|
||||
/* fcFontList() may return NULL if fonts are not installed. */
|
||||
fontdirs = NULL;
|
||||
} else {
|
||||
fontdirs = (char**)calloc(fontSet->nfont+1, sizeof(char*));
|
||||
if (fontdirs == NULL) {
|
||||
(*fcFontSetDestroy)(fontSet);
|
||||
goto cleanup;
|
||||
}
|
||||
for (f=0; f < fontSet->nfont; f++) {
|
||||
FcChar8 *file;
|
||||
FcChar8 *dir;
|
||||
if ((*fcPatternGetString)(fontSet->fonts[f], FC_FILE, 0, &file) == FcResultMatch) {
|
||||
dir = (*fcStrDirname)(file);
|
||||
found = 0;
|
||||
for (i=0;i<numdirs; i++) {
|
||||
if (strcmp(fontdirs[i], (char*)dir) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
fontdirs[numdirs++] = (char*)dir;
|
||||
} else {
|
||||
free((char*)dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Free fontset if one was returned */
|
||||
(*fcFontSetDestroy)(fontSet);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/* Free memory and close the ".so" */
|
||||
(*fcObjectSetDestroy)(objset);
|
||||
(*fcPatternDestroy)(pattern);
|
||||
return fontdirs;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_font_FontConfigManager_getFontConfigVersion
|
||||
(JNIEnv *env, jclass obj) {
|
||||
|
||||
#ifdef DISABLE_FONTCONFIG
|
||||
return 0;
|
||||
#else
|
||||
if (usingFontConfig() == false) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (*fcGetVersion)();
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_font_FontConfigManager_setupFontConfigFonts
|
||||
(JNIEnv *env, jclass obj, jstring localeStr, jobject fcInfoObj,
|
||||
jobjectArray fcCompFontArray, jboolean includeFallbacks) {
|
||||
|
||||
#ifdef DISABLE_FONTCONFIG
|
||||
return;
|
||||
#else
|
||||
if (usingFontConfig() == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
int i, arrlen;
|
||||
jobject fcCompFontObj;
|
||||
jstring fcNameStr, jstr;
|
||||
const char *locale, *fcName;
|
||||
FcPattern *pattern;
|
||||
FcResult result;
|
||||
jfieldID fcNameID, fcFirstFontID, fcAllFontsID, fcVersionID, fcCacheDirsID;
|
||||
jfieldID familyNameID, styleNameID, fullNameID, fontFileID;
|
||||
jmethodID fcFontCons;
|
||||
char* debugMinGlyphsStr = getenv("J2D_DEBUG_MIN_GLYPHS");
|
||||
jclass fcInfoClass;
|
||||
jclass fcCompFontClass;
|
||||
jclass fcFontClass;
|
||||
|
||||
CHECK_NULL(fcInfoObj);
|
||||
CHECK_NULL(fcCompFontArray);
|
||||
|
||||
CHECK_NULL(fcInfoClass = (*env)->FindClass(env, "sun/font/FontConfigManager$FontConfigInfo"));
|
||||
CHECK_NULL(fcCompFontClass = (*env)->FindClass(env, "sun/font/FontConfigManager$FcCompFont"));
|
||||
CHECK_NULL(fcFontClass = (*env)->FindClass(env, "sun/font/FontConfigManager$FontConfigFont"));
|
||||
CHECK_NULL(fcVersionID = (*env)->GetFieldID(env, fcInfoClass, "fcVersion", "I"));
|
||||
CHECK_NULL(fcCacheDirsID = (*env)->GetFieldID(env, fcInfoClass, "cacheDirs", "[Ljava/lang/String;"));
|
||||
CHECK_NULL(fcNameID = (*env)->GetFieldID(env, fcCompFontClass, "fcName", "Ljava/lang/String;"));
|
||||
CHECK_NULL(fcFirstFontID = (*env)->GetFieldID(env, fcCompFontClass, "firstFont", "Lsun/font/FontConfigManager$FontConfigFont;"));
|
||||
CHECK_NULL(fcAllFontsID = (*env)->GetFieldID(env, fcCompFontClass, "allFonts", "[Lsun/font/FontConfigManager$FontConfigFont;"));
|
||||
CHECK_NULL(fcFontCons = (*env)->GetMethodID(env, fcFontClass, "<init>", "()V"));
|
||||
CHECK_NULL(familyNameID = (*env)->GetFieldID(env, fcFontClass, "familyName", "Ljava/lang/String;"));
|
||||
CHECK_NULL(styleNameID = (*env)->GetFieldID(env, fcFontClass, "styleStr", "Ljava/lang/String;"));
|
||||
CHECK_NULL(fullNameID = (*env)->GetFieldID(env, fcFontClass, "fullName", "Ljava/lang/String;"));
|
||||
CHECK_NULL(fontFileID = (*env)->GetFieldID(env, fcFontClass, "fontFile", "Ljava/lang/String;"));
|
||||
|
||||
(*env)->SetIntField(env, fcInfoObj, fcVersionID, (*fcGetVersion)());
|
||||
|
||||
/* Optionally get the cache dir locations. This isn't
|
||||
* available until v 2.4.x, but this is OK since on those later versions
|
||||
* we can check the time stamps on the cache dirs to see if we
|
||||
* are out of date. There are a couple of assumptions here. First
|
||||
* that the time stamp on the directory changes when the contents are
|
||||
* updated. Secondly that the locations don't change. The latter is
|
||||
* most likely if a new version of fontconfig is installed, but we also
|
||||
* invalidate the cache if we detect that. Arguably even that is "rare",
|
||||
* and most likely is tied to an OS upgrade which gets a new file anyway.
|
||||
*/
|
||||
if (fcStrListNext != NULL && fcStrListDone != NULL &&
|
||||
fcConfigGetCacheDirs != NULL) {
|
||||
|
||||
FcStrList* cacheDirs;
|
||||
FcChar8* cacheDir;
|
||||
int cnt = 0;
|
||||
jobject cacheDirArray = (*env)->GetObjectField(env, fcInfoObj, fcCacheDirsID);
|
||||
int max = (*env)->GetArrayLength(env, cacheDirArray);
|
||||
|
||||
cacheDirs = (*fcConfigGetCacheDirs)(NULL);
|
||||
if (cacheDirs != NULL) {
|
||||
while ((cnt < max) && (cacheDir = (*fcStrListNext)(cacheDirs))) {
|
||||
jstr = (*env)->NewStringUTF(env, (const char*)cacheDir);
|
||||
if (IS_NULL(jstr)) {
|
||||
(*fcStrListDone)(cacheDirs);
|
||||
return;
|
||||
}
|
||||
(*env)->SetObjectArrayElement(env, cacheDirArray, cnt++, jstr);
|
||||
(*env)->DeleteLocalRef(env, jstr);
|
||||
}
|
||||
(*fcStrListDone)(cacheDirs);
|
||||
}
|
||||
}
|
||||
|
||||
locale = (*env)->GetStringUTFChars(env, localeStr, 0);
|
||||
if (locale == NULL) {
|
||||
(*env)->ExceptionClear(env);
|
||||
JNU_ThrowOutOfMemoryError(env, "Could not create locale");
|
||||
return;
|
||||
}
|
||||
|
||||
arrlen = (*env)->GetArrayLength(env, fcCompFontArray);
|
||||
for (i=0; i<arrlen; i++) {
|
||||
FcFontSet* fontset;
|
||||
int fn, j, fontCount, nfonts;
|
||||
unsigned int minGlyphs;
|
||||
FcChar8 **family, **styleStr, **fullname, **file;
|
||||
jarray fcFontArr = NULL;
|
||||
FcCharSet *unionCharset = NULL;
|
||||
FcCharSet *prevUnionCharset = NULL;
|
||||
|
||||
fcCompFontObj = (*env)->GetObjectArrayElement(env, fcCompFontArray, i);
|
||||
fcNameStr =
|
||||
(jstring)((*env)->GetObjectField(env, fcCompFontObj, fcNameID));
|
||||
fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0);
|
||||
if (fcName == NULL) {
|
||||
(*env)->DeleteLocalRef(env, fcCompFontObj);
|
||||
(*env)->DeleteLocalRef(env, fcNameStr);
|
||||
continue;
|
||||
}
|
||||
pattern = (*fcNameParse)((FcChar8 *)fcName);
|
||||
(*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);
|
||||
(*env)->DeleteLocalRef(env, fcNameStr);
|
||||
if (pattern == NULL) {
|
||||
if (locale) {
|
||||
(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* locale may not usually be necessary as fontconfig appears to apply
|
||||
* this anyway based on the user's environment. However we want
|
||||
* to use the value of the JDK startup locale so this should take
|
||||
* care of it.
|
||||
*/
|
||||
if (locale != NULL) {
|
||||
(*fcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale);
|
||||
}
|
||||
(*fcConfigSubstitute)(NULL, pattern, FcMatchPattern);
|
||||
(*fcDefaultSubstitute)(pattern);
|
||||
fontset = (*fcFontSort)(NULL, pattern, FcTrue, NULL, &result);
|
||||
if (fontset == NULL) {
|
||||
(*fcPatternDestroy)(pattern);
|
||||
if (locale) {
|
||||
(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* fontconfig returned us "nfonts". If we are just getting the
|
||||
* first font, we set nfont to zero. Otherwise we use "nfonts".
|
||||
* Next create separate C arrays of length nfonts for family file etc.
|
||||
* Inspect the returned fonts and the ones we like (adds enough glyphs)
|
||||
* are added to the arrays and we increment 'fontCount'.
|
||||
*/
|
||||
nfonts = fontset->nfont;
|
||||
family = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
|
||||
styleStr = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
|
||||
fullname = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
|
||||
file = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
|
||||
if (family == NULL || styleStr == NULL ||
|
||||
fullname == NULL || file == NULL) {
|
||||
if (family != NULL) {
|
||||
free(family);
|
||||
}
|
||||
if (styleStr != NULL) {
|
||||
free(styleStr);
|
||||
}
|
||||
if (fullname != NULL) {
|
||||
free(fullname);
|
||||
}
|
||||
if (file != NULL) {
|
||||
free(file);
|
||||
}
|
||||
(*fcPatternDestroy)(pattern);
|
||||
(*fcFontSetDestroy)(fontset);
|
||||
if (locale) {
|
||||
(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
|
||||
}
|
||||
return;
|
||||
}
|
||||
fontCount = 0;
|
||||
minGlyphs = 20;
|
||||
if (debugMinGlyphsStr != NULL) {
|
||||
int val = minGlyphs;
|
||||
sscanf(debugMinGlyphsStr, "%5d", &val);
|
||||
if (val >= 0 && val <= 65536) {
|
||||
minGlyphs = val;
|
||||
}
|
||||
}
|
||||
|
||||
for (j=0; j<nfonts; j++) {
|
||||
FcPattern *fontPattern = fontset->fonts[j];
|
||||
FcChar8 *fontformat;
|
||||
FcCharSet *charset = NULL;
|
||||
|
||||
fontformat = NULL;
|
||||
(*fcPatternGetString)(fontPattern, FC_FONTFORMAT, 0, &fontformat);
|
||||
/* We only want TrueType fonts but some Linuxes still depend
|
||||
* on Type 1 fonts for some Locale support, so we'll allow
|
||||
* them there.
|
||||
*/
|
||||
if (fontformat != NULL
|
||||
&& (strcmp((char*)fontformat, "TrueType") != 0)
|
||||
#if defined(__linux__) || defined(_AIX)
|
||||
&& (strcmp((char*)fontformat, "Type 1") != 0)
|
||||
&& (strcmp((char*)fontformat, "CFF") != 0)
|
||||
#endif
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
result = (*fcPatternGetCharSet)(fontPattern, FC_CHARSET, 0, &charset);
|
||||
if (result != FcResultMatch) {
|
||||
free(family);
|
||||
free(fullname);
|
||||
free(styleStr);
|
||||
free(file);
|
||||
(*fcPatternDestroy)(pattern);
|
||||
(*fcFontSetDestroy)(fontset);
|
||||
if (prevUnionCharset != NULL) {
|
||||
(*fcCharSetDestroy)(prevUnionCharset);
|
||||
}
|
||||
if (locale) {
|
||||
(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* We don't want 20 or 30 fonts, so once we hit 10 fonts,
|
||||
* then require that they really be adding value. Too many
|
||||
* adversely affects load time for minimal value-add.
|
||||
* This is still likely far more than we've had in the past.
|
||||
*/
|
||||
if (j==10) {
|
||||
minGlyphs = 50;
|
||||
}
|
||||
if (unionCharset == NULL) {
|
||||
unionCharset = charset;
|
||||
} else {
|
||||
if ((*fcCharSetSubtractCount)(charset, unionCharset)
|
||||
> minGlyphs) {
|
||||
unionCharset = (* fcCharSetUnion)(unionCharset, charset);
|
||||
if (prevUnionCharset != NULL) {
|
||||
(*fcCharSetDestroy)(prevUnionCharset);
|
||||
}
|
||||
prevUnionCharset = unionCharset;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
fontCount++; // found a font we will use.
|
||||
(*fcPatternGetString)(fontPattern, FC_FILE, 0, &file[j]);
|
||||
(*fcPatternGetString)(fontPattern, FC_FAMILY, 0, &family[j]);
|
||||
(*fcPatternGetString)(fontPattern, FC_STYLE, 0, &styleStr[j]);
|
||||
(*fcPatternGetString)(fontPattern, FC_FULLNAME, 0, &fullname[j]);
|
||||
if (!includeFallbacks) {
|
||||
break;
|
||||
}
|
||||
if (fontCount == 254) {
|
||||
break; // CompositeFont will only use up to 254 slots from here.
|
||||
}
|
||||
}
|
||||
|
||||
// Release last instance of CharSet union
|
||||
if (prevUnionCharset != NULL) {
|
||||
(*fcCharSetDestroy)(prevUnionCharset);
|
||||
}
|
||||
|
||||
/* Once we get here 'fontCount' is the number of returned fonts
|
||||
* we actually want to use, so we create 'fcFontArr' of that length.
|
||||
* The non-null entries of "family[]" etc are those fonts.
|
||||
* Then loop again over all nfonts adding just those non-null ones
|
||||
* to 'fcFontArr'. If its null (we didn't want the font)
|
||||
* then we don't enter the main body.
|
||||
* So we should never get more than 'fontCount' entries.
|
||||
*/
|
||||
if (includeFallbacks) {
|
||||
fcFontArr =
|
||||
(*env)->NewObjectArray(env, fontCount, fcFontClass, NULL);
|
||||
if (IS_NULL(fcFontArr)) {
|
||||
free(family);
|
||||
free(fullname);
|
||||
free(styleStr);
|
||||
free(file);
|
||||
(*fcPatternDestroy)(pattern);
|
||||
(*fcFontSetDestroy)(fontset);
|
||||
if (locale) {
|
||||
(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
|
||||
}
|
||||
return;
|
||||
}
|
||||
(*env)->SetObjectField(env,fcCompFontObj, fcAllFontsID, fcFontArr);
|
||||
}
|
||||
fn=0;
|
||||
|
||||
for (j=0;j<nfonts;j++) {
|
||||
if (family[j] != NULL) {
|
||||
jobject fcFont = (*env)->NewObject(env, fcFontClass, fcFontCons);
|
||||
if (IS_NULL(fcFont)) break;
|
||||
jstr = (*env)->NewStringUTF(env, (const char*)family[j]);
|
||||
if (IS_NULL(jstr)) break;
|
||||
(*env)->SetObjectField(env, fcFont, familyNameID, jstr);
|
||||
(*env)->DeleteLocalRef(env, jstr);
|
||||
if (file[j] != NULL) {
|
||||
jstr = (*env)->NewStringUTF(env, (const char*)file[j]);
|
||||
if (IS_NULL(jstr)) break;
|
||||
(*env)->SetObjectField(env, fcFont, fontFileID, jstr);
|
||||
(*env)->DeleteLocalRef(env, jstr);
|
||||
}
|
||||
if (styleStr[j] != NULL) {
|
||||
jstr = (*env)->NewStringUTF(env, (const char*)styleStr[j]);
|
||||
if (IS_NULL(jstr)) break;
|
||||
(*env)->SetObjectField(env, fcFont, styleNameID, jstr);
|
||||
(*env)->DeleteLocalRef(env, jstr);
|
||||
}
|
||||
if (fullname[j] != NULL) {
|
||||
jstr = (*env)->NewStringUTF(env, (const char*)fullname[j]);
|
||||
if (IS_NULL(jstr)) break;
|
||||
(*env)->SetObjectField(env, fcFont, fullNameID, jstr);
|
||||
(*env)->DeleteLocalRef(env, jstr);
|
||||
}
|
||||
if (fn==0) {
|
||||
(*env)->SetObjectField(env, fcCompFontObj,
|
||||
fcFirstFontID, fcFont);
|
||||
}
|
||||
if (includeFallbacks) {
|
||||
(*env)->SetObjectArrayElement(env, fcFontArr, fn++,fcFont);
|
||||
} else {
|
||||
(*env)->DeleteLocalRef(env, fcFont);
|
||||
break;
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, fcFont);
|
||||
}
|
||||
}
|
||||
if (includeFallbacks) {
|
||||
(*env)->DeleteLocalRef(env, fcFontArr);
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, fcCompFontObj);
|
||||
(*fcFontSetDestroy)(fontset);
|
||||
(*fcPatternDestroy)(pattern);
|
||||
free(family);
|
||||
free(styleStr);
|
||||
free(fullname);
|
||||
free(file);
|
||||
}
|
||||
|
||||
/* release resources and close the ".so" */
|
||||
|
||||
if (locale) {
|
||||
(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_font_FontConfigManager_getFontConfigAASettings
|
||||
(JNIEnv *env, jclass obj, jstring fcNameStr, jstring localeStr) {
|
||||
|
||||
#ifdef DISABLE_FONTCONFIG
|
||||
return -1;
|
||||
#else
|
||||
if (usingFontConfig() == false) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rgba = 0;
|
||||
const char *locale=NULL, *fcName=NULL;
|
||||
|
||||
if (fcNameStr == NULL || localeStr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0);
|
||||
locale = (*env)->GetStringUTFChars(env, localeStr, 0);
|
||||
int status = 0;
|
||||
RenderingFontHints renderingFontHints;
|
||||
if (fcName && locale) {
|
||||
status = setupRenderingFontHints(fcName, locale, 0, &renderingFontHints);
|
||||
} else {
|
||||
status = -1;
|
||||
}
|
||||
|
||||
if (locale) {
|
||||
(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
|
||||
}
|
||||
if (fcName) {
|
||||
(*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);
|
||||
}
|
||||
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (renderingFontHints.fcAntialias == FcFalse) {
|
||||
return TEXT_AA_OFF;
|
||||
} else if (renderingFontHints.fcRGBA <= FC_RGBA_UNKNOWN || renderingFontHints.fcRGBA >= FC_RGBA_NONE) {
|
||||
return TEXT_AA_ON;
|
||||
} else {
|
||||
switch (renderingFontHints.fcRGBA) {
|
||||
case FC_RGBA_RGB : return TEXT_AA_LCD_HRGB;
|
||||
case FC_RGBA_BGR : return TEXT_AA_LCD_HBGR;
|
||||
case FC_RGBA_VRGB : return TEXT_AA_LCD_VRGB;
|
||||
case FC_RGBA_VBGR : return TEXT_AA_LCD_VBGR;
|
||||
default : return TEXT_AA_LCD_HRGB; // should not get here.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_sun_font_FontConfigManager_getFontProperty
|
||||
(JNIEnv *env, jclass obj, jstring query, jstring property) {
|
||||
|
||||
#ifdef DISABLE_FONTCONFIG
|
||||
return NULL;
|
||||
#else
|
||||
if (usingFontConfig() == false) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *queryPtr = NULL;
|
||||
const char *propertyPtr = NULL;
|
||||
FcChar8 *fontFamily = NULL;
|
||||
FcChar8 *fontPath = NULL;
|
||||
jstring res = NULL;
|
||||
|
||||
queryPtr = (*env)->GetStringUTFChars(env, query, 0);
|
||||
propertyPtr = (*env)->GetStringUTFChars(env, property, 0);
|
||||
if (queryPtr == NULL || propertyPtr == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
FcPattern *pattern = (*fcNameParse)((FcChar8 *) queryPtr);
|
||||
if (pattern == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
(*fcConfigSubstitute)(NULL, pattern, FcMatchScan);
|
||||
(*fcDefaultSubstitute)(pattern);
|
||||
|
||||
FcResult fcResult;
|
||||
FcPattern *match = (*fcFontMatch)(0, pattern, &fcResult);
|
||||
if (match == NULL || fcResult != FcResultMatch) {
|
||||
goto cleanup;
|
||||
}
|
||||
fontFamily = (*fcPatternFormat)(match, (FcChar8*) "%{family}");
|
||||
if (fontFamily == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
// result of foundFontName could be set of families, so we left only first family
|
||||
char *commaPos = strchr((char *) fontFamily, ',');
|
||||
if (commaPos != NULL) {
|
||||
*commaPos = '\0';
|
||||
}
|
||||
if (strstr(queryPtr, (char *) fontFamily) == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fontPath = (*fcPatternFormat)(match, (FcChar8*) propertyPtr);
|
||||
if (fontPath == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
res = (*env)->NewStringUTF(env, (char *) fontPath);
|
||||
|
||||
cleanup:
|
||||
if (fontPath) {
|
||||
(*fcStrFree)(fontPath);
|
||||
}
|
||||
if (fontFamily) {
|
||||
(*fcStrFree)(fontFamily);
|
||||
}
|
||||
if (propertyPtr) {
|
||||
(*env)->ReleaseStringUTFChars(env, property, (const char*)propertyPtr);
|
||||
}
|
||||
if (queryPtr) {
|
||||
(*env)->ReleaseStringUTFChars(env, query, (const char*)queryPtr);
|
||||
}
|
||||
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
@@ -31,6 +31,8 @@
|
||||
|
||||
#include <Trace.h>
|
||||
#include <jni_util.h>
|
||||
#include <java_awt_event_KeyEvent.h>
|
||||
#include <java_awt_event_InputEvent.h>
|
||||
|
||||
#include "sun_awt_wl_WLRobotPeer.h"
|
||||
#include "WLToolkit.h"
|
||||
@@ -116,6 +118,158 @@ init_mutex_and_cond(JNIEnv *env, pthread_mutex_t *mutex, pthread_cond_t *cond)
|
||||
|
||||
static void
|
||||
handle_wakefield_error(JNIEnv *env, uint32_t error_code);
|
||||
|
||||
struct wayland_keycode_map_item {
|
||||
int java_key_code;
|
||||
int wayland_key_code;
|
||||
};
|
||||
|
||||
// Key codes correspond to the Linux event codes:
|
||||
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
|
||||
static struct wayland_keycode_map_item wayland_keycode_map[] = {
|
||||
{ java_awt_event_KeyEvent_VK_ESCAPE, 1 },
|
||||
{ java_awt_event_KeyEvent_VK_1, 2 },
|
||||
{ java_awt_event_KeyEvent_VK_2, 3 },
|
||||
{ java_awt_event_KeyEvent_VK_3, 4 },
|
||||
{ java_awt_event_KeyEvent_VK_4, 5 },
|
||||
{ java_awt_event_KeyEvent_VK_5, 6 },
|
||||
{ java_awt_event_KeyEvent_VK_6, 7 },
|
||||
{ java_awt_event_KeyEvent_VK_7, 8 },
|
||||
{ java_awt_event_KeyEvent_VK_8, 9 },
|
||||
{ java_awt_event_KeyEvent_VK_9, 10 },
|
||||
{ java_awt_event_KeyEvent_VK_0, 11 },
|
||||
{ java_awt_event_KeyEvent_VK_MINUS, 12 },
|
||||
{ java_awt_event_KeyEvent_VK_EQUALS, 13 },
|
||||
{ java_awt_event_KeyEvent_VK_BACK_SPACE, 14 },
|
||||
{ java_awt_event_KeyEvent_VK_TAB, 15 },
|
||||
{ java_awt_event_KeyEvent_VK_Q, 16 },
|
||||
{ java_awt_event_KeyEvent_VK_W, 17 },
|
||||
{ java_awt_event_KeyEvent_VK_E, 18 },
|
||||
{ java_awt_event_KeyEvent_VK_R, 19 },
|
||||
{ java_awt_event_KeyEvent_VK_T, 20 },
|
||||
{ java_awt_event_KeyEvent_VK_Y, 21 },
|
||||
{ java_awt_event_KeyEvent_VK_U, 22 },
|
||||
{ java_awt_event_KeyEvent_VK_I, 23 },
|
||||
{ java_awt_event_KeyEvent_VK_O, 24 },
|
||||
{ java_awt_event_KeyEvent_VK_P, 25 },
|
||||
{ java_awt_event_KeyEvent_VK_OPEN_BRACKET, 26 },
|
||||
{ java_awt_event_KeyEvent_VK_CLOSE_BRACKET, 27 },
|
||||
{ java_awt_event_KeyEvent_VK_ENTER, 28 },
|
||||
{ java_awt_event_KeyEvent_VK_CONTROL, 29 },
|
||||
{ java_awt_event_KeyEvent_VK_A, 30 },
|
||||
{ java_awt_event_KeyEvent_VK_S, 31 },
|
||||
{ java_awt_event_KeyEvent_VK_D, 32 },
|
||||
{ java_awt_event_KeyEvent_VK_F, 33 },
|
||||
{ java_awt_event_KeyEvent_VK_G, 34 },
|
||||
{ java_awt_event_KeyEvent_VK_H, 35 },
|
||||
{ java_awt_event_KeyEvent_VK_J, 36 },
|
||||
{ java_awt_event_KeyEvent_VK_K, 37 },
|
||||
{ java_awt_event_KeyEvent_VK_L, 38 },
|
||||
{ java_awt_event_KeyEvent_VK_SEMICOLON, 39 },
|
||||
{ java_awt_event_KeyEvent_VK_QUOTE, 40 },
|
||||
{ java_awt_event_KeyEvent_VK_BACK_QUOTE, 41 },
|
||||
{ java_awt_event_KeyEvent_VK_SHIFT, 42 },
|
||||
{ java_awt_event_KeyEvent_VK_BACK_SLASH, 43 },
|
||||
{ java_awt_event_KeyEvent_VK_Z, 44 },
|
||||
{ java_awt_event_KeyEvent_VK_X, 45 },
|
||||
{ java_awt_event_KeyEvent_VK_C, 46 },
|
||||
{ java_awt_event_KeyEvent_VK_V, 47 },
|
||||
{ java_awt_event_KeyEvent_VK_B, 48 },
|
||||
{ java_awt_event_KeyEvent_VK_N, 49 },
|
||||
{ java_awt_event_KeyEvent_VK_M, 50 },
|
||||
{ java_awt_event_KeyEvent_VK_COMMA, 51 },
|
||||
{ java_awt_event_KeyEvent_VK_PERIOD, 52 },
|
||||
{ java_awt_event_KeyEvent_VK_SLASH, 53 },
|
||||
{ java_awt_event_KeyEvent_VK_MULTIPLY, 55 },
|
||||
{ java_awt_event_KeyEvent_VK_ALT, 56 },
|
||||
{ java_awt_event_KeyEvent_VK_SPACE, 57 },
|
||||
{ java_awt_event_KeyEvent_VK_CAPS_LOCK, 58 },
|
||||
{ java_awt_event_KeyEvent_VK_F1, 59 },
|
||||
{ java_awt_event_KeyEvent_VK_F2, 60 },
|
||||
{ java_awt_event_KeyEvent_VK_F3, 61 },
|
||||
{ java_awt_event_KeyEvent_VK_F4, 62 },
|
||||
{ java_awt_event_KeyEvent_VK_F5, 63 },
|
||||
{ java_awt_event_KeyEvent_VK_F6, 64 },
|
||||
{ java_awt_event_KeyEvent_VK_F7, 65 },
|
||||
{ java_awt_event_KeyEvent_VK_F8, 66 },
|
||||
{ java_awt_event_KeyEvent_VK_F9, 67 },
|
||||
{ java_awt_event_KeyEvent_VK_F10, 68 },
|
||||
{ java_awt_event_KeyEvent_VK_NUM_LOCK, 69 },
|
||||
{ java_awt_event_KeyEvent_VK_SCROLL_LOCK, 70 },
|
||||
{ java_awt_event_KeyEvent_VK_NUMPAD7, 71 },
|
||||
{ java_awt_event_KeyEvent_VK_KP_UP, 72 },
|
||||
{ java_awt_event_KeyEvent_VK_NUMPAD8, 72 },
|
||||
{ java_awt_event_KeyEvent_VK_NUMPAD9, 73 },
|
||||
{ java_awt_event_KeyEvent_VK_SUBTRACT, 74 },
|
||||
{ java_awt_event_KeyEvent_VK_KP_LEFT, 75 },
|
||||
{ java_awt_event_KeyEvent_VK_NUMPAD4, 75 },
|
||||
{ java_awt_event_KeyEvent_VK_NUMPAD5, 76 },
|
||||
{ java_awt_event_KeyEvent_VK_KP_RIGHT, 77 },
|
||||
{ java_awt_event_KeyEvent_VK_NUMPAD6, 77 },
|
||||
{ java_awt_event_KeyEvent_VK_ADD, 78 },
|
||||
{ java_awt_event_KeyEvent_VK_NUMPAD1, 79 },
|
||||
{ java_awt_event_KeyEvent_VK_KP_DOWN, 80 },
|
||||
{ java_awt_event_KeyEvent_VK_NUMPAD2, 80 },
|
||||
{ java_awt_event_KeyEvent_VK_NUMPAD3, 81 },
|
||||
{ java_awt_event_KeyEvent_VK_NUMPAD0, 82 },
|
||||
{ java_awt_event_KeyEvent_VK_DECIMAL, 83 },
|
||||
{ java_awt_event_KeyEvent_VK_LESS, 86 },
|
||||
{ java_awt_event_KeyEvent_VK_F11, 87 },
|
||||
{ java_awt_event_KeyEvent_VK_F12, 88 },
|
||||
{ java_awt_event_KeyEvent_VK_KATAKANA, 90 },
|
||||
{ java_awt_event_KeyEvent_VK_HIRAGANA, 91 },
|
||||
{ java_awt_event_KeyEvent_VK_INPUT_METHOD_ON_OFF, 92 },
|
||||
{ java_awt_event_KeyEvent_VK_NONCONVERT, 94 },
|
||||
{ java_awt_event_KeyEvent_VK_DIVIDE, 98 },
|
||||
{ java_awt_event_KeyEvent_VK_PRINTSCREEN, 99 },
|
||||
{ java_awt_event_KeyEvent_VK_ALT_GRAPH, 100 },
|
||||
{ java_awt_event_KeyEvent_VK_HOME, 102 },
|
||||
{ java_awt_event_KeyEvent_VK_UP, 103 },
|
||||
{ java_awt_event_KeyEvent_VK_PAGE_UP, 104 },
|
||||
{ java_awt_event_KeyEvent_VK_LEFT, 105 },
|
||||
{ java_awt_event_KeyEvent_VK_RIGHT, 106 },
|
||||
{ java_awt_event_KeyEvent_VK_END, 107 },
|
||||
{ java_awt_event_KeyEvent_VK_DOWN, 108 },
|
||||
{ java_awt_event_KeyEvent_VK_PAGE_DOWN, 109 },
|
||||
{ java_awt_event_KeyEvent_VK_INSERT, 110 },
|
||||
{ java_awt_event_KeyEvent_VK_DELETE, 111 },
|
||||
{ java_awt_event_KeyEvent_VK_PAUSE, 119 },
|
||||
{ java_awt_event_KeyEvent_VK_DECIMAL, 121 },
|
||||
{ java_awt_event_KeyEvent_VK_META, 125 },
|
||||
{ java_awt_event_KeyEvent_VK_WINDOWS, 125 },
|
||||
{ java_awt_event_KeyEvent_VK_STOP, 128 },
|
||||
{ java_awt_event_KeyEvent_VK_AGAIN, 129 },
|
||||
{ java_awt_event_KeyEvent_VK_UNDO, 131 },
|
||||
{ java_awt_event_KeyEvent_VK_FIND, 136 },
|
||||
{ java_awt_event_KeyEvent_VK_HELP, 138 },
|
||||
{ java_awt_event_KeyEvent_VK_LEFT_PARENTHESIS, 179 },
|
||||
{ java_awt_event_KeyEvent_VK_RIGHT_PARENTHESIS, 180 },
|
||||
{ java_awt_event_KeyEvent_VK_F13, 183 },
|
||||
{ java_awt_event_KeyEvent_VK_F14, 184 },
|
||||
{ java_awt_event_KeyEvent_VK_F15, 185 },
|
||||
{ java_awt_event_KeyEvent_VK_F16, 186 },
|
||||
{ java_awt_event_KeyEvent_VK_F17, 187 },
|
||||
{ java_awt_event_KeyEvent_VK_F18, 188 },
|
||||
{ java_awt_event_KeyEvent_VK_F19, 189 },
|
||||
{ java_awt_event_KeyEvent_VK_F20, 190 },
|
||||
{ java_awt_event_KeyEvent_VK_F21, 191 },
|
||||
{ java_awt_event_KeyEvent_VK_F22, 192 },
|
||||
{ java_awt_event_KeyEvent_VK_F23, 193 },
|
||||
{ java_awt_event_KeyEvent_VK_F24, 194 },
|
||||
{ java_awt_event_KeyEvent_VK_UNDEFINED, -1 }
|
||||
};
|
||||
|
||||
struct wayland_button_map_item {
|
||||
int java_button_mask;
|
||||
int wayland_button_code;
|
||||
};
|
||||
|
||||
static struct wayland_button_map_item wayland_button_map[] = {
|
||||
{ java_awt_event_InputEvent_BUTTON1_DOWN_MASK | java_awt_event_InputEvent_BUTTON1_MASK, 0x110 },
|
||||
{ java_awt_event_InputEvent_BUTTON2_DOWN_MASK | java_awt_event_InputEvent_BUTTON2_MASK, 0x112 },
|
||||
{ java_awt_event_InputEvent_BUTTON3_DOWN_MASK | java_awt_event_InputEvent_BUTTON3_MASK, 0x111 },
|
||||
{ -1, -1 },
|
||||
};
|
||||
#endif
|
||||
|
||||
static jclass pointClass; // java.awt.Point
|
||||
@@ -177,7 +331,7 @@ Java_sun_awt_wl_WLRobotPeer_getRGBPixelImpl(JNIEnv *env, jclass clazz, jint x, j
|
||||
WAKEFIELD_REQUEST_INIT(pixel_color_request);
|
||||
|
||||
wakefield_get_pixel_color(wakefield, x, y);
|
||||
wl_flush_to_server(env); // the event will be delivered on a dedicated thread, see wakefield_pixel_color()
|
||||
wlFlushToServer(env); // the event will be delivered on a dedicated thread, see wakefield_pixel_color()
|
||||
|
||||
WAKEFIELD_REQUEST_WAIT_START(pixel_color_request);
|
||||
const uint32_t error_code = pixel_color_request.error_code;
|
||||
@@ -208,7 +362,7 @@ Java_sun_awt_wl_WLRobotPeer_getLocationOfWLSurfaceImpl
|
||||
|
||||
struct wl_surface * const surface = (struct wl_surface*) wlSurfacePtr;
|
||||
wakefield_get_surface_location(wakefield, surface);
|
||||
wl_flush_to_server(env); // the event will be delivered on a dedicated thread, see wakefield_surface_location()
|
||||
wlFlushToServer(env); // the event will be delivered on a dedicated thread, see wakefield_surface_location()
|
||||
|
||||
WAKEFIELD_REQUEST_WAIT_START(surface_location_request);
|
||||
const uint32_t error_code = surface_location_request.error_code;
|
||||
@@ -243,7 +397,7 @@ Java_sun_awt_wl_WLRobotPeer_setLocationOfWLSurfaceImpl
|
||||
struct wl_surface * const surface = (struct wl_surface*) wlSurfacePtr;
|
||||
wakefield_move_surface(wakefield, surface, x, y);
|
||||
wl_surface_commit(surface);
|
||||
wl_flush_to_server(env);
|
||||
wlFlushToServer(env);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -298,6 +452,79 @@ Java_sun_awt_wl_WLRobotPeer_getRGBPixelsImpl
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_WLRobotPeer_sendJavaKeyImpl
|
||||
(JNIEnv *env, jclass clazz, jint javaKeyCode, jboolean pressed)
|
||||
{
|
||||
#ifdef WAKEFIELD_ROBOT
|
||||
if (!wakefield) {
|
||||
JNU_ThrowByName(env, "java/awt/AWTError", "no 'wakefield' protocol extension");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t key = 0;
|
||||
|
||||
for (struct wayland_keycode_map_item* item = wayland_keycode_map; item->wayland_key_code != -1; ++item) {
|
||||
if (item->java_key_code == javaKeyCode) {
|
||||
key = item->wayland_key_code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
|
||||
wakefield_send_key(wakefield, key, pressed ? 1 : 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_WLRobotPeer_mouseMoveImpl
|
||||
(JNIEnv *env, jclass clazz, jint x, jint y)
|
||||
{
|
||||
#ifdef WAKEFIELD_ROBOT
|
||||
if (!wakefield) {
|
||||
JNU_ThrowByName(env, "java/awt/AWTError", "no 'wakefield' protocol extension");
|
||||
return;
|
||||
}
|
||||
|
||||
wakefield_send_cursor(wakefield, x, y);
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_WLRobotPeer_sendMouseButtonImpl
|
||||
(JNIEnv *env, jclass clazz, jint buttons, jboolean pressed)
|
||||
{
|
||||
#ifdef WAKEFIELD_ROBOT
|
||||
if (!wakefield) {
|
||||
JNU_ThrowByName(env, "java/awt/AWTError", "no 'wakefield' protocol extension");
|
||||
return;
|
||||
}
|
||||
|
||||
for (struct wayland_button_map_item* item = wayland_button_map; item->wayland_button_code != -1; ++item) {
|
||||
if (item->java_button_mask & buttons) {
|
||||
wakefield_send_button(wakefield, item->wayland_button_code, pressed ? 1 : 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_WLRobotPeer_mouseWheelImpl
|
||||
(JNIEnv *env, jclass clazz, jint amount)
|
||||
{
|
||||
#ifdef WAKEFIELD_ROBOT
|
||||
if (!wakefield) {
|
||||
JNU_ThrowByName(env, "java/awt/AWTError", "no 'wakefield' protocol extension");
|
||||
return;
|
||||
}
|
||||
|
||||
wakefield_send_wheel(wakefield, amount);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WAKEFIELD_ROBOT
|
||||
|
||||
static void wakefield_surface_location(void *data, struct wakefield *wakefield,
|
||||
|
||||
@@ -356,13 +356,13 @@ wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
|
||||
}
|
||||
|
||||
static inline void
|
||||
reset_pointer_event(struct pointer_event_cumulative *e)
|
||||
resetPointerEvent(struct pointer_event_cumulative *e)
|
||||
{
|
||||
memset(e, 0, sizeof(struct pointer_event_cumulative));
|
||||
}
|
||||
|
||||
static void
|
||||
fill_java_pointer_event(JNIEnv* env, jobject pointerEventRef)
|
||||
fillJavaPointerEvent(JNIEnv* env, jobject pointerEventRef)
|
||||
{
|
||||
(*env)->SetBooleanField(env, pointerEventRef, hasEnterEventFID, pointer_event.has_enter_event);
|
||||
(*env)->SetBooleanField(env, pointerEventRef, hasLeaveEventFID, pointer_event.has_leave_event);
|
||||
@@ -396,14 +396,14 @@ wl_pointer_frame(void *data, struct wl_pointer *wl_pointer)
|
||||
pointerEventFactoryMID);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
|
||||
fill_java_pointer_event(env, pointerEventRef);
|
||||
fillJavaPointerEvent(env, pointerEventRef);
|
||||
(*env)->CallStaticVoidMethod(env,
|
||||
tkClass,
|
||||
dispatchPointerEventMID,
|
||||
pointerEventRef);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
|
||||
reset_pointer_event(&pointer_event);
|
||||
resetPointerEvent(&pointer_event);
|
||||
}
|
||||
|
||||
static const struct wl_pointer_listener wl_pointer_listener = {
|
||||
@@ -546,6 +546,16 @@ wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard,
|
||||
XKB_MOD_NAME_LOGO,
|
||||
XKB_STATE_MODS_EFFECTIVE);
|
||||
|
||||
const bool is_caps_active
|
||||
= xkb_ifs.xkb_state_mod_name_is_active(xkb_state,
|
||||
XKB_MOD_NAME_CAPS,
|
||||
XKB_STATE_MODS_EFFECTIVE);
|
||||
|
||||
const bool is_num_active
|
||||
= xkb_ifs.xkb_state_mod_name_is_active(xkb_state,
|
||||
XKB_MOD_NAME_NUM,
|
||||
XKB_STATE_MODS_EFFECTIVE);
|
||||
|
||||
(*env)->CallStaticVoidMethod(env,
|
||||
tkClass,
|
||||
dispatchKeyboardModifiersEventMID,
|
||||
@@ -553,7 +563,9 @@ wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard,
|
||||
is_shift_active,
|
||||
is_alt_active,
|
||||
is_ctrl_active,
|
||||
is_meta_active);
|
||||
is_meta_active,
|
||||
is_caps_active,
|
||||
is_num_active);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
|
||||
@@ -776,7 +788,7 @@ initJavaRefs(JNIEnv *env, jclass clazz)
|
||||
JNI_FALSE);
|
||||
CHECK_NULL_RETURN(dispatchKeyboardModifiersEventMID = (*env)->GetStaticMethodID(env, tkClass,
|
||||
"dispatchKeyboardModifiersEvent",
|
||||
"(JZZZZ)V"),
|
||||
"(JZZZZZZ)V"),
|
||||
JNI_FALSE);
|
||||
|
||||
CHECK_NULL_RETURN(keyRepeatRateFID = (*env)->GetStaticFieldID(env, tkClass,
|
||||
@@ -854,7 +866,7 @@ initCursors() {
|
||||
}
|
||||
|
||||
static void
|
||||
finalize_init(JNIEnv *env) {
|
||||
finalizeInit(JNIEnv *env) {
|
||||
// NB: we are NOT on EDT here so shouldn't dispatch EDT-sensitive stuff
|
||||
while (num_of_outstanding_sync > 0) {
|
||||
// There are outstanding events that carry information essential for the toolkit
|
||||
@@ -902,7 +914,7 @@ Java_sun_awt_wl_WLToolkit_initIDs
|
||||
|
||||
initCursors();
|
||||
|
||||
finalize_init(env);
|
||||
finalizeInit(env);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
@@ -915,8 +927,12 @@ Java_sun_awt_wl_WLToolkit_dispatchEventsOnEDT
|
||||
wl_display_dispatch_pending(wl_display);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for poll_timeout ms for an event on the Wayland server socket.
|
||||
* Returns -1 in case of error and 'revents' (see poll(2)) otherwise.
|
||||
*/
|
||||
static int
|
||||
wl_display_poll(struct wl_display *display, int events, int poll_timeout)
|
||||
wlDisplayPoll(struct wl_display *display, int events, int poll_timeout)
|
||||
{
|
||||
int rc = 0;
|
||||
struct pollfd pfd[1] = { {.fd = wl_display_get_fd(display), .events = events} };
|
||||
@@ -924,11 +940,12 @@ wl_display_poll(struct wl_display *display, int events, int poll_timeout)
|
||||
errno = 0;
|
||||
rc = poll(pfd, 1, poll_timeout);
|
||||
} while (rc == -1 && errno == EINTR);
|
||||
return rc;
|
||||
|
||||
return rc == -1 ? -1 : (pfd[0].revents & 0xffff);
|
||||
}
|
||||
|
||||
int
|
||||
wl_flush_to_server(JNIEnv *env)
|
||||
wlFlushToServer(JNIEnv *env)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
@@ -939,7 +956,7 @@ wl_flush_to_server(JNIEnv *env)
|
||||
break;
|
||||
}
|
||||
|
||||
rc = wl_display_poll(wl_display, POLLOUT, -1);
|
||||
rc = wlDisplayPoll(wl_display, POLLOUT, -1);
|
||||
if (rc == -1) {
|
||||
JNU_ThrowByName(env, "java/awt/AWTError", "Wayland display error polling out to the server");
|
||||
return sun_awt_wl_WLToolkit_READ_RESULT_ERROR;
|
||||
@@ -958,7 +975,7 @@ JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_WLToolkit_flushImpl
|
||||
(JNIEnv *env, jobject obj)
|
||||
{
|
||||
(void) wl_flush_to_server(env);
|
||||
(void) wlFlushToServer(env);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
@@ -974,16 +991,7 @@ Java_sun_awt_wl_WLToolkit_dispatchNonDefaultQueuesImpl
|
||||
|
||||
while (rc >= 0) {
|
||||
// Dispatch pending events on the wakefield queue
|
||||
while (wl_display_prepare_read_queue(wl_display, robot_queue) != 0 && rc >= 0) {
|
||||
rc = wl_display_dispatch_queue_pending(wl_display, robot_queue);
|
||||
}
|
||||
if (rc < 0) {
|
||||
wl_display_cancel_read(wl_display);
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait for new events, wl_display_read_events is a synchronization point between all threads reading events.
|
||||
rc = wl_display_read_events(wl_display);
|
||||
rc = wl_display_dispatch_queue(wl_display, robot_queue);
|
||||
}
|
||||
|
||||
// Simply return in case of any error; the actual error reporting (exception)
|
||||
@@ -1007,7 +1015,7 @@ Java_sun_awt_wl_WLToolkit_readEvents
|
||||
return sun_awt_wl_WLToolkit_READ_RESULT_FINISHED_WITH_EVENTS;
|
||||
}
|
||||
|
||||
rc = wl_flush_to_server(env);
|
||||
rc = wlFlushToServer(env);
|
||||
if (rc != 0) {
|
||||
wl_display_cancel_read(wl_display);
|
||||
return sun_awt_wl_WLToolkit_READ_RESULT_ERROR;
|
||||
@@ -1016,7 +1024,7 @@ Java_sun_awt_wl_WLToolkit_readEvents
|
||||
// Wait for new data *from* the server.
|
||||
// Specify some timeout because otherwise 'flush' above that sends data
|
||||
// to the server will have to wait too long.
|
||||
rc = wl_display_poll(wl_display, POLLIN,
|
||||
rc = wlDisplayPoll(wl_display, POLLIN,
|
||||
sun_awt_wl_WLToolkit_WAYLAND_DISPLAY_INTERACTION_TIMEOUT_MS);
|
||||
if (rc == -1) {
|
||||
wl_display_cancel_read(wl_display);
|
||||
@@ -1024,7 +1032,14 @@ Java_sun_awt_wl_WLToolkit_readEvents
|
||||
return sun_awt_wl_WLToolkit_READ_RESULT_ERROR;
|
||||
}
|
||||
|
||||
// Transform the data read by the above call into events on the corresponding queues of the display.
|
||||
const bool hasMoreData = (rc & POLLIN);
|
||||
if (!hasMoreData) {
|
||||
wl_display_cancel_read(wl_display);
|
||||
return sun_awt_wl_WLToolkit_READ_RESULT_FINISHED_NO_EVENTS;
|
||||
}
|
||||
|
||||
// Read new data from Wayland and transform them into events
|
||||
// on the corresponding queues of the display.
|
||||
rc = wl_display_read_events(wl_display);
|
||||
if (rc == -1) { // display disconnect has likely happened
|
||||
return sun_awt_wl_WLToolkit_READ_RESULT_ERROR;
|
||||
@@ -1216,7 +1231,7 @@ Java_sun_awt_SunToolkit_closeSplashScreen(JNIEnv *env, jclass cls)
|
||||
|
||||
void awt_output_flush()
|
||||
{
|
||||
wl_flush_to_server(getEnv());
|
||||
wlFlushToServer(getEnv());
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -55,6 +55,6 @@ extern uint32_t last_pointer_enter_serial;
|
||||
|
||||
JNIEnv *getEnv();
|
||||
|
||||
int wl_flush_to_server(JNIEnv* env);
|
||||
int wlFlushToServer(JNIEnv* env);
|
||||
|
||||
struct wl_shm_pool *CreateShmPool(size_t size, const char *name, void **data);
|
||||
|
||||
@@ -28,6 +28,16 @@
|
||||
#include <stdint.h>
|
||||
#include "wayland-util.h"
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
|
||||
#endif
|
||||
|
||||
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
|
||||
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define WL_PRIVATE
|
||||
#endif
|
||||
|
||||
extern const struct wl_interface wl_buffer_interface;
|
||||
extern const struct wl_interface wl_surface_interface;
|
||||
|
||||
@@ -56,6 +66,10 @@ static const struct wl_message wakefield_requests[] = {
|
||||
{ "move_surface", "oii", wakefield_types + 4 },
|
||||
{ "get_surface_location", "o", wakefield_types + 7 },
|
||||
{ "get_pixel_color", "ii", wakefield_types + 0 },
|
||||
{ "send_key", "uu", wakefield_types + 0 },
|
||||
{ "send_cursor", "ii", wakefield_types + 0 },
|
||||
{ "send_button", "uu", wakefield_types + 0 },
|
||||
{ "send_wheel", "i", wakefield_types + 0 },
|
||||
{ "capture_create", "oii", wakefield_types + 8 },
|
||||
};
|
||||
|
||||
@@ -65,9 +79,9 @@ static const struct wl_message wakefield_events[] = {
|
||||
{ "capture_ready", "ou", wakefield_types + 15 },
|
||||
};
|
||||
|
||||
WL_EXPORT const struct wl_interface wakefield_interface = {
|
||||
WL_PRIVATE const struct wl_interface wakefield_interface = {
|
||||
"wakefield", 1,
|
||||
5, wakefield_requests,
|
||||
9, wakefield_requests,
|
||||
3, wakefield_events,
|
||||
};
|
||||
|
||||
|
||||
@@ -142,7 +142,11 @@ wakefield_add_listener(struct wakefield *wakefield,
|
||||
#define WAKEFIELD_MOVE_SURFACE 1
|
||||
#define WAKEFIELD_GET_SURFACE_LOCATION 2
|
||||
#define WAKEFIELD_GET_PIXEL_COLOR 3
|
||||
#define WAKEFIELD_CAPTURE_CREATE 4
|
||||
#define WAKEFIELD_SEND_KEY 4
|
||||
#define WAKEFIELD_SEND_CURSOR 5
|
||||
#define WAKEFIELD_SEND_BUTTON 6
|
||||
#define WAKEFIELD_SEND_WHEEL 7
|
||||
#define WAKEFIELD_CAPTURE_CREATE 8
|
||||
|
||||
/**
|
||||
* @ingroup iface_wakefield
|
||||
@@ -173,6 +177,22 @@ wakefield_add_listener(struct wakefield *wakefield,
|
||||
* @ingroup iface_wakefield
|
||||
*/
|
||||
#define WAKEFIELD_GET_PIXEL_COLOR_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_wakefield
|
||||
*/
|
||||
#define WAKEFIELD_SEND_KEY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_wakefield
|
||||
*/
|
||||
#define WAKEFIELD_SEND_CURSOR_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_wakefield
|
||||
*/
|
||||
#define WAKEFIELD_SEND_BUTTON_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_wakefield
|
||||
*/
|
||||
#define WAKEFIELD_SEND_WHEEL_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_wakefield
|
||||
*/
|
||||
@@ -249,6 +269,54 @@ wakefield_get_pixel_color(struct wakefield *wakefield, int32_t x, int32_t y)
|
||||
WAKEFIELD_GET_PIXEL_COLOR, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_wakefield
|
||||
*
|
||||
* This requests an emulation of a key press by its Linux event key code.
|
||||
*/
|
||||
static inline void
|
||||
wakefield_send_key(struct wakefield *wakefield, uint32_t key, uint32_t state)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) wakefield,
|
||||
WAKEFIELD_SEND_KEY, key, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_wakefield
|
||||
*
|
||||
* This requests an emulation of the mouse cursor being moved to the specified screen coordinates.
|
||||
*/
|
||||
static inline void
|
||||
wakefield_send_cursor(struct wakefield *wakefield, int32_t x, int32_t y)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) wakefield,
|
||||
WAKEFIELD_SEND_CURSOR, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_wakefield
|
||||
*
|
||||
* This requests an emulation of a mouse button press by its Linux event code.
|
||||
*/
|
||||
static inline void
|
||||
wakefield_send_button(struct wakefield *wakefield, uint32_t button, uint32_t state)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) wakefield,
|
||||
WAKEFIELD_SEND_BUTTON, button, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_wakefield
|
||||
*
|
||||
* This requests an emulation of a rotation of a mouse scroll wheel.
|
||||
*/
|
||||
static inline void
|
||||
wakefield_send_wheel(struct wakefield *wakefield, int32_t amount)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) wakefield,
|
||||
WAKEFIELD_SEND_WHEEL, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_wakefield
|
||||
*/
|
||||
|
||||
@@ -33,7 +33,9 @@ public interface WindowMove {
|
||||
* The intended use is to facilitate the implementation of window management similar to the way
|
||||
* it is done natively on the platform.
|
||||
*
|
||||
* Preconditions for calling this method:
|
||||
* The service is implemented both for X11 and Wayland toolkits.
|
||||
*
|
||||
* Preconditions for calling this method with the X11 toolkit:
|
||||
* <ul>
|
||||
* <li>WM supports _NET_WM_MOVE_RESIZE (this is checked automatically when an implementation
|
||||
* of this interface is obtained).</li>
|
||||
@@ -41,13 +43,20 @@ public interface WindowMove {
|
||||
* <li>The mouse button specified by {@code mouseButton} is pressed.</li>
|
||||
* </ul>
|
||||
*
|
||||
* Preconditions for calling this method with the Wayland toolkit:
|
||||
* <ul>
|
||||
* <li>Mouse pointer is within this window's bounds.</li>
|
||||
* </ul>
|
||||
* The {@code mouseButton} is ignored for Wayland; the latest mouse press event is used
|
||||
* automatically; this is enforced by the Wayland protocol.
|
||||
*
|
||||
* Calling this method will make the window start moving together with the mouse pointer until
|
||||
* the specified mouse button is released or Esc is pressed. The conditions for cancelling
|
||||
* the move may differ between WMs.
|
||||
*
|
||||
* @param mouseButton indicates the mouse button that was pressed to start moving the window;
|
||||
* must be one of {@code MouseEvent.BUTTON1}, {@code MouseEvent.BUTTON2},
|
||||
* or {@code MouseEvent.BUTTON3}.
|
||||
* or {@code MouseEvent.BUTTON3}. This argument is ignored for Wayland.
|
||||
*/
|
||||
void startMovingTogetherWithMouse(Window window, int mouseButton);
|
||||
}
|
||||
|
||||
@@ -11,4 +11,4 @@ VERSION = 0.0.14
|
||||
# Hash is used to track changes to jetbrains.api, so you would not forget to update version when needed.
|
||||
# When you make any changes, "make jbr-api" will fail and ask you to update hash and version number here.
|
||||
|
||||
HASH = A522CCED3246461BB9CC92E620DEE3AA
|
||||
HASH = D28F22789F62EA4F8B8F4E7EC8B342E5
|
||||
|
||||
299
test/jdk/java/awt/wakefield/RobotKeyboard.java
Normal file
299
test/jdk/java/awt/wakefield/RobotKeyboard.java
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @key headful
|
||||
* @summary JBR-5676 Wayland: support generation of input events by AWT Robot in weston plugin
|
||||
* @requires (os.family == "linux")
|
||||
* @library /test/lib
|
||||
* @build RobotKeyboard
|
||||
* @run driver WakefieldTestDriver -timeout 60 RobotKeyboard
|
||||
*/
|
||||
|
||||
public class RobotKeyboard {
|
||||
private static String ordinaryKeyNames[] = {
|
||||
"VK_0",
|
||||
"VK_1",
|
||||
"VK_2",
|
||||
"VK_3",
|
||||
"VK_4",
|
||||
"VK_5",
|
||||
"VK_6",
|
||||
"VK_7",
|
||||
"VK_8",
|
||||
"VK_9",
|
||||
"VK_A",
|
||||
"VK_ADD",
|
||||
"VK_AGAIN",
|
||||
"VK_ALT",
|
||||
// TODO: WLToolkit doesn't differentiate VK_ALT and VK_ALT_GRAPH for now
|
||||
// "VK_ALT_GRAPH",
|
||||
"VK_B",
|
||||
"VK_BACK_QUOTE",
|
||||
"VK_BACK_SLASH",
|
||||
"VK_BACK_SPACE",
|
||||
"VK_C",
|
||||
"VK_CLOSE_BRACKET",
|
||||
"VK_COMMA",
|
||||
"VK_CONTROL",
|
||||
"VK_D",
|
||||
"VK_DECIMAL",
|
||||
"VK_DELETE",
|
||||
"VK_DIVIDE",
|
||||
"VK_DOWN",
|
||||
"VK_E",
|
||||
"VK_END",
|
||||
"VK_ENTER",
|
||||
"VK_EQUALS",
|
||||
"VK_ESCAPE",
|
||||
"VK_F",
|
||||
"VK_F1",
|
||||
"VK_F2",
|
||||
"VK_F3",
|
||||
"VK_F4",
|
||||
"VK_F5",
|
||||
"VK_F6",
|
||||
"VK_F7",
|
||||
"VK_F8",
|
||||
"VK_F9",
|
||||
"VK_F10",
|
||||
"VK_F11",
|
||||
"VK_F12",
|
||||
// TODO: WLToolkit ignores F13..F24 due to the XKB issues presumably
|
||||
// "VK_F13",
|
||||
// "VK_F14",
|
||||
// "VK_F15",
|
||||
// "VK_F16",
|
||||
// "VK_F17",
|
||||
// "VK_F18",
|
||||
// "VK_F19",
|
||||
// "VK_F20",
|
||||
// "VK_F21",
|
||||
// "VK_F22",
|
||||
// "VK_F23",
|
||||
// "VK_F24",
|
||||
"VK_FIND",
|
||||
"VK_G",
|
||||
"VK_H",
|
||||
"VK_HELP",
|
||||
"VK_HIRAGANA",
|
||||
"VK_HOME",
|
||||
"VK_I",
|
||||
"VK_INPUT_METHOD_ON_OFF",
|
||||
"VK_INSERT",
|
||||
"VK_J",
|
||||
"VK_K",
|
||||
"VK_KATAKANA",
|
||||
"VK_L",
|
||||
"VK_LEFT",
|
||||
"VK_LEFT_PARENTHESIS",
|
||||
"VK_LESS",
|
||||
"VK_M",
|
||||
// TODO: WLToolkit reports the Meta key as VK_WINDOWS
|
||||
// "VK_META",
|
||||
"VK_MINUS",
|
||||
"VK_MULTIPLY",
|
||||
"VK_N",
|
||||
"VK_NONCONVERT",
|
||||
"VK_NUMPAD0",
|
||||
"VK_NUMPAD1",
|
||||
"VK_NUMPAD2",
|
||||
"VK_NUMPAD3",
|
||||
"VK_NUMPAD4",
|
||||
"VK_NUMPAD5",
|
||||
"VK_NUMPAD6",
|
||||
"VK_NUMPAD7",
|
||||
"VK_NUMPAD8",
|
||||
"VK_NUMPAD9",
|
||||
"VK_O",
|
||||
"VK_OPEN_BRACKET",
|
||||
"VK_P",
|
||||
"VK_PAGE_DOWN",
|
||||
"VK_PAGE_UP",
|
||||
"VK_PAUSE",
|
||||
"VK_PERIOD",
|
||||
"VK_PRINTSCREEN",
|
||||
"VK_Q",
|
||||
"VK_QUOTE",
|
||||
"VK_R",
|
||||
"VK_RIGHT",
|
||||
"VK_RIGHT_PARENTHESIS",
|
||||
"VK_S",
|
||||
"VK_SEMICOLON",
|
||||
"VK_SHIFT",
|
||||
"VK_SLASH",
|
||||
"VK_SPACE",
|
||||
"VK_STOP",
|
||||
"VK_SUBTRACT",
|
||||
"VK_T",
|
||||
"VK_TAB",
|
||||
"VK_U",
|
||||
"VK_UNDO",
|
||||
"VK_UP",
|
||||
"VK_V",
|
||||
"VK_W",
|
||||
"VK_WINDOWS",
|
||||
"VK_X",
|
||||
"VK_Y",
|
||||
"VK_Z",
|
||||
};
|
||||
|
||||
private static String lockingKeyNames[] = {
|
||||
"VK_CAPS_LOCK",
|
||||
"VK_NUM_LOCK",
|
||||
"VK_SCROLL_LOCK",
|
||||
};
|
||||
|
||||
private static Robot robot;
|
||||
private static JFrame frame;
|
||||
private static JTextArea textArea;
|
||||
private static final List<KeyEvent> events = new ArrayList<>();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
frame = new JFrame("test");
|
||||
|
||||
textArea = new JTextArea("");
|
||||
textArea.setEditable(false);
|
||||
frame.add(new JScrollPane(textArea));
|
||||
frame.setSize(500, 500);
|
||||
frame.setVisible(true);
|
||||
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(
|
||||
new KeyEventDispatcher() {
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent e) {
|
||||
if (e.getID() == KeyEvent.KEY_PRESSED || e.getID() == KeyEvent.KEY_RELEASED) {
|
||||
events.add(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
robot = new Robot();
|
||||
robot.setAutoDelay(50);
|
||||
robot.delay(500);
|
||||
|
||||
if (Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_CAPS_LOCK)) {
|
||||
// Disable caps lock
|
||||
robot.keyPress(KeyEvent.VK_CAPS_LOCK);
|
||||
robot.keyRelease(KeyEvent.VK_CAPS_LOCK);
|
||||
}
|
||||
|
||||
if (!Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_NUM_LOCK)) {
|
||||
// Enable num lock
|
||||
robot.keyPress(KeyEvent.VK_NUM_LOCK);
|
||||
robot.keyRelease(KeyEvent.VK_NUM_LOCK);
|
||||
}
|
||||
|
||||
boolean ok = true;
|
||||
|
||||
for (String key : ordinaryKeyNames) {
|
||||
ok &= processKey(key);
|
||||
}
|
||||
|
||||
for (String key : lockingKeyNames) {
|
||||
ok &= processKey(key);
|
||||
|
||||
// reset the locking state to the previous one
|
||||
int keyCode = getKeyCodeByName(key);
|
||||
robot.keyPress(keyCode);
|
||||
robot.keyRelease(keyCode);
|
||||
robot.waitForIdle();
|
||||
}
|
||||
|
||||
System.err.println("===== TEST RESULT =====");
|
||||
System.err.println(ok ? "TEST PASSED" : "TEST FAILED");
|
||||
System.err.println("===== FULL LOG =====");
|
||||
System.err.println(textArea.getText());
|
||||
|
||||
frame.dispose();
|
||||
|
||||
// Due to some reason that probably has something to do with the implementation
|
||||
// of the test driver, it's necessary to manually call System.exit() here
|
||||
System.exit(ok ? 0 : 1);
|
||||
}
|
||||
|
||||
private static int getKeyCodeByName(String name) {
|
||||
try {
|
||||
return KeyEvent.class.getDeclaredField(name).getInt(KeyEvent.class);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkKey(String name) {
|
||||
int keyCode = getKeyCodeByName(name);
|
||||
events.clear();
|
||||
textArea.grabFocus();
|
||||
robot.waitForIdle();
|
||||
robot.keyPress(keyCode);
|
||||
robot.keyRelease(keyCode);
|
||||
robot.waitForIdle();
|
||||
|
||||
if (events.size() != 2) {
|
||||
throw new RuntimeException("Expected two events, got: " + events.size());
|
||||
}
|
||||
|
||||
if (events.get(0).getID() != KeyEvent.KEY_PRESSED || events.get(1).getID() != KeyEvent.KEY_RELEASED) {
|
||||
throw new RuntimeException("Expected one KEY_PRESSED and one KEY_RELEASED");
|
||||
}
|
||||
|
||||
if (events.get(0).getKeyCode() != keyCode) {
|
||||
throw new RuntimeException("KEY_PRESSED keyCode is " + events.get(0).getKeyCode() + ", expected " + keyCode);
|
||||
}
|
||||
|
||||
if (events.get(1).getKeyCode() != keyCode) {
|
||||
throw new RuntimeException("KEY_RELEASED keyCode is " + events.get(1).getKeyCode() + ", expected " + keyCode);
|
||||
}
|
||||
}
|
||||
|
||||
private static void log(String what) {
|
||||
textArea.append(what);
|
||||
textArea.setCaretPosition(textArea.getDocument().getLength());
|
||||
System.err.print(what);
|
||||
}
|
||||
|
||||
private static boolean processKey(String name) {
|
||||
log(name + ": ");
|
||||
try {
|
||||
checkKey(name);
|
||||
log("OK\n");
|
||||
return true;
|
||||
} catch (RuntimeException e) {
|
||||
log(e.getMessage() + "\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,8 +40,8 @@ import java.io.IOException;
|
||||
* @requires (os.family == "linux")
|
||||
* @library /test/lib
|
||||
* @build ScreenCapture
|
||||
* @run driver WakefieldTestDriver 1x1400x800 ScreenCapture
|
||||
* @run driver WakefieldTestDriver 2x830x800 ScreenCapture
|
||||
* @run driver WakefieldTestDriver -resolution 1x1400x800 ScreenCapture
|
||||
* @run driver WakefieldTestDriver -resolution 2x830x800 ScreenCapture
|
||||
*/
|
||||
|
||||
public class ScreenCapture {
|
||||
|
||||
@@ -37,11 +37,11 @@ public class WakefieldTestDriver {
|
||||
final static int DEFAULT_NUMBER_OF_SCREENS = 1;
|
||||
final static int DEFAULT_SCREEN_WIDTH = 1280;
|
||||
final static int DEFAULT_SCREEN_HEIGHT = 800;
|
||||
final static int TEST_TIMEOUT_SECONDS = 10;
|
||||
static int testTimeoutSeconds = 10;
|
||||
static void usage() {
|
||||
System.out.println(
|
||||
"""
|
||||
WakefieldTestDriver [NxWxH] ClassName [args]
|
||||
WakefieldTestDriver [-resolution NxWxH] [-timeout SECONDS] ClassName [args]
|
||||
where
|
||||
N - number of Weston outputs (screens); defaults to 1
|
||||
W - width of each screen in pixels; defaults to 1280
|
||||
@@ -65,24 +65,37 @@ public class WakefieldTestDriver {
|
||||
int nScreens = DEFAULT_NUMBER_OF_SCREENS;
|
||||
int screenWidth = DEFAULT_SCREEN_WIDTH;
|
||||
int screenHeight = DEFAULT_SCREEN_HEIGHT;
|
||||
final String firstArg = args[0];
|
||||
if (Character.isDigit(firstArg.charAt(0))) {
|
||||
try {
|
||||
final int firstXIndex = firstArg.indexOf("x", 0);
|
||||
final int secondXIndex = firstArg.indexOf("x", firstXIndex + 1);
|
||||
nScreens = Integer.valueOf(firstArg.substring(0, firstXIndex));
|
||||
screenWidth = Integer.valueOf(firstArg.substring(firstXIndex + 1, secondXIndex));
|
||||
screenHeight = Integer.valueOf(firstArg.substring(secondXIndex + 1, firstArg.length()));
|
||||
|
||||
for (int i = 1; i < args.length; ++i) {
|
||||
jvmArgs.add(args[i]);
|
||||
for (int i = 0; i < args.length; ++i) {
|
||||
if (args[i].equals("-resolution") && i + 1 < args.length) {
|
||||
final String arg = args[i + 1];
|
||||
if (Character.isDigit(arg.charAt(0))) {
|
||||
try {
|
||||
final int firstXIndex = arg.indexOf("x", 0);
|
||||
final int secondXIndex = arg.indexOf("x", firstXIndex + 1);
|
||||
nScreens = Integer.valueOf(arg.substring(0, firstXIndex));
|
||||
screenWidth = Integer.valueOf(arg.substring(firstXIndex + 1, secondXIndex));
|
||||
screenHeight = Integer.valueOf(arg.substring(secondXIndex + 1, arg.length()));
|
||||
} catch (IndexOutOfBoundsException | NumberFormatException ignored) {
|
||||
usage();
|
||||
throw new RuntimeException("Error parsing the first argument of the test driver");
|
||||
}
|
||||
}
|
||||
} catch (IndexOutOfBoundsException | NumberFormatException ignored) {
|
||||
usage();
|
||||
throw new RuntimeException("Error parsing the first argument of the test driver");
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
jvmArgs.addAll(Arrays.asList(args));
|
||||
|
||||
if (args[i].equals("-timeout") && i + 1 < args.length) {
|
||||
final String arg = args[i + 1];
|
||||
testTimeoutSeconds = Integer.valueOf(arg);
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = i; j < args.length; ++j) {
|
||||
jvmArgs.add(args[j]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
final String socketName = SOCKET_NAME_PREFIX + ProcessHandle.current().pid();
|
||||
@@ -95,13 +108,13 @@ public class WakefieldTestDriver {
|
||||
|
||||
final Process p = pb.start();
|
||||
final OutputAnalyzer output = new OutputAnalyzer(p);
|
||||
final boolean exited = p.waitFor(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
final boolean exited = p.waitFor(testTimeoutSeconds, TimeUnit.SECONDS);
|
||||
if (!exited) p.destroy();
|
||||
System.out.println("Test finished. Output: [[[");
|
||||
System.out.println(output.getOutput());
|
||||
System.out.println("]]]");
|
||||
if (!exited) {
|
||||
throw new RuntimeException("Test timed out after " + TEST_TIMEOUT_SECONDS + " seconds");
|
||||
throw new RuntimeException("Test timed out after " + testTimeoutSeconds + " seconds");
|
||||
}
|
||||
|
||||
if (exited && output.getExitValue() != 0) {
|
||||
|
||||
@@ -142,7 +142,7 @@ java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_2.java 820420
|
||||
java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_4.java 8204200 windows-all,macosx-all,linux-all
|
||||
java/awt/dnd/DropTargetEnterExitTest/ExtraDragEnterTest.java 8029680 generic-all
|
||||
java/awt/dnd/DropTargetEnterExitTest/MissedDragExitTest.java JBR-5730 linux-all
|
||||
java/awt/dnd/MissingDragExitEventTest/MissingDragExitEventTest.java JBR-5727 linux-all
|
||||
java/awt/dnd/MissingDragExitEventTest/MissingDragExitEventTest.java 8288839,JBR-5727,JBR-5959 windows-x64,linux-all, windows-aarch64
|
||||
java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.java 8171510,JBR-881 macosx-all,linux-all
|
||||
javax/swing/dnd/7171812/bug7171812.java 8041447,8253184 macosx-all,windows-all
|
||||
java/awt/Focus/ChildWindowFocusTest/ChildWindowFocusTest.java JBR-5545 linux-all,windows-all
|
||||
@@ -867,7 +867,7 @@ javax/sound/sampled/Clip/ClipIsRunningAfterStop.java 8307574,JBR-4455 linux-x64,
|
||||
|
||||
############################################################################
|
||||
|
||||
javax/imageio/plugins/external_plugin_tests/TestClassPathPlugin.sh JBR-5363 window-all
|
||||
javax/imageio/plugins/external_plugin_tests/TestClassPathPlugin.sh JBR-5363 windows-all
|
||||
|
||||
# jdk_swing
|
||||
|
||||
|
||||
Reference in New Issue
Block a user