(Lookup, MethodHandle target, MethodHandle callerBoundTarget)
clb.withMethodBody(INIT_NAME, MTD_void_Lookup_MethodHandle_MethodHandle, 0, cob -> {
- cob.aload(0);
- cob.invokespecial(CD_Object, INIT_NAME, MTD_void);
-
- // call ensureOriginalLookup to verify the given Lookup has access
- cob.aload(1);
- cob.invokestatic(proxyDesc, "ensureOriginalLookup", MTD_void_Lookup);
-
- // this.target = target;
- cob.aload(0);
- cob.aload(2);
- cob.putfield(proxyDesc, TARGET_NAME, CD_MethodHandle);
+ cob.aload(0)
+ .invokespecial(CD_Object, INIT_NAME, MTD_void)
+ // call ensureOriginalLookup to verify the given Lookup has access
+ .aload(1)
+ .invokestatic(proxyDesc, ENSURE_ORIGINAL_LOOKUP, MTD_void_Lookup)
+ // this.target = target;
+ .aload(0)
+ .aload(2)
+ .putfield(proxyDesc, TARGET_NAME, CD_MethodHandle);
// method handles adjusted to the method type of each method
for (var mi : methods) {
// this.m = callerBoundTarget.asType(xxType);
- cob.aload(0);
- cob.aload(3);
- cob.loadConstant(mi.desc);
- cob.invokevirtual(CD_MethodHandle, "asType", MTD_MethodHandle_MethodType);
- cob.putfield(proxyDesc, mi.fieldName, CD_MethodHandle);
+ cob.aload(0)
+ .aload(3)
+ .loadConstant(mi.desc)
+ .invokevirtual(CD_MethodHandle, "asType", MTD_MethodHandle_MethodType)
+ .putfield(proxyDesc, mi.fieldName, CD_MethodHandle);
}
// complete
@@ -426,26 +423,26 @@ private static byte[] createTemplate(ClassLoader loader, ClassDesc proxyDesc, Cl
clb.withMethodBody(ENSURE_ORIGINAL_LOOKUP, MTD_void_Lookup, ACC_PRIVATE | ACC_STATIC, cob -> {
var failLabel = cob.newLabel();
// check lookupClass
- cob.aload(0);
- cob.invokevirtual(CD_MethodHandles_Lookup, "lookupClass", MTD_Class);
- cob.loadConstant(proxyDesc);
- cob.if_acmpne(failLabel);
- // check original access
- cob.aload(0);
- cob.invokevirtual(CD_MethodHandles_Lookup, "lookupModes", MTD_int);
- cob.loadConstant(Lookup.ORIGINAL);
- cob.iand();
- cob.ifeq(failLabel);
- // success
- cob.return_();
- // throw exception
- cob.labelBinding(failLabel);
- cob.new_(CD_IllegalAccessException);
- cob.dup();
- cob.aload(0); // lookup
- cob.invokevirtual(CD_Object, "toString", MTD_String);
- cob.invokespecial(CD_IllegalAccessException, INIT_NAME, MTD_void_String);
- cob.athrow();
+ cob.aload(0)
+ .invokevirtual(CD_MethodHandles_Lookup, "lookupClass", MTD_Class)
+ .loadConstant(proxyDesc)
+ .if_acmpne(failLabel)
+ // check original access
+ .aload(0)
+ .invokevirtual(CD_MethodHandles_Lookup, "lookupModes", MTD_int)
+ .loadConstant(Lookup.ORIGINAL)
+ .iand()
+ .ifeq(failLabel)
+ // success
+ .return_()
+ // throw exception
+ .labelBinding(failLabel)
+ .new_(CD_IllegalAccessException)
+ .dup()
+ .aload(0) // lookup
+ .invokevirtual(CD_Object, "toString", MTD_String)
+ .invokespecial(CD_IllegalAccessException, INIT_NAME, MTD_void_String)
+ .athrow();
});
// implementation methods
@@ -454,14 +451,14 @@ private static byte[] createTemplate(ClassLoader loader, ClassDesc proxyDesc, Cl
clb.withMethodBody(methodName, mi.desc, ACC_PUBLIC, cob -> cob
.trying(bcb -> {
// return this.handleField.invokeExact(arguments...);
- bcb.aload(0);
- bcb.getfield(proxyDesc, mi.fieldName, CD_MethodHandle);
+ bcb.aload(0)
+ .getfield(proxyDesc, mi.fieldName, CD_MethodHandle);
for (int j = 0; j < mi.desc.parameterCount(); j++) {
bcb.loadLocal(TypeKind.from(mi.desc.parameterType(j)),
bcb.parameterSlot(j));
}
- bcb.invokevirtual(CD_MethodHandle, "invokeExact", mi.desc);
- bcb.return_(TypeKind.from(mi.desc.returnType()));
+ bcb.invokevirtual(CD_MethodHandle, "invokeExact", mi.desc)
+ .return_(TypeKind.from(mi.desc.returnType()));
}, ctb -> ctb
// catch (Error | RuntimeException | Declared ex) { throw ex; }
.catchingMulti(mi.thrown, CodeBuilder::athrow)
diff --git a/src/java.base/share/classes/java/lang/package-info.java b/src/java.base/share/classes/java/lang/package-info.java
index 0484ecb2952..9ca4482c819 100644
--- a/src/java.base/share/classes/java/lang/package-info.java
+++ b/src/java.base/share/classes/java/lang/package-info.java
@@ -29,8 +29,8 @@
* Object}, which is the root of the class hierarchy, and {@link
* Class}, instances of which represent classes at run time.
*
- * Frequently it is necessary to represent a value of primitive
- * type as if it were an object.The {@index
+ * Frequently it is necessary to represent a
+ * value of primitive type as if it were an object.The {@index
* "wrapper classes"} {@link Boolean}, {@link Byte}, {@link
* Character}, {@link Short}, {@link Integer}, {@link Long}, {@link
* Float}, and {@link Double} serve this purpose. An object of type
diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java
index 06d716c5434..087b3b5ac06 100644
--- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java
+++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java
@@ -29,7 +29,6 @@
import java.lang.classfile.CodeBuilder;
import java.lang.constant.ClassDesc;
import java.lang.constant.ConstantDesc;
-import java.lang.constant.ConstantDescs;
import java.lang.constant.MethodTypeDesc;
import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite;
@@ -55,6 +54,7 @@
import jdk.internal.misc.PreviewFeatures;
import jdk.internal.vm.annotation.Stable;
+import static java.lang.constant.ConstantDescs.*;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
import java.util.Arrays;
@@ -86,15 +86,15 @@ private SwitchBootstraps() {}
private static final ClassDesc CD_Objects = ReferenceClassDescImpl.ofValidated("Ljava/util/Objects;");
private static final MethodTypeDesc CHECK_INDEX_DESCRIPTOR =
- MethodTypeDescImpl.ofValidated(ConstantDescs.CD_int, ConstantDescs.CD_int, ConstantDescs.CD_int);
- private static final MethodTypeDesc MTD_TYPE_SWITCH = MethodTypeDescImpl.ofValidated(ConstantDescs.CD_int,
- ConstantDescs.CD_Object,
- ConstantDescs.CD_int);
- private static final MethodTypeDesc MTD_TYPE_SWITCH_EXTRA = MethodTypeDescImpl.ofValidated(ConstantDescs.CD_int,
- ConstantDescs.CD_Object,
- ConstantDescs.CD_int,
+ MethodTypeDescImpl.ofValidated(CD_int, CD_int, CD_int);
+ private static final MethodTypeDesc MTD_TYPE_SWITCH = MethodTypeDescImpl.ofValidated(CD_int,
+ CD_Object,
+ CD_int);
+ private static final MethodTypeDesc MTD_TYPE_SWITCH_EXTRA = MethodTypeDescImpl.ofValidated(CD_int,
+ CD_Object,
+ CD_int,
CD_BiPredicate,
- ConstantDescs.CD_List);
+ CD_List);
private static final MethodType MT_TYPE_SWITCH_EXTRA = MethodType.methodType(int.class,
Object.class,
int.class,
@@ -484,19 +484,19 @@ private static Consumer generateTypeSwitchSkeleton(Class> selecto
return cb -> {
// Objects.checkIndex(RESTART_IDX, labelConstants + 1)
- cb.iload(RESTART_IDX);
- cb.loadConstant(labelConstants.length + 1);
- cb.invokestatic(CD_Objects, "checkIndex", CHECK_INDEX_DESCRIPTOR);
- cb.pop();
- cb.aload(SELECTOR_OBJ);
+ cb.iload(RESTART_IDX)
+ .loadConstant(labelConstants.length + 1)
+ .invokestatic(CD_Objects, "checkIndex", CHECK_INDEX_DESCRIPTOR)
+ .pop()
+ .aload(SELECTOR_OBJ);
Label nonNullLabel = cb.newLabel();
- cb.ifnonnull(nonNullLabel);
- cb.iconst_m1();
- cb.ireturn();
- cb.labelBinding(nonNullLabel);
+ cb.ifnonnull(nonNullLabel)
+ .iconst_m1()
+ .ireturn()
+ .labelBinding(nonNullLabel);
if (labelConstants.length == 0) {
cb.loadConstant(0)
- .ireturn();
+ .ireturn();
return;
}
cb.iload(RESTART_IDX);
@@ -535,132 +535,132 @@ private static Consumer generateTypeSwitchSkeleton(Class> selecto
if (!selectorType.isPrimitive() && !Wrapper.isWrapperNumericOrBooleanType(selectorType)) {
// Object o = ...
// o instanceof Wrapped(float)
- cb.aload(SELECTOR_OBJ);
- cb.instanceOf(Wrapper.forBasicType(classLabel).wrapperClassDescriptor());
- cb.ifeq(next);
+ cb.aload(SELECTOR_OBJ)
+ .instanceOf(Wrapper.forBasicType(classLabel).wrapperClassDescriptor())
+ .ifeq(next);
} else if (!unconditionalExactnessCheck(Wrapper.asPrimitiveType(selectorType), classLabel)) {
// Integer i = ... or int i = ...
// o instanceof float
Label notNumber = cb.newLabel();
- cb.aload(SELECTOR_OBJ);
- cb.instanceOf(ConstantDescs.CD_Number);
+ cb.aload(SELECTOR_OBJ)
+ .instanceOf(CD_Number);
if (selectorType == long.class || selectorType == float.class || selectorType == double.class ||
selectorType == Long.class || selectorType == Float.class || selectorType == Double.class) {
cb.ifeq(next);
} else {
cb.ifeq(notNumber);
}
- cb.aload(SELECTOR_OBJ);
- cb.checkcast(ConstantDescs.CD_Number);
+ cb.aload(SELECTOR_OBJ)
+ .checkcast(CD_Number);
if (selectorType == long.class || selectorType == Long.class) {
- cb.invokevirtual(ConstantDescs.CD_Number,
+ cb.invokevirtual(CD_Number,
"longValue",
- MethodTypeDesc.of(ConstantDescs.CD_long));
+ MethodTypeDesc.of(CD_long));
} else if (selectorType == float.class || selectorType == Float.class) {
- cb.invokevirtual(ConstantDescs.CD_Number,
+ cb.invokevirtual(CD_Number,
"floatValue",
- MethodTypeDesc.of(ConstantDescs.CD_float));
+ MethodTypeDesc.of(CD_float));
} else if (selectorType == double.class || selectorType == Double.class) {
- cb.invokevirtual(ConstantDescs.CD_Number,
+ cb.invokevirtual(CD_Number,
"doubleValue",
- MethodTypeDesc.of(ConstantDescs.CD_double));
+ MethodTypeDesc.of(CD_double));
} else {
Label compare = cb.newLabel();
- cb.invokevirtual(ConstantDescs.CD_Number,
+ cb.invokevirtual(CD_Number,
"intValue",
- MethodTypeDesc.of(ConstantDescs.CD_int));
- cb.goto_(compare);
- cb.labelBinding(notNumber);
- cb.aload(SELECTOR_OBJ);
- cb.instanceOf(ConstantDescs.CD_Character);
- cb.ifeq(next);
- cb.aload(SELECTOR_OBJ);
- cb.checkcast(ConstantDescs.CD_Character);
- cb.invokevirtual(ConstantDescs.CD_Character,
+ MethodTypeDesc.of(CD_int))
+ .goto_(compare)
+ .labelBinding(notNumber)
+ .aload(SELECTOR_OBJ)
+ .instanceOf(CD_Character)
+ .ifeq(next)
+ .aload(SELECTOR_OBJ)
+ .checkcast(CD_Character)
+ .invokevirtual(CD_Character,
"charValue",
- MethodTypeDesc.of(ConstantDescs.CD_char));
- cb.labelBinding(compare);
+ MethodTypeDesc.of(CD_char))
+ .labelBinding(compare);
}
TypePairs typePair = TypePairs.of(Wrapper.asPrimitiveType(selectorType), classLabel);
String methodName = TypePairs.typePairToName.get(typePair);
cb.invokestatic(referenceClassDesc(ExactConversionsSupport.class),
methodName,
- MethodTypeDesc.of(ConstantDescs.CD_boolean, classDesc(typePair.from)));
- cb.ifeq(next);
+ MethodTypeDesc.of(CD_boolean, classDesc(typePair.from)))
+ .ifeq(next);
}
} else {
Optional classLabelConstableOpt = classLabel.describeConstable();
if (classLabelConstableOpt.isPresent()) {
- cb.aload(SELECTOR_OBJ);
- cb.instanceOf(classLabelConstableOpt.orElseThrow());
- cb.ifeq(next);
+ cb.aload(SELECTOR_OBJ)
+ .instanceOf(classLabelConstableOpt.orElseThrow())
+ .ifeq(next);
} else {
- cb.aload(EXTRA_CLASS_LABELS);
- cb.loadConstant(extraClassLabels.size());
- cb.invokeinterface(ConstantDescs.CD_List,
+ cb.aload(EXTRA_CLASS_LABELS)
+ .loadConstant(extraClassLabels.size())
+ .invokeinterface(CD_List,
"get",
- MethodTypeDesc.of(ConstantDescs.CD_Object,
- ConstantDescs.CD_int));
- cb.checkcast(ConstantDescs.CD_Class);
- cb.aload(SELECTOR_OBJ);
- cb.invokevirtual(ConstantDescs.CD_Class,
+ MethodTypeDesc.of(CD_Object,
+ CD_int))
+ .checkcast(CD_Class)
+ .aload(SELECTOR_OBJ)
+ .invokevirtual(CD_Class,
"isInstance",
- MethodTypeDesc.of(ConstantDescs.CD_boolean,
- ConstantDescs.CD_Object));
- cb.ifeq(next);
+ MethodTypeDesc.of(CD_boolean,
+ CD_Object))
+ .ifeq(next);
extraClassLabels.add(classLabel);
}
}
} else if (caseLabel instanceof EnumDesc> enumLabel) {
int enumIdx = enumDescs.size();
enumDescs.add(enumLabel);
- cb.aload(ENUM_CACHE);
- cb.loadConstant(enumIdx);
- cb.invokestatic(ConstantDescs.CD_Integer,
+ cb.aload(ENUM_CACHE)
+ .loadConstant(enumIdx)
+ .invokestatic(CD_Integer,
"valueOf",
- MethodTypeDesc.of(ConstantDescs.CD_Integer,
- ConstantDescs.CD_int));
- cb.aload(SELECTOR_OBJ);
- cb.invokeinterface(CD_BiPredicate,
+ MethodTypeDesc.of(CD_Integer,
+ CD_int))
+ .aload(SELECTOR_OBJ)
+ .invokeinterface(CD_BiPredicate,
"test",
- MethodTypeDesc.of(ConstantDescs.CD_boolean,
- ConstantDescs.CD_Object,
- ConstantDescs.CD_Object));
- cb.ifeq(next);
+ MethodTypeDesc.of(CD_boolean,
+ CD_Object,
+ CD_Object))
+ .ifeq(next);
} else if (caseLabel instanceof String stringLabel) {
- cb.ldc(stringLabel);
- cb.aload(SELECTOR_OBJ);
- cb.invokevirtual(ConstantDescs.CD_Object,
+ cb.ldc(stringLabel)
+ .aload(SELECTOR_OBJ)
+ .invokevirtual(CD_Object,
"equals",
- MethodTypeDesc.of(ConstantDescs.CD_boolean,
- ConstantDescs.CD_Object));
- cb.ifeq(next);
+ MethodTypeDesc.of(CD_boolean,
+ CD_Object))
+ .ifeq(next);
} else if (caseLabel instanceof Integer integerLabel) {
Label compare = cb.newLabel();
Label notNumber = cb.newLabel();
- cb.aload(SELECTOR_OBJ);
- cb.instanceOf(ConstantDescs.CD_Number);
- cb.ifeq(notNumber);
- cb.aload(SELECTOR_OBJ);
- cb.checkcast(ConstantDescs.CD_Number);
- cb.invokevirtual(ConstantDescs.CD_Number,
+ cb.aload(SELECTOR_OBJ)
+ .instanceOf(CD_Number)
+ .ifeq(notNumber)
+ .aload(SELECTOR_OBJ)
+ .checkcast(CD_Number)
+ .invokevirtual(CD_Number,
"intValue",
- MethodTypeDesc.of(ConstantDescs.CD_int));
- cb.goto_(compare);
- cb.labelBinding(notNumber);
- cb.aload(SELECTOR_OBJ);
- cb.instanceOf(ConstantDescs.CD_Character);
- cb.ifeq(next);
- cb.aload(SELECTOR_OBJ);
- cb.checkcast(ConstantDescs.CD_Character);
- cb.invokevirtual(ConstantDescs.CD_Character,
+ MethodTypeDesc.of(CD_int))
+ .goto_(compare)
+ .labelBinding(notNumber)
+ .aload(SELECTOR_OBJ)
+ .instanceOf(CD_Character)
+ .ifeq(next)
+ .aload(SELECTOR_OBJ)
+ .checkcast(CD_Character)
+ .invokevirtual(CD_Character,
"charValue",
- MethodTypeDesc.of(ConstantDescs.CD_char));
- cb.labelBinding(compare);
+ MethodTypeDesc.of(CD_char))
+ .labelBinding(compare)
- cb.loadConstant(integerLabel);
- cb.if_icmpne(next);
+ .loadConstant(integerLabel)
+ .if_icmpne(next);
} else if ((caseLabel instanceof Long ||
caseLabel instanceof Float ||
caseLabel instanceof Double ||
@@ -674,23 +674,23 @@ private static Consumer generateTypeSwitchSkeleton(Class> selecto
cb.invokestatic(caseLabelWrapper.wrapperClassDescriptor(),
"valueOf",
MethodTypeDesc.of(caseLabelWrapper.wrapperClassDescriptor(),
- caseLabelWrapper.basicClassDescriptor()));
- cb.aload(SELECTOR_OBJ);
- cb.invokevirtual(ConstantDescs.CD_Object,
+ caseLabelWrapper.basicClassDescriptor()))
+ .aload(SELECTOR_OBJ)
+ .invokevirtual(CD_Object,
"equals",
- MethodTypeDesc.of(ConstantDescs.CD_boolean,
- ConstantDescs.CD_Object));
- cb.ifeq(next);
+ MethodTypeDesc.of(CD_boolean,
+ CD_Object))
+ .ifeq(next);
} else {
throw new InternalError("Unsupported label type: " +
caseLabel.getClass());
}
- cb.loadConstant(idx);
- cb.ireturn();
+ cb.loadConstant(idx)
+ .ireturn();
}
- cb.labelBinding(dflt);
- cb.loadConstant(labelConstants.length);
- cb.ireturn();
+ cb.labelBinding(dflt)
+ .loadConstant(labelConstants.length)
+ .ireturn();
};
}
diff --git a/src/java.base/share/classes/java/util/ArrayList.java b/src/java.base/share/classes/java/util/ArrayList.java
index bcf7b79e780..c00b130a553 100644
--- a/src/java.base/share/classes/java/util/ArrayList.java
+++ b/src/java.base/share/classes/java/util/ArrayList.java
@@ -1808,6 +1808,7 @@ private void replaceAllRange(UnaryOperator operator, int i, int end) {
@Override
public void sort(Comparator super E> c) {
sortRange(c, 0, size);
+ modCount++;
}
@SuppressWarnings("unchecked")
@@ -1816,7 +1817,6 @@ private void sortRange(Comparator super E> c, int fromIndex, int toIndex) {
Arrays.sort((E[]) elementData, fromIndex, toIndex, c);
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
- modCount++;
}
void checkInvariants() {
diff --git a/src/java.base/share/classes/java/util/Currency.java b/src/java.base/share/classes/java/util/Currency.java
index 14d1cf4351d..b11b774e614 100644
--- a/src/java.base/share/classes/java/util/Currency.java
+++ b/src/java.base/share/classes/java/util/Currency.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2024, Oracle and/or its affiliates. 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
@@ -108,7 +108,7 @@
* with {@code Currency} or monetary values as it provides better handling of floating
* point numbers and their operations.
*
- * @spec http://www.iso.org/iso/home/standards/currency_codes.htm ISO - ISO 4217 - Currency codes
+ * @spec https://www.iso.org/iso-4217-currency-codes.html ISO - ISO 4217 - Currency codes
* @see java.math.BigDecimal
* @since 1.4
*/
diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java
index 73132b81c09..5550d399a7f 100644
--- a/src/java.base/share/classes/java/util/Locale.java
+++ b/src/java.base/share/classes/java/util/Locale.java
@@ -2324,12 +2324,11 @@ public String getDisplayName(Locale inLocale) {
// If we cannot get the message format pattern, then we use a simple
// hard-coded pattern. This should not occur in practice unless the
// installation is missing some core files (FormatData etc.).
- StringBuilder result = new StringBuilder();
- result.append((String)displayNames[1]);
- if (displayNames.length > 2) {
- result.append(" (");
- result.append((String)displayNames[2]);
- result.append(')');
+ StringBuilder result = new StringBuilder((String) displayNames[1]);
+ if (displayNames[2] != null) {
+ result.append(" (")
+ .append((String) displayNames[2])
+ .append(')');
}
return result.toString();
}
diff --git a/src/java.base/share/classes/java/util/zip/ZipEntry.java b/src/java.base/share/classes/java/util/zip/ZipEntry.java
index 243779a7c49..b7ecd1bea8f 100644
--- a/src/java.base/share/classes/java/util/zip/ZipEntry.java
+++ b/src/java.base/share/classes/java/util/zip/ZipEntry.java
@@ -564,20 +564,20 @@ void setExtra0(byte[] extra, boolean doZIP64, boolean isLOC) {
// be the magic value and it "accidentally" has some
// bytes in extra match the id.
if (sz >= 16) {
- size = get64(extra, off);
- csize = get64(extra, off + 8);
+ size = get64S(extra, off);
+ csize = get64S(extra, off + 8);
}
} else {
// CEN extra zip64
if (size == ZIP64_MAGICVAL) {
if (off + 8 > len) // invalid zip64 extra
break; // fields, just skip
- size = get64(extra, off);
+ size = get64S(extra, off);
}
if (csize == ZIP64_MAGICVAL) {
if (off + 16 > len) // invalid zip64 extra
break; // fields, just skip
- csize = get64(extra, off + 8);
+ csize = get64S(extra, off + 8);
}
}
}
@@ -588,15 +588,15 @@ void setExtra0(byte[] extra, boolean doZIP64, boolean isLOC) {
int pos = off + 4; // reserved 4 bytes
if (get16(extra, pos) != 0x0001 || get16(extra, pos + 2) != 24)
break;
- long wtime = get64(extra, pos + 4);
+ long wtime = get64S(extra, pos + 4);
if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
mtime = winTimeToFileTime(wtime);
}
- wtime = get64(extra, pos + 12);
+ wtime = get64S(extra, pos + 12);
if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
atime = winTimeToFileTime(wtime);
}
- wtime = get64(extra, pos + 20);
+ wtime = get64S(extra, pos + 20);
if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
ctime = winTimeToFileTime(wtime);
}
diff --git a/src/java.base/share/classes/java/util/zip/ZipError.java b/src/java.base/share/classes/java/util/zip/ZipError.java
index 2aa37bef010..933cc447091 100644
--- a/src/java.base/share/classes/java/util/zip/ZipError.java
+++ b/src/java.base/share/classes/java/util/zip/ZipError.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2024, Oracle and/or its affiliates. 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
@@ -28,9 +28,12 @@
/**
* Signals that an unrecoverable error has occurred.
*
+ * @deprecated ZipError is no longer used and is obsolete.
+ * {@link ZipException} should be used instead.
* @author Dave Bristor
* @since 1.6
*/
+@Deprecated(since="24", forRemoval = true)
public class ZipError extends InternalError {
@java.io.Serial
private static final long serialVersionUID = 853973422266861979L;
diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java
index 43b2261f1c6..21b9593c017 100644
--- a/src/java.base/share/classes/java/util/zip/ZipFile.java
+++ b/src/java.base/share/classes/java/util/zip/ZipFile.java
@@ -411,13 +411,10 @@ public InputStream getInputStream(ZipEntry entry) throws IOException {
case DEFLATED:
// Inflater likes a bit of slack
// MORE: Compute good size for inflater stream:
- long size = CENLEN(zsrc.cen, pos) + 2;
+ long size = CENSIZ(zsrc.cen, pos);
if (size > 65536) {
size = 8192;
}
- if (size <= 0) {
- size = 4096;
- }
InputStream is = new ZipFileInflaterInputStream(in, res, (int) size);
synchronized (istreams) {
istreams.add(is);
@@ -906,21 +903,21 @@ private void checkZIP64(byte[] cen, int cenpos) {
if (size == ZIP64_MAGICVAL) {
if (sz < 8 || (off + 8) > end)
break;
- size = get64(cen, off);
+ size = get64S(cen, off);
sz -= 8;
off += 8;
}
if (rem == ZIP64_MAGICVAL) {
if (sz < 8 || (off + 8) > end)
break;
- rem = get64(cen, off);
+ rem = get64S(cen, off);
sz -= 8;
off += 8;
}
if (pos == ZIP64_MAGICVAL) {
if (sz < 8 || (off + 8) > end)
break;
- pos = get64(cen, off);
+ pos = get64S(cen, off);
sz -= 8;
off += 8;
}
@@ -1239,12 +1236,12 @@ private int checkAndAddEntry(int pos, int index)
int nlen = CENNAM(cen, pos);
int elen = CENEXT(cen, pos);
int clen = CENCOM(cen, pos);
- long headerSize = (long)CENHDR + nlen + clen + elen;
+ int headerSize = CENHDR + nlen + clen + elen;
// CEN header size + name length + comment length + extra length
// should not exceed 65,535 bytes per the PKWare APP.NOTE
// 4.4.10, 4.4.11, & 4.4.12. Also check that current CEN header will
// not exceed the length of the CEN array
- if (headerSize > 0xFFFF || pos + headerSize > cen.length) {
+ if (headerSize > 0xFFFF || pos > cen.length - headerSize) {
zerror("invalid CEN header (bad header size)");
}
@@ -1376,7 +1373,7 @@ private void checkZip64ExtraFieldValues(int off, int blockSize, long csize,
// Check the uncompressed size is not negative
if (size == ZIP64_MAGICVAL) {
if ( blockSize >= Long.BYTES) {
- if (get64(cen, off) < 0) {
+ if (get64S(cen, off) < 0) {
zerror("Invalid zip64 extra block size value");
}
off += Long.BYTES;
@@ -1388,7 +1385,7 @@ private void checkZip64ExtraFieldValues(int off, int blockSize, long csize,
// Check the compressed size is not negative
if (csize == ZIP64_MAGICVAL) {
if (blockSize >= Long.BYTES) {
- if (get64(cen, off) < 0) {
+ if (get64S(cen, off) < 0) {
zerror("Invalid zip64 extra block compressed size value");
}
off += Long.BYTES;
@@ -1400,7 +1397,7 @@ private void checkZip64ExtraFieldValues(int off, int blockSize, long csize,
// Check the LOC offset is not negative
if (locoff == ZIP64_MAGICVAL) {
if (blockSize >= Long.BYTES) {
- if (get64(cen, off) < 0) {
+ if (get64S(cen, off) < 0) {
zerror("Invalid zip64 extra block LOC OFFSET value");
}
// Note: We do not need to adjust the following fields as
@@ -1608,7 +1605,7 @@ private final int readAt(byte[] buf, int off, int len, long pos)
private static class End {
- int centot; // 4 bytes
+ long centot; // 4 bytes
long cenlen; // 4 bytes
long cenoff; // 4 bytes
long endpos; // 4 bytes
@@ -1641,10 +1638,7 @@ private End findEND() throws IOException {
}
// Now scan the block backwards for END header signature
for (int i = buf.length - ENDHDR; i >= 0; i--) {
- if (buf[i+0] == (byte)'P' &&
- buf[i+1] == (byte)'K' &&
- buf[i+2] == (byte)'\005' &&
- buf[i+3] == (byte)'\006') {
+ if (get32(buf, i) == ENDSIG) {
// Found ENDSIG header
byte[] endbuf = Arrays.copyOfRange(buf, i, i + ENDHDR);
end.centot = ENDTOT(endbuf);
@@ -1664,9 +1658,9 @@ private End findEND() throws IOException {
if (cenpos < 0 ||
locpos < 0 ||
readFullyAt(sbuf, 0, sbuf.length, cenpos) != 4 ||
- GETSIG(sbuf) != CENSIG ||
+ get32(sbuf, 0) != CENSIG ||
readFullyAt(sbuf, 0, sbuf.length, locpos) != 4 ||
- GETSIG(sbuf) != LOCSIG) {
+ get32(sbuf, 0) != LOCSIG) {
continue;
}
}
@@ -1681,13 +1675,13 @@ private End findEND() throws IOException {
byte[] loc64 = new byte[ZIP64_LOCHDR];
if (end.endpos < ZIP64_LOCHDR ||
readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR)
- != loc64.length || GETSIG(loc64) != ZIP64_LOCSIG) {
+ != loc64.length || get32(loc64, 0) != ZIP64_LOCSIG) {
return end;
}
long end64pos = ZIP64_LOCOFF(loc64);
byte[] end64buf = new byte[ZIP64_ENDHDR];
if (readFullyAt(end64buf, 0, end64buf.length, end64pos)
- != end64buf.length || GETSIG(end64buf) != ZIP64_ENDSIG) {
+ != end64buf.length || get32(end64buf, 0) != ZIP64_ENDSIG) {
return end;
}
// end64 candidate found,
@@ -1703,7 +1697,7 @@ private End findEND() throws IOException {
// to use the end64 values
end.cenlen = cenlen64;
end.cenoff = cenoff64;
- end.centot = (int)centot64; // assume total < 2g
+ end.centot = centot64;
end.endpos = end64pos;
} catch (IOException x) {} // no ZIP64 loc/end
return end;
@@ -1739,11 +1733,14 @@ private void initCEN(int knownTotal) throws IOException {
if (end.cenlen > MAX_CEN_SIZE) {
zerror("invalid END header (central directory size too large)");
}
+ if (end.centot < 0 || end.centot > end.cenlen / CENHDR) {
+ zerror("invalid END header (total entries count too large)");
+ }
cen = this.cen = new byte[(int)end.cenlen];
if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen) {
zerror("read CEN tables failed");
}
- this.total = end.centot;
+ this.total = Math.toIntExact(end.centot);
} else {
cen = this.cen;
this.total = knownTotal;
@@ -1768,18 +1765,18 @@ private void initCEN(int knownTotal) throws IOException {
// Iterate through the entries in the central directory
int idx = 0; // Index into the entries array
int pos = 0;
- int entryPos = CENHDR;
- int limit = cen.length;
manifestNum = 0;
- while (entryPos <= limit) {
+ int limit = cen.length - CENHDR;
+ while (pos <= limit) {
if (idx >= entriesLength) {
// This will only happen if the ZIP file has an incorrect
// ENDTOT field, which usually means it contains more than
// 65535 entries.
- initCEN(countCENHeaders(cen, limit));
+ initCEN(countCENHeaders(cen));
return;
}
+ int entryPos = pos + CENHDR;
// Checks the entry and adds values to entries[idx ... idx+2]
int nlen = checkAndAddEntry(pos, idx);
idx += 3;
@@ -1810,7 +1807,6 @@ private void initCEN(int knownTotal) throws IOException {
}
// skip to the start of the next entry
pos = nextEntryPos(pos, entryPos, nlen);
- entryPos = pos + CENHDR;
}
// Adjust the total entries
@@ -2034,17 +2030,20 @@ private int getMetaVersion(int off, int len) {
/**
* Returns the number of CEN headers in a central directory.
- * Will not throw, even if the ZIP file is corrupt.
*
* @param cen copy of the bytes in a ZIP file's central directory
- * @param size number of bytes in central directory
+ * @throws ZipException if a CEN header exceeds the length of the CEN array
*/
- private static int countCENHeaders(byte[] cen, int size) {
+ private static int countCENHeaders(byte[] cen) throws ZipException {
int count = 0;
- for (int p = 0;
- p + CENHDR <= size;
- p += CENHDR + CENNAM(cen, p) + CENEXT(cen, p) + CENCOM(cen, p))
+ for (int p = 0; p <= cen.length - CENHDR;) {
+ int headerSize = CENHDR + CENNAM(cen, p) + CENEXT(cen, p) + CENCOM(cen, p);
+ if (p > cen.length - headerSize) {
+ zerror("invalid CEN header (bad header size)");
+ }
+ p += headerSize;
count++;
+ }
return count;
}
}
diff --git a/src/java.base/share/classes/java/util/zip/ZipInputStream.java b/src/java.base/share/classes/java/util/zip/ZipInputStream.java
index 5302cf75160..3a433cf5c6d 100644
--- a/src/java.base/share/classes/java/util/zip/ZipInputStream.java
+++ b/src/java.base/share/classes/java/util/zip/ZipInputStream.java
@@ -603,14 +603,14 @@ private void readEnd(ZipEntry e) throws IOException {
long sig = get32(tmpbuf, 0);
if (sig != EXTSIG) { // no EXTSIG present
e.crc = sig;
- e.csize = get64(tmpbuf, ZIP64_EXTSIZ - ZIP64_EXTCRC);
- e.size = get64(tmpbuf, ZIP64_EXTLEN - ZIP64_EXTCRC);
+ e.csize = get64S(tmpbuf, ZIP64_EXTSIZ - ZIP64_EXTCRC);
+ e.size = get64S(tmpbuf, ZIP64_EXTLEN - ZIP64_EXTCRC);
((PushbackInputStream)in).unread(
tmpbuf, ZIP64_EXTHDR - ZIP64_EXTCRC, ZIP64_EXTCRC);
} else {
e.crc = get32(tmpbuf, ZIP64_EXTCRC);
- e.csize = get64(tmpbuf, ZIP64_EXTSIZ);
- e.size = get64(tmpbuf, ZIP64_EXTLEN);
+ e.csize = get64S(tmpbuf, ZIP64_EXTSIZ);
+ e.size = get64S(tmpbuf, ZIP64_EXTLEN);
}
} else {
readFully(tmpbuf, 0, EXTHDR);
diff --git a/src/java.base/share/classes/java/util/zip/ZipUtils.java b/src/java.base/share/classes/java/util/zip/ZipUtils.java
index ab37fc03a56..5b1d896f420 100644
--- a/src/java.base/share/classes/java/util/zip/ZipUtils.java
+++ b/src/java.base/share/classes/java/util/zip/ZipUtils.java
@@ -39,6 +39,7 @@
import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.Unsafe;
+import jdk.internal.util.Preconditions;
class ZipUtils {
@@ -170,7 +171,10 @@ static LocalDateTime javaEpochToLocalDateTime(long time) {
* The bytes are assumed to be in Intel (little-endian) byte order.
*/
public static final int get16(byte[] b, int off) {
- return (b[off] & 0xff) | ((b[off + 1] & 0xff) << 8);
+ Preconditions.checkIndex(off, b.length, Preconditions.AIOOBE_FORMATTER);
+ Preconditions.checkIndex(off + 1, b.length, Preconditions.AIOOBE_FORMATTER);
+ return Short.toUnsignedInt(
+ UNSAFE.getShortUnaligned(b, off + Unsafe.ARRAY_BYTE_BASE_OFFSET, false));
}
/**
@@ -178,15 +182,20 @@ public static final int get16(byte[] b, int off) {
* The bytes are assumed to be in Intel (little-endian) byte order.
*/
public static final long get32(byte[] b, int off) {
- return (get16(b, off) | ((long)get16(b, off+2) << 16)) & 0xffffffffL;
+ Preconditions.checkIndex(off, b.length, Preconditions.AIOOBE_FORMATTER);
+ Preconditions.checkIndex(off + 3, b.length, Preconditions.AIOOBE_FORMATTER);
+ return Integer.toUnsignedLong(
+ UNSAFE.getIntUnaligned(b, off + Unsafe.ARRAY_BYTE_BASE_OFFSET, false));
}
/**
* Fetches signed 64-bit value from byte array at specified offset.
* The bytes are assumed to be in Intel (little-endian) byte order.
*/
- public static final long get64(byte[] b, int off) {
- return get32(b, off) | (get32(b, off+4) << 32);
+ public static final long get64S(byte[] b, int off) {
+ Preconditions.checkIndex(off, b.length, Preconditions.AIOOBE_FORMATTER);
+ Preconditions.checkIndex(off + 7, b.length, Preconditions.AIOOBE_FORMATTER);
+ return UNSAFE.getLongUnaligned(b, off + Unsafe.ARRAY_BYTE_BASE_OFFSET, false);
}
/**
@@ -195,28 +204,9 @@ public static final long get64(byte[] b, int off) {
*
*/
public static final int get32S(byte[] b, int off) {
- return (get16(b, off) | (get16(b, off+2) << 16));
- }
-
- // fields access methods
- static final int CH(byte[] b, int n) {
- return b[n] & 0xff ;
- }
-
- static final int SH(byte[] b, int n) {
- return (b[n] & 0xff) | ((b[n + 1] & 0xff) << 8);
- }
-
- static final long LG(byte[] b, int n) {
- return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL;
- }
-
- static final long LL(byte[] b, int n) {
- return (LG(b, n)) | (LG(b, n + 4) << 32);
- }
-
- static final long GETSIG(byte[] b) {
- return LG(b, 0);
+ Preconditions.checkIndex(off, b.length, Preconditions.AIOOBE_FORMATTER);
+ Preconditions.checkIndex(off + 3, b.length, Preconditions.AIOOBE_FORMATTER);
+ return UNSAFE.getIntUnaligned(b, off + Unsafe.ARRAY_BYTE_BASE_OFFSET, false);
}
/*
@@ -231,56 +221,56 @@ static final long GETSIG(byte[] b) {
// local file (LOC) header fields
- static final long LOCSIG(byte[] b) { return LG(b, 0); } // signature
- static final int LOCVER(byte[] b) { return SH(b, 4); } // version needed to extract
- static final int LOCFLG(byte[] b) { return SH(b, 6); } // general purpose bit flags
- static final int LOCHOW(byte[] b) { return SH(b, 8); } // compression method
- static final long LOCTIM(byte[] b) { return LG(b, 10);} // modification time
- static final long LOCCRC(byte[] b) { return LG(b, 14);} // crc of uncompressed data
- static final long LOCSIZ(byte[] b) { return LG(b, 18);} // compressed data size
- static final long LOCLEN(byte[] b) { return LG(b, 22);} // uncompressed data size
- static final int LOCNAM(byte[] b) { return SH(b, 26);} // filename length
- static final int LOCEXT(byte[] b) { return SH(b, 28);} // extra field length
+ static final long LOCSIG(byte[] b) { return get32(b, 0); } // signature
+ static final int LOCVER(byte[] b) { return get16(b, 4); } // version needed to extract
+ static final int LOCFLG(byte[] b) { return get16(b, 6); } // general purpose bit flags
+ static final int LOCHOW(byte[] b) { return get16(b, 8); } // compression method
+ static final long LOCTIM(byte[] b) { return get32(b, 10);} // modification time
+ static final long LOCCRC(byte[] b) { return get32(b, 14);} // crc of uncompressed data
+ static final long LOCSIZ(byte[] b) { return get32(b, 18);} // compressed data size
+ static final long LOCLEN(byte[] b) { return get32(b, 22);} // uncompressed data size
+ static final int LOCNAM(byte[] b) { return get16(b, 26);} // filename length
+ static final int LOCEXT(byte[] b) { return get16(b, 28);} // extra field length
// extra local (EXT) header fields
- static final long EXTCRC(byte[] b) { return LG(b, 4);} // crc of uncompressed data
- static final long EXTSIZ(byte[] b) { return LG(b, 8);} // compressed size
- static final long EXTLEN(byte[] b) { return LG(b, 12);} // uncompressed size
+ static final long EXTCRC(byte[] b) { return get32(b, 4);} // crc of uncompressed data
+ static final long EXTSIZ(byte[] b) { return get32(b, 8);} // compressed size
+ static final long EXTLEN(byte[] b) { return get32(b, 12);} // uncompressed size
// end of central directory header (END) fields
- static final int ENDSUB(byte[] b) { return SH(b, 8); } // number of entries on this disk
- static final int ENDTOT(byte[] b) { return SH(b, 10);} // total number of entries
- static final long ENDSIZ(byte[] b) { return LG(b, 12);} // central directory size
- static final long ENDOFF(byte[] b) { return LG(b, 16);} // central directory offset
- static final int ENDCOM(byte[] b) { return SH(b, 20);} // size of ZIP file comment
- static final int ENDCOM(byte[] b, int off) { return SH(b, off + 20);}
-
- // zip64 end of central directory recoder fields
- static final long ZIP64_ENDTOD(byte[] b) { return LL(b, 24);} // total number of entries on disk
- static final long ZIP64_ENDTOT(byte[] b) { return LL(b, 32);} // total number of entries
- static final long ZIP64_ENDSIZ(byte[] b) { return LL(b, 40);} // central directory size
- static final long ZIP64_ENDOFF(byte[] b) { return LL(b, 48);} // central directory offset
- static final long ZIP64_LOCOFF(byte[] b) { return LL(b, 8);} // zip64 end offset
+ static final int ENDSUB(byte[] b) { return get16(b, 8); } // number of entries on this disk
+ static final int ENDTOT(byte[] b) { return get16(b, 10);} // total number of entries
+ static final long ENDSIZ(byte[] b) { return get32(b, 12);} // central directory size
+ static final long ENDOFF(byte[] b) { return get32(b, 16);} // central directory offset
+ static final int ENDCOM(byte[] b) { return get16(b, 20);} // size of ZIP file comment
+ static final int ENDCOM(byte[] b, int off) { return get16(b, off + 20);}
+
+ // zip64 end of central directory record fields
+ static final long ZIP64_ENDTOD(byte[] b) { return get64S(b, 24);} // total number of entries on disk
+ static final long ZIP64_ENDTOT(byte[] b) { return get64S(b, 32);} // total number of entries
+ static final long ZIP64_ENDSIZ(byte[] b) { return get64S(b, 40);} // central directory size
+ static final long ZIP64_ENDOFF(byte[] b) { return get64S(b, 48);} // central directory offset
+ static final long ZIP64_LOCOFF(byte[] b) { return get64S(b, 8);} // zip64 end offset
// central directory header (CEN) fields
- static final long CENSIG(byte[] b, int pos) { return LG(b, pos + 0); }
- static final int CENVEM(byte[] b, int pos) { return SH(b, pos + 4); }
- static final int CENVEM_FA(byte[] b, int pos) { return CH(b, pos + 5); } // file attribute compatibility
- static final int CENVER(byte[] b, int pos) { return SH(b, pos + 6); }
- static final int CENFLG(byte[] b, int pos) { return SH(b, pos + 8); }
- static final int CENHOW(byte[] b, int pos) { return SH(b, pos + 10);}
- static final long CENTIM(byte[] b, int pos) { return LG(b, pos + 12);}
- static final long CENCRC(byte[] b, int pos) { return LG(b, pos + 16);}
- static final long CENSIZ(byte[] b, int pos) { return LG(b, pos + 20);}
- static final long CENLEN(byte[] b, int pos) { return LG(b, pos + 24);}
- static final int CENNAM(byte[] b, int pos) { return SH(b, pos + 28);}
- static final int CENEXT(byte[] b, int pos) { return SH(b, pos + 30);}
- static final int CENCOM(byte[] b, int pos) { return SH(b, pos + 32);}
- static final int CENDSK(byte[] b, int pos) { return SH(b, pos + 34);}
- static final int CENATT(byte[] b, int pos) { return SH(b, pos + 36);}
- static final long CENATX(byte[] b, int pos) { return LG(b, pos + 38);}
- static final int CENATX_PERMS(byte[] b, int pos) { return SH(b, pos + 40);} // posix permission data
- static final long CENOFF(byte[] b, int pos) { return LG(b, pos + 42);}
+ static final long CENSIG(byte[] b, int pos) { return get32(b, pos + 0); }
+ static final int CENVEM(byte[] b, int pos) { return get16(b, pos + 4); }
+ static final int CENVEM_FA(byte[] b, int pos) { return Byte.toUnsignedInt(b[pos + 5]); } // file attribute compatibility
+ static final int CENVER(byte[] b, int pos) { return get16(b, pos + 6); }
+ static final int CENFLG(byte[] b, int pos) { return get16(b, pos + 8); }
+ static final int CENHOW(byte[] b, int pos) { return get16(b, pos + 10);}
+ static final long CENTIM(byte[] b, int pos) { return get32(b, pos + 12);}
+ static final long CENCRC(byte[] b, int pos) { return get32(b, pos + 16);}
+ static final long CENSIZ(byte[] b, int pos) { return get32(b, pos + 20);}
+ static final long CENLEN(byte[] b, int pos) { return get32(b, pos + 24);}
+ static final int CENNAM(byte[] b, int pos) { return get16(b, pos + 28);}
+ static final int CENEXT(byte[] b, int pos) { return get16(b, pos + 30);}
+ static final int CENCOM(byte[] b, int pos) { return get16(b, pos + 32);}
+ static final int CENDSK(byte[] b, int pos) { return get16(b, pos + 34);}
+ static final int CENATT(byte[] b, int pos) { return get16(b, pos + 36);}
+ static final long CENATX(byte[] b, int pos) { return get32(b, pos + 38);}
+ static final int CENATX_PERMS(byte[] b, int pos) { return get16(b, pos + 40);} // posix permission data
+ static final long CENOFF(byte[] b, int pos) { return get32(b, pos + 42);}
// The END header is followed by a variable length comment of size < 64k.
static final long END_MAXLEN = 0xFFFF + ENDHDR;
@@ -293,16 +283,16 @@ static void loadLibrary() {
jdk.internal.loader.BootLoader.loadLibrary("zip");
}
- private static final Unsafe unsafe = Unsafe.getUnsafe();
+ private static final Unsafe UNSAFE = Unsafe.getUnsafe();
- private static final long byteBufferArrayOffset = unsafe.objectFieldOffset(ByteBuffer.class, "hb");
- private static final long byteBufferOffsetOffset = unsafe.objectFieldOffset(ByteBuffer.class, "offset");
+ private static final long byteBufferArrayOffset = UNSAFE.objectFieldOffset(ByteBuffer.class, "hb");
+ private static final long byteBufferOffsetOffset = UNSAFE.objectFieldOffset(ByteBuffer.class, "offset");
static byte[] getBufferArray(ByteBuffer byteBuffer) {
- return (byte[]) unsafe.getReference(byteBuffer, byteBufferArrayOffset);
+ return (byte[]) UNSAFE.getReference(byteBuffer, byteBufferArrayOffset);
}
static int getBufferOffset(ByteBuffer byteBuffer) {
- return unsafe.getInt(byteBuffer, byteBufferOffsetOffset);
+ return UNSAFE.getInt(byteBuffer, byteBufferOffsetOffset);
}
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java
index d3258427937..6b77f6ff1ad 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java
@@ -801,7 +801,12 @@ public TypeKind typeKind() {
@Override
public void writeTo(DirectCodeBuilder writer) {
- writer.writeLocalVar(op, slot);
+ var op = this.op;
+ if (op.sizeIfFixed() == 1) {
+ writer.writeBytecode(op);
+ } else {
+ writer.writeLocalVar(op, slot);
+ }
}
@Override
@@ -832,7 +837,12 @@ public TypeKind typeKind() {
@Override
public void writeTo(DirectCodeBuilder writer) {
- writer.writeLocalVar(op, slot);
+ var op = this.op;
+ if (op.sizeIfFixed() == 1) {
+ writer.writeBytecode(op);
+ } else {
+ writer.writeLocalVar(op, slot);
+ }
}
@Override
@@ -1061,7 +1071,7 @@ public boolean isInterface() {
@Override
public int count() {
return op == Opcode.INVOKEINTERFACE
- ? Util.parameterSlots(Util.methodTypeSymbol(methodEntry.nameAndType())) + 1
+ ? Util.parameterSlots(Util.methodTypeSymbol(methodEntry.type())) + 1
: 0;
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java
index 1d8d298857a..447e7e25c45 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java
@@ -246,66 +246,69 @@ private void inflate() {
this.contentHash = hash;
charLen = rawLen;
state = State.BYTE;
+ } else {
+ inflateNonAscii(singleBytes, hash);
}
- else {
- char[] chararr = new char[rawLen];
- int chararr_count = singleBytes;
- // Inflate prefix of bytes to characters
- JLA.inflateBytesToChars(rawBytes, offset, chararr, 0, singleBytes);
-
- int px = offset + singleBytes;
- int utfend = offset + rawLen;
- while (px < utfend) {
- int c = (int) rawBytes[px] & 0xff;
- switch (c >> 4) {
- case 0, 1, 2, 3, 4, 5, 6, 7: {
- // 0xxx xxxx
- px++;
- chararr[chararr_count++] = (char) c;
- hash = 31 * hash + c;
- break;
+ }
+
+ private void inflateNonAscii(int singleBytes, int hash) {
+ char[] chararr = new char[rawLen];
+ int chararr_count = singleBytes;
+ // Inflate prefix of bytes to characters
+ JLA.inflateBytesToChars(rawBytes, offset, chararr, 0, singleBytes);
+
+ int px = offset + singleBytes;
+ int utfend = offset + rawLen;
+ while (px < utfend) {
+ int c = (int) rawBytes[px] & 0xff;
+ switch (c >> 4) {
+ case 0, 1, 2, 3, 4, 5, 6, 7: {
+ // 0xxx xxxx
+ px++;
+ chararr[chararr_count++] = (char) c;
+ hash = 31 * hash + c;
+ break;
+ }
+ case 12, 13: {
+ // 110x xxxx 10xx xxxx
+ px += 2;
+ if (px > utfend) {
+ throw malformedInput(utfend);
}
- case 12, 13: {
- // 110x xxxx 10xx xxxx
- px += 2;
- if (px > utfend) {
- throw malformedInput(utfend);
- }
- int char2 = rawBytes[px - 1];
- if ((char2 & 0xC0) != 0x80) {
- throw malformedInput(px);
- }
- char v = (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
- chararr[chararr_count++] = v;
- hash = 31 * hash + v;
- break;
+ int char2 = rawBytes[px - 1];
+ if ((char2 & 0xC0) != 0x80) {
+ throw malformedInput(px);
}
- case 14: {
- // 1110 xxxx 10xx xxxx 10xx xxxx
- px += 3;
- if (px > utfend) {
- throw malformedInput(utfend);
- }
- int char2 = rawBytes[px - 2];
- int char3 = rawBytes[px - 1];
- if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) {
- throw malformedInput(px - 1);
- }
- char v = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | (char3 & 0x3F));
- chararr[chararr_count++] = v;
- hash = 31 * hash + v;
- break;
+ char v = (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
+ chararr[chararr_count++] = v;
+ hash = 31 * hash + v;
+ break;
+ }
+ case 14: {
+ // 1110 xxxx 10xx xxxx 10xx xxxx
+ px += 3;
+ if (px > utfend) {
+ throw malformedInput(utfend);
}
- default:
- // 10xx xxxx, 1111 xxxx
- throw malformedInput(px);
+ int char2 = rawBytes[px - 2];
+ int char3 = rawBytes[px - 1];
+ if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) {
+ throw malformedInput(px - 1);
+ }
+ char v = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | (char3 & 0x3F));
+ chararr[chararr_count++] = v;
+ hash = 31 * hash + v;
+ break;
}
+ default:
+ // 10xx xxxx, 1111 xxxx
+ throw malformedInput(px);
}
- this.contentHash = hash;
- charLen = chararr_count;
- this.chars = chararr;
- state = State.CHAR;
}
+ this.contentHash = hash;
+ charLen = chararr_count;
+ this.chars = chararr;
+ state = State.CHAR;
}
private ConstantPoolException malformedInput(int px) {
@@ -461,14 +464,13 @@ public boolean equalsString(String s) {
@Override
void writeTo(BufWriterImpl pool) {
- pool.writeU1(TAG_UTF8);
if (rawBytes != null) {
- pool.writeU2(rawLen);
+ pool.writeU1U2(TAG_UTF8, rawLen);
pool.writeBytes(rawBytes, offset, rawLen);
}
else {
// state == STRING and no raw bytes
- pool.writeUTF(stringValue);
+ pool.writeUtfEntry(stringValue);
}
}
@@ -502,8 +504,7 @@ public T ref1() {
}
void writeTo(BufWriterImpl pool) {
- pool.writeU1(tag());
- pool.writeU2(ref1.index());
+ pool.writeU1U2(tag(), ref1.index());
}
@Override
@@ -532,9 +533,7 @@ public U ref2() {
}
void writeTo(BufWriterImpl pool) {
- pool.writeU1(tag());
- pool.writeU2(ref1.index());
- pool.writeU2(ref2.index());
+ pool.writeU1U2U2(tag(), ref1.index(), ref2.index());
}
@Override
@@ -864,9 +863,7 @@ public NameAndTypeEntryImpl nameAndType() {
}
void writeTo(BufWriterImpl pool) {
- pool.writeU1(tag());
- pool.writeU2(bsmIndex);
- pool.writeU2(nameAndType.index());
+ pool.writeU1U2U2(tag(), bsmIndex, nameAndType.index());
}
@Override
@@ -984,9 +981,7 @@ public DirectMethodHandleDesc asSymbol() {
@Override
void writeTo(BufWriterImpl pool) {
- pool.writeU1(TAG_METHOD_HANDLE);
- pool.writeU1(refKind);
- pool.writeU2(reference.index());
+ pool.writeU1U1U2(TAG_METHOD_HANDLE, refKind, reference.index());
}
@Override
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java
index e33012ef183..02f6167d436 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java
@@ -315,8 +315,7 @@ public static void writeTypeAnnotation(BufWriterImpl buf, TypeAnnotation ta) {
case TypeAnnotation.TypeParameterTarget tpt -> buf.writeU1(tpt.typeParameterIndex());
case TypeAnnotation.SupertypeTarget st -> buf.writeU2(st.supertypeIndex());
case TypeAnnotation.TypeParameterBoundTarget tpbt -> {
- buf.writeU1(tpbt.typeParameterIndex());
- buf.writeU1(tpbt.boundIndex());
+ buf.writeU1U1(tpbt.typeParameterIndex(), tpbt.boundIndex());
}
case TypeAnnotation.EmptyTarget _ -> {
// nothing to write
@@ -327,9 +326,7 @@ public static void writeTypeAnnotation(BufWriterImpl buf, TypeAnnotation ta) {
buf.writeU2(lvt.table().size());
for (var e : lvt.table()) {
int startPc = labelToBci(lr, e.startLabel(), ta);
- buf.writeU2(startPc);
- buf.writeU2(labelToBci(lr, e.endLabel(), ta) - startPc);
- buf.writeU2(e.index());
+ buf.writeU2U2U2(startPc, labelToBci(lr, e.endLabel(), ta) - startPc, e.index());
}
}
case TypeAnnotation.CatchTarget ct -> buf.writeU2(ct.exceptionTableIndex());
@@ -343,8 +340,7 @@ public static void writeTypeAnnotation(BufWriterImpl buf, TypeAnnotation ta) {
// target_path
buf.writeU1(ta.targetPath().size());
for (TypeAnnotation.TypePathComponent component : ta.targetPath()) {
- buf.writeU1(component.typePathKind().tag());
- buf.writeU1(component.typeArgumentIndex());
+ buf.writeU1U1(component.typePathKind().tag(), component.typeArgumentIndex());
}
// annotation data
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java
index fb9ecc98902..6060170a8d1 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java
@@ -24,14 +24,15 @@
*/
package jdk.internal.classfile.impl;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Arrays;
import java.lang.classfile.Attribute;
import java.lang.classfile.AttributeMapper;
public class AttributeHolder {
- private final List> attributes = new ArrayList<>();
+ private static final Attribute>[] EMPTY_ATTRIBUTE_ARRAY = {};
+ private int attributesCount = 0;
+ private Attribute>[] attributes = EMPTY_ATTRIBUTE_ARRAY;
public > void withAttribute(Attribute> a) {
if (a == null)
@@ -39,36 +40,54 @@ public > void withAttribute(Attribute> a) {
@SuppressWarnings("unchecked")
AttributeMapper am = (AttributeMapper) a.attributeMapper();
- if (!am.allowMultiple() && isPresent(am)) {
- remove(am);
+ int attributesCount = this.attributesCount;
+ var attributes = this.attributes;
+ if (!am.allowMultiple()) {
+ // remove if
+ for (int i = attributesCount - 1; i >= 0; i--) {
+ if (attributes[i].attributeMapper() == am) {
+ attributesCount--;
+ System.arraycopy(attributes, i + 1, attributes, i, attributesCount - i);
+ }
+ }
}
- attributes.add(a);
+
+ // add attribute
+ if (attributesCount >= attributes.length) {
+ int newCapacity = attributesCount + 4;
+ this.attributes = attributes = Arrays.copyOf(attributes, newCapacity);
+ }
+ attributes[attributesCount] = a;
+ this.attributesCount = attributesCount + 1;
}
public int size() {
- return attributes.size();
+ return attributesCount;
}
public void writeTo(BufWriterImpl buf) {
- Util.writeAttributes(buf, attributes);
+ int attributesCount = this.attributesCount;
+ buf.writeU2(attributesCount);
+ for (int i = 0; i < attributesCount; i++) {
+ Util.writeAttribute(buf, attributes[i]);
+ }
}
@SuppressWarnings("unchecked")
> A get(AttributeMapper am) {
- for (Attribute> a : attributes)
+ for (int i = 0; i < attributesCount; i++) {
+ Attribute> a = attributes[i];
if (a.attributeMapper() == am)
- return (A)a;
+ return (A) a;
+ }
return null;
}
boolean isPresent(AttributeMapper> am) {
- for (Attribute> a : attributes)
- if (a.attributeMapper() == am)
+ for (int i = 0; i < attributesCount; i++) {
+ if (attributes[i].attributeMapper() == am)
return true;
+ }
return false;
}
-
- private void remove(AttributeMapper> am) {
- attributes.removeIf(a -> a.attributeMapper() == am);
- }
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java
index 4cc6c205fe4..cf5b98dafb1 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java
@@ -38,6 +38,10 @@
import jdk.internal.access.SharedSecrets;
import jdk.internal.vm.annotation.ForceInline;
+import static java.lang.classfile.constantpool.PoolEntry.TAG_UTF8;
+import static jdk.internal.util.ModifiedUtf.putChar;
+import static jdk.internal.util.ModifiedUtf.utfLen;
+
public final class BufWriterImpl implements BufWriter {
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
@@ -111,6 +115,83 @@ public void writeU2(int x) {
this.offset = offset + 2;
}
+ @ForceInline
+ public void writeU1U1(int x1, int x2) {
+ reserveSpace(2);
+ byte[] elems = this.elems;
+ int offset = this.offset;
+ elems[offset ] = (byte) x1;
+ elems[offset + 1] = (byte) x2;
+ this.offset = offset + 2;
+ }
+
+ public void writeU1U2(int u1, int u2) {
+ reserveSpace(3);
+ byte[] elems = this.elems;
+ int offset = this.offset;
+ elems[offset ] = (byte) u1;
+ elems[offset + 1] = (byte) (u2 >> 8);
+ elems[offset + 2] = (byte) u2;
+ this.offset = offset + 3;
+ }
+
+ public void writeU1U1U1(int x1, int x2, int x3) {
+ reserveSpace(3);
+ byte[] elems = this.elems;
+ int offset = this.offset;
+ elems[offset ] = (byte) x1;
+ elems[offset + 1] = (byte) x2;
+ elems[offset + 2] = (byte) x3;
+ this.offset = offset + 3;
+ }
+
+ public void writeU1U1U2(int x1, int x2, int x3) {
+ reserveSpace(4);
+ byte[] elems = this.elems;
+ int offset = this.offset;
+ elems[offset ] = (byte) x1;
+ elems[offset + 1] = (byte) x2;
+ elems[offset + 2] = (byte) (x3 >> 8);
+ elems[offset + 3] = (byte) x3;
+ this.offset = offset + 4;
+ }
+
+ public void writeU1U2U2(int x1, int x2, int x3) {
+ reserveSpace(5);
+ byte[] elems = this.elems;
+ int offset = this.offset;
+ elems[offset ] = (byte) x1;
+ elems[offset + 1] = (byte) (x2 >> 8);
+ elems[offset + 2] = (byte) x2;
+ elems[offset + 3] = (byte) (x3 >> 8);
+ elems[offset + 4] = (byte) x3;
+ this.offset = offset + 5;
+ }
+
+ public void writeU2U2(int x1, int x2) {
+ reserveSpace(4);
+ byte[] elems = this.elems;
+ int offset = this.offset;
+ elems[offset ] = (byte) (x1 >> 8);
+ elems[offset + 1] = (byte) x1;
+ elems[offset + 2] = (byte) (x2 >> 8);
+ elems[offset + 3] = (byte) x2;
+ this.offset = offset + 4;
+ }
+
+ public void writeU2U2U2(int x1, int x2, int x3) {
+ reserveSpace(6);
+ byte[] elems = this.elems;
+ int offset = this.offset;
+ elems[offset ] = (byte) (x1 >> 8);
+ elems[offset + 1] = (byte) x1;
+ elems[offset + 2] = (byte) (x2 >> 8);
+ elems[offset + 3] = (byte) x2;
+ elems[offset + 4] = (byte) (x3 >> 8);
+ elems[offset + 5] = (byte) x3;
+ this.offset = offset + 6;
+ }
+
@Override
public void writeInt(int x) {
reserveSpace(4);
@@ -159,46 +240,28 @@ public void writeBytes(BufWriterImpl other) {
}
@SuppressWarnings("deprecation")
- void writeUTF(String str) {
+ void writeUtfEntry(String str) {
int strlen = str.length();
int countNonZeroAscii = JLA.countNonZeroAscii(str);
- int utflen = strlen;
- if (countNonZeroAscii != strlen) {
- for (int i = countNonZeroAscii; i < strlen; i++) {
- int c = str.charAt(i);
- if (c >= 0x80 || c == 0)
- utflen += (c >= 0x800) ? 2 : 1;
- }
- }
+ int utflen = utfLen(str, countNonZeroAscii);
if (utflen > 65535) {
throw new IllegalArgumentException("string too long");
}
- reserveSpace(utflen + 2);
+ reserveSpace(utflen + 3);
int offset = this.offset;
byte[] elems = this.elems;
- elems[offset ] = (byte) (utflen >> 8);
- elems[offset + 1] = (byte) utflen;
- offset += 2;
+ elems[offset ] = (byte) TAG_UTF8;
+ elems[offset + 1] = (byte) (utflen >> 8);
+ elems[offset + 2] = (byte) utflen;
+ offset += 3;
str.getBytes(0, countNonZeroAscii, elems, offset);
offset += countNonZeroAscii;
- for (int i = countNonZeroAscii; i < strlen; ++i) {
- char c = str.charAt(i);
- if (c >= '\001' && c <= '\177') {
- elems[offset++] = (byte) c;
- } else if (c > '\u07FF') {
- elems[offset ] = (byte) (0xE0 | c >> 12 & 0xF);
- elems[offset + 1] = (byte) (0x80 | c >> 6 & 0x3F);
- elems[offset + 2] = (byte) (0x80 | c & 0x3F);
- offset += 3;
- } else {
- elems[offset ] = (byte) (0xC0 | c >> 6 & 0x1F);
- elems[offset + 1] = (byte) (0x80 | c & 0x3F);
- offset += 2;
- }
+ for (int i = countNonZeroAscii; i < strlen; i++) {
+ offset = putChar(elems, offset, str.charAt(i));
}
this.offset = offset;
@@ -285,13 +348,21 @@ public void copyTo(byte[] array, int bufferOffset) {
// writeIndex methods ensure that any CP info written
// is relative to the correct constant pool
- @ForceInline
- @Override
- public void writeIndex(PoolEntry entry) {
+ public int cpIndex(PoolEntry entry) {
int idx = AbstractPoolEntry.maybeClone(constantPool, entry).index();
if (idx < 1 || idx > Character.MAX_VALUE)
throw invalidIndex(idx, entry);
- writeU2(idx);
+ return idx;
+ }
+
+ @ForceInline
+ @Override
+ public void writeIndex(PoolEntry entry) {
+ writeU2(cpIndex(entry));
+ }
+
+ public void writeIndex(int bytecode, PoolEntry entry) {
+ writeU1U2(bytecode, cpIndex(entry));
}
static IllegalArgumentException invalidIndex(int idx, PoolEntry entry) {
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java
index 6994a62c0ab..bca80c1ed4b 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java
@@ -88,9 +88,9 @@ public static Opcode aload(int slot) {
case 2 -> Opcode.ALOAD_2;
case 3 -> Opcode.ALOAD_3;
default -> {
- if ((slot & 0xFF) == slot)
+ if ((slot & ~0xFF) == 0)
yield Opcode.ALOAD;
- if ((slot & 0xFFFF) == slot)
+ if ((slot & ~0xFFFF) == 0)
yield Opcode.ALOAD_W;
throw slotOutOfBounds(slot);
}
@@ -104,9 +104,9 @@ public static Opcode fload(int slot) {
case 2 -> Opcode.FLOAD_2;
case 3 -> Opcode.FLOAD_3;
default -> {
- if ((slot & 0xFF) == slot)
+ if ((slot & ~0xFF) == 0)
yield Opcode.FLOAD;
- if ((slot & 0xFFFF) == slot)
+ if ((slot & ~0xFFFF) == 0)
yield Opcode.FLOAD_W;
throw slotOutOfBounds(slot);
}
@@ -120,9 +120,9 @@ public static Opcode dload(int slot) {
case 2 -> Opcode.DLOAD_2;
case 3 -> Opcode.DLOAD_3;
default -> {
- if ((slot & 0xFF) == slot)
+ if ((slot & ~0xFF) == 0)
yield Opcode.DLOAD;
- if ((slot & 0xFFFF) == slot)
+ if ((slot & ~0xFFFF) == 0)
yield Opcode.DLOAD_W;
throw slotOutOfBounds(slot);
}
@@ -136,9 +136,9 @@ public static Opcode lload(int slot) {
case 2 -> Opcode.LLOAD_2;
case 3 -> Opcode.LLOAD_3;
default -> {
- if ((slot & 0xFF) == slot)
+ if ((slot & ~0xFF) == 0)
yield Opcode.LLOAD;
- if ((slot & 0xFFFF) == slot)
+ if ((slot & ~0xFFFF) == 0)
yield Opcode.LLOAD_W;
throw slotOutOfBounds(slot);
}
@@ -152,9 +152,9 @@ public static Opcode iload(int slot) {
case 2 -> Opcode.ILOAD_2;
case 3 -> Opcode.ILOAD_3;
default -> {
- if ((slot & 0xFF) == slot)
+ if ((slot & ~0xFF) == 0)
yield Opcode.ILOAD;
- if ((slot & 0xFFFF) == slot)
+ if ((slot & ~0xFFFF) == 0)
yield Opcode.ILOAD_W;
throw slotOutOfBounds(slot);
}
@@ -180,9 +180,9 @@ public static Opcode astore(int slot) {
case 2 -> Opcode.ASTORE_2;
case 3 -> Opcode.ASTORE_3;
default -> {
- if ((slot & 0xFF) == slot)
+ if ((slot & ~0xFF) == 0)
yield Opcode.ASTORE;
- if ((slot & 0xFFFF) == slot)
+ if ((slot & ~0xFFFF) == 0)
yield Opcode.ASTORE_W;
throw slotOutOfBounds(slot);
}
@@ -196,9 +196,9 @@ public static Opcode fstore(int slot) {
case 2 -> Opcode.FSTORE_2;
case 3 -> Opcode.FSTORE_3;
default -> {
- if ((slot & 0xFF) == slot)
+ if ((slot & ~0xFF) == 0)
yield Opcode.FSTORE;
- if ((slot & 0xFFFF) == slot)
+ if ((slot & ~0xFFFF) == 0)
yield Opcode.FSTORE_W;
throw slotOutOfBounds(slot);
}
@@ -212,9 +212,9 @@ public static Opcode dstore(int slot) {
case 2 -> Opcode.DSTORE_2;
case 3 -> Opcode.DSTORE_3;
default -> {
- if ((slot & 0xFF) == slot)
+ if ((slot & ~0xFF) == 0)
yield Opcode.DSTORE;
- if ((slot & 0xFFFF) == slot)
+ if ((slot & ~0xFFFF) == 0)
yield Opcode.DSTORE_W;
throw slotOutOfBounds(slot);
}
@@ -228,9 +228,9 @@ public static Opcode lstore(int slot) {
case 2 -> Opcode.LSTORE_2;
case 3 -> Opcode.LSTORE_3;
default -> {
- if ((slot & 0xFF) == slot)
+ if ((slot & ~0xFF) == 0)
yield Opcode.LSTORE;
- if ((slot & 0xFFFF) == slot)
+ if ((slot & ~0xFFFF) == 0)
yield Opcode.LSTORE_W;
throw slotOutOfBounds(slot);
}
@@ -244,9 +244,9 @@ public static Opcode istore(int slot) {
case 2 -> Opcode.ISTORE_2;
case 3 -> Opcode.ISTORE_3;
default -> {
- if ((slot & 0xFF) == slot)
+ if ((slot & ~0xFF) == 0)
yield Opcode.ISTORE;
- if ((slot & 0xFFFF) == slot)
+ if ((slot & ~0xFFFF) == 0)
yield Opcode.ISTORE_W;
throw slotOutOfBounds(slot);
}
@@ -264,6 +264,11 @@ public static Opcode returnOpcode(TypeKind tk) {
};
}
+ public static int returnBytecode(TypeKind tk) {
+ int kind = Math.max(0, tk.ordinal() - 4); // BYTE, SHORT, CHAR, BOOLEAN becomes INT
+ return IRETURN + kind;
+ }
+
public static Opcode arrayLoadOpcode(TypeKind tk) {
return switch (tk) {
case BYTE, BOOLEAN -> Opcode.BALOAD;
@@ -278,6 +283,20 @@ public static Opcode arrayLoadOpcode(TypeKind tk) {
};
}
+ public static int arrayLoadBytecode(TypeKind tk) {
+ return switch (tk) {
+ case BYTE, BOOLEAN -> BALOAD;
+ case SHORT -> SALOAD;
+ case INT -> IALOAD;
+ case FLOAT -> FALOAD;
+ case LONG -> LALOAD;
+ case DOUBLE -> DALOAD;
+ case REFERENCE -> AALOAD;
+ case CHAR -> CALOAD;
+ case VOID -> throw new IllegalArgumentException("void not an allowable array type");
+ };
+ }
+
public static Opcode arrayStoreOpcode(TypeKind tk) {
return switch (tk) {
case BYTE, BOOLEAN -> Opcode.BASTORE;
@@ -292,6 +311,20 @@ public static Opcode arrayStoreOpcode(TypeKind tk) {
};
}
+ public static int arrayStoreBytecode(TypeKind tk) {
+ return switch (tk) {
+ case BYTE, BOOLEAN -> BASTORE;
+ case SHORT -> SASTORE;
+ case INT -> IASTORE;
+ case FLOAT -> FASTORE;
+ case LONG -> LASTORE;
+ case DOUBLE -> DASTORE;
+ case REFERENCE -> AASTORE;
+ case CHAR -> CASTORE;
+ case VOID -> throw new IllegalArgumentException("void not an allowable array type");
+ };
+ }
+
public static Opcode reverseBranchOpcode(Opcode op) {
return switch (op) {
case IFEQ -> Opcode.IFNE;
@@ -314,6 +347,29 @@ public static Opcode reverseBranchOpcode(Opcode op) {
};
}
+ public static int reverseBranchOpcode(int bytecode) {
+ return switch (bytecode) {
+ case IFEQ -> IFNE;
+ case IFNE -> IFEQ;
+ case IFLT -> IFGE;
+ case IFGE -> IFLT;
+ case IFGT -> IFLE;
+ case IFLE -> IFGT;
+ case IF_ICMPEQ -> IF_ICMPNE;
+ case IF_ICMPNE -> IF_ICMPEQ;
+ case IF_ICMPLT -> IF_ICMPGE;
+ case IF_ICMPGE -> IF_ICMPLT;
+ case IF_ICMPGT -> IF_ICMPLE;
+ case IF_ICMPLE -> IF_ICMPGT;
+ case IF_ACMPEQ -> IF_ACMPNE;
+ case IF_ACMPNE -> IF_ACMPEQ;
+ case IFNULL -> IFNONNULL;
+ case IFNONNULL -> IFNULL;
+ default -> throw new IllegalArgumentException(
+ String.format("Wrong opcode kind specified; found %d, expected %s", bytecode, Opcode.Kind.BRANCH));
+ };
+ }
+
public static Opcode convertOpcode(TypeKind from, TypeKind to) {
return switch (from) {
case INT ->
@@ -377,20 +433,20 @@ public static TypeKind convertToType(Opcode opcode) {
public static void validateSlot(Opcode opcode, int slot, boolean load) {
int size = opcode.sizeIfFixed();
if (size == 1 && slot == (load ? intrinsicLoadSlot(opcode) : intrinsicStoreSlot(opcode)) ||
- size == 2 && slot == (slot & 0xFF) ||
- size == 4 && slot == (slot & 0xFFFF))
+ size == 2 && (slot & ~0xFF) == 0 ||
+ size == 4 && (slot & ~0xFFFF) == 0)
return;
throw slotOutOfBounds(opcode, slot);
}
public static void validateSlot(int slot) {
- if ((slot & 0xFFFF) != slot)
+ if ((slot & ~0xFFFF) != 0)
throw slotOutOfBounds(slot);
}
public static boolean validateAndIsWideIinc(int slot, int val) {
var ret = false;
- if ((slot & 0xFF) != slot) {
+ if ((slot & ~0xFF) != 0) {
validateSlot(slot);
ret = true;
}
@@ -404,8 +460,8 @@ public static boolean validateAndIsWideIinc(int slot, int val) {
}
public static void validateRet(Opcode opcode, int slot) {
- if (opcode == Opcode.RET && slot == (slot & 0xFF) ||
- opcode == Opcode.RET_W && slot == (slot & 0xFFFF))
+ if (opcode == Opcode.RET && (slot & ~0xFF) == 0 ||
+ opcode == Opcode.RET_W && (slot & ~0xFFFF) == 0)
return;
Objects.requireNonNull(opcode);
throw slotOutOfBounds(opcode, slot);
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java
index 2ef39504e9b..0f183ad427f 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java
@@ -353,7 +353,11 @@ private static boolean checkTag(int tag, Class> cls) {
static T checkType(PoolEntry e, int index, Class cls) {
if (cls.isInstance(e)) return cls.cast(e);
- throw new ConstantPoolException("Not a " + cls.getSimpleName() + " at index: " + index);
+ throw checkTypeError(index, cls);
+ }
+
+ private static ConstantPoolException checkTypeError(int index, Class> cls) {
+ return new ConstantPoolException("Not a " + cls.getSimpleName() + " at index: " + index);
}
@Override
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java
index 5f02ae708ea..b599f2b61aa 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, Alibaba Group Holding Limited. 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
@@ -30,6 +31,7 @@
import java.lang.constant.MethodTypeDesc;
import java.lang.reflect.AccessFlag;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
@@ -54,9 +56,13 @@ public final class DirectClassBuilder
/** The value of default class access flags */
static final int DEFAULT_CLASS_FLAGS = ClassFile.ACC_PUBLIC;
+ static final Util.Writable[] EMPTY_WRITABLE_ARRAY = {};
+ static final ClassEntry[] EMPTY_CLASS_ENTRY_ARRAY = {};
final ClassEntry thisClassEntry;
- private final List fields = new ArrayList<>();
- private final List methods = new ArrayList<>();
+ private Util.Writable[] fields = EMPTY_WRITABLE_ARRAY;
+ private Util.Writable[] methods = EMPTY_WRITABLE_ARRAY;
+ private int fieldsCount = 0;
+ private int methodsCount = 0;
private ClassEntry superclassEntry;
private List interfaceEntries;
private int majorVersion;
@@ -137,12 +143,20 @@ public ClassBuilder transformMethod(MethodModel method, MethodTransform transfor
// internal / for use by elements
ClassBuilder withField(Util.Writable field) {
- fields.add(field);
+ if (fieldsCount >= fields.length) {
+ int newCapacity = fieldsCount + 8;
+ this.fields = Arrays.copyOf(fields, newCapacity);
+ }
+ fields[fieldsCount++] = field;
return this;
}
ClassBuilder withMethod(Util.Writable method) {
- methods.add(method);
+ if (methodsCount >= methods.length) {
+ int newCapacity = methodsCount + 8;
+ this.methods = Arrays.copyOf(methods, newCapacity);
+ }
+ methods[methodsCount++] = method;
return this;
}
@@ -184,9 +198,7 @@ public byte[] build() {
else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisClassEntry.asInternalName()))
superclass = constantPool.classEntry(ConstantDescs.CD_Object);
int interfaceEntriesSize = interfaceEntries.size();
- List ies = new ArrayList<>(interfaceEntriesSize);
- for (int i = 0; i < interfaceEntriesSize; i++)
- ies.add(AbstractPoolEntry.maybeClone(constantPool, interfaceEntries.get(i)));
+ ClassEntry[] ies = interfaceEntriesSize == 0 ? EMPTY_CLASS_ENTRY_ARRAY : buildInterfaceEnties(interfaceEntriesSize);
// We maintain two writers, and then we join them at the end
int size = sizeHint == 0 ? 256 : sizeHint;
@@ -195,8 +207,8 @@ else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisC
// The tail consists of fields and methods, and attributes
// This should trigger all the CP/BSM mutation
- Util.writeList(tail, fields);
- Util.writeList(tail, methods);
+ Util.writeList(tail, fields, fieldsCount);
+ Util.writeList(tail, methods, methodsCount);
int attributesOffset = tail.size();
attributes.writeTo(tail);
@@ -211,12 +223,21 @@ else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisC
| ((minorVersion & 0xFFFFL) << 16)
| (majorVersion & 0xFFFFL));
constantPool.writeTo(head);
- head.writeU2(flags);
- head.writeIndex(thisClassEntry);
+ head.writeU2U2(flags, head.cpIndex(thisClassEntry));
head.writeIndexOrZero(superclass);
- Util.writeListIndices(head, ies);
+ head.writeU2(interfaceEntriesSize);
+ for (int i = 0; i < interfaceEntriesSize; i++) {
+ head.writeIndex(ies[i]);
+ }
// Join head and tail into an exact-size buffer
return BufWriterImpl.join(head, tail);
}
+
+ private ClassEntry[] buildInterfaceEnties(int interfaceEntriesSize) {
+ var ies = new ClassEntry[interfaceEntriesSize];
+ for (int i = 0; i < interfaceEntriesSize; i++)
+ ies[i] = AbstractPoolEntry.maybeClone(constantPool, interfaceEntries.get(i));
+ return ies;
+ }
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java
index ee312a97dad..72c37ade9ac 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java
@@ -25,6 +25,8 @@
*/
package jdk.internal.classfile.impl;
+import java.lang.constant.ClassDesc;
+import java.lang.constant.MethodTypeDesc;
import java.lang.classfile.Attribute;
import java.lang.classfile.Attributes;
import java.lang.classfile.ClassFile;
@@ -52,8 +54,8 @@
import java.lang.classfile.instruction.LocalVariable;
import java.lang.classfile.instruction.LocalVariableType;
import java.lang.classfile.instruction.SwitchCase;
-import java.lang.constant.ConstantDesc;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -62,18 +64,27 @@
import java.util.function.Consumer;
import java.util.function.Function;
-import static java.lang.classfile.Opcode.*;
-
import static jdk.internal.classfile.impl.BytecodeHelpers.*;
+import static jdk.internal.classfile.impl.RawBytecodeHelper.*;
public final class DirectCodeBuilder
extends AbstractDirectBuilder
implements TerminalCodeBuilder {
- private final List characterRanges = new ArrayList<>();
+ private static final CharacterRange[] EMPTY_CHARACTER_RANGE = {};
+ private static final DeferredLabel[] EMPTY_LABEL_ARRAY = {};
+ private static final LocalVariable[] EMPTY_LOCAL_VARIABLE_ARRAY = {};
+ private static final LocalVariableType[] EMPTY_LOCAL_VARIABLE_TYPE_ARRAY = {};
+ private static final AbstractPseudoInstruction.ExceptionCatchImpl[] EMPTY_HANDLER_ARRAY = {};
+ private static final DeferredLabel[] EMPTY_DEFERRED_LABEL_ARRAY = {};
+
final List handlers = new ArrayList<>();
- private final List localVariables = new ArrayList<>();
- private final List localVariableTypes = new ArrayList<>();
- private final boolean transformFwdJumps, transformBackJumps;
+ private CharacterRange[] characterRanges = EMPTY_CHARACTER_RANGE;
+ private LocalVariable[] localVariables = EMPTY_LOCAL_VARIABLE_ARRAY;
+ private LocalVariableType[] localVariableTypes = EMPTY_LOCAL_VARIABLE_TYPE_ARRAY;
+ private int characterRangesCount = 0;
+ private int localVariablesCount = 0;
+ private int localVariableTypesCount = 0;
+ private final boolean transformDeferredJumps, transformKnownJumps;
private final Label startLabel, endLabel;
final MethodInfo methodInfo;
final BufWriterImpl bytecodesBufWriter;
@@ -83,7 +94,8 @@ public final class DirectCodeBuilder
private DedupLineNumberTableAttribute lineNumberWriter;
private int topLocal;
- List deferredLabels;
+ private DeferredLabel[] deferredLabels = EMPTY_DEFERRED_LABEL_ARRAY;
+ private int deferredLabelsCount = 0;
/* Locals management
lazily computed maxLocal = -1
@@ -117,12 +129,12 @@ private DirectCodeBuilder(MethodInfo methodInfo,
SplitConstantPool constantPool,
ClassFileImpl context,
CodeModel original,
- boolean transformFwdJumps) {
+ boolean transformDeferredJumps) {
super(constantPool, context);
setOriginal(original);
this.methodInfo = methodInfo;
- this.transformFwdJumps = transformFwdJumps;
- this.transformBackJumps = context.fixShortJumps();
+ this.transformDeferredJumps = transformDeferredJumps;
+ this.transformKnownJumps = context.fixShortJumps();
bytecodesBufWriter = (original instanceof CodeImpl cai) ? new BufWriterImpl(constantPool, context, cai.codeLength())
: new BufWriterImpl(constantPool, context);
this.startLabel = new LabelImpl(this, 0);
@@ -208,9 +220,7 @@ private void writeExceptionHandlers(BufWriterImpl buf, int pos) {
throw new IllegalArgumentException("Unbound label in exception handler");
}
} else {
- buf.writeU2(startPc);
- buf.writeU2(endPc);
- buf.writeU2(handlerPc);
+ buf.writeU2U2U2(startPc, endPc, handlerPc);
buf.writeIndexOrZero(h.catchTypeEntry());
handlersSize++;
}
@@ -227,15 +237,16 @@ private void buildContent() {
processDeferredLabels();
if (context.passDebugElements()) {
- if (!characterRanges.isEmpty()) {
+ if (characterRangesCount > 0) {
Attribute> a = new UnboundAttribute.AdHocAttribute<>(Attributes.characterRangeTable()) {
@Override
public void writeBody(BufWriterImpl b) {
int pos = b.size();
- int crSize = characterRanges.size();
+ int crSize = characterRangesCount;
b.writeU2(crSize);
- for (CharacterRange cr : characterRanges) {
+ for (int i = 0; i < characterRangesCount; i++) {
+ CharacterRange cr = characterRanges[i];
var start = labelToBci(cr.startScope());
var end = labelToBci(cr.endScope());
if (start == -1 || end == -1) {
@@ -245,28 +256,28 @@ public void writeBody(BufWriterImpl b) {
throw new IllegalArgumentException("Unbound label in character range");
}
} else {
- b.writeU2(start);
- b.writeU2(end - 1);
+ b.writeU2U2(start, end - 1);
b.writeInt(cr.characterRangeStart());
b.writeInt(cr.characterRangeEnd());
b.writeU2(cr.flags());
}
}
- if (crSize < characterRanges.size())
+ if (crSize < characterRangesCount)
b.patchU2(pos, crSize);
}
};
attributes.withAttribute(a);
}
- if (!localVariables.isEmpty()) {
+ if (localVariablesCount > 0) {
Attribute> a = new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTable()) {
@Override
public void writeBody(BufWriterImpl b) {
int pos = b.size();
- int lvSize = localVariables.size();
+ int lvSize = localVariablesCount;
b.writeU2(lvSize);
- for (LocalVariable l : localVariables) {
+ for (int i = 0; i < localVariablesCount; i++) {
+ LocalVariable l = localVariables[i];
if (!Util.writeLocalVariable(b, l)) {
if (context.dropDeadLabels()) {
lvSize--;
@@ -275,21 +286,22 @@ public void writeBody(BufWriterImpl b) {
}
}
}
- if (lvSize < localVariables.size())
+ if (lvSize < localVariablesCount)
b.patchU2(pos, lvSize);
}
};
attributes.withAttribute(a);
}
- if (!localVariableTypes.isEmpty()) {
+ if (localVariableTypesCount > 0) {
Attribute> a = new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTypeTable()) {
@Override
public void writeBody(BufWriterImpl b) {
int pos = b.size();
- int lvtSize = localVariableTypes.size();
- b.writeU2(localVariableTypes.size());
- for (LocalVariableType l : localVariableTypes) {
+ int lvtSize = localVariableTypesCount;
+ b.writeU2(lvtSize);
+ for (int i = 0; i < localVariableTypesCount; i++) {
+ LocalVariableType l = localVariableTypes[i];
if (!Util.writeLocalVariable(b, l)) {
if (context.dropDeadLabels()) {
lvtSize--;
@@ -298,7 +310,7 @@ public void writeBody(BufWriterImpl b) {
}
}
}
- if (lvtSize < localVariableTypes.size())
+ if (lvtSize < localVariableTypesCount)
b.patchU2(pos, lvtSize);
}
};
@@ -315,22 +327,20 @@ public void writeBody(BufWriterImpl b) {
private void writeCounters(boolean codeMatch, BufWriterImpl buf) {
if (codeMatch) {
var originalAttribute = (CodeImpl) original;
- buf.writeU2(originalAttribute.maxStack());
- buf.writeU2(originalAttribute.maxLocals());
+ buf.writeU2U2(originalAttribute.maxStack(), originalAttribute.maxLocals());
} else {
StackCounter cntr = StackCounter.of(DirectCodeBuilder.this, buf);
- buf.writeU2(cntr.maxStack());
- buf.writeU2(cntr.maxLocals());
+ buf.writeU2U2(cntr.maxStack(), cntr.maxLocals());
}
}
private void generateStackMaps(BufWriterImpl buf) throws IllegalArgumentException {
//new instance of generator immediately calculates maxStack, maxLocals, all frames,
// patches dead bytecode blocks and removes them from exception table
- StackMapGenerator gen = StackMapGenerator.of(DirectCodeBuilder.this, buf);
- attributes.withAttribute(gen.stackMapTableAttribute());
- buf.writeU2(gen.maxStack());
- buf.writeU2(gen.maxLocals());
+ var dcb = DirectCodeBuilder.this;
+ StackMapGenerator gen = StackMapGenerator.of(dcb, buf);
+ dcb.attributes.withAttribute(gen.stackMapTableAttribute());
+ buf.writeU2U2(gen.maxStack(), gen.maxLocals());
}
private void tryGenerateStackMaps(boolean codeMatch, BufWriterImpl buf) {
@@ -352,20 +362,22 @@ private void tryGenerateStackMaps(boolean codeMatch, BufWriterImpl buf) {
@Override
public void writeBody(BufWriterImpl buf) {
- buf.setLabelContext(DirectCodeBuilder.this);
+ DirectCodeBuilder dcb = DirectCodeBuilder.this;
+ buf.setLabelContext(dcb);
int codeLength = curPc();
if (codeLength == 0 || codeLength >= 65536) {
throw new IllegalArgumentException(String.format(
"Code length %d is outside the allowed range in %s%s",
codeLength,
- methodInfo.methodName().stringValue(),
- methodInfo.methodTypeSymbol().displayDescriptor()));
+ dcb.methodInfo.methodName().stringValue(),
+ dcb.methodInfo.methodTypeSymbol().displayDescriptor()));
}
- if (codeAndExceptionsMatch(codeLength)) {
+ var context = dcb.context;
+ if (dcb.original != null && codeAndExceptionsMatch(codeLength)) {
if (context.stackMapsWhenRequired()) {
- attributes.withAttribute(original.findAttribute(Attributes.stackMapTable()).orElse(null));
+ dcb.attributes.withAttribute(dcb.original.findAttribute(Attributes.stackMapTable()).orElse(null));
writeCounters(true, buf);
} else if (context.generateStackMaps()) {
generateStackMaps(buf);
@@ -383,9 +395,9 @@ public void writeBody(BufWriterImpl buf) {
}
buf.writeInt(codeLength);
- buf.writeBytes(bytecodesBufWriter);
- writeExceptionHandlers(buf);
- attributes.writeTo(buf);
+ buf.writeBytes(dcb.bytecodesBufWriter);
+ dcb.writeExceptionHandlers(buf);
+ dcb.attributes.writeTo(buf);
buf.setLabelContext(null);
}
};
@@ -405,8 +417,7 @@ public DedupLineNumberTableAttribute(ConstantPoolBuilder constantPool, ClassFile
private void push() {
//subsequent identical line numbers are skipped
if (lastPc >= 0 && lastLine != writtenLine) {
- buf.writeU2(lastPc);
- buf.writeU2(lastLine);
+ buf.writeU2U2(lastPc, lastLine);
writtenLine = lastLine;
}
}
@@ -456,32 +467,16 @@ private boolean codeAndExceptionsMatch(int codeLength) {
private record DeferredLabel(int labelPc, int size, int instructionPc, Label label) { }
- private void writeLabelOffset(int nBytes, int instructionPc, Label label) {
- int targetBci = labelToBci(label);
- if (targetBci == -1) {
- int pc = bytecodesBufWriter.skip(nBytes);
- if (deferredLabels == null)
- deferredLabels = new ArrayList<>();
- deferredLabels.add(new DeferredLabel(pc, nBytes, instructionPc, label));
- }
- else {
- int branchOffset = targetBci - instructionPc;
- if (nBytes == 2 && (short)branchOffset != branchOffset) throw new LabelOverflowException();
- bytecodesBufWriter.writeIntBytes(nBytes, branchOffset);
- }
- }
-
private void processDeferredLabels() {
- if (deferredLabels != null) {
- for (DeferredLabel dl : deferredLabels) {
- int branchOffset = labelToBci(dl.label) - dl.instructionPc;
- if (dl.size == 2) {
- if ((short)branchOffset != branchOffset) throw new LabelOverflowException();
- bytecodesBufWriter.patchU2(dl.labelPc, branchOffset);
- } else {
- assert dl.size == 4;
- bytecodesBufWriter.patchInt(dl.labelPc, branchOffset);
- }
+ for (int i = 0; i < deferredLabelsCount; i++) {
+ DeferredLabel dl = deferredLabels[i];
+ int branchOffset = labelToBci(dl.label) - dl.instructionPc;
+ if (dl.size == 2) {
+ if ((short) branchOffset != branchOffset) throw new LabelOverflowException();
+ bytecodesBufWriter.patchU2(dl.labelPc, branchOffset);
+ } else {
+ assert dl.size == 4;
+ bytecodesBufWriter.patchInt(dl.labelPc, branchOffset);
}
}
}
@@ -489,72 +484,140 @@ private void processDeferredLabels() {
// Instruction writing
public void writeBytecode(Opcode opcode) {
+ assert !opcode.isWide();
+ bytecodesBufWriter.writeU1(opcode.bytecode());
+ }
+
+ // Instruction version, refer to opcode
+ public void writeLocalVar(Opcode opcode, int slot) {
if (opcode.isWide()) {
- bytecodesBufWriter.writeU2(opcode.bytecode());
+ bytecodesBufWriter.writeU2U2(opcode.bytecode(), slot);
} else {
- bytecodesBufWriter.writeU1(opcode.bytecode());
+ bytecodesBufWriter.writeU1U1(opcode.bytecode(), slot);
}
}
- public void writeLocalVar(Opcode opcode, int localVar) {
- writeBytecode(opcode);
- switch (opcode.sizeIfFixed()) {
- case 1 -> { }
- case 2 -> bytecodesBufWriter.writeU1(localVar);
- case 4 -> bytecodesBufWriter.writeU2(localVar);
- default -> throw new IllegalArgumentException("Unexpected instruction size: " + opcode);
+ // Shortcut version, refer to and validate slot
+ private void writeLocalVar(int bytecode, int slot) {
+ // TODO validation like (slot & 0xFFFF) == slot
+ if (slot < 256) {
+ bytecodesBufWriter.writeU1U1(bytecode, slot);
+ } else {
+ bytecodesBufWriter.writeU1U1U2(WIDE, bytecode, slot);
}
}
public void writeIncrement(boolean wide, int slot, int val) {
if (wide) {
- bytecodesBufWriter.writeU1(RawBytecodeHelper.WIDE);
- }
- bytecodesBufWriter.writeU1(RawBytecodeHelper.IINC);
- if (wide) {
- bytecodesBufWriter.writeU2(slot);
- bytecodesBufWriter.writeU2(val);
+ bytecodesBufWriter.writeU2U2U2((WIDE << 8) | IINC, slot, val);
} else {
- bytecodesBufWriter.writeU1(slot);
- bytecodesBufWriter.writeU1(val);
+ bytecodesBufWriter.writeU1U1U1(IINC, slot, val);
}
}
public void writeBranch(Opcode op, Label target) {
+ if (op.sizeIfFixed() == 3) {
+ writeShortJump(op.bytecode(), target);
+ } else {
+ writeLongJump(op.bytecode(), target);
+ }
+ }
+
+ private void writeLongLabelOffset(int instructionPc, Label label) {
+ int targetBci = labelToBci(label);
+
+ // algebraic union of jump | (instructionPc, target), distinguished by null == target.
+ int jumpOrInstructionPc;
+ Label nullOrTarget;
+ if (targetBci == -1) {
+ jumpOrInstructionPc = instructionPc;
+ nullOrTarget = label;
+ } else {
+ jumpOrInstructionPc = targetBci - instructionPc;
+ nullOrTarget = null;
+ }
+
+ writeParsedLongLabel(jumpOrInstructionPc, nullOrTarget);
+ }
+
+ private void writeShortJump(int bytecode, Label target) {
int instructionPc = curPc();
int targetBci = labelToBci(target);
+
+ // algebraic union of jump | (instructionPc, target), distinguished by null == target.
+ int jumpOrInstructionPc;
+ Label nullOrTarget;
+ if (targetBci == -1) {
+ jumpOrInstructionPc = instructionPc;
+ nullOrTarget = target;
+ } else {
+ jumpOrInstructionPc = targetBci - instructionPc;
+ nullOrTarget = null;
+ }
+
//transform short-opcode forward jumps if enforced, and backward jumps if enabled and overflowing
- if (op.sizeIfFixed() == 3 && (targetBci == -1
- ? transformFwdJumps
- : (transformBackJumps
- && targetBci - instructionPc < Short.MIN_VALUE))) {
- if (op == GOTO) {
- writeBytecode(GOTO_W);
- writeLabelOffset(4, instructionPc, target);
- } else if (op == JSR) {
- writeBytecode(JSR_W);
- writeLabelOffset(4, instructionPc, target);
+ if (transformDeferredJumps || transformKnownJumps && nullOrTarget == null && jumpOrInstructionPc < Short.MIN_VALUE) {
+ fixShortJump(bytecode, jumpOrInstructionPc, nullOrTarget);
+ } else {
+ bytecodesBufWriter.writeU1(bytecode);
+ writeParsedShortLabel(jumpOrInstructionPc, nullOrTarget);
+ }
+ }
+
+ private void writeLongJump(int bytecode, Label target) {
+ int instructionPc = curPc();
+ bytecodesBufWriter.writeU1(bytecode);
+ writeLongLabelOffset(instructionPc, target);
+ }
+
+ private void fixShortJump(int bytecode, int jumpOrInstructionPc, Label nullOrTarget) {
+ if (bytecode == GOTO) {
+ bytecodesBufWriter.writeU1(GOTO_W);
+ writeParsedLongLabel(jumpOrInstructionPc, nullOrTarget);
+ } else if (bytecode == JSR) {
+ bytecodesBufWriter.writeU1(JSR_W);
+ writeParsedLongLabel(jumpOrInstructionPc, nullOrTarget);
+ } else {
+ bytecodesBufWriter.writeU1U2(
+ BytecodeHelpers.reverseBranchOpcode(bytecode), // u1
+ 8); // u1 + s2 + u1 + s4 // s2
+ bytecodesBufWriter.writeU1(GOTO_W); // u1
+ if (nullOrTarget == null) {
+ jumpOrInstructionPc -= 3; // jump -= 3;
} else {
- writeBytecode(BytecodeHelpers.reverseBranchOpcode(op));
- Label bypassJump = newLabel();
- writeLabelOffset(2, instructionPc, bypassJump);
- writeBytecode(GOTO_W);
- writeLabelOffset(4, instructionPc + 3, target);
- labelBinding(bypassJump);
+ jumpOrInstructionPc += 3; // instructionPc += 3;
}
+ writeParsedLongLabel(jumpOrInstructionPc, nullOrTarget); // s4
+ }
+ }
+
+ private void writeParsedShortLabel(int jumpOrInstructionPc, Label nullOrTarget) {
+ if (nullOrTarget == null) {
+ if ((short) jumpOrInstructionPc != jumpOrInstructionPc)
+ throw new LabelOverflowException();
+ bytecodesBufWriter.writeU2(jumpOrInstructionPc);
} else {
- writeBytecode(op);
- writeLabelOffset(op.sizeIfFixed() == 3 ? 2 : 4, instructionPc, target);
+ int pc = bytecodesBufWriter.skip(2);
+ addLabel(new DeferredLabel(pc, 2, jumpOrInstructionPc, nullOrTarget));
+ }
+ }
+
+ private void writeParsedLongLabel(int jumpOrInstructionPc, Label nullOrTarget) {
+ if (nullOrTarget == null) {
+ bytecodesBufWriter.writeInt(jumpOrInstructionPc);
+ } else {
+ int pc = bytecodesBufWriter.skip(4);
+ addLabel(new DeferredLabel(pc, 4, jumpOrInstructionPc, nullOrTarget));
}
}
public void writeLookupSwitch(Label defaultTarget, List cases) {
int instructionPc = curPc();
- writeBytecode(LOOKUPSWITCH);
+ bytecodesBufWriter.writeU1(LOOKUPSWITCH);
int pad = 4 - (curPc() % 4);
if (pad != 4)
bytecodesBufWriter.skip(pad); // padding content can be anything
- writeLabelOffset(4, instructionPc, defaultTarget);
+ writeLongLabelOffset(instructionPc, defaultTarget);
bytecodesBufWriter.writeInt(cases.size());
cases = new ArrayList<>(cases);
cases.sort(new Comparator<>() {
@@ -565,17 +628,18 @@ public int compare(SwitchCase c1, SwitchCase c2) {
});
for (var c : cases) {
bytecodesBufWriter.writeInt(c.caseValue());
- writeLabelOffset(4, instructionPc, c.target());
+ var target = c.target();
+ writeLongLabelOffset(instructionPc, target);
}
}
public void writeTableSwitch(int low, int high, Label defaultTarget, List cases) {
int instructionPc = curPc();
- writeBytecode(TABLESWITCH);
+ bytecodesBufWriter.writeU1(TABLESWITCH);
int pad = 4 - (curPc() % 4);
if (pad != 4)
bytecodesBufWriter.skip(pad); // padding content can be anything
- writeLabelOffset(4, instructionPc, defaultTarget);
+ writeLongLabelOffset(instructionPc, defaultTarget);
bytecodesBufWriter.writeInt(low);
bytecodesBufWriter.writeInt(high);
var caseMap = new HashMap(cases.size());
@@ -583,85 +647,74 @@ public void writeTableSwitch(int low, int high, Label defaultTarget, List 256
+ // rewrite to _W if index is >= 256
int index = AbstractPoolEntry.maybeClone(constantPool, value).index();
- Opcode op = opcode;
if (value instanceof LongEntry || value instanceof DoubleEntry) {
- op = LDC2_W;
+ opcode = Opcode.LDC2_W;
} else if (index >= 256)
- op = LDC_W;
+ opcode = Opcode.LDC_W;
- writeBytecode(op);
- if (op.sizeIfFixed() == 3) {
- bytecodesBufWriter.writeU2(index);
+ assert !opcode.isWide();
+ if (opcode.sizeIfFixed() == 3) {
+ bytecodesBufWriter.writeU1U2(opcode.bytecode(), index);
} else {
- bytecodesBufWriter.writeU1(index);
+ bytecodesBufWriter.writeU1U1(opcode.bytecode(), index);
}
}
@@ -677,7 +730,11 @@ public int labelToBci(Label label) {
if (context == this) {
return lab.getBCI();
}
- else if (context == mruParent) {
+ return labelToBci(context, lab);
+ }
+
+ private int labelToBci(LabelContext context, LabelImpl lab) {
+ if (context == mruParent) {
return mruParentTable[lab.getBCI()] - 1;
}
else if (context instanceof CodeAttribute parent) {
@@ -717,14 +774,18 @@ public void setLabelTarget(Label label) {
@Override
public void setLabelTarget(Label label, int bci) {
LabelImpl lab = (LabelImpl) label;
- LabelContext context = lab.labelContext();
-
- if (context == this) {
+ if (lab.labelContext() == this) {
if (lab.getBCI() != -1)
throw new IllegalArgumentException("Setting label target for already-set label");
lab.setBCI(bci);
+ } else {
+ setLabelTarget(lab, bci);
}
- else if (context == mruParent) {
+ }
+
+ private void setLabelTarget(LabelImpl lab, int bci) {
+ LabelContext context = lab.labelContext();
+ if (context == mruParent) {
mruParentTable[lab.getBCI()] = bci + 1;
}
else if (context instanceof CodeAttribute parent) {
@@ -739,7 +800,7 @@ public int[] apply(CodeAttribute x) {
mruParent = parent;
mruParentTable = table;
- mruParentTable[lab.getBCI()] = bci + 1;
+ table[lab.getBCI()] = bci + 1;
}
else if (context instanceof BufferedCodeBuilder) {
// Hijack the label
@@ -751,7 +812,19 @@ else if (context instanceof BufferedCodeBuilder) {
}
public void addCharacterRange(CharacterRange element) {
- characterRanges.add(element);
+ if (characterRangesCount >= characterRanges.length) {
+ int newCapacity = characterRangesCount + 8;
+ this.characterRanges = Arrays.copyOf(characterRanges, newCapacity);
+ }
+ characterRanges[characterRangesCount++] = element;
+ }
+
+ public void addLabel(DeferredLabel label) {
+ if (deferredLabelsCount >= deferredLabels.length) {
+ int newCapacity = deferredLabelsCount + 8;
+ this.deferredLabels = Arrays.copyOf(deferredLabels, newCapacity);
+ }
+ deferredLabels[deferredLabelsCount++] = label;
}
public void addHandler(ExceptionCatch element) {
@@ -763,11 +836,19 @@ public void addHandler(ExceptionCatch element) {
}
public void addLocalVariable(LocalVariable element) {
- localVariables.add(element);
+ if (localVariablesCount >= localVariables.length) {
+ int newCapacity = localVariablesCount + 8;
+ this.localVariables = Arrays.copyOf(localVariables, newCapacity);
+ }
+ localVariables[localVariablesCount++] = element;
}
public void addLocalVariableType(LocalVariableType element) {
- localVariableTypes.add(element);
+ if (localVariableTypesCount >= localVariableTypes.length) {
+ int newCapacity = localVariableTypesCount + 8;
+ this.localVariableTypes = Arrays.copyOf(localVariableTypes, newCapacity);
+ }
+ localVariableTypes[localVariableTypesCount++] = element;
}
@Override
@@ -788,28 +869,54 @@ public LabelOverflowException() {
// Fast overrides to avoid intermediate instructions
// These are helpful for direct class building
+ @Override
+ public CodeBuilder return_() {
+ bytecodesBufWriter.writeU1(RETURN);
+ return this;
+ }
+
@Override
public CodeBuilder return_(TypeKind tk) {
- writeBytecode(BytecodeHelpers.returnOpcode(tk));
+ bytecodesBufWriter.writeU1(returnBytecode(tk));
return this;
}
@Override
public CodeBuilder storeLocal(TypeKind tk, int slot) {
- writeLocalVar(BytecodeHelpers.storeOpcode(tk, slot), slot);
+ return switch (tk) {
+ case INT, SHORT, BYTE, CHAR, BOOLEAN
+ -> istore(slot);
+ case LONG -> lstore(slot);
+ case DOUBLE -> dstore(slot);
+ case FLOAT -> fstore(slot);
+ case REFERENCE -> astore(slot);
+ case VOID -> throw new IllegalArgumentException("void");
+ };
+ }
+
+ @Override
+ public CodeBuilder labelBinding(Label label) {
+ setLabelTarget(label, curPc());
return this;
}
@Override
public CodeBuilder loadLocal(TypeKind tk, int slot) {
- writeLocalVar(BytecodeHelpers.loadOpcode(tk, slot), slot);
- return this;
+ return switch (tk) {
+ case INT, SHORT, BYTE, CHAR, BOOLEAN
+ -> iload(slot);
+ case LONG -> lload(slot);
+ case DOUBLE -> dload(slot);
+ case FLOAT -> fload(slot);
+ case REFERENCE -> aload(slot);
+ case VOID -> throw new IllegalArgumentException("void");
+ };
}
@Override
public CodeBuilder invoke(Opcode opcode, MemberRefEntry ref) {
- if (opcode == INVOKEINTERFACE) {
- int slots = Util.parameterSlots(Util.methodTypeSymbol(ref.nameAndType())) + 1;
+ if (opcode == Opcode.INVOKEINTERFACE) {
+ int slots = Util.parameterSlots(Util.methodTypeSymbol(ref.type())) + 1;
writeInvokeInterface(opcode, (InterfaceMethodRefEntry) ref, slots);
} else {
writeInvokeNormal(opcode, ref);
@@ -817,21 +924,45 @@ public CodeBuilder invoke(Opcode opcode, MemberRefEntry ref) {
return this;
}
+ @Override
+ public CodeBuilder invokespecial(ClassDesc owner, String name, MethodTypeDesc type) {
+ bytecodesBufWriter.writeIndex(INVOKESPECIAL, constantPool().methodRefEntry(owner, name, type));
+ return this;
+ }
+
+ @Override
+ public CodeBuilder invokestatic(ClassDesc owner, String name, MethodTypeDesc type) {
+ bytecodesBufWriter.writeIndex(INVOKESTATIC, constantPool().methodRefEntry(owner, name, type));
+ return this;
+ }
+
+ @Override
+ public CodeBuilder invokevirtual(ClassDesc owner, String name, MethodTypeDesc type) {
+ bytecodesBufWriter.writeIndex(INVOKEVIRTUAL, constantPool().methodRefEntry(owner, name, type));
+ return this;
+ }
+
+ @Override
+ public CodeBuilder getfield(ClassDesc owner, String name, ClassDesc type) {
+ bytecodesBufWriter.writeIndex(GETFIELD, constantPool().fieldRefEntry(owner, name, type));
+ return this;
+ }
+
@Override
public CodeBuilder fieldAccess(Opcode opcode, FieldRefEntry ref) {
- writeFieldAccess(opcode, ref);
+ bytecodesBufWriter.writeIndex(opcode.bytecode(), ref);
return this;
}
@Override
public CodeBuilder arrayLoad(TypeKind tk) {
- writeBytecode(BytecodeHelpers.arrayLoadOpcode(tk));
+ bytecodesBufWriter.writeU1(BytecodeHelpers.arrayLoadBytecode(tk));
return this;
}
@Override
public CodeBuilder arrayStore(TypeKind tk) {
- writeBytecode(BytecodeHelpers.arrayStoreOpcode(tk));
+ bytecodesBufWriter.writeU1(BytecodeHelpers.arrayStoreBytecode(tk));
return this;
}
@@ -843,19 +974,23 @@ public CodeBuilder branch(Opcode op, Label target) {
@Override
public CodeBuilder nop() {
- writeBytecode(NOP);
+ bytecodesBufWriter.writeU1(NOP);
return this;
}
@Override
public CodeBuilder aconst_null() {
- writeBytecode(ACONST_NULL);
+ bytecodesBufWriter.writeU1(ACONST_NULL);
return this;
}
@Override
public CodeBuilder aload(int slot) {
- writeLocalVar(BytecodeHelpers.aload(slot), slot);
+ if (slot >= 0 && slot <= 3) {
+ bytecodesBufWriter.writeU1(ALOAD_0 + slot);
+ } else {
+ writeLocalVar(ALOAD, slot);
+ }
return this;
}
@@ -867,350 +1002,496 @@ public CodeBuilder anewarray(ClassEntry entry) {
@Override
public CodeBuilder arraylength() {
- writeBytecode(ARRAYLENGTH);
+ bytecodesBufWriter.writeU1(ARRAYLENGTH);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder areturn() {
+ bytecodesBufWriter.writeU1(ARETURN);
return this;
}
@Override
public CodeBuilder astore(int slot) {
- writeLocalVar(BytecodeHelpers.astore(slot), slot);
+ if (slot >= 0 && slot <= 3) {
+ bytecodesBufWriter.writeU1(ASTORE_0 + slot);
+ } else {
+ writeLocalVar(ASTORE, slot);
+ }
return this;
}
@Override
public CodeBuilder athrow() {
- writeBytecode(ATHROW);
+ bytecodesBufWriter.writeU1(ATHROW);
return this;
}
@Override
public CodeBuilder bipush(int b) {
BytecodeHelpers.validateBipush(b);
- writeArgumentConstant(BIPUSH, b);
+ bytecodesBufWriter.writeU1U1(BIPUSH, b);
return this;
}
@Override
public CodeBuilder checkcast(ClassEntry type) {
- writeTypeCheck(CHECKCAST, type);
+ bytecodesBufWriter.writeIndex(CHECKCAST, type);
return this;
}
@Override
public CodeBuilder d2f() {
- writeBytecode(D2F);
+ bytecodesBufWriter.writeU1(D2F);
return this;
}
@Override
public CodeBuilder d2i() {
- writeBytecode(D2I);
+ bytecodesBufWriter.writeU1(D2I);
return this;
}
@Override
public CodeBuilder d2l() {
- writeBytecode(D2L);
+ bytecodesBufWriter.writeU1(D2L);
return this;
}
@Override
public CodeBuilder dadd() {
- writeBytecode(DADD);
+ bytecodesBufWriter.writeU1(DADD);
return this;
}
@Override
public CodeBuilder dcmpg() {
- writeBytecode(DCMPG);
+ bytecodesBufWriter.writeU1(DCMPG);
return this;
}
@Override
public CodeBuilder dcmpl() {
- writeBytecode(DCMPL);
+ bytecodesBufWriter.writeU1(DCMPL);
return this;
}
@Override
public CodeBuilder dconst_0() {
- writeBytecode(DCONST_0);
+ bytecodesBufWriter.writeU1(DCONST_0);
return this;
}
@Override
public CodeBuilder dconst_1() {
- writeBytecode(DCONST_1);
+ bytecodesBufWriter.writeU1(DCONST_1);
return this;
}
@Override
public CodeBuilder ddiv() {
- writeBytecode(DDIV);
+ bytecodesBufWriter.writeU1(DDIV);
return this;
}
@Override
public CodeBuilder dload(int slot) {
- writeLocalVar(BytecodeHelpers.dload(slot), slot);
+ if (slot >= 0 && slot <= 3) {
+ bytecodesBufWriter.writeU1(DLOAD_0 + slot);
+ } else {
+ writeLocalVar(DLOAD, slot);
+ }
return this;
}
@Override
public CodeBuilder dmul() {
- writeBytecode(DMUL);
+ bytecodesBufWriter.writeU1(DMUL);
return this;
}
@Override
public CodeBuilder dneg() {
- writeBytecode(DNEG);
+ bytecodesBufWriter.writeU1(DNEG);
return this;
}
@Override
public CodeBuilder drem() {
- writeBytecode(DREM);
+ bytecodesBufWriter.writeU1(DREM);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder dreturn() {
+ bytecodesBufWriter.writeU1(DRETURN);
return this;
}
@Override
public CodeBuilder dstore(int slot) {
- writeLocalVar(BytecodeHelpers.dstore(slot), slot);
+ if (slot >= 0 && slot <= 3) {
+ bytecodesBufWriter.writeU1(DSTORE_0 + slot);
+ } else {
+ writeLocalVar(DSTORE, slot);
+ }
return this;
}
@Override
public CodeBuilder dsub() {
- writeBytecode(DSUB);
+ bytecodesBufWriter.writeU1(DSUB);
return this;
}
@Override
public CodeBuilder dup() {
- writeBytecode(DUP);
+ bytecodesBufWriter.writeU1(DUP);
return this;
}
@Override
public CodeBuilder dup2() {
- writeBytecode(DUP2);
+ bytecodesBufWriter.writeU1(DUP2);
return this;
}
@Override
public CodeBuilder dup2_x1() {
- writeBytecode(DUP2_X1);
+ bytecodesBufWriter.writeU1(DUP2_X1);
return this;
}
@Override
public CodeBuilder dup2_x2() {
- writeBytecode(DUP2_X2);
+ bytecodesBufWriter.writeU1(DUP2_X2);
return this;
}
@Override
public CodeBuilder dup_x1() {
- writeBytecode(DUP_X1);
+ bytecodesBufWriter.writeU1(DUP_X1);
return this;
}
@Override
public CodeBuilder dup_x2() {
- writeBytecode(DUP_X2);
+ bytecodesBufWriter.writeU1(DUP_X2);
return this;
}
@Override
public CodeBuilder f2d() {
- writeBytecode(F2D);
+ bytecodesBufWriter.writeU1(F2D);
return this;
}
@Override
public CodeBuilder f2i() {
- writeBytecode(F2I);
+ bytecodesBufWriter.writeU1(F2I);
return this;
}
@Override
public CodeBuilder f2l() {
- writeBytecode(F2L);
+ bytecodesBufWriter.writeU1(F2L);
return this;
}
@Override
public CodeBuilder fadd() {
- writeBytecode(FADD);
+ bytecodesBufWriter.writeU1(FADD);
return this;
}
@Override
public CodeBuilder fcmpg() {
- writeBytecode(FCMPG);
+ bytecodesBufWriter.writeU1(FCMPG);
return this;
}
@Override
public CodeBuilder fcmpl() {
- writeBytecode(FCMPL);
+ bytecodesBufWriter.writeU1(FCMPL);
return this;
}
@Override
public CodeBuilder fconst_0() {
- writeBytecode(FCONST_0);
+ bytecodesBufWriter.writeU1(FCONST_0);
return this;
}
@Override
public CodeBuilder fconst_1() {
- writeBytecode(FCONST_1);
+ bytecodesBufWriter.writeU1(FCONST_1);
return this;
}
@Override
public CodeBuilder fconst_2() {
- writeBytecode(FCONST_2);
+ bytecodesBufWriter.writeU1(FCONST_2);
return this;
}
@Override
public CodeBuilder fdiv() {
- writeBytecode(FDIV);
+ bytecodesBufWriter.writeU1(FDIV);
return this;
}
@Override
public CodeBuilder fload(int slot) {
- writeLocalVar(BytecodeHelpers.fload(slot), slot);
+ if (slot >= 0 && slot <= 3) {
+ bytecodesBufWriter.writeU1(FLOAD_0 + slot);
+ } else {
+ writeLocalVar(FLOAD, slot);
+ }
return this;
}
@Override
public CodeBuilder fmul() {
- writeBytecode(FMUL);
+ bytecodesBufWriter.writeU1(FMUL);
return this;
}
@Override
public CodeBuilder fneg() {
- writeBytecode(FNEG);
+ bytecodesBufWriter.writeU1(FNEG);
return this;
}
@Override
public CodeBuilder frem() {
- writeBytecode(FREM);
+ bytecodesBufWriter.writeU1(FREM);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder freturn() {
+ bytecodesBufWriter.writeU1(FRETURN);
return this;
}
@Override
public CodeBuilder fstore(int slot) {
- writeLocalVar(BytecodeHelpers.fstore(slot), slot);
+ if (slot >= 0 && slot <= 3) {
+ bytecodesBufWriter.writeU1(FSTORE_0 + slot);
+ } else {
+ writeLocalVar(FSTORE, slot);
+ }
return this;
}
@Override
public CodeBuilder fsub() {
- writeBytecode(FSUB);
+ bytecodesBufWriter.writeU1(FSUB);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder getstatic(ClassDesc owner, String name, ClassDesc type) {
+ bytecodesBufWriter.writeIndex(GETSTATIC, constantPool().fieldRefEntry(owner, name, type));
+ return this;
+ }
+
+ @Override
+ public CodeBuilder goto_(Label target) {
+ writeShortJump(GOTO, target);
return this;
}
@Override
public CodeBuilder i2b() {
- writeBytecode(I2B);
+ bytecodesBufWriter.writeU1(I2B);
return this;
}
@Override
public CodeBuilder i2c() {
- writeBytecode(I2C);
+ bytecodesBufWriter.writeU1(I2C);
return this;
}
@Override
public CodeBuilder i2d() {
- writeBytecode(I2D);
+ bytecodesBufWriter.writeU1(I2D);
return this;
}
@Override
public CodeBuilder i2f() {
- writeBytecode(I2F);
+ bytecodesBufWriter.writeU1(I2F);
return this;
}
@Override
public CodeBuilder i2l() {
- writeBytecode(I2L);
+ bytecodesBufWriter.writeU1(I2L);
return this;
}
@Override
public CodeBuilder i2s() {
- writeBytecode(I2S);
+ bytecodesBufWriter.writeU1(I2S);
return this;
}
@Override
public CodeBuilder iadd() {
- writeBytecode(IADD);
+ bytecodesBufWriter.writeU1(IADD);
return this;
}
@Override
public CodeBuilder iand() {
- writeBytecode(IAND);
+ bytecodesBufWriter.writeU1(IAND);
return this;
}
@Override
public CodeBuilder iconst_0() {
- writeBytecode(ICONST_0);
+ bytecodesBufWriter.writeU1(ICONST_0);
return this;
}
@Override
public CodeBuilder iconst_1() {
- writeBytecode(ICONST_1);
+ bytecodesBufWriter.writeU1(ICONST_1);
return this;
}
@Override
public CodeBuilder iconst_2() {
- writeBytecode(ICONST_2);
+ bytecodesBufWriter.writeU1(ICONST_2);
return this;
}
@Override
public CodeBuilder iconst_3() {
- writeBytecode(ICONST_3);
+ bytecodesBufWriter.writeU1(ICONST_3);
return this;
}
@Override
public CodeBuilder iconst_4() {
- writeBytecode(ICONST_4);
+ bytecodesBufWriter.writeU1(ICONST_4);
return this;
}
@Override
public CodeBuilder iconst_5() {
- writeBytecode(ICONST_5);
+ bytecodesBufWriter.writeU1(ICONST_5);
return this;
}
@Override
public CodeBuilder iconst_m1() {
- writeBytecode(ICONST_M1);
+ bytecodesBufWriter.writeU1(ICONST_M1);
return this;
}
@Override
public CodeBuilder idiv() {
- writeBytecode(IDIV);
+ bytecodesBufWriter.writeU1(IDIV);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder if_acmpeq(Label target) {
+ writeShortJump(IF_ACMPEQ, target);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder if_acmpne(Label target) {
+ writeShortJump(IF_ACMPNE, target);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder if_icmpeq(Label target) {
+ writeShortJump(IF_ICMPEQ, target);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder if_icmpge(Label target) {
+ writeShortJump(IF_ICMPGE, target);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder if_icmpgt(Label target) {
+ writeShortJump(IF_ICMPGT, target);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder if_icmple(Label target) {
+ writeShortJump(IF_ICMPLE, target);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder if_icmplt(Label target) {
+ writeShortJump(IF_ICMPLT, target);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder if_icmpne(Label target) {
+ writeShortJump(IF_ICMPNE, target);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder ifnonnull(Label target) {
+ writeShortJump(IFNONNULL, target);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder ifnull(Label target) {
+ writeShortJump(IFNULL, target);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder ifeq(Label target) {
+ writeShortJump(IFEQ, target);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder ifge(Label target) {
+ writeShortJump(IFGE, target);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder ifgt(Label target) {
+ writeShortJump(IFGT, target);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder ifle(Label target) {
+ writeShortJump(IFLE, target);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder iflt(Label target) {
+ writeShortJump(IFLT, target);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder ifne(Label target) {
+ writeShortJump(IFNE, target);
return this;
}
@@ -1222,25 +1503,29 @@ public CodeBuilder iinc(int slot, int val) {
@Override
public CodeBuilder iload(int slot) {
- writeLocalVar(BytecodeHelpers.iload(slot), slot);
+ if (slot >= 0 && slot <= 3) {
+ bytecodesBufWriter.writeU1(ILOAD_0 + slot);
+ } else {
+ writeLocalVar(ILOAD, slot);
+ }
return this;
}
@Override
public CodeBuilder imul() {
- writeBytecode(IMUL);
+ bytecodesBufWriter.writeU1(IMUL);
return this;
}
@Override
public CodeBuilder ineg() {
- writeBytecode(INEG);
+ bytecodesBufWriter.writeU1(INEG);
return this;
}
@Override
public CodeBuilder instanceOf(ClassEntry target) {
- writeTypeCheck(INSTANCEOF, target);
+ bytecodesBufWriter.writeIndex(INSTANCEOF, target);
return this;
}
@@ -1252,85 +1537,95 @@ public CodeBuilder invokedynamic(InvokeDynamicEntry ref) {
@Override
public CodeBuilder invokeinterface(InterfaceMethodRefEntry ref) {
- writeInvokeInterface(INVOKEINTERFACE, ref, Util.parameterSlots(ref.typeSymbol()) + 1);
+ writeInvokeInterface(Opcode.INVOKEINTERFACE, ref, Util.parameterSlots(ref.typeSymbol()) + 1);
return this;
}
@Override
public CodeBuilder invokespecial(InterfaceMethodRefEntry ref) {
- writeInvokeNormal(INVOKESPECIAL, ref);
+ bytecodesBufWriter.writeIndex(INVOKESPECIAL, ref);
return this;
}
@Override
public CodeBuilder invokespecial(MethodRefEntry ref) {
- writeInvokeNormal(INVOKESPECIAL, ref);
+ bytecodesBufWriter.writeIndex(INVOKESPECIAL, ref);
return this;
}
@Override
public CodeBuilder invokestatic(InterfaceMethodRefEntry ref) {
- writeInvokeNormal(INVOKESTATIC, ref);
+ bytecodesBufWriter.writeIndex(INVOKESTATIC, ref);
return this;
}
@Override
public CodeBuilder invokestatic(MethodRefEntry ref) {
- writeInvokeNormal(INVOKESTATIC, ref);
+ bytecodesBufWriter.writeIndex(INVOKESTATIC, ref);
return this;
}
@Override
public CodeBuilder invokevirtual(MethodRefEntry ref) {
- writeInvokeNormal(INVOKEVIRTUAL, ref);
+ bytecodesBufWriter.writeIndex(INVOKEVIRTUAL, ref);
return this;
}
@Override
public CodeBuilder ior() {
- writeBytecode(IOR);
+ bytecodesBufWriter.writeU1(IOR);
return this;
}
@Override
public CodeBuilder irem() {
- writeBytecode(IREM);
+ bytecodesBufWriter.writeU1(IREM);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder ireturn() {
+ bytecodesBufWriter.writeU1(IRETURN);
return this;
}
@Override
public CodeBuilder ishl() {
- writeBytecode(ISHL);
+ bytecodesBufWriter.writeU1(ISHL);
return this;
}
@Override
public CodeBuilder ishr() {
- writeBytecode(ISHR);
+ bytecodesBufWriter.writeU1(ISHR);
return this;
}
@Override
public CodeBuilder istore(int slot) {
- writeLocalVar(BytecodeHelpers.istore(slot), slot);
+ if (slot >= 0 && slot <= 3) {
+ bytecodesBufWriter.writeU1(ISTORE_0 + slot);
+ } else {
+ writeLocalVar(ISTORE, slot);
+ }
return this;
}
@Override
public CodeBuilder isub() {
- writeBytecode(ISUB);
+ bytecodesBufWriter.writeU1(ISUB);
return this;
}
@Override
public CodeBuilder iushr() {
- writeBytecode(IUSHR);
+ bytecodesBufWriter.writeU1(IUSHR);
return this;
}
@Override
public CodeBuilder ixor() {
- writeBytecode(IXOR);
+ bytecodesBufWriter.writeU1(IXOR);
return this;
}
@@ -1342,49 +1637,49 @@ public CodeBuilder lookupswitch(Label defaultTarget, List cases) {
@Override
public CodeBuilder l2d() {
- writeBytecode(L2D);
+ bytecodesBufWriter.writeU1(L2D);
return this;
}
@Override
public CodeBuilder l2f() {
- writeBytecode(L2F);
+ bytecodesBufWriter.writeU1(L2F);
return this;
}
@Override
public CodeBuilder l2i() {
- writeBytecode(L2I);
+ bytecodesBufWriter.writeU1(L2I);
return this;
}
@Override
public CodeBuilder ladd() {
- writeBytecode(LADD);
+ bytecodesBufWriter.writeU1(LADD);
return this;
}
@Override
public CodeBuilder land() {
- writeBytecode(LAND);
+ bytecodesBufWriter.writeU1(LAND);
return this;
}
@Override
public CodeBuilder lcmp() {
- writeBytecode(LCMP);
+ bytecodesBufWriter.writeU1(LCMP);
return this;
}
@Override
public CodeBuilder lconst_0() {
- writeBytecode(LCONST_0);
+ bytecodesBufWriter.writeU1(LCONST_0);
return this;
}
@Override
public CodeBuilder lconst_1() {
- writeBytecode(LCONST_1);
+ bytecodesBufWriter.writeU1(LCONST_1);
return this;
}
@@ -1396,85 +1691,99 @@ public CodeBuilder ldc(LoadableConstantEntry entry) {
@Override
public CodeBuilder ldiv() {
- writeBytecode(LDIV);
+ bytecodesBufWriter.writeU1(LDIV);
return this;
}
@Override
public CodeBuilder lload(int slot) {
- writeLocalVar(BytecodeHelpers.lload(slot), slot);
+ if (slot >= 0 && slot <= 3) {
+ bytecodesBufWriter.writeU1(LLOAD_0 + slot);
+ } else {
+ writeLocalVar(LLOAD, slot);
+ }
return this;
}
@Override
public CodeBuilder lmul() {
- writeBytecode(LMUL);
+ bytecodesBufWriter.writeU1(LMUL);
return this;
}
@Override
public CodeBuilder lneg() {
- writeBytecode(LNEG);
+ bytecodesBufWriter.writeU1(LNEG);
return this;
}
@Override
public CodeBuilder lor() {
- writeBytecode(LOR);
+ bytecodesBufWriter.writeU1(LOR);
return this;
}
@Override
public CodeBuilder lrem() {
- writeBytecode(LREM);
+ bytecodesBufWriter.writeU1(LREM);
+ return this;
+ }
+
+ @Override
+ public CodeBuilder lreturn() {
+ bytecodesBufWriter.writeU1(LRETURN);
return this;
}
@Override
public CodeBuilder lshl() {
- writeBytecode(LSHL);
+ bytecodesBufWriter.writeU1(LSHL);
return this;
}
@Override
public CodeBuilder lshr() {
- writeBytecode(LSHR);
+ bytecodesBufWriter.writeU1(LSHR);
return this;
}
@Override
public CodeBuilder lstore(int slot) {
- writeLocalVar(BytecodeHelpers.lstore(slot), slot);
+ if (slot >= 0 && slot <= 3) {
+ bytecodesBufWriter.writeU1(LSTORE_0 + slot);
+ } else {
+ writeLocalVar(LSTORE, slot);
+ }
return this;
}
@Override
public CodeBuilder lsub() {
- writeBytecode(LSUB);
+ bytecodesBufWriter.writeU1(LSUB);
return this;
}
@Override
public CodeBuilder lushr() {
- writeBytecode(LUSHR);
+ bytecodesBufWriter.writeU1(LUSHR);
return this;
}
@Override
public CodeBuilder lxor() {
- writeBytecode(LXOR);
+ bytecodesBufWriter.writeU1(LXOR);
return this;
}
@Override
public CodeBuilder monitorenter() {
- writeBytecode(MONITORENTER);
+ bytecodesBufWriter.writeU1(MONITORENTER);
return this;
}
@Override
public CodeBuilder monitorexit() {
- writeBytecode(MONITOREXIT);
+ bytecodesBufWriter.writeU1(MONITOREXIT);
return this;
}
@@ -1501,26 +1810,26 @@ public CodeBuilder newarray(TypeKind typeKind) {
@Override
public CodeBuilder pop() {
- writeBytecode(POP);
+ bytecodesBufWriter.writeU1(POP);
return this;
}
@Override
public CodeBuilder pop2() {
- writeBytecode(POP2);
+ bytecodesBufWriter.writeU1(POP2);
return this;
}
@Override
public CodeBuilder sipush(int s) {
BytecodeHelpers.validateSipush(s);
- writeArgumentConstant(SIPUSH, s);
+ bytecodesBufWriter.writeU1U2(SIPUSH, s);
return this;
}
@Override
public CodeBuilder swap() {
- writeBytecode(SWAP);
+ bytecodesBufWriter.writeU1(SWAP);
return this;
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java
index ec4e148baf3..a841cbf47f4 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java
@@ -148,9 +148,7 @@ public DirectMethodBuilder run(Consumer super MethodBuilder> handler) {
@Override
public void writeTo(BufWriterImpl buf) {
- buf.writeU2(flags);
- buf.writeIndex(name);
- buf.writeIndex(desc);
+ buf.writeU2U2U2(flags, buf.cpIndex(name), buf.cpIndex(desc));
attributes.writeTo(buf);
}
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/EntryMap.java b/src/java.base/share/classes/jdk/internal/classfile/impl/EntryMap.java
index d5ebbbebe7a..be350cb5814 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/EntryMap.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/EntryMap.java
@@ -113,6 +113,7 @@ public void put(int hash, int index) {
throw new IllegalArgumentException("hash must be nonzero");
int ptr = (hash & mask1) << 1;
+ var data = this.data;
int k = data[ptr];
if (k == 0) {
data[ptr] = hash;
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/LabelImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/LabelImpl.java
index 2aaf5f033c0..aac0fafaef1 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/LabelImpl.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/LabelImpl.java
@@ -24,8 +24,6 @@
*/
package jdk.internal.classfile.impl;
-import java.util.Objects;
-
import java.lang.classfile.Label;
import java.lang.classfile.instruction.LabelTarget;
@@ -52,7 +50,7 @@ public final class LabelImpl
private int bci;
public LabelImpl(LabelContext labelContext, int bci) {
- this.labelContext = Objects.requireNonNull(labelContext);
+ this.labelContext = labelContext;
this.bci = bci;
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java
index 2403ae150e9..659f41f9699 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java
@@ -299,7 +299,6 @@ public static int align(int n) {
private int nextBci;
private int bci;
private int opcode;
- private boolean isWide;
public static CodeRange of(byte[] array) {
return new CodeRange(array, array.length);
@@ -341,14 +340,14 @@ public void reset(int nextBci) {
* be valid and can be accessed unchecked.
*/
public int opcode() {
- return opcode;
+ return opcode & 0xFF;
}
/**
* Returns whether the current functional opcode is in wide.
*/
public boolean isWide() {
- return isWide;
+ return (opcode & (WIDE << 8)) != 0;
}
/**
@@ -411,7 +410,7 @@ public int destW() {
// *load, *store, iinc
public int getIndex() {
- return isWide ? getU2Unchecked(bci + 2) : getIndexU1();
+ return isWide() ? getU2Unchecked(bci + 2) : getIndexU1();
}
// ldc
@@ -443,12 +442,11 @@ public boolean next() {
int len = LENGTHS[code & 0xFF]; // & 0xFF eliminates bound check
this.bci = bci;
opcode = code;
- isWide = false;
if (len <= 0) {
len = checkSpecialInstruction(bci, end, code); // sets opcode
}
- if (len <= 0 || (nextBci += len) > end) {
+ if ((nextBci += len) > end) {
opcode = ILLEGAL;
}
@@ -457,37 +455,34 @@ public boolean next() {
// Put rarely used code in another method to reduce code size
private int checkSpecialInstruction(int bci, int end, int code) {
+ int len = -1;
if (code == WIDE) {
- if (bci + 1 >= end) {
- return -1;
+ if (bci + 1 < end) {
+ opcode = (WIDE << 8) | (code = getIndexU1());
+ // Validated in UtilTest.testOpcodeLengthTable
+ len = LENGTHS[code] * 2;
}
- opcode = code = getIndexU1();
- isWide = true;
- // Validated in UtilTest.testOpcodeLengthTable
- return LENGTHS[code] * 2;
- }
- if (code == TABLESWITCH) {
+ } else if (code == TABLESWITCH) {
int alignedBci = align(bci + 1);
- if (alignedBci + 3 * 4 >= end) {
- return -1;
+ if (alignedBci + 3 * 4 < end) {
+ int lo = getIntUnchecked(alignedBci + 1 * 4);
+ int hi = getIntUnchecked(alignedBci + 2 * 4);
+ long l = alignedBci - bci + (3L + (long) hi - lo + 1L) * 4L;
+ len = l > 0 && ((int) l == l) ? (int) l : -1;
}
- int lo = getIntUnchecked(alignedBci + 1 * 4);
- int hi = getIntUnchecked(alignedBci + 2 * 4);
- long l = alignedBci - bci + (3L + (long) hi - lo + 1L) * 4L;
- return l > 0 && ((int) l == l) ? (int) l : -1;
- }
- if (code == LOOKUPSWITCH) {
+ } else if (code == LOOKUPSWITCH) {
int alignedBci = align(bci + 1);
- if (alignedBci + 2 * 4 >= end) {
- return -1;
- }
- int npairs = getIntUnchecked(alignedBci + 4);
- if (npairs < 0) {
- return -1;
+ if (alignedBci + 2 * 4 < end) {
+ int npairs = getIntUnchecked(alignedBci + 4);
+ if (npairs >= 0) {
+ long l = alignedBci - bci + (2L + 2L * npairs) * 4L;
+ len = l > 0 && ((int) l == l) ? (int) l : -1;
+ }
}
- long l = alignedBci - bci + (2L + 2L * npairs) * 4L;
- return l > 0 && ((int) l == l) ? (int) l : -1;
}
- return -1;
+ if (len <= 0) {
+ opcode = ILLEGAL;
+ }
+ return len;
}
}
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java
index 2193eb76108..0b99766b385 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java
@@ -34,7 +34,6 @@
import java.lang.classfile.BootstrapMethodEntry;
import java.lang.classfile.attribute.BootstrapMethodsAttribute;
import java.lang.classfile.constantpool.*;
-import java.util.Objects;
import jdk.internal.constant.ConstantUtils;
@@ -87,20 +86,27 @@ public int bootstrapMethodCount() {
@Override
public PoolEntry entryByIndex(int index) {
if (index <= 0 || index >= size()) {
- throw new ConstantPoolException("Bad CP index: " + index);
+ throw badCP(index);
}
PoolEntry pe = (index < parentSize)
? parent.entryByIndex(index)
: myEntries[index - parentSize];
if (pe == null) {
- throw new ConstantPoolException("Unusable CP index: " + index);
+ throw unusableCP(index);
}
return pe;
}
+ private static ConstantPoolException badCP(int index) {
+ return new ConstantPoolException("Bad CP index: " + index);
+ }
+
+ private static ConstantPoolException unusableCP(int index) {
+ return new ConstantPoolException("Unusable CP index: " + index);
+ }
+
@Override
public T entryByIndex(int index, Class cls) {
- Objects.requireNonNull(cls);
return ClassReaderImpl.checkType(entryByIndex(index), index, cls);
}
@@ -165,8 +171,10 @@ void writeTo(BufWriterImpl buf) {
}
private EntryMap map() {
+ int parentSize = this.parentSize;
+ var map = this.map;
if (map == null) {
- map = new EntryMap(Math.max(size, 1024), .75f);
+ this.map = map = new EntryMap(Math.max(size, 1024), .75f);
// Doing a full scan here yields fall-off-the-cliff performance results,
// especially if we only need a few entries that are already
@@ -203,8 +211,10 @@ private void fullScan() {
}
private EntryMap bsmMap() {
+ int bsmSize = this.bsmSize;
+ var bsmMap = this.bsmMap;
if (bsmMap == null) {
- bsmMap = new EntryMap(Math.max(bsmSize, 16), .75f);
+ this.bsmMap = bsmMap = new EntryMap(Math.max(bsmSize, 16), .75f);
for (int i=0; i {
var cpe = cp.entryByIndex(bcs.getIndexU2());
var nameAndType = opcode == INVOKEDYNAMIC ? ((DynamicConstantPoolEntry)cpe).nameAndType() : ((MemberRefEntry)cpe).nameAndType();
- var mtd = Util.methodTypeSymbol(nameAndType);
+ var mtd = Util.methodTypeSymbol(nameAndType.type());
var delta = Util.slotSize(mtd.returnType()) - Util.parameterSlots(mtd);
if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) {
delta--;
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java
index 884f7b8bbc8..54b4139a9e0 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java
@@ -48,7 +48,7 @@ public class StackMapDecoder {
private static final int
SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247,
SAME_EXTENDED = 251;
- private static final StackMapFrameInfo[] NO_STACK_FRAME_INFOS = new StackMapFrameInfo[0];
+ private static final StackMapFrameInfo[] NO_STACK_FRAME_INFOS = {};
private final ClassReader classReader;
private final int pos;
diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java
index ae983520683..9bd5084061a 100644
--- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java
+++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, Alibaba Group Holding Limited. 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
@@ -39,7 +40,6 @@
import java.lang.constant.MethodTypeDesc;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.BitSet;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@@ -58,8 +58,8 @@
*
* The {@linkplain #generate() frames computation} consists of following steps:
*
- * - {@linkplain #detectFrameOffsets() Detection} of mandatory stack map frames offsets:
- * - Mandatory stack map frame offsets include all jump and switch instructions targets,
+ *
- {@linkplain #detectFrames() Detection} of mandatory stack map frames:
+ * - Mandatory stack map frame include all jump and switch instructions targets,
* offsets immediately following {@linkplain #noControlFlow(int) "no control flow"}
* and all exception table handlers.
*
- Detection is performed in a single fast pass through the bytecode,
@@ -163,6 +163,7 @@ static StackMapGenerator of(DirectCodeBuilder dcb, BufWriterImpl buf) {
private static final int FLAG_THIS_UNINIT = 0x01;
private static final int FRAME_DEFAULT_CAPACITY = 10;
private static final int T_BOOLEAN = 4, T_LONG = 11;
+ private static final Frame[] EMPTY_FRAME_ARRAY = {};
private static final int ITEM_TOP = 0,
ITEM_INTEGER = 1,
@@ -198,7 +199,8 @@ static record RawExceptionCatch(int start, int end, int handler, Type catchType)
private final ClassHierarchyImpl classHierarchy;
private final boolean patchDeadCode;
private final boolean filterDeadLabels;
- private List frames;
+ private Frame[] frames = EMPTY_FRAME_ARRAY;
+ private int framesCount = 0;
private final Frame currentFrame;
private int maxStack, maxLocals;
@@ -262,10 +264,10 @@ public int maxStack() {
private Frame getFrame(int offset) {
//binary search over frames ordered by offset
int low = 0;
- int high = frames.size() - 1;
+ int high = framesCount - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
- var f = frames.get(mid);
+ var f = frames[mid];
if (f.offset < offset)
low = mid + 1;
else if (f.offset > offset)
@@ -283,8 +285,8 @@ private void checkJumpTarget(Frame frame, int target) {
private int exMin, exMax;
private boolean isAnyFrameDirty() {
- for (var f : frames) {
- if (f.dirty) return true;
+ for (int i = 0; i < framesCount; i++) {
+ if (frames[i].dirty) return true;
}
return false;
}
@@ -292,27 +294,10 @@ private boolean isAnyFrameDirty() {
private void generate() {
exMin = bytecode.length();
exMax = -1;
- for (var exhandler : handlers) {
- int start_pc = labelContext.labelToBci(exhandler.tryStart());
- int end_pc = labelContext.labelToBci(exhandler.tryEnd());
- int handler_pc = labelContext.labelToBci(exhandler.handler());
- if (start_pc >= 0 && end_pc >= 0 && end_pc > start_pc && handler_pc >= 0) {
- if (start_pc < exMin) exMin = start_pc;
- if (end_pc > exMax) exMax = end_pc;
- var catchType = exhandler.catchType();
- rawHandlers.add(new RawExceptionCatch(start_pc, end_pc, handler_pc,
- catchType.isPresent() ? cpIndexToType(catchType.get().index(), cp)
- : Type.THROWABLE_TYPE));
- }
- }
- BitSet frameOffsets = detectFrameOffsets();
- int framesCount = frameOffsets.cardinality();
- frames = new ArrayList<>(framesCount);
- int offset = -1;
- for (int i = 0; i < framesCount; i++) {
- offset = frameOffsets.nextSetBit(offset + 1);
- frames.add(new Frame(offset, classHierarchy));
+ if (!handlers.isEmpty()) {
+ generateHandlers();
}
+ detectFrames();
do {
processMethod();
} while (isAnyFrameDirty());
@@ -321,23 +306,45 @@ private void generate() {
//dead code patching
for (int i = 0; i < framesCount; i++) {
- var frame = frames.get(i);
+ var frame = frames[i];
if (frame.flags == -1) {
- if (!patchDeadCode) throw generatorError("Unable to generate stack map frame for dead code", frame.offset);
- //patch frame
- frame.pushStack(Type.THROWABLE_TYPE);
- if (maxStack < 1) maxStack = 1;
- int end = (i < framesCount - 1 ? frames.get(i + 1).offset : bytecode.length()) - 1;
- //patch bytecode
- var arr = bytecode.array();
- Arrays.fill(arr, frame.offset, end, (byte) NOP);
- arr[end] = (byte) ATHROW;
- //patch handlers
- removeRangeFromExcTable(frame.offset, end + 1);
+ deadCodePatching(frame, i);
+ }
+ }
+ }
+
+ private void generateHandlers() {
+ var labelContext = this.labelContext;
+ for (int i = 0; i < handlers.size(); i++) {
+ var exhandler = handlers.get(i);
+ int start_pc = labelContext.labelToBci(exhandler.tryStart());
+ int end_pc = labelContext.labelToBci(exhandler.tryEnd());
+ int handler_pc = labelContext.labelToBci(exhandler.handler());
+ if (start_pc >= 0 && end_pc >= 0 && end_pc > start_pc && handler_pc >= 0) {
+ if (start_pc < exMin) exMin = start_pc;
+ if (end_pc > exMax) exMax = end_pc;
+ var catchType = exhandler.catchType();
+ rawHandlers.add(new RawExceptionCatch(start_pc, end_pc, handler_pc,
+ catchType.isPresent() ? cpIndexToType(catchType.get().index(), cp)
+ : Type.THROWABLE_TYPE));
}
}
}
+ private void deadCodePatching(Frame frame, int i) {
+ if (!patchDeadCode) throw generatorError("Unable to generate stack map frame for dead code", frame.offset);
+ //patch frame
+ frame.pushStack(Type.THROWABLE_TYPE);
+ if (maxStack < 1) maxStack = 1;
+ int end = (i < framesCount - 1 ? frames[i + 1].offset : bytecode.length()) - 1;
+ //patch bytecode
+ var arr = bytecode.array();
+ Arrays.fill(arr, frame.offset, end, (byte) NOP);
+ arr[end] = (byte) ATHROW;
+ //patch handlers
+ removeRangeFromExcTable(frame.offset, end + 1);
+ }
+
private void removeRangeFromExcTable(int rangeStart, int rangeEnd) {
var it = handlers.listIterator();
while (it.hasNext()) {
@@ -380,14 +387,15 @@ private void removeRangeFromExcTable(int rangeStart, int rangeEnd) {
* @return
StackMapTableAttribute
or null if stack map is empty
*/
public Attribute extends StackMapTableAttribute> stackMapTableAttribute() {
- return frames.isEmpty() ? null : new UnboundAttribute.AdHocAttribute<>(Attributes.stackMapTable()) {
+ return framesCount == 0 ? null : new UnboundAttribute.AdHocAttribute<>(Attributes.stackMapTable()) {
@Override
public void writeBody(BufWriterImpl b) {
- b.writeU2(frames.size());
+ b.writeU2(framesCount);
Frame prevFrame = new Frame(classHierarchy);
prevFrame.setLocalsFromArg(methodName, methodDesc, isStatic, thisType);
prevFrame.trimAndCompress();
- for (var fr : frames) {
+ for (int i = 0; i < framesCount; i++) {
+ var fr = frames[i];
fr.trimAndCompress();
fr.writeTo(b, prevFrame, cp);
prevFrame = fr;
@@ -412,19 +420,19 @@ private void processMethod() {
boolean ncf = false;
while (bcs.next()) {
currentFrame.offset = bcs.bci();
- if (stackmapIndex < frames.size()) {
- int thisOffset = frames.get(stackmapIndex).offset;
+ if (stackmapIndex < framesCount) {
+ int thisOffset = frames[stackmapIndex].offset;
if (ncf && thisOffset > bcs.bci()) {
throw generatorError("Expecting a stack map frame");
}
if (thisOffset == bcs.bci()) {
- Frame nextFrame = frames.get(stackmapIndex++);
+ Frame nextFrame = frames[stackmapIndex++];
if (!ncf) {
currentFrame.checkAssignableTo(nextFrame);
}
while (!nextFrame.dirty) { //skip unmatched frames
- if (stackmapIndex == frames.size()) return; //skip the rest of this round
- nextFrame = frames.get(stackmapIndex++);
+ if (stackmapIndex == framesCount) return; //skip the rest of this round
+ nextFrame = frames[stackmapIndex++];
}
bcs.reset(nextFrame.offset); //skip code up-to the next frame
bcs.next();
@@ -748,22 +756,20 @@ private void processSwitch(RawBytecodeHelper bcs) {
}
private void processFieldInstructions(RawBytecodeHelper bcs) {
- var desc = Util.fieldTypeSymbol(cp.entryByIndex(bcs.getIndexU2(), MemberRefEntry.class).nameAndType());
+ var desc = Util.fieldTypeSymbol(cp.entryByIndex(bcs.getIndexU2(), MemberRefEntry.class).type());
+ var currentFrame = this.currentFrame;
switch (bcs.opcode()) {
case GETSTATIC ->
currentFrame.pushStack(desc);
case PUTSTATIC -> {
- currentFrame.popStack();
- if (Util.isDoubleSlot(desc)) currentFrame.popStack();
+ currentFrame.decStack(Util.isDoubleSlot(desc) ? 2 : 1);
}
case GETFIELD -> {
- currentFrame.popStack();
+ currentFrame.decStack(1);
currentFrame.pushStack(desc);
}
case PUTFIELD -> {
- currentFrame.popStack();
- currentFrame.popStack();
- if (Util.isDoubleSlot(desc)) currentFrame.popStack();
+ currentFrame.decStack(Util.isDoubleSlot(desc) ? 3 : 2);
}
default -> throw new AssertionError("Should not reach here");
}
@@ -775,12 +781,12 @@ private boolean processInvokeInstructions(RawBytecodeHelper bcs, boolean inTryBl
var nameAndType = opcode == INVOKEDYNAMIC
? cp.entryByIndex(index, InvokeDynamicEntry.class).nameAndType()
: cp.entryByIndex(index, MemberRefEntry.class).nameAndType();
- String invokeMethodName = nameAndType.name().stringValue();
- var mDesc = Util.methodTypeSymbol(nameAndType);
+ var mDesc = Util.methodTypeSymbol(nameAndType.type());
int bci = bcs.bci();
+ var currentFrame = this.currentFrame;
currentFrame.decStack(Util.parameterSlots(mDesc));
if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) {
- if (OBJECT_INITIALIZER_NAME.equals(invokeMethodName)) {
+ if (nameAndType.name().equalsString(OBJECT_INITIALIZER_NAME)) {
Type type = currentFrame.popStack();
if (type == Type.UNITIALIZED_THIS_TYPE) {
if (inTryBlock) {
@@ -789,9 +795,7 @@ private boolean processInvokeInstructions(RawBytecodeHelper bcs, boolean inTryBl
currentFrame.initializeObject(type, thisType);
thisUninit = true;
} else if (type.tag == ITEM_UNINITIALIZED) {
- int new_offset = type.bci;
- int new_class_index = bcs.getU2(new_offset + 1);
- Type new_class_type = cpIndexToType(new_class_index, cp);
+ Type new_class_type = cpIndexToType(bcs.getU2(type.bci + 1), cp);
if (inTryBlock) {
processExceptionHandlerTargets(bci, thisUninit);
}
@@ -800,7 +804,7 @@ private boolean processInvokeInstructions(RawBytecodeHelper bcs, boolean inTryBl
throw generatorError("Bad operand type when invoking ");
}
} else {
- currentFrame.popStack();
+ currentFrame.decStack(1);
}
}
currentFrame.pushStack(mDesc.returnType());
@@ -841,18 +845,10 @@ private IllegalArgumentException generatorError(String msg, int offset) {
}
/**
- * Performs detection of mandatory stack map frames offsets
- * in a single bytecode traversing pass
- * @return java.lang.BitSet
of detected frames offsets
+ * Performs detection of mandatory stack map frames in a single bytecode traversing pass
+ * @return detected frames
*/
- private BitSet detectFrameOffsets() {
- var offsets = new BitSet() {
- @Override
- public void set(int i) {
- Preconditions.checkIndex(i, bytecode.length(), RawBytecodeHelper.IAE_FORMATTER);
- super.set(i);
- }
- };
+ private void detectFrames() {
var bcs = bytecode.start();
boolean no_control_flow = false;
int opcode, bci = 0;
@@ -860,22 +856,22 @@ public void set(int i) {
opcode = bcs.opcode();
bci = bcs.bci();
if (no_control_flow) {
- offsets.set(bci);
+ addFrame(bci);
}
no_control_flow = switch (opcode) {
case GOTO -> {
- offsets.set(bcs.dest());
+ addFrame(bcs.dest());
yield true;
}
case GOTO_W -> {
- offsets.set(bcs.destW());
+ addFrame(bcs.destW());
yield true;
}
case IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE,
IF_ICMPGT, IF_ICMPLE, IFEQ, IFNE,
IFLT, IFGE, IFGT, IFLE, IF_ACMPEQ,
IF_ACMPNE , IFNULL , IFNONNULL -> {
- offsets.set(bcs.dest());
+ addFrame(bcs.dest());
yield false;
}
case TABLESWITCH, LOOKUPSWITCH -> {
@@ -891,9 +887,9 @@ public void set(int i) {
keys = bcs.getIntUnchecked(aligned_bci + 4);
delta = 2;
}
- offsets.set(bci + default_ofset);
+ addFrame(bci + default_ofset);
for (int i = 0; i < keys; i++) {
- offsets.set(bci + bcs.getIntUnchecked(aligned_bci + (3 + i * delta) * 4));
+ addFrame(bci + bcs.getIntUnchecked(aligned_bci + (3 + i * delta) * 4));
}
yield true;
}
@@ -904,13 +900,36 @@ public void set(int i) {
} catch (IllegalArgumentException iae) {
throw generatorError("Detected branch target out of bytecode range", bci);
}
- for (var exhandler : rawHandlers) try {
- offsets.set(exhandler.handler());
+ for (int i = 0; i < rawHandlers.size(); i++) try {
+ addFrame(rawHandlers.get(i).handler());
} catch (IllegalArgumentException iae) {
if (!filterDeadLabels)
throw generatorError("Detected exception handler out of bytecode range");
}
- return offsets;
+ }
+
+ private void addFrame(int offset) {
+ Preconditions.checkIndex(offset, bytecode.length(), RawBytecodeHelper.IAE_FORMATTER);
+ var frames = this.frames;
+ int i = 0, framesCount = this.framesCount;
+ for (; i < framesCount; i++) {
+ var frameOffset = frames[i].offset;
+ if (frameOffset == offset) {
+ return;
+ }
+ if (frameOffset > offset) {
+ break;
+ }
+ }
+ if (framesCount >= frames.length) {
+ int newCapacity = framesCount + 8;
+ this.frames = frames = framesCount == 0 ? new Frame[newCapacity] : Arrays.copyOf(frames, newCapacity);
+ }
+ if (i != framesCount) {
+ System.arraycopy(frames, i, frames, i + 1, framesCount - i);
+ }
+ frames[i] = new Frame(offset, classHierarchy);
+ this.framesCount = framesCount + 1;
}
private final class Frame {
@@ -1200,7 +1219,9 @@ private static boolean equals(Type[] l1, Type[] l2, int commonSize) {
return Arrays.equals(l1, 0, commonSize, l2, 0, commonSize);
}
- void writeTo(BufWriter out, Frame prevFrame, ConstantPoolBuilder cp) {
+ void writeTo(BufWriterImpl out, Frame prevFrame, ConstantPoolBuilder cp) {
+ int localsSize = this.localsSize;
+ int stackSize = this.stackSize;
int offsetDelta = offset - prevFrame.offset - 1;
if (stackSize == 0) {
int commonLocalsSize = localsSize > prevFrame.localsSize ? prevFrame.localsSize : localsSize;
@@ -1209,8 +1230,7 @@ void writeTo(BufWriter out, Frame prevFrame, ConstantPoolBuilder cp) {
if (diffLocalsSize == 0 && offsetDelta < 64) { //same frame
out.writeU1(offsetDelta);
} else { //chop, same extended or append frame
- out.writeU1(251 + diffLocalsSize);
- out.writeU2(offsetDelta);
+ out.writeU1U2(251 + diffLocalsSize, offsetDelta);
for (int i=commonLocalsSize; i> void writeAttribute(BufWriterImpl writer, Attribute> attr) {
+ public static > void writeAttribute(BufWriterImpl writer, Attribute> attr) {
if (attr instanceof CustomAttribute> ca) {
var mapper = (AttributeMapper) ca.attributeMapper();
mapper.writeAttribute(writer, (T) ca);
@@ -260,11 +252,10 @@ public static void writeAttributes(BufWriterImpl buf, List extends Attribute
}
@ForceInline
- static void writeList(BufWriterImpl buf, List list) {
- int size = list.size();
+ static void writeList(BufWriterImpl buf, Writable[] array, int size) {
buf.writeU2(size);
for (int i = 0; i < size; i++) {
- list.get(i).writeTo(buf);
+ array[i].writeTo(buf);
}
}
@@ -409,6 +400,7 @@ public static int pow31(int k) {
0x54fbc001, 0xb9f78001, 0x2ef34001, 0xb3ef0001, 0x48eac001, 0xede68001, 0xa2e24001,
0x67de0001, 0xcfbc0001, 0x379a0001, 0x9f780001, 0x07560001, 0x6f340001, 0xd7120001,
0x3ef00001, 0x7de00001, 0xbcd00001, 0xfbc00001, 0x3ab00001, 0x79a00001, 0xb8900001,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static int powersIndex(int digit, int index) {
@@ -419,6 +411,6 @@ static int powersIndex(int digit, int index) {
// digit: 0 - 7
// index: 0 - SIGNIFICANT_OCTAL_DIGITS - 1
private static int powerOctal(int digit, int index) {
- return digit == 0 ? 1 : powers[powersIndex(digit, index)];
+ return digit == 0 ? 1 : powers[powersIndex(digit, index) & 0x3F]; // & 0x3F eliminates bound check
}
}
diff --git a/src/java.base/share/classes/jdk/internal/constant/MethodTypeDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/MethodTypeDescImpl.java
index 7d4442c255e..6f59c476a6b 100644
--- a/src/java.base/share/classes/jdk/internal/constant/MethodTypeDescImpl.java
+++ b/src/java.base/share/classes/jdk/internal/constant/MethodTypeDescImpl.java
@@ -287,15 +287,31 @@ public String descriptorString() {
if (desc != null)
return desc;
- int len = 2 + returnType.descriptorString().length();
- for (ClassDesc argType : argTypes) {
- len += argType.descriptorString().length();
- }
- StringBuilder sb = new StringBuilder(len).append('(');
- for (ClassDesc argType : argTypes) {
- sb.append(argType.descriptorString());
+ return buildDescriptorString();
+ }
+
+ private String buildDescriptorString() {
+ var returnType = this.returnType;
+ var returnTypeDesc = returnType.descriptorString();
+ var argTypes = this.argTypes;
+ String desc;
+ if (argTypes.length == 0) {
+ // getter
+ desc = "()".concat(returnTypeDesc);
+ } else if (argTypes.length == 1 && returnType == ConstantDescs.CD_void) {
+ // setter
+ desc = ConstantUtils.concat("(", argTypes[0].descriptorString(), ")V");
+ } else {
+ int len = 2 + returnTypeDesc.length();
+ for (ClassDesc argType : argTypes) {
+ len += argType.descriptorString().length();
+ }
+ StringBuilder sb = new StringBuilder(len).append('(');
+ for (ClassDesc argType : argTypes) {
+ sb.append(argType.descriptorString());
+ }
+ desc = sb.append(')').append(returnTypeDesc).toString();
}
- desc = sb.append(')').append(returnType.descriptorString()).toString();
cachedDescriptorString = desc;
return desc;
}
diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java b/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java
index bc5f63fd50e..f1e1d1728d8 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java
@@ -193,11 +193,10 @@ private static byte[] specializeHelper(MethodType leafType, MethodType callerMet
CallingSequence callingSequence, ABIDescriptor abi) {
String className = callingSequence.forDowncall() ? CLASS_NAME_DOWNCALL : CLASS_NAME_UPCALL;
byte[] bytes = ClassFile.of().build(ClassDesc.ofInternalName(className), clb -> {
- clb.withFlags(ACC_PUBLIC + ACC_FINAL + ACC_SUPER);
- clb.withSuperclass(CD_Object);
- clb.withVersion(CLASSFILE_VERSION, 0);
-
- clb.withMethodBody(METHOD_NAME, methodTypeDesc(callerMethodType), ACC_PUBLIC | ACC_STATIC,
+ clb.withFlags(ACC_PUBLIC + ACC_FINAL + ACC_SUPER)
+ .withSuperclass(CD_Object)
+ .withVersion(CLASSFILE_VERSION, 0)
+ .withMethodBody(METHOD_NAME, methodTypeDesc(callerMethodType), ACC_PUBLIC | ACC_STATIC,
cb -> new BindingSpecializer(cb, callerMethodType, callingSequence, abi, leafType).specialize());
});
@@ -275,8 +274,8 @@ private void specialize() {
if (shouldAcquire(i)) {
int scopeLocal = cb.allocateLocal(REFERENCE);
initialScopeSlots[numScopes++] = scopeLocal;
- cb.loadConstant(null);
- cb.storeLocal(REFERENCE, scopeLocal); // need to initialize all scope locals here in case an exception occurs
+ cb.aconst_null()
+ .astore(scopeLocal); // need to initialize all scope locals here in case an exception occurs
}
}
scopeSlots = Arrays.copyOf(initialScopeSlots, numScopes); // fit to size
@@ -285,15 +284,15 @@ private void specialize() {
// create a Binding.Context for this call
if (callingSequence.allocationSize() != 0) {
- cb.loadConstant(callingSequence.allocationSize());
- cb.invokestatic(CD_SharedUtils, "newBoundedArena", MTD_NEW_BOUNDED_ARENA);
+ cb.loadConstant(callingSequence.allocationSize())
+ .invokestatic(CD_SharedUtils, "newBoundedArena", MTD_NEW_BOUNDED_ARENA);
} else if (callingSequence.forUpcall() && needsSession()) {
cb.invokestatic(CD_SharedUtils, "newEmptyArena", MTD_NEW_EMPTY_ARENA);
} else {
cb.getstatic(CD_SharedUtils, "DUMMY_ARENA", CD_Arena);
}
contextIdx = cb.allocateLocal(REFERENCE);
- cb.storeLocal(REFERENCE, contextIdx);
+ cb.astore(contextIdx);
// in case the call needs a return buffer, allocate it here.
// for upcalls the VM wrapper stub allocates the buffer.
@@ -301,7 +300,7 @@ private void specialize() {
emitLoadInternalAllocator();
emitAllocateCall(callingSequence.returnBufferSize(), 1);
returnBufferIdx = cb.allocateLocal(REFERENCE);
- cb.storeLocal(REFERENCE, returnBufferIdx);
+ cb.astore(returnBufferIdx);
}
Label tryStart = cb.newLabel();
@@ -324,7 +323,7 @@ private void specialize() {
// for downcalls, recipes have an input value, which we set up here
if (callingSequence.needsReturnBuffer() && i == 0) {
assert returnBufferIdx != -1;
- cb.loadLocal(REFERENCE, returnBufferIdx);
+ cb.aload(returnBufferIdx);
pushType(MemorySegment.class);
} else {
emitGetInput();
@@ -340,7 +339,7 @@ private void specialize() {
// return buffer ptr is wrapped in a MemorySegment above, but not passed to the leaf handle
popType(MemorySegment.class);
returnBufferIdx = cb.allocateLocal(REFERENCE);
- cb.storeLocal(REFERENCE, returnBufferIdx);
+ cb.astore(returnBufferIdx);
} else {
// for upcalls the recipe result is an argument to the leaf handle
emitSetOutput(typeStack.pop());
@@ -355,7 +354,7 @@ private void specialize() {
if (callingSequence.forDowncall()) {
cb.loadConstant(CLASS_DATA_DESC);
} else {
- cb.loadLocal(REFERENCE, 0); // load target arg
+ cb.aload(0); // load target arg
}
cb.checkcast(CD_MethodHandle);
// load all the leaf args
@@ -496,8 +495,8 @@ private void emitGetInput() {
}
private void emitAcquireScope() {
- cb.checkcast(CD_AbstractMemorySegmentImpl);
- cb.invokevirtual(CD_AbstractMemorySegmentImpl, "sessionImpl", MTD_SESSION_IMPL);
+ cb.checkcast(CD_AbstractMemorySegmentImpl)
+ .invokevirtual(CD_AbstractMemorySegmentImpl, "sessionImpl", MTD_SESSION_IMPL);
Label skipAcquire = cb.newLabel();
Label end = cb.newLabel();
@@ -505,23 +504,22 @@ private void emitAcquireScope() {
assert curScopeLocalIdx != -1;
boolean hasOtherScopes = curScopeLocalIdx != 0;
for (int i = 0; i < curScopeLocalIdx; i++) {
- cb.dup(); // dup for comparison
- cb.loadLocal(REFERENCE, scopeSlots[i]);
- cb.if_acmpeq(skipAcquire);
+ cb.dup() // dup for comparison
+ .aload(scopeSlots[i])
+ .if_acmpeq(skipAcquire);
}
// 1 scope to acquire on the stack
cb.dup();
int nextScopeLocal = scopeSlots[curScopeLocalIdx++];
// call acquire first here. So that if it fails, we don't call release
- cb.invokevirtual(CD_MemorySessionImpl, "acquire0", MTD_ACQUIRE0); // call acquire on the other
- cb.storeLocal(REFERENCE, nextScopeLocal); // store off one to release later
+ cb.invokevirtual(CD_MemorySessionImpl, "acquire0", MTD_ACQUIRE0) // call acquire on the other
+ .astore(nextScopeLocal); // store off one to release later
if (hasOtherScopes) { // avoid ASM generating a bunch of nops for the dead code
- cb.goto_(end);
-
- cb.labelBinding(skipAcquire);
- cb.pop(); // drop scope
+ cb.goto_(end)
+ .labelBinding(skipAcquire)
+ .pop(); // drop scope
}
cb.labelBinding(end);
@@ -529,10 +527,10 @@ private void emitAcquireScope() {
private void emitReleaseScopes() {
for (int scopeLocal : scopeSlots) {
- cb.loadLocal(REFERENCE, scopeLocal);
- cb.ifThen(Opcode.IFNONNULL, ifCb -> {
- ifCb.loadLocal(REFERENCE, scopeLocal);
- ifCb.invokevirtual(CD_MemorySessionImpl, "release0", MTD_RELEASE0);
+ cb.aload(scopeLocal)
+ .ifThen(Opcode.IFNONNULL, ifCb -> {
+ ifCb.aload(scopeLocal)
+ .invokevirtual(CD_MemorySessionImpl, "release0", MTD_RELEASE0);
});
}
}
@@ -551,28 +549,28 @@ private void emitRestoreReturnValue(Class> loadType) {
private void emitLoadInternalSession() {
assert contextIdx != -1;
- cb.loadLocal(REFERENCE, contextIdx);
- cb.checkcast(CD_Arena);
- cb.invokeinterface(CD_Arena, "scope", MTD_SCOPE);
- cb.checkcast(CD_MemorySessionImpl);
+ cb.aload(contextIdx)
+ .checkcast(CD_Arena)
+ .invokeinterface(CD_Arena, "scope", MTD_SCOPE)
+ .checkcast(CD_MemorySessionImpl);
}
private void emitLoadInternalAllocator() {
assert contextIdx != -1;
- cb.loadLocal(REFERENCE, contextIdx);
+ cb.aload(contextIdx);
}
private void emitCloseContext() {
assert contextIdx != -1;
- cb.loadLocal(REFERENCE, contextIdx);
- cb.checkcast(CD_Arena);
- cb.invokeinterface(CD_Arena, "close", MTD_CLOSE);
+ cb.aload(contextIdx)
+ .checkcast(CD_Arena)
+ .invokeinterface(CD_Arena, "close", MTD_CLOSE);
}
private void emitBoxAddress(BoxAddress boxAddress) {
popType(long.class);
- cb.loadConstant(boxAddress.size());
- cb.loadConstant(boxAddress.align());
+ cb.loadConstant(boxAddress.size())
+ .loadConstant(boxAddress.align());
if (needsSession()) {
emitLoadInternalSession();
cb.invokestatic(CD_Utils, "longToAddress", MTD_LONG_TO_ADDRESS_SCOPE);
@@ -585,7 +583,7 @@ private void emitBoxAddress(BoxAddress boxAddress) {
private void emitAllocBuffer(Allocate binding) {
if (callingSequence.forDowncall()) {
assert returnAllocatorIdx != -1;
- cb.loadLocal(REFERENCE, returnAllocatorIdx);
+ cb.aload(returnAllocatorIdx);
} else {
emitLoadInternalAllocator();
}
@@ -607,8 +605,8 @@ private void emitBufferStore(BufferStore bufferStore) {
cb.storeLocal(storeTypeKind, valueIdx);
ClassDesc valueLayoutType = emitLoadLayoutConstant(storeType);
- cb.loadConstant(offset);
- cb.loadLocal(storeTypeKind, valueIdx);
+ cb.loadConstant(offset)
+ .loadLocal(storeTypeKind, valueIdx);
MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(storeType));
cb.invokeinterface(CD_MemorySegment, "set", descriptor);
} else {
@@ -619,9 +617,9 @@ private void emitBufferStore(BufferStore bufferStore) {
assert storeType == long.class; // chunking only for int and long
}
int longValueIdx = cb.allocateLocal(LONG);
- cb.storeLocal(LONG, longValueIdx);
+ cb.lstore(longValueIdx);
int writeAddrIdx = cb.allocateLocal(REFERENCE);
- cb.storeLocal(REFERENCE, writeAddrIdx);
+ cb.astore(writeAddrIdx);
int remaining = byteWidth;
int chunkOffset = 0;
@@ -648,25 +646,25 @@ private void emitBufferStore(BufferStore bufferStore) {
//int writeChunk = (int) (((0xFFFF_FFFFL << shiftAmount) & longValue) >>> shiftAmount);
int shiftAmount = chunkOffset * Byte.SIZE;
mask = mask << shiftAmount;
- cb.loadLocal(LONG, longValueIdx);
- cb.loadConstant(mask);
- cb.land();
+ cb.lload(longValueIdx)
+ .loadConstant(mask)
+ .land();
if (shiftAmount != 0) {
- cb.loadConstant(shiftAmount);
- cb.lushr();
+ cb.loadConstant(shiftAmount)
+ .lushr();
}
cb.l2i();
TypeKind chunkStoreTypeKind = TypeKind.from(chunkStoreType);
int chunkIdx = cb.allocateLocal(chunkStoreTypeKind);
- cb.storeLocal(chunkStoreTypeKind, chunkIdx);
+ cb.storeLocal(chunkStoreTypeKind, chunkIdx)
// chunk done, now write it
//writeAddress.set(JAVA_SHORT_UNALIGNED, offset, writeChunk);
- cb.loadLocal(REFERENCE, writeAddrIdx);
+ .aload(writeAddrIdx);
ClassDesc valueLayoutType = emitLoadLayoutConstant(chunkStoreType);
long writeOffset = offset + SharedUtils.pickChunkOffset(chunkOffset, byteWidth, chunkSize);
- cb.loadConstant(writeOffset);
- cb.loadLocal(chunkStoreTypeKind, chunkIdx);
+ cb.loadConstant(writeOffset)
+ .loadLocal(chunkStoreTypeKind, chunkIdx);
MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(chunkStoreType));
cb.invokeinterface(CD_MemorySegment, "set", descriptor);
@@ -690,16 +688,16 @@ private void emitVMStore(VMStore vmStore) {
if (!callingSequence.needsReturnBuffer()) {
emitSaveReturnValue(storeType);
} else {
- int valueIdx = cb.allocateLocal(storeTypeKind);
- cb.storeLocal(storeTypeKind, valueIdx); // store away the stored value, need it later
-
assert returnBufferIdx != -1;
- cb.loadLocal(REFERENCE, returnBufferIdx);
+ int valueIdx = cb.allocateLocal(storeTypeKind);
+ cb.storeLocal(storeTypeKind, valueIdx) // store away the stored value, need it later
+ .aload(returnBufferIdx);
ClassDesc valueLayoutType = emitLoadLayoutConstant(storeType);
- cb.loadConstant(retBufOffset);
- cb.loadLocal(storeTypeKind, valueIdx);
- MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(storeType));
- cb.invokeinterface(CD_MemorySegment, "set", descriptor);
+ cb.loadConstant(retBufOffset)
+ .loadLocal(storeTypeKind, valueIdx)
+ .invokeinterface(CD_MemorySegment,
+ "set",
+ MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(storeType)));
retBufOffset += abi.arch.typeSize(vmStore.storage().type());
}
}
@@ -714,11 +712,12 @@ private void emitVMLoad(VMLoad vmLoad) {
emitRestoreReturnValue(loadType);
} else {
assert returnBufferIdx != -1;
- cb.loadLocal(REFERENCE, returnBufferIdx);
+ cb.aload(returnBufferIdx);
ClassDesc valueLayoutType = emitLoadLayoutConstant(loadType);
- cb.loadConstant(retBufOffset);
- MethodTypeDesc descriptor = MethodTypeDesc.of(classDesc(loadType), valueLayoutType, CD_long);
- cb.invokeinterface(CD_MemorySegment, "get", descriptor);
+ cb.loadConstant(retBufOffset)
+ .invokeinterface(CD_MemorySegment,
+ "get",
+ MethodTypeDesc.of(classDesc(loadType), valueLayoutType, CD_long));
retBufOffset += abi.arch.typeSize(vmLoad.storage().type());
pushType(loadType);
}
@@ -736,15 +735,15 @@ private void emitDupBinding() {
private void emitShiftLeft(ShiftLeft shiftLeft) {
popType(long.class);
- cb.loadConstant(shiftLeft.shiftAmount() * Byte.SIZE);
- cb.lshl();
+ cb.loadConstant(shiftLeft.shiftAmount() * Byte.SIZE)
+ .lshl();
pushType(long.class);
}
private void emitShiftRight(ShiftRight shiftRight) {
popType(long.class);
- cb.loadConstant(shiftRight.shiftAmount() * Byte.SIZE);
- cb.lushr();
+ cb.loadConstant(shiftRight.shiftAmount() * Byte.SIZE)
+ .lushr();
pushType(long.class);
}
@@ -758,11 +757,10 @@ private void emitCast(Cast cast) {
// implement least significant byte non-zero test
// select first byte
- cb.loadConstant(0xFF);
- cb.iand();
-
- // convert to boolean
- cb.invokestatic(CD_Utils, "byteToBoolean", MTD_BYTE_TO_BOOLEAN);
+ cb.loadConstant(0xFF)
+ .iand()
+ // convert to boolean
+ .invokestatic(CD_Utils, "byteToBoolean", MTD_BYTE_TO_BOOLEAN);
}
case INT_TO_BYTE -> cb.i2b();
case INT_TO_CHAR -> cb.i2c();
@@ -782,8 +780,8 @@ private void emitCast(Cast cast) {
private void emitSegmentBase() {
popType(MemorySegment.class);
- cb.checkcast(CD_AbstractMemorySegmentImpl);
- cb.invokevirtual(CD_AbstractMemorySegmentImpl, "unsafeGetBase", MTD_UNSAFE_GET_BASE);
+ cb.checkcast(CD_AbstractMemorySegmentImpl)
+ .invokevirtual(CD_AbstractMemorySegmentImpl, "unsafeGetBase", MTD_UNSAFE_GET_BASE);
pushType(Object.class);
}
@@ -791,11 +789,11 @@ private void emitSegmentOffset(SegmentOffset segmentOffset) {
popType(MemorySegment.class);
if (!segmentOffset.allowHeap()) {
- cb.dup();
- cb.invokestatic(CD_SharedUtils, "checkNative", MTD_CHECK_NATIVE);
+ cb.dup()
+ .invokestatic(CD_SharedUtils, "checkNative", MTD_CHECK_NATIVE);
}
- cb.checkcast(CD_AbstractMemorySegmentImpl);
- cb.invokevirtual(CD_AbstractMemorySegmentImpl, "unsafeGetOffset", MTD_UNSAFE_GET_OFFSET);
+ cb.checkcast(CD_AbstractMemorySegmentImpl)
+ .invokevirtual(CD_AbstractMemorySegmentImpl, "unsafeGetOffset", MTD_UNSAFE_GET_OFFSET);
pushType(long.class);
}
@@ -809,17 +807,17 @@ private void emitBufferLoad(BufferLoad bufferLoad) {
if (SharedUtils.isPowerOfTwo(byteWidth)) {
ClassDesc valueLayoutType = emitLoadLayoutConstant(loadType);
- cb.loadConstant(offset);
- MethodTypeDesc descriptor = MethodTypeDesc.of(classDesc(loadType), valueLayoutType, CD_long);
- cb.invokeinterface(CD_MemorySegment, "get", descriptor);
+ cb.loadConstant(offset)
+ .invokeinterface(CD_MemorySegment,
+ "get",
+ MethodTypeDesc.of(classDesc(loadType), valueLayoutType, CD_long));
} else {
// chunked
int readAddrIdx = cb.allocateLocal(REFERENCE);
- cb.storeLocal(REFERENCE, readAddrIdx);
-
- cb.loadConstant(0L); // result
+ cb.astore(readAddrIdx)
+ .loadConstant(0L); // result
int resultIdx = cb.allocateLocal(LONG);
- cb.storeLocal(LONG, resultIdx);
+ cb.lstore(resultIdx);
int remaining = byteWidth;
int chunkOffset = 0;
@@ -848,30 +846,30 @@ private void emitBufferLoad(BufferLoad bufferLoad) {
throw new IllegalStateException("Unexpected chunk size for chunked write: " + chunkSize);
}
// read from segment
- cb.loadLocal(REFERENCE, readAddrIdx);
+ cb.aload(readAddrIdx);
ClassDesc valueLayoutType = emitLoadLayoutConstant(chunkType);
MethodTypeDesc descriptor = MethodTypeDesc.of(classDesc(chunkType), valueLayoutType, CD_long);
long readOffset = offset + SharedUtils.pickChunkOffset(chunkOffset, byteWidth, chunkSize);
- cb.loadConstant(readOffset);
- cb.invokeinterface(CD_MemorySegment, "get", descriptor);
- cb.invokestatic(toULongHolder, "toUnsignedLong", toULongDescriptor);
+ cb.loadConstant(readOffset)
+ .invokeinterface(CD_MemorySegment, "get", descriptor)
+ .invokestatic(toULongHolder, "toUnsignedLong", toULongDescriptor);
// shift to right offset
int shiftAmount = chunkOffset * Byte.SIZE;
if (shiftAmount != 0) {
- cb.loadConstant(shiftAmount);
- cb.lshl();
+ cb.loadConstant(shiftAmount)
+ .lshl();
}
// add to result
- cb.loadLocal(LONG, resultIdx);
- cb.lor();
- cb.storeLocal(LONG, resultIdx);
+ cb.lload(resultIdx)
+ .lor()
+ .lstore(resultIdx);
remaining -= chunkSize;
chunkOffset += chunkSize;
} while (remaining != 0);
- cb.loadLocal(LONG, resultIdx);
+ cb.lload(resultIdx);
if (loadType == int.class) {
cb.l2i();
} else {
@@ -898,19 +896,18 @@ private void emitCopyBuffer(Copy copy) {
emitAllocateCall(size, alignment);
cb.dup();
int storeIdx = cb.allocateLocal(REFERENCE);
- cb.storeLocal(REFERENCE, storeIdx);
- cb.loadConstant(0L);
- cb.loadConstant(size);
- cb.invokestatic(CD_MemorySegment, "copy", MTD_COPY, true);
-
- cb.loadLocal(REFERENCE, storeIdx);
+ cb.astore(storeIdx)
+ .loadConstant(0L)
+ .loadConstant(size)
+ .invokestatic(CD_MemorySegment, "copy", MTD_COPY, true)
+ .aload(storeIdx);
pushType(MemorySegment.class);
}
private void emitAllocateCall(long size, long alignment) {
- cb.loadConstant(size);
- cb.loadConstant(alignment);
- cb.invokeinterface(CD_SegmentAllocator, "allocate", MTD_ALLOCATE);
+ cb.loadConstant(size)
+ .loadConstant(alignment)
+ .invokeinterface(CD_SegmentAllocator, "allocate", MTD_ALLOCATE);
}
private ClassDesc emitLoadLayoutConstant(Class> type) {
diff --git a/src/java.base/share/classes/jdk/internal/util/ModifiedUtf.java b/src/java.base/share/classes/jdk/internal/util/ModifiedUtf.java
new file mode 100644
index 00000000000..a8d2fe8bb74
--- /dev/null
+++ b/src/java.base/share/classes/jdk/internal/util/ModifiedUtf.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2024, Alibaba Group Holding Limited. 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.
+ */
+
+package jdk.internal.util;
+
+import jdk.internal.vm.annotation.ForceInline;
+
+/**
+ * Helper to JDK UTF putChar and Calculate length
+ *
+ * @since 24
+ */
+public abstract class ModifiedUtf {
+ private ModifiedUtf() {
+ }
+
+ @ForceInline
+ public static int putChar(byte[] buf, int offset, char c) {
+ if (c != 0 && c < 0x80) {
+ buf[offset++] = (byte) c;
+ } else if (c >= 0x800) {
+ buf[offset ] = (byte) (0xE0 | c >> 12 & 0x0F);
+ buf[offset + 1] = (byte) (0x80 | c >> 6 & 0x3F);
+ buf[offset + 2] = (byte) (0x80 | c & 0x3F);
+ offset += 3;
+ } else {
+ buf[offset ] = (byte) (0xC0 | c >> 6 & 0x1F);
+ buf[offset + 1] = (byte) (0x80 | c & 0x3F);
+ offset += 2;
+ }
+ return offset;
+ }
+
+ /**
+ * Calculate the utf length of a string
+ * @param str input string
+ * @param countNonZeroAscii the number of non-zero ascii characters in the prefix calculated by JLA.countNonZeroAscii(str)
+ */
+ @ForceInline
+ public static int utfLen(String str, int countNonZeroAscii) {
+ int utflen = str.length();
+ for (int i = utflen - 1; i >= countNonZeroAscii; i--) {
+ int c = str.charAt(i);
+ if (c >= 0x80 || c == 0)
+ utflen += (c >= 0x800) ? 2 : 1;
+ }
+ return utflen;
+ }
+}
diff --git a/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java b/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java
index 0632f846cbf..1baf3264122 100644
--- a/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java
+++ b/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024, Oracle and/or its affiliates. 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
@@ -257,7 +257,20 @@ Map get(CertStatusRequestType type,
}
if (!task.isCancelled()) {
- StatusInfo info = task.get();
+ StatusInfo info;
+ try {
+ info = task.get();
+ } catch (ExecutionException exc) {
+ // Check for an underlying cause available and log
+ // that, otherwise just log the ExecutionException
+ Throwable cause = Optional.ofNullable(
+ exc.getCause()).orElse(exc);
+ if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
+ SSLLogger.fine("Exception during OCSP fetch: " +
+ cause);
+ }
+ continue;
+ }
if (info != null && info.responseData != null) {
responseMap.put(info.cert,
info.responseData.ocspBytes);
@@ -272,10 +285,12 @@ Map get(CertStatusRequestType type,
}
}
}
- } catch (InterruptedException | ExecutionException exc) {
- // Not sure what else to do here
+ } catch (InterruptedException intex) {
+ // Log and reset the interrupt state
+ Thread.currentThread().interrupt();
if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) {
- SSLLogger.fine("Exception when getting data: ", exc);
+ SSLLogger.fine("Interrupt occurred while fetching: " +
+ intex);
}
}
}
@@ -582,8 +597,7 @@ private void addToCache(CertId certId, ResponseCacheEntry entry) {
}
- static final StaplingParameters processStapling(
- ServerHandshakeContext shc) {
+ static StaplingParameters processStapling(ServerHandshakeContext shc) {
StaplingParameters params = null;
SSLExtension ext = null;
CertStatusRequestType type = null;
diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java
index 3b09bd259ce..2a036d22aed 100644
--- a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java
+++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2024, Oracle and/or its affiliates. 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
@@ -58,6 +58,7 @@ class UnixFileAttributes
private long st_ctime_nsec;
private long st_birthtime_sec;
private long st_birthtime_nsec;
+ private boolean birthtime_available;
// created lazily
private volatile UserPrincipal owner;
@@ -163,10 +164,10 @@ public FileTime lastAccessTime() {
@Override
public FileTime creationTime() {
- if (UnixNativeDispatcher.birthtimeSupported()) {
+ if (UnixNativeDispatcher.birthtimeSupported() && birthtime_available) {
return toFileTime(st_birthtime_sec, st_birthtime_nsec);
} else {
- // return last modified when birth time not supported
+ // return last modified when birth time unsupported or unavailable
return lastModifiedTime();
}
}
diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c
index b91ab6f0cab..61e9215471a 100644
--- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c
+++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c
@@ -184,6 +184,7 @@ static jfieldID attrs_st_birthtime_sec;
#if defined(__linux__) // Linux has nsec granularity if supported
static jfieldID attrs_st_birthtime_nsec;
#endif
+static jfieldID attrs_birthtime_available;
static jfieldID attrs_f_frsize;
static jfieldID attrs_f_blocks;
@@ -332,6 +333,8 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this)
attrs_st_birthtime_nsec = (*env)->GetFieldID(env, clazz, "st_birthtime_nsec", "J");
CHECK_NULL_RETURN(attrs_st_birthtime_nsec, 0);
#endif
+ attrs_birthtime_available = (*env)->GetFieldID(env, clazz, "birthtime_available", "Z");
+ CHECK_NULL_RETURN(attrs_birthtime_available, 0);
clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileStoreAttributes");
CHECK_NULL_RETURN(clazz, 0);
@@ -620,19 +623,19 @@ static void copy_statx_attributes(JNIEnv* env, struct my_statx* buf, jobject att
(*env)->SetLongField(env, attrs, attrs_st_atime_sec, (jlong)buf->stx_atime.tv_sec);
(*env)->SetLongField(env, attrs, attrs_st_mtime_sec, (jlong)buf->stx_mtime.tv_sec);
(*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->stx_ctime.tv_sec);
+
+ // Check mask for birth time and set flag accordingly. The birth time is
+ // filled in if and only if the STATX_BTIME bit is set in the mask.
+ // Although the statx system call might be supported by the operating
+ // system, the birth time is not necessarily supported by the file system.
if ((buf->stx_mask & STATX_BTIME) != 0) {
- // Birth time was filled in so use it
- (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec,
- (jlong)buf->stx_btime.tv_sec);
- (*env)->SetLongField(env, attrs, attrs_st_birthtime_nsec,
- (jlong)buf->stx_btime.tv_nsec);
+ (*env)->SetBooleanField(env, attrs, attrs_birthtime_available, (jboolean)JNI_TRUE);
+ (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->stx_btime.tv_sec);
+ (*env)->SetLongField(env, attrs, attrs_st_birthtime_nsec, (jlong)buf->stx_btime.tv_nsec);
} else {
- // Birth time was not filled in: fall back to last modification time
- (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec,
- (jlong)buf->stx_mtime.tv_sec);
- (*env)->SetLongField(env, attrs, attrs_st_birthtime_nsec,
- (jlong)buf->stx_mtime.tv_nsec);
+ (*env)->SetBooleanField(env, attrs, attrs_birthtime_available, (jboolean)JNI_FALSE);
}
+
(*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->stx_atime.tv_nsec);
(*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->stx_mtime.tv_nsec);
(*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->stx_ctime.tv_nsec);
@@ -661,7 +664,9 @@ static void copy_stat_attributes(JNIEnv* env, struct stat* buf, jobject attrs) {
(*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->st_ctime);
#ifdef _DARWIN_FEATURE_64_BIT_INODE
+ // birthtime_available defaults to 'false'; on Darwin, it is always true
(*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->st_birthtime);
+ (*env)->SetBooleanField(env, attrs, attrs_birthtime_available, (jboolean)JNI_TRUE);
// rely on default value of 0 for st_birthtime_nsec field on Darwin
#endif
diff --git a/src/java.compiler/share/classes/javax/lang/model/util/Types.java b/src/java.compiler/share/classes/javax/lang/model/util/Types.java
index ce83cda4058..951b56ed214 100644
--- a/src/java.compiler/share/classes/javax/lang/model/util/Types.java
+++ b/src/java.compiler/share/classes/javax/lang/model/util/Types.java
@@ -206,7 +206,7 @@ public interface Types {
*
* @throws IllegalArgumentException if the given type has no
* unboxing conversion. Only types for the {@linkplain
- * java.lang##wrapperClasses wrapper classes} have an
+ * java.lang##wrapperClass wrapper classes} have an
* unboxing conversion.
* @jls 5.1.8 Unboxing Conversion
*/
@@ -263,7 +263,10 @@ public interface Types {
*
* @param componentType the component type
* @throws IllegalArgumentException if the component type is not valid for
- * an array, including executable, package, module, and wildcard types
+ * an array. All valid types are {@linkplain ReferenceType
+ * reference types} or {@linkplain PrimitiveType primitive types}.
+ * Invalid types include {@linkplain NullType null}, executable, package,
+ * module, and wildcard types.
* @jls 10.1 Array Types
*/
ArrayType getArrayType(TypeMirror componentType);
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
index fd4a72bae45..0fe08f0b611 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
@@ -1861,6 +1861,10 @@ Symbol findMethod(Env env,
bestSoFar,
allowBoxing,
useVarargs);
+ if (bestSoFar.kind == AMBIGUOUS) {
+ AmbiguityError a_err = (AmbiguityError)bestSoFar.baseSymbol();
+ bestSoFar = a_err.mergeAbstracts(site);
+ }
return bestSoFar;
}
// where
@@ -2765,7 +2769,7 @@ Symbol resolveMethod(DiagnosticPosition pos,
return lookupMethod(env, pos, env.enclClass.sym, resolveMethodCheck,
new BasicLookupHelper(name, env.enclClass.sym.type, argtypes, typeargtypes) {
@Override
- Symbol doLookup(Env env, MethodResolutionPhase phase) {
+ Symbol lookup(Env env, MethodResolutionPhase phase) {
return findFun(env, name, argtypes, typeargtypes,
phase.isBoxingRequired(),
phase.isVarargsRequired());
@@ -2797,7 +2801,7 @@ private Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext,
List typeargtypes) {
return lookupMethod(env, pos, location, resolveContext, new BasicLookupHelper(name, site, argtypes, typeargtypes) {
@Override
- Symbol doLookup(Env env, MethodResolutionPhase phase) {
+ Symbol lookup(Env env, MethodResolutionPhase phase) {
return findMethod(env, site, name, argtypes, typeargtypes,
phase.isBoxingRequired(),
phase.isVarargsRequired());
@@ -2921,7 +2925,7 @@ private Symbol resolveConstructor(MethodResolutionContext resolveContext,
List typeargtypes) {
return lookupMethod(env, pos, site.tsym, resolveContext, new BasicLookupHelper(names.init, site, argtypes, typeargtypes) {
@Override
- Symbol doLookup(Env env, MethodResolutionPhase phase) {
+ Symbol lookup(Env env, MethodResolutionPhase phase) {
return findConstructor(pos, env, site, argtypes, typeargtypes,
phase.isBoxingRequired(),
phase.isVarargsRequired());
@@ -2980,7 +2984,7 @@ Symbol resolveDiamond(DiagnosticPosition pos,
return lookupMethod(env, pos, site.tsym, resolveMethodCheck,
new BasicLookupHelper(names.init, site, argtypes, typeargtypes) {
@Override
- Symbol doLookup(Env env, MethodResolutionPhase phase) {
+ Symbol lookup(Env env, MethodResolutionPhase phase) {
return findDiamond(pos, env, site, argtypes, typeargtypes,
phase.isBoxingRequired(),
phase.isVarargsRequired());
@@ -3511,18 +3515,6 @@ abstract class BasicLookupHelper extends LookupHelper {
super(name, site, argtypes, typeargtypes, maxPhase);
}
- @Override
- final Symbol lookup(Env env, MethodResolutionPhase phase) {
- Symbol sym = doLookup(env, phase);
- if (sym.kind == AMBIGUOUS) {
- AmbiguityError a_err = (AmbiguityError)sym.baseSymbol();
- sym = a_err.mergeAbstracts(site);
- }
- return sym;
- }
-
- abstract Symbol doLookup(Env env, MethodResolutionPhase phase);
-
@Override
Symbol access(Env env, DiagnosticPosition pos, Symbol location, Symbol sym) {
if (sym.kind.isResolutionError()) {
@@ -3569,10 +3561,6 @@ ReferenceLookupHelper unboundLookup(InferenceContext inferenceContext) {
abstract JCMemberReference.ReferenceKind referenceKind(Symbol sym);
Symbol access(Env env, DiagnosticPosition pos, Symbol location, Symbol sym) {
- if (sym.kind == AMBIGUOUS) {
- AmbiguityError a_err = (AmbiguityError)sym.baseSymbol();
- sym = a_err.mergeAbstracts(site);
- }
//skip error reporting
return sym;
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java
index 1bc5de7f73a..71e39a6a408 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java
@@ -193,10 +193,14 @@ public NoType getNoType(TypeKind kind) {
public ArrayType getArrayType(TypeMirror componentType) {
switch (componentType.getKind()) {
case VOID:
+ case NONE:
+ case NULL:
case EXECUTABLE:
case WILDCARD: // heh!
case PACKAGE:
case MODULE:
+ case UNION:
+ case INTERSECTION:
throw new IllegalArgumentException(componentType.toString());
}
return new Type.ArrayType((Type) componentType, syms.arrayClass);
diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp b/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp
index 962b1ae5172..0ad95d0eac7 100644
--- a/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp
+++ b/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp
@@ -420,7 +420,6 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo
jboolean isCopy;
jlongArray array;
jlong *regs;
- int i;
struct ps_prochandle* ph = get_proc_handle(env, this_obj);
if (get_lwp_regs(ph, lwp_id, &gregs) != true) {
diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c
index d3b4d3d1af9..c36b9e5707e 100644
--- a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c
+++ b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c
@@ -356,7 +356,6 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t
if (shdr->sh_type == sym_section) {
ELF_SYM *syms;
- int rslt;
size_t size, n, j, htab_sz;
// FIXME: there could be multiple data buffers associated with the
@@ -390,7 +389,8 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t
goto bad;
}
- rslt = hcreate_r(htab_sz, symtab->hash_table);
+ // int rslt =
+ hcreate_r(htab_sz, symtab->hash_table);
// guarantee(rslt, "unexpected failure: hcreate_r");
// shdr->sh_link points to the section that contains the actual strings
diff --git a/src/jdk.incubator.vector/linux/native/libsleef/lib/vector_math_rvv.c b/src/jdk.incubator.vector/linux/native/libsleef/lib/vector_math_rvv.c
new file mode 100644
index 00000000000..4515457fa89
--- /dev/null
+++ b/src/jdk.incubator.vector/linux/native/libsleef/lib/vector_math_rvv.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2024, Rivos Inc. 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.
+ */
+
+// On riscv, sleef vector apis depend on native vector intrinsic, which is supported on
+// some compiler, e.g. gcc 14+.
+// __riscv_v_intrinsic is used to tell if the compiler supports vector intrinsic.
+//
+// At compile-time, if the current compiler does support vector intrinsics, bridge
+// functions will be built in the library. In case the current compiler doesn't support
+// vector intrinsics (gcc < 14), then the bridge functions won't be compiled.
+// At run-time, if the library is found and the bridge functions are available in the
+// library, then the java vector API will call into the bridge functions and sleef.
+
+#ifdef __riscv_v_intrinsic
+
+#include
+
+#include
+
+#include "../generated/misc.h"
+#include "../generated/sleefinline_rvvm1.h"
+
+#include
+
+// We maintain an invariant in java world that default dynamic rounding mode is RNE,
+// please check JDK-8330094, JDK-8330266 for more details.
+// Currently, sleef source on riscv does not change rounding mode to others except
+// of RNE. But we still think it's safer to make sure that after calling into sleef
+// the dynamic rounding mode is always RNE.
+
+#ifdef DEBUG
+#define CHECK_FRM __asm__ __volatile__ ( \
+ " frrm t0 \n\t" \
+ " beqz t0, 2f \n\t" \
+ " csrrw x0, cycle, x0 \n\t" \
+ "2: \n\t" \
+ : : : "memory" );
+#else
+#define CHECK_FRM
+#endif
+
+#define DEFINE_VECTOR_MATH_UNARY_RVV(op, type) \
+JNIEXPORT \
+type op##rvv(type input) { \
+ type res = Sleef_##op##rvvm1(input); \
+ CHECK_FRM \
+ return res; \
+}
+
+#define DEFINE_VECTOR_MATH_BINARY_RVV(op, type) \
+JNIEXPORT \
+type op##rvv(type input1, type input2) { \
+ type res = Sleef_##op##rvvm1(input1, input2); \
+ CHECK_FRM \
+ return res; \
+}
+
+DEFINE_VECTOR_MATH_UNARY_RVV(tanfx_u10, vfloat_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(sinfx_u10, vfloat_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(sinhfx_u10, vfloat_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(cosfx_u10, vfloat_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(coshfx_u10, vfloat_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(asinfx_u10, vfloat_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(acosfx_u10, vfloat_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(atanfx_u10, vfloat_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(cbrtfx_u10, vfloat_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(logfx_u10, vfloat_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(log10fx_u10, vfloat_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(log1pfx_u10, vfloat_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(expfx_u10, vfloat_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(expm1fx_u10, vfloat_rvvm1_sleef)
+
+DEFINE_VECTOR_MATH_UNARY_RVV(tandx_u10, vdouble_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(sindx_u10, vdouble_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(sinhdx_u10, vdouble_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(cosdx_u10, vdouble_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(coshdx_u10, vdouble_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(asindx_u10, vdouble_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(acosdx_u10, vdouble_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(atandx_u10, vdouble_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(cbrtdx_u10, vdouble_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(logdx_u10, vdouble_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(log10dx_u10, vdouble_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(log1pdx_u10, vdouble_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(expdx_u10, vdouble_rvvm1_sleef)
+DEFINE_VECTOR_MATH_UNARY_RVV(expm1dx_u10, vdouble_rvvm1_sleef)
+
+DEFINE_VECTOR_MATH_BINARY_RVV(atan2fx_u10, vfloat_rvvm1_sleef)
+DEFINE_VECTOR_MATH_BINARY_RVV(powfx_u10, vfloat_rvvm1_sleef)
+DEFINE_VECTOR_MATH_BINARY_RVV(hypotfx_u05, vfloat_rvvm1_sleef)
+
+DEFINE_VECTOR_MATH_BINARY_RVV(atan2dx_u10, vdouble_rvvm1_sleef)
+DEFINE_VECTOR_MATH_BINARY_RVV(powdx_u10, vdouble_rvvm1_sleef)
+DEFINE_VECTOR_MATH_BINARY_RVV(hypotdx_u05, vdouble_rvvm1_sleef)
+
+#undef DEFINE_VECTOR_MATH_UNARY_RVV
+
+#undef DEFINE_VECTOR_MATH_BINARY_RVV
+
+#endif /* __riscv_v_intrinsic */
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template
index 633f453bc43..2185b1c951f 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template
@@ -300,6 +300,7 @@ document.addEventListener("DOMContentLoaded", function(e) {
});
var expanded = false;
var windowWidth;
+ var bodyHeight;
function collapse(e) {
if (expanded) {
mainnav.removeAttribute("style");
@@ -365,6 +366,7 @@ document.addEventListener("DOMContentLoaded", function(e) {
var scrollTimeoutNeeded;
var prevHash;
function initSectionData() {
+ bodyHeight = document.body.offsetHeight;
sections = [{ id: "", top: 0 }].concat(Array.from(main.querySelectorAll("section[id], h2[id], h2 a[id], div[id]"))
.filter((e) => {
return sidebar.querySelector("a[href=\"#" + encodeURI(e.getAttribute("id")) + "\"]") !== null
@@ -469,7 +471,7 @@ document.addEventListener("DOMContentLoaded", function(e) {
expand();
}
}
- if (sections) {
+ if (sections && document.body.offsetHeight !== bodyHeight) {
initSectionData();
prevHash = null;
handleScroll();
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css
index 97fcc91eadc..641a6684444 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css
@@ -28,8 +28,8 @@
/* Line height for continuous text blocks */
--block-line-height: 1.4em;
/* Text colors for body and block elements */
- --body-text-color: #353833;
- --block-text-color: #474747;
+ --body-text-color: #282828;
+ --block-text-color: #282828;
/* Background colors for various structural elements */
--body-background-color: #ffffff;
--section-background-color: #f8f8f8;
@@ -49,8 +49,11 @@
/* Text color for page title */
--title-color: #2c4557;
/* Text colors for links */
- --link-color: #4A6782;
+ --link-color: #437291;
--link-color-active: #bb7a2a;
+ /* Table of contents */
+ --toc-background-color: var(--section-background-color);
+ --toc-link-color: #4a698a;
/* Snippet colors */
--snippet-background-color: #ebecee;
--snippet-text-color: var(--block-text-color);
@@ -99,6 +102,9 @@ a:link, a:visited {
text-decoration:none;
color:var(--link-color);
}
+nav a:link, nav a:visited {
+ color: var(--toc-link-color);
+}
a[href]:hover, a[href]:active {
text-decoration:none;
color:var(--link-color-active);
@@ -398,7 +404,7 @@ dl.name-value > dd {
* Styles for table of contents.
*/
.main-grid nav.toc {
- background-color: var(--section-background-color);
+ background-color: var(--toc-background-color);
border-right: 1px solid var(--border-color);
position: sticky;
top: calc(var(--nav-height));
@@ -409,8 +415,6 @@ dl.name-value > dd {
z-index: 1;
}
.main-grid nav.toc div.toc-header {
- background-color: var(--section-background-color);
- border-right: 1px solid var(--border-color);
top: var(--nav-height);
z-index: 1;
padding: 15px 20px;
@@ -473,7 +477,6 @@ nav.toc div.toc-header {
display: inline-flex;
align-items: center;
color: var(--body-text-color);
- background-color: var(--body-background-color);
font-size: 0.856em;
font-weight: bold;
white-space: nowrap;
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.c b/src/jdk.jdwp.agent/share/native/libjdwp/util.c
index 98e19d450cc..141dde0e372 100644
--- a/src/jdk.jdwp.agent/share/native/libjdwp/util.c
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.c
@@ -1651,6 +1651,185 @@ setAgentPropertyValue(JNIEnv *env, char *propertyName, char* propertyValue)
}
}
+#ifdef DEBUG
+// APIs that can be called when debugging the debug agent
+
+#define check_jvmti_status(err, msg) \
+ if (err != JVMTI_ERROR_NONE) { \
+ EXIT_ERROR(err, msg); \
+ }
+
+char*
+translateThreadState(jint flags) {
+ char str[15 * 20];
+ str[0] = '\0';
+
+ if (flags & JVMTI_THREAD_STATE_ALIVE) {
+ strcat(str, " ALIVE");
+ }
+ if (flags & JVMTI_THREAD_STATE_TERMINATED) {
+ strcat(str, " TERMINATED");
+ }
+ if (flags & JVMTI_THREAD_STATE_RUNNABLE) {
+ strcat(str, " RUNNABLE");
+ }
+ if (flags & JVMTI_THREAD_STATE_WAITING) {
+ strcat(str, " WAITING");
+ }
+ if (flags & JVMTI_THREAD_STATE_WAITING_INDEFINITELY) {
+ strcat(str, " WAITING_INDEFINITELY");
+ }
+ if (flags & JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT) {
+ strcat(str, " WAITING_WITH_TIMEOUT");
+ }
+ if (flags & JVMTI_THREAD_STATE_SLEEPING) {
+ strcat(str, " SLEEPING");
+ }
+ if (flags & JVMTI_THREAD_STATE_IN_OBJECT_WAIT) {
+ strcat(str, " IN_OBJECT_WAIT");
+ }
+ if (flags & JVMTI_THREAD_STATE_PARKED) {
+ strcat(str, " PARKED");
+ }
+ if (flags & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER) {
+ strcat(str, " BLOCKED_ON_MONITOR_ENTER");
+ }
+ if (flags & JVMTI_THREAD_STATE_SUSPENDED) {
+ strcat(str, " SUSPENDED");
+ }
+ if (flags & JVMTI_THREAD_STATE_INTERRUPTED) {
+ strcat(str, " INTERRUPTED");
+ }
+ if (flags & JVMTI_THREAD_STATE_IN_NATIVE) {
+ strcat(str, " IN_NATIVE");
+ }
+
+ if (strlen(str) == 0) {
+ strcpy(str, "");
+ }
+
+ char* tstate = (char*)jvmtiAllocate((int)strlen(str) + 1);
+ strcpy(tstate, str);
+
+ return tstate;
+}
+
+char*
+getThreadName(jthread thread) {
+ jvmtiThreadInfo thr_info;
+ jvmtiError err;
+
+ memset(&thr_info, 0, sizeof(thr_info));
+ err = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo)
+ (gdata->jvmti, thread, &thr_info);
+ if (err == JVMTI_ERROR_WRONG_PHASE || err == JVMTI_ERROR_THREAD_NOT_ALIVE) {
+ return NULL; // VM or target thread completed its work
+ }
+ check_jvmti_status(err, "getThreadName: error in JVMTI GetThreadInfo call");
+
+ char* tname = thr_info.name;
+ if (tname == NULL) {
+ const char* UNNAMED_STR = "";
+ size_t UNNAMED_LEN = strlen(UNNAMED_STR);
+ tname = (char*)jvmtiAllocate((int)UNNAMED_LEN + 1);
+ strcpy(tname, UNNAMED_STR);
+ }
+ return tname;
+}
+
+char*
+getMethodName(jmethodID method) {
+ char* mname = NULL;
+ jvmtiError err;
+
+ err = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodName)
+ (gdata->jvmti, method, &mname, NULL, NULL);
+ check_jvmti_status(err, "getMethodName: error in JVMTI GetMethodName call");
+
+ return mname;
+}
+
+static char*
+get_method_class_name(jmethodID method) {
+ jclass klass = NULL;
+ char* cname = NULL;
+ char* result = NULL;
+ jvmtiError err;
+
+ err = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass)
+ (gdata->jvmti, method, &klass);
+ check_jvmti_status(err, "get_method_class_name: error in JVMTI GetMethodDeclaringClass");
+
+ err = JVMTI_FUNC_PTR(gdata->jvmti,GetClassSignature)
+ (gdata->jvmti, klass, &cname, NULL);
+ check_jvmti_status(err, "get_method_class_name: error in JVMTI GetClassSignature");
+
+ size_t len = strlen(cname) - 2; // get rid of leading 'L' and trailing ';'
+ result = (char*)jvmtiAllocate((int)len + 1);
+ strncpy(result, cname + 1, len); // skip leading 'L'
+ result[len] = '\0';
+ jvmtiDeallocate((void*)cname);
+ return result;
+}
+
+static void
+print_method(jmethodID method, jint depth) {
+ char* cname = NULL;
+ char* mname = NULL;
+ char* msign = NULL;
+ jvmtiError err;
+
+ cname = get_method_class_name(method);
+
+ err = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodName)
+ (gdata->jvmti, method, &mname, &msign, NULL);
+ check_jvmti_status(err, "print_method: error in JVMTI GetMethodName");
+
+ tty_message("%2d: %s: %s%s", depth, cname, mname, msign);
+ jvmtiDeallocate((void*)cname);
+ jvmtiDeallocate((void*)mname);
+ jvmtiDeallocate((void*)msign);
+}
+
+#define MAX_FRAME_COUNT_PRINT_STACK_TRACE 200
+
+void
+printStackTrace(jthread thread) {
+ jvmtiFrameInfo frames[MAX_FRAME_COUNT_PRINT_STACK_TRACE];
+ char* tname = getThreadName(thread);
+ jint count = 0;
+
+ jvmtiError err = JVMTI_FUNC_PTR(gdata->jvmti,GetStackTrace)
+ (gdata->jvmti, thread, 0, MAX_FRAME_COUNT_PRINT_STACK_TRACE, frames, &count);
+ check_jvmti_status(err, "printStackTrace: error in JVMTI GetStackTrace");
+
+ tty_message("JVMTI Stack Trace for thread %s: frame count: %d", tname, count);
+ for (int depth = 0; depth < count; depth++) {
+ print_method(frames[depth].method, depth);
+ }
+ jvmtiDeallocate((void*)tname);
+}
+
+void
+printThreadInfo(jthread thread) {
+ jvmtiThreadInfo thread_info;
+ jint thread_state;
+ jvmtiError err;
+ err = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo)
+ (gdata->jvmti, thread, &thread_info);
+ check_jvmti_status(err, "Error in GetThreadInfo");
+ err = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadState)
+ (gdata->jvmti, thread, &thread_state);
+ check_jvmti_status(err, "Error in GetThreadState");
+ const char* state = translateThreadState(thread_state);
+ tty_message("Thread: %p, name: %s, state(%x): %s, attrs: %s %s",
+ thread, thread_info.name, thread_state, state,
+ (isVThread(thread) ? "virtual": "platform"),
+ (thread_info.is_daemon ? "daemon": ""));
+}
+
+#endif /* DEBUG*/
+
/**
* Return property value as JDWP allocated string in UTF8 encoding
*/
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.h b/src/jdk.jdwp.agent/share/native/libjdwp/util.h
index 75281813709..3d499d7d569 100644
--- a/src/jdk.jdwp.agent/share/native/libjdwp/util.h
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.h
@@ -386,6 +386,15 @@ jvmtiError allNestedClasses(jclass clazz, jclass **ppnested, jint *pcount);
void setAgentPropertyValue(JNIEnv *env, char *propertyName, char* propertyValue);
+#ifdef DEBUG
+// APIs that can be called when debugging the debug agent
+char* translateThreadState(jint flags);
+char* getThreadName(jthread thread);
+char* getMethodName(jmethodID method);
+void printStackTrace(jthread thread);
+void printThreadInfo(jthread thread);
+#endif
+
void *jvmtiAllocate(jint numBytes);
void jvmtiDeallocate(void *buffer);
diff --git a/src/jdk.jpackage/share/native/common/Log.cpp b/src/jdk.jpackage/share/native/common/Log.cpp
index 66154ee8247..8227bb1cce4 100644
--- a/src/jdk.jpackage/share/native/common/Log.cpp
+++ b/src/jdk.jpackage/share/native/common/Log.cpp
@@ -40,10 +40,6 @@ namespace {
// variables are initialized if any. This will result in AV. To avoid such
// use cases keep logging module free from static variables that require
// initialization with functions called by CRT.
- //
-
- // by default log everything
- const Logger::LogLevel defaultLogLevel = Logger::LOG_TRACE;
char defaultLogAppenderMemory[sizeof(StreamLogAppender)] = {};
diff --git a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp
index a4ac2fee66b..d55d6dbfc23 100644
--- a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp
+++ b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp
@@ -93,6 +93,18 @@ class OopStorage::TestAccess : public AllStatic {
static void block_array_set_block_count(ActiveArray* blocks, size_t count) {
blocks->_block_count = count;
}
+
+ static const oop* get_block_pointer(const Block& block, unsigned index) {
+ return block.get_pointer(index);
+ }
+
+ static Block* new_block(const OopStorage& owner) {
+ return Block::new_block(&owner);
+ }
+
+ static void delete_block(const Block& block) {
+ Block::delete_block(block);
+ }
};
typedef OopStorage::TestAccess TestAccess;
@@ -518,24 +530,35 @@ TEST_VM_F(OopStorageTest, bulk_allocation) {
}
}
-#ifndef DISABLE_GARBAGE_ALLOCATION_STATUS_TESTS
-TEST_VM_F(OopStorageTest, invalid_pointer) {
- {
- char* mem = NEW_C_HEAP_ARRAY(char, 1000, mtInternal);
- oop* ptr = reinterpret_cast(align_down(mem + 250, sizeof(oop)));
- // Predicate returns false for some malloc'ed block.
- EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr));
- FREE_C_HEAP_ARRAY(char, mem);
- }
+TEST_VM_F(OopStorageTest, invalid_malloc_pointer) {
+ char* mem = NEW_C_HEAP_ARRAY(char, 1000, mtInternal);
+ oop* ptr = reinterpret_cast(align_down(mem + 250, sizeof(oop)));
+ // Predicate returns false for some malloc'ed block.
+ EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr));
+ FREE_C_HEAP_ARRAY(char, mem);
+}
- {
- oop obj;
- oop* ptr = &obj;
- // Predicate returns false for some "random" location.
- EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr));
- }
+TEST_VM_F(OopStorageTest, invalid_random_pointer) {
+ oop obj;
+ oop* ptr = &obj;
+ // Predicate returns false for some "random" location.
+ EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr));
+}
+
+TEST_VM_F(OopStorageTest, invalid_block_pointer) {
+ // Allocate a block for storage, but don't insert it into the storage. This
+ // also tests the false positive case of block_for_ptr where we have a
+ // reference to storage at just the "right" place.
+ const OopBlock* block = TestAccess::new_block(storage());
+ ASSERT_NE(block, NULL_BLOCK);
+ const oop* ptr = TestAccess::get_block_pointer(*block, 0);
+ EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr));
+ TestAccess::delete_block(*block);
+}
+
+TEST_VM_F(OopStorageTest, invalid_null_pointer) {
+ EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(nullptr));
}
-#endif // DISABLE_GARBAGE_ALLOCATION_STATUS_TESTS
class OopStorageTest::CountingIterateClosure {
public:
diff --git a/test/hotspot/gtest/runtime/test_os_linux.cpp b/test/hotspot/gtest/runtime/test_os_linux.cpp
index 69c3d991b2a..387940afdf2 100644
--- a/test/hotspot/gtest/runtime/test_os_linux.cpp
+++ b/test/hotspot/gtest/runtime/test_os_linux.cpp
@@ -360,10 +360,10 @@ TEST_VM(os_linux, pretouch_thp_and_use_concurrent) {
EXPECT_TRUE(os::commit_memory(heap, size, false));
{
- auto pretouch = [heap, size](Thread*, int) {
+ auto pretouch = [heap](Thread*, int) {
os::pretouch_memory(heap, heap + size, os::vm_page_size());
};
- auto useMemory = [heap, size](Thread*, int) {
+ auto useMemory = [heap](Thread*, int) {
int* iptr = reinterpret_cast(heap);
for (int i = 0; i < 1000; i++) *iptr++ = i;
};
diff --git a/test/hotspot/gtest/runtime/test_os_windows.cpp b/test/hotspot/gtest/runtime/test_os_windows.cpp
index d611b5287a9..c7e99bcdbc5 100644
--- a/test/hotspot/gtest/runtime/test_os_windows.cpp
+++ b/test/hotspot/gtest/runtime/test_os_windows.cpp
@@ -722,6 +722,114 @@ TEST_VM(os_windows, processor_count) {
}
}
+TEST_VM(os_windows, large_page_init_multiple_sizes) {
+ // Call request_lock_memory_privilege() and check the result
+ if (!os::win32::request_lock_memory_privilege()) {
+ GTEST_SKIP() << "Skipping test because lock memory privilege is not granted.";
+ }
+ // Set globals to make sure we hit the correct code path
+ AutoSaveRestore guardUseLargePages(UseLargePages);
+ AutoSaveRestore guardEnableAllLargePageSizesForWindows(EnableAllLargePageSizesForWindows);
+ AutoSaveRestore guardLargePageSizeInBytes(LargePageSizeInBytes);
+ FLAG_SET_CMDLINE(UseLargePages, true);
+ FLAG_SET_CMDLINE(EnableAllLargePageSizesForWindows, true);
+
+ // Determine the minimum page size
+ const size_t min_size = GetLargePageMinimum();
+
+ // End the test if GetLargePageMinimum returns 0
+ if (min_size == 0) {
+ GTEST_SKIP() << "Large pages are not supported on this system.";
+ return;
+ }
+
+ // Set LargePageSizeInBytes to 4 times the minimum page size
+ FLAG_SET_CMDLINE(LargePageSizeInBytes, 4 * min_size); // Set a value for multiple page sizes
+
+ // Initialize large page settings
+ os::large_page_init();
+
+ // Verify that large pages are enabled
+ EXPECT_TRUE(UseLargePages) << "UseLargePages should be true after initialization for LargePageSizeInBytes = 4 * min_size";
+
+ // Verify that decided_large_page_size is greater than the default page size
+ const size_t default_page_size = os::vm_page_size();
+ size_t decided_large_page_size = os::win32::large_page_init_decide_size();
+ EXPECT_GT(decided_large_page_size, default_page_size) << "Large page size should be greater than the default page size for LargePageSizeInBytes = 4 * min_size";
+
+#if !defined(IA32)
+ size_t page_size_count = 0;
+ size_t page_size = os::page_sizes().largest();
+
+ do {
+ ++page_size_count;
+ page_size = os::page_sizes().next_smaller(page_size);
+ } while (page_size >= os::page_sizes().smallest());
+
+ EXPECT_GT(page_size_count, 1u) << "There should be multiple large page sizes available.";
+
+ size_t large_page_size = decided_large_page_size;
+
+ for (size_t page_size = os::page_sizes().largest(); page_size >= min_size; page_size = os::page_sizes().next_smaller(page_size)) {
+ EXPECT_TRUE(page_size % min_size == 0) << "Each page size should be a multiple of the minimum large page size.";
+ EXPECT_LE(page_size, large_page_size) << "Page size should not exceed the determined large page size.";
+ }
+#endif
+}
+
+TEST_VM(os_windows, large_page_init_decide_size) {
+ // Initial setup
+ // Call request_lock_memory_privilege() and check the result
+ if (!os::win32::request_lock_memory_privilege()) {
+ GTEST_SKIP() << "Skipping test because lock memory privilege is not granted.";
+ }
+ AutoSaveRestore guardUseLargePages(UseLargePages);
+ AutoSaveRestore guardLargePageSizeInBytes(LargePageSizeInBytes);
+ FLAG_SET_CMDLINE(UseLargePages, true);
+ FLAG_SET_CMDLINE(LargePageSizeInBytes, 0); // Reset to default
+
+ // Test for large page support
+ size_t decided_size = os::win32::large_page_init_decide_size();
+ size_t min_size = GetLargePageMinimum();
+ if (min_size == 0) {
+ EXPECT_EQ(decided_size, 0) << "Expected decided size to be 0 when large page is not supported by the processor";
+ return;
+ }
+
+ // Scenario 1: Test with 2MB large page size
+ if (min_size == 2 * M) {
+ FLAG_SET_CMDLINE(LargePageSizeInBytes, 2 * M); // Set large page size to 2MB
+ decided_size = os::win32::large_page_init_decide_size(); // Recalculate decided size
+ EXPECT_EQ(decided_size, 2 * M) << "Expected decided size to be 2M when large page and OS reported size are both 2M";
+ }
+
+ // Scenario 2: Test with 1MB large page size
+ if (min_size == 2 * M) {
+ FLAG_SET_CMDLINE(LargePageSizeInBytes, 1 * M); // Set large page size to 1MB
+ decided_size = os::win32::large_page_init_decide_size(); // Recalculate decided size
+ EXPECT_EQ(decided_size, 2 * M) << "Expected decided size to be 2M when large page is 1M and OS reported size is 2M";
+ }
+
+#if defined(IA32) || defined(AMD64)
+ FLAG_SET_CMDLINE(LargePageSizeInBytes, 5 * M); // Set large page size to 5MB
+ if (!EnableAllLargePageSizesForWindows) {
+ decided_size = os::win32::large_page_init_decide_size(); // Recalculate decided size
+ EXPECT_EQ(decided_size, 0) << "Expected decided size to be 0 for large pages bigger than 4mb on IA32 or AMD64";
+ }
+#endif
+
+ // Additional check for non-multiple of minimum size
+ // Set an arbitrary large page size which is not a multiple of min_size
+ FLAG_SET_CMDLINE(LargePageSizeInBytes, 5 * min_size + 1);
+
+ // Recalculate decided size
+ decided_size = os::win32::large_page_init_decide_size();
+
+ // Assert that the decided size defaults to minimum page size when LargePageSizeInBytes
+ // is not a multiple of the minimum size, assuming conditions are always met
+ EXPECT_EQ(decided_size, 0) << "Expected decided size to default to 0 when LargePageSizeInBytes is not a multiple of minimum size";
+}
+
class ReserveMemorySpecialRunnable : public TestRunnable {
public:
void runUnitTest() const {
diff --git a/test/hotspot/jtreg/ProblemList-Xcomp.txt b/test/hotspot/jtreg/ProblemList-Xcomp.txt
index cb6bb2b4cca..2e9b6da3828 100644
--- a/test/hotspot/jtreg/ProblemList-Xcomp.txt
+++ b/test/hotspot/jtreg/ProblemList-Xcomp.txt
@@ -39,9 +39,11 @@ serviceability/jvmti/vthread/SuspendWithInterruptLock/SuspendWithInterruptLock.j
serviceability/sa/ClhsdbInspect.java 8283578 windows-x64
-vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java 8308367 windows-x64
-vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manySame_a/TestDescription.java 8308367 windows-x64
-vmTestbase/vm/mlvm/indy/func/jvmti/redefineClassInTarget/TestDescription.java 8308367 windows-x64
+vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java 8308367 generic-all
+vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manySame_a/TestDescription.java 8308367 generic-all
+vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2none_b/TestDescription.java 8308367 generic-all
+vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_none2indy_b/TestDescription.java 8308367 generic-all
+vmTestbase/vm/mlvm/indy/func/jvmti/redefineClassInTarget/TestDescription.java 8308367 generic-all
vmTestbase/nsk/jdi/StepRequest/addClassFilter_rt/filter_rt001/TestDescription.java 8043571 generic-all
vmTestbase/nsk/jdi/StepRequest/addClassFilter_rt/filter_rt003/TestDescription.java 8043571 generic-all
@@ -54,4 +56,6 @@ compiler/cha/TypeProfileFinalMethod.java 8341039 generic-all
gc/arguments/TestNewSizeFlags.java 8299116 macosx-aarch64
+runtime/cds/appcds/DumpRuntimeClassesTest.java 8341452 generic-all
+
runtime/condy/escapeAnalysis/TestEscapeCondy.java 8339694 generic-all
diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt
index 4440fe0628f..4bc196ff949 100644
--- a/test/hotspot/jtreg/ProblemList.txt
+++ b/test/hotspot/jtreg/ProblemList.txt
@@ -43,6 +43,8 @@
# :hotspot_compiler
+applications/ctw/modules/java_base_2.java 8341831 linux-x64
+
compiler/ciReplay/TestSAServer.java 8029528 generic-all
compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java 8225370 generic-all
@@ -53,7 +55,6 @@ compiler/loopopts/TestUnreachableInnerLoop.java 8288981 linux-s390x
compiler/c2/Test8004741.java 8235801 generic-all
compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all
-compiler/c2/irTests/TestIfMinMax.java 8339220 linux-s390x
compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all
compiler/codecache/CheckLargePages.java 8332654 linux-x64
@@ -124,6 +125,7 @@ applications/jcstress/copy.java 8229852 linux-all
containers/docker/TestJcmd.java 8278102 linux-all
containers/docker/TestMemoryAwareness.java 8303470 linux-all
containers/docker/TestJFREvents.java 8327723 linux-x64
+containers/docker/TestJcmdWithSideCar.java 8341518 linux-x64
# Valhalla
diff --git a/test/hotspot/jtreg/compiler/blackhole/BlackholeExperimentalUnlockTest.java b/test/hotspot/jtreg/compiler/blackhole/BlackholeExperimentalUnlockTest.java
index 6597b2186f2..0a403a78450 100644
--- a/test/hotspot/jtreg/compiler/blackhole/BlackholeExperimentalUnlockTest.java
+++ b/test/hotspot/jtreg/compiler/blackhole/BlackholeExperimentalUnlockTest.java
@@ -25,6 +25,7 @@
* @test
* @library /test/lib /
* @requires vm.flagless
+ * @requires ! vm.opt.final.UnlockExperimentalVMOptions
* @requires vm.compMode != "Xint"
* @run driver compiler.blackhole.BlackholeExperimentalUnlockTest
*/
diff --git a/test/hotspot/jtreg/compiler/c2/TestSerialAdditions.java b/test/hotspot/jtreg/compiler/c2/TestSerialAdditions.java
new file mode 100644
index 00000000000..c52f17dd975
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/c2/TestSerialAdditions.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2024 Red Hat and/or its affiliates. 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.
+ */
+
+package compiler.c2;
+
+import compiler.lib.ir_framework.Test;
+import compiler.lib.ir_framework.*;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.Utils;
+
+import java.util.Random;
+
+/*
+ * @test
+ * @bug 8325495
+ * @summary C2 should optimize for series of Add of unique value. e.g., a + a + ... + a => a*n
+ * @library /test/lib /
+ * @run driver compiler.c2.TestSerialAdditions
+ */
+public class TestSerialAdditions {
+ private static final Random RNG = Utils.getRandomInstance();
+
+ public static void main(String[] args) {
+ TestFramework.run();
+ }
+
+ @Run(test = {
+ "addTo2",
+ "addTo3",
+ "addTo4",
+ "shiftAndAddTo4",
+ "mulAndAddTo4",
+ "addTo5",
+ "addTo6",
+ "addTo7",
+ "addTo8",
+ "addTo16",
+ "addAndShiftTo16",
+ "addTo42",
+ "mulAndAddTo42",
+ "mulAndAddToMax",
+ "mulAndAddToOverflow",
+ "mulAndAddToZero",
+ "mulAndAddToMinus1",
+ "mulAndAddToMinus42"
+ })
+ private void runIntTests() {
+ for (int a : new int[] { 0, 1, Integer.MIN_VALUE, Integer.MAX_VALUE, RNG.nextInt() }) {
+ Asserts.assertEQ(a * 2, addTo2(a));
+ Asserts.assertEQ(a * 3, addTo3(a));
+ Asserts.assertEQ(a * 4, addTo4(a));
+ Asserts.assertEQ(a * 4, shiftAndAddTo4(a));
+ Asserts.assertEQ(a * 4, mulAndAddTo4(a));
+ Asserts.assertEQ(a * 5, addTo5(a));
+ Asserts.assertEQ(a * 6, addTo6(a));
+ Asserts.assertEQ(a * 7, addTo7(a));
+ Asserts.assertEQ(a * 8, addTo8(a));
+ Asserts.assertEQ(a * 16, addTo16(a));
+ Asserts.assertEQ(a * 16, addAndShiftTo16(a));
+ Asserts.assertEQ(a * 42, addTo42(a));
+ Asserts.assertEQ(a * 42, mulAndAddTo42(a));
+ Asserts.assertEQ(a * Integer.MAX_VALUE, mulAndAddToMax(a));
+ Asserts.assertEQ(a * Integer.MIN_VALUE, mulAndAddToOverflow(a));
+ Asserts.assertEQ(0, mulAndAddToZero(a));
+ Asserts.assertEQ(a * -1, mulAndAddToMinus1(a));
+ Asserts.assertEQ(a * -42, mulAndAddToMinus42(a));
+ }
+ }
+
+ @Run(test = {
+ "mulAndAddToIntOverflowL",
+ "mulAndAddToMaxL",
+ "mulAndAddToOverflowL"
+ })
+ private void runLongTests() {
+ for (long a : new long[] { 0, 1, Long.MIN_VALUE, Long.MAX_VALUE, RNG.nextLong() }) {
+ Asserts.assertEQ(a * (Integer.MAX_VALUE + 1L), mulAndAddToIntOverflowL(a));
+ Asserts.assertEQ(a * Long.MAX_VALUE, mulAndAddToMaxL(a));
+ Asserts.assertEQ(a * Long.MIN_VALUE, mulAndAddToOverflowL(a));
+ }
+ }
+
+ // ----- integer tests -----
+ @Test
+ @IR(counts = { IRNode.ADD_I, "1" })
+ @IR(failOn = IRNode.LSHIFT_I)
+ private static int addTo2(int a) {
+ return a + a; // Simple additions like a + a should be kept as-is
+ }
+
+ @Test
+ @IR(counts = { IRNode.ADD_I, "1", IRNode.LSHIFT_I, "1" })
+ private static int addTo3(int a) {
+ return a + a + a; // a*3 => (a<<1) + a
+ }
+
+ @Test
+ @IR(failOn = IRNode.ADD_I)
+ @IR(counts = { IRNode.LSHIFT_I, "1" })
+ private static int addTo4(int a) {
+ return a + a + a + a; // a*4 => a<<2
+ }
+
+ @Test
+ @IR(failOn = IRNode.ADD_I)
+ @IR(counts = { IRNode.LSHIFT_I, "1" })
+ private static int shiftAndAddTo4(int a) {
+ return (a << 1) + a + a; // a*2 + a + a => a*3 + a => a*4 => a<<2
+ }
+
+ @Test
+ @IR(failOn = IRNode.ADD_I)
+ @IR(counts = { IRNode.LSHIFT_I, "1" })
+ private static int mulAndAddTo4(int a) {
+ return a * 3 + a; // a*4 => a<<2
+ }
+
+ @Test
+ @IR(counts = { IRNode.ADD_I, "1", IRNode.LSHIFT_I, "1" })
+ private static int addTo5(int a) {
+ return a + a + a + a + a; // a*5 => (a<<2) + a
+ }
+
+ @Test
+ @IR(counts = { IRNode.ADD_I, "1", IRNode.LSHIFT_I, "2" })
+ private static int addTo6(int a) {
+ return a + a + a + a + a + a; // a*6 => (a<<1) + (a<<2)
+ }
+
+ @Test
+ @IR(failOn = IRNode.ADD_I)
+ @IR(counts = { IRNode.LSHIFT_I, "1", IRNode.SUB_I, "1" })
+ private static int addTo7(int a) {
+ return a + a + a + a + a + a + a; // a*7 => (a<<3) - a
+ }
+
+ @Test
+ @IR(failOn = IRNode.ADD_I)
+ @IR(counts = { IRNode.LSHIFT_I, "1" })
+ private static int addTo8(int a) {
+ return a + a + a + a + a + a + a + a; // a*8 => a<<3
+ }
+
+ @Test
+ @IR(failOn = IRNode.ADD_I)
+ @IR(counts = { IRNode.LSHIFT_I, "1" })
+ private static int addTo16(int a) {
+ return a + a + a + a + a + a + a + a + a + a
+ + a + a + a + a + a + a; // a*16 => a<<4
+ }
+
+ @Test
+ @IR(failOn = IRNode.ADD_I)
+ @IR(counts = { IRNode.LSHIFT_I, "1" })
+ private static int addAndShiftTo16(int a) {
+ return (a + a) << 3; // a<<(3 + 1) => a<<4
+ }
+
+ @Test
+ @IR(failOn = IRNode.ADD_I)
+ @IR(counts = { IRNode.MUL_I, "1" })
+ private static int addTo42(int a) {
+ return a + a + a + a + a + a + a + a + a + a
+ + a + a + a + a + a + a + a + a + a + a
+ + a + a + a + a + a + a + a + a + a + a
+ + a + a + a + a + a + a + a + a + a + a
+ + a + a; // a*42
+ }
+
+ @Test
+ @IR(failOn = IRNode.ADD_I)
+ @IR(counts = { IRNode.MUL_I, "1" })
+ private static int mulAndAddTo42(int a) {
+ return a * 40 + a + a; // a*41 + a => a*42
+ }
+
+ private static final int INT_MAX_MINUS_ONE = Integer.MAX_VALUE - 1;
+
+ @Test
+ @IR(failOn = IRNode.ADD_I)
+ @IR(counts = { IRNode.LSHIFT_I, "1", IRNode.SUB_I, "1" })
+ private static int mulAndAddToMax(int a) {
+ return a * INT_MAX_MINUS_ONE + a; // a*MAX => a*(MIN-1) => a*MIN - a => (a<<31) - a
+ }
+
+ @Test
+ @IR(failOn = IRNode.ADD_I)
+ @IR(counts = { IRNode.LSHIFT_I, "1" })
+ private static int mulAndAddToOverflow(int a) {
+ return a * Integer.MAX_VALUE + a; // a*(MAX+1) => a*(MIN) => a<<31
+ }
+
+ @Test
+ @IR(failOn = IRNode.ADD_I)
+ @IR(counts = { IRNode.CON_I, "1" })
+ private static int mulAndAddToZero(int a) {
+ return a * -1 + a; // 0
+ }
+
+ @Test
+ @IR(failOn = IRNode.ADD_I)
+ @IR(counts = { IRNode.LSHIFT_I, "1", IRNode.SUB_I, "1" })
+ private static int mulAndAddToMinus1(int a) {
+ return a * -2 + a; // a*-1 => a - (a<<1)
+ }
+
+ @Test
+ @IR(failOn = IRNode.ADD_I)
+ @IR(counts = { IRNode.MUL_I, "1" })
+ private static int mulAndAddToMinus42(int a) {
+ return a * -43 + a; // a*-42
+ }
+
+ // --- long tests ---
+ @Test
+ @IR(failOn = IRNode.ADD_L)
+ @IR(counts = { IRNode.LSHIFT_L, "1" })
+ private static long mulAndAddToIntOverflowL(long a) {
+ return a * Integer.MAX_VALUE + a; // a*(INT_MAX+1)
+ }
+
+ private static final long LONG_MAX_MINUS_ONE = Long.MAX_VALUE - 1;
+
+ @Test
+ @IR(failOn = IRNode.ADD_L)
+ @IR(counts = { IRNode.LSHIFT_L, "1", IRNode.SUB_L, "1" })
+ private static long mulAndAddToMaxL(long a) {
+ return a * LONG_MAX_MINUS_ONE + a; // a*MAX => a*(MIN-1) => a*MIN - 1 => (a<<63) - 1
+ }
+
+ @Test
+ @IR(failOn = IRNode.ADD_L)
+ @IR(counts = { IRNode.LSHIFT_L, "1" })
+ private static long mulAndAddToOverflowL(long a) {
+ return a * Long.MAX_VALUE + a; // a*(MAX+1) => a*(MIN) => a<<63
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java b/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java
index 033ea49e609..d05dbad4a73 100644
--- a/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java
+++ b/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java
@@ -46,11 +46,20 @@ public class TestUnalignedAccess {
static final Unsafe UNSAFE = Unsafe.getUnsafe();
static void sink(int x) {}
+ public static long lseed = 1;
+ public static int iseed = 2;
+ public static short sseed = 3;
+ public static byte bseed = 4;
+ public static long lres = lseed;
+ public static int ires = iseed;
+ public static short sres = sseed;
+ public static byte bres = bseed;
+
public static class TestLong {
private static final byte[] BYTES = new byte[LEN];
private static final long rawdata = 0xbeef;
- private static final long lseed = 1;
+ private static final long data;
static {
sink(2);
@@ -60,10 +69,13 @@ public static class TestLong {
// 1030 can't be encoded as "base + offset" mode into the instruction field.
UNSAFE.putLongUnaligned(BYTES, 1030, rawdata);
+ lres += UNSAFE.getLongUnaligned(BYTES, 1030);
// 127 can be encoded into simm9 field.
- UNSAFE.putLongUnaligned(BYTES, 127, rawdata+lseed);
+ UNSAFE.putLongUnaligned(BYTES, 127, lres);
+ lres += UNSAFE.getLongUnaligned(BYTES, 127);
// 1096 can be encoded into uimm12 field.
- UNSAFE.putLongUnaligned(BYTES, 1096, rawdata-lseed);
+ UNSAFE.putLongUnaligned(BYTES, 1096, lres);
+ data = UNSAFE.getLongUnaligned(BYTES, 1096);
}
}
@@ -72,7 +84,7 @@ public static class TestInt {
private static final byte[] BYTES = new byte[LEN];
private static final int rawdata = 0xbeef;
- private static final int iseed = 2;
+ private static final int data;
static {
sink(2);
// Signed immediate byte offset: range -256 to 255
@@ -81,10 +93,13 @@ public static class TestInt {
// 274 can't be encoded as "base + offset" mode into the instruction field.
UNSAFE.putIntUnaligned(BYTES, 274, rawdata);
+ ires += UNSAFE.getIntUnaligned(BYTES, 274);
// 255 can be encoded into simm9 field.
- UNSAFE.putIntUnaligned(BYTES, 255, rawdata + iseed);
+ UNSAFE.putIntUnaligned(BYTES, 255, ires);
+ ires += UNSAFE.getIntUnaligned(BYTES, 255);
// 528 can be encoded into uimm12 field.
- UNSAFE.putIntUnaligned(BYTES, 528, rawdata - iseed);
+ UNSAFE.putIntUnaligned(BYTES, 528, ires);
+ data = UNSAFE.getIntUnaligned(BYTES, 528);
}
}
@@ -93,7 +108,7 @@ public static class TestShort {
private static final byte[] BYTES = new byte[LEN];
private static final short rawdata = (short)0xbeef;
- private static final short sseed = 3;
+ private static final short data;
static {
sink(2);
// Signed immediate byte offset: range -256 to 255
@@ -102,10 +117,13 @@ public static class TestShort {
// 257 can't be encoded as "base + offset" mode into the instruction field.
UNSAFE.putShortUnaligned(BYTES, 257, rawdata);
+ sres = (short) (sres + UNSAFE.getShortUnaligned(BYTES, 257));
// 253 can be encoded into simm9 field.
- UNSAFE.putShortUnaligned(BYTES, 253, (short) (rawdata + sseed));
+ UNSAFE.putShortUnaligned(BYTES, 253, sres);
+ sres = (short) (sres + UNSAFE.getShortUnaligned(BYTES, 253));
// 272 can be encoded into uimm12 field.
- UNSAFE.putShortUnaligned(BYTES, 272, (short) (rawdata - sseed));
+ UNSAFE.putShortUnaligned(BYTES, 272, sres);
+ data = UNSAFE.getShortUnaligned(BYTES, 272);
}
}
@@ -114,7 +132,7 @@ public static class TestByte {
private static final byte[] BYTES = new byte[LEN];
private static final byte rawdata = (byte)0x3f;
- private static final byte bseed = 4;
+ private static final byte data;
static {
sink(2);
// Signed immediate byte offset: range -256 to 255
@@ -123,34 +141,29 @@ public static class TestByte {
// 272 can be encoded into simm9 field.
UNSAFE.putByte(BYTES, 272, rawdata);
+ bres = (byte) (bres + UNSAFE.getByte(BYTES, 272));
// 53 can be encoded into simm9 field.
- UNSAFE.putByte(BYTES, 53, (byte) (rawdata + bseed));
+ UNSAFE.putByte(BYTES, 53, bres);
+ bres = (byte) (bres + UNSAFE.getByte(BYTES, 53));
// 1027 can be encoded into uimm12 field.
- UNSAFE.putByte(BYTES, 1027, (byte) (rawdata - bseed));
+ UNSAFE.putByte(BYTES, 1027, bres);
+ data = UNSAFE.getByte(BYTES, 1027);
}
}
static void test() {
TestLong ta = new TestLong();
- Asserts.assertEquals(UNSAFE.getLongUnaligned(ta.BYTES, 1030), ta.rawdata, "putUnaligned long failed!");
- Asserts.assertEquals(UNSAFE.getLongUnaligned(ta.BYTES, 127), ta.rawdata + ta.lseed, "putUnaligned long failed!");
- Asserts.assertEquals(UNSAFE.getLongUnaligned(ta.BYTES, 1096), ta.rawdata - ta.lseed, "putUnaligned long failed!");
+ Asserts.assertEquals(ta.data, (ta.rawdata + lseed) * 2, "putUnaligned long failed!");
TestInt tb = new TestInt();
- Asserts.assertEquals(UNSAFE.getIntUnaligned(tb.BYTES, 274), tb.rawdata, "putUnaligned int failed!");
- Asserts.assertEquals(UNSAFE.getIntUnaligned(tb.BYTES, 255), tb.rawdata + tb.iseed, "putUnaligned int failed!");
- Asserts.assertEquals(UNSAFE.getIntUnaligned(tb.BYTES, 528), tb.rawdata - tb.iseed, "putUnaligned int failed!");
+ Asserts.assertEquals(tb.data, (tb.rawdata + iseed) * 2, "putUnaligned int failed!");
TestShort tc = new TestShort();
- Asserts.assertEquals(UNSAFE.getShortUnaligned(tc.BYTES, 257), tc.rawdata, "putUnaligned short failed!");
- Asserts.assertEquals(UNSAFE.getShortUnaligned(tc.BYTES, 253), (short) (tc.rawdata + tc.sseed), "putUnaligned short failed!");
- Asserts.assertEquals(UNSAFE.getShortUnaligned(tc.BYTES, 272), (short) (tc.rawdata - tc.sseed), "putUnaligned short failed!");
+ Asserts.assertEquals(tc.data, (short) (((short) (tc.rawdata + sseed)) * 2), "putUnaligned short failed!");
TestByte td = new TestByte();
- Asserts.assertEquals(UNSAFE.getByte(td.BYTES, 272), td.rawdata, "put byte failed!");
- Asserts.assertEquals(UNSAFE.getByte(td.BYTES, 53), (byte) (td.rawdata + td.bseed), "put byte failed!");
- Asserts.assertEquals(UNSAFE.getByte(td.BYTES, 1027), (byte) (td.rawdata - td.bseed), "put byte failed!");
+ Asserts.assertEquals(td.data, (byte) (((byte) (td.rawdata + bseed)) * 2), "put byte failed!");
}
public static void main(String[] strArr) {
diff --git a/test/hotspot/jtreg/compiler/controldependency/TestAntiDependencyForPinnedLoads.java b/test/hotspot/jtreg/compiler/controldependency/TestAntiDependencyForPinnedLoads.java
new file mode 100644
index 00000000000..05673015ebe
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/controldependency/TestAntiDependencyForPinnedLoads.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. 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.
+ */
+
+/**
+ * @test
+ * @bug 8337066
+ * @summary Test that MergeMem is skipped when looking for stores
+ * @run main/othervm -Xbatch -XX:-TieredCompilation
+ * -XX:CompileCommand=compileonly,java.lang.StringUTF16::reverse
+ * compiler.controldependency.TestAntiDependencyForPinnedLoads
+ */
+
+package compiler.controldependency;
+
+public class TestAntiDependencyForPinnedLoads {
+ public static void main(String[] args) {
+ for(int i = 0; i < 50_000; i++) {
+ String str = "YYYY年MM月DD日";
+ StringBuffer strBuffer = new StringBuffer(str);
+ String revStr = strBuffer.reverse().toString();
+ if (!revStr.equals("日DD月MM年YYYY")) throw new InternalError("FAIL");
+ }
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/debug/TestStressBailout.java b/test/hotspot/jtreg/compiler/debug/TestStressBailout.java
new file mode 100644
index 00000000000..68610576a39
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/debug/TestStressBailout.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. 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.
+ */
+
+package compiler.debug;
+
+import java.util.Random;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.Utils;
+
+/*
+ * @test
+ * @key stress randomness
+ * @bug 8330157
+ * @requires vm.debug == true & vm.compiler2.enabled & (vm.opt.AbortVMOnCompilationFailure == "null" | !vm.opt.AbortVMOnCompilationFailure)
+ * @summary Basic tests for bailout stress flag.
+ * @library /test/lib /
+ * @run driver compiler.debug.TestStressBailout
+ */
+
+public class TestStressBailout {
+
+ static void runTest(int invprob) throws Exception {
+ String[] procArgs = {"-Xcomp", "-XX:-TieredCompilation", "-XX:+StressBailout",
+ "-XX:StressBailoutMean=" + invprob, "-version"};
+ ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(procArgs);
+ OutputAnalyzer out = new OutputAnalyzer(pb.start());
+ out.shouldHaveExitValue(0);
+ }
+
+ public static void main(String[] args) throws Exception {
+ Random r = Utils.getRandomInstance();
+ // Likely bail out on -version, for some low Mean value.
+ runTest(r.nextInt(1, 10));
+ // Higher value
+ runTest(r.nextInt(10, 1_000_000));
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/longcountedloops/TestSafePointWithEAState.java b/test/hotspot/jtreg/compiler/longcountedloops/TestSafePointWithEAState.java
new file mode 100644
index 00000000000..a04af09570f
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/longcountedloops/TestSafePointWithEAState.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2024, Red Hat, Inc. 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.
+ */
+
+/**
+ * @test
+ * @bug 8336702
+ * @summary C2 compilation fails with "all memory state should have been processed" assert
+ *
+ * @run main/othervm TestSafePointWithEAState
+ *
+ */
+
+public class TestSafePointWithEAState {
+ int[] b = new int[400];
+
+ void c() {
+ int e;
+ float f;
+ for (long d = 0; d < 5000; d++) {
+ e = 1;
+ while ((e += 3) < 200) {
+ if (d < b.length) {
+ for (int g = 0; g < 10000; ++g) ;
+ }
+ }
+ synchronized (TestSafePointWithEAState.class) {
+ f = new h(e).n;
+ }
+ }
+ }
+
+ public static void main(String[] m) {
+ TestSafePointWithEAState o = new TestSafePointWithEAState();
+ o.c();
+ }
+}
+
+class h {
+ float n;
+ h(float n) {
+ this.n = n;
+ }
+}
diff --git a/test/hotspot/jtreg/compiler/types/TestBadMemSliceWithInterfaces.java b/test/hotspot/jtreg/compiler/types/TestBadMemSliceWithInterfaces.java
new file mode 100644
index 00000000000..5090c2dd6cf
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/types/TestBadMemSliceWithInterfaces.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2024, Red Hat, Inc. 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.
+ */
+
+/**
+ * @test
+ * @bug 8340214
+ * @summary C2 compilation asserts with "no node with a side effect" in PhaseIdealLoop::try_sink_out_of_loop
+ *
+ * @run main/othervm -XX:-BackgroundCompilation TestBadMemSliceWithInterfaces
+ *
+ */
+
+public class TestBadMemSliceWithInterfaces {
+ public static void main(String[] args) {
+ B b = new B();
+ C c = new C();
+ for (int i = 0; i < 20_000; i++) {
+ test1(b, c, true);
+ test1(b, c, false);
+ b.field = 0;
+ c.field = 0;
+ int res = test2(b, c, true);
+ if (res != 42) {
+ throw new RuntimeException("incorrect result " + res);
+ }
+ res = test2(b, c, false);
+ if (res != 42) {
+ throw new RuntimeException("incorrect result " + res);
+ }
+ }
+ }
+
+ private static void test1(B b, C c, boolean flag) {
+ A a;
+ if (flag) {
+ a = b;
+ } else {
+ a = c;
+ }
+ for (int i = 0; i < 1000; i++) {
+ a.field = 42;
+ }
+ }
+
+ private static int test2(B b, C c, boolean flag) {
+ A a;
+ if (flag) {
+ a = b;
+ } else {
+ a = c;
+ }
+ int v = 0;
+ for (int i = 0; i < 2; i++) {
+ v += a.field;
+ a.field = 42;
+ }
+ return v;
+ }
+
+ interface I {
+ void m();
+ }
+
+ static class A {
+ int field;
+ }
+
+ static class B extends A implements I {
+ @Override
+ public void m() {
+
+ }
+ }
+
+ static class C extends A implements I {
+ @Override
+ public void m() {
+
+ }
+ }
+}
diff --git a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java
index 20883988347..5dea864f427 100644
--- a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java
+++ b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java
@@ -42,8 +42,8 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Paths;
-import java.util.Arrays;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
@@ -52,7 +52,9 @@
import java.util.function.Consumer;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
+
import jdk.test.lib.Container;
+import jdk.test.lib.Platform;
import jdk.test.lib.Utils;
import jdk.test.lib.containers.docker.Common;
import jdk.test.lib.containers.docker.DockerRunOptions;
@@ -108,6 +110,11 @@ public static void main(String[] args) throws Exception {
mainContainer.waitForMainMethodStart(TIME_TO_WAIT_FOR_MAIN_METHOD_START);
for (AttachStrategy attachStrategy : EnumSet.allOf(AttachStrategy.class)) {
+ if (attachStrategy == AttachStrategy.ACCESS_TMP_VIA_PROC_ROOT &&
+ elevated && !Platform.isRoot()) {
+ // Elevated attach via proc/root not yet supported.
+ continue;
+ }
long mainProcPid = testCase01(attachStrategy, elevated);
// Excluding the test case below until JDK-8228850 is fixed
diff --git a/test/hotspot/jtreg/runtime/CommandLine/VMOptionWarning.java b/test/hotspot/jtreg/runtime/CommandLine/VMOptionWarning.java
index aaee80169eb..90b309069ac 100644
--- a/test/hotspot/jtreg/runtime/CommandLine/VMOptionWarning.java
+++ b/test/hotspot/jtreg/runtime/CommandLine/VMOptionWarning.java
@@ -22,14 +22,37 @@
*/
/*
- * @test
+ * @test VMOptionWarningExperimental
* @bug 8027314
- * @summary Warn if diagnostic or experimental vm option is used and -XX:+UnlockDiagnosticVMOptions or -XX:+UnlockExperimentalVMOptions, respectively, isn't specified. Warn if develop vm option is used with product version of VM.
+ * @summary Warn if experimental vm option is used and -XX:+UnlockExperimentalVMOptions isn't specified.
* @requires vm.flagless
+ * @requires ! vm.opt.final.UnlockExperimentalVMOptions
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.management
- * @run driver VMOptionWarning
+ * @run driver VMOptionWarning Experimental
+ */
+
+/* @test VMOptionWarningDiagnostic
+ * @bug 8027314
+ * @summary Warn if diagnostic vm option is used and -XX:+UnlockDiagnosticVMOptions isn't specified.
+ * @requires vm.flagless
+ * @requires ! vm.debug
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ * java.management
+ * @run driver VMOptionWarning Diagnostic
+ */
+
+/* @test VMOptionWarningDevelop
+ * @bug 8027314
+ * @summary Warn if develop vm option is used with product version of VM.
+ * @requires vm.flagless
+ * @requires ! vm.debug
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ * java.management
+ * @run driver VMOptionWarning Develop
*/
import jdk.test.lib.process.ProcessTools;
@@ -38,24 +61,37 @@
public class VMOptionWarning {
public static void main(String[] args) throws Exception {
- ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+AlwaysSafeConstructors", "-version");
- OutputAnalyzer output = new OutputAnalyzer(pb.start());
- output.shouldNotHaveExitValue(0);
- output.shouldContain("Error: VM option 'AlwaysSafeConstructors' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions.");
-
- if (Platform.isDebugBuild()) {
- System.out.println("Skip the rest of the tests on debug builds since diagnostic, and develop options are available on debug builds.");
- return;
+ if (args.length != 1) {
+ throw new RuntimeException("wrong number of args: " + args.length);
}
- pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+PrintInlining", "-version");
- output = new OutputAnalyzer(pb.start());
- output.shouldNotHaveExitValue(0);
- output.shouldContain("Error: VM option 'PrintInlining' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.");
-
- pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+VerifyStack", "-version");
- output = new OutputAnalyzer(pb.start());
- output.shouldNotHaveExitValue(0);
- output.shouldContain("Error: VM option 'VerifyStack' is develop and is available only in debug version of VM.");
+ ProcessBuilder pb;
+ OutputAnalyzer output;
+ switch (args[0]) {
+ case "Experimental": {
+ pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+AlwaysSafeConstructors", "-version");
+ output = new OutputAnalyzer(pb.start());
+ output.shouldNotHaveExitValue(0);
+ output.shouldContain("Error: VM option 'AlwaysSafeConstructors' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions.");
+ break;
+ }
+ case "Diagnostic": {
+ pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+PrintInlining", "-version");
+ output = new OutputAnalyzer(pb.start());
+ output.shouldNotHaveExitValue(0);
+ output.shouldContain("Error: VM option 'PrintInlining' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.");
+ break;
+ }
+ case "Develop": {
+ pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+VerifyStack", "-version");
+ output = new OutputAnalyzer(pb.start());
+ output.shouldNotHaveExitValue(0);
+ output.shouldContain("Error: VM option 'VerifyStack' is develop and is available only in debug version of VM.");
+ break;
+ }
+ default: {
+ throw new RuntimeException("Invalid argument: " + args[0]);
+ }
+ }
}
}
diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ValueCopyingTest.java b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ValueCopyingTest.java
index 88d379d9f9f..6c4631769ef 100644
--- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ValueCopyingTest.java
+++ b/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ValueCopyingTest.java
@@ -28,7 +28,7 @@
* @modules java.base/jdk.internal.vm.annotation
* @enablePreview
* @compile ValueCopyingTest.java
- * @run main/othervm -Xint -XX:+PrintInlineLayout runtime.valhalla.inlinetypes.ValueCopyingTest
+ * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlineLayout runtime.valhalla.inlinetypes.ValueCopyingTest
*/
package runtime.valhalla.inlinetypes;
@@ -99,4 +99,4 @@ static public void main(String[] args) throws InterruptedException {
throw e;
}
}
-}
\ No newline at end of file
+}
diff --git a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java
index d62e286c68d..e2c7230bc0d 100644
--- a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java
+++ b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java
@@ -309,6 +309,13 @@ private String[] cmd(long classStart, long classStop) {
// allocation allocate lots of memory
"-XX:CompileCommand=memlimit,*.*,0"));
+ // Use this stress mode 10% of the time as it could make some long-running compilations likely to abort.
+ if (rng.nextInt(10) == 0) {
+ Args.add("-XX:+StressBailout");
+ Args.add("-XX:StressBailoutMean=100000");
+ Args.add("-XX:+CaptureBailoutInformation");
+ }
+
for (String arg : CTW_EXTRA_ARGS.split(",")) {
Args.add(arg);
}
diff --git a/test/jdk/ProblemList-Xcomp.txt b/test/jdk/ProblemList-Xcomp.txt
index 2fc09ee4df4..8963ead2bce 100644
--- a/test/jdk/ProblemList-Xcomp.txt
+++ b/test/jdk/ProblemList-Xcomp.txt
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2018, 2024, Oracle and/or its affiliates. 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
@@ -28,5 +28,5 @@
#############################################################################
java/lang/invoke/MethodHandles/CatchExceptionTest.java 8146623 generic-all
-java/lang/management/MemoryMXBean/CollectionUsageThreshold.java 8318668 generic-all
+java/foreign/TestUpcallStress.java 8341584 generic-all
com/sun/jdi/InterruptHangTest.java 8043571 generic-all
diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt
index 1944ce2d88d..29b39c1338a 100644
--- a/test/jdk/ProblemList.txt
+++ b/test/jdk/ProblemList.txt
@@ -121,13 +121,16 @@ java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java 6848406 gen
java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java 6848407 generic-all
java/awt/Frame/MaximizedUndecorated/MaximizedUndecorated.java 8022302 generic-all
java/awt/Frame/RestoreToOppositeScreen/RestoreToOppositeScreen.java 8286840 linux-all
-java/awt/Frame/InitialIconifiedTest.java 8203920 macosx-all,linux-all
+java/awt/Frame/InitialIconifiedTest.java 7144049,8203920 macosx-all,linux-all
java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java 8341370 macosx-all
+java/awt/Frame/FocusTest.java 8341480 macosx-all
java/awt/FileDialog/FileDialogIconTest/FileDialogIconTest.java 8160558 windows-all
java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion.java 8060176 windows-all,macosx-all
java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_1.java 8060176 windows-all,macosx-all
java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.java 8171510 macosx-all
java/awt/dnd/MissingDragExitEventTest/MissingDragExitEventTest.java 8288839 windows-x64
+java/awt/dnd/DragExitBeforeDropTest.java 8242805 macosx-all
+java/awt/dnd/DragThresholdTest.java 8076299 macosx-all
java/awt/Focus/ChoiceFocus/ChoiceFocus.java 8169103 windows-all,macosx-all
java/awt/Focus/ClearLwQueueBreakTest/ClearLwQueueBreakTest.java 8198618 macosx-all
java/awt/Focus/ConsumeNextKeyTypedOnModalShowTest/ConsumeNextKeyTypedOnModalShowTest.java 6986252 macosx-all
@@ -210,6 +213,9 @@ java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java 8150540,8295300 windows
java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java 8150540 windows-all
java/awt/TrayIcon/TrayIconPopup/TrayIconPopupClickTest.java 8150540 windows-all,macosx-all
java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java 8150540 windows-all
+java/awt/TrayIcon/MouseMoveTest.java 8203053 linux-all
+java/awt/TrayIcon/TrayIconKeySelectTest.java 8341557 windows-all
+java/awt/TrayIcon/TrayIconTest.java 8341559 generic-all
java/awt/Window/ShapedAndTranslucentWindows/SetShapeAndClick.java 8197936 macosx-all
java/awt/Window/ShapedAndTranslucentWindows/SetShapeDynamicallyAndClick.java 8013450 macosx-all
@@ -433,6 +439,7 @@ java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.j
java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java 7107528 linux-all,macosx-all
java/awt/Mouse/MouseDragEvent/MouseDraggedTest.java 8080676 linux-all
java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersInKeyEvent.java 8157147 linux-all,windows-all,macosx-all
+java/awt/Mouse/MouseClickCount.java 8017182 macosx-all
java/awt/Toolkit/ToolkitPropertyTest/ToolkitPropertyTest_Enable.java 6847163 linux-all
java/awt/xembed/server/RunTestXEmbed.java 7034201 linux-all
java/awt/Modal/ModalFocusTransferTests/FocusTransferDialogsDocModalTest.java 8164473 linux-all
@@ -467,6 +474,9 @@ java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemoni
java/awt/Window/GetScreenLocation/GetScreenLocationTest.java 8225787 linux-x64
java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java 8266243 macosx-aarch64
java/awt/dnd/BadSerializationTest/BadSerializationTest.java 8277817 linux-x64,windows-x64
+java/awt/dnd/DragSourceMotionListenerTest.java 8225131 windows-all
+java/awt/dnd/RejectDragTest.java 7124259 macosx-all
+java/awt/dnd/DnDHTMLToOutlookTest/DnDHTMLToOutlookTest.java 8027424 generic-all
java/awt/GraphicsDevice/DisplayModes/UnknownRefrshRateTest.java 8286436 macosx-aarch64
java/awt/image/multiresolution/MultiresolutionIconTest.java 8291979 linux-x64,windows-all
java/awt/event/SequencedEvent/MultipleContextsFunctionalTest.java 8305061 macosx-x64
@@ -670,7 +680,6 @@ javax/swing/AbstractButton/6711682/bug6711682.java 8060765 windows-all,macosx-al
javax/swing/JFileChooser/6396844/TwentyThousandTest.java 8198003 generic-all
javax/swing/JFileChooser/8194044/FileSystemRootTest.java 8327236 windows-all
javax/swing/JPopupMenu/6800513/bug6800513.java 7184956 macosx-all
-javax/swing/JTabbedPane/8007563/Test8007563.java 8051591 generic-all
javax/swing/JTabbedPane/4624207/bug4624207.java 8064922 macosx-all
javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java 8160720 generic-all
javax/swing/JFileChooser/6798062/bug6798062.java 8146446 windows-all
@@ -813,6 +822,10 @@ java/awt/PopupMenu/PopupHangTest.java 8340022 windows-all
java/awt/Focus/MinimizeNonfocusableWindowTest.java 8024487 windows-all
java/awt/Focus/InactiveFocusRace.java 8023263 linux-all
java/awt/List/HandlingKeyEventIfMousePressedTest.java 6848358 macosx-all,windows-all
+java/awt/Checkbox/CheckboxBoxSizeTest.java 8340870 windows-all
+java/awt/Checkbox/CheckboxIndicatorSizeTest.java 8340870 windows-all
+java/awt/Checkbox/CheckboxNullLabelTest.java 8340870 windows-all
+java/awt/dnd/WinMoveFileToShellTest.java 8341665 windows-all
# valhalla
jdk/jfr/event/runtime/TestSyncOnValueBasedClassEvent.java 8328777 generic-all
diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups
index 00e0695bdaf..e4128765a45 100644
--- a/test/jdk/TEST.groups
+++ b/test/jdk/TEST.groups
@@ -389,7 +389,8 @@ jdk_svc = \
jdk_foreign = \
java/foreign \
jdk/internal/reflect/CallerSensitive/CheckCSMs.java \
- -java/foreign/TestMatrix.java
+ -java/foreign/TestMatrix.java \
+ -java/foreign/TestUpcallStress.java
jdk_vector = \
jdk/incubator/vector
diff --git a/test/jdk/java/awt/CardLayout/RemoveComponentTest/RemoveComponentTest.java b/test/jdk/java/awt/CardLayout/RemoveComponentTest/RemoveComponentTest.java
new file mode 100644
index 00000000000..0a23a989533
--- /dev/null
+++ b/test/jdk/java/awt/CardLayout/RemoveComponentTest/RemoveComponentTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2002, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4546123
+ * @summary CardLayout becomes unusable after deleting an element
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual RemoveComponentTest
+ */
+
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
+import java.awt.Color;
+import java.awt.Frame;
+import java.awt.Insets;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.Panel;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+public class RemoveComponentTest {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ You should see a frame titled "Test Frame For
+ RemoveComponentTest". Try to select a few different panels from
+ the second menu. Make sure your last choice is the red panel.
+ Then click close (in first menu). After that you should be able
+ to select any panels except red one.
+ If that is the case, the test passes. Otherwise, the test failed.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(35)
+ .testUI(RemoveComponentTest::createUI)
+ .logArea(5)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static Frame createUI() {
+ TestFrame frame = new TestFrame();
+ frame.setSize(200, 200);
+ return frame;
+ }
+}
+
+class TestFrame extends Frame implements ActionListener {
+ public Panel aPanel;
+ public TestPanel pageRed;
+ public TestPanel pageGreen;
+ public TestPanel pageBlue;
+ public String currentSelection = "";
+
+ public MenuItem mi;
+ public CardLayout theCardLayout;
+
+
+ public TestFrame() {
+ super("Test Frame For RemoveComponentTest");
+
+ setBackground(Color.black);
+ setLayout(new BorderLayout(5, 5));
+
+ MenuBar mb = new MenuBar();
+
+ Menu fileMenu = new Menu("File");
+ Menu pageMenu = new Menu("Pages");
+
+ mi = new MenuItem("Close");
+ mi.addActionListener(this);
+ fileMenu.add(mi);
+
+ mi = new MenuItem("Red");
+ mi.addActionListener(this);
+ pageMenu.add(mi);
+
+ mi = new MenuItem("Green");
+ mi.addActionListener(this);
+ pageMenu.add(mi);
+
+ mi = new MenuItem("Blue");
+ mi.addActionListener(this);
+ pageMenu.add(mi);
+
+ mb.add(fileMenu);
+ mb.add(pageMenu);
+
+ setMenuBar(mb);
+
+ aPanel = new Panel();
+ theCardLayout = new CardLayout();
+
+ aPanel.setLayout(theCardLayout);
+
+ pageRed = new TestPanel("PageRed", Color.red);
+ pageGreen = new TestPanel("PageGreen", Color.green);
+ pageBlue = new TestPanel("PageBlue", Color.blue);
+
+ aPanel.add("PageRed", pageRed);
+ aPanel.add("PageGreen", pageGreen);
+ aPanel.add("PageBlue", pageBlue);
+
+ add("Center", aPanel);
+ setSize(getPreferredSize());
+ }
+
+ public Insets getInsets() {
+ return new Insets(47, 9, 9, 9);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (e.getActionCommand().equals("Red")) {
+ theCardLayout.show(aPanel, "PageRed");
+ currentSelection = "PageRed";
+ } else if (e.getActionCommand().equals("Green")) {
+ theCardLayout.show(aPanel, "PageGreen");
+ } else if (e.getActionCommand().equals("Blue")) {
+ theCardLayout.show(aPanel, "PageBlue");
+ } else if (e.getActionCommand().equals("Close")) {
+ PassFailJFrame.log("Closing");
+
+ if (currentSelection.equals("PageRed")) {
+ PassFailJFrame.log("Remove page red");
+ theCardLayout.removeLayoutComponent(pageRed);
+ }
+ }
+ }
+}
+
+class TestPanel extends JPanel {
+ private String pageName;
+
+ TestPanel(String pageName, Color color) {
+ setBackground(color);
+ add(new JLabel(pageName));
+ }
+}
diff --git a/test/jdk/java/awt/Checkbox/CheckboxBoxSizeTest.java b/test/jdk/java/awt/Checkbox/CheckboxBoxSizeTest.java
new file mode 100644
index 00000000000..0d500e5daa1
--- /dev/null
+++ b/test/jdk/java/awt/Checkbox/CheckboxBoxSizeTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2001, 2024, Oracle and/or its affiliates. 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 java.awt.Checkbox;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Panel;
+
+/*
+ * @test
+ * @bug 4410522
+ * @requires (os.family == "windows")
+ * @summary The box size of the Checkbox control should be the same as
+ * in Windows native applications.
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual CheckboxBoxSizeTest
+ */
+
+public class CheckboxBoxSizeTest {
+ private static final String INSTRUCTIONS = """
+ This test must be run at UI Scale of 100% AND
+ 150% or greater.
+ Compare the size of box to any of native apps on Windows
+ (Eg. Font Dialog Settings on Word).
+ They should be the same.
+
+ If the sizes are same Press PASS, else Press FAIL.
+ """;
+
+ public static void main(String[] args) throws Exception {
+ PassFailJFrame.builder()
+ .title("CheckboxBoxSizeTest Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(CheckboxBoxSizeTest::createTestUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Frame createTestUI() {
+ Frame frame = new Frame("CheckboxBoxSizeTest");
+ Panel panel = new Panel(new FlowLayout());
+ Checkbox checkbox = new Checkbox("Compare the box size");
+ panel.add(checkbox);
+ frame.add(panel);
+ frame.pack();
+ return frame;
+ }
+}
diff --git a/test/jdk/java/awt/Checkbox/CheckboxIndicatorSizeTest.java b/test/jdk/java/awt/Checkbox/CheckboxIndicatorSizeTest.java
new file mode 100644
index 00000000000..3456e7e040d
--- /dev/null
+++ b/test/jdk/java/awt/Checkbox/CheckboxIndicatorSizeTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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 java.awt.Checkbox;
+import java.awt.CheckboxGroup;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.Label;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.Panel;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+/*
+ * @test
+ * @bug 4090493
+ * @summary Test for Checkbox indicator size
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual CheckboxIndicatorSizeTest
+ */
+
+public class CheckboxIndicatorSizeTest implements ActionListener {
+ private static final String INSTRUCTIONS = """
+ Indicator size of Checkbox depends
+ on the platform font used to render the label.
+
+ In the frame you can see a group of checkboxes
+ and radio buttons.
+ Verify that all checkboxes and radio buttons have
+ indicators of the same size and proportional to
+ the uiScale and/or font-size.
+
+ Use menu to change the font size and the indicators
+ should scale proportionally.
+
+ If there is a bug, the checkbox/radiobutton with
+ dingbats label will have a smaller indicator.
+
+ Press PASS if the above conditions are true else Press FAIL.
+ """;
+ private static Frame frame;
+ private static Panel testPanel;
+
+ public static void main(String[] args) throws Exception {
+
+ CheckboxIndicatorSizeTest obj = new CheckboxIndicatorSizeTest();
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 3)
+ .columns(60)
+ .testUI(obj::createAndShowUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private Frame createAndShowUI() {
+ frame = new Frame("CheckboxIndicatorSizeTest");
+
+ testPanel = new Panel(new GridLayout(0, 1));
+ testPanel.setFont(new Font("Dialog", Font.PLAIN, 12));
+ frame.add(testPanel);
+
+ MenuBar menuBar = new MenuBar();
+ Menu fontSizeMenu = new Menu("FontSize");
+
+ MenuItem size10 = new MenuItem("10");
+ size10.addActionListener(this);
+ fontSizeMenu.add(size10);
+
+ MenuItem size12 = new MenuItem("12");
+ size12.addActionListener(this);
+ fontSizeMenu.add(size12);
+
+ MenuItem size14 = new MenuItem("14");
+ size14.addActionListener(this);
+ fontSizeMenu.add(size14);
+
+ MenuItem size18 = new MenuItem("18");
+ size18.addActionListener(this);
+ fontSizeMenu.add(size18);
+
+ MenuItem size24 = new MenuItem("24");
+ size24.addActionListener(this);
+ fontSizeMenu.add(size24);
+
+ MenuItem size36 = new MenuItem("36");
+ size36.addActionListener(this);
+ fontSizeMenu.add(size36);
+
+ menuBar.add(fontSizeMenu);
+ frame.setMenuBar(menuBar);
+
+ Checkbox cbEnglishOnly
+ = new Checkbox("Toggle", true);
+ Checkbox cbDingbatsOnly
+ = new Checkbox("\u274a\u274b\u274c\u274d", true);
+ Checkbox cbEnglishDingbats
+ = new Checkbox("Toggle \u274a\u274d", true);
+ Checkbox cbDingbatsEnglish
+ = new Checkbox("\u274a\u274d toggle", true);
+
+ CheckboxGroup radioGroup = new CheckboxGroup();
+ Checkbox rbEnglishOnly
+ = new Checkbox("Radio", true, radioGroup);
+ Checkbox rbDingbatsOnly
+ = new Checkbox("\u274a\u274b\u274c\u274d", false, radioGroup);
+ Checkbox rbEnglishDingbats
+ = new Checkbox("Radio \u274a\u274d", false, radioGroup);
+ Checkbox rbDingbatsEnglish
+ = new Checkbox("\u274a\u274d radio", false, radioGroup);
+
+ Label cbLabel = new Label("Checkboxes");
+ cbLabel.setBackground(Color.YELLOW);
+ testPanel.add(cbLabel);
+ testPanel.add(cbEnglishOnly);
+ testPanel.add(cbDingbatsOnly);
+ testPanel.add(cbEnglishDingbats);
+ testPanel.add(cbDingbatsEnglish);
+
+ Label rbLabel = new Label("Radio buttons");
+ rbLabel.setBackground(Color.YELLOW);
+ testPanel.add(rbLabel);
+ testPanel.add(rbEnglishOnly);
+ testPanel.add(rbDingbatsOnly);
+ testPanel.add(rbEnglishDingbats);
+ testPanel.add(rbDingbatsEnglish);
+
+ frame.pack();
+ return frame;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String sizeStr = e.getActionCommand();
+ int size = Integer.parseInt(sizeStr);
+ Font oldFont = testPanel.getFont();
+ Font newFont = new Font(oldFont.getName(), oldFont.getStyle(), size);
+ testPanel.setFont(newFont);
+ frame.pack();
+ frame.setVisible(true);
+ }
+}
diff --git a/test/jdk/java/awt/Checkbox/CheckboxNullLabelTest.java b/test/jdk/java/awt/Checkbox/CheckboxNullLabelTest.java
new file mode 100644
index 00000000000..c5cb7c27829
--- /dev/null
+++ b/test/jdk/java/awt/Checkbox/CheckboxNullLabelTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2024, Oracle and/or its affiliates. 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 java.awt.BorderLayout;
+import java.awt.Checkbox;
+import java.awt.CheckboxGroup;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.Panel;
+
+/*
+ * @test
+ * @bug 4383735
+ * @summary Checkbox buttons are too small with java 1.3 and 1.4
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual CheckboxNullLabelTest
+ */
+
+public class CheckboxNullLabelTest {
+ private static final String INSTRUCTIONS = """
+ Please look at the frame titled 'CheckboxNullLabelTest'.
+ Check if all the check boxes in each group
+ (of 3 check boxes) have the same size.
+
+ If the size of labeled check box is NOT the same as
+ the size of non-labeled Press FAIL otherwise Press PASS.
+ """;
+
+ public static void main(String[] args) throws Exception {
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 1)
+ .columns(35)
+ .testUI(CheckboxNullLabelTest::createAndShowUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Frame createAndShowUI() {
+ Frame f = new Frame("CheckboxNullLabelTest");
+ f.setLayout(new BorderLayout());
+ f.add(new CheckboxTest(Color.gray, new Font(null, 0, 12)), "North");
+ f.add(new CheckboxTest(Color.green, new Font(null, 0, 18)), "South");
+ f.add(new CheckboxTest(Color.red, new Font(null, 0, 24)), "East");
+ f.add(new CheckboxTest(Color.white, new Font(null, 0, 30)), "West");
+ f.add(new CheckboxTest(f.getBackground(), new Font(null, 0, 36)), "Center");
+ f.setSize(600, 450);
+ return f;
+ }
+
+ private static class CheckboxTest extends Panel {
+ Checkbox cb1, cb2, cb3;
+
+ CheckboxTest(Color background, Font font) {
+ setBackground(background);
+ CheckboxGroup cbg = new CheckboxGroup();
+
+ cb1 = new Checkbox(null, cbg, true);
+ cb1.setFont(font);
+
+ cb2 = new Checkbox("", cbg, true);
+ cb2.setFont(font);
+
+ cb3 = new Checkbox("Label", cbg, false);
+ cb3.setFont(font);
+
+ add(cb1);
+ add(cb2);
+ add(cb3);
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Checkbox/CheckboxPreferredSizeTest.java b/test/jdk/java/awt/Checkbox/CheckboxPreferredSizeTest.java
new file mode 100644
index 00000000000..dd61b52aaed
--- /dev/null
+++ b/test/jdk/java/awt/Checkbox/CheckboxPreferredSizeTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2000, 2024, Oracle and/or its affiliates. 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 java.awt.Checkbox;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Frame;
+
+/*
+ * @test
+ * @bug 4304049
+ * @summary tests that Checkbox fits into its preferred size entirely
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual CheckboxPreferredSizeTest
+ */
+
+public class CheckboxPreferredSizeTest {
+ private static final String INSTRUCTIONS = """
+ As the test starts, ensure that the
+ whole checkbox with all its text is visible.
+ If the checkbox is entirely visible, press PASS else,
+ press FAIL.
+ """;
+
+ public static void main(String[] args) throws Exception {
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 1)
+ .columns(35)
+ .testUI(CheckboxPreferredSizeTest::createAndShowUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Frame createAndShowUI() {
+ Frame frame = new Frame("Checkbox Preferred Size Test");
+ frame.setBackground(Color.BLUE);
+ Checkbox box = new Checkbox("Checkbox_With_Some_Size");
+ box.setFont(new Font("Helvetica", Font.PLAIN, 36));
+ box.setBackground(Color.RED);
+ frame.add(box);
+ frame.pack();
+ return frame;
+ }
+}
diff --git a/test/jdk/java/awt/Checkbox/DynamicChangeTest/DynamicChangeTest.java b/test/jdk/java/awt/Checkbox/DynamicChangeTest/DynamicChangeTest.java
new file mode 100644
index 00000000000..b62255efa45
--- /dev/null
+++ b/test/jdk/java/awt/Checkbox/DynamicChangeTest/DynamicChangeTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6225679
+ * @summary Tests that checkbox changes into radiobutton dynamically
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual DynamicChangeTest
+ */
+
+import java.awt.Checkbox;
+import java.awt.CheckboxGroup;
+import java.awt.Frame;
+import java.awt.GridLayout;
+
+public class DynamicChangeTest {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ This test is primarily for Windows platform, but should pass
+ on other platforms as well. Ensure that 'This is checkbox' is
+ checkbox, and 'This is radiobutton' is radiobutton.
+ If it is so, press pass else fail.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(DynamicChangeTest::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static Frame createUI() {
+ Frame f = new Frame("Dynamic Change Checkbox Test");
+ f.setSize(200, 200);
+
+ f.setLayout(new GridLayout(2, 1));
+ Checkbox ch1 = new Checkbox("This is checkbox",
+ new CheckboxGroup(), true);
+ f.add(ch1);
+ Checkbox ch2 = new Checkbox("This is radiobutton", null, true);
+ f.add(ch2);
+
+ ch1.setCheckboxGroup(null);
+ ch2.setCheckboxGroup(new CheckboxGroup());
+ return f;
+ }
+}
diff --git a/test/jdk/java/awt/Choice/ChoiceDragEventsInside.java b/test/jdk/java/awt/Choice/ChoiceDragEventsInside.java
new file mode 100644
index 00000000000..dde773f1928
--- /dev/null
+++ b/test/jdk/java/awt/Choice/ChoiceDragEventsInside.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2000, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6251983 6722236
+ * @summary MouseDragged events not triggered for Choice when dragging it with left mouse button
+ * @key headful
+ * @run main ChoiceDragEventsInside
+ */
+
+import java.awt.Choice;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionAdapter;
+import java.lang.reflect.InvocationTargetException;
+
+public class ChoiceDragEventsInside extends Frame {
+ Robot robot;
+ Choice choice1;
+ Point pt;
+ Dimension size;
+ volatile boolean mouseDragged = false;
+ volatile boolean mouseDraggedOutside = false;
+
+ public void setupUI() {
+ setTitle("Choce Drag Events Inside");
+ choice1 = new Choice();
+ for (int i = 1; i < 50; i++) {
+ choice1.add("item-0" + i);
+ }
+ choice1.setForeground(Color.red);
+ choice1.setBackground(Color.red);
+ choice1.addMouseMotionListener(new MouseMotionAdapter() {
+ public void mouseMoved(MouseEvent me) {
+ System.out.println(me);
+ }
+
+ public void mouseDragged(MouseEvent me) {
+ System.out.println(me);
+ mouseDragged = true;
+ if (me.getY() < 0) {
+ mouseDraggedOutside = true;
+ }
+ }
+ }
+ );
+ add(choice1);
+ setLayout(new FlowLayout());
+ setSize(200, 200);
+ setLocationRelativeTo(null);
+ setVisible(true);
+ validate();
+ }
+
+ public void start() {
+ try {
+ robot = new Robot();
+ robot.setAutoWaitForIdle(true);
+ robot.setAutoDelay(50);
+ robot.delay(100);
+ EventQueue.invokeAndWait(() -> {
+ pt = choice1.getLocationOnScreen();
+ size = choice1.getSize();
+ });
+ testDragInsideChoice(InputEvent.BUTTON1_MASK);
+ testDragInsideChoiceList(InputEvent.BUTTON1_MASK);
+ testDragOutsideChoice(InputEvent.BUTTON1_MASK);
+ } catch (Throwable e) {
+ throw new RuntimeException("Test failed. Exception thrown: " + e);
+ }
+ }
+
+ public void testDragInsideChoice(int button) {
+ robot.mouseMove(pt.x + size.width / 2, pt.y + size.height / 2);
+ robot.delay(100);
+ robot.mousePress(button);
+ robot.mouseRelease(button);
+ robot.delay(200);
+ robot.mousePress(button);
+ robot.mouseRelease(button);
+ robot.delay(200);
+
+ //close opened choice
+ robot.keyPress(KeyEvent.VK_ESCAPE);
+ robot.keyRelease(KeyEvent.VK_ESCAPE);
+ robot.delay(200);
+
+ robot.mouseMove(pt.x + size.width / 4, pt.y + size.height / 2);
+ robot.mousePress(button);
+
+ dragMouse(pt.x + size.width / 4, pt.y + size.height / 2,
+ pt.x + size.width * 3 / 4, pt.y + size.height / 2);
+ robot.mouseRelease(button);
+ robot.delay(200);
+ if (!mouseDragged) {
+ throw new RuntimeException("Test failed. Choice should generate MouseDragged events inside Choice itself");
+ } else {
+ System.out.println("Stage 1 passed. Choice generates MouseDragged events inside Choice itself");
+ }
+ mouseDragged = false;
+ //close opened choice
+ robot.keyPress(KeyEvent.VK_ESCAPE);
+ robot.keyRelease(KeyEvent.VK_ESCAPE);
+ robot.delay(200);
+ }
+
+ public void testDragInsideChoiceList(int button) {
+ robot.mouseMove(pt.x + size.width / 2, pt.y + size.height / 2);
+ robot.delay(100);
+ robot.mousePress(button);
+ robot.mouseRelease(button);
+ robot.delay(200);
+
+ robot.mouseMove(pt.x + size.width / 2, pt.y + 5 * size.height);
+ robot.delay(200);
+ robot.mousePress(button);
+
+ dragMouse(pt.x + size.width / 2, pt.y + 5 * size.height,
+ pt.x + size.width / 2, pt.y + 8 * size.height);
+ robot.mouseRelease(button);
+ robot.delay(200);
+ if (mouseDragged) {
+ throw new RuntimeException("Test failed. Choice shouldn't generate MouseDragged events inside Choice's list");
+ } else {
+ System.out.println("Stage 2 passed. Choice doesn't generate MouseDragged events inside Choice's list");
+ }
+ robot.keyPress(KeyEvent.VK_ESCAPE);
+ robot.keyRelease(KeyEvent.VK_ESCAPE);
+ robot.delay(200);
+ mouseDragged = false;
+ }
+
+ public void testDragOutsideChoice(int button) {
+ pt = choice1.getLocationOnScreen();
+ robot.mouseMove(pt.x + size.width / 2, pt.y + size.height / 2);
+ robot.delay(100);
+
+ robot.mousePress(button);
+ //drag mouse outside of Choice
+ dragMouse(pt.x + size.width / 2, pt.y + size.height / 2,
+ pt.x + size.width / 2, pt.y - 3 * size.height);
+ robot.mouseRelease(button);
+ robot.delay(200);
+ if (!mouseDragged || !mouseDraggedOutside) {
+ throw new RuntimeException("Test failed. Choice should generate MouseDragged events outside Choice");
+ } else {
+ System.out.println("Stage 3 passed. Choice generates MouseDragged events outside Choice");
+ }
+ robot.keyPress(KeyEvent.VK_ESCAPE);
+ robot.keyRelease(KeyEvent.VK_ESCAPE);
+ robot.delay(200);
+ mouseDragged = false;
+ }
+
+ public void dragMouse(int x0, int y0, int x1, int y1) {
+ int curX = x0;
+ int curY = y0;
+ int dx = x0 < x1 ? 1 : -1;
+ int dy = y0 < y1 ? 1 : -1;
+
+ while (curX != x1) {
+ curX += dx;
+ robot.mouseMove(curX, curY);
+ }
+ while (curY != y1) {
+ curY += dy;
+ robot.mouseMove(curX, curY);
+ }
+ }
+
+ public static void main(final String[] args) throws InterruptedException,
+ InvocationTargetException {
+ ChoiceDragEventsInside app = new ChoiceDragEventsInside();
+ try {
+ EventQueue.invokeAndWait(app::setupUI);
+ app.start();
+ } finally {
+ EventQueue.invokeAndWait(app::dispose);
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Choice/ChoiceMouseEventTest.java b/test/jdk/java/awt/Choice/ChoiceMouseEventTest.java
new file mode 100644
index 00000000000..9603d5c763d
--- /dev/null
+++ b/test/jdk/java/awt/Choice/ChoiceMouseEventTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2000, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4319246
+ * @summary Tests that MouseReleased, MouseClicked and MouseDragged are triggered on choice
+ * @key headful
+ * @run main ChoiceMouseEventTest
+ */
+
+import java.awt.AWTException;
+import java.awt.BorderLayout;
+import java.awt.Choice;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.lang.reflect.InvocationTargetException;
+
+
+public class ChoiceMouseEventTest extends Frame {
+ static volatile boolean mousePressed = false;
+ static volatile boolean mouseReleased = false;
+ static volatile boolean mouseClicked = false;
+ Choice choice = new Choice();
+ static Point location;
+ static Dimension size;
+
+ public void setupGUI() {
+ setTitle("Choice Mouse Event Test");
+ this.setLayout(new BorderLayout());
+ choice.add("item-1");
+ choice.add("item-2");
+ choice.add("item-3");
+ choice.add("item-4");
+ add("Center", choice);
+ choice.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ mouseClicked = true;
+ }
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ mousePressed = true;
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ mouseReleased = true;
+ }
+ });
+ setLocationRelativeTo(null);
+ setSize(400, 200);
+ setVisible(true);
+ }
+
+ public Point _location() {
+ return choice.getLocationOnScreen();
+ }
+
+ public Dimension _size() {
+ return choice.getSize();
+ }
+
+ public static void main(String[] args) throws InterruptedException,
+ InvocationTargetException, AWTException {
+ ChoiceMouseEventTest test = new ChoiceMouseEventTest();
+ try {
+ EventQueue.invokeAndWait(test::setupGUI);
+ Robot robot = new Robot();
+ robot.setAutoDelay(50);
+ robot.delay(1000);
+ robot.waitForIdle();
+ EventQueue.invokeAndWait(() -> {
+ location = test._location();
+ size = test._size();
+ });
+ robot.waitForIdle();
+ robot.mouseMove(location.x + size.width - 10, location.y + (size.height / 2));
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ robot.delay(2000);
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+ robot.delay(2000);
+ robot.waitForIdle();
+ if (!mouseClicked || !mousePressed || !mouseReleased) {
+ throw new RuntimeException(String.format("One of the events not arrived: " +
+ "mouseClicked = %b, mousePressed = %b, mouseReleased = %b",
+ mouseClicked, mousePressed, mouseReleased));
+ }
+ } finally {
+ if (test != null) {
+ EventQueue.invokeAndWait(test::dispose);
+ }
+ }
+ }
+}
+
diff --git a/test/jdk/java/awt/Choice/ChoiceRemoveTest.java b/test/jdk/java/awt/Choice/ChoiceRemoveTest.java
new file mode 100644
index 00000000000..6de66db9362
--- /dev/null
+++ b/test/jdk/java/awt/Choice/ChoiceRemoveTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4079027
+ * @summary Removing an item dynamically from a Choice object breaks lower items.
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual ChoiceRemoveTest
+ */
+
+import java.awt.Choice;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.Label;
+import java.awt.Panel;
+import java.awt.event.ItemEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.lang.reflect.InvocationTargetException;
+
+public class ChoiceRemoveTest extends Frame {
+ Choice selector;
+ static final String INSTRUCTIONS = """
+ After window 'Choice Remove Test' appears wait for three seconds
+ and then click on the choice. In popup there should be no
+ 'Choice A' variant. Try selecting each variant with mouse
+ and verify by the log that the correct variant gets selected.
+ If after selecting item in the list the correct item gets selected
+ and correct item name appears in the log press Pass otherwise press Fail.
+ """;
+
+ public static void main(String[] argv) throws InterruptedException,
+ InvocationTargetException {
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .testUI(ChoiceRemoveTest::new)
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .logArea()
+ .build()
+ .awaitAndCheck();
+ }
+
+ public ChoiceRemoveTest() {
+ super("Choice Remove Test");
+ Panel p;
+ Label prompt;
+
+ addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowOpened(WindowEvent e) {
+ super.windowOpened(e);
+ new Thread(() -> {
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ignore) {
+ }
+ removeFirst();
+ }).start();
+ }
+ });
+
+ setLayout(new GridLayout());
+ p = new Panel();
+
+ prompt = new Label("Select different items including the last one");
+ p.add(prompt);
+
+ selector = new Choice();
+ selector.add("Choice A");
+ selector.add("Choice B");
+ selector.add("Choice C");
+ selector.add("Choice D");
+ selector.add("Choice E");
+ selector.addItemListener(e -> {
+ if (e.getStateChange() == ItemEvent.SELECTED) {
+ Object selected = e.getItem();
+ PassFailJFrame.log(selected.toString());
+ }
+ });
+ p.add(selector);
+ add(p);
+ pack();
+ }
+
+ public void removeFirst() {
+ selector.remove("Choice A");
+ }
+}
diff --git a/test/jdk/java/awt/Choice/PopupMenuOnChoiceArea.java b/test/jdk/java/awt/Choice/PopupMenuOnChoiceArea.java
new file mode 100644
index 00000000000..2a56d7281ee
--- /dev/null
+++ b/test/jdk/java/awt/Choice/PopupMenuOnChoiceArea.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6240046
+ * @summary REG:Choice's Drop-down does not disappear when clicking somewhere, after popup menu is disposed-XTkt
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual PopupMenuOnChoiceArea
+ */
+
+
+import java.awt.CheckboxMenuItem;
+import java.awt.Choice;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.PopupMenu;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.lang.reflect.InvocationTargetException;
+
+public class PopupMenuOnChoiceArea extends Frame {
+ static final String INSTRUCTIONS = """
+ You would see a window named 'Popup menu on choice area'
+ with Choice in it. Move the mouse pointer to the choice.
+ Click right mouse button on it.
+ You should see a popup menu with 'File' in it.
+ Close this popup menu by pressing Esc.
+ Click the left mouse button on the Choice.
+ You should see a Choice drop-down menu.
+ Move mouse pointer into drop-down menu.
+ Click right mouse button on any item in it.
+ If you see a 'File' popup menu press Fail.
+ If Choice drop-down closes instead press Pass.
+ """;
+
+ public PopupMenuOnChoiceArea() {
+ super("Popup menu on choice area");
+ this.setLayout(new FlowLayout());
+ Choice choice = new Choice();
+ choice.add("item-1");
+ choice.add("item-2");
+ choice.add("item-3");
+ choice.add("item-4");
+ add("Center", choice);
+ Menu fileMenu = new Menu("File");
+ Menu open = new Menu("Open");
+ Menu save = new Menu("save");
+ CheckboxMenuItem exit = new CheckboxMenuItem("Exit");
+ fileMenu.add(open);
+ fileMenu.add(save);
+ fileMenu.add(exit);
+ final PopupMenu pop = new PopupMenu();
+ pop.setLabel("This is a popup menu");
+ pop.setName("a menu");
+ pop.add(fileMenu);
+ choice.add(pop);
+ choice.addMouseListener(new MouseAdapter() {
+ public void mousePressed(MouseEvent me) {
+ if (me.isPopupTrigger()) {
+ pop.show(me.getComponent(), me.getX(), me.getY());
+ }
+ }
+
+ public void mouseReleased(MouseEvent me) {
+ if (me.isPopupTrigger()) {
+ pop.show(me.getComponent(), me.getX(), me.getY());
+ }
+ }
+ });
+ setSize(200, 200);
+ }
+
+ public static void main(String[] args) throws InterruptedException,
+ InvocationTargetException {
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .testUI(PopupMenuOnChoiceArea::new)
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .build()
+ .awaitAndCheck();
+ }
+}
diff --git a/test/jdk/java/awt/Choice/ScrollbarFlickers.java b/test/jdk/java/awt/Choice/ScrollbarFlickers.java
new file mode 100644
index 00000000000..c35d4900134
--- /dev/null
+++ b/test/jdk/java/awt/Choice/ScrollbarFlickers.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2006, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6405707
+ * @summary Choice popup & scrollbar gets Flickering when mouse is pressed & drag on the scrollbar
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual ScrollbarFlickers
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Choice;
+import java.awt.Frame;
+import java.lang.reflect.InvocationTargetException;
+
+public class ScrollbarFlickers extends Frame {
+ static final String INSTRUCTIONS = """
+ Open the choice popup. Select any item in it and
+ drag it with the mouse above or below the choice.
+ Keep the choice opened.
+ Continue dragging the mouse outside of the choice
+ making content of the popup scroll.
+ If you see that scrollbar flickers press Fail.
+ Otherwise press Pass.
+ """;
+
+ public ScrollbarFlickers() {
+ super("Scrollbar Flickering Test");
+ Choice ch = new Choice();
+ setLayout(new BorderLayout());
+ ch.add("Praveen");
+ ch.add("Mohan");
+ ch.add("Rakesh");
+ ch.add("Menon");
+ ch.add("Girish");
+ ch.add("Ramachandran");
+ ch.add("Elancheran");
+ ch.add("Subramanian");
+ ch.add("Raju");
+ ch.add("Pallath");
+ ch.add("Mayank");
+ ch.add("Joshi");
+ ch.add("Sundar");
+ ch.add("Srinivas");
+ ch.add("Mandalika");
+ ch.add("Suresh");
+ ch.add("Chandar");
+ add(ch);
+ setSize(200, 200);
+ validate();
+ }
+
+ public static void main(String[] args) throws InterruptedException,
+ InvocationTargetException {
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .testUI(ScrollbarFlickers::new)
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .build()
+ .awaitAndCheck();
+ }
+}
diff --git a/test/jdk/java/awt/Component/PaintGlitchTest/PaintGlitchTest.java b/test/jdk/java/awt/Component/PaintGlitchTest/PaintGlitchTest.java
new file mode 100644
index 00000000000..867d82d3262
--- /dev/null
+++ b/test/jdk/java/awt/Component/PaintGlitchTest/PaintGlitchTest.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 1997, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4045781
+ * @summary Exposed/damaged canvases don't always update correctly
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual PaintGlitchTest
+ */
+
+import java.awt.Button;
+import java.awt.Canvas;
+import java.awt.Checkbox;
+import java.awt.Choice;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dialog;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Label;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.Panel;
+import java.awt.Scrollbar;
+import java.awt.TextArea;
+import java.awt.TextField;
+import java.lang.reflect.InvocationTargetException;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollBar;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+
+public class PaintGlitchTest extends Frame {
+ static final String INSTRUCTIONS = """
+ 1. Click on the 'Painting Glitch Test' window and select from
+ its menu a content type (text, gradient, fill,
+ AWT components, Swing components etc.).
+ 2. Select 'Modal Dialog...' to create a dialog.
+ 3. Drag the dialog over the content very fast
+ for 10 seconds or so - make sure you
+ keep dragging while the content is painting.
+ 4. Verify that the area exposed by the drag (the damaged regions)
+ always update properly no white areas or bits of the dialog
+ should be left after the drag operation is
+ completed (i.e. after you let go of the mouse).
+ 5. Repeat for all other content types.
+ 6. If for any content type the damaged dialog is not properly
+ repainted press Fail. Otherwise press Pass.
+ """;
+
+ public PaintGlitchTest() {
+ super("Painting Glitch Test");
+
+ TextPanel textPanel = new TextPanel();
+ GradientPanel gradientPanel = new GradientPanel();
+ ComponentPanel componentPanel = new ComponentPanel();
+ SwingPanel swingPanel = new SwingPanel();
+
+ add(textPanel);
+
+ MenuBar menubar = new MenuBar();
+ Menu testMenu = new Menu("Test");
+ testMenu.add(makeContentItem("Text Lines", textPanel) );
+ testMenu.add(makeContentItem("Gradient Fill", gradientPanel) );
+ testMenu.add(makeContentItem("AWT Components", componentPanel) );
+ testMenu.add(makeContentItem("Swing Components", swingPanel) );
+ testMenu.addSeparator();
+ MenuItem dialogItem = new MenuItem("Modal Dialog...");
+ dialogItem.addActionListener(ev -> new ObscuringDialog(PaintGlitchTest.this).show());
+ testMenu.add(dialogItem);
+ testMenu.addSeparator();
+ menubar.add(testMenu);
+
+ setMenuBar(menubar);
+ setSize(400,300);
+ }
+
+ public static void main(String args[]) throws InterruptedException,
+ InvocationTargetException {
+ PassFailJFrame.builder()
+ .title("Repaint Glitch")
+ .testUI(PaintGlitchTest::new)
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .logArea()
+ .build()
+ .awaitAndCheck();
+ }
+
+ public MenuItem makeContentItem(String title, final Component content) {
+ MenuItem menuItem = new MenuItem(title);
+ menuItem.addActionListener(
+ ev -> {
+ remove(0);
+ add(content);
+ validate();
+ }
+ );
+
+ return menuItem;
+ }
+}
+
+class GradientPanel extends Canvas {
+ public void paint(Graphics g) {
+ long ms = System.currentTimeMillis();
+ // just paint something that'll take a while
+ int x, y;
+ int width = getSize().width;
+ int height = getSize().height;
+ int step = 8;
+
+ for (x = 0; x < width; x += step) {
+ for (y = 0; y < height; y += step) {
+ int red = (255 * y) / height;
+ int green = (255 * x * y) / (width * height);
+ int blue = (255 * x) / width;
+
+ Color color = new Color(red, green, blue);
+ g.setColor(color);
+ g.fillRect(x, y, step, step);
+ }
+ }
+ long time = System.currentTimeMillis() - ms;
+ PassFailJFrame.log("GradientPanel paint took " + time + " ms");
+ }
+
+ public Dimension getPreferredSize() {
+ return new Dimension(200,1000);
+ }
+}
+
+class TextPanel extends Canvas {
+ public void paint(Graphics g) {
+ long ms = System.currentTimeMillis();
+ Font font = new Font("SanSerif", Font.ITALIC, 12);
+
+ g.setFont(font);
+ // just paint something that'll take a while
+ int x, y;
+ int height = getHeight();
+ int step = 16;
+
+ for (x = y = 0; y < height; y += step) {
+ g.drawString(y + " : The quick brown fox jumps over the lazy dog. " +
+ "The rain in Spain falls mainly on the plain.", x, y);
+ }
+ long time = System.currentTimeMillis() - ms;
+ PassFailJFrame.log("TextPanel paint took " + time + " ms");
+ }
+
+ public Dimension getPreferredSize() {
+ return new Dimension(640,1000);
+ }
+}
+
+class ComponentPanel extends Panel {
+ ComponentPanel() {
+ add(new Label("Label"));
+ add(new Button("Button"));
+ add(new Checkbox("Checkbox"));
+ Choice c = new Choice();
+ c.add("choice");
+ java.awt.List l = new java.awt.List();
+ l.add("list");
+ add(new Scrollbar());
+ add(new TextField("TextField"));
+ add(new TextArea("TextArea"));
+ add(new Panel());
+ add(new Canvas());
+ }
+}
+
+class SwingPanel extends JPanel {
+ SwingPanel() {
+ add(new JLabel("JLabel"));
+ add(new JButton("JButton"));
+ add(new JCheckBox("JCheckBox"));
+ JComboBox c = new JComboBox();
+ JList l = new JList();
+ add(new JScrollBar());
+ add(new JTextField("This is a JTextField with some text in it to make it longer."));
+ add(new JTextArea("This is a JTextArea with some text in it to make it longer."));
+ }
+}
+
+class ObscuringDialog extends Dialog {
+ ObscuringDialog(Frame f) {
+ super(f, "Obscuring Dialog");
+ Button ok = new Button("OK, go away");
+ ok.addActionListener(ev -> dispose());
+ add(ok);
+ pack();
+ }
+}
diff --git a/test/jdk/java/awt/Component/ProcessEvent/ProcessEvent.java b/test/jdk/java/awt/Component/ProcessEvent/ProcessEvent.java
new file mode 100644
index 00000000000..3dfd5a04038
--- /dev/null
+++ b/test/jdk/java/awt/Component/ProcessEvent/ProcessEvent.java
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4292099
+ * @summary AWT Event delivery to processEvent
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual ProcessEvent
+ */
+
+import java.awt.AWTEvent;
+import java.awt.AWTEventMulticaster;
+import java.awt.Adjustable;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.ItemSelectable;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.AdjustmentEvent;
+import java.awt.event.AdjustmentListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.TextEvent;
+import java.awt.event.TextListener;
+import java.lang.reflect.InvocationTargetException;
+
+public class ProcessEvent extends Frame {
+
+ static final String INSTRUCTIONS = """
+ Press each of the four buttons for ActionEvent, AdjustmentEvent,
+ ItemEvent and TextEvent. If a message for each corresponding event
+ appears in the log area and says the event listener was
+ called, then press Pass otherwise press Fail.
+ """;
+ ActionBtn af;
+ AdjustmentBtn adjf;
+ ItemBtn itf;
+ TextBtn txtf;
+
+ public ProcessEvent() {
+ setLayout(new FlowLayout());
+ add(af = new ActionBtn());
+ af.setBackground(Color.green);
+
+ add(adjf = new AdjustmentBtn());
+ adjf.setBackground(Color.green);
+
+ add(itf = new ItemBtn());
+ itf.setBackground(Color.green);
+
+ add(txtf = new TextBtn());
+ txtf.setBackground(Color.green);
+
+ // These action listeners simply provide feedback of when
+ // the event is delivered properly.
+ af.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent ae) {
+ PassFailJFrame.log(af.getText()
+ + ": action listener called: "
+ + ae.toString());
+ }
+ });
+
+ adjf.addAdjustmentListener(new AdjustmentListener() {
+ public void adjustmentValueChanged(AdjustmentEvent ae) {
+ PassFailJFrame.log(adjf.getText()
+ + ": adjustment listener called: "
+ + ae.toString());
+ }
+ });
+
+ itf.addItemListener(new ItemListener() {
+ public void itemStateChanged(ItemEvent e) {
+ PassFailJFrame.log(itf.getText()
+ + ": item listener called: "
+ + e.toString());
+ }
+ });
+
+ txtf.addTextListener(new TextListener() {
+ public void textValueChanged(TextEvent e) {
+ PassFailJFrame.log(txtf.getText()
+ + ": text listener called: "
+ + e.toString());
+ }
+ });
+
+ pack();
+ }
+
+ public static void main(String[] args) throws InterruptedException,
+ InvocationTargetException {
+ PassFailJFrame.builder()
+ .title("Process Events Test")
+ .testUI(ProcessEvent::new)
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .logArea()
+ .build()
+ .awaitAndCheck();
+ }
+}
+
+class ButtonComponent extends Component implements ItemSelectable, Adjustable {
+
+ transient protected TextListener textListener;
+ transient ActionListener actionListener;
+ transient AdjustmentListener adjustmentListener;
+ transient ItemListener itemListener;
+ String actionCommand = null;
+
+ String text = null;
+
+ public ButtonComponent(String label) {
+ super();
+ text = label;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public Dimension getPreferredSize() {
+ return new Dimension(200, 30);
+ }
+
+ public Dimension getMinimumSize() {
+ return getPreferredSize();
+ }
+
+ public String getActionCommand() {
+ if (actionCommand == null)
+ return getText();
+ else
+ return actionCommand;
+ }
+
+ public void setActionCommand(String ac) {
+ actionCommand = ac;
+ }
+
+ // ActionEvent listener support
+
+ public synchronized void addActionListener(ActionListener l) {
+ if (l == null) {
+ return;
+ }
+ enableEvents(AWTEvent.ACTION_EVENT_MASK);
+ actionListener = AWTEventMulticaster.add(actionListener, l);
+ }
+
+ public synchronized void removeActionListener(ActionListener l) {
+ if (l == null) {
+ return;
+ }
+ actionListener = AWTEventMulticaster.remove(actionListener, l);
+ }
+
+ // AdjustmentEvent listener support
+
+ public synchronized void addAdjustmentListener(AdjustmentListener l) {
+ if (l == null) {
+ return;
+ }
+ enableEvents(AWTEvent.ADJUSTMENT_EVENT_MASK);
+ adjustmentListener = AWTEventMulticaster.add(adjustmentListener, l);
+ }
+
+ public synchronized void removeAdjustmentListener(AdjustmentListener l) {
+ if (l == null) {
+ return;
+ }
+ adjustmentListener = AWTEventMulticaster.remove(adjustmentListener, l);
+ }
+
+ // ItemEvent listener support
+
+ public synchronized void addItemListener(ItemListener l) {
+ if (l == null) {
+ return;
+ }
+ enableEvents(AWTEvent.ITEM_EVENT_MASK);
+ itemListener = AWTEventMulticaster.add(itemListener, l);
+ }
+
+ public synchronized void removeItemListener(ItemListener l) {
+ if (l == null) {
+ return;
+ }
+ itemListener = AWTEventMulticaster.remove(itemListener, l);
+ }
+
+ // TextEvent listener support
+
+ public synchronized void addTextListener(TextListener l) {
+ if (l == null) {
+ return;
+ }
+ enableEvents(AWTEvent.TEXT_EVENT_MASK);
+ textListener = AWTEventMulticaster.add(textListener, l);
+ }
+
+ public synchronized void removeTextListener(TextListener l) {
+ if (l == null) {
+ return;
+ }
+ textListener = AWTEventMulticaster.remove(textListener, l);
+ }
+
+ // Implement the processEvent and processXXXEvent methods to
+ // handle reception and processing of the event types.
+
+ protected void processEvent(AWTEvent e) {
+ if (e instanceof ActionEvent) {
+ processActionEvent((ActionEvent) e);
+ return;
+ }
+ if (e instanceof AdjustmentEvent) {
+ processAdjustmentEvent((AdjustmentEvent) e);
+ return;
+ }
+ if (e instanceof ItemEvent) {
+ processItemEvent((ItemEvent) e);
+ return;
+ }
+ if (e instanceof TextEvent) {
+ processTextEvent((TextEvent) e);
+ return;
+ }
+ super.processEvent(e);
+ }
+
+ protected void processActionEvent(ActionEvent e) {
+ if (actionListener != null) {
+ actionListener.actionPerformed(e);
+ }
+ }
+
+ protected void processAdjustmentEvent(AdjustmentEvent e) {
+ if (adjustmentListener != null) {
+ adjustmentListener.adjustmentValueChanged(e);
+ }
+ }
+
+ protected void processItemEvent(ItemEvent e) {
+ if (itemListener != null) {
+ itemListener.itemStateChanged(e);
+ }
+ }
+
+ protected void processTextEvent(TextEvent e) {
+ if (textListener != null) {
+ textListener.textValueChanged(e);
+ }
+ }
+
+ public void paint(Graphics g) {
+ Dimension dim = getSize();
+ g.clearRect(0, 0, dim.width, dim.height);
+ g.setColor(getForeground());
+ g.drawString(text, 2, dim.height - 2);
+ }
+
+ /**
+ * Returns the selected items or null if no items are selected.
+ */
+ public Object[] getSelectedObjects() {
+ return null;
+ }
+
+ /**
+ * Gets the orientation of the adjustable object.
+ */
+ public int getOrientation() {
+ return 0;
+ }
+
+ /**
+ * Gets the minimum value of the adjustable object.
+ */
+ public int getMinimum() {
+ return 0;
+ }
+
+ /**
+ * Sets the minimum value of the adjustable object.
+ *
+ * @param min the minimum value
+ */
+ public void setMinimum(int min) {
+ }
+
+ /**
+ * Gets the maximum value of the adjustable object.
+ */
+ public int getMaximum() {
+ return 0;
+ }
+
+ /**
+ * Sets the maximum value of the adjustable object.
+ *
+ * @param max the maximum value
+ */
+ public void setMaximum(int max) {
+ }
+
+ /**
+ * Gets the unit value increment for the adjustable object.
+ */
+ public int getUnitIncrement() {
+ return 0;
+ }
+
+ /**
+ * Sets the unit value increment for the adjustable object.
+ *
+ * @param u the unit increment
+ */
+ public void setUnitIncrement(int u) {
+ }
+
+ /**
+ * Gets the block value increment for the adjustable object.
+ */
+ public int getBlockIncrement() {
+ return 0;
+ }
+
+ /**
+ * Sets the block value increment for the adjustable object.
+ *
+ * @param b the block increment
+ */
+ public void setBlockIncrement(int b) {
+ }
+
+ /**
+ * Gets the length of the propertional indicator.
+ */
+ public int getVisibleAmount() {
+ return 0;
+ }
+
+ /**
+ * Sets the length of the proportionl indicator of the
+ * adjustable object.
+ *
+ * @param v the length of the indicator
+ */
+ public void setVisibleAmount(int v) {
+ }
+
+ /**
+ * Gets the current value of the adjustable object.
+ */
+ public int getValue() {
+ return 0;
+ }
+
+ /**
+ * Sets the current value of the adjustable object. This
+ * value must be within the range defined by the minimum and
+ * maximum values for this object.
+ *
+ * @param v the current value
+ */
+ public void setValue(int v) {
+ }
+
+}
+
+class ActionBtn extends ButtonComponent {
+ public ActionBtn() {
+ super("ActionEvent");
+ addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ ActionEvent ae = new ActionEvent(e.getSource(),
+ ActionEvent.ACTION_PERFORMED,
+ getActionCommand());
+ Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ae);
+ }
+ });
+ }
+}
+
+class AdjustmentBtn extends ButtonComponent {
+ public AdjustmentBtn() {
+ super("AdjustmentEvent");
+ addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ AdjustmentEvent ae = new AdjustmentEvent((Adjustable) e.getSource(),
+ AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED,
+ 1, 1);
+ Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ae);
+ }
+ });
+ }
+}
+
+class ItemBtn extends ButtonComponent {
+ public ItemBtn() {
+ super("ItemEvent");
+ addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ ItemEvent ae = new ItemEvent((ItemSelectable) e.getSource(),
+ ItemEvent.ITEM_STATE_CHANGED,
+ e.getSource(), 1);
+ Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ae);
+ }
+ });
+ }
+}
+
+class TextBtn extends ButtonComponent {
+ public TextBtn() {
+ super("TextEvent");
+ addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ TextEvent ae = new TextEvent(e.getSource(),
+ TextEvent.TEXT_VALUE_CHANGED);
+ Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ae);
+ }
+ });
+ }
+}
diff --git a/test/jdk/java/awt/Component/SetFontOrBackground/SetBgrFnt.java b/test/jdk/java/awt/Component/SetFontOrBackground/SetBgrFnt.java
new file mode 100644
index 00000000000..02707ad5784
--- /dev/null
+++ b/test/jdk/java/awt/Component/SetFontOrBackground/SetBgrFnt.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4906548 4921849
+ * @summary Checks that setFont and setBackground have immediate effect
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual SetBgrFnt
+ */
+
+import java.awt.Button;
+import java.awt.Canvas;
+import java.awt.Checkbox;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.Label;
+import java.lang.reflect.InvocationTargetException;
+
+public class SetBgrFnt extends Frame {
+ static final String INSTRUCTIONS = """
+ 1. Press a button marked 'Switch fonts'
+ fonts in three components below (a Button, a Checkbox
+ and a Label) must change immediately.
+
+ 2. Press a button marked 'Switch background'
+ background of three components and canvas must change.
+ MacOS is an exception - AWT buttons on macOS so not
+ change color so on macOS only canvas, checkbox
+ and a label should change background.
+
+ If this is the behavior that you observe press Pass,
+ otherwise press Fail.
+ """;
+ Label la;
+ Button bu, bu1, bu2;
+ Checkbox cb;
+ Font font1, font2;
+ Canvas ca;
+ boolean bToggleFont = true;
+ boolean bToggleBg = true;
+
+ public SetBgrFnt() {
+ bu = new Button("Switch fonts");
+ bu1 = new Button("Switch background");
+ bu2 = new Button("I'm a button");
+ cb = new Checkbox("Checkbox I am");
+ la = new Label("I am a label");
+ ca = new Canvas();
+ font1 = new Font("Serif", Font.ITALIC, 22);
+ font2 = new Font("SansSerif", Font.PLAIN, 10);
+ la.setFont(font1);
+ cb.setFont(font1);
+ bu2.setFont(font1);
+ bu.addActionListener(ae -> {
+ if (bToggleFont) {
+ la.setFont(font2);
+ cb.setFont(font2);
+ bu2.setFont(font2);
+ } else {
+ la.setFont(font1);
+ cb.setFont(font1);
+ bu2.setFont(font1);
+ }
+ bToggleFont = !bToggleFont;
+ });
+
+ bu1.addActionListener(ae -> {
+ if (bToggleBg) {
+ ca.setBackground(Color.YELLOW);
+ setBackground(Color.YELLOW);
+ } else {
+ ca.setBackground(Color.GREEN);
+ setBackground(Color.GREEN);
+ }
+ bToggleBg = !bToggleBg;
+ });
+
+ setLayout(new GridLayout(8, 1));
+ add(bu);
+ add(bu1);
+ add(new Label());
+ add("South", la);
+ add("South", bu2);
+ add("South", cb);
+ add("South", ca);
+ pack();
+ }
+
+ public static void main(String[] args) throws InterruptedException,
+ InvocationTargetException {
+ PassFailJFrame.builder()
+ .title("Set Font and Background Test")
+ .testUI(SetBgrFnt::new)
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .build()
+ .awaitAndCheck();
+ }
+}
diff --git a/test/jdk/java/awt/Cursor/BlockedWindowTest/BlockedWindowTest.java b/test/jdk/java/awt/Cursor/BlockedWindowTest/BlockedWindowTest.java
new file mode 100644
index 00000000000..f1313dbb742
--- /dev/null
+++ b/test/jdk/java/awt/Cursor/BlockedWindowTest/BlockedWindowTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2006, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6391547
+ * @summary Test if the JTextField's cursor is changed when there is a modal dialog
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual BlockedWindowTest
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Cursor;
+import java.awt.Dialog;
+import java.awt.Frame;
+import java.awt.TextField;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+class MyDialog extends Dialog implements ActionListener {
+ MyDialog(Frame owner) {
+ super(owner, "Modal dialog", true);
+ setBounds(owner.getX() + 150, owner.getY() + 150, 100, 100);
+ setLayout(new BorderLayout());
+ Button b = new Button("Close");
+ add(b, "South");
+ b.addActionListener(this);
+ setVisible(true);
+ }
+
+ public void actionPerformed(ActionEvent ae) {
+ setVisible(false);
+ this.dispose();
+ }
+}
+
+class MyFrame extends Frame implements ActionListener {
+ Dialog d;
+
+ public MyFrame() {
+ super("ManualYesNoTest");
+ Button b = new Button("Click here");
+ TextField tf = new TextField("A text field");
+ b.addActionListener(this);
+ setLayout(new BorderLayout());
+ setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ add(b, "South");
+ add(tf, "North");
+ setSize(300, 300);
+ }
+
+ public void actionPerformed(ActionEvent ae) {
+ d = new MyDialog(this);
+ }
+}
+
+public class BlockedWindowTest {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ Verify that the hand cursor is displayed over the window and
+ text cursor over TextField.
+ Click the button in the window to display a modal dialog.
+ Verify that default cursor is displayed over the window
+ and over TextField now.
+ Then close modal dialog and verify that hand cursor is
+ displayed over window and text cursor over TextField.
+ If so, press PASS, else press FAIL.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(35)
+ .testUI(BlockedWindowTest::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static MyFrame createUI() {
+ MyFrame f = new MyFrame();
+ return f;
+ }
+}
diff --git a/test/jdk/java/awt/Cursor/CursorDragTest/ListDragCursor.java b/test/jdk/java/awt/Cursor/CursorDragTest/ListDragCursor.java
new file mode 100644
index 00000000000..32923f1d78b
--- /dev/null
+++ b/test/jdk/java/awt/Cursor/CursorDragTest/ListDragCursor.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2000, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4313052
+ * @summary Test cursor changes after mouse dragging ends
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual ListDragCursor
+ */
+
+import java.awt.Cursor;
+import java.awt.Frame;
+import java.awt.List;
+import java.awt.Panel;
+import java.awt.TextArea;
+
+public class ListDragCursor {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ 1. Move mouse to the TextArea.
+ 2. Press the left mouse button.
+ 3. Drag mouse to the list.
+ 4. Release the left mouse button.
+
+ If the mouse cursor starts as a Text Line Cursor and changes
+ to a regular Pointer Cursor, then Hand Cursor when hovering
+ the list, pass the test. This test fails if the cursor does
+ not update at all when pointing over the different components.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(ListDragCursor::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static Frame createUI() {
+ Frame frame = new Frame("Cursor change after drag");
+ Panel panel = new Panel();
+
+ List list = new List(2);
+ list.add("List1");
+ list.add("List2");
+ list.add("List3");
+ list.add("List4");
+ list.setCursor(new Cursor(Cursor.HAND_CURSOR));
+
+ TextArea textArea = new TextArea(3, 5);
+ textArea.setCursor(new Cursor(Cursor.TEXT_CURSOR));
+
+ panel.add(textArea);
+ panel.add(list);
+
+ frame.add(panel);
+ frame.setBounds(300, 100, 300, 150);
+ return frame;
+ }
+}
diff --git a/test/jdk/java/awt/Cursor/CursorUpdateTest/CursorUpdateTest.java b/test/jdk/java/awt/Cursor/CursorUpdateTest/CursorUpdateTest.java
new file mode 100644
index 00000000000..33e2a3cb166
--- /dev/null
+++ b/test/jdk/java/awt/Cursor/CursorUpdateTest/CursorUpdateTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2004, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 5097531
+ * @summary Make sure the cursor updates correctly under certain
+ * circumstances even when the EDT is busy
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual CursorUpdateTest
+ */
+
+import java.awt.Button;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Graphics;
+
+public class CursorUpdateTest {
+ final static String progress = "|/-\\";
+
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ Check the following:
+ 1. Cursor must be crosshair when hovering the mouse over the
+ blue square.
+ 2. Crosshair cursor must not flicker.
+ 3. The cursor must be "I-beam" when hovering the mouse over the
+ button.
+ 4. Click the button - it will display "Busy" message and a
+ rotating bar for 5 seconds. The cursor must change to
+ hourglass.
+ 5. (Windows only) While the cursor is on the button, press Alt.
+ The cursor must change to normal shape. Pressing Alt again
+ must revert it back to I-beam.
+ 6. Move the mouse out of the button and back onto it. The cursor
+ must update correctly (hourglass over the button, normal
+ over the frame) even when the button displays "busy".
+ Do not try to check (1) or (5) when the button displays
+ "Busy" - this is not required.
+ Pass if all the steps are as behave as described. Otherwise,
+ fail this test.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(35)
+ .testUI(CursorUpdateTest::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static Frame createUI() {
+ Frame f = new Frame();
+ f.setLayout(new FlowLayout());
+ Button b = new Button("Button");
+ f.add(b);
+ b.setCursor(new Cursor(Cursor.TEXT_CURSOR));
+ Component c = new MyComponent();
+ f.add(c);
+ c.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
+ b.addActionListener(e -> {
+ String oldLabel = b.getLabel();
+ Cursor oldCursor = b.getCursor();
+ b.setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ try {
+ for (int i = 0; i < 50; i++) {
+ b.setLabel("Busy " + progress.charAt(i % 4));
+ Thread.sleep(100);
+ }
+ } catch (InterruptedException ex) {
+ }
+ b.setCursor(oldCursor);
+ b.setLabel(oldLabel);
+ });
+ return f;
+ }
+}
+
+class MyComponent extends Component {
+ public void paint(Graphics g) {
+ g.setColor(getBackground());
+ g.fillRect(0, 0, getSize().width, getSize().height);
+ }
+
+ public MyComponent() {
+ setBackground(Color.blue);
+ }
+
+ public Dimension getPreferredSize() {
+ return new Dimension(100, 100);
+ }
+}
diff --git a/test/jdk/java/awt/Cursor/CustomCursorTest/CustomCursorTest.java b/test/jdk/java/awt/Cursor/CustomCursorTest/CustomCursorTest.java
new file mode 100644
index 00000000000..32c1fdc1506
--- /dev/null
+++ b/test/jdk/java/awt/Cursor/CustomCursorTest/CustomCursorTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4174035 4106384 4205805
+ * @summary Test for functionality of Custom Cursor
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual CustomCursorTest
+ */
+
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Frame;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Panel;
+import java.awt.Point;
+import java.awt.Toolkit;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+
+import javax.imageio.ImageIO;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+
+import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
+
+public class CustomCursorTest {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ This test is for switching between a custom cursor and the
+ system cursor.
+
+ 1. Click on the test window panel to change from the default
+ system cursor to the custom red square cursor
+ 2. Verify that the square cursor shows when the panel is clicked
+ 3. Verify that the square cursor is colored red
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(35)
+ .testUI(CustomCursorTest::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static Frame createUI() {
+ JFrame f = new JFrame("Custom Cursor Test");
+ CustomCursorPanel c = null;
+ try {
+ c = new CustomCursorPanel();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ f.setIconImage(c.getImage());
+ f.getContentPane().add(c);
+ f.setSize(400, 400);
+ return f;
+ }
+}
+
+class CustomCursorPanel extends Panel {
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+ Image image;
+ Cursor cursor;
+ boolean flip = false;
+
+ public CustomCursorPanel() throws IOException {
+ generateRedSquareCursor();
+
+ image = toolkit.getImage(System.getProperty("test.classes", ".")
+ + java.io.File.separator + "square_cursor.gif");
+
+ setBackground(Color.green);
+ cursor = toolkit.createCustomCursor(image, new Point(0, 0), "custom");
+
+ JLabel c = (JLabel) add(new JLabel("click to switch between " +
+ "red square and default cursors"));
+ c.setBackground(Color.white);
+ c.setForeground(Color.red);
+
+ addMouseListener(new MouseAdapter() {
+ public void mousePressed(MouseEvent me) {
+ if (!flip) {
+ setCursor(cursor);
+ flip = true;
+ } else {
+ setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+ flip = false;
+ }
+ }
+ });
+ }
+
+ public Image getImage() {
+ return image;
+ }
+
+ private static void generateRedSquareCursor() throws IOException {
+ Path p = Path.of(System.getProperty("test.classes", "."));
+ BufferedImage bImg = new BufferedImage(35, 34, TYPE_INT_ARGB);
+ Graphics2D cg = bImg.createGraphics();
+ cg.setColor(Color.RED);
+ cg.fillRect(0, 0, 35, 34);
+ ImageIO.write(bImg, "png", new File(p + java.io.File.separator +
+ "square_cursor.gif"));
+ }
+}
diff --git a/test/jdk/java/awt/Cursor/HiddenDialogParentTest/HiddenDialogParentTest.java b/test/jdk/java/awt/Cursor/HiddenDialogParentTest/HiddenDialogParentTest.java
new file mode 100644
index 00000000000..7450f4ec3bb
--- /dev/null
+++ b/test/jdk/java/awt/Cursor/HiddenDialogParentTest/HiddenDialogParentTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 5079694
+ * @summary Test if JDialog respects setCursor
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual HiddenDialogParentTest
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Cursor;
+
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.border.LineBorder;
+
+public class HiddenDialogParentTest {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ You can see a label area in the center of JDialog.
+ Verify that the cursor is a hand cursor in this area.
+ If so, press pass, else press fail.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(HiddenDialogParentTest::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static JDialog createUI() {
+ JDialog dialog = new JDialog();
+ dialog.setTitle("JDialog Cursor Test");
+ dialog.setLayout(new BorderLayout());
+ JLabel centerLabel = new JLabel("Cursor should be a hand in this " +
+ "label area");
+ centerLabel.setBorder(new LineBorder(Color.BLACK));
+ centerLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ dialog.add(centerLabel, BorderLayout.CENTER);
+ dialog.setSize(300, 200);
+
+ return dialog;
+ }
+}
diff --git a/test/jdk/java/awt/Cursor/InvalidImageCustomCursorTest/InvalidImageCustomCursorTest.java b/test/jdk/java/awt/Cursor/InvalidImageCustomCursorTest/InvalidImageCustomCursorTest.java
new file mode 100644
index 00000000000..9877df342ec
--- /dev/null
+++ b/test/jdk/java/awt/Cursor/InvalidImageCustomCursorTest/InvalidImageCustomCursorTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4212593
+ * @summary The Toolkit.createCustomCursor does not check absence of the
+ * image of cursor
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual InvalidImageCustomCursorTest
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Frame;
+import java.awt.Image;
+import java.awt.Panel;
+import java.awt.Point;
+import java.awt.Toolkit;
+
+public class InvalidImageCustomCursorTest {
+ static Cursor cursor;
+
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ Press 'Hide' button to hide (set transparent) cursor for the
+ green panel. Move the pointer over the green panel - pointer
+ should disappear. Press 'Default' button to set default cursor
+ for the green panel.
+
+ If you see any exceptions or cursor is not transparent,
+ test failed, otherwise it passed.
+ """;
+
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ Image image = tk.getImage("NON_EXISTING_FILE.gif");
+ Point p = new Point(0, 0);
+
+ cursor = tk.createCustomCursor(image, p, "Test");
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(InvalidImageCustomCursorTest::createUI)
+ .logArea(5)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static Frame createUI() {
+ Frame f = new Frame("Invalid Cursor Image Test");
+ f.setLayout(new BorderLayout());
+ f.setSize(200, 200);
+
+ Button def = new Button("Default");
+ Button hide = new Button("Hide");
+ Panel panel = new Panel();
+
+ def.addActionListener(e -> panel.setCursor(Cursor.getDefaultCursor()));
+ hide.addActionListener(e -> panel.setCursor(cursor));
+
+ panel.setBackground(Color.green);
+ panel.setSize(100, 100);
+ f.add("Center", panel);
+ f.add("North", hide);
+ f.add("South", def);
+
+ return f;
+ }
+}
diff --git a/test/jdk/java/awt/Cursor/JPanelCursorTest/JPanelCursorTest.java b/test/jdk/java/awt/Cursor/JPanelCursorTest/JPanelCursorTest.java
new file mode 100644
index 00000000000..8acd622e592
--- /dev/null
+++ b/test/jdk/java/awt/Cursor/JPanelCursorTest/JPanelCursorTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4114073
+ * @summary Test for setCursor in a JPanel when added to a JFrame's contentPane
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual JPanelCursorTest
+ */
+
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Graphics;
+
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JSplitPane;
+import javax.swing.border.BevelBorder;
+
+public class JPanelCursorTest {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ This test checks for setCursor in a JPanel when added to a
+ JFrame's contentPane.
+
+ 1. Verify that the cursor in the left side of the test window
+ is a default cursor.
+ 2. Verify that the cursor changes to the crosshair cursor when
+ pointing over the button.
+ 3. Verify that the cursor changes to the hand cursor when in
+ the right side of the splitpane (and not on the button).
+
+ If true, then pass the test. Otherwise, fail this test.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(35)
+ .testUI(JPanelCursorTest::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static JFrame createUI() {
+ JFrame frame = new JFrame();
+
+ JSplitPane j = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
+ ExtJComponent pane = new ExtJComponent();
+
+ CursorBugPanel panel = new CursorBugPanel();
+
+ j.setLeftComponent(pane);
+ j.setRightComponent(panel);
+ j.setContinuousLayout(true);
+
+ frame.getContentPane().add("Center", j);
+ pane.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+ frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+ frame.pack();
+ return frame;
+ }
+}
+
+class ExtJComponent extends JComponent {
+ public ExtJComponent() {
+ super();
+ setOpaque(true);
+ setBackground(Color.green);
+ setForeground(Color.red);
+ setBorder(new BevelBorder(BevelBorder.RAISED));
+ }
+ public void paintComponent(Graphics g) {
+ g.drawString("Default", 20, 30);
+ }
+ public Dimension getPreferredSize() {
+ return new Dimension(100, 100);
+ }
+}
+
+class CursorBugPanel extends JPanel {
+ public CursorBugPanel () {
+ // BUG: fails to set cursor for panel
+ setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+
+ // Create a button
+ JButton button = new JButton("Crosshair");
+
+ // Sets cursor for button, no problem
+ button.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
+ add(button);
+ }
+
+ public void paintComponent(Graphics g) {
+ g.drawString("Hand", 20, 60);
+ }
+}
diff --git a/test/jdk/java/awt/Cursor/NullCursorTest/NullCursorTest.java b/test/jdk/java/awt/Cursor/NullCursorTest/NullCursorTest.java
new file mode 100644
index 00000000000..c2398a80eb2
--- /dev/null
+++ b/test/jdk/java/awt/Cursor/NullCursorTest/NullCursorTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4111379
+ * @summary Test for setting cursor to null for lightweight components
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual NullCursorTest
+ */
+
+import java.awt.Button;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Cursor;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+public class NullCursorTest {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ 1. Hover over each colored area as described:
+ Green area shows a CrossCursor.
+ Red area shows a TextCursor.
+ Yellow area shows a HandCursor.
+ 2. Click once in red area, then:
+ Green area shows a HandCursor.
+ Red area shows a BusyCursor.
+ Yellow area shows a HandCursor.
+ 3. Click again in red area, then:
+ Green area shows a CrossCursor.
+ Red area shows a HandCursor.
+ Yellow area shows a HandCursor.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(NullCursorTest::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static Frame createUI() {
+ Frame f = new Frame("Null Cursor Test Frame");
+ f.setSize(200, 200);
+ final Container p = f;
+ p.setName("parent");
+ p.setLayout(null);
+
+ final Component green = p.add(new Component() {
+ public void paint(Graphics g) {
+ Rectangle r = getBounds();
+ g.setColor(Color.green);
+ g.fillRect(0, 0, r.width, r.height);
+ }
+ });
+ green.setName("green");
+ green.setBackground(Color.red);
+ green.setBounds(50, 50, 75, 75);
+ green.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
+
+ Container h = new Container() {
+ public void paint(Graphics g) {
+ Rectangle r = getBounds();
+ g.setColor(Color.yellow);
+ g.fillRect(0, 0, r.width, r.height);
+ super.paint(g);
+ }
+ };
+ h.setBounds(15, 25, 150, 150);
+ h.setName("container");
+ h.setBackground(Color.yellow);
+ h.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ final Component red = new Component() {
+ public void paint(Graphics g) {
+ Rectangle r = getBounds();
+ Color c = getBackground();
+ g.setColor(c);
+ g.fillRect(0, 0, r.width, r.height);
+ super.paint(g);
+ }
+ };
+ red.setName("red");
+ red.setBackground(Color.red);
+ red.setBounds(10, 10, 120, 120);
+ red.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
+
+ final Button b = (Button)h.add(new Button("Test"));
+ b.setBounds(10, 10, 40, 20);
+ h.add(red);
+ p.add(h);
+
+ b.addActionListener(new ActionListener() {
+ boolean f = false;
+ public void actionPerformed(ActionEvent e) {
+ if (f) {
+ b.setCursor(null);
+ } else {
+ b.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ }
+ f = !f;
+ }
+ });
+ red.addMouseListener(new MouseAdapter() {
+ boolean f = true;
+
+ public void mouseClicked(MouseEvent e) {
+ Component c = (Component)e.getSource();
+ if (f) {
+ c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+ p.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
+ green.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ f = false;
+ } else {
+ c.setCursor(null);
+ p.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+ green.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
+ f = true;
+ }
+ }
+ });
+ return f;
+ }
+}
diff --git a/test/jdk/java/awt/Cursor/SetCursorTest/SetCursorTest.java b/test/jdk/java/awt/Cursor/SetCursorTest/SetCursorTest.java
new file mode 100644
index 00000000000..87f028eb4f6
--- /dev/null
+++ b/test/jdk/java/awt/Cursor/SetCursorTest/SetCursorTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4160080
+ * @summary Test setCursor() on lightweight components when event is generated
+ * by a button
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual SetCursorTest
+ */
+
+import java.awt.Cursor;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+
+public class SetCursorTest {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ This test checks for the behavior of setCursor() when called in
+ a JFrame's JButton action event.
+
+ 1. Click the "OK" button in the test window.
+ 2. Verify that the cursor changes to the waiting cursor instead
+ of the default system cursor.
+
+ If true, then pass the test. Otherwise, fail this test.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(35)
+ .testUI(SetCursorTest::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static myFrame createUI() {
+ myFrame f = new myFrame();
+ return f;
+ }
+}
+
+class myFrame extends JFrame {
+ public myFrame() {
+ super("SetCursor With Button Test");
+ setSize(200, 200);
+
+ final JPanel p = new JPanel();
+ final JButton okButton = new JButton("OK");
+ okButton.addActionListener(e ->
+ setCursor(new Cursor(Cursor.WAIT_CURSOR)));
+
+ p.add(okButton);
+ getContentPane().add(p);
+ }
+}
diff --git a/test/jdk/java/awt/Desktop/ActionSupportTest.java b/test/jdk/java/awt/Desktop/ActionSupportTest.java
new file mode 100644
index 00000000000..e5cdec0e422
--- /dev/null
+++ b/test/jdk/java/awt/Desktop/ActionSupportTest.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6255196
+ * @key headful
+ * @summary Verifies the supported actions on different platforms.
+ * @library /test/lib
+ * @run main/othervm ActionSupportTest
+ */
+
+import java.awt.Desktop;
+import java.io.File;
+import java.net.URI;
+import javax.swing.JMenuBar;
+import jtreg.SkippedException;
+
+import static java.awt.desktop.QuitStrategy.NORMAL_EXIT;
+
+public class ActionSupportTest {
+
+ public static void main(String[] args) {
+ final File file = new File("nonExistentFile");
+ final URI uri = URI.create("nonExistentSchema:anything");
+ final StringBuilder error = new StringBuilder();
+
+ if (!Desktop.isDesktopSupported()) {
+ throw new SkippedException("Class java.awt.Desktop is not supported on " +
+ "current platform. Farther testing will not be performed");
+ }
+
+ Desktop desktop = Desktop.getDesktop();
+ for (Desktop.Action action : Desktop.Action.values()) {
+ boolean supported = desktop.isSupported(action);
+
+ try {
+ switch (action) {
+ case OPEN:
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.open(file);
+ break;
+ case EDIT:
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.edit(file);
+ break;
+ case PRINT:
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.print(file);
+ break;
+ case MAIL:
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.mail(uri);
+ break;
+ case BROWSE:
+ if (supported) {
+ continue; // prevent native message about strange schema
+ }
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.browse(uri);
+ break;
+ case APP_EVENT_FOREGROUND:
+ case APP_EVENT_HIDDEN:
+ case APP_EVENT_REOPENED:
+ case APP_EVENT_SCREEN_SLEEP:
+ case APP_EVENT_SYSTEM_SLEEP:
+ case APP_EVENT_USER_SESSION:
+ continue; // Has no effect if SystemEventListener's sub-type
+ // is unsupported on the current platform.
+ case APP_ABOUT:
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.setAboutHandler(e -> {
+ });
+ break;
+ case APP_PREFERENCES:
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.setPreferencesHandler(e -> {
+ });
+ break;
+ case APP_OPEN_FILE:
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.setOpenFileHandler(e -> {
+ });
+ break;
+ case APP_PRINT_FILE:
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.setPrintFileHandler(e -> {
+ });
+ break;
+ case APP_OPEN_URI:
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.setOpenURIHandler(e -> {
+ });
+ break;
+ case APP_QUIT_HANDLER:
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.setQuitHandler((e, response) -> {
+ });
+ break;
+ case APP_QUIT_STRATEGY:
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.setQuitStrategy(NORMAL_EXIT);
+ break;
+ case APP_SUDDEN_TERMINATION:
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.enableSuddenTermination();
+ break;
+ case APP_REQUEST_FOREGROUND:
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.requestForeground(true);
+ break;
+ case APP_HELP_VIEWER:
+ if (supported) {
+ continue; // prevent open separate window
+ }
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.openHelpViewer();
+ break;
+ case APP_MENU_BAR:
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.setDefaultMenuBar(new JMenuBar());
+ break;
+ case BROWSE_FILE_DIR:
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.browseFileDirectory(file);
+ break;
+ case MOVE_TO_TRASH:
+ // if not supported, an UnsupportedOperationException will be thrown.
+ // if supported, other exception might be thrown.
+ desktop.moveToTrash(file);
+ break;
+ }
+ // no exception has been thrown.
+ if (!supported) {
+ error.append("Action " + action.name() + " is an " +
+ "unsupported operation, but no exception has been thrown\n");
+ }
+ } catch (UnsupportedOperationException uoe) {
+ if (!supported) {
+ System.out.println("Action " + action.name() + "is not supported.");
+ } else {
+ error.append("Action " + action.name() + " is a " +
+ "supported operation, " +
+ "but UnsupportedOperationException has been thrown\n");
+ }
+ } catch (Exception e) {
+ if (supported) {
+ System.out.println("Action " + action.name() + "supported.");
+ } else {
+ error.append("Action " + action.name() + " is an " +
+ "unsupported operation, but " +
+ "UnsupportedOperationException has not been thrown\n");
+ }
+ }
+ }
+
+ if (!error.isEmpty()) {
+ System.err.println(error);
+ throw new RuntimeException("One or more tests failed. " +
+ "Look at the error output for details");
+ }
+ System.out.println("Test completed");
+ }
+}
diff --git a/test/jdk/java/awt/Desktop/BrowseTest.java b/test/jdk/java/awt/Desktop/BrowseTest.java
new file mode 100644
index 00000000000..1bdccace3fc
--- /dev/null
+++ b/test/jdk/java/awt/Desktop/BrowseTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6255196
+ * @summary Verifies the function of method browse(java.net.URI uri).
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual BrowseTest
+ */
+
+import java.awt.Desktop;
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import javax.swing.JPanel;
+
+public class BrowseTest extends JPanel {
+ static final String INSTRUCTIONS = """
+ This test could launch default file manager to open user's home
+ directory, and default web browser to show the URL of java vendor.
+ After test execution close the native file manager and web browser
+ windows if they were launched by test.
+ Also check output for any unexpected EXCEPTIONS,
+ if you see any failure messages press Fail otherwise press Pass.
+ """;
+
+ public BrowseTest() {
+ if (!Desktop.isDesktopSupported()) {
+ PassFailJFrame.log("Class java.awt.Desktop is not supported on " +
+ "current platform. Farther testing will not be performed");
+ PassFailJFrame.forcePass();
+ }
+
+ Desktop desktop = Desktop.getDesktop();
+
+ URI dirURI = new File(System.getProperty("user.home")).toURI();
+ URI webURI = URI.create(System.getProperty("java.vendor.url", "http://www.java.com"));
+ boolean failed = false;
+ try {
+ PassFailJFrame.log("Try to browse " + dirURI + " ...");
+ desktop.browse(dirURI);
+ PassFailJFrame.log("Succeed.\n");
+ } catch (Exception e) {
+ PassFailJFrame.log("EXCEPTION: " + e.getMessage());
+ }
+
+ try {
+ PassFailJFrame.log("Try to browse " + webURI + " ...");
+ desktop.browse(webURI);
+ PassFailJFrame.log("Succeed.\n");
+ } catch (Exception e) {
+ PassFailJFrame.log("EXCEPTION: " + e.getMessage());
+ }
+ }
+
+ public static void main(String[] args) throws InterruptedException,
+ InvocationTargetException {
+ PassFailJFrame.builder()
+ .title("Browser Test")
+ .splitUI(BrowseTest::new)
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 1)
+ .columns(40)
+ .logArea()
+ .build()
+ .awaitAndCheck();
+ }
+}
diff --git a/test/jdk/java/awt/Desktop/DesktopSupportTest.java b/test/jdk/java/awt/Desktop/DesktopSupportTest.java
new file mode 100644
index 00000000000..ec8b82ba5ef
--- /dev/null
+++ b/test/jdk/java/awt/Desktop/DesktopSupportTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6255196
+ * @key headful
+ * @summary Verifies if class Desktop is supported on current platform.
+ * @run main DesktopSupportTest
+ */
+
+import java.awt.Desktop;
+
+public class DesktopSupportTest {
+ public static void main(String[] args) {
+ boolean supported = Desktop.isDesktopSupported();
+ try {
+ Desktop desktop = Desktop.getDesktop();
+ if (!supported) {
+ throw new RuntimeException("UnsupportedOperationException " +
+ "should be thrown, as this class is not supported " +
+ "on current platform.");
+ }
+ } catch (UnsupportedOperationException uoe) {
+ if (supported) {
+ throw new RuntimeException("UnsupportedOperationException " +
+ "should NOT be thrown, as this class is supported " +
+ "on current platform.");
+ }
+ } catch (Exception e) {
+ if (!supported) {
+ throw new RuntimeException("UnsupportedOperationException " +
+ "should be thrown, as this class is not supported " +
+ "on current platform. But " + e.getClass().getName() +
+ " has been thrown instead.");
+ }
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Desktop/MailTest.java b/test/jdk/java/awt/Desktop/MailTest.java
new file mode 100644
index 00000000000..15e5c0769a0
--- /dev/null
+++ b/test/jdk/java/awt/Desktop/MailTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6255196
+ * @summary Verifies the function of methods mail() and mail(java.net.URI uri).
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual MailTest
+ */
+
+import java.awt.Desktop;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import javax.swing.JPanel;
+
+public class MailTest extends JPanel {
+
+ static final String INSTRUCTIONS = """
+ This test could launch the mail client to compose mail
+ with and without filling the message fields.
+ After test execution close the mail composing windows if they
+ were launched by test.
+ If you see any unexpected EXCEPTION messages in the output
+ press Fail. Otherwise press Pass.
+ """;
+
+ private MailTest() {
+ if (!Desktop.isDesktopSupported()) {
+ PassFailJFrame.log("Class java.awt.Desktop is not supported on " +
+ "current platform. Farther testing will not be performed");
+ PassFailJFrame.forcePass();
+ }
+
+ Desktop desktop = Desktop.getDesktop();
+ if (!desktop.isSupported(Desktop.Action.MAIL)) {
+ PassFailJFrame.log("Action.MAIL is not supported.");
+ PassFailJFrame.forcePass();
+ }
+
+ /*
+ * Part 1: launch the mail composing window without a mailto URI.
+ */
+ try {
+ desktop.mail();
+ } catch (IOException e) {
+ PassFailJFrame.log("EXCEPTION: " + e.getMessage());
+ }
+
+ /*
+ * Part 2: launch the mail composing window with a mailto URI.
+ */
+ URI testURI = null;
+ try {
+ testURI = new URI("mailto", "foo@bar.com?subject=test subject" +
+ "&cc=foocc@bar.com&body=test body", null);
+ desktop.mail(testURI);
+ } catch (IOException e) {
+ PassFailJFrame.log("EXCEPTION: " + e.getMessage());
+ } catch (java.net.URISyntaxException use) {
+ // Should not reach here.
+ PassFailJFrame.log("EXCEPTION: " + use.getMessage());
+ }
+
+ /*
+ * Part 3: try to launch the mail composing window with a URI with a
+ * scheme which is not "mailto":
+ * http://java.net.
+ * An IOException should be thrown in this case.
+ */
+ try {
+ testURI = URI.create("http://java.com");
+ PassFailJFrame.log("Try to mail: " + testURI);
+ desktop.mail(testURI);
+ } catch (IllegalArgumentException e) {
+ PassFailJFrame.log("Caught expected IllegalArgumentException");
+ } catch (IOException ioe) {
+ PassFailJFrame.log("EXCEPTION: " + ioe.getMessage());
+ }
+ }
+
+ public static void main(String[] args) throws InterruptedException,
+ InvocationTargetException {
+ PassFailJFrame.builder()
+ .title("Mail Test")
+ .splitUI(MailTest::new)
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 1)
+ .columns(40)
+ .logArea()
+ .build()
+ .awaitAndCheck();
+ }
+}
diff --git a/test/jdk/java/awt/Desktop/OpenTest.java b/test/jdk/java/awt/Desktop/OpenTest.java
new file mode 100644
index 00000000000..1ed29067d50
--- /dev/null
+++ b/test/jdk/java/awt/Desktop/OpenTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6255196
+ * @summary Verifies the function of method open(java.io.File file).
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual/othervm OpenTest
+ */
+
+import java.awt.Desktop;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import javax.swing.JPanel;
+
+public class OpenTest extends JPanel {
+
+ static final String INSTRUCTIONS = """
+ This test could open the user's home directory and a .txt file.
+ After test execution, close the native application windows that
+ are used to open the directory and .txt file if they were launched
+ by the test.
+ If you see any unexpected EXCEPTION messages in the output press Fail.
+ Otherwise press Pass.
+ """;
+
+ public OpenTest() {
+ if (!Desktop.isDesktopSupported()) {
+ PassFailJFrame.log("Class java.awt.Desktop is not supported on " +
+ "current platform. Further testing will not be performed");
+ PassFailJFrame.forcePass();
+ }
+
+ Desktop desktop = Desktop.getDesktop();
+
+ /*
+ * Part 1: open a directory, which should launch the system default
+ * file explorer.
+ *
+ * On Windows platforms, the default file explorer is explorer;
+ * on UNIX platforms with Gnome installed and running, the default
+ * file explorer is Nautilus.
+ */
+ File userHome = new File(System.getProperty("user.home"));
+
+ try {
+ PassFailJFrame.log("Try to open " + userHome);
+ desktop.open(userHome);
+ PassFailJFrame.log("Succeed.");
+ } catch (IOException e) {
+ PassFailJFrame.log("EXCEPTION: " + e.getMessage());
+ }
+
+ /*
+ * Part 2: open a normal .txt file, which should launch the registered
+ * application for .txt files.
+ */
+ // Create a temp .txt file for test.
+ File testFile = null;
+ try {
+ PassFailJFrame.log("Creating temporary file");
+ testFile = File.createTempFile("JDIC-test", ".txt",
+ new File(System.getProperty("java.io.tmpdir")));
+ testFile.deleteOnExit();
+ } catch (java.io.IOException ioe) {
+ PassFailJFrame.log("EXCEPTION: " + ioe.getMessage());
+ PassFailJFrame.log("Failed to create test file");
+ }
+
+ try {
+ PassFailJFrame.log("Try to open " + testFile);
+ desktop.open(testFile);
+ PassFailJFrame.log("Succeed.");
+ } catch (IOException e) {
+ PassFailJFrame.log("EXCEPTION: " + e.getMessage());
+ }
+ }
+
+ public static void main(String[] args) throws InterruptedException,
+ InvocationTargetException {
+ PassFailJFrame.builder()
+ .title("Mail Test")
+ .splitUI(OpenTest::new)
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 1)
+ .columns(40)
+ .logArea()
+ .build()
+ .awaitAndCheck();
+ }
+}
diff --git a/test/jdk/java/awt/FileDialog/DoubleActionCloseX.java b/test/jdk/java/awt/FileDialog/DoubleActionCloseX.java
new file mode 100644
index 00000000000..5d3feaa42ed
--- /dev/null
+++ b/test/jdk/java/awt/FileDialog/DoubleActionCloseX.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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 java.awt.Button;
+import java.awt.FileDialog;
+import java.awt.Frame;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+/*
+ * @test
+ * @bug 6227750
+ * @summary Tests that FileDialog can be closed by clicking the 'close' (X) button
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual DoubleActionCloseX
+ */
+
+public class DoubleActionCloseX {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ NOTE: On Linux and Mac, there is no 'close'(X) button
+ when file dialog is visible, press Pass.
+
+ Click the 'Open File Dialog' button to open FileDialog.
+ A file dialog will appear on the screen.
+ Click on the 'close'(X) button.
+ The dialog should be closed.
+ If not, the test failed, press Fail otherwise press Pass.
+ """;
+
+ PassFailJFrame.builder()
+ .title("DoubleActionCloseX Instruction")
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .testUI(DoubleActionCloseX::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+ public static Frame createUI() {
+ Frame f = new Frame("DoubleActionCloseX Test");
+ Button b = new Button("Open File Dialog");
+ FileDialog fd = new FileDialog(f);
+ b.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ fd.setVisible(true);
+ }
+ });
+ f.add(b);
+ f.setSize(300, 200);
+ return f;
+ }
+}
diff --git a/test/jdk/java/awt/FileDialog/DoubleActionESC.java b/test/jdk/java/awt/FileDialog/DoubleActionESC.java
new file mode 100644
index 00000000000..748c3aeb5e4
--- /dev/null
+++ b/test/jdk/java/awt/FileDialog/DoubleActionESC.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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 java.awt.Button;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.FileDialog;
+import java.awt.Frame;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.util.concurrent.CountDownLatch;
+
+/*
+ * @test
+ * @bug 5097243
+ * @summary Tests that FileDialog can be closed by ESC any time
+ * @key headful
+ * @run main DoubleActionESC
+ */
+
+public class DoubleActionESC {
+ private static Frame f;
+ private static Button showBtn;
+ private static FileDialog fd;
+ private static Robot robot;
+ private static volatile Point p;
+ private static volatile Dimension d;
+ private static volatile CountDownLatch latch;
+ private static final int REPEAT_COUNT = 2;
+
+ public static void main(String[] args) throws Exception {
+ latch = new CountDownLatch(1);
+
+ robot = new Robot();
+ robot.setAutoDelay(100);
+ try {
+ EventQueue.invokeAndWait(() -> {
+ createAndShowUI();
+ });
+
+ robot.delay(1000);
+ EventQueue.invokeAndWait(() -> {
+ p = showBtn.getLocationOnScreen();
+ d = showBtn.getSize();
+ });
+
+ for (int i = 0; i < REPEAT_COUNT; ++i) {
+ Thread thread = new Thread(() -> {
+ robot.mouseMove(p.x + d.width / 2, p.y + d.height / 2);
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+ });
+ thread.start();
+ robot.delay(3000);
+
+ Thread thread1 = new Thread(() -> {
+ robot.keyPress(KeyEvent.VK_ESCAPE);
+ robot.keyRelease(KeyEvent.VK_ESCAPE);
+ robot.waitForIdle();
+ });
+ thread1.start();
+ robot.delay(3000);
+ }
+
+ latch.await();
+ if (fd.isVisible()) {
+ throw new RuntimeException("File Dialog is not closed");
+ }
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (f != null) {
+ f.dispose();
+ }
+ });
+ }
+ }
+
+ public static void createAndShowUI() {
+ f = new Frame("DoubleActionESC Test");
+ showBtn = new Button("Show File Dialog");
+ fd = new FileDialog(f);
+ showBtn.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource() == showBtn) {
+ fd.setSize(200, 200);
+ fd.setLocation(200, 200);
+ fd.setVisible(true);
+ latch.countDown();
+ }
+ }
+ });
+ f.add(showBtn);
+ f.setSize(300, 200);
+ f.setLocationRelativeTo(null);
+ f.setVisible(true);
+ }
+}
diff --git a/test/jdk/java/awt/FileDialog/TestFileDialogDupJNIRef.java b/test/jdk/java/awt/FileDialog/TestFileDialogDupJNIRef.java
new file mode 100644
index 00000000000..56b6c492144
--- /dev/null
+++ b/test/jdk/java/awt/FileDialog/TestFileDialogDupJNIRef.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. 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 java.awt.Button;
+import java.awt.Dialog;
+import java.awt.FileDialog;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+/*
+ * @test
+ * @bug 4906972
+ * @summary Tests using of JNI reference to peer object.
+ * @requires (os.family == "windows")
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual TestFileDialogDupJNIRef
+ */
+
+public class TestFileDialogDupJNIRef {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ This is a crash test.
+ After test started you will see 'Test Frame' with one button.
+ 1. Click the button to open FileDialog.
+ 2. Go to the dialog and choose any directory with some files in it..
+ 3. Click on any file to highlight it.
+ 4. Click on the file again to rename.
+ 5. Leave the file in edit mode and click Open button
+
+ If there was no crash the test passed, Press Pass.
+ """;
+
+ PassFailJFrame.builder()
+ .title("TestFileDialogDupJNIRef Instruction")
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .testUI(TestFileDialogDupJNIRef::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static Frame createUI() {
+ Frame frame = new Frame("TestFileDialogDupJNIRef Test Frame");
+ Button open = new Button("Open File Dialog");
+
+ open.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ FileDialog fd = new FileDialog(frame);
+ fd.setVisible(true);
+ }
+ });
+
+ frame.setLayout(new FlowLayout());
+ frame.add(open);
+ frame.setSize(250, 70);
+ return frame;
+ }
+}
diff --git a/test/jdk/java/awt/Frame/AddRemoveMenuBarTest_5.java b/test/jdk/java/awt/Frame/AddRemoveMenuBarTest_5.java
new file mode 100644
index 00000000000..f5f1018c262
--- /dev/null
+++ b/test/jdk/java/awt/Frame/AddRemoveMenuBarTest_5.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1998, 2024, Oracle and/or its affiliates. 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 java.awt.Button;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.Robot;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+/*
+ * @test
+ * @key headful
+ * @bug 4159883
+ * @summary Adding/Removing a menu causes frame to unexpected small size
+ * @requires (os.family == "linux" | os.family == "windows")
+ */
+
+public class AddRemoveMenuBarTest_5 {
+
+ static Frame frame;
+ static MenuBar menu;
+ static Button btnAdd, btnRemove;
+ static Dimension oldSize;
+
+ public static void main(String[] args) throws Exception {
+ Robot robot = new Robot();
+ try {
+ EventQueue.invokeAndWait(AddRemoveMenuBarTest_5::initAndShowGui);
+ robot.waitForIdle();
+ robot.delay(500);
+
+ EventQueue.invokeAndWait(() -> {
+ oldSize = frame.getSize();
+ changeMenubar(true);
+ });
+ robot.waitForIdle();
+ robot.delay(500);
+
+ EventQueue.invokeAndWait(() -> {
+ checkSize();
+ changeMenubar(false);
+ });
+ robot.waitForIdle();
+ robot.delay(500);
+
+ EventQueue.invokeAndWait(AddRemoveMenuBarTest_5::checkSize);
+ } finally {
+ EventQueue.invokeAndWait(frame::dispose);
+ }
+ }
+
+ public static void initAndShowGui() {
+ frame = new Frame();
+ frame.setLocationRelativeTo(null);
+ frame.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowOpened(WindowEvent e) {
+ System.out.println("Frame size:" + frame.getSize().toString());
+ System.out.println("Button size:" + btnAdd.getSize().toString());
+ }
+ });
+ frame.add("West", btnAdd = new Button("TRY:ADD"));
+ frame.add("East", btnRemove = new Button("TRY:REMOVE"));
+
+
+ btnAdd.addActionListener((e) -> changeMenubar(true));
+ btnRemove.addActionListener((e) -> changeMenubar(false));
+ frame.setSize(500, 100);
+ frame.setVisible(true);
+ }
+
+ private static void changeMenubar(boolean enable) {
+ if (enable) {
+ menu = new MenuBar();
+ menu.add(new Menu("BAAAAAAAAAAAAAAA"));
+ menu.add(new Menu("BZZZZZZZZZZZZZZZ"));
+ menu.add(new Menu("BXXXXXXXXXXXXXXX"));
+ } else {
+ menu = null;
+ }
+ frame.setMenuBar(menu);
+ frame.invalidate();
+ frame.validate();
+
+ System.out.println("Frame size:" + frame.getSize().toString());
+ System.out.println("Button size:" + btnAdd.getSize().toString());
+ }
+
+ private static void checkSize() {
+ Dimension newSize = frame.getSize();
+ if (!oldSize.equals(newSize)) {
+ throw new RuntimeException("Frame size changed: old %s new %s"
+ .formatted(oldSize, newSize));
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Frame/FocusTest.java b/test/jdk/java/awt/Frame/FocusTest.java
new file mode 100644
index 00000000000..14d194789fe
--- /dev/null
+++ b/test/jdk/java/awt/Frame/FocusTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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 java.awt.Canvas;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.GridLayout;
+import java.awt.Panel;
+import java.awt.Window;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+/*
+ * @test
+ * @bug 4140293
+ * @summary Tests that focus is returned to the correct Component when a Frame
+ * is reactivated.
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual FocusTest
+ */
+
+public class FocusTest {
+ private static final String INSTRUCTIONS = """
+ Click on the bottom rectangle. Move the mouse slightly.
+ A focus rectangle should appear around the bottom rectangle.
+
+ Now, deactivate the window and then reactivate it.
+ (You would click on the caption bar of another window,
+ and then on the caption bar of the FocusTest Frame.)
+
+ If the focus rectangle appears again, the test passes.
+ If it does not appear, or appears around the top rectangle,
+ the test fails.
+ """;
+
+ public static void main(String[] args) throws Exception {
+ PassFailJFrame.builder()
+ .title("FocusTest Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(45)
+ .logArea(6)
+ .testUI(FocusTest::createAndShowUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Window createAndShowUI() {
+ Frame frame = new Frame("FocusTest");
+
+ frame.add(new FocusTestPanel());
+ frame.setSize(400, 400);
+
+ frame.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ frame.dispose();
+ }
+ });
+
+ frame.validate();
+ return frame;
+ }
+
+ private static class FocusTestPanel extends Panel {
+ PassiveClient pc1 = new PassiveClient("pc1");
+ PassiveClient pc2 = new PassiveClient("pc2");
+
+ public FocusTestPanel() {
+ super();
+ setLayout(new GridLayout(2, 1, 10, 10));
+ add(pc1);
+ add(pc2);
+ }
+ }
+
+ private static class PassiveClient extends Canvas implements FocusListener {
+ boolean haveFocus = false;
+ final String name;
+
+ PassiveClient(String name) {
+ super();
+ this.name = name;
+ setSize(400, 100);
+ setBackground(Color.cyan);
+ setVisible(true);
+ setEnabled(true);
+ addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ requestFocus();
+ }
+ });
+ addFocusListener(this);
+ }
+
+ public void paint(Graphics g) {
+ g.setColor(getBackground());
+ Dimension size = getSize();
+ g.fillRect(0, 0, size.width, size.height);
+ if (haveFocus) {
+ g.setColor(Color.black);
+ g.drawRect(0, 0, size.width - 1, size.height - 1);
+ g.drawRect(1, 1, size.width - 3, size.height - 3);
+ }
+ g.setColor(getForeground());
+ }
+
+ public void focusGained(FocusEvent event) {
+ haveFocus = true;
+ paint(getGraphics());
+ PassFailJFrame.log("<<<< %s Got focus!! %s>>>>".formatted(this, event));
+ }
+
+ public void focusLost(FocusEvent event) {
+ haveFocus = false;
+ paint(getGraphics());
+ PassFailJFrame.log("<<<< %s Lost focus!! %s>>>>".formatted(this, event));
+ }
+
+ @Override
+ public String toString() {
+ return "PassiveClient " + name;
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Frame/FrameResizableTest.java b/test/jdk/java/awt/Frame/FrameResizableTest.java
new file mode 100644
index 00000000000..4734ce71670
--- /dev/null
+++ b/test/jdk/java/awt/Frame/FrameResizableTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1998, 2024, Oracle and/or its affiliates. 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 java.awt.Button;
+import java.awt.Frame;
+import java.awt.Label;
+import java.awt.Panel;
+import java.awt.event.ActionListener;
+
+/*
+ * @test
+ * @bug 1231233
+ * @summary Tests whether the resizable property of a Frame is
+ * respected after it is set.
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual FrameResizableTest
+ */
+
+public class FrameResizableTest {
+ private static final String INSTRUCTIONS = """
+ There is a frame with two buttons and a label. The label
+ reads 'true' or 'false' to indicate whether the frame can be
+ resized or not.
+
+ When the first button, 'Set Resizable', is
+ clicked, you should be able to resize the frame.
+ When the second button, 'UnSet Resizable', is clicked, you should
+ not be able to resize the frame.
+
+ A frame is resized in a way which depends upon the window manager (WM) running.
+ You may resize the frame by dragging the corner resize handles or the borders,
+ or you may use the title bar's resize menu items and buttons.
+
+ Upon test completion, click Pass or Fail appropriately.
+ """;
+
+ public static void main(String[] args) throws Exception {
+ PassFailJFrame.builder()
+ .title("FrameResizableTest Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(50)
+ .testUI(FrameResizable::new)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static class FrameResizable extends Frame {
+ Label label;
+ Button buttonResizable;
+ Button buttonNotResizable;
+
+ public FrameResizable() {
+ super("FrameResizable");
+ setResizable(false);
+ Panel panel = new Panel();
+
+ add("North", panel);
+ ActionListener actionListener = (e) -> {
+ if (e.getSource() == buttonResizable) {
+ setResizable(true);
+ } else if (e.getSource() == buttonNotResizable) {
+ setResizable(false);
+ }
+ label.setText("Resizable: " + isResizable());
+ };
+
+ panel.add(buttonResizable = new Button("Set Resizable"));
+ panel.add(buttonNotResizable = new Button("UnSet Resizable"));
+ panel.add(label = new Label("Resizable: " + isResizable()));
+ buttonResizable.addActionListener(actionListener);
+ buttonNotResizable.addActionListener(actionListener);
+
+ setSize(400, 200);
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Frame/I18NTitle.java b/test/jdk/java/awt/Frame/I18NTitle.java
new file mode 100644
index 00000000000..7127fc3dfbf
--- /dev/null
+++ b/test/jdk/java/awt/Frame/I18NTitle.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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 java.awt.BorderLayout;
+import java.awt.Frame;
+import java.awt.Label;
+import java.awt.Window;
+
+/*
+ * @test
+ * @bug 6269884 4929291
+ * @summary Tests that title which contains mix of non-English characters is displayed correctly
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual I18NTitle
+ */
+
+public class I18NTitle {
+ private static final String INSTRUCTIONS = """
+ You will see a frame with some title (S. Chinese, Cyrillic and German).
+ Please check if non-English characters are visible and compare
+ the visible title with the same string shown in the label
+ (it should not look worse than the label).
+ """;
+
+ public static void main(String[] args) throws Exception {
+ PassFailJFrame.builder()
+ .title("I18NTitle Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(50)
+ .testUI(I18NTitle::createAndShowGUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Window createAndShowGUI() {
+ String s = "\u4e2d\u6587\u6d4b\u8bd5 \u0420\u0443\u0441\u0441\u043a\u0438\u0439 Zur\u00FCck";
+ Frame frame = new Frame(s);
+ frame.setLayout(new BorderLayout());
+ Label l = new Label(s);
+ frame.add(l);
+ frame.setSize(400, 100);
+ return frame;
+ }
+}
diff --git a/test/jdk/java/awt/Frame/InitialIconifiedTest.java b/test/jdk/java/awt/Frame/InitialIconifiedTest.java
index f3f43929e7b..4a8d9595665 100644
--- a/test/jdk/java/awt/Frame/InitialIconifiedTest.java
+++ b/test/jdk/java/awt/Frame/InitialIconifiedTest.java
@@ -50,36 +50,75 @@ public class InitialIconifiedTest {
private static Robot robot;
+ private static final StringBuilder FAILURES = new StringBuilder();
+
public static void main(String[] args) throws Exception {
robot = new Robot();
-
try {
- EventQueue.invokeAndWait(InitialIconifiedTest::initAndShowGui);
+ EventQueue.invokeAndWait(InitialIconifiedTest::initAndShowBackground);
robot.waitForIdle();
robot.delay(500);
- test();
+
+ test(false);
+ test(true);
} finally {
EventQueue.invokeAndWait(() -> {
backgroundFrame.dispose();
testedFrame.dispose();
});
}
+
+ if (!FAILURES.isEmpty()) {
+ throw new RuntimeException(FAILURES.toString());
+ }
+ }
+
+ private static void test(boolean isUndecorated) throws Exception {
+ String prefix = isUndecorated ? "undecorated" : "decorated";
+
+ EventQueue.invokeAndWait(() -> initAndShowTestedFrame(isUndecorated));
+ // On macos, we can observe the animation of the window from the initial
+ // NORMAL state to the ICONIFIED state,
+ // even if the window was created in the ICONIFIED state.
+ // The following delay is commented out to capture this animation
+ // robot.waitForIdle();
+ // robot.delay(500);
+ if (!testIfIconified(prefix + "_no_extra_delay")) {
+ FAILURES.append("Case %s frame with no extra delay failed\n"
+ .formatted(isUndecorated ? "undecorated" : "decorated"));
+ }
+
+ EventQueue.invokeAndWait(() -> initAndShowTestedFrame(isUndecorated));
+ robot.waitForIdle();
+ robot.delay(500);
+ if (!testIfIconified(prefix + "_with_extra_delay")) {
+ FAILURES.append("Case %s frame with extra delay failed\n"
+ .formatted(isUndecorated ? "undecorated" : "decorated"));
+ }
}
- private static void initAndShowGui() {
+ private static void initAndShowBackground() {
backgroundFrame = new Frame("DisposeTest background");
backgroundFrame.setUndecorated(true);
backgroundFrame.setBackground(Color.RED);
backgroundFrame.setBounds(backgroundFrameBounds);
backgroundFrame.setVisible(true);
+ }
+ private static void initAndShowTestedFrame(boolean isUndecorated) {
+ if (testedFrame != null) {
+ testedFrame.dispose();
+ }
testedFrame = new Frame("Should have started ICONIC");
+ if (isUndecorated) {
+ testedFrame.setUndecorated(true);
+ }
testedFrame.setExtendedState(Frame.ICONIFIED);
testedFrame.setBounds(testedFrameBounds);
testedFrame.setVisible(true);
}
- private static void test() {
+ private static boolean testIfIconified(String prefix) {
BufferedImage bi = robot.createScreenCapture(backgroundFrameBounds);
int redPix = Color.RED.getRGB();
@@ -88,11 +127,12 @@ private static void test() {
if (bi.getRGB(x, y) != redPix) {
try {
ImageIO.write(bi, "png",
- new File("failure.png"));
+ new File(prefix + "_failure.png"));
} catch (IOException ignored) {}
- throw new RuntimeException("Test failed");
+ return false;
}
}
}
+ return true;
}
}
diff --git a/test/jdk/java/awt/Frame/MenuBarOffsetTest.java b/test/jdk/java/awt/Frame/MenuBarOffsetTest.java
new file mode 100644
index 00000000000..65a4a8ef4bd
--- /dev/null
+++ b/test/jdk/java/awt/Frame/MenuBarOffsetTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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 java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.Menu;
+import java.awt.MenuBar;
+
+/*
+ * @test
+ * @bug 4180577
+ * @summary offset problems with menus in frames: (2 * 1) should be (2 * menuBarBorderSize)
+ * @requires (os.family == "linux" | os.family == "windows")
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual MenuBarOffsetTest
+*/
+
+public class MenuBarOffsetTest {
+ private static final String INSTRUCTIONS = """
+ If a menubar containing a menubar item labeled Test appears.
+ in a frame, and fits within the frame, press Pass, else press Fail.
+ """;
+
+ public static void main(String[] args) throws Exception {
+ PassFailJFrame.builder()
+ .title("MenuBarOffsetTest Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(45)
+ .testUI(FrameTest::new)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static class FrameTest extends Frame {
+ public FrameTest() {
+ super("MenuBarOffsetTest FrameTest");
+ MenuBar m = new MenuBar();
+ setMenuBar(m);
+ Menu test = m.add(new Menu("Test"));
+ test.add("1");
+ test.add("2");
+ setSize(100, 100);
+ }
+
+ public void paint(Graphics g) {
+ setForeground(Color.red);
+ Insets i = getInsets();
+ Dimension d = getSize();
+ System.err.println(getBounds());
+ System.err.println("" + i);
+
+ g.drawRect(i.left, i.top,
+ d.width - i.left - i.right - 1,
+ d.height - i.top - i.bottom - 1);
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Frame/MinimumSizeTest.java b/test/jdk/java/awt/Frame/MinimumSizeTest.java
new file mode 100644
index 00000000000..cfff77be5f9
--- /dev/null
+++ b/test/jdk/java/awt/Frame/MinimumSizeTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1998, 2024, Oracle and/or its affiliates. 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.imageio.ImageIO;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.Toolkit;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+/*
+ * @test
+ * @key headful
+ * @bug 1256759
+ * @summary Checks that Frames with a very small size don't cause Motif
+ * to generate VendorShells which consume the entire desktop.
+ */
+
+public class MinimumSizeTest {
+
+ private static final Color BG_COLOR = Color.RED;
+ private static Frame backgroundFrame;
+ private static Frame testedFrame;
+
+ private static Robot robot;
+ private static final Point location = new Point(200, 200);
+ private static final Point[] testPointLocations = {
+ new Point(100, 200),
+ new Point(200, 100),
+ new Point(450, 210),
+ new Point(210, 350),
+ };
+
+ public static void main(String[] args) throws Exception {
+ robot = new Robot();
+
+ try {
+ EventQueue.invokeAndWait(MinimumSizeTest::initAndShowGui);
+ robot.waitForIdle();
+ robot.delay(500);
+ test();
+ System.out.println("Test passed.");
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ backgroundFrame.dispose();
+ testedFrame.dispose();
+ });
+ }
+ }
+
+ private static void test() {
+ for (Point testLocation : testPointLocations) {
+ Color pixelColor = robot.getPixelColor(testLocation.x, testLocation.y);
+
+ if (!pixelColor.equals(BG_COLOR)) {
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ BufferedImage screenCapture = robot.createScreenCapture(new Rectangle(screenSize));
+ try {
+ ImageIO.write(screenCapture, "png", new File("failure.png"));
+ } catch (IOException ignored) {}
+ throw new RuntimeException("Pixel color does not match expected color %s at %s"
+ .formatted(pixelColor, testLocation));
+ }
+ }
+ }
+
+ private static void initAndShowGui() {
+ backgroundFrame = new Frame("MinimumSizeTest background");
+ backgroundFrame.setUndecorated(true);
+ backgroundFrame.setBackground(BG_COLOR);
+ backgroundFrame.setBounds(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
+ backgroundFrame.setVisible(true);
+
+ testedFrame = new MinimumSizeTestFrame();
+ testedFrame.setVisible(true);
+ }
+
+ private static class MinimumSizeTestFrame extends Frame {
+ public MinimumSizeTestFrame() {
+ super("MinimumSizeTest");
+ setVisible(true);
+ setBackground(Color.BLUE);
+ setSize(0, 0);
+ setLocation(location);
+ }
+ }
+}
+
diff --git a/test/jdk/java/awt/GradientPaint/JerkyGradient.java b/test/jdk/java/awt/GradientPaint/JerkyGradient.java
new file mode 100644
index 00000000000..dc33b9c185a
--- /dev/null
+++ b/test/jdk/java/awt/GradientPaint/JerkyGradient.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4221201
+ * @summary Test where the gradient drawn should remain in sync with the
+ * rotating rectangle.
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual JerkyGradient
+ */
+
+import java.awt.Color;
+import java.awt.Frame;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Panel;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+
+public class JerkyGradient extends Panel implements Runnable {
+ protected static Shape mShape;
+ protected static Paint mPaint;
+ protected static double mTheta;
+ static Thread animatorThread;
+ static BufferedImage mImg;
+
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ Watch at least one full rotation of the rectangle. Check that
+ the gradient drawn remains in sync with the rotating
+ rectangle. If so, pass this test. Otherwise, fail this test.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(35)
+ .testUI(JerkyGradient::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static Frame createUI() {
+ Frame f = new Frame("Rotating Gradient Test");
+ JerkyGradient jg = new JerkyGradient();
+ f.add(jg);
+ f.setSize(200, 200);
+ return f;
+ }
+
+ public JerkyGradient() {
+ mShape = new Rectangle2D.Double(60, 50, 80, 100);
+ mPaint = new GradientPaint(0, 0, Color.red,
+ 25, 25, Color.yellow,
+ true);
+ mImg = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB);
+
+ animatorThread = new Thread(this);
+ animatorThread.setPriority(Thread.MIN_PRIORITY);
+ animatorThread.start();
+ }
+
+ public synchronized void run() {
+ Thread me = Thread.currentThread();
+ double increment = Math.PI / 36;
+ double twoPI = Math.PI * 2;
+
+ while (animatorThread == me) {
+ mTheta = (mTheta + increment) % twoPI;
+ repaint();
+ try {
+ wait(50);
+ } catch (InterruptedException ie) {
+ break;
+ }
+ }
+ }
+
+ public void update(Graphics g) {
+ Graphics2D g2 = mImg.createGraphics();
+ g2.setColor(getBackground());
+ g2.fillRect(0, 0, 200, 200);
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.rotate(mTheta, 100, 100);
+ g2.setPaint(Color.black);
+ g2.drawLine(100, 30, 100, 55);
+ g2.setPaint(mPaint);
+ g2.fill(mShape);
+ g2.setPaint(Color.black);
+ g2.draw(mShape);
+ paint(g);
+ g2.dispose();
+ }
+
+ public void paint(Graphics g) {
+ g.drawImage(mImg, 0, 0, null);
+ }
+}
diff --git a/test/jdk/java/awt/GradientPaint/ShearTest.java b/test/jdk/java/awt/GradientPaint/ShearTest.java
new file mode 100644
index 00000000000..95a4e4a6dcd
--- /dev/null
+++ b/test/jdk/java/awt/GradientPaint/ShearTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4171820
+ * @summary Checks that GradientPaint responds to shearing transforms correctly
+ * The gradients drawn should be parallel to the sides of the
+ * indicated anchor rectangle.
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual ShearTest
+ */
+
+import java.awt.Canvas;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GridLayout;
+import java.awt.Panel;
+import java.awt.Rectangle;
+import java.awt.geom.AffineTransform;
+
+public class ShearTest {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ This test displays 2 rows each containing 4 gradient fills. Each
+ gradient fill is labeled depending on whether the line or lines
+ of the gradient should be truly vertical, truly horizontal, or
+ some slanted diagonal direction. The test passes if the direction
+ of each gradient matches its label.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(35)
+ .testUI(ShearTest::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static Frame createUI() {
+ Frame f = new Frame("Shear Gradient Test");
+ f.setLayout(new GridLayout(0, 1));
+ f.add(getPanelSet(false), "North");
+ f.add(getPanelSet(true), "Center");
+ f.setSize(500, 300);
+ return f;
+ }
+
+ public static Panel getPanelSet(boolean horizontal) {
+ String direven = horizontal ? "Slanted" : "Vertical";
+ String dirodd = horizontal ? "Horizontal" : "Slanted";
+
+ Panel p = new Panel();
+ p.setLayout(new GridLayout(0, 4));
+ p.add(new ShearCanvas(direven, false, horizontal, false, true));
+ p.add(new ShearCanvas(dirodd, false, horizontal, true, false));
+ p.add(new ShearCanvas(direven, true, horizontal, false, true));
+ p.add(new ShearCanvas(dirodd, true, horizontal, true, false));
+
+ return p;
+ }
+
+ public static class ShearCanvas extends Canvas {
+ public static final int GRADW = 30;
+
+ public static final Rectangle anchor =
+ new Rectangle(-GRADW / 2, -GRADW / 2, GRADW, GRADW);
+
+ public static final Color faintblue = new Color(0f, 0f, 1.0f, 0.35f);
+
+ private AffineTransform txform;
+ private GradientPaint grad;
+ private String label;
+
+ public ShearCanvas(String label,
+ boolean cyclic, boolean horizontal,
+ boolean shearx, boolean sheary) {
+ txform = new AffineTransform();
+ if (shearx) {
+ txform.shear(-.5, 0);
+ }
+ if (sheary) {
+ txform.shear(0, -.5);
+ }
+ int relx = horizontal ? 0 : GRADW / 2;
+ int rely = horizontal ? GRADW / 2 : 0;
+ grad = new GradientPaint(-relx, -rely, Color.green,
+ relx, rely, Color.yellow, cyclic);
+ this.label = label;
+ }
+
+ public void paint(Graphics g) {
+ Graphics2D g2d = (Graphics2D) g;
+
+ AffineTransform at = g2d.getTransform();
+ g2d.translate(75, 75);
+ g2d.transform(txform);
+ g2d.setPaint(grad);
+ g2d.fill(g.getClip());
+ g2d.setColor(faintblue);
+ g2d.fill(anchor);
+ g2d.setTransform(at);
+
+ Dimension d = getSize();
+ g2d.setColor(Color.black);
+ g2d.drawRect(0, 0, d.width - 1, d.height - 1);
+ g2d.drawString(label, 5, d.height - 5);
+ g2d.dispose();
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Graphics2D/BasicStrokeValidate.java b/test/jdk/java/awt/Graphics2D/BasicStrokeValidate.java
new file mode 100644
index 00000000000..251f14e5081
--- /dev/null
+++ b/test/jdk/java/awt/Graphics2D/BasicStrokeValidate.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2000, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4363534
+ * @summary This test verifies that setting a non-thin-line BasicStroke
+ * on a Graphics2D obtained from a BufferedImage will correctly validate
+ * the pipelines for the line-widening pipeline even if that is the only
+ * non-default attribute on the graphics.
+ *
+ */
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+
+public class BasicStrokeValidate {
+
+ public static final int TESTW = 100;
+ public static final int TESTH = 100;
+
+ public static void main(String[] args) {
+ BufferedImage bi1 = createImage(false);
+ BufferedImage bi2 = createImage(true);
+ compare(bi1, bi2); // images should differ
+ }
+
+ static BufferedImage createImage(boolean dashed) {
+ BufferedImage bi = new BufferedImage(TESTW, TESTH, BufferedImage.TYPE_INT_RGB);
+ Graphics2D g2d = bi.createGraphics();
+ g2d.setColor(Color.white);
+ g2d.fillRect(0, 0, TESTW, TESTH);
+ g2d.setColor(Color.black);
+ if (dashed) {
+ g2d.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_SQUARE,
+ BasicStroke.JOIN_MITER, 10.0f,
+ new float[] {2.5f, 3.5f},
+ 0.0f));
+ }
+ g2d.drawRect(10, 10, TESTW-20, TESTH-20);
+ g2d.setStroke(new BasicStroke(10f));
+ g2d.drawRect(20, 20, TESTW-40, TESTH-40);
+ return bi;
+ }
+
+ static void compare(BufferedImage i1, BufferedImage i2) {
+ boolean same = true;
+ int w = i1.getWidth(), h = i1.getHeight();
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ int p1 = i1.getRGB(x, y);
+ int p2 = i2.getRGB(x, y);
+ if (p1 != p2) {
+ same = false;
+ }
+ }
+ if (!same) {
+ break;
+ }
+ }
+ if (same) {
+ throw new RuntimeException("No difference");
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Graphics2D/DrawImageIAETest/DrawImageIAETest.java b/test/jdk/java/awt/Graphics2D/DrawImageIAETest/DrawImageIAETest.java
new file mode 100644
index 00000000000..af7ebae72a6
--- /dev/null
+++ b/test/jdk/java/awt/Graphics2D/DrawImageIAETest/DrawImageIAETest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4191004
+ * @summary Tests that no IllegalArgumentException is thrown when calling
+ * drawImage with certain conditions
+ * @key headful
+ */
+
+import java.awt.AlphaComposite;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.MediaTracker;
+import java.awt.Toolkit;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+public class DrawImageIAETest extends Frame {
+
+ static String filename = "/duke.gif";
+ private volatile Image dimg;
+ private volatile BufferedImage bimg;
+ static volatile DrawImageIAETest app;
+ static volatile JFrame jframe;
+ static volatile boolean passed = true;
+ static volatile Exception exception = null;
+ static volatile CountDownLatch imageLatch = new CountDownLatch(1);
+
+ DrawImageIAETest(String title) {
+ super(title);
+ }
+
+ public static void main(final String[] args) throws Exception {
+ EventQueue.invokeAndWait(DrawImageIAETest:: createUI);
+ imageLatch.await(3, TimeUnit.MILLISECONDS);
+ try {
+ if (!passed) {
+ throw new RuntimeException("Test FAILED: exception caught:" + exception);
+ }
+ } finally {
+ if (jframe != null) {
+ EventQueue.invokeAndWait(jframe::dispose);
+ }
+ if (app != null) {
+ EventQueue.invokeAndWait(app::dispose);
+ }
+ }
+ }
+
+ static void createUI() {
+ app = new DrawImageIAETest("DrawImageIAETest");
+ app.setLayout (new BorderLayout());
+ app.setSize(200,200);
+ app.setLocationRelativeTo(null);
+ app.setVisible(true);
+
+ String file;
+ try {
+ String dir = System.getProperty("test.src",
+ System.getProperty("user.dir"));
+ file = dir + filename;
+ } catch (Exception e) {
+ file = "." + filename;
+ }
+
+ Image textureAlphaSource = null;
+ MediaTracker tracker = new MediaTracker(app);
+ app.dimg = Toolkit.getDefaultToolkit().getImage(file);
+ tracker.addImage(app.dimg, 1);
+ try {
+ tracker.waitForAll();
+ imageLatch.countDown();
+ } catch (Exception e) {
+ System.err.println("Can't load images");
+ }
+
+ if (app.dimg == null) {
+ passed = false;
+ return;
+ }
+
+ jframe = new JFrame("Test DrawImageIAETest");
+ jframe.setSize(300, 300);
+ JPanel jpanel;
+ jframe.getContentPane().add("Center", jpanel = new JPanel() {
+ public void paint(Graphics _g) {
+ Graphics2D g = (Graphics2D)_g;
+ Dimension d = getSize();
+ Graphics2D g2 = app.createGraphics2D(d.width, d.height);
+ app.drawDemo(d.width, d.height, g2);
+ g2.dispose();
+ g.drawImage(app.bimg, 0, 0, app);
+ }
+ });
+ jpanel.setSize(140, 140);
+ jframe.setVisible(true);
+ }
+
+ public void drawDemo(int w, int h, Graphics2D g2) {
+ GeneralPath p1 = new GeneralPath();
+ GeneralPath p2 = new GeneralPath();
+
+ int dukeX = 73;
+ int dukeY = 26;
+
+ double x = 118;
+ double y = 17;
+ double ew = 50;
+ double eh = 48;
+
+ p1.append(new Ellipse2D.Double(x, y, ew, eh), false);
+ p2.append(new Rectangle2D.Double(x+5, y+5, ew-10, eh-10),false);
+
+ g2.setClip(p1);
+ g2.clip(p2);
+ try {
+ g2.drawImage(dimg, dukeX, dukeY, null);
+ } catch (IllegalArgumentException e) {
+ passed = false;
+ exception = e;
+ }
+ }
+
+ public Graphics2D createGraphics2D(int w, int h) {
+ Graphics2D g2 = null;
+ if (bimg == null || bimg.getWidth() != w || bimg.getHeight() != h) {
+ bimg = (BufferedImage) createImage(w, h);
+ }
+ g2 = bimg.createGraphics();
+ g2.setBackground(getBackground());
+ g2.clearRect(0, 0, w, h);
+ g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
+ return g2;
+ }
+}
diff --git a/test/jdk/java/awt/Graphics2D/DrawImageIAETest/duke.gif b/test/jdk/java/awt/Graphics2D/DrawImageIAETest/duke.gif
new file mode 100644
index 00000000000..ed32e0ff79b
Binary files /dev/null and b/test/jdk/java/awt/Graphics2D/DrawImageIAETest/duke.gif differ
diff --git a/test/jdk/java/awt/Graphics2D/ImageRendering/ImageRendering.java b/test/jdk/java/awt/Graphics2D/ImageRendering/ImageRendering.java
new file mode 100644
index 00000000000..209a93e92d5
--- /dev/null
+++ b/test/jdk/java/awt/Graphics2D/ImageRendering/ImageRendering.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4203598
+ * @summary This test verifies that an image with transparent background can be displayed
+ * correctly with the red background color given.
+ * The correct display should be the sleeping Duke on a red background.
+ *
+ */
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import javax.imageio.ImageIO;
+
+public class ImageRendering {
+
+ public static void main(String[] args) throws Exception {
+
+ String imgName = "snooze.gif";
+ File file = new File(System.getProperty("test.src", "."), imgName);
+ BufferedImage image = ImageIO.read(file);
+ int w = image.getWidth();
+ int h = image.getHeight();
+ BufferedImage dest = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ Graphics2D g2d = dest.createGraphics();
+ g2d.drawImage(image, 0, 0, Color.red, null);
+ int redPixel = Color.red.getRGB();
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ int srcPixel = image.getRGB(x, y);
+ if ((srcPixel & 0x0ff000000) == 0) {
+ int destPix = dest.getRGB(x, y);
+ if (destPix != redPixel) {
+ throw new RuntimeException("Not red at x=" + x +
+ " y=" + y +
+ "pix = " + Integer.toHexString(destPix));
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Graphics2D/ImageRendering/snooze.gif b/test/jdk/java/awt/Graphics2D/ImageRendering/snooze.gif
new file mode 100644
index 00000000000..e357e316cdb
Binary files /dev/null and b/test/jdk/java/awt/Graphics2D/ImageRendering/snooze.gif differ
diff --git a/test/jdk/java/awt/Graphics2D/ScaledThinLineTest.java b/test/jdk/java/awt/Graphics2D/ScaledThinLineTest.java
new file mode 100644
index 00000000000..fd4a5dd5e7c
--- /dev/null
+++ b/test/jdk/java/awt/Graphics2D/ScaledThinLineTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2001, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/**
+ * @test
+ * @bug 4210466 4417756
+ * @summary thin lines are not draw correctly under large scales
+ */
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.image.BufferedImage;
+import java.awt.geom.Ellipse2D;
+
+public class ScaledThinLineTest {
+
+ public static void main(String[] args) {
+ ScaledThinLineTest c1 = new ScaledThinLineTest(200, 200);
+ ScaledThinLineTest c2 = new ScaledThinLineTest(1, 10000);
+ ScaledThinLineTest c3 = new ScaledThinLineTest(10000, 1);
+ ScaledThinLineTest c4 = new ScaledThinLineTest(0.01, 10000);
+ ScaledThinLineTest c5 = new ScaledThinLineTest(10000, 0.01);
+ compare(c1.bi, c2.bi);
+ compare(c2.bi, c3.bi);
+ compare(c3.bi, c4.bi);
+ compare(c4.bi, c5.bi);
+ }
+
+ private final Shape shape;
+ private final double scaleX,scaleY;
+ private BufferedImage bi = null;
+
+ public ScaledThinLineTest(double width, double height) {
+ shape = new Ellipse2D.Double(0.25*width, 0.25*height, width, height);
+ scaleX = 200/width;
+ scaleY = 200/height;
+ int iw = 300, ih = 300;
+ bi = new BufferedImage(iw, ih, BufferedImage.TYPE_INT_RGB);
+ Graphics2D g2 = bi.createGraphics();
+ g2.setColor(Color.white);
+ g2.fillRect(0, 0, iw, ih);
+ g2.setColor(Color.black);
+ g2.scale(scaleX,scaleY);
+ g2.setStroke(new BasicStroke(0));
+ g2.draw(shape);
+ }
+
+
+ static void compare(BufferedImage i1, BufferedImage i2) {
+ int w = i1.getWidth(), h = i1.getHeight();
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ int p1 = i1.getRGB(x, y);
+ int p2 = i2.getRGB(x, y);
+ if (p1 != p2) {
+ System.out.println("images differ at " + x + " " + y);
+ }
+ }
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Graphics2D/TextPerf.java b/test/jdk/java/awt/Graphics2D/TextPerf.java
new file mode 100644
index 00000000000..d3e5cc2d4d0
--- /dev/null
+++ b/test/jdk/java/awt/Graphics2D/TextPerf.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4190429
+ * @key headful
+ * @summary In this bug, text drawing performance should be reasonable.
+ * And should (per string) be consistent with the size of the
+ * rectangle in which the string is drawn, not the rectangle
+ * bounding the whole window.
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Canvas;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Panel;
+import java.awt.RenderingHints;
+import java.awt.Toolkit;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class TextPerf extends Canvas {
+
+ static volatile CountDownLatch paintLatch = new CountDownLatch(1);
+ static volatile long paintTime = 5000; // causes test fail if it is not updated.
+ static volatile Frame frame;
+
+ public static void main(String[] args) throws Exception {
+ EventQueue.invokeAndWait(TextPerf::createUI);
+ paintLatch.await(5, TimeUnit.SECONDS);
+ if (paintTime > 2000) {
+ throw new RuntimeException("Paint time is " + paintTime + "ms");
+ }
+ if (frame != null) {
+ EventQueue.invokeAndWait(frame::dispose);
+ }
+ }
+
+ static void createUI() {
+ frame = new Frame("TextPerf");
+ frame.setLayout(new BorderLayout());
+ TextPerf tp = new TextPerf();
+ frame.add(tp, BorderLayout.CENTER);
+ frame.pack();
+ frame.setVisible(true);
+ }
+
+ public Dimension getPreferredSize() {
+ Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
+ return new Dimension(d.width - 50, d.height - 50);
+ }
+
+ static Font[] fonts = {
+ new Font(Font.SERIF, Font.PLAIN, 10),
+ new Font(Font.SANS_SERIF, Font.PLAIN, 10),
+ new Font(Font.MONOSPACED, Font.ITALIC, 10),
+ new Font(Font.SERIF, Font.PLAIN, 14),
+ new Font(Font.SERIF, Font.BOLD, 12),
+ };
+
+ public void paint(Graphics g1) {
+
+ Graphics2D g = (Graphics2D)g1;
+ String text = "Hello,_Wgjpqy!";
+ Toolkit.getDefaultToolkit().sync();
+ long startTime = System.currentTimeMillis();
+ FontMetrics[] cachedMetrics = new FontMetrics[fonts.length];
+ Dimension size = getSize();
+ int prim = 0;
+ int spaceWidth = 5;
+ Color cols[] = { Color.red, Color.blue, Color.yellow,
+ Color.green, Color.pink, Color.orange} ;
+
+ for (int y = 20; y < size.height; y += 20) {
+ int i = 0;
+ for (int x = 0; x < size.width; i++) {
+ Font font = fonts[i % fonts.length];
+ FontMetrics metrics = cachedMetrics[i % fonts.length];
+ if (metrics == null) {
+ metrics = g.getFontMetrics(font);
+ cachedMetrics[i % fonts.length] = metrics;
+ }
+
+ g.setFont(font);
+ g.setColor(cols[i % cols.length]);
+ switch (prim++) {
+ case 0: g.drawString(text, x, y);
+ break;
+ case 1: g.drawBytes(text.getBytes(), 0, text.length(), x, y);
+ break;
+ case 2: char[] chs= new char[text.length()];
+ text.getChars(0,text.length(), chs, 0);
+ g.drawChars(chs, 0, text.length(), x, y);
+ break;
+ case 3: GlyphVector gv = font.createGlyphVector(
+ g.getFontRenderContext(), text);
+ g.drawGlyphVector(gv, (float)x, (float)y);
+ default: prim = 0;
+ }
+
+ x += metrics.stringWidth(text) + spaceWidth;
+ }
+ }
+
+ // Draw some transformed text to verify correct bounds calculated
+ AffineTransform at = AffineTransform.getTranslateInstance(50, 50);
+ at.scale(7.0,7.0);
+ at.rotate(1.0);
+ g.transform(at);
+ g.setColor(Color.black);
+ Font font = new Font(Font.SERIF, Font.PLAIN, 20);
+ RenderingHints hints = new RenderingHints(null);
+ hints.put(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ g.setRenderingHints(hints);
+ g.setFont(font);
+ FontMetrics metrics = g.getFontMetrics(font);
+ g.drawString("Java", 5,5);
+
+ Toolkit.getDefaultToolkit().sync();
+ long endTime = System.currentTimeMillis();
+ paintTime = endTime - startTime;
+ String msg = "repainted in " + paintTime + " milliseconds";
+ System.out.println(msg);
+ System.out.flush();
+
+ paintLatch.countDown();
+ }
+}
diff --git a/test/jdk/java/awt/GraphicsEnvironment/DefaultScreenDeviceTest.java b/test/jdk/java/awt/GraphicsEnvironment/DefaultScreenDeviceTest.java
new file mode 100644
index 00000000000..b59460322da
--- /dev/null
+++ b/test/jdk/java/awt/GraphicsEnvironment/DefaultScreenDeviceTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2001, 2024, Oracle and/or its affiliates. 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 java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Color;
+import java.awt.Frame;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Label;
+import java.awt.Rectangle;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.List;
+
+/*
+ * @test
+ * @bug 4473671
+ * @summary Test to verify GraphicsEnvironment.getDefaultScreenDevice always
+ * returning first screen
+ * @requires (os.family == "windows")
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual DefaultScreenDeviceTest
+ */
+
+public class DefaultScreenDeviceTest {
+ private static Frame testFrame;
+
+ public static void main(String[] args) throws Exception {
+ GraphicsEnvironment ge = GraphicsEnvironment.
+ getLocalGraphicsEnvironment();
+ GraphicsDevice[] gds = ge.getScreenDevices();
+ if (gds.length < 2) {
+ System.out.println("Test requires at least 2 displays");
+ return;
+ }
+
+ String INSTRUCTIONS = """
+ 1. The test is for systems which allows primary display
+ selection in multiscreen systems.
+ Set the system primary screen to be the rightmost
+ (i.e. the right screen in two screen configuration)
+ This can be done by going to OS Display Settings
+ selecting the screen and checking the 'Use this device
+ as primary monitor' checkbox.
+ 2. When done, click on 'Frame on Primary Screen' button and
+ see where the frame will pop up
+ 3. If Primary Frame pops up on the primary display,
+ the test passed, otherwise it failed
+ """;
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(initialize())
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static List initialize() {
+ Frame frame = new Frame("Default screen device test");
+ GraphicsConfiguration gc =
+ GraphicsEnvironment.getLocalGraphicsEnvironment().
+ getDefaultScreenDevice().getDefaultConfiguration();
+
+ testFrame = new Frame("Primary screen frame", gc);
+ frame.setLayout(new BorderLayout());
+ frame.setSize(200, 200);
+
+ Button b = new Button("Frame on Primary Screen");
+ b.addActionListener(e -> {
+ if (testFrame != null) {
+ testFrame.setVisible(false);
+ testFrame.dispose();
+ }
+
+ testFrame.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e1) {
+ testFrame.setVisible(false);
+ testFrame.dispose();
+ }
+ });
+ testFrame.add(new Label("This frame should be on the primary screen"));
+ testFrame.setBackground(Color.red);
+ testFrame.pack();
+ Rectangle rect = gc.getBounds();
+ testFrame.setLocation(rect.x + 100, rect.y + 100);
+ testFrame.setVisible(true);
+ });
+ frame.add(b);
+ return List.of(testFrame, frame);
+ }
+}
diff --git a/test/jdk/java/awt/LightweightComponent/LWParentMovedTest/LWParentMovedTest.java b/test/jdk/java/awt/LightweightComponent/LWParentMovedTest/LWParentMovedTest.java
new file mode 100644
index 00000000000..d46af3a0d5e
--- /dev/null
+++ b/test/jdk/java/awt/LightweightComponent/LWParentMovedTest/LWParentMovedTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4147246
+ * @summary Simple check for peer != null in Component.componentMoved
+ * @key headful
+ * @run main LWParentMovedTest
+ */
+
+import java.awt.Button;
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.EventQueue;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Graphics;
+
+public class LWParentMovedTest {
+ static CMTFrame f;
+
+ // test will throw an exception and fail if lwc is null
+ public static void main(String[] args) throws Exception {
+ try {
+ EventQueue.invokeAndWait(() -> f = new CMTFrame());
+ } finally {
+ if (f != null) {
+ EventQueue.invokeAndWait(() -> f.dispose());
+ }
+ }
+ }
+}
+
+class CMTFrame extends Frame {
+ Container lwc;
+ Button button;
+
+ public CMTFrame() {
+ super("Moving LWC Test");
+ setLayout(new FlowLayout());
+ lwc = new LWSquare(Color.blue, 100, 100);
+ button = new Button();
+ lwc.add(button);
+ add(lwc);
+
+ setSize(400, 300);
+ setVisible(true);
+
+ // queue up a bunch of COMPONENT_MOVED events
+ for (int i = 0; i < 1000; i++) {
+ lwc.setLocation(i, i);
+ }
+
+ // remove heavyweight from lightweight container
+ lwc.remove(button);
+ }
+}
+
+//
+// Lightweight container
+//
+class LWSquare extends Container {
+ int width;
+ int height;
+
+ public LWSquare(Color color, int w, int h) {
+ setBackground(color);
+ setLayout(new FlowLayout());
+ width = w;
+ height = h;
+ setName("LWSquare-" + color.toString());
+ }
+
+ public void paint(Graphics g) {
+ g.setColor(getBackground());
+ g.fillRect(0, 0, 1000, 1000);
+ }
+}
diff --git a/test/jdk/java/awt/LightweightComponent/LightWeightTabFocus/LightWeightTabFocus.java b/test/jdk/java/awt/LightweightComponent/LightWeightTabFocus/LightWeightTabFocus.java
new file mode 100644
index 00000000000..05889580fd4
--- /dev/null
+++ b/test/jdk/java/awt/LightweightComponent/LightWeightTabFocus/LightWeightTabFocus.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2001, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4095214
+ * @summary Test change of focus on lightweights using the tab key
+ * @key headful
+ * @run main LightWeightTabFocus
+ */
+
+import java.awt.Button;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+
+public class LightWeightTabFocus {
+ private static Frame f;
+ private static LightweightButton btn1;
+ private static Button btn2;
+ private static Robot robot;
+ private static volatile Point point;
+ private static Point loc;
+
+ public static void main(String[] args) throws Exception {
+ robot = new Robot();
+ robot.setAutoDelay(100);
+ try {
+ EventQueue.invokeAndWait(() -> createUI());
+ robot.delay(1000);
+ EventQueue.invokeAndWait(() -> {
+ loc = f.getLocation();
+ point = btn2.getLocation();
+ });
+ robot.mouseMove(loc.x + point.x, loc.y + point.y);
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ // First TAB
+ robot.keyPress(KeyEvent.VK_TAB);
+ robot.keyRelease(KeyEvent.VK_TAB);
+ if (!btn1.hasFocus()) {
+ new RuntimeException("First tab failed");
+ }
+ // Second TAB
+ robot.keyPress(KeyEvent.VK_TAB);
+ robot.keyRelease(KeyEvent.VK_TAB);
+ if (!btn2.hasFocus()) {
+ new RuntimeException("Second tab failed");
+ }
+ // First SHIFT+TAB
+ robot.keyPress(KeyEvent.VK_SHIFT);
+ robot.keyPress(KeyEvent.VK_TAB);
+ robot.delay(100);
+ robot.keyRelease(KeyEvent.VK_TAB);
+ robot.keyRelease(KeyEvent.VK_SHIFT);
+ if (!btn1.hasFocus()) {
+ new RuntimeException("First shift+tab failed");
+ }
+ // Second SHIFT+TAB
+ robot.keyPress(KeyEvent.VK_SHIFT);
+ robot.keyPress(KeyEvent.VK_TAB);
+ robot.delay(100);
+ robot.keyRelease(KeyEvent.VK_TAB);
+ robot.keyRelease(KeyEvent.VK_SHIFT);
+ if (!btn2.hasFocus()) {
+ new RuntimeException("Second shift+tab failed");
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (f != null) {
+ f.dispose();
+ }
+ });
+ }
+ }
+
+ private static Frame createUI() {
+ f = new Frame("TAB Focus Change on LW Test");
+ f.setLayout(new FlowLayout());
+ btn1 = new LightweightButton();
+ f.add(btn1);
+ btn2 = new Button("Click Me To start");
+ f.add(btn2);
+ f.pack();
+ f.setVisible(true);
+ return f;
+ }
+}
+
+class LightweightButton extends Component implements FocusListener {
+ boolean focus;
+ LightweightButton() {
+ focus = false;
+ addFocusListener(this);
+ }
+
+ public Dimension getPreferredSize()
+ {
+ return new Dimension(100, 100);
+ }
+
+ public void focusGained(FocusEvent e) {
+ focus = true;
+ repaint();
+ }
+
+ public void focusLost(FocusEvent e) {
+ focus = false;
+ repaint();
+ }
+
+ public void paint(Graphics g) {
+ if (focus) {
+ g.drawString("Has Focus", 10, 20);
+ } else {
+ g.drawString("Not Focused", 10, 20);
+ }
+ }
+
+ public boolean isFocusable() {
+ return true;
+ }
+}
diff --git a/test/jdk/java/awt/LightweightComponent/LightweightFontTest/LightweightFontTest.java b/test/jdk/java/awt/LightweightComponent/LightweightFontTest/LightweightFontTest.java
new file mode 100644
index 00000000000..4fd90656d61
--- /dev/null
+++ b/test/jdk/java/awt/LightweightComponent/LightweightFontTest/LightweightFontTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 1998, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4077709 4153989
+ * @summary Lightweight component font settable test
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual LightweightFontTest
+ */
+
+import java.awt.Button;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Frame;
+import java.awt.Graphics;
+
+
+public class LightweightFontTest {
+ static Font desiredFont = null;
+
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ [ There are 7 steps to this test ]
+ 1. The 2 bordered labels (Emacs vs. vi) should be in a LARGE font
+ (approximately 1/2 inch tall)
+ 2. The labels should not overlap.
+ 3. Each button should be large enough to contain the entire label.
+ 4. The labels should have red backgrounds
+ 5. The text in the left label should be blue and the right yellow
+ 6. Resize the window to make it much smaller and larger
+ 7. The buttons should never overlap, and they should be large
+ enough to contain the entire label.
+ (although the button may disappear if there is not enough
+ room in the window)"
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(LightweightFontTest::createUI)
+ .logArea(5)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Frame createUI() {
+ Frame f = new Frame("Lightweight Font Test");
+ f.setLayout(new FlowLayout());
+
+ desiredFont = new Font(Font.DIALOG, Font.PLAIN, 36);
+ Component component;
+ component = new BorderedLabel("Emacs or vi?");
+ component.setFont(desiredFont);
+ component.setBackground(Color.red);
+ component.setForeground(Color.blue);
+ f.add(component);
+ component = new BorderedLabel("Vi or Emacs???");
+ component.setFont(desiredFont);
+ component.setBackground(Color.red);
+ component.setForeground(Color.yellow);
+ f.add(component);
+ f.pack();
+ return f;
+ }
+}
+
+/**
+ * Lightweight component
+ */
+class BorderedLabel extends Component {
+ boolean superIsButton;
+ String labelString;
+
+ BorderedLabel(String labelString) {
+ this.labelString = labelString;
+
+ Component thisComponent = this;
+ superIsButton = (thisComponent instanceof Button);
+ if(superIsButton) {
+ ((Button)thisComponent).setLabel(labelString);
+ }
+ }
+
+ public Dimension getMinimumSize() {
+ Dimension minSize = new Dimension();
+
+ if (superIsButton) {
+ minSize = super.getMinimumSize();
+ } else {
+
+ Graphics g = getGraphics();
+ verifyFont(g);
+ FontMetrics metrics = g.getFontMetrics();
+
+ minSize.width = metrics.stringWidth(labelString) + 14;
+ minSize.height = metrics.getMaxAscent() + metrics.getMaxDescent() + 9;
+
+ g.dispose();
+ }
+ return minSize;
+ }
+
+ public Dimension getPreferredSize() {
+ Dimension prefSize = new Dimension();
+ if (superIsButton) {
+ prefSize = super.getPreferredSize();
+ } else {
+ prefSize = getMinimumSize();
+ }
+ return prefSize;
+ }
+
+ public void paint(Graphics g) {
+ verifyFont(g);
+ super.paint(g);
+ if (superIsButton) {
+ return;
+ }
+ Dimension size = getSize();
+ Color oldColor = g.getColor();
+
+ // draw border
+ g.setColor(getBackground());
+ g.fill3DRect(0, 0, size.width, size.height, false);
+ g.fill3DRect(3, 3, size.width - 6, size.height - 6, true);
+
+ // draw text
+ FontMetrics metrics = g.getFontMetrics();
+ int centerX = size.width / 2;
+ int centerY = size.height / 2;
+ int textX = centerX - (metrics.stringWidth(labelString) / 2);
+ int textY = centerY + ((metrics.getMaxAscent()
+ + metrics.getMaxDescent()) / 2);
+ g.setColor(getForeground());
+ g.drawString(labelString, textX, textY);
+
+ g.setColor(oldColor);
+ }
+
+ /**
+ * Verifies that the font is correct and prints a warning
+ * message and/or throws a RuntimeException if it is not.
+ */
+ private void verifyFont(Graphics g) {
+ Font desiredFont = LightweightFontTest.desiredFont;
+ Font actualFont = g.getFont();
+ if (!actualFont.equals(desiredFont)) {
+ PassFailJFrame.log("AWT BUG: FONT INFORMATION LOST!");
+ PassFailJFrame.log(" Desired font: " + desiredFont);
+ PassFailJFrame.log(" Actual font: " + actualFont);
+ PassFailJFrame.forceFail();
+ }
+ }
+}
diff --git a/test/jdk/java/awt/MenuBar/CellsResize.java b/test/jdk/java/awt/MenuBar/CellsResize.java
new file mode 100644
index 00000000000..64777095fa8
--- /dev/null
+++ b/test/jdk/java/awt/MenuBar/CellsResize.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2011, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6502052
+ * @summary Menu cells must resize if font changes (XToolkit)
+ * @requires os.family == "linux"
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual CellsResize
+ */
+
+import java.awt.Button;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuComponent;
+import java.awt.MenuItem;
+import java.awt.Panel;
+import java.awt.PopupMenu;
+import java.awt.Toolkit;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+public class CellsResize {
+ private static Frame frame;
+ private static MenuBar menuBar;
+ private static PopupMenu popupMenu;
+ private static Menu barSubMenu;
+ private static Menu popupSubMenu;
+ private static boolean fontMultiplied = false;
+
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ 1. Open all nested menus in menu bar.
+ 2. Click on "popup-menu" button to show popup-menus.
+ 3. Open all nested menus in popup-menu.
+ 4. Click on "big-font" button (to make all menus have a
+ bigger font).
+ 5. Open all nested menus again (as described in 1, 2, 3).
+ 6. If all menu items use a bigger font now and their labels fit
+ into menu-item size, press "pass", otherwise press "fail".
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(CellsResize::createUI)
+ .logArea(5)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static Frame createUI () {
+ if (!checkToolkit()) {
+ new RuntimeException("Toolkit check failed.");
+ }
+ frame = new Frame("MenuBar Cell Resize Test");
+
+ popupMenu = new PopupMenu();
+ popupMenu.add(createMenu(false));
+
+ frame.add(popupMenu);
+
+ menuBar = new MenuBar();
+ menuBar.add(createMenu(true));
+
+ frame.setMenuBar(menuBar);
+
+ Button bp = new Button("popup-menu");
+ bp.addMouseListener(new MouseAdapter() {
+ public void mouseReleased(MouseEvent e) {
+ popupMenu.show(e.getComponent(), e.getX(), e.getY());
+ }
+ });
+
+ Button bf = new Button("big-font");
+ bf.addMouseListener(new MouseAdapter() {
+ public void mouseReleased(MouseEvent e) {
+ bigFont();
+ }
+ });
+
+ Panel panel = new Panel();
+ panel.setLayout(new GridLayout(2, 1));
+ panel.add(bp);
+ panel.add(bf);
+
+ frame.add(panel);
+ frame.setSize(300, 300);
+ return frame;
+ }
+
+ static boolean checkToolkit() {
+ String toolkitName = Toolkit.getDefaultToolkit().getClass().getName();
+ return toolkitName.equals("sun.awt.X11.XToolkit");
+ }
+
+ static Menu createMenu(boolean bar) {
+ Menu menu1 = new Menu("Menu-1");
+ Menu menu11 = new Menu("Menu-11");
+ menu1.add(menu11);
+ if (bar) {
+ barSubMenu = menu11;
+ } else {
+ popupSubMenu = menu11;
+ }
+ menu11.add(new MenuItem("MenuItem"));
+ return menu1;
+ }
+
+ static void bigFont() {
+ if (fontMultiplied) {
+ return;
+ } else {
+ fontMultiplied = true;
+ }
+
+ multiplyFont(barSubMenu, 7);
+ multiplyFont(popupSubMenu, 7);
+
+ // NOTE: if previous two are moved below following
+ // two, they get their font multiplied twice.
+
+ multiplyFont(menuBar, 5);
+ multiplyFont(popupMenu, 5);
+ }
+
+ static void multiplyFont(MenuComponent comp, int times) {
+ Font font = comp.getFont();
+ float size = font.getSize() * times;
+ comp.setFont(font.deriveFont(size));
+ }
+}
diff --git a/test/jdk/java/awt/MenuBar/MenuBarAddRemoveTest/MenuBarAddRemoveTest.java b/test/jdk/java/awt/MenuBar/MenuBarAddRemoveTest/MenuBarAddRemoveTest.java
new file mode 100644
index 00000000000..fdb9f06e98c
--- /dev/null
+++ b/test/jdk/java/awt/MenuBar/MenuBarAddRemoveTest/MenuBarAddRemoveTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1998, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4028130 4112308
+ * @summary Test for location of Frame/MenuBar when MenuBar is re-added
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual MenuBarAddRemoveTest
+ */
+
+import java.awt.Button;
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuBar;
+
+public class MenuBarAddRemoveTest {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ 1. Click the left mouse button on the "Re-Add MenuBar"
+ button several times.
+ 3. The Frame/MenuBar may repaint or flash, but the location
+ of its upper left corner should never change.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(MenuBarAddRemoveTest::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Frame createUI() {
+ Frame f = new Frame("Re-Add MenuBar Test Frame");
+ Button b = new Button("Re-Add MenuBar");
+ b.addActionListener(e -> f.setMenuBar(createMenuBar()));
+ f.setMenuBar(createMenuBar());
+ f.add(b);
+ f.pack();
+ return f;
+ }
+
+ private static MenuBar createMenuBar() {
+ MenuBar bar = new MenuBar();
+ bar.add(new Menu("foo"));
+ return bar;
+ }
+}
diff --git a/test/jdk/java/awt/MenuBar/MenuBarOnDisabledFrame/MenuBarOnDisabledFrame.java b/test/jdk/java/awt/MenuBar/MenuBarOnDisabledFrame/MenuBarOnDisabledFrame.java
new file mode 100644
index 00000000000..06f5d96c19e
--- /dev/null
+++ b/test/jdk/java/awt/MenuBar/MenuBarOnDisabledFrame/MenuBarOnDisabledFrame.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6185057
+ * @summary Disabling a frame does not disable the menus on the frame, on
+ * solaris/linux
+ * @requires os.family != "mac"
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual MenuBarOnDisabledFrame
+ */
+
+import java.awt.Button;
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+
+public class MenuBarOnDisabledFrame {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ Check if MenuBar is disabled on 'Disabled frame'
+ Press pass if menu bar is disabled, fail otherwise
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(MenuBarOnDisabledFrame::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static Frame createUI() {
+ Frame f = new Frame("Disabled frame");
+ MenuBar mb = new MenuBar();
+ Menu m1 = new Menu("Disabled Menu 1");
+ Menu m2 = new Menu("Disabled Menu 2");
+ MenuItem m11 = new MenuItem("MenuItem 1.1");
+ MenuItem m21 = new MenuItem("MenuItem 2.1");
+ Button b = new Button("Disabled button");
+
+ m1.add(m11);
+ m2.add(m21);
+ mb.add(m1);
+ mb.add(m2);
+ f.setMenuBar(mb);
+ f.add(b);
+ f.setEnabled(false);
+ f.setSize(300, 300);
+ return f;
+ }
+}
diff --git a/test/jdk/java/awt/MenuBar/MenuBarRemoveMenu/MenuBarRemoveMenuTest.java b/test/jdk/java/awt/MenuBar/MenuBarRemoveMenu/MenuBarRemoveMenuTest.java
new file mode 100644
index 00000000000..098065d1361
--- /dev/null
+++ b/test/jdk/java/awt/MenuBar/MenuBarRemoveMenu/MenuBarRemoveMenuTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4275848
+ * @summary Tests that MenuBar is painted correctly after its submenu is removed
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual MenuBarRemoveMenuTest
+ */
+
+import java.awt.Button;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class MenuBarRemoveMenuTest implements ActionListener {
+ private static MenuBar menubar;
+ private static Button removeButton;
+ private static Button addButton;
+
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ Press "Remove menu" button. If you see that both menus
+ disappeared, the test failed. Otherwise try to add and remove
+ menu several times to verify that the test passed. Every time
+ you press "Remove menu" button only one menu should go away.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(MenuBarRemoveMenuTest::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Frame createUI() {
+ Frame frame = new Frame();
+ menubar = new MenuBar();
+ removeButton = new Button("Remove menu");
+ addButton = new Button("Add menu");
+ removeButton.addActionListener(new MenuBarRemoveMenuTest());
+ addButton.addActionListener(new MenuBarRemoveMenuTest());
+ addButton.setEnabled(false);
+ menubar.add(new Menu("menu"));
+ menubar.add(new Menu("menu"));
+ frame.setMenuBar(menubar);
+ frame.setLayout(new GridLayout(1, 2));
+ frame.add(removeButton);
+ frame.add(addButton);
+ frame.pack();
+ return frame;
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource() == removeButton) {
+ menubar.remove(0);
+ removeButton.setEnabled(false);
+ addButton.setEnabled(true);
+ } else {
+ menubar.add(new Menu("menu"));
+ removeButton.setEnabled(true);
+ addButton.setEnabled(false);
+ }
+ }
+}
diff --git a/test/jdk/java/awt/MenuBar/MenuBarVisuals/MenuBarVisuals.java b/test/jdk/java/awt/MenuBar/MenuBarVisuals/MenuBarVisuals.java
new file mode 100644
index 00000000000..7663dd0d99b
--- /dev/null
+++ b/test/jdk/java/awt/MenuBar/MenuBarVisuals/MenuBarVisuals.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6180416
+ * @summary Tests MenuBar and drop down menu visuals
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual MenuBarVisuals
+ */
+
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.MenuShortcut;
+import java.awt.event.KeyEvent;
+
+public class MenuBarVisuals {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ Look at the MenuBar and traverse the menus using mouse and
+ keyboard. Then check if following is showing correctly:
+ 1. Mnemonic label Ctrl+A is NOT drawn for Menu 1/Submenu 1.1
+ 2. Mnemonic label Ctrl+B is drawn for
+ Menu 1/Submenu 1.1/Item 1.1.1
+ 3. Mnemonic label Ctrl+C is drawn for Menu1/Item 1.2
+ Press PASS if Menu is drawing correctly, FAIL otherwise.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(MenuBarVisuals::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Frame createUI() {
+ Frame f = new Frame("MenuBar Visuals Test");
+ MenuBar mb = new MenuBar();
+ Menu menu1 = new Menu("Menu 1");
+ Menu submenu11 = new Menu("Submenu 1.1");
+ MenuItem item111 = new MenuItem("Item 1.1.1");
+ MenuItem item112 = new MenuItem("Item 1.1.2");
+ MenuItem item12 = new MenuItem("Item 1.2");
+ Menu menu2 = new Menu("Menu 2");
+ MenuItem item21 = new MenuItem("Item 2.1");
+ MenuItem item22 = new MenuItem("Item 2.2");
+ item111.setShortcut(new MenuShortcut(KeyEvent.VK_B, false));
+ submenu11.add(item111);
+ submenu11.add(item112);
+ submenu11.setShortcut(new MenuShortcut(KeyEvent.VK_A, false));
+ menu1.add(submenu11);
+ item12.setShortcut(new MenuShortcut(KeyEvent.VK_C, false));
+ menu1.add(item12);
+ mb.add(menu1);
+ menu2.add(item21);
+ menu2.add(item22);
+ mb.add(menu2);
+ f.setMenuBar(mb);
+ f.setSize(300, 300);
+ return f;
+ }
+}
diff --git a/test/jdk/java/awt/MenuBar/MenuNPE/MenuNPE.java b/test/jdk/java/awt/MenuBar/MenuNPE/MenuNPE.java
new file mode 100644
index 00000000000..a7a3a348011
--- /dev/null
+++ b/test/jdk/java/awt/MenuBar/MenuNPE/MenuNPE.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2004, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 5005194
+ * @summary Frame.remove(getMenuBar()) throws NPE if the frame doesn't
+ * have a menu bar
+ * @key headful
+ * @run main MenuNPE
+ */
+
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+
+public class MenuNPE {
+ private static Frame frame;
+ public static void main(String[] args) throws Exception {
+ try {
+ frame = new Frame("Menu NPE");
+ MenuBar menuBar = new MenuBar();
+ Menu menu1 = new Menu("Menu 01");
+ MenuItem menuLabel = new MenuItem("Item 01");
+ menu1.add(menuLabel);
+ menuBar.add(menu1);
+ frame.setMenuBar(menuBar);
+ frame.setSize(200, 200);
+ frame.setVisible(true);
+ frame.validate();
+ frame.remove(frame.getMenuBar());
+ frame.remove(frame.getMenuBar());
+ System.out.println("Test passed.");
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (frame != null) {
+ frame.dispose();
+ }
+ }
+ }
+}
diff --git a/test/jdk/java/awt/MenuBar/SetHelpMenuTest/SetHelpMenuTest.java b/test/jdk/java/awt/MenuBar/SetHelpMenuTest/SetHelpMenuTest.java
new file mode 100644
index 00000000000..fcfc3e80ed3
--- /dev/null
+++ b/test/jdk/java/awt/MenuBar/SetHelpMenuTest/SetHelpMenuTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4275843
+ * @summary MenuBar doesn't display all of its Menus correctly on Windows
+ * @requires os.family == "windows"
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual SetHelpMenuTest
+ */
+
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+
+public class SetHelpMenuTest {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ An empty frame should be visible. When focused, the MenuBar
+ should have 5 menus ("one", "two", "three", "Help 2",
+ "four"). If so, then the test passed. Otherwise, the test
+ failed.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(SetHelpMenuTest::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Frame createUI() {
+ Frame f = new Frame("Help MenuBar Test");
+ f.setSize(100, 100);
+
+ MenuBar mb = new MenuBar();
+ Menu h1, h2;
+
+ f.setMenuBar(mb);
+ mb.add(createMenu("one", false));
+ mb.add(createMenu("two", false));
+ mb.add(createMenu("three", true));
+
+ mb.add(h1 = createMenu("Help 1", false)); // h1 is HelpMenu
+ mb.setHelpMenu(h1);
+
+ mb.add(h2 = createMenu("Help 2", false)); // h2 replaced h1
+ mb.setHelpMenu(h2);
+
+ mb.add(createMenu("four", false));
+
+ return f;
+ }
+
+ private static Menu createMenu(String name, boolean tearOff) {
+ Menu m = new Menu(name, tearOff);
+ m.add(new MenuItem(name + " item 1"));
+ m.add(new MenuItem(name + " item 2"));
+ m.add(new MenuItem(name + " item 3"));
+ return m;
+ }
+}
diff --git a/test/jdk/java/awt/MenuBar/SetMBarWhenHidden/SetMBarWhenHidden.java b/test/jdk/java/awt/MenuBar/SetMBarWhenHidden/SetMBarWhenHidden.java
new file mode 100644
index 00000000000..67eefe48942
--- /dev/null
+++ b/test/jdk/java/awt/MenuBar/SetMBarWhenHidden/SetMBarWhenHidden.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4105881
+ * @summary Sets the menu bar while frame window is hidden, then shows
+ frame again
+ * @key headful
+ * @run main SetMBarWhenHidden
+ */
+
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.Rectangle;
+
+// test case for 4105881: FRAME.SETSIZE() DOESN'T WORK FOR SOME SOLARIS WITH
+// JDK115+CASES ON
+public class SetMBarWhenHidden {
+ private static Frame f;
+ private static Rectangle startBounds;
+ private static Rectangle endBounds;
+
+ public static void main(String[] args) throws Exception {
+ try {
+ EventQueue.invokeAndWait(() -> {
+ f = new Frame("Set MenuBar When Hidden Test");
+ Menu file;
+ Menu edit;
+ MenuBar menubar = new MenuBar();
+ file = new Menu("File");
+ menubar.add(file);
+ edit = new Menu("Edit");
+ menubar.add(edit);
+ edit.setEnabled(false);
+ f.setMenuBar(menubar);
+ f.setSize(200, 200);
+ startBounds = f.getBounds();
+ System.out.println("About to call setVisible(false)");
+ f.setVisible(false);
+ System.out.println("About to call setSize(500, 500)");
+ f.setSize(500, 500);
+ // create a new menubar and add
+ MenuBar menubar1 = new MenuBar();
+ menubar1.add(file);
+ menubar1.add(edit);
+ System.out.println("About to call setMenuBar");
+ f.setMenuBar(menubar1);
+ System.out.println("About to call setVisible(true)");
+ f.setVisible(true);
+ endBounds = f.getBounds();
+ });
+ if (startBounds.getHeight() > endBounds.getHeight() &&
+ startBounds.getWidth() > endBounds.getWidth()) {
+ throw new RuntimeException("Test failed. Frame size didn't " +
+ "change.\nStart: " + startBounds + "\n" +
+ "End: " + endBounds);
+ } else {
+ System.out.println("Test passed.\nStart: " + startBounds +
+ "\nEnd: " + endBounds);
+ }
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (f != null) {
+ f.dispose();
+ }
+ });
+ }
+ }
+}
diff --git a/test/jdk/java/awt/MenuShortcut/ActionCommandTest.java b/test/jdk/java/awt/MenuShortcut/ActionCommandTest.java
new file mode 100644
index 00000000000..bd1648cdc2c
--- /dev/null
+++ b/test/jdk/java/awt/MenuShortcut/ActionCommandTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1998, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4079449
+ * @key headful
+ * @summary MenuItem objects return null if they are activated by shortcut
+ */
+
+import java.awt.Dialog;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.MenuShortcut;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.TextArea;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+
+import static java.awt.event.KeyEvent.VK_CONTROL;
+import static java.awt.event.KeyEvent.VK_META;
+
+public class ActionCommandTest implements ActionListener {
+
+ static volatile Frame frame;
+ static volatile boolean event = false;
+ static volatile boolean failed = false;
+ static final String ITEMTEXT = "Testitem";
+
+ static void createUI() {
+ frame = new Frame("ActionCommand Menu Shortcut Test");
+ MenuBar mb = new MenuBar();
+ Menu m = new Menu("Test");
+ MenuItem mi = new MenuItem(ITEMTEXT, new MenuShortcut(KeyEvent.VK_T));
+ mi.addActionListener(new ActionCommandTest());
+ m.add(mi);
+ mb.add(m);
+ frame.setMenuBar(mb);
+ frame.setBounds(50, 400, 200, 200);
+ frame.setVisible(true);
+ }
+
+ public static void main(String[] args ) throws Exception {
+
+ EventQueue.invokeAndWait(ActionCommandTest::createUI);
+ try {
+ Robot robot = new Robot();
+
+ robot.waitForIdle();
+ robot.delay(2000);
+
+ // Ensure window has focus
+ Point p = frame.getLocationOnScreen();
+ robot.mouseMove(p.x + frame.getWidth() / 2, p.y + frame.getHeight() / 2);
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+ robot.waitForIdle();
+ robot.delay(2000);
+
+ // invoke short cut.
+ robot.keyPress(KeyEvent.VK_T);
+ robot.delay(50);
+ robot.keyRelease(KeyEvent.VK_T);
+ robot.waitForIdle();
+ robot.delay(2000);
+ } finally {
+ if (frame != null) {
+ EventQueue.invokeAndWait(frame::dispose);
+ }
+ }
+ if (failed) {
+ throw new RuntimeException("No actioncommand");
+ }
+ }
+
+ // Since no ActionCommand is set, this should be the menuitem's label.
+ public void actionPerformed(ActionEvent e) {
+ event = true;
+ String s = e.getActionCommand();
+ if (s == null || !s.equals(ITEMTEXT)) {
+ failed = true;
+ }
+ }
+
+}
diff --git a/test/jdk/java/awt/MenuShortcut/CheckMenuShortcut.java b/test/jdk/java/awt/MenuShortcut/CheckMenuShortcut.java
new file mode 100644
index 00000000000..cebb42f1b55
--- /dev/null
+++ b/test/jdk/java/awt/MenuShortcut/CheckMenuShortcut.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4167811
+ * @summary tests that shortcuts work for Checkbox menu items
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual CheckMenuShortcut
+*/
+
+import java.awt.CheckboxMenuItem;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Insets;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.MenuShortcut;
+import java.awt.Panel;
+import java.awt.Rectangle;
+import java.awt.TextArea;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyEvent;
+
+public class CheckMenuShortcut implements ActionListener, ItemListener {
+
+ static final String INSTRUCTIONS = """
+ A window that contains a text area will be displayed.
+ The window will have a menu labeled 'Window Menu'. Click on the menu to see its items.
+
+ The two menu items should have shortcuts which in order are : Ctrl-A, Ctrl-I.
+ On macOS these will be Command-A, Command-I.
+
+ If the second item only has the label 'checkbox item' and no shortcut
+ ie none of Ctrl-I or Ctrl-i, or Command-I or Command-i on macOS painted on it, the test FAILS.
+
+ The same second item - labeled 'checkbox item' is in fact a Checkbox menu item.
+ The menu item should NOT be checked (eg no tick mark).
+
+ Dismiss the menu by clicking inside the window, do not select any of menu items.
+ After that press Ctrl-i, (Command-i on macOS).
+
+ After that click on the menu again. If the second menu item 'checkbox item' is now
+ checked, the test PASSES, if it is not checked, the test FAILS.
+ """;
+
+ public static void main(String[] args) throws Exception {
+ PassFailJFrame.builder()
+ .title("CheckboxMenuItem Shortcut Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(60)
+ .logArea()
+ .testUI(CheckMenuShortcut::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+
+ static Frame createUI() {
+
+ MenuBar mainMenu;
+ Menu menu;
+ MenuItem action;
+ CheckboxMenuItem item;
+ TextArea pane;
+
+ boolean isMac = System.getProperty("os.name").startsWith("Mac");
+ String ctrlA = (isMac) ? "Command-A" : "Ctrl-A";
+ String ctrlI = (isMac) ? "Command-I" : "Ctrl-I";
+
+ CheckMenuShortcut cms = new CheckMenuShortcut();
+ Frame frame = new Frame("CheckMenuShortcut");
+
+ mainMenu = new MenuBar();
+ menu = new Menu("Window Menu");
+
+ action = new MenuItem("action");
+ action.setShortcut(new MenuShortcut(KeyEvent.VK_A, false));
+ action.addActionListener(cms);
+ action.setActionCommand("action");
+ menu.add(action);
+
+ item = new CheckboxMenuItem("checkbox item", false);
+ item.setShortcut(new MenuShortcut(KeyEvent.VK_I,false));
+ item.addItemListener(cms);
+ item.addActionListener(cms);
+ menu.add(item);
+
+ mainMenu.add(menu);
+
+ frame.setMenuBar(mainMenu);
+
+ pane = new TextArea(ctrlA + " -- action menu test\n", 10, 40, TextArea.SCROLLBARS_VERTICAL_ONLY);
+ Dimension mySize = frame.getSize();
+ Insets myIns = frame.getInsets();
+ pane.setBounds(new Rectangle(mySize.width - myIns.left - myIns.right,
+ mySize.height - myIns.top - myIns.bottom));
+ pane.setLocation(myIns.left,myIns.top);
+ frame.add(pane);
+
+ pane.append(ctrlI + " -- item menu test\n");
+
+ frame.pack();
+ return frame;
+ }
+
+ public void itemStateChanged(ItemEvent evt) {
+ PassFailJFrame.log("Got item: " + evt.getItem() + "\n");
+ }
+
+ public void actionPerformed(ActionEvent evt) {
+ PassFailJFrame.log("Got action: " + evt.getActionCommand() + "\n");
+ }
+}
diff --git a/test/jdk/java/awt/MenuShortcut/FunctionKeyShortcut.java b/test/jdk/java/awt/MenuShortcut/FunctionKeyShortcut.java
new file mode 100644
index 00000000000..960de08bd2d
--- /dev/null
+++ b/test/jdk/java/awt/MenuShortcut/FunctionKeyShortcut.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 1998, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4034665
+ * @key headful
+ * @summary Function keys should work correctly as shortcuts
+ */
+
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.MenuShortcut;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+
+import static java.awt.event.KeyEvent.VK_CONTROL;
+import static java.awt.event.KeyEvent.VK_META;
+
+public class FunctionKeyShortcut implements ActionListener {
+
+ static volatile Frame frame;
+ static volatile boolean event = false;
+ static volatile boolean failed = false;
+
+ static final boolean isMac = System.getProperty("os.name").contains("OS X");
+
+ static void createUI() {
+ frame = new Frame("Function Key Menu Shortcut Test");
+ MenuBar mb = new MenuBar();
+ Menu m = new Menu("Test");
+ MenuItem mi1 = new MenuItem("Function key 1", new MenuShortcut(KeyEvent.VK_F1));
+ MenuItem mi2 = new MenuItem("Function key 2", new MenuShortcut(KeyEvent.VK_F2));
+ MenuItem mi3 = new MenuItem("Function key 3", new MenuShortcut(KeyEvent.VK_F3));
+ MenuItem mi4 = new MenuItem("Function key 4", new MenuShortcut(KeyEvent.VK_F4));
+ MenuItem mi5 = new MenuItem("Function key 5", new MenuShortcut(KeyEvent.VK_F5));
+ MenuItem mi6 = new MenuItem("Function key 6", new MenuShortcut(KeyEvent.VK_F6));
+ MenuItem mi7 = new MenuItem("Function key 7", new MenuShortcut(KeyEvent.VK_F7));
+ MenuItem mi8 = new MenuItem("Function key 8", new MenuShortcut(KeyEvent.VK_F8));
+ MenuItem mi9 = new MenuItem("Function key 8", new MenuShortcut(KeyEvent.VK_F9));
+
+ FunctionKeyShortcut fks = new FunctionKeyShortcut();
+ mi1.addActionListener(fks);
+ mi2.addActionListener(fks);
+ mi3.addActionListener(fks);
+ mi4.addActionListener(fks);
+ mi5.addActionListener(fks);
+ mi6.addActionListener(fks);
+ mi7.addActionListener(fks);
+ mi8.addActionListener(fks);
+ mi9.addActionListener(fks);
+
+ m.add(mi1);
+ m.add(mi2);
+ m.add(mi3);
+ m.add(mi4);
+ m.add(mi5);
+ m.add(mi6);
+ m.add(mi7);
+ m.add(mi8);
+ m.add(mi9);
+
+ mb.add(m);
+ frame.setMenuBar(mb);
+ frame.setBounds(50,400,200,200);
+ frame.setVisible(true);
+ }
+
+ public static void main(String[] args ) throws Exception {
+
+ EventQueue.invokeAndWait(FunctionKeyShortcut::createUI);
+ try {
+ Robot robot = new Robot();
+
+ robot.waitForIdle();
+ robot.delay(2000);
+
+ // Ensure window has focus
+ Point p = frame.getLocationOnScreen();
+ robot.mouseMove(p.x + frame.getWidth() / 2, p.y + frame.getHeight() / 2);
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+ robot.waitForIdle();
+ robot.delay(2000);
+
+ int mod = (isMac) ? KeyEvent.VK_META : KeyEvent.VK_CONTROL;
+ robot.keyPress(mod);
+ robot.keyPress(KeyEvent.VK_F1);
+ robot.delay(50);
+ robot.keyRelease(KeyEvent.VK_F1);
+ robot.keyRelease(mod);
+ robot.waitForIdle();
+ robot.delay(2000);
+ } finally {
+ if (frame != null) {
+ EventQueue.invokeAndWait(frame::dispose);
+ }
+ }
+ if (!event || failed) {
+ throw new RuntimeException("No actioncommand");
+ }
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ System.out.println("Got " + e);
+ String s = e.getActionCommand();
+ event = true;
+ if (s == null || !s.equals("Function key 1")) {
+ failed = true;
+ }
+ }
+
+}
diff --git a/test/jdk/java/awt/MenuShortcut/MenuItemShortcutReplaceTest.java b/test/jdk/java/awt/MenuShortcut/MenuItemShortcutReplaceTest.java
new file mode 100644
index 00000000000..fe59d1a02ef
--- /dev/null
+++ b/test/jdk/java/awt/MenuShortcut/MenuItemShortcutReplaceTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4080225
+ * @summary A replaced menu shortcut does not draw in the menu.
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual MenuItemShortcutReplaceTest
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.MenuShortcut;
+import java.awt.Panel;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+
+/*
+ * Manual test because visual verification of the shortcut being painted is required.
+ */
+
+public class MenuItemShortcutReplaceTest implements ActionListener {
+
+ static boolean isMac = System.getProperty("os.name").startsWith("Mac");
+ static String shortcut = (isMac) ? "Cmd" : "Ctrl";
+ static String instructions =
+ "1. On the frame 'MenuItem Shortcut Replace Test' click on the Menu 'Click here'.\n" +
+ " You will see a MenuItem 'MenuItem1' with the shortcut key displayed as" +
+ " '" + shortcut + "+M'.\n" +
+ "2. Click the 'Change Shortcutkey' button.\n" +
+ "3. Now click on the Menu again to see the MenuItem.\n" +
+ "4. If the shortcut key displayed near the MenuItem is changed to " +
+ "'" + shortcut + "+C', press 'Pass' else press 'Fail'";
+
+ public static void main(String[] args) throws Exception {
+ PassFailJFrame.builder()
+ .title("MenuItem Shortcut Replace Test Instructions")
+ .instructions(instructions)
+ .columns(60)
+ .logArea()
+ .testUI(MenuItemShortcutReplaceTest::createUI)
+ .build()
+ .awaitAndCheck();
+
+ }
+
+ static volatile Button change;
+ static volatile MenuItem mi;
+ static volatile MenuShortcut ms;
+
+ static Frame createUI() {
+ Frame frame = new Frame("MenuItem Shortcut Replace Test");
+ MenuBar mb = new MenuBar();
+ change = new Button("Change ShortcutKey");
+ Panel p = new Panel();
+ p.add(change);
+ MenuItemShortcutReplaceTest misrt = new MenuItemShortcutReplaceTest();
+ change.addActionListener(misrt);
+ Menu m = new Menu("Click here");
+ mb.add(m);
+ mi = new MenuItem("MenuItem1");
+ m.add(mi);
+ mi.addActionListener(misrt);
+ frame.setMenuBar(mb);
+ //Set the shortcut key for the menuitem
+ ms = new MenuShortcut(KeyEvent.VK_M);
+ mi.setShortcut(ms);
+ frame.add(p, BorderLayout.SOUTH);
+ frame.setSize(300, 300);
+ return frame;
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ //change the shortcut key
+ if (e.getSource() == change) {
+ ms = new MenuShortcut(KeyEvent.VK_C);
+ mi.setShortcut(ms);
+ PassFailJFrame.log("Shortcut key set to "+shortcut+"C");
+ }
+ if (e.getSource() == mi) {
+ PassFailJFrame.log("MenuItem Selected");
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Mouse/DoubleClickTest.java b/test/jdk/java/awt/Mouse/DoubleClickTest.java
new file mode 100644
index 00000000000..037332a4098
--- /dev/null
+++ b/test/jdk/java/awt/Mouse/DoubleClickTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1998, 2024, Oracle and/or its affiliates. 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 java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Event;
+import java.awt.Frame;
+import java.awt.Panel;
+import java.awt.TextArea;
+
+/*
+ * @test
+ * @bug 4092370
+ * @summary Test to verify double click
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual DoubleClickTest
+ */
+
+public class DoubleClickTest {
+ static TextArea ta = new TextArea("", 10, 40);
+
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ 1. Double click on the red area.
+ 2. Verify that the event reports click_count > 1 on
+ Double-Click. If click_count shows only 1 for every
+ Double-Clicks then test FAILS, else test PASS.
+ """;
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(initialize())
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static Frame initialize() {
+ Frame frame = new Frame("Double-click Test");
+ frame.setLayout(new BorderLayout());
+ frame.add("East", new MyPanel(ta));
+ frame.add("West", ta);
+ frame.setSize(200, 200);
+ return frame;
+ }
+}
+
+class MyPanel extends Panel {
+ TextArea ta;
+
+ MyPanel(TextArea ta) {
+ this.ta = ta;
+ setBackground(Color.red);
+ }
+
+ public Dimension getPreferredSize() {
+ return new Dimension(50, 50);
+ }
+
+
+ public boolean mouseDown(Event event, int x, int y) {
+ ta.append("event click count= " + event.clickCount + "\n");
+ return false;
+ }
+}
diff --git a/test/jdk/java/awt/Mouse/MouseClickCount.java b/test/jdk/java/awt/Mouse/MouseClickCount.java
new file mode 100644
index 00000000000..a63d24fcb9f
--- /dev/null
+++ b/test/jdk/java/awt/Mouse/MouseClickCount.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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 java.awt.Frame;
+import java.awt.TextArea;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+/*
+ * @test
+ * @bug 4199397
+ * @summary Test to mouse click count
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual MouseClickCount
+ */
+
+public class MouseClickCount {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ 1. Clicking on Frame panel quickly will produce clickCount larger than 1
+ in the TextArea the count is printed for each mouse click
+ 2. Verify that a left-button click followed by a right button click quickly
+ will not generate 1, 2, i.e. it's not considered a double clicking.
+ """;
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(initialize())
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Frame initialize() {
+ Frame f = new Frame("Mouse Click Count Test");
+ final TextArea ta = new TextArea();
+ f.add("South", ta);
+ f.addMouseListener(new MouseAdapter() {
+ public void mousePressed(MouseEvent e) {
+ if (e.getClickCount() == 1) ta.append("\n1");
+ else ta.append(", " + e.getClickCount());
+ }
+ });
+ f.setSize(300, 500);
+ return f;
+ }
+}
diff --git a/test/jdk/java/awt/Mouse/MouseDragEnterExitTest.java b/test/jdk/java/awt/Mouse/MouseDragEnterExitTest.java
new file mode 100644
index 00000000000..b2d8e446ffc
--- /dev/null
+++ b/test/jdk/java/awt/Mouse/MouseDragEnterExitTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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 java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Frame;
+import java.awt.Panel;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.List;
+
+/*
+ * @test
+ * @bug 4141361
+ * @summary Test to Ensures that mouse enter / exit is delivered to a new
+ * frame or component during a drag
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual MouseDragEnterExitTest
+ */
+
+public class MouseDragEnterExitTest {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ Click on the blue frame, drag to the white frame, and back
+ You should get enter/exit messages for the frames when dragging
+ """;
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(MouseEvents.initialize())
+ .logArea(8)
+ .build()
+ .awaitAndCheck();
+ }
+}
+
+class MouseEvents extends Frame {
+ static int WITH_WIDGET = 0;
+
+ public MouseEvents(int mode) {
+ super("Mouse Drag Enter/Exit Test");
+ setSize(300, 300);
+
+ addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseEntered(MouseEvent e) {
+ PassFailJFrame.log("Frame MOUSE_ENTERED" + ": " + " " +
+ e.getX() + " " + e.getY());
+ }
+
+ @Override
+ public void mouseExited(MouseEvent e) {
+ PassFailJFrame.log("Frame MOUSE_EXITED" + ": " + " " +
+ e.getX() + " " + e.getY());
+ }
+ });
+
+ if (mode == WITH_WIDGET) {
+ setLayout(new BorderLayout());
+ add("Center", new SimplePanel());
+ }
+ }
+
+ public static List initialize() {
+ MouseEvents m = new MouseEvents(MouseEvents.WITH_WIDGET);
+ m.setLocation(500, 300);
+ MouseEvents t = new MouseEvents(MouseEvents.WITH_WIDGET + 1);
+ t.setLocation(200, 200);
+ return List.of(m, t);
+ }
+}
+
+class SimplePanel extends Panel {
+ public SimplePanel() {
+ super();
+ setName("Test Panel");
+ addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseEntered(MouseEvent e) {
+ PassFailJFrame.log("Panel MOUSE_ENTERED" + ": " + " " +
+ e.getX() + " " + e.getY());
+ }
+
+ @Override
+ public void mouseExited(MouseEvent e) {
+ PassFailJFrame.log("Panel MOUSE_EXITED" + ": " + " " +
+ e.getX() + " " + e.getY());
+ }
+ });
+ setSize(100, 100);
+ setBackground(Color.blue);
+ }
+}
+
diff --git a/test/jdk/java/awt/Mouse/MouseDragTest.java b/test/jdk/java/awt/Mouse/MouseDragTest.java
new file mode 100644
index 00000000000..cb8be7b0de2
--- /dev/null
+++ b/test/jdk/java/awt/Mouse/MouseDragTest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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 java.awt.Canvas;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionAdapter;
+import java.awt.event.MouseMotionListener;
+
+/*
+ * @test
+ * @bug 4035189
+ * @summary Test to verify that Drag events go to wrong component
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual MouseDragTest
+ */
+
+class HeavySquare extends Canvas {
+ private final Color colorNormal;
+ private boolean gotADragEvent;
+
+ public HeavySquare(Color color) {
+ colorNormal = color;
+ setBackground(colorNormal);
+ new MouseChecker(this);
+ addMouseMotionListener(new DragAdapter());
+ addMouseListener(new PressReleaseAdapter());
+ }
+
+ class DragAdapter extends MouseMotionAdapter {
+ public void mouseDragged(MouseEvent ev) {
+ if (gotADragEvent)
+ return;
+
+ Point mousePt = ev.getPoint();
+ Dimension csize = getSize();
+ boolean inBounds =
+ (mousePt.x >= 0 && mousePt.x <= csize.width &&
+ mousePt.y >= 0 && mousePt.y <= csize.height);
+ if (!inBounds) {
+ setBackground(Color.green);
+ }
+ gotADragEvent = true;
+ }
+ }
+
+ class PressReleaseAdapter extends MouseAdapter {
+ public void mousePressed(MouseEvent ev) {
+ gotADragEvent = false;
+ }
+
+ public void mouseReleased(MouseEvent ev) {
+ setBackground(colorNormal);
+ }
+ }
+
+ public Dimension preferredSize() {
+ return new Dimension(50, 50);
+ }
+}
+
+class MouseFrame extends Frame {
+ public MouseFrame() {
+ super("MouseDragTest");
+ new MouseChecker(this);
+ setLayout(new FlowLayout());
+ add(new HeavySquare(Color.red));
+ add(new HeavySquare(Color.blue));
+ setBounds(new Rectangle(20, 20, 400, 300));
+ }
+}
+
+public class MouseDragTest {
+ static Frame TestFrame;
+
+ public MouseDragTest() {
+ TestFrame = new MouseFrame();
+ }
+
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ 1. A frame with two boxes will appear. Click and drag _very_ quickly
+ off one of the components. You will know you were quick enough
+ when the component you dragged off of turns green
+ 2. Repeat this several times on both boxes, ensuring you get them
+ to turn green. The components should revert to their original
+ color when you release the mouse
+ 3. The test FAILS if the component doesn't revert to original
+ color, else PASS.
+ """;
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(new MouseFrame())
+ .build()
+ .awaitAndCheck();
+ }
+}
+
+class MouseChecker implements MouseListener, MouseMotionListener {
+ private boolean isPressed = false;
+ private MouseEvent evPrev = null;
+ private MouseEvent evPrevPrev = null;
+
+ public MouseChecker(Component comp) {
+ comp.addMouseListener(this);
+ comp.addMouseMotionListener(this);
+ }
+
+ private void recordEv(MouseEvent ev) {
+ evPrevPrev = evPrev;
+ evPrev = ev;
+ }
+
+ private synchronized void failure(String str) {
+ PassFailJFrame.forceFail("Test Failed : "+str);
+ }
+
+ public void mouseClicked(MouseEvent ev) {
+ if (!(evPrev.getID() == MouseEvent.MOUSE_RELEASED &&
+ evPrevPrev.getID() == MouseEvent.MOUSE_PRESSED)) {
+ failure("Got mouse click without press/release preceding.");
+ }
+ recordEv(ev);
+ }
+
+ public void mousePressed(MouseEvent ev) {
+ recordEv(ev);
+ if (isPressed) {
+ failure("Got two mouse presses without a release.");
+ }
+ isPressed = true;
+ }
+
+ public void mouseReleased(MouseEvent ev) {
+ recordEv(ev);
+ if (!isPressed) {
+ failure("Got mouse release without being pressed.");
+ }
+ isPressed = false;
+ }
+
+ public void mouseEntered(MouseEvent ev) {
+ recordEv(ev);
+ Point mousePt = ev.getPoint();
+ Component comp = (Component) ev.getSource();
+ Dimension size = comp.getSize();
+ boolean inBounds =
+ (mousePt.x >= 0 && mousePt.x <= size.width &&
+ mousePt.y >= 0 && mousePt.y <= size.height);
+
+ if (!inBounds) {
+ failure("Got mouse entered, but mouse not inside component.");
+ }
+ }
+
+ public void mouseExited(MouseEvent ev) {
+ recordEv(ev);
+ Point mousePt = ev.getPoint();
+ Component comp = (Component) ev.getSource();
+ if (comp instanceof Frame) {
+ return;
+ }
+ Dimension size = comp.getSize();
+ boolean isOnChild = (comp != comp.getComponentAt(mousePt));
+ boolean inBounds =
+ (mousePt.x >= 0 && mousePt.x <= size.width &&
+ mousePt.y >= 0 && mousePt.y <= size.height);
+ if (!isOnChild && inBounds) {
+ failure("Got mouse exit, but mouse still inside component.");
+ }
+ }
+
+ public void mouseDragged(MouseEvent ev) {
+ recordEv(ev);
+ if (!isPressed) {
+ failure("Got drag without a press first.");
+ }
+ }
+
+ public void mouseMoved(MouseEvent ev) {
+ recordEv(ev);
+ }
+}
diff --git a/test/jdk/java/awt/Mouse/MouseEnterExitTest.java b/test/jdk/java/awt/Mouse/MouseEnterExitTest.java
new file mode 100644
index 00000000000..059ad5c0548
--- /dev/null
+++ b/test/jdk/java/awt/Mouse/MouseEnterExitTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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 java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Robot;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+/*
+ * @test
+ * @bug 4050138
+ * @key headful
+ * @summary Test to verify Lightweight components don't get
+ * enter/exit during drags
+ * @run main MouseEnterExitTest
+ */
+
+class LWSquare extends Container {
+ int width;
+ int height;
+
+ public LWSquare(Color color, int w, int h) {
+ setBackground(color);
+ setLayout(new FlowLayout());
+ width = w;
+ height = h;
+ addMouseListener(new EnterExitAdapter(this));
+ setName("LWSquare-" + color.toString());
+ }
+
+ public void paint(Graphics g) {
+ g.setColor(getBackground());
+ g.fillRect(0, 0, getSize().width, getSize().height);
+ super.paint(g);
+ }
+
+ public Dimension getPreferredSize() {
+ return new Dimension(width, height);
+ }
+
+ public Cursor getCursor() {
+ return new Cursor(Cursor.CROSSHAIR_CURSOR);
+ }
+}
+
+class MouseFrame extends Frame {
+ public LWSquare lw;
+
+ public MouseFrame() {
+ super("MouseEnterExitTest");
+ setLayout(new FlowLayout());
+
+ lw = new LWSquare(Color.red, 75, 75);
+ add(lw);
+ setBounds(50, 50, 300, 200);
+ setVisible(true);
+ System.out.println(getInsets());
+
+ addMouseListener(new EnterExitAdapter(this));
+ addWindowListener(
+ new WindowAdapter() {
+ public void windowClosing(WindowEvent ev) {
+ dispose();
+ }
+ }
+ );
+ addKeyListener(
+ new KeyAdapter() {
+ public void keyPressed(KeyEvent ev) {
+ MouseEnterExitTest.getFrame().setTitle("MouseEnterExitTest");
+ }
+ }
+ );
+ }
+}
+
+
+public class MouseEnterExitTest {
+ static MouseFrame testFrame;
+
+ public static void main(String[] args) throws Exception {
+ Robot robot = new Robot();
+
+ robot.setAutoDelay(100);
+ try {
+ EventQueue.invokeAndWait(() -> testFrame = new MouseFrame());
+ if (testFrame.lw.getBackground() != Color.red) {
+ throw new RuntimeException("Initial Background color not matching");
+ }
+ robot.waitForIdle();
+ robot.delay(100);
+ EventQueue.invokeAndWait(() -> robot.mouseMove(
+ testFrame.getLocationOnScreen().x + testFrame.getSize().width / 2,
+ testFrame.getLocationOnScreen().y + testFrame.getSize().height / 2));
+ robot.waitForIdle();
+ robot.delay(100);
+
+ if (testFrame.lw.getBackground() != Color.green) {
+ throw new RuntimeException("Initial Background color not matching");
+ }
+ EventQueue.invokeAndWait(() -> robot.mouseMove(
+ testFrame.getLocationOnScreen().x + testFrame.getSize().width * 2,
+ testFrame.getLocationOnScreen().y + testFrame.getSize().height / 2));
+ robot.waitForIdle();
+ robot.delay(100);
+
+ if (testFrame.lw.getBackground() != Color.red) {
+ throw new RuntimeException("Initial Background color not matching");
+ }
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (testFrame != null) {
+ testFrame.dispose();
+ }
+ });
+ }
+ }
+
+ public static Frame getFrame() {
+ return testFrame;
+ }
+}
+
+class EnterExitAdapter extends MouseAdapter {
+ Component compToColor;
+ Color colorNormal;
+
+ EnterExitAdapter(Component comp) {
+ compToColor = comp;
+ colorNormal = comp.getBackground();
+ }
+
+ public void mouseEntered(MouseEvent ev) {
+ compToColor.setBackground(Color.green);
+ compToColor.repaint();
+ }
+
+ public void mouseExited(MouseEvent ev) {
+ compToColor.setBackground(colorNormal);
+ compToColor.repaint();
+ }
+}
diff --git a/test/jdk/java/awt/Mouse/MouseEnterExitTest2.java b/test/jdk/java/awt/Mouse/MouseEnterExitTest2.java
new file mode 100644
index 00000000000..e09ac333447
--- /dev/null
+++ b/test/jdk/java/awt/Mouse/MouseEnterExitTest2.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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 java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.GridLayout;
+import java.awt.Rectangle;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+/*
+ * @test
+ * @bug 4150851
+ * @summary Tests enter and exit events when a lightweight component is on a border
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual MouseEnterExitTest2
+ */
+
+public class MouseEnterExitTest2 {
+
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ 1. Verify that white component turns black whenever mouse enters the frame,
+ except when it enters the red rectangle.
+ 2. When the mouse enters the red part of the frame the component should stay white.
+ """;
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(EntryExitTest.initialize())
+ .build()
+ .awaitAndCheck();
+ }
+}
+
+class EntryExitTest extends Component {
+ boolean inWin;
+
+ public Dimension getPreferredSize() {
+ return new Dimension(200, 150);
+ }
+
+ public void paint(Graphics g) {
+ Color c1, c2;
+ String s;
+ if (inWin) {
+ c1 = Color.black;
+ c2 = Color.white;
+ s = "IN";
+ } else {
+ c2 = Color.black;
+ c1 = Color.white;
+ s = "OUT";
+ }
+ g.setColor(c1);
+ Rectangle r = getBounds();
+ g.fillRect(0, 0, r.width, r.height);
+ g.setColor(c2);
+ g.drawString(s, r.width / 2, r.height / 2);
+ }
+
+ public static Frame initialize() {
+ EntryExitTest test = new EntryExitTest();
+ MouseListener frameEnterExitListener = new MouseAdapter() {
+ public void mouseEntered(MouseEvent e) {
+ test.inWin = true;
+ test.repaint();
+ }
+
+ public void mouseExited(MouseEvent e) {
+ test.inWin = false;
+ test.repaint();
+ }
+ };
+
+ Frame f = new Frame("Mouse Modifier Test");
+
+ f.add(test);
+ Component jc = new Component() {
+ public Dimension getPreferredSize() {
+ return new Dimension(100, 50);
+ }
+
+ public void paint(Graphics g) {
+ Dimension d = getSize();
+ g.setColor(Color.red);
+ g.fillRect(0, 0, d.width, d.height);
+ }
+ };
+ final Container cont = new Container() {
+ public Dimension getPreferredSize() {
+ return new Dimension(100, 100);
+ }
+ };
+ cont.setLayout(new GridLayout(2, 1));
+ cont.add(jc);
+ jc.addMouseListener(new MouseAdapter() {
+ public void mouseEntered(MouseEvent e) {
+ //System.out.println("Component entered");
+ }
+ public void mouseExited(MouseEvent e) {
+ //System.out.println("Component exited");
+ }
+ });
+
+ f.add(cont, BorderLayout.NORTH);
+ f.addMouseListener(frameEnterExitListener);
+ f.pack();
+ return f;
+ }
+}
diff --git a/test/jdk/java/awt/Mouse/MouseEnterExitTest3.java b/test/jdk/java/awt/Mouse/MouseEnterExitTest3.java
new file mode 100644
index 00000000000..d5096d7acf0
--- /dev/null
+++ b/test/jdk/java/awt/Mouse/MouseEnterExitTest3.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2001, 2024, Oracle and/or its affiliates. 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 java.awt.Button;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import javax.swing.JButton;
+
+/*
+ * @test
+ * @bug 4431868
+ * @summary Tests that hw container doesn't receive mouse enter/exit events when mouse
+ * is moved between its lw and hw children
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual MouseEnterExitTest3
+ */
+
+public class MouseEnterExitTest3 {
+ static final Button button = new Button("Button");
+ static final JButton jbutton = new JButton("JButton");
+ static final Frame frame = new Frame("Mouse Enter/Exit Test");
+
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ 1. Move the mouse between Button and JButton
+ 2. Verify that the frame doesn't receive enter/exit events
+ (Enter/exit events are dumped to the area below)
+ 4. If you see enter/exit events dumped the test fails
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(initialize())
+ .logArea(4)
+ .build()
+ .awaitAndCheck();
+ }
+
+ final static MouseListener listener = new MouseAdapter() {
+ public void mouseEntered(MouseEvent e) {
+ PassFailJFrame.log(e.toString());
+ }
+
+ public void mouseExited(MouseEvent e) {
+ PassFailJFrame.log(e.toString());
+ }
+ };
+
+ public static Frame initialize() {
+ frame.setLayout(new GridLayout(2, 1));
+ frame.add(button);
+ frame.add(jbutton);
+ frame.addMouseListener(listener);
+ frame.pack();
+ return frame;
+ }
+}
diff --git a/test/jdk/java/awt/Mouse/MouseEnterExitTest4.java b/test/jdk/java/awt/Mouse/MouseEnterExitTest4.java
new file mode 100644
index 00000000000..2ee3993ae4e
--- /dev/null
+++ b/test/jdk/java/awt/Mouse/MouseEnterExitTest4.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2001, 2024, Oracle and/or its affiliates. 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 java.awt.Button;
+import java.awt.Color;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Robot;
+import java.awt.Window;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+/*
+ * @test
+ * @bug 4431868
+ * @key headful
+ * @summary Tests that window totally obscured by its child doesn't receive
+ * enter/exit events when located over another frame
+ * @run main MouseEnterExitTest4
+ */
+
+public class MouseEnterExitTest4 {
+ static Button button = new Button("Button");
+ static Frame frame = new Frame("Mouse Enter/Exit test");
+ static Window window = new Window(frame);
+ static MouseListener listener = new MouseAdapter() {
+ public void mouseEntered(MouseEvent e) {
+ throw new RuntimeException("Test failed due to Mouse Enter event");
+ }
+
+ public void mouseExited(MouseEvent e) {
+ throw new RuntimeException("Test failed due to Mouse Exit event");
+ }
+ };
+
+ public static void main(String[] args) throws Exception {
+ Robot robot = new Robot();
+
+ robot.setAutoDelay(100);
+ try {
+ EventQueue.invokeAndWait(() -> {
+ button.setBackground(Color.red);
+ window.add(button);
+ frame.setBounds(100, 100, 300, 300);
+ window.setBounds(200, 200, 100, 100);
+ window.addMouseListener(listener);
+ window.setVisible(true);
+ frame.setVisible(true);
+ });
+ robot.waitForIdle();
+ robot.delay(200);
+ EventQueue.invokeAndWait(() -> robot.mouseMove(
+ frame.getLocationOnScreen().x + frame.getSize().width / 2,
+ frame.getLocationOnScreen().y + frame.getSize().height / 2));
+ robot.waitForIdle();
+ robot.delay(200);
+ EventQueue.invokeAndWait(() -> robot.mouseMove(
+ window.getLocationOnScreen().x + window.getSize().width * 2,
+ window.getLocationOnScreen().y + window.getSize().height / 2));
+ robot.waitForIdle();
+ robot.delay(500);
+ System.out.println("Test Passed");
+
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (frame != null) {
+ frame.dispose();
+ }
+ if (window != null) {
+ window.dispose();
+ }
+ });
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Mouse/MousePressedTest.java b/test/jdk/java/awt/Mouse/MousePressedTest.java
new file mode 100644
index 00000000000..721d69bd5dd
--- /dev/null
+++ b/test/jdk/java/awt/Mouse/MousePressedTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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 java.awt.Container;
+import java.awt.GridLayout;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JScrollPane;
+import javax.swing.JToggleButton;
+
+/*
+ * @test
+ * @bug 4268759
+ * @summary Tests whether clicking on the edge of a lightweight button
+ * causes sticking behavior
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual MousePressedTest
+ */
+
+public class MousePressedTest {
+
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ 1. Click and hold on the very bottom border (2-pixel-wide border) of the
+ JButton. Then drag the mouse straight down out of the JButton and
+ into the JRadioButton, and release the mouse button
+ 2. If the component remains highlighted as if the mouse button is still
+ down, the test fails
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows((int) INSTRUCTIONS.lines().count() + 2)
+ .columns(35)
+ .testUI(initialize())
+ .build()
+ .awaitAndCheck();
+ }
+
+ public static JFrame initialize() {
+ JFrame f = new JFrame("JButton Test");
+ JPanel p = new JPanel();
+ p.setLayout(new GridLayout(2, 2));
+ JButton b = new JButton("JButton");
+ p.add(b);
+ JCheckBox cb = new JCheckBox("JCheckBox");
+ p.add(cb);
+ JRadioButton rb = new JRadioButton("JRadioButton");
+ p.add(rb);
+ p.add(new JToggleButton("JToggleButton"));
+
+ JScrollPane j = new JScrollPane(p,
+ JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
+ JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+
+ Container c = f.getContentPane();
+ c.setLayout(new GridLayout(1, 1));
+ c.add(j);
+ f.pack();
+ return f;
+ }
+}
diff --git a/test/jdk/java/awt/PopupMenu/ActivePopupCrashTest.java b/test/jdk/java/awt/PopupMenu/ActivePopupCrashTest.java
new file mode 100644
index 00000000000..51c12964e62
--- /dev/null
+++ b/test/jdk/java/awt/PopupMenu/ActivePopupCrashTest.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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 java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Label;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.Panel;
+import java.awt.Point;
+import java.awt.PopupMenu;
+import java.awt.Robot;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import java.util.Hashtable;
+
+/*
+ * @test
+ * @bug 4214550
+ * @summary Tests that there is no seg fault on repeatedly showing
+ * PopupMenu by right-clicking Label, Panel or Button
+ * @key headful
+ * @run main ActivePopupCrashTest
+ */
+
+public class ActivePopupCrashTest {
+ private static Frame f;
+ private static Label l;
+ private static Button b;
+ private static Panel p;
+
+ private static volatile Point labelCenter;
+ private static volatile Point buttonCenter;
+ private static volatile Point panelCenter;
+
+ public static void main(String[] args) throws Exception {
+ final int REPEAT_COUNT = 5;
+ try {
+ Robot robot = new Robot();
+ robot.setAutoDelay(50);
+ EventQueue.invokeAndWait(ActivePopupCrashTest::createAndShowUI);
+ robot.delay(1000);
+
+ EventQueue.invokeAndWait(() -> {
+ labelCenter = getCenterPoint(l);
+ buttonCenter = getCenterPoint(b);
+ panelCenter = getCenterPoint(p);
+ });
+
+ for (int i = 0; i < REPEAT_COUNT; i++) {
+ robot.mouseMove(labelCenter.x, labelCenter.y);
+ robot.mousePress(InputEvent.BUTTON3_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK);
+
+ robot.mouseMove(buttonCenter.x, buttonCenter.y);
+ robot.mousePress(InputEvent.BUTTON3_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK);
+
+ robot.mouseMove(panelCenter.x, panelCenter.y);
+ robot.mousePress(InputEvent.BUTTON3_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK);
+ }
+
+ // To close the popup, otherwise test fails on windows with timeout error
+ robot.mouseMove(panelCenter.x - 5, panelCenter.y - 5);
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (f != null) {
+ f.dispose();
+ }
+ });
+ }
+ }
+
+ private static Point getCenterPoint(Component component) {
+ Point p = component.getLocationOnScreen();
+ Dimension size = component.getSize();
+ return new Point(p.x + size.width / 2, p.y + size.height / 2);
+ }
+
+ public static void createAndShowUI() {
+ f = new Frame("ActivePopupCrashTest Test");
+ MenuItem item = new MenuItem("file-1");
+ item.addActionListener(ActivePopupCrashTest::logActionEvent);
+ Menu m = new Menu("file");
+ m.add(item);
+ item = new MenuItem("file-2");
+ m.add(item);
+ MenuBar mb = new MenuBar();
+ mb.add(m);
+
+ f.setMenuBar(mb);
+ f.setSize(200, 200);
+ f.setLayout(new BorderLayout());
+
+ l = new Label("label");
+ addPopup(l, "label");
+ f.add(l, BorderLayout.NORTH);
+
+ p = new Panel();
+ addPopup(p, "panel");
+ f.add(p, BorderLayout.CENTER);
+
+ b = new Button("button");
+ addPopup(b, "button");
+ f.add(b, BorderLayout.SOUTH);
+
+ f.setSize(400, 300);
+ f.setLocationRelativeTo(null);
+ f.setVisible(true);
+ }
+
+ static void addPopup(Component c, String name) {
+ PopupMenu pm = new PopupMenu();
+ MenuItem mi = new MenuItem(name + "-1");
+ mi.addActionListener(ActivePopupCrashTest::logActionEvent);
+ pm.add(mi);
+
+ mi = new MenuItem(name + "-2");
+ pm.add(mi);
+
+ setHash(c, pm);
+ c.add(pm);
+ c.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ mouseAction("mouseClicked", e);
+ }
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ mouseAction("mousePressed", e);
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ mouseAction("mouseReleased", e);
+ }
+ });
+ }
+
+ static void logActionEvent(ActionEvent e) {
+ System.out.println("actionPerformed, event=" + e + ", mod=" + getMods(e));
+ System.out.println("command=" + e.getActionCommand());
+ System.out.println("param=" + e.paramString());
+ System.out.println("source=" + e.getSource());
+ }
+
+ static String getMods(ActionEvent e) { return getMods(e.getModifiers()); }
+
+ static String getMods(MouseEvent e) { return getMods(e.getModifiers()); }
+
+ static String getMods(int mods) {
+ String modstr = "";
+ if ((mods & ActionEvent.SHIFT_MASK) == ActionEvent.SHIFT_MASK) {
+ modstr += (" SHIFT");
+ } else if ((mods & ActionEvent.ALT_MASK) == ActionEvent.ALT_MASK) {
+ modstr += (" ALT");
+ } else if ((mods & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK) {
+ modstr += (" CTRL");
+ } else if ((mods & ActionEvent.META_MASK) == ActionEvent.META_MASK) {
+ modstr += (" META");
+ }
+ return modstr;
+ }
+
+ static void mouseAction(String which, MouseEvent e) {
+ Component c = e.getComponent();
+ System.out.println(which + " e = " + e + " , mods = " + getMods(e) +
+ " , component = " + c);
+ if (e.isPopupTrigger()) {
+ System.out.println("isPopup");
+ PopupMenu pm = getHash(c);
+ pm.show(c, c.getWidth() / 2, c.getHeight() / 2);
+ }
+ }
+
+ static Hashtable popupTable = new Hashtable<>();
+
+ static void setHash(Component c, PopupMenu p) {
+ popupTable.put(c, p);
+ }
+
+ static PopupMenu getHash(Component c) {
+ return popupTable.get(c);
+ }
+
+}
diff --git a/test/jdk/java/awt/PopupMenu/KeyTraversalCrash.java b/test/jdk/java/awt/PopupMenu/KeyTraversalCrash.java
new file mode 100644
index 00000000000..4d1d4e8f831
--- /dev/null
+++ b/test/jdk/java/awt/PopupMenu/KeyTraversalCrash.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2004, 2024, Oracle and/or its affiliates. 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 java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Label;
+import java.awt.Menu;
+import java.awt.MenuItem;
+import java.awt.Point;
+import java.awt.PopupMenu;
+import java.awt.Robot;
+
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+/*
+ * @test
+ * @bug 5021183
+ * @summary Tests Key Traversal doesn't crash PopupMenu
+ * @key headful
+ * @run main KeyTraversalCrash
+ */
+
+public class KeyTraversalCrash {
+ private static Frame f;
+ private static Label label;
+
+ private static volatile Point loc;
+ private static volatile Dimension dim;
+
+ public static void main(String[] args) throws Exception {
+ try {
+ Robot robot = new Robot();
+ robot.setAutoDelay(100);
+ EventQueue.invokeAndWait(KeyTraversalCrash::createAndShowUI);
+ robot.delay(1000);
+
+ EventQueue.invokeAndWait(() -> {
+ loc = label.getLocationOnScreen();
+ dim = label.getSize();
+ });
+
+ robot.mouseMove(loc.x + 20, loc.y + 20);
+ robot.mousePress(InputEvent.BUTTON3_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK);
+
+ robot.mouseMove(loc.x + 25, loc.y + 25);
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+
+ robot.keyPress(KeyEvent.VK_LEFT);
+ robot.keyRelease(KeyEvent.VK_LEFT);
+
+ robot.keyPress(KeyEvent.VK_DOWN);
+ robot.keyRelease(KeyEvent.VK_DOWN);
+
+ // To close the popup, otherwise test fails on windows with timeout error
+ robot.mouseMove(loc.x + dim.width - 20, loc.y + dim.height - 20);
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (f != null) {
+ f.dispose();
+ }
+ });
+ }
+ }
+
+ public static void createAndShowUI() {
+ f = new Frame("KeyTraversalCrash Test");
+ final PopupMenu popup = new PopupMenu();
+ for (int i = 0; i < 10; i++) {
+ Menu menu = new Menu("Menu " + i);
+ for(int j = 0; j < 10; j++) {
+ MenuItem menuItem = new MenuItem("MenuItem " + j);
+ menu.add(menuItem);
+ }
+ popup.add(menu);
+ }
+ label = new Label("Label");
+ f.add(label);
+ f.add(popup);
+ label.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mousePressed(MouseEvent me) {
+ if (me.isPopupTrigger()) {
+ popup.show(me.getComponent(), me.getX(), me.getY());
+ }
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent me) {
+ if (me.isPopupTrigger()) {
+ popup.show(me.getComponent(), me.getX(), me.getY());
+ }
+ }
+ });
+ f.setSize(200, 200);
+ f.setLocationRelativeTo(null);
+ f.setVisible(true);
+ }
+}
diff --git a/test/jdk/java/awt/PopupMenu/MultiplePopupMenusTest.java b/test/jdk/java/awt/PopupMenu/MultiplePopupMenusTest.java
new file mode 100644
index 00000000000..f939186ca07
--- /dev/null
+++ b/test/jdk/java/awt/PopupMenu/MultiplePopupMenusTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1998, 2024, Oracle and/or its affiliates. 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 java.awt.AWTEvent;
+import java.awt.Button;
+import java.awt.Frame;
+import java.awt.MenuItem;
+import java.awt.PopupMenu;
+
+import java.awt.event.MouseEvent;
+
+/*
+ * @test
+ * @bug 4186663 4265525
+ * @summary Tests that multiple PopupMenus cannot appear at the same time
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual MultiplePopupMenusTest
+ */
+
+public class MultiplePopupMenusTest {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ Click the right mouse button on the button
+ If multiple popups appear at the same time the
+ test fails else passes.
+ """;
+
+ PassFailJFrame.builder()
+ .title("MultiplePopupMenusTest Instruction")
+ .instructions(INSTRUCTIONS)
+ .columns(30)
+ .testUI(MultiplePopupMenusTest::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Frame createUI() {
+ Frame fr = new Frame("MultiplePopupMenusTest Test");
+ TestButton button = new TestButton("button");
+ fr.add(button);
+ fr.setSize(200, 200);
+ return fr;
+ }
+
+ static class TestButton extends Button {
+ public TestButton(String title) {
+ super(title);
+ enableEvents(AWTEvent.MOUSE_EVENT_MASK);
+ }
+
+ @Override
+ public void processMouseEvent(MouseEvent e) {
+ if (e.isPopupTrigger()) {
+ for (int i = 0; i < 10; i++) {
+ PopupMenu pm = new PopupMenu("Popup " + i);
+ pm.add(new MenuItem("item 1"));
+ pm.add(new MenuItem("item 2"));
+ add(pm);
+ pm.show(this, e.getX() + i * 5, e.getY() + i * 5);
+ }
+ }
+ super.processMouseEvent(e);
+ }
+ }
+}
diff --git a/test/jdk/java/awt/PopupMenu/PopupMenuCrash.java b/test/jdk/java/awt/PopupMenu/PopupMenuCrash.java
new file mode 100644
index 00000000000..7ba738b21d2
--- /dev/null
+++ b/test/jdk/java/awt/PopupMenu/PopupMenuCrash.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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 java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Label;
+import java.awt.MenuItem;
+import java.awt.PopupMenu;
+
+import java.awt.event.InputEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+/*
+ * @test
+ * @bug 4281273
+ * @summary PopupMenu crashed in Java. Simplified testcase.
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @requires (os.family == "windows")
+ * @run main/manual PopupMenuCrash
+ */
+
+public class PopupMenuCrash {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ This tests a windows specific problem.
+ When you see a frame titled "PopupMenuCrash Test", right-click on it
+ several times for a few seconds. Then wait about 10 seconds before the
+ PopupMenus start to appear. Then dispose them one by one by clicking on them.
+ When PopupMenus do not appear anymore, press Pass.
+ In case of a failure, you'll see a crash.
+ """;
+
+ PassFailJFrame.builder()
+ .title("PopupMenuCrash Instruction")
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .testUI(PopupMenuCrash::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Frame createUI() {
+ final Frame f = new Frame("PopupMenuCrash Test");
+ f.setLayout(new FlowLayout());
+ f.add(new Label("Press right mouse button inside this frame."));
+ f.add(new Label("A pop-up menu should appear."));
+ f.addMouseListener(new MouseAdapter() {
+ PopupMenu popup;
+ boolean firstPress = true;
+
+ @Override
+ public void mousePressed(MouseEvent evt) {
+ if (firstPress) {
+ firstPress = false;
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException ignored) {
+ }
+ }
+
+ if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) {
+ popup = new PopupMenu("Popup Menu Title");
+ MenuItem mi = new MenuItem("MenuItem");
+ popup.add(mi);
+ f.add(popup);
+ popup.show(evt.getComponent(), evt.getX(), evt.getY());
+ }
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent evt) {
+ if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) {
+ if (popup != null) {
+ f.remove(popup);
+ popup = null;
+ }
+ }
+ }
+ });
+
+ f.setSize(400, 350);
+ return f;
+ }
+}
diff --git a/test/jdk/java/awt/PopupMenu/StressTest.java b/test/jdk/java/awt/PopupMenu/StressTest.java
new file mode 100644
index 00000000000..221aa252aa0
--- /dev/null
+++ b/test/jdk/java/awt/PopupMenu/StressTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 1998, 2024, Oracle and/or its affiliates. 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 java.awt.Component;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.MenuItem;
+import java.awt.Panel;
+import java.awt.Point;
+import java.awt.PopupMenu;
+import java.awt.Robot;
+
+import java.awt.event.InputEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+/*
+ * @test
+ * @bug 4083400
+ * @key headful
+ * @summary Tests that excessive popping up and down does not crash or
+ * throw an exception.
+ * @run main StressTest
+ */
+
+public class StressTest {
+ private static Frame fr;
+ private static PopupTestPanel panel;
+
+ private static volatile Point panelCenter;
+
+ public static void main(String[] args) throws Exception {
+ final int REPEAT_COUNT = 5;
+ try {
+ Robot robot = new Robot();
+ robot.setAutoDelay(50);
+ EventQueue.invokeAndWait(StressTest::createAndShowUI);
+ robot.delay(1000);
+
+ EventQueue.invokeAndWait(() -> {
+ Point loc = panel.getLocationOnScreen();
+ Dimension dim = panel.getSize();
+ panelCenter = new Point(loc.x + dim.width / 2, loc.y + dim.height / 2);
+ });
+
+ for (int i = 0; i < REPEAT_COUNT; i++) {
+ robot.mouseMove(panelCenter.x + i * 2, panelCenter.y + i * 2);
+
+ robot.mousePress(InputEvent.BUTTON3_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK);
+
+ robot.mouseMove(panelCenter.x - i * 2, panelCenter.y - i * 2);
+
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+ }
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (fr != null) {
+ fr.dispose();
+ }
+ });
+ }
+ }
+
+ public static void createAndShowUI() {
+ fr = new Frame("PopupMenu Test");
+ panel = new PopupTestPanel();
+ fr.add(panel);
+ fr.setSize(300, 200);
+ fr.setVisible(true);
+ }
+
+ static class PopupTestPanel extends Panel {
+
+ static class Item extends MenuItem {
+ public Item(String text) {
+ super(text);
+ }
+
+ public boolean isEnabled() {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignored) {
+ }
+ return super.isEnabled();
+ }
+ }
+
+ final PopupMenu popup;
+
+ public PopupTestPanel() {
+ popup = new PopupMenu();
+ popup.add(new Item("Soap"));
+ popup.add(new Item("Sponge"));
+ popup.add(new Item("Flannel"));
+ popup.add(new Item("Mat"));
+ popup.add(new Item("Towel"));
+ add(popup);
+ addMouseListener(new MouseAdapter() {
+ @Override
+ public void mousePressed(MouseEvent e) {
+ if (e.isPopupTrigger()) {
+ showPopup(e);
+ }
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ if (e.isPopupTrigger()) {
+ showPopup(e);
+ }
+ }
+
+ private void showPopup(MouseEvent e) {
+ popup.show((Component) e.getSource(), e.getX(), e.getY());
+ }
+ });
+ }
+ }
+}
diff --git a/test/jdk/java/awt/TrayIcon/ClearPrevImageTest.java b/test/jdk/java/awt/TrayIcon/ClearPrevImageTest.java
new file mode 100644
index 00000000000..e97f645bec5
--- /dev/null
+++ b/test/jdk/java/awt/TrayIcon/ClearPrevImageTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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 java.awt.AWTException;
+import java.awt.Color;
+import java.awt.EventQueue;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.RenderingHints;
+import java.awt.SystemTray;
+import java.awt.TrayIcon;
+import java.awt.image.BufferedImage;
+
+import jtreg.SkippedException;
+
+/*
+ * @test
+ * @bug 6267936
+ * @library /java/awt/regtesthelpers /test/lib
+ * @build PassFailJFrame jtreg.SkippedException
+ * @summary Tests that the previous image in TrayIcon is cleared
+ * when a new image is set
+ * @run main/manual ClearPrevImageTest
+ */
+
+public class ClearPrevImageTest {
+ private static SystemTray tray;
+ private static TrayIcon icon;
+ private static final String INSTRUCTIONS = """
+ This test checks that the previous image in TrayIcon is cleared
+ when a new image is set.
+
+ When the test starts, a RED square TrayIcon is added
+ to the SystemTray (also, called Taskbar Status Area in MS Windows,
+ Notification Area in, GNOME and System Tray in KDE).
+
+ You should see it change into YELLOW after 5 seconds.
+ If you still see RED TrayIcon after 5 seconds,
+ press FAIL, otherwise press PASS
+ """;
+
+
+ public static void main(String[] args) throws Exception {
+ if (!SystemTray.isSupported()) {
+ throw new SkippedException("Test not applicable as"
+ + " System Tray not supported");
+ }
+
+ PassFailJFrame passFailJFrame
+ = PassFailJFrame.builder()
+ .title("TrayIcon Change Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .build();
+
+ EventQueue.invokeAndWait(ClearPrevImageTest::createAndShowTrayIcon);
+ try {
+ changeTrayIcon();
+ passFailJFrame.awaitAndCheck();
+ } catch (Exception e) {
+ throw new RuntimeException("Test failed: ", e);
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (tray != null) {
+ tray.remove(icon);
+ }
+ });
+ }
+ }
+
+ private static void createAndShowTrayIcon() {
+ Image img1 = createIcon(Color.RED);
+ tray = SystemTray.getSystemTray();
+ icon = new TrayIcon(img1);
+ icon.setImageAutoSize(true);
+
+ try {
+ tray.add(icon);
+ } catch (AWTException e) {
+ throw new RuntimeException("Error while adding"
+ + " icon to system tray", e);
+ }
+ }
+
+ private static void changeTrayIcon() {
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ Image img2 = createIcon(Color.YELLOW);
+ icon.setImage(img2);
+ }
+
+ private static Image createIcon(Color color) {
+ BufferedImage image = new BufferedImage(16, 16,
+ BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g = image.createGraphics();
+ g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ g.setColor(color);
+ g.fillRect(0, 0, 16, 16);
+ g.dispose();
+ return image;
+ }
+}
diff --git a/test/jdk/java/awt/TrayIcon/FocusLostAfterTrayTest.java b/test/jdk/java/awt/TrayIcon/FocusLostAfterTrayTest.java
new file mode 100644
index 00000000000..bd831ce94e4
--- /dev/null
+++ b/test/jdk/java/awt/TrayIcon/FocusLostAfterTrayTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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 java.awt.AWTException;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.SystemTray;
+import java.awt.TextArea;
+import java.awt.TrayIcon;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.image.BufferedImage;
+
+import jtreg.SkippedException;
+
+/*
+ * @test
+ * @bug 6269309
+ * @library /java/awt/regtesthelpers /test/lib
+ * @build PassFailJFrame jtreg.SkippedException
+ * @summary Tests that focus is transferred properly back
+ * to toplevel after clicking on a tray icon.
+ * @run main/manual FocusLostAfterTrayTest
+ */
+
+public class FocusLostAfterTrayTest {
+ private static SystemTray tray;
+ private static TrayIcon icon;
+
+ private static final String INSTRUCTIONS = """
+ This test checks that focus is transferred properly back
+ to top-level after clicking on a tray icon.
+
+ When the test starts, a Frame with a text area & a RED tray icon
+ are shown. If you don't see a tray icon please make sure that
+ the tray area (also called Taskbar Status Area on MS Windows
+ Notification Area on Gnome or System Tray on KDE) is visible.
+
+ Click with a mouse inside a text area and make sure that it has
+ received input focus. Then click on the tray icon and then back
+ on the text area and verify that it has input focus again. Repeat
+ the last step several times. Ensure that the text area always
+ has the input focus and there are no "FOCUS LOST" event
+ for text area in the log section.
+
+ If above is true, Press PASS, else FAIL.
+ """;
+
+ public static void main(String[] args) throws Exception {
+ if (!SystemTray.isSupported()) {
+ throw new SkippedException("Test not applicable as"
+ + " System Tray not supported");
+ }
+
+ try {
+ PassFailJFrame.builder()
+ .title("FocusLostAfterTrayTest Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .testUI(FocusLostAfterTrayTest::createAndShowTrayIcon)
+ .logArea()
+ .build()
+ .awaitAndCheck();
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (tray != null) {
+ tray.remove(icon);
+ }
+ });
+ }
+ }
+
+ private static Frame createAndShowTrayIcon() {
+ Frame frame = new Frame("FocusLostAfterTrayTest");
+ frame.setBounds(100, 300, 200, 200);
+ frame.setLayout(new BorderLayout());
+ TextArea ta = new TextArea();
+ ta.addFocusListener(new FocusAdapter() {
+ @Override
+ public void focusGained(FocusEvent e) {
+ PassFailJFrame.log("FOCUS GAINED: "
+ + e.getComponent().getClass().toString());
+ }
+ @Override
+ public void focusLost(FocusEvent e) {
+ PassFailJFrame.log("FOCUS LOST !! "
+ + e.getComponent().getClass().toString());
+ }
+ });
+ frame.add(ta);
+
+ BufferedImage image = new BufferedImage(16, 16,
+ BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g = image.createGraphics();
+ g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ g.setColor(Color.RED);
+ g.fillRect(0, 0, 16, 16);
+ g.dispose();
+ tray = SystemTray.getSystemTray();
+ icon = new TrayIcon(image);
+ icon.setImageAutoSize(true);
+
+ try {
+ tray.add(icon);
+ } catch (AWTException e) {
+ throw new RuntimeException("Error while adding"
+ + " icon to system tray", e);
+ }
+ return frame;
+ }
+}
diff --git a/test/jdk/java/awt/TrayIcon/MouseMoveTest.java b/test/jdk/java/awt/TrayIcon/MouseMoveTest.java
new file mode 100644
index 00000000000..51d80ff127b
--- /dev/null
+++ b/test/jdk/java/awt/TrayIcon/MouseMoveTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2011, 2024, Oracle and/or its affiliates. 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 java.awt.AWTException;
+import java.awt.Color;
+import java.awt.EventQueue;
+import java.awt.Graphics;
+import java.awt.SystemTray;
+import java.awt.TrayIcon;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionAdapter;
+import java.awt.image.BufferedImage;
+
+import jtreg.SkippedException;
+
+/*
+ * @test
+ * @bug 6267980
+ * @summary PIT:Spurious MouseMoved events are triggered by Tray Icon
+ * @library /java/awt/regtesthelpers /test/lib
+ * @build PassFailJFrame jtreg.SkippedException
+ * @run main/manual MouseMoveTest
+ */
+
+public class MouseMoveTest {
+ private static SystemTray tray;
+ private static TrayIcon icon;
+ private static final String INSTRUCTIONS = """
+ 1) You will see a tray icon (white square) in notification area,
+ 2) Move mouse pointer to the icon and leave it somewhere inside the icon,
+ 3) Verify that MOUSE_MOVE events are NOT triggered after you have STOPPED
+ moving mouse.
+ 4) If events are still triggered Press FAIL else PASS.
+ """;
+
+ public static void main(String[] args) throws Exception {
+ if (!SystemTray.isSupported()) {
+ throw new SkippedException("Test not applicable as"
+ + " System Tray not supported");
+ }
+
+ PassFailJFrame passFailJFrame
+ = PassFailJFrame.builder()
+ .title("TrayIcon Change Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(45)
+ .logArea()
+ .build();
+
+ try {
+ EventQueue.invokeAndWait(MouseMoveTest::createAndShowTrayIcon);
+ passFailJFrame.awaitAndCheck();
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (tray != null) {
+ tray.remove(icon);
+ }
+ });
+ }
+ }
+
+ private static void createAndShowTrayIcon() {
+ BufferedImage img = new BufferedImage(32, 32,
+ BufferedImage.TYPE_INT_ARGB);
+ Graphics g = img.createGraphics();
+ g.setColor(Color.WHITE);
+ g.fillRect(0, 0, 32, 32);
+ g.dispose();
+
+ tray = SystemTray.getSystemTray();
+ icon = new TrayIcon(img);
+ icon.setImageAutoSize(true);
+
+ icon.addMouseMotionListener(new MouseMotionAdapter() {
+ public void mouseMoved(MouseEvent me){
+ PassFailJFrame.log(me.toString());
+ }
+ });
+
+ try {
+ tray.add(icon);
+ } catch (AWTException e) {
+ throw new RuntimeException("Error while adding"
+ + " icon to system tray", e);
+ }
+ }
+}
diff --git a/test/jdk/java/awt/TrayIcon/TrayIconKeySelectTest.java b/test/jdk/java/awt/TrayIcon/TrayIconKeySelectTest.java
new file mode 100644
index 00000000000..5e41f546382
--- /dev/null
+++ b/test/jdk/java/awt/TrayIcon/TrayIconKeySelectTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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 java.awt.AWTException;
+import java.awt.Color;
+import java.awt.EventQueue;
+import java.awt.Graphics;
+import java.awt.SystemTray;
+import java.awt.TrayIcon;
+import java.awt.image.BufferedImage;
+
+import jtreg.SkippedException;
+
+/*
+ * @test
+ * @bug 6267943
+ * @requires (os.family == "windows")
+ * @library /java/awt/regtesthelpers /test/lib
+ * @build PassFailJFrame jtreg.SkippedException
+ * @summary Tests the possibility of selecting a tray icon with the keyboard.
+ * @run main/manual TrayIconKeySelectTest
+ */
+
+public class TrayIconKeySelectTest {
+ private static SystemTray tray;
+ private static TrayIcon icon;
+ private static final String INSTRUCTIONS = """
+ Tests that TrayIcon is selectable with the keyboard
+ When the test is started you will see three-color icon
+ in the system tray.
+
+ 1. Bring the focus to the icon with TAB. Press ENTER key.
+ - One or more ActionEvent should be generated
+ (see the output area of the test)
+
+ 2. Bring the focus again to the icon. Press SPACE key twice.
+ - One or more ActionEvent should be generated.
+
+ 3. Bring the focus again to the icon. Click on the icon with
+ the LEFT mouse button twice.
+ - One or more ActionEvent should be generated.
+
+ 4. Again bring the focus to the icon. Click on the icon with
+ the LEFT mouse button just once.
+ - NO ActionEvent should be generated.
+
+ 5. Repeat the 4th step with other mouse buttons.
+
+ If all the above are true press PASS, else FAIL
+ """;
+
+ public static void main(String[] args) throws Exception {
+ if (!SystemTray.isSupported()) {
+ throw new SkippedException("Test not applicable as"
+ + " System Tray not supported");
+ }
+ PassFailJFrame passFailJFrame;
+ try {
+ passFailJFrame
+ = PassFailJFrame.builder()
+ .title("TrayIconKeySelectTest Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .logArea()
+ .build();
+
+ EventQueue.invokeAndWait(TrayIconKeySelectTest::createAndShowTrayIcon);
+ passFailJFrame.awaitAndCheck();
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (tray != null) {
+ tray.remove(icon);
+ }
+ });
+ }
+ }
+
+ private static void createAndShowTrayIcon() {
+ BufferedImage im = new BufferedImage(16, 16,
+ BufferedImage.TYPE_INT_ARGB);
+ Graphics gr = im.createGraphics();
+ gr.setColor(Color.white);
+ gr.fillRect(0, 0, 16, 5);
+ gr.setColor(Color.blue);
+ gr.fillRect(0, 5, 16, 10);
+ gr.setColor(Color.red);
+ gr.fillRect(0, 10, 16, 16);
+ gr.dispose();
+
+ tray = SystemTray.getSystemTray();
+ icon = new TrayIcon(im);
+ icon.setImageAutoSize(true);
+ icon.addActionListener(e -> PassFailJFrame.log(e.toString()));
+
+ try {
+ tray.add(icon);
+ } catch (AWTException e) {
+ throw new RuntimeException("Error while adding"
+ + " icon to system tray", e);
+ }
+ }
+}
diff --git a/test/jdk/java/awt/TrayIcon/TrayIconTest.java b/test/jdk/java/awt/TrayIcon/TrayIconTest.java
new file mode 100644
index 00000000000..c78f6c134fe
--- /dev/null
+++ b/test/jdk/java/awt/TrayIcon/TrayIconTest.java
@@ -0,0 +1,613 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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 java.awt.AWTException;
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Checkbox;
+import java.awt.CheckboxGroup;
+import java.awt.Choice;
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.EventQueue;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Graphics2D;
+import java.awt.GridLayout;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Label;
+import java.awt.MenuItem;
+import java.awt.Panel;
+import java.awt.PopupMenu;
+import java.awt.RenderingHints;
+import java.awt.SystemTray;
+import java.awt.TextField;
+import java.awt.Toolkit;
+import java.awt.TrayIcon;
+import java.awt.TrayIcon.MessageType;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionAdapter;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeEvent;
+import java.util.HashMap;
+import java.util.Map;
+import jtreg.SkippedException;
+
+/*
+ * @test
+ * @key headful
+ * @bug 4310333
+ * @library /java/awt/regtesthelpers /test/lib
+ * @build PassFailJFrame jtreg.SkippedException
+ * @summary A unit test for TrayIcon RFE
+ * @run main/manual TrayIconTest
+ */
+
+public class TrayIconTest {
+ private static SystemTray tray;
+ static Frame frame = new Frame("TrayIcon Test");
+ private static final String INSTRUCTIONS = """
+ The test frame contains CheckboxGroup of tray icons.
+ A selected checkbox represents the TrayIcon (or null
+ TrayIcon) whose functionality is currently tested.
+
+ If you are under Linux make sure your Application Panel has
+ System Tray (on Gnome it is called Notification Area).
+
+ Perform all the cases (1-7) documented below.
+
+ CASE 1: Testing ADD/REMOVE/PropertyChange functionality.
+ --------------------------------------------------------
+ 1. Select null TrayIcon and pressAdd button:
+ - NullPointerException should be thrown.
+ 2. Select some of the valid TrayIcons and press Add button:
+ - The selected TrayIcon should appear in the SystemTray.
+ - PropertyChangeEvent should be fired (the property is
+ an array of TrayIcons added to the system tray).
+ 3. Press Add button again:
+ - IllegalArgumentException should be thrown.
+ - No PropertyChangeEvent should be fired.
+ 4. Press Remove button:
+ - The TrayIcon should disappear from the SystemTray.
+ - PropertyChangeEvent should be fired.
+ 5. Press Remove button again:
+ - It should have no effect.
+ - No PropertyChangeEvent should be fired.
+ 6. Add all the valid TrayIcons (by selecting everyone and pressing Add
+ button):
+ - All the TrayIcons should appear in the SystemTray.
+ - PropertyChangeEvent should be fired on each adding.
+ 7. Remove all the TrayIcons (again by selecting everyone and pressing
+ Remove):
+ - All the TrayIcons should disappear from the SystemTray.
+ - PropertyChangeEvent should be fired on each removing.
+ 8. Not for Windows! Remove the system tray (Notification Area) from
+ the desktop. Try to add some valid TrayIcon:
+ - AWTException should be thrown.
+ - No PropertyChangeEvent should be fired.
+ 9. Not for Windows! Add the system tray back to the desktop. Add all the
+ valid TrayIcons:
+ - All the TrayIcons should appear in the system tray.
+ - PropertyChangeEvent should be fired on each adding.
+ 11. Not for Windows! Remove the system tray from the desktop:
+ - All the TrayIcons should disappear.
+ - PropertyChangeEvent should be fired for each TrayIcon
+ removal.
+ - PropertyChangeEvent should be fired for SystemTray removal.
+ 12. Add the system tray and go to the next step.
+ - All the TrayIcons should appear again.
+ - PropertyChangeEvent should be fired for SystemTray addition.
+ - PropertyChangeEvent shouldn't be fired for TrayIcon removal.
+
+ CASE 2: Testing RESIZE functionality.
+ -------------------------------------
+ 1. Select some of the TrayIcons and add it. Then press resize button:
+ - The TrayIcon selected should be resized to fit the area it occupies.
+ 2. Press resize button again:
+ - The TrayIcon should be resized to the original size.
+ 3. Repeat the 1-2 steps for other TrayIcons:
+ - The TrayIcons should be resized appropriately.
+
+ CASE 3: Testing EVENTS functionality
+ ---------------------------------
+ 1. Select some of the TrayIcons and add it. Select MouseEvent from the
+ group of checkboxes at the top-right of the test frame.
+ Click on the TrayIcon in the SystemTray:
+ - MOUSE_PRESSED MOUSE_RELEASED and MOUSE_CLICKED events should be
+ generated.
+ 2. Press mouse inside the TrayIcon dragging mouse and releasing it.
+ - Make sure that MOUSE_CLICKED event is not triggered.
+ 3. Click on the TrayIcon with different modification keys:
+ - there should be appropriate modifiers in the events.
+ 4. Keep clicking on the TrayIcon:
+ - there should be correct absolute coordinates in the events.
+ 5. Only for Windows! Focus the system tray using keyboard:
+ - press WIN key once to bring up the start menu then press ESC once to
+ close the menu the focus should be on the start button
+ - press TAB key for several times until you focus on the system
+ tray then use ARROW keys to move to the TrayIcon
+ - press ENTER or SPACE should trigger ACTION_PERFORMED message
+ make sure that mouse events are not triggered.
+ 6. Select MouseMotionEvent checkbox. Move mouse over the TrayIcon:
+ - MOUSE_MOVED event should be generated. It should contain
+ correct coordinates.
+ 7. Deselect both the checkboxes and then select AWTEventListener.
+ Click on the TrayIcon and then move mouse over it:
+ - Appropriate mouse events should be generated (catched by the
+ AWTEventListener).
+ 8. Deselect all the checkboxes and go to the following step.
+
+ CASE 4: Testing DISPLAY MESSAGE functionality.
+ ----------------------------------------------
+ 1. Select some of the TrayIcons and add it. Then press Display message
+ button:
+ - A balloon message should appear near the TrayIcon.
+ 2. After the message is displayed wait for some period:
+ - The message window should be closed automatically.
+ 3. Display the message again. Close it by pressing X in its top-right
+ corner:
+ - The message window should be closed immediately.
+ 4. Display the message again. Click inside it:
+ - The message should be closed an ACTION_PERFORMED event should be
+ generated with correct information and an Ok dialog should appear.
+ Close the dialog.
+ 5. Select a message type from the Type choice and display the message
+ again:
+ - It should contain an icon appropriate to the message type selected
+ or no icon if NONE is selected.
+ 6. Change the content of the Message and Caption text fields and
+ display the message:
+ - The message content should be changed in the accordance with the text
+ typed.
+ 7. Not for Windows! Type some too long or too short text for the Caption
+ and Message:
+ - The message should process the text correctly. The long text should
+ be cut.
+ 8. Not for Windows! Type null in the Message text field and display
+ the message:
+ - The message body should contain no text.
+ 9. Type null in the Caption text field and display the message:
+ - The message caption should contain no text.
+ 10. Type null in the both Message and Caption fields and display
+ the message:
+ - NullPointerException should be generated and no message should be
+ displayed.
+ 11. Try to hide the taskbar. Click Display message for several times.
+ Then restore the taskbar. Click on the TrayIcon:
+ - No message should appear.
+ Try to display the message once more:
+ - It should appear appropriately.
+ 12. Try to display the message for other TrayIcons:
+ - The messages should be displayed appropriately.
+
+ CASE 5: Testing POPUP MENU functionality.
+ -----------------------------------------
+ 1. Add some TrayIcon to the system tray. Press Set button in the
+ Popup menu test area. Trigger the popup menu for the TrayIcon with
+ the mouse:
+ - A popup menu should appear. Make sure it behaves properly.
+ - Make sure the 'duke.gif' image is animated while the popup menu is shown.
+ 2. Press Remove button for the popup menu and try to trigger it again:
+ - No popup menu should appear.
+ 3. Perform 1-2 steps for other TrayIcons:
+ - Make sure the popup menu behaves properly.
+ 4. Add more than one TrayIcons to the system tray. Press Set button in
+ the PopupMenu test area for some of the TrayIcon added. Trigger
+ the popup menu for this TrayIcon:
+ - A popup menu should appear properly.
+ 5. Try to set the popup menu to the same TrayIcon again:
+ - It should have no effect
+ 6. Try to set the popup menu for other TrayIcons you've added to the system
+ tray:
+ - for each one IllegalArgumentException should be thrown.
+
+ CASE 6: Testing TOOLTIP functionality.
+ --------------------------------------
+ 1. Type something in the Tooltip text field and press Set button.
+ Then move mouse cursor over the TrayIcon and wait for a second:
+ - A tooltip should appear containing the text typed.
+ 2. Show a tooltip again and keep your mouse over the TrayIcon for some period:
+ - The tooltip should disappear automatically.
+ 3. Show a tooltip again and leave the TrayIcon:
+ - The tooltip should disappear immediately.
+ 4. Type null in the Tooltip field and press set then move your
+ mouse to the SystemTray:
+ - The tooltip shouldn't appear.
+ 5. Type something too long in the Tooltip field and show the tooltip:
+ - The tooltip text should be cut.
+
+ CASE 7: Testing ACTION functionality.
+ -------------------------------------
+ 1. Add some TrayIcon to the system tray. Double click it with the left mouse
+ button:
+ - An ACTION_PERFORMED event should be generated.
+ 2. Double click the TrayIcon with the left mouse button several times:
+ - Several ACTION_PERFORMED events should be generated
+ - Make sure that the time-stamp of each event ('when' field) is increased.
+
+ If all the above cases work as expected Press PASS else FAIL.
+ """;
+
+ public static void main(String[] args) throws Exception {
+ if (!SystemTray.isSupported()) {
+ throw new SkippedException("Test not applicable as"
+ + " System Tray not supported");
+ }
+ try {
+ PassFailJFrame.builder()
+ .title("TrayIconTest Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(50)
+ .rows(40)
+ .testUI(TrayIconTest::createAndShowUI)
+ .logArea(10)
+ .build()
+ .awaitAndCheck();
+
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (tray != null) {
+ //Remove any remaining tray icons before ending the test.
+ TrayIcon[] icons = tray.getTrayIcons();
+ for (TrayIcon icon : icons) {
+ tray.remove(icon);
+ }
+ }
+ });
+ }
+ }
+
+ private static Frame createAndShowUI() {
+ final TrayIconControl ctrl = new TrayIconControl();
+ frame.setLayout(new BorderLayout());
+ frame.add(ctrl.cont, BorderLayout.CENTER);
+ frame.setBackground(Color.LIGHT_GRAY);
+
+ frame.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ ctrl.dispose();
+ }
+ });
+
+ frame.pack();
+ return frame;
+ }
+
+ private static class TrayIconControl {
+ final String RED_ICON = "RED ICON";
+ final String BLUE_ICON = "BLUE ICON";
+ final String GREEN_ICON = "GREEN ICON";
+
+ CheckboxGroup cbg = new CheckboxGroup();
+ Button addButton = new PackedButton(" Add ");
+ Button remButton = new PackedButton("Remove");
+ Button resizeButton = new PackedButton("Resize");
+ Button balloonButton = new PackedButton("Display message");
+ Choice balloonChoice = new Choice();
+ String[] balloonTypes = new String[] { "ERROR", "WARNING", "INFO", "NONE" };
+
+ TextField balloonText = new TextField(
+ "A TrayIcon can generate various MouseEvents and"
+ + " supports adding corresponding listeners to receive"
+ + " notification of these events. TrayIcon processes"
+ + " some of the events by itself. For example,"
+ + " by default, when the right-mouse click", 70);
+ TextField balloonCaption = new TextField("TrayIcon", 70);
+
+ MessageType[] typeArr = new MessageType[] { MessageType.ERROR, MessageType.WARNING,
+ MessageType.INFO, MessageType.NONE };
+ Checkbox mouseListenerCbox = new Checkbox("MouseEvent");
+ Checkbox motionListenerCbox = new Checkbox(" MouseMotionEvent");
+ Checkbox awtListenerCbox = new Checkbox(" AWTEventListener");
+ TextField tipText = new TextField("TrayIcon", 50);
+ Button tipButton = new PackedButton("Set");
+ Button setPopupButton = new PackedButton("Set");
+ Button remPopupButton = new PackedButton("Remove");
+
+ PopupMenu popupMenu = new PopupMenu();
+
+ Map resToObjMap = new HashMap<>();
+
+ Container cont = new Container();
+
+ TrayIconControl() {
+ Toolkit.getDefaultToolkit().addAWTEventListener(e -> {
+ if (e.getSource() instanceof TrayIcon && awtListenerCbox.getState()) {
+ PassFailJFrame.log(e.toString());
+ }
+ }, MouseEvent.MOUSE_EVENT_MASK | MouseEvent.MOUSE_MOTION_EVENT_MASK |
+ ActionEvent.ACTION_EVENT_MASK);
+
+ cont.setLayout(new GridLayout(4, 1));
+
+ Container raw1 = new Container();
+ raw1.setLayout(new GridLayout(1, 4));
+ cont.add(raw1);
+
+ InsetsPanel cbgPanel = new InsetsPanel();
+ cbgPanel.setLayout(new GridLayout(4, 1));
+ Checkbox nullCbox = new Checkbox("null", cbg, true);
+ Checkbox redCbox = new Checkbox(RED_ICON, cbg, false);
+ Checkbox blueCbox = new Checkbox(BLUE_ICON, cbg, false);
+ Checkbox greenCbox = new Checkbox(GREEN_ICON, cbg, false);
+ cbgPanel.add(nullCbox);
+ cbgPanel.add(redCbox);
+ cbgPanel.add(blueCbox);
+ cbgPanel.add(greenCbox);
+ cbgPanel.addTo(raw1);
+
+ InsetsPanel addremPanel = new InsetsPanel();
+ addremPanel.setLayout(new BorderLayout());
+ addremPanel.add(addButton.getParent(), BorderLayout.NORTH);
+ addremPanel.add(remButton.getParent(), BorderLayout.SOUTH);
+ addremPanel.addTo(raw1);
+
+ InsetsPanel resizePanel = new InsetsPanel();
+ resizePanel.add(resizeButton);
+ resizePanel.addTo(raw1);
+
+ InsetsPanel lstPanel = new InsetsPanel();
+ lstPanel.setLayout(new GridLayout(3, 1));
+ lstPanel.add(mouseListenerCbox);
+ lstPanel.add(motionListenerCbox);
+ lstPanel.add(awtListenerCbox);
+ lstPanel.addTo(raw1);
+
+ Container raw2 = new Container();
+ raw2.setLayout(new BorderLayout());
+ cont.add(raw2);
+
+ InsetsPanel balloonPanel = new InsetsPanel();
+ balloonPanel.setLayout(new BorderLayout());
+ balloonPanel.add(balloonButton.getParent(), BorderLayout.NORTH);
+ Container bc = new Container();
+ bc.setLayout(new FlowLayout());
+ bc.add(new Label(" Type:"));
+ bc.add(balloonChoice);
+ balloonPanel.add(bc, BorderLayout.SOUTH);
+ balloonPanel.addTo(raw2, BorderLayout.WEST);
+
+ InsetsPanel blnTextPanel = new InsetsPanel();
+ blnTextPanel.setLayout(new GridLayout(2, 2));
+ Container c1 = new Panel();
+ c1.setLayout(new FlowLayout());
+ blnTextPanel.add(c1);
+ c1.add(new Label("Message:"));
+ c1.add(balloonText);
+
+ Container c2 = new Panel();
+ c2.setLayout(new FlowLayout());
+ blnTextPanel.add(c2);
+ c2.add(new Label("Caption:"));
+ c2.add(balloonCaption);
+ blnTextPanel.addTo(raw2, BorderLayout.CENTER);
+
+
+ Container raw3 = new Container();
+ raw3.setLayout(new BorderLayout());
+ cont.add(raw3);
+
+ InsetsPanel popupPanel = new InsetsPanel();
+ popupPanel.setLayout(new FlowLayout());
+ popupPanel.add(new Label("Popup menu:"));
+ popupPanel.add(setPopupButton);
+ popupPanel.add(remPopupButton);
+ popupPanel.addTo(raw3);
+
+
+ Container raw4 = new Container();
+ raw4.setLayout(new BorderLayout());
+ cont.add(raw4);
+
+ InsetsPanel tipPanel = new InsetsPanel();
+ tipPanel.setLayout(new FlowLayout());
+ tipPanel.add(new Label("Tooltip:"));
+ tipPanel.add(tipText);
+ tipPanel.add(tipButton);
+ tipPanel.addTo(raw4);
+
+ addButton.addActionListener(e -> {
+ try {
+ tray.add(getCurIcon());
+ } catch (NullPointerException npe) {
+ if (npe.getMessage() == null) {
+ PassFailJFrame.log("Probably wrong path to the images.");
+ throw npe; // if wrong images path was set
+ }
+ PassFailJFrame.log(npe.toString());
+ } catch (IllegalArgumentException iae) {
+ PassFailJFrame.log(iae.toString());
+ } catch (AWTException ise) {
+ PassFailJFrame.log(ise.toString());
+ }
+ });
+ remButton.addActionListener(e -> tray.remove(getCurIcon()));
+
+ resizeButton.addActionListener(
+ e -> getCurIcon().setImageAutoSize(!getCurIcon().isImageAutoSize()));
+
+ balloonButton.addActionListener(e -> {
+ String text = null, caption = null;
+ if (balloonText.getText().compareToIgnoreCase("null") != 0) {
+ text = balloonText.getText();
+ }
+ if (balloonCaption.getText().compareToIgnoreCase("null") != 0) {
+ caption = balloonCaption.getText();
+ }
+ try {
+ getCurIcon().displayMessage(caption, text, typeArr[balloonChoice.getSelectedIndex()]);
+ } catch (NullPointerException npe) {
+ PassFailJFrame.log(npe.toString());
+ }
+ });
+
+ tipButton.addActionListener(e -> {
+ String tip = null;
+ if (tipText.getText().compareToIgnoreCase("null") != 0) {
+ tip = tipText.getText();
+ }
+ getCurIcon().setToolTip(tip);
+ });
+
+ setPopupButton.addActionListener(e -> {
+ try {
+ getCurIcon().setPopupMenu(popupMenu);
+ } catch (IllegalArgumentException iae) {
+ PassFailJFrame.log(iae.toString());
+ }
+ });
+
+ remPopupButton.addActionListener(e -> getCurIcon().setPopupMenu(null));
+ for (String s: balloonTypes) {
+ balloonChoice.add(s);
+ }
+
+ init();
+ }
+
+ void init() {
+ tray = SystemTray.getSystemTray();
+ tray.addPropertyChangeListener("trayIcons",
+ e -> printPropertyChangeEvent(e));
+
+ tray.addPropertyChangeListener("systemTray",
+ e -> printPropertyChangeEvent(e));
+
+ configureTrayIcon(RED_ICON);
+ configureTrayIcon(BLUE_ICON);
+ configureTrayIcon(GREEN_ICON);
+
+ for (String s: balloonTypes) {
+ popupMenu.add(new MenuItem(s));
+ }
+ }
+
+ void printPropertyChangeEvent(PropertyChangeEvent e) {
+ String name = e.getPropertyName();
+ Object oldValue = e.getOldValue();
+ Object newValue = e.getNewValue();
+
+ PassFailJFrame.log("PropertyChangeEvent[name=" + name
+ + ",oldValue=" + oldValue + ",newValue=" + newValue + "]");
+ }
+
+ void configureTrayIcon(String icon) {
+ Color color = Color.WHITE;
+ switch (icon) {
+ case "RED ICON" -> color = Color.RED;
+ case "BLUE ICON" -> color = Color.BLUE;
+ case "GREEN ICON" -> color = Color.GREEN;
+ }
+ Image image = createIcon(color);
+ TrayIcon trayIcon = new TrayIcon(image);
+
+ trayIcon.addMouseListener(new MouseAdapter() {
+ public void mousePressed(MouseEvent e) {
+ if (mouseListenerCbox.getState())
+ PassFailJFrame.log(e.toString());
+ }
+ public void mouseReleased(MouseEvent e) {
+ if (mouseListenerCbox.getState())
+ PassFailJFrame.log(e.toString());
+ }
+ public void mouseClicked(MouseEvent e) {
+ if (mouseListenerCbox.getState())
+ PassFailJFrame.log(e.toString());
+ }
+ });
+ trayIcon.addMouseMotionListener(new MouseMotionAdapter() {
+ public void mouseMoved(MouseEvent e) {
+ if (motionListenerCbox.getState())
+ PassFailJFrame.log(e.toString());
+ }
+ });
+ trayIcon.addActionListener(e -> PassFailJFrame.log(e.toString()));
+
+ resToObjMap.remove(icon);
+ resToObjMap.put(icon, trayIcon);
+ }
+
+ String getCurImgName() {
+ return cbg.getSelectedCheckbox().getLabel();
+ }
+
+ TrayIcon getCurIcon() {
+ return resToObjMap.get(getCurImgName());
+ }
+
+ public void dispose() {
+ tray.remove(getCurIcon());
+ }
+
+ private static Image createIcon(Color color) {
+ BufferedImage image = new BufferedImage(16, 16,
+ BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g = image.createGraphics();
+ g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ g.setColor(color);
+ g.fillRect(0, 0, 16, 16);
+ g.dispose();
+ return image;
+ }
+
+ }
+
+ private static class InsetsPanel extends Panel {
+ Container parent = new Container() {
+ public Insets getInsets() {
+ return new Insets(2, 2, 2, 2);
+ }
+ };
+
+ InsetsPanel() {
+ parent.setLayout(new BorderLayout());
+ setBackground(new Color(240, 240, 240));
+ }
+
+ void addTo(Container c) {
+ parent.add(this);
+ c.add(parent);
+ }
+
+ void addTo(Container c, String pos) {
+ parent.add(this);
+ c.add(parent, pos);
+ }
+ }
+
+ private static class PackedButton extends Button {
+ Container parent = new Container();
+ PackedButton(String l) {
+ super(l);
+ parent.setLayout(new FlowLayout());
+ parent.add(this);
+ }
+ }
+}
+
diff --git a/test/jdk/java/awt/Window/BadConfigure/BadConfigure.java b/test/jdk/java/awt/Window/BadConfigure/BadConfigure.java
new file mode 100644
index 00000000000..a25ab9b91b9
--- /dev/null
+++ b/test/jdk/java/awt/Window/BadConfigure/BadConfigure.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6261336
+ * @summary Tests that Choice inside ScrollPane opens at the right location
+ * after resize
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual BadConfigure
+*/
+
+import java.awt.BorderLayout;
+import java.awt.Choice;
+import java.awt.Frame;
+
+public class BadConfigure
+{
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ Please resize the BadConfigure window using the left border.
+ Now click on choice. Its popup will be opened.
+ Please verify that the popup is opened right under the choice.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(35)
+ .testUI(initialize())
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Frame initialize() {
+ Frame f = new Frame("BadConfigure");
+ f.setLayout(new BorderLayout());
+ Choice ch = new Choice();
+ f.add(ch, BorderLayout.NORTH);
+ ch.add("One");
+ ch.add("One");
+ ch.add("One");
+ ch.add("One");
+ ch.add("One");
+ ch.add("One");
+ f.setSize(200, 200);
+ f.validate();
+ return f;
+ }
+}
diff --git a/test/jdk/java/awt/Window/InvalidFocusLostEventTest/InvalidFocusLostEventTest.java b/test/jdk/java/awt/Window/InvalidFocusLostEventTest/InvalidFocusLostEventTest.java
new file mode 100644
index 00000000000..569d59f146d
--- /dev/null
+++ b/test/jdk/java/awt/Window/InvalidFocusLostEventTest/InvalidFocusLostEventTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2001, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4397883
+ * @summary Tests that non-focusable Window doesn't grab focus
+ * @key headful
+ * @run main InvalidFocusLostEventTest
+ */
+
+import java.awt.Button;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.KeyboardFocusManager;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.InputEvent;
+
+public class InvalidFocusLostEventTest implements ActionListener {
+ private static Frame f;
+ private static Button b;
+ private static KeyboardFocusManager fm;
+ private static volatile Point bp;
+ private static volatile int width, height;
+ private static Robot robot;
+
+ public static void main(String[] args) throws Exception {
+ try {
+ InvalidFocusLostEventTest test = new InvalidFocusLostEventTest();
+ EventQueue.invokeAndWait(() -> test.createUI());
+ runTest();
+ // we should check focus after all events are processed,
+ // since focus transfers are asynchronous
+ robot.waitForIdle();
+ if (fm.getFocusOwner() != b) {
+ throw new RuntimeException("Failed: focus was lost");
+ }
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (f != null) {
+ f.dispose();
+ }
+ });
+ }
+ }
+
+ private void createUI() {
+ f = new Frame("InvalidFocusLostEventTest");
+ b = new Button("Press me");
+ fm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+ b.addActionListener(this);
+ f.add(b);
+ f.pack();
+ f.setLocationRelativeTo(null);
+ f.setVisible(true);
+ }
+
+ private static void runTest() throws Exception {
+ robot = new Robot();
+ robot.setAutoDelay(100);
+ robot.setAutoWaitForIdle(true);
+ EventQueue.invokeAndWait(() -> {
+ bp = b.getLocationOnScreen();
+ width = b.getWidth();
+ height = b.getHeight();
+ });
+ robot.mouseMove(bp.x + width / 2, bp.y + height / 2 );
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+ }
+
+ public void actionPerformed(ActionEvent ev) {
+ // pop up a non-focusable window
+ Window win = new Window(f);
+ win.setFocusableWindowState(false);
+ }
+}
diff --git a/test/jdk/java/awt/Window/LocationByPlatform/TestLocationByPlatform.java b/test/jdk/java/awt/Window/LocationByPlatform/TestLocationByPlatform.java
new file mode 100644
index 00000000000..33b9d048ef2
--- /dev/null
+++ b/test/jdk/java/awt/Window/LocationByPlatform/TestLocationByPlatform.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6318630
+ * @summary Test that location by platform works
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual TestLocationByPlatform
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Canvas;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Graphics;
+
+public class TestLocationByPlatform {
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ You should see two frames. One has locationByPlatform set, it
+ should be displayed somewhere on the screen most probably without
+ intersecting other Frames or stacked over normal frame with some
+ offset. Another has its location explicitly set to (0, 450).
+ Please verify that the frames are located correctly on the screen.
+
+ Also verify that the picture inside of frames looks the same
+ and consists of red descending triangle occupying exactly the bottom
+ half of the frame. Make sure that there is a blue rectangle exactly
+ surrounding the client area of frame with no pixels between it and
+ the frame's decorations. Press Pass if this all is true,
+ otherwise press Fail.
+ """;
+
+ PassFailJFrame passFailJFrame = PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows(13)
+ .columns(40)
+ .build();
+ EventQueue.invokeAndWait(TestLocationByPlatform::createUI);
+ passFailJFrame.awaitAndCheck();
+ }
+ private static void createUI() {
+ Frame frame = new Frame("Normal");
+ frame.setLocation(0, 450);
+ Canvas c = new MyCanvas();
+ frame.add(c, BorderLayout.CENTER);
+ frame.pack();
+ PassFailJFrame.addTestWindow(frame);
+ frame.setVisible(true);
+
+ frame = new Frame("Location by platform");
+ frame.setLocationByPlatform(true);
+ c = new MyCanvas();
+ frame.add(c, BorderLayout.CENTER);
+ frame.pack();
+ PassFailJFrame.addTestWindow(frame);
+ frame.setVisible(true);
+ }
+
+ static class MyCanvas extends Canvas {
+ @Override
+ public Dimension getPreferredSize() {
+ return new Dimension(400, 400);
+ }
+
+ @Override
+ public void paint(Graphics g) {
+ g.setColor(Color.red);
+ for (int i = 399; i >= 0; i--) {
+ g.drawLine(400 - i - 1, 400 - i - 1,
+ 400 - i - 1, 399);
+ }
+ g.setColor(Color.blue);
+ g.drawLine(0, 0, 399, 0);
+ g.drawLine(0, 0, 0, 399);
+ g.drawLine(0, 399, 399, 399);
+ g.drawLine(399, 0, 399, 399);
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Window/LocationByPlatformWithControls/TestLocationByPlatformWithControls.java b/test/jdk/java/awt/Window/LocationByPlatformWithControls/TestLocationByPlatformWithControls.java
new file mode 100644
index 00000000000..bfdba97e4eb
--- /dev/null
+++ b/test/jdk/java/awt/Window/LocationByPlatformWithControls/TestLocationByPlatformWithControls.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4102292
+ * @summary Tests that location by platform works with other APIs
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual TestLocationByPlatformWithControls
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Checkbox;
+import java.awt.Frame;
+import java.awt.Label;
+import java.awt.Panel;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.util.Vector;
+
+public class TestLocationByPlatformWithControls extends Frame
+ implements ActionListener, ItemListener {
+ Panel northP;
+ Panel centerP;
+ Checkbox undecoratedCB;
+ Checkbox defaultLocationCB;
+ Checkbox visibleCB;
+ Checkbox iconifiedCB;
+ Checkbox maximizedCB;
+ Button createB;
+ Button packB;
+ Button moveB;
+ Button resizeB;
+ Button reshapeB;
+ Button disposeB;
+ Vector frames;
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ This test is to check that LocationByPlatform works with other
+ controls API.
+ 1) Create New Frame by clicking on "Create" Button in
+ "TestLocationByPlatformWithControls" window.
+ 2) Initially this Frame will not be visible, Click on checkbox
+ "LocationByPlatform" to set default platform location for the frame
+ and then click on checkbox "Visible" to see that Frame is displayed
+ at default offsets.
+ 3) Now you can play with different controls like Iconified,
+ Maximized, Pack, Move, Resize and Reshape to verify that these
+ controls work properly with the Frame.
+ 4) At the end dispose the Frame by clicking on "Dispose" button.
+ 5) Also we can do verify this for Undecorated Frame but for that we
+ need to follow same steps but in step 2 before we click on checkbox
+ "Visible", select "Undecorated" checkbox along with
+ "LocationByPlatform".
+ 6) If everything works properly test is passed, otherwise failed.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .testUI(TestLocationByPlatformWithControls::new)
+ .logArea(4)
+ .build()
+ .awaitAndCheck();
+ }
+
+ public TestLocationByPlatformWithControls() {
+ northP = new Panel();
+ centerP = new Panel();
+
+ undecoratedCB = new Checkbox("Undecorated");
+ defaultLocationCB = new Checkbox("LocationByPlatform");
+ visibleCB = new Checkbox("Visible");
+ iconifiedCB = new Checkbox("Iconified");
+ maximizedCB = new Checkbox("Maximized");
+
+ createB = new Button("Create");
+ packB = new Button("Pack");
+ moveB = new Button("Move");
+ resizeB = new Button("Resize");
+ reshapeB = new Button("Reshape");
+ disposeB = new Button("Dispose");
+
+ frames = new Vector(10);
+ this.setTitle("TestLocationByPlatformWithControls");
+ this.setLayout(new BorderLayout());
+ this.add(northP, BorderLayout.NORTH);
+
+ northP.add(new Label("New Frame"));
+
+ createB.addActionListener(this);
+ northP.add(createB);
+
+ centerP.setEnabled(false);
+ this.add(centerP, BorderLayout.CENTER);
+
+ centerP.add(new Label("Last Frame"));
+
+ centerP.add(defaultLocationCB);
+ defaultLocationCB.addItemListener(this);
+
+ centerP.add(undecoratedCB);
+ undecoratedCB.addItemListener(this);
+
+ centerP.add(iconifiedCB);
+ iconifiedCB.addItemListener(this);
+
+ centerP.add(maximizedCB);
+ maximizedCB.addItemListener(this);
+
+ centerP.add(visibleCB);
+ visibleCB.addItemListener(this);
+
+ packB.addActionListener(this);
+ centerP.add(packB);
+
+ moveB.addActionListener(this);
+ centerP.add(moveB);
+
+ resizeB.addActionListener(this);
+ centerP.add(resizeB);
+
+ reshapeB.addActionListener(this);
+ centerP.add(reshapeB);
+
+ disposeB.addActionListener(this);
+ centerP.add(disposeB);
+ this.pack();
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource() == createB) {
+ Frame frame = new Frame();
+ frame.setSize(200, 200);
+ frames.add(frame);
+ updateControls(frame);
+ Panel panel = new Panel();
+ frame.add(panel);
+ panel.add(new Button ("Test Button"));
+ panel.add(new Button ("Test Button 1"));
+ panel.add(new Button ("Test Button 2"));
+ panel.add(new Button ("Test Button 3"));
+ centerP.setEnabled(true);
+ return;
+ }
+
+ if (frames.isEmpty()) {
+ return;
+ }
+
+ Frame last = (Frame)frames.lastElement();
+
+ if (e.getSource() == packB) {
+ last.pack();
+ } else
+ if (e.getSource() == moveB) {
+ int x = (int)(Math.random() * 200);
+ int y = (int)(Math.random() * 200);
+ last.setLocation(x, y);
+ } else
+ if (e.getSource() == resizeB) {
+ int w = (int)(Math.random() * 200);
+ int h = (int)(Math.random() * 200);
+ last.setSize(w, h);
+ } else
+ if (e.getSource() == reshapeB) {
+ int x = (int)(Math.random() * 200);
+ int y = (int)(Math.random() * 200);
+ int w = (int)(Math.random() * 200);
+ int h = (int)(Math.random() * 200);
+ last.setBounds(x, y, w, h);
+ } else
+ if (e.getSource() == disposeB) {
+ last.dispose();
+ frames.remove(frames.size() - 1);
+ if (frames.isEmpty()) {
+ updateControls(null);
+ centerP.setEnabled(false);
+ return;
+ }
+ last = (Frame)frames.lastElement();
+ }
+ updateControls(last);
+ }
+
+ public void updateControls(Frame f) {
+ undecoratedCB.setState(f != null ?
+ f.isUndecorated() : false);
+ defaultLocationCB.setState(f != null ?
+ f.isLocationByPlatform() : false);
+ visibleCB.setState(f != null ?
+ f.isVisible() : false);
+ iconifiedCB.setState(f != null ?
+ (f.getExtendedState() & Frame.ICONIFIED) != 0 : false);
+ maximizedCB.setState(f != null ?
+ (f.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 : false);
+ }
+
+ public void itemStateChanged(ItemEvent e) {
+ Frame last = (Frame)frames.lastElement();
+ try {
+ boolean state = e.getStateChange() == ItemEvent.SELECTED;
+ if (e.getSource() == visibleCB) {
+ last.setVisible(state);
+ } else
+ if (e.getSource() == defaultLocationCB) {
+ last.setLocationByPlatform(state);
+ } else
+ if (e.getSource() == undecoratedCB) {
+ last.setUndecorated(state);
+ } else
+ if (e.getSource() == iconifiedCB) {
+ if (state) {
+ last.setExtendedState(last.getExtendedState() |
+ Frame.ICONIFIED);
+ } else {
+ last.setExtendedState(last.getExtendedState() &
+ ~Frame.ICONIFIED);
+ }
+ } else
+ if (e.getSource() == maximizedCB) {
+ if (state) {
+ last.setExtendedState(last.getExtendedState() |
+ Frame.MAXIMIZED_BOTH);
+ } else {
+ last.setExtendedState(last.getExtendedState() &
+ ~Frame.MAXIMIZED_BOTH);
+ }
+ }
+ } catch (Throwable ex) {
+ PassFailJFrame.log(ex.getMessage());
+ } finally {
+ updateControls(last);
+ }
+ }
+
+ @Override
+ public void dispose() {
+ while (!frames.isEmpty()) {
+ Frame last = (Frame)frames.lastElement();
+ last.dispose();
+ frames.remove(frames.size() - 1);
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Window/NoResizeEvent/NoResizeEvent.java b/test/jdk/java/awt/Window/NoResizeEvent/NoResizeEvent.java
new file mode 100644
index 00000000000..50b264acde9
--- /dev/null
+++ b/test/jdk/java/awt/Window/NoResizeEvent/NoResizeEvent.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4942457
+ * @key headful
+ * @summary Verifies that filtering of resize events on native level works.
+ * I.E.after Frame is shown no additional resize events are generated.
+ * @library /java/awt/patchlib ../../regtesthelpers
+ * @build java.desktop/java.awt.Helper
+ * @build Util
+ * @run main NoResizeEvent
+ */
+
+import test.java.awt.regtesthelpers.Util;
+
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+
+public class NoResizeEvent {
+ //Mutter can send window insets too late, causing additional resize events.
+ private static final boolean IS_MUTTER = Util.getWMID() == Util.MUTTER_WM;
+ private static final int RESIZE_COUNT_LIMIT = IS_MUTTER ? 5 : 3;
+ private static Frame frame;
+ static int resize_count = 0;
+
+ public static void main(String[] args) throws Exception {
+ try {
+ EventQueue.invokeAndWait(() -> createUI());
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (frame != null) {
+ frame.dispose();
+ }
+ });
+ if (resize_count > RESIZE_COUNT_LIMIT) {
+ throw new RuntimeException("Resize event arrived: "
+ + resize_count + " times.");
+ }
+ }
+ }
+
+ private static void createUI() {
+ frame = new Frame("NoResizeEvent");
+ frame.addComponentListener(new ComponentAdapter() {
+ public void componentResized(ComponentEvent e) {
+ System.out.println(e);
+ resize_count++;
+ }
+ });
+ frame.setVisible(true);
+
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException ie) {
+ }
+ System.out.println("Resize count: " + resize_count);
+ }
+}
diff --git a/test/jdk/java/awt/Window/OwnedWindowShowTest/OwnedWindowShowTest.java b/test/jdk/java/awt/Window/OwnedWindowShowTest/OwnedWindowShowTest.java
new file mode 100644
index 00000000000..c8b5ad4a619
--- /dev/null
+++ b/test/jdk/java/awt/Window/OwnedWindowShowTest/OwnedWindowShowTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1998, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4177156
+ * @key headful
+ * @summary Tests that multiple level of window ownership doesn't cause
+ * NullPointerException when showing a Window
+ * @run main OwnedWindowShowTest
+ */
+
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Window;
+
+public class OwnedWindowShowTest {
+ public static void main(String[] args) throws Exception {
+ EventQueue.invokeAndWait(OwnedWindowShowTest::runTest);
+ }
+
+ static void runTest() {
+ Frame parent = new Frame("OwnedWindowShowTest");
+ try {
+ Window owner = new Window(parent);
+ Window window = new Window(owner);
+ // Showing a window with multiple levels of ownership
+ // should not throw NullPointerException
+ window.setVisible(true);
+ } finally {
+ parent.dispose();
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Window/ProxyCrash/PopupProxyCrash.java b/test/jdk/java/awt/Window/ProxyCrash/PopupProxyCrash.java
new file mode 100644
index 00000000000..b17b934a702
--- /dev/null
+++ b/test/jdk/java/awt/Window/ProxyCrash/PopupProxyCrash.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2001, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4381561
+ * @key headful
+ * @summary Tests that when we show the popup window AWT doesn't crash due to
+ * the problems with focus proxy window code
+ * @run main PopupProxyCrash
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Panel;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.InputEvent;
+
+import javax.swing.Box;
+import javax.swing.JComboBox;
+import javax.swing.JTextField;
+import javax.swing.plaf.basic.BasicComboBoxUI;
+import javax.swing.plaf.basic.BasicComboPopup;
+import javax.swing.plaf.basic.ComboPopup;
+
+public class PopupProxyCrash implements ActionListener {
+ private static JTextField jtf;
+ private static Button tf;
+ private static Panel panel;
+ private static Font[] fonts;
+ private static Robot robot;
+
+ private static JComboBox cb;
+
+ private static MyComboBoxUI comboBoxUI;
+ private static Frame frame;
+ private static int TEST_COUNT = 10;
+ public static void main(String[] args) throws Exception {
+ try {
+ robot = new Robot();
+ robot.setAutoDelay(100);
+ EventQueue.invokeAndWait(() -> createUI());
+ robot.waitForIdle();
+ runTest();
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (frame != null) {
+ frame.dispose();
+ }
+ });
+ }
+ }
+
+ private static void createUI() {
+ frame = new Frame("PopupProxyCrash");
+ Font dialog = new Font("Dialog", Font.PLAIN, 12);
+ Font serif = new Font("Serif", Font.PLAIN, 12);
+ Font monospaced = new Font("Monospaced", Font.PLAIN, 12);
+
+ fonts = new Font[] { dialog, serif, monospaced };
+
+ cb = new JComboBox(fonts);
+
+ cb.setLightWeightPopupEnabled(false);
+ comboBoxUI = new MyComboBoxUI();
+ cb.setUI(comboBoxUI);
+ jtf = new JTextField("JTextField");
+ jtf.setFont(fonts[1]);
+ tf = new Button("TextField");
+ tf.setFont(fonts[1]);
+ cb.addActionListener(new PopupProxyCrash());
+
+ panel = new Panel() {
+ public Dimension getPreferredSize() {
+ return new Dimension(100, 20);
+ }
+ public void paint(Graphics g) {
+ System.out.println("Painting with font " + getFont());
+ g.setColor(Color.white);
+ g.fillRect(0, 0, getWidth(), getHeight());
+ g.setColor(Color.black);
+ g.setFont(getFont());
+ g.drawString("LightWeight", 10, 10);
+ }
+ };
+ panel.setFont(fonts[1]);
+
+ Container parent = Box.createVerticalBox();
+ parent.add(jtf);
+ parent.add(tf);
+ parent.add(panel);
+ parent.add(cb);
+
+ frame.add(parent, BorderLayout.CENTER);
+ frame.pack();
+ frame.setLocationRelativeTo(null);
+ frame.setVisible(true);
+ }
+
+ private static Point getComboBoxLocation() throws Exception {
+ final Point[] result = new Point[1];
+
+ EventQueue.invokeAndWait(() -> {
+ Point point = cb.getLocationOnScreen();
+ Dimension size = cb.getSize();
+
+ point.x += size.width / 2;
+ point.y += size.height / 2;
+ result[0] = point;
+ });
+ return result[0];
+ }
+
+ private static Point getItemPointToClick(final int item) throws Exception {
+ final Point[] result = new Point[1];
+
+ EventQueue.invokeAndWait(() -> {
+ BasicComboPopup popup = (BasicComboPopup)comboBoxUI.getComboPopup();
+ Point point = popup.getLocationOnScreen();
+ Dimension size = popup.getSize();
+
+ int step = size.height / fonts.length;
+ point.x += size.width / 2;
+ point.y += step / 2 + step * item;
+ result[0] = point;
+ });
+ return result[0];
+ }
+
+ static void runTest() throws Exception {
+ for (int i = 0; i < TEST_COUNT; i++) {
+ Point point = getComboBoxLocation();
+ robot.mouseMove(point.x, point.y);
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+ robot.waitForIdle();
+ robot.delay(500);
+
+ point = getItemPointToClick(i % fonts.length);
+ robot.mouseMove(point.x, point.y);
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+ robot.waitForIdle();
+ robot.delay(500);
+ }
+ }
+ public void actionPerformed(ActionEvent ae) {
+ System.out.println("Font selected");
+ Font font = fonts[((JComboBox)ae.getSource()).getSelectedIndex()];
+
+ tf.setFont(font);
+ jtf.setFont(font);
+ panel.setFont(font);
+ panel.repaint();
+ }
+
+ private static class MyComboBoxUI extends BasicComboBoxUI {
+ public ComboPopup getComboPopup() {
+ return popup;
+ }
+ }
+}
diff --git a/test/jdk/java/awt/Window/ResizeTest/ResizeTest.java b/test/jdk/java/awt/Window/ResizeTest/ResizeTest.java
new file mode 100644
index 00000000000..a9191f8bd05
--- /dev/null
+++ b/test/jdk/java/awt/Window/ResizeTest/ResizeTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4225955
+ * @summary Tests that focus lost is delivered to a lightweight component
+ * in a disposed window
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual ResizeTest
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Dialog;
+import java.awt.Frame;
+
+public class ResizeTest
+{
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ 1) Push button A to create modal dialog 2.
+ 2) Resize dialog 2, then click button B to hide it.
+ 3) Push button A again. Dialog B should be packed to its original
+ size.
+ 4) Push button B again to hide, and A to reshow.
+ Dialog B should still be the same size, then test is passed,
+ otherwise failed.
+ 5) Push button B to hide the modal dialog and then select pass/fail.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .testUI(ResizeTest::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Frame createUI() {
+ Frame f = new Frame("1");
+ Dialog d = new Dialog(f, "2", true);
+ d.setLocationRelativeTo(null);
+ Button b2 = new Button("B");
+ b2.addActionListener(e -> d.setVisible(false));
+ d.setLayout(new BorderLayout());
+ d.add(b2, BorderLayout.CENTER);
+
+ Button b = new Button("A");
+ f.add(b, BorderLayout.CENTER);
+ b.addActionListener(e -> {
+ d.pack();
+ d.setVisible(true);
+ });
+ f.pack();
+ return f;
+ }
+}
diff --git a/test/jdk/java/awt/Window/ShowWindowTest/ShowWindowTest.java b/test/jdk/java/awt/Window/ShowWindowTest/ShowWindowTest.java
new file mode 100644
index 00000000000..4857929c94e
--- /dev/null
+++ b/test/jdk/java/awt/Window/ShowWindowTest/ShowWindowTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1998, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4084997
+ * @summary See if Window can be created without its size explicitly set
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual ShowWindowTest
+ */
+
+import java.awt.Button;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Label;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class ShowWindowTest implements ActionListener
+{
+ private static Window window;
+ private static Button showButton;
+ private static Button hideButton;
+
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ 1. You should see a Frame with a "Show" and a "Hide" button in it.
+ 2. Click on the "Show" button. A window with a "Hello World" Label
+ should appear
+ 3. If the window does not appear, the test failed, otherwise passed.
+ """;
+
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .testUI(ShowWindowTest::createUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Frame createUI() {
+ Frame frame = new Frame("ShowWindowTest");
+ frame.setLayout(new FlowLayout());
+ frame.setSize(100,100);
+ frame.add(showButton = new Button("Show"));
+ frame.add(hideButton = new Button("Hide"));
+
+ ActionListener handler = new ShowWindowTest();
+ showButton.addActionListener(handler);
+ hideButton.addActionListener(handler);
+
+ window = new Window(frame);
+ window.add("Center", new Label("Hello World"));
+ window.setLocationRelativeTo(null);
+ return frame;
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource() == showButton) {
+ window.pack();
+ window.setVisible(true);
+ } else if (e.getSource() == hideButton)
+ window.setVisible(false);
+ }
+}
diff --git a/test/jdk/java/awt/Window/WindowToFrontTest/WindowToFrontTest.java b/test/jdk/java/awt/Window/WindowToFrontTest/WindowToFrontTest.java
new file mode 100644
index 00000000000..e6bbadcb546
--- /dev/null
+++ b/test/jdk/java/awt/Window/WindowToFrontTest/WindowToFrontTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2001, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 4488209
+ * @summary JFrame toFront causes the entire frame to be repainted, causes UI
+ * to flash
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual WindowToFrontTest
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class WindowToFrontTest implements ActionListener {
+ static Frame frame;
+ public static void main(String[] args) throws Exception {
+ String INSTRUCTIONS = """
+ 1) Click the "toFront" button, this causes the
+ "WindowToFrontTest" frame to move front and gets repainted
+ completely.
+ 2) Move "WindowToFrontTest" window and continue to click on "toFront
+ multiple times. If the "WindowToFrontTest" Frame content is not
+ drawn properly and continues to blink, test is failed
+ otherwise passed.
+ """;
+
+ PassFailJFrame passFailJFrame = PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .rows(13)
+ .columns(40)
+ .build();
+ EventQueue.invokeAndWait(() -> createUI());
+ passFailJFrame.awaitAndCheck();
+ }
+
+ private static void createUI() {
+ frame = new Frame("WindowToFrontTest");
+ frame.setLayout(new BorderLayout());
+ frame.setSize(512, 512);
+ PassFailJFrame.addTestWindow(frame);
+ frame.setVisible(true);
+
+ Frame buttonFrame = new Frame("Test Button");
+ Button push = new Button("toFront");
+ push.addActionListener(new WindowToFrontTest());
+ buttonFrame.add(push);
+ buttonFrame.pack();
+ PassFailJFrame.addTestWindow(buttonFrame);
+ buttonFrame.setVisible(true);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ frame.toFront();
+ }
+}
diff --git a/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDHTMLToOutlookTest.java b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDHTMLToOutlookTest.java
new file mode 100644
index 00000000000..8a39ce53705
--- /dev/null
+++ b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDHTMLToOutlookTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011, 2024, Oracle and/or its affiliates. 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 java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Frame;
+import java.awt.Panel;
+
+
+/*
+ * @test
+ * @bug 6392086
+ * @summary Tests dnd to another screen
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual DnDHTMLToOutlookTest
+ */
+
+public class DnDHTMLToOutlookTest {
+
+ private static final String INSTRUCTIONS = """
+ The window contains a yellow button. Click on the button
+ to copy HTML from DnDSource.html file into the clipboard or drag
+ HTML context. Paste into or drop over the HTML capable editor in
+ external application such as Outlook, Word.
+
+ When the mouse enters the editor, cursor should change to indicate
+ that copy operation is about to happen and then release the mouse
+ button. HTML text without tags should appear inside the document.
+
+ You should be able to repeat this operation multiple times.
+ If the above is true Press PASS else FAIL.
+ """;
+
+ public static void main(String[] args) throws Exception {
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .testUI(DnDHTMLToOutlookTest::createAndShowUI)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Frame createAndShowUI() {
+ Frame frame = new Frame("DnDHTMLToOutlookTest");
+ Panel mainPanel;
+ Component dragSource;
+
+ mainPanel = new Panel();
+ mainPanel.setLayout(new BorderLayout());
+
+ mainPanel.setBackground(Color.YELLOW);
+ dragSource = new DnDSource("Drag ME (HTML)!");
+
+ mainPanel.add(dragSource, BorderLayout.CENTER);
+ frame.add(mainPanel);
+ frame.setSize(200, 200);
+ return frame;
+ }
+}
diff --git a/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.html b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.html
new file mode 100644
index 00000000000..0f1b9751dec
--- /dev/null
+++ b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.html
@@ -0,0 +1,25 @@
+
+
+DnDHTMLToOutlookTest
HTML Drag & Paste problem
+if you see the bold header above without HTML tags and without StartHTML as the first word, press PASS
diff --git a/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.java b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.java
new file mode 100644
index 00000000000..58f17e9415c
--- /dev/null
+++ b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2011, 2024, Oracle and/or its affiliates. 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 java.awt.Button;
+import java.awt.Color;
+import java.awt.Toolkit;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DragGestureEvent;
+import java.awt.dnd.DragGestureListener;
+import java.awt.dnd.DragSource;
+import java.awt.dnd.DragSourceDragEvent;
+import java.awt.dnd.DragSourceDropEvent;
+import java.awt.dnd.DragSourceEvent;
+import java.awt.dnd.DragSourceListener;
+import java.awt.dnd.InvalidDnDOperationException;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+class DnDSource extends Button implements Transferable,
+ DragGestureListener,
+ DragSourceListener {
+ private DataFlavor m_df;
+ private transient int m_dropAction;
+ private ByteArrayInputStream m_data = null;
+
+ DnDSource(String label) {
+ super(label);
+ setBackground(Color.yellow);
+ setForeground(Color.blue);
+ setSize(200, 120);
+
+ try {
+ m_df = new DataFlavor("text/html; Class=" + InputStream.class.getName() + "; charset=UTF-8");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ DragSource dragSource = new DragSource();
+ dragSource.createDefaultDragGestureRecognizer(
+ this,
+ DnDConstants.ACTION_COPY_OR_MOVE,
+ this
+ );
+ dragSource.addDragSourceListener(this);
+
+ String dir = System.getProperty("test.src", ".");
+
+ try {
+ m_data = new ByteArrayInputStream(Files.readAllBytes(
+ Paths.get(dir, "DnDSource.html")));
+ m_data.mark(m_data.available());
+ addActionListener(
+ new ActionListener(){
+ public void actionPerformed(ActionEvent ae){
+ Toolkit.getDefaultToolkit().getSystemClipboard()
+ .setContents( DnDSource.this, null);
+ }
+ }
+ );
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void dragGestureRecognized(DragGestureEvent dge) {
+ System.err.println("starting Drag");
+ try {
+ dge.startDrag(null, this, this);
+ } catch (InvalidDnDOperationException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void dragEnter(DragSourceDragEvent dsde) {
+ System.err.println("[Source] dragEnter");
+ }
+
+ public void dragOver(DragSourceDragEvent dsde) {
+ System.err.println("[Source] dragOver");
+ m_dropAction = dsde.getDropAction();
+ System.out.println("m_dropAction = " + m_dropAction);
+ }
+
+ public void dragExit(DragSourceEvent dsde) {
+ System.err.println("[Source] dragExit");
+ }
+
+ public void dragDropEnd(DragSourceDropEvent dsde) {
+ System.err.println("[Source] dragDropEnd");
+ }
+
+ public void dropActionChanged(DragSourceDragEvent dsde) {
+ System.err.println("[Source] dropActionChanged");
+ m_dropAction = dsde.getDropAction();
+ System.out.println("m_dropAction = " + m_dropAction);
+ }
+
+ public DataFlavor[] getTransferDataFlavors() {
+ return new DataFlavor[] {m_df};
+ }
+
+ public boolean isDataFlavorSupported(DataFlavor sdf) {
+ System.err.println("[Source] isDataFlavorSupported" + m_df.equals(sdf));
+ return m_df.equals(sdf);
+ }
+
+ public Object getTransferData(DataFlavor tdf) throws UnsupportedFlavorException {
+ if (!m_df.equals(tdf)) {
+ throw new UnsupportedFlavorException(tdf);
+ }
+ System.err.println("[Source] Ok");
+ m_data.reset();
+ return m_data;
+ }
+}
diff --git a/test/jdk/java/awt/dnd/DragExitBeforeDropTest.java b/test/jdk/java/awt/dnd/DragExitBeforeDropTest.java
new file mode 100644
index 00000000000..2ef778a18ba
--- /dev/null
+++ b/test/jdk/java/awt/dnd/DragExitBeforeDropTest.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2001, 2024, Oracle and/or its affiliates. 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 java.awt.Button;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.Panel;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DragGestureEvent;
+import java.awt.dnd.DragGestureListener;
+import java.awt.dnd.DragSource;
+import java.awt.dnd.DragSourceDragEvent;
+import java.awt.dnd.DragSourceDropEvent;
+import java.awt.dnd.DragSourceEvent;
+import java.awt.dnd.DragSourceListener;
+import java.awt.dnd.DropTarget;
+import java.awt.dnd.DropTargetContext;
+import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.dnd.DropTargetEvent;
+import java.awt.dnd.DropTargetListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+/*
+ * @test
+ * @bug 4395290
+ * @key headful
+ * @summary tests that dragExit() is not called before drop()
+ */
+
+public class DragExitBeforeDropTest {
+ private static Frame frame;
+ private static final DragSourceButton dragSourceButton = new DragSourceButton();
+ private static final DropTargetPanel dropTargetPanel = new DropTargetPanel();
+ private static volatile Point srcPoint;
+ private static volatile Point dstPoint;
+
+ public static void main(String[] args) throws Exception {
+ try {
+ Robot robot = new Robot();
+ EventQueue.invokeAndWait(DragExitBeforeDropTest::createAndShowUI);
+ robot.waitForIdle();
+ robot.delay(1000);
+
+ EventQueue.invokeAndWait(() -> {
+ Point p = dragSourceButton.getLocationOnScreen();
+ Dimension d = dragSourceButton.getSize();
+ p.translate(d.width / 2, d.height / 2);
+ srcPoint = p;
+
+ p = dropTargetPanel.getLocationOnScreen();
+ d = dropTargetPanel.getSize();
+ p.translate(d.width / 2, d.height / 2);
+ dstPoint = p;
+ });
+
+ robot.mouseMove(srcPoint.x, srcPoint.y);
+ robot.keyPress(KeyEvent.VK_CONTROL);
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ for (; !srcPoint.equals(dstPoint);
+ srcPoint.translate(sign(dstPoint.x - srcPoint.x),
+ sign(dstPoint.y - srcPoint.y))) {
+ robot.mouseMove(srcPoint.x, srcPoint.y);
+ robot.delay(10);
+ }
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+ robot.keyRelease(KeyEvent.VK_CONTROL);
+ robot.waitForIdle();
+ robot.delay(1000);
+
+ if (!dropTargetPanel.getStatus()) {
+ throw new RuntimeException("The test failed: dragExit()"
+ + " is called before drop()");
+ }
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (frame != null) {
+ frame.dispose();
+ }
+ });
+ }
+ }
+
+ private static void createAndShowUI() {
+ frame = new Frame("DragExitBeforeDropTest");
+ frame.setLayout(new GridLayout(2, 1));
+ frame.add(dragSourceButton);
+ frame.add(dropTargetPanel);
+ frame.setLocationRelativeTo(null);
+ frame.setSize(300, 400);
+ frame.setVisible(true);
+ }
+
+ public static int sign(int n) {
+ return Integer.compare(n, 0);
+ }
+
+ private static class DragSourceButton extends Button implements Serializable,
+ Transferable,
+ DragGestureListener,
+ DragSourceListener {
+ private final DataFlavor dataflavor =
+ new DataFlavor(Button.class, "DragSourceButton");
+
+ public DragSourceButton() {
+ this("DragSourceButton");
+ }
+
+ public DragSourceButton(String str) {
+ super(str);
+
+ DragSource ds = DragSource.getDefaultDragSource();
+ ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY,
+ this);
+ }
+
+ public void dragGestureRecognized(DragGestureEvent dge) {
+ dge.startDrag(null, this, this);
+ }
+
+ public void dragEnter(DragSourceDragEvent dsde) {}
+
+ public void dragExit(DragSourceEvent dse) {}
+
+ public void dragOver(DragSourceDragEvent dsde) {}
+
+ public void dragDropEnd(DragSourceDropEvent dsde) {}
+
+ public void dropActionChanged(DragSourceDragEvent dsde) {}
+
+ public Object getTransferData(DataFlavor flavor)
+ throws UnsupportedFlavorException, IOException {
+
+ if (!isDataFlavorSupported(flavor)) {
+ throw new UnsupportedFlavorException(flavor);
+ }
+
+ Object retObj;
+
+ ByteArrayOutputStream baoStream = new ByteArrayOutputStream();
+ ObjectOutputStream ooStream = new ObjectOutputStream(baoStream);
+ ooStream.writeObject(this);
+
+ ByteArrayInputStream baiStream =
+ new ByteArrayInputStream(baoStream.toByteArray());
+ ObjectInputStream ois = new ObjectInputStream(baiStream);
+ try {
+ retObj = ois.readObject();
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e.toString());
+ }
+
+ return retObj;
+ }
+
+ public DataFlavor[] getTransferDataFlavors() {
+ return new DataFlavor[] { dataflavor };
+ }
+
+ public boolean isDataFlavorSupported(DataFlavor dflavor) {
+ return dataflavor.equals(dflavor);
+ }
+ }
+
+ private static class DropTargetPanel extends Panel implements DropTargetListener {
+
+ final Dimension preferredDimension = new Dimension(200, 100);
+ volatile boolean testPassed = true;
+
+ public DropTargetPanel() {
+ setDropTarget(new DropTarget(this, this));
+ }
+
+ public boolean getStatus() {
+ return testPassed;
+ }
+
+ public Dimension getPreferredSize() {
+ return preferredDimension;
+ }
+
+ public void dragEnter(DropTargetDragEvent dtde) {}
+
+ public void dragExit(DropTargetEvent dte) {
+ testPassed = false;
+ }
+
+ public void dragOver(DropTargetDragEvent dtde) {}
+
+ public void dropActionChanged(DropTargetDragEvent dtde) {}
+
+ public void drop(DropTargetDropEvent dtde) {
+ DropTargetContext dtc = dtde.getDropTargetContext();
+
+ if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) {
+ dtde.acceptDrop(DnDConstants.ACTION_COPY);
+ } else {
+ dtde.rejectDrop();
+ }
+
+ DataFlavor[] dfs = dtde.getCurrentDataFlavors();
+ Component comp = null;
+
+ if(dfs != null && dfs.length >= 1) {
+ Transferable transfer = dtde.getTransferable();
+
+ try {
+ comp = (Component)transfer.getTransferData(dfs[0]);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ dtc.dropComplete(false);
+ }
+ }
+ dtc.dropComplete(true);
+ add(comp);
+ }
+ }
+}
+
+
+
diff --git a/test/jdk/java/awt/dnd/DragSourceMotionListenerTest.java b/test/jdk/java/awt/dnd/DragSourceMotionListenerTest.java
new file mode 100644
index 00000000000..25bf7ef03fd
--- /dev/null
+++ b/test/jdk/java/awt/dnd/DragSourceMotionListenerTest.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2001, 2024, Oracle and/or its affiliates. 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 java.awt.AWTEvent;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.Panel;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.Toolkit;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DragGestureListener;
+import java.awt.dnd.DragSource;
+import java.awt.dnd.DragSourceAdapter;
+import java.awt.dnd.DragSourceDragEvent;
+import java.awt.dnd.DragSourceDropEvent;
+import java.awt.dnd.DropTarget;
+import java.awt.dnd.DropTargetAdapter;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.dnd.DropTargetListener;
+import java.awt.event.AWTEventListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/*
+ * @test
+ * @key headful
+ * @bug 4422345
+ * @summary tests that DragSourceMotionListeners work correctly and
+ DragSourceEvents position is correct
+ */
+
+public class DragSourceMotionListenerTest implements AWTEventListener {
+ static class TestPanel extends Panel {
+ final Dimension preferredDimension = new Dimension(200, 200);
+ public Dimension getPreferredSize() {
+ return preferredDimension;
+ }
+ }
+
+ private static Frame frame;
+ private static final Panel source = new TestPanel();
+ private static final Panel target = new TestPanel();
+ private static final DragSource ds = DragSource.getDefaultDragSource();
+ private static volatile CountDownLatch mouseReleaseEvent;
+
+ static volatile boolean passedTest1 = false;
+ static volatile boolean passedTest2 = false;
+
+ private static final Point testPoint1 = new Point();
+ private static final Point testPoint2 = new Point();
+ private static volatile Point srcPoint;
+ private static volatile Point dstOutsidePoint;
+ private static volatile Point dstInsidePoint;
+
+ private static final Transferable t = new StringSelection("TEXT");
+ private static final DragGestureListener gestureListener = e -> e.startDrag(null, t);
+
+ private static final DragSourceAdapter sourceAdapter = new DragSourceAdapter() {
+ public void dragMouseMoved(DragSourceDragEvent dsde) {
+ if (Math.abs(dsde.getX() - testPoint1.getX()) < 5) {
+ passedTest1 = true;
+ }
+ }
+
+ public void dragDropEnd(DragSourceDropEvent dsde) {
+ if (Math.abs(dsde.getX() - testPoint2.getX()) < 5) {
+ passedTest2 = true;
+ }
+ }
+ };
+
+ private static final DropTargetListener targetAdapter = new DropTargetAdapter() {
+ public void drop(DropTargetDropEvent e) {
+ e.acceptDrop(DnDConstants.ACTION_COPY);
+ try {
+ final Transferable t = e.getTransferable();
+ final String str =
+ (String) t.getTransferData(DataFlavor.stringFlavor);
+ e.dropComplete(true);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ e.dropComplete(false);
+ }
+ }
+ };
+
+ private static final DropTarget dropTarget = new DropTarget(target, targetAdapter);
+ Component clickedComponent = null;
+
+ private void createAndShowUI() {
+ frame = new Frame("DragSourceMotionListenerTest");
+ ds.addDragSourceListener(sourceAdapter);
+ ds.addDragSourceMotionListener(sourceAdapter);
+ ds.createDefaultDragGestureRecognizer(source, DnDConstants.ACTION_COPY, gestureListener);
+ target.setDropTarget(dropTarget);
+
+ frame.setLayout(new GridLayout(1, 2));
+
+ frame.add(source);
+ frame.add(target);
+
+ Toolkit.getDefaultToolkit()
+ .addAWTEventListener(this, AWTEvent.MOUSE_EVENT_MASK);
+ frame.pack();
+ frame.setVisible(true);
+ }
+
+ public static void main(String[] args) throws Exception {
+ try {
+ Robot robot = new Robot();
+ robot.setAutoDelay(10);
+
+ DragSourceMotionListenerTest dsmObj = new DragSourceMotionListenerTest();
+ EventQueue.invokeAndWait(dsmObj::createAndShowUI);
+ robot.waitForIdle();
+ robot.delay(1000);
+
+ EventQueue.invokeAndWait(() -> {
+ srcPoint = getPoint(source, 1);
+
+ dstOutsidePoint = getPoint(frame, 3);
+ testPoint1.setLocation(dstOutsidePoint);
+
+ dstInsidePoint = getPoint(target, 1);
+ testPoint2.setLocation(dstInsidePoint);
+ });
+ robot.waitForIdle();
+
+ if (!dsmObj.pointInComponent(robot, srcPoint, source)) {
+ throw new RuntimeException("WARNING: Couldn't locate source panel.");
+ }
+
+ if (!dsmObj.pointInComponent(robot, dstInsidePoint, target)) {
+ throw new RuntimeException("WARNING: Couldn't locate target panel.");
+ }
+
+ robot.mouseMove(srcPoint.x, srcPoint.y);
+ robot.keyPress(KeyEvent.VK_CONTROL);
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ for (; !srcPoint.equals(dstOutsidePoint);
+ srcPoint.translate(sign(dstOutsidePoint.x - srcPoint.x),
+ sign(dstOutsidePoint.y - srcPoint.y))) {
+ robot.mouseMove(srcPoint.x, srcPoint.y);
+ }
+
+ for (int i = 0; i < 10; i++) {
+ robot.mouseMove(srcPoint.x, srcPoint.y++);
+ }
+
+ for (;!srcPoint.equals(dstInsidePoint);
+ srcPoint.translate(sign(dstInsidePoint.x - srcPoint.x),
+ sign(dstInsidePoint.y - srcPoint.y))) {
+ robot.mouseMove(srcPoint.x, srcPoint.y);
+ }
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+ robot.keyRelease(KeyEvent.VK_CONTROL);
+ robot.waitForIdle();
+ robot.delay(1000);
+
+ if (!passedTest1) {
+ throw new RuntimeException("Failed first test.");
+ }
+
+ if (!passedTest2) {
+ throw new RuntimeException("Failed second test.");
+ }
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (frame != null) {
+ frame.dispose();
+ }
+ });
+ }
+ }
+
+ private static Point getPoint(Container container, int multiple) {
+ Point p = container.getLocationOnScreen();
+ Dimension d = container.getSize();
+ p.translate(multiple * d.width / 2, d.height / 2);
+ return p;
+ }
+
+ public static int sign(int n) {
+ return Integer.compare(n, 0);
+ }
+
+ public void eventDispatched(AWTEvent e) {
+ if (e.getID() == MouseEvent.MOUSE_RELEASED) {
+ clickedComponent = (Component)e.getSource();
+ mouseReleaseEvent.countDown();
+ }
+ }
+
+ boolean pointInComponent(Robot robot, Point p, Component comp) throws Exception {
+ robot.waitForIdle();
+ clickedComponent = null;
+ mouseReleaseEvent = new CountDownLatch(1);
+ robot.mouseMove(p.x, p.y);
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+ if (!mouseReleaseEvent.await(2, TimeUnit.SECONDS)) {
+ throw new RuntimeException("Mouse Release Event not received");
+ }
+
+ Component c = clickedComponent;
+ while (c != null && c != comp) {
+ c = c.getParent();
+ }
+ return c == comp;
+ }
+}
diff --git a/test/jdk/java/awt/dnd/DragThresholdTest.java b/test/jdk/java/awt/dnd/DragThresholdTest.java
new file mode 100644
index 00000000000..bcb3bbf91c2
--- /dev/null
+++ b/test/jdk/java/awt/dnd/DragThresholdTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. 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 java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Panel;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DragGestureListener;
+import java.awt.dnd.DragSource;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionAdapter;
+
+/*
+ @test
+ @key headful
+ @bug 4415175
+ @summary tests DragSource.getDragThreshold() and
+ that the AWT default drag gesture recognizers
+ honor the drag gesture motion threshold
+*/
+
+public class DragThresholdTest {
+ private static Frame frame;
+ private static Panel panel;
+ private static MouseEvent lastMouseEvent;
+ private static volatile boolean failed;
+ private static volatile Point startPoint;
+ private static volatile Point endPoint;
+
+ public static void main(String[] args) throws Exception {
+ try {
+ Robot robot = new Robot();
+
+ EventQueue.invokeAndWait(DragThresholdTest::createAndShowDnD);
+ robot.waitForIdle();
+ robot.delay(1000);
+
+ EventQueue.invokeAndWait(() -> {
+ Point p = panel.getLocationOnScreen();
+ p.translate(50, 50);
+ startPoint = p;
+ endPoint = new Point(p.x + 2 * DragSource.getDragThreshold(),
+ p.y + 2 * DragSource.getDragThreshold());
+ });
+
+ robot.mouseMove(startPoint.x, startPoint.y);
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ for (Point p = new Point(startPoint); !p.equals(endPoint);
+ p.translate(sign(endPoint.x - p.x),
+ sign(endPoint.y - p.y))) {
+ robot.mouseMove(p.x, p.y);
+ robot.delay(100);
+ }
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+ robot.waitForIdle();
+ robot.delay(200);
+
+ if (failed) {
+ throw new RuntimeException("drag gesture recognized too early");
+ }
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (frame != null) {
+ frame.dispose();
+ }
+ });
+ }
+ }
+
+ private static void createAndShowDnD() {
+ frame = new Frame("DragThresholdTest");
+ panel = new Panel();
+ // Mouse motion listener mml is added to the panel first.
+ // We rely on it that this listener will be called first.
+ panel.addMouseMotionListener(new MouseMotionAdapter() {
+ public void mouseDragged(MouseEvent evt) {
+ lastMouseEvent = evt;
+ System.out.println(evt);
+ }
+ });
+ frame.add(panel);
+ frame.setSize(200, 200);
+ frame.setLocationRelativeTo(null);
+
+ DragGestureListener dgl = dge -> {
+ Point dragOrigin = dge.getDragOrigin();
+ int diffx = Math.abs(dragOrigin.x - lastMouseEvent.getX());
+ int diffy = Math.abs(dragOrigin.y - lastMouseEvent.getY());
+ System.out.println("dragGestureRecognized(): " +
+ " diffx=" + diffx + " diffy=" + diffy +
+ " DragSource.getDragThreshold()="
+ + DragSource.getDragThreshold());
+ if (diffx <= DragSource.getDragThreshold() &&
+ diffy <= DragSource.getDragThreshold()) {
+ failed = true;
+ System.out.println("drag gesture recognized too early!");
+ }
+ };
+
+ // Default drag gesture recognizer is a mouse motion listener.
+ // It is added to the panel second.
+ new DragSource().createDefaultDragGestureRecognizer(
+ panel,
+ DnDConstants.ACTION_COPY_OR_MOVE, dgl);
+ frame.setVisible(true);
+ }
+
+ private static int sign(int n) {
+ return Integer.compare(n, 0);
+ }
+}
diff --git a/test/jdk/java/awt/dnd/DragToAnotherScreenTest.java b/test/jdk/java/awt/dnd/DragToAnotherScreenTest.java
new file mode 100644
index 00000000000..89f18061845
--- /dev/null
+++ b/test/jdk/java/awt/dnd/DragToAnotherScreenTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. 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 java.awt.Frame;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Label;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DragGestureListener;
+import java.awt.dnd.DragSource;
+import java.awt.dnd.DropTarget;
+import java.awt.dnd.DropTargetAdapter;
+import java.awt.dnd.DropTargetDropEvent;
+import java.util.List;
+
+import javax.swing.JOptionPane;
+
+/*
+ * @test
+ * @bug 6179157
+ * @key multimon
+ * @summary Tests dnd to another screen
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual DragToAnotherScreenTest
+ */
+
+public class DragToAnotherScreenTest {
+ private static Label label0;
+ private static Label label1;
+ private static final int HGAP = 20;
+
+ private static final String INSTRUCTIONS = """
+ The following test is applicable for Single as well
+ as Multi-monitor screens.
+
+ It is a semi-automated test, the test will prompt
+ the user whether the drag and drop action was successful or not
+ and automatically PASS/FAIL the test.
+
+ If on multi-monitor screens then please position
+ the drag and drop windows on different screens.
+
+ If you can not move the mouse from the frame "Drag Source"
+ to the frame "Drop Target" press PASS,
+ else proceed to the next step.
+
+ Drag the label "Drag me" and drop it on the
+ label "Drop on me".
+
+ If you can not drag to the second label (for example
+ if you can not drag across screens) press FAIL.
+
+ After the drag and drop action, the test displays
+ Success/Failure msg in JOptionPane.
+ Click on OK button and the test is configured to
+ automatically PASS/FAIL.
+ """;
+
+ public static void main(String[] args) throws Exception {
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(35)
+ .testUI(DragToAnotherScreenTest::createAndShowUI)
+ .positionTestUI(DragToAnotherScreenTest::positionMultiTestUI)
+ .logArea(10)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static List createAndShowUI() {
+ PassFailJFrame.log("----- System Configuration ----");
+ PassFailJFrame.log("Toolkit:" + Toolkit.getDefaultToolkit()
+ .getClass()
+ .getName());
+
+ GraphicsDevice[] gd = GraphicsEnvironment.getLocalGraphicsEnvironment()
+ .getScreenDevices();
+ if (gd.length == 1) {
+ PassFailJFrame.log("Single Monitor");
+ } else {
+ PassFailJFrame.log("Multi-Monitor");
+ }
+ PassFailJFrame.log("--------------");
+ PassFailJFrame.log("Test logs:\n");
+ Frame frame0 = new Frame("Drag Source", gd[0].getDefaultConfiguration());
+ frame0.setSize(300, 300);
+ label0 = new Label("Drag me");
+ frame0.add(label0);
+
+ Frame frame1 = new Frame("Drop Target", gd[(gd.length > 1 ? 1 : 0)].getDefaultConfiguration());
+ frame1.setSize(300, 300);
+ label1 = new Label("Drop on me");
+ frame1.add(label1);
+
+ DragGestureListener dragGestureListener = dge -> dge.startDrag(null, new StringSelection(label0.getText()), null);
+ new DragSource().createDefaultDragGestureRecognizer(label0,
+ DnDConstants.ACTION_COPY, dragGestureListener);
+
+ DropTargetAdapter dropTargetAdapter = new DropTargetAdapter() {
+ public void drop(DropTargetDropEvent dtde) {
+ Transferable t = dtde.getTransferable();
+ if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) {
+ dtde.acceptDrop(DnDConstants.ACTION_COPY);
+ try {
+ String str = (String) t.getTransferData(DataFlavor.stringFlavor);
+ label1.setText(str);
+ JOptionPane.showMessageDialog(frame0,
+ "getTransferData was successful",
+ "Test Passed", JOptionPane.PLAIN_MESSAGE);
+ } catch (Exception e) {
+ dtde.dropComplete(false);
+ e.printStackTrace();
+ PassFailJFrame.log("getTransferData() Failed");
+ JOptionPane.showMessageDialog(frame0,
+ "getTransferData() Failed",
+ "Test Failed", JOptionPane.ERROR_MESSAGE);
+ PassFailJFrame.forceFail("getTransferData() Failed");
+ }
+ dtde.dropComplete(true);
+ } else {
+ dtde.rejectDrop();
+ PassFailJFrame.log("stringFlavor is not supported by Transferable");
+ JOptionPane.showMessageDialog(frame0,
+ "stringFlavor is not supported by Transferable",
+ "Test Failed", JOptionPane.ERROR_MESSAGE);
+ PassFailJFrame.forceFail("stringFlavor is not supported by Transferable");
+ }
+ }
+ };
+ new DropTarget(label1, dropTargetAdapter);
+ return List.of(frame0, frame1);
+ }
+
+ private static void positionMultiTestUI(List extends Window> windows,
+ PassFailJFrame.InstructionUI instructionUI) {
+ int x = instructionUI.getLocation().x + instructionUI.getSize().width + HGAP;
+ for (Window w : windows) {
+ w.setLocation(x, instructionUI.getLocation().y);
+ x += w.getWidth() + HGAP;
+ }
+ }
+}
diff --git a/test/jdk/java/awt/dnd/RejectDragTest.java b/test/jdk/java/awt/dnd/RejectDragTest.java
new file mode 100644
index 00000000000..c65612436bc
--- /dev/null
+++ b/test/jdk/java/awt/dnd/RejectDragTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2002, 2024, Oracle and/or its affiliates. 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 java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.datatransfer.StringSelection;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DragGestureListener;
+import java.awt.dnd.DragSource;
+import java.awt.dnd.DragSourceAdapter;
+import java.awt.dnd.DragSourceDragEvent;
+import java.awt.dnd.DragSourceDropEvent;
+import java.awt.dnd.DragSourceEvent;
+import java.awt.dnd.DragSourceListener;
+import java.awt.dnd.DropTarget;
+import java.awt.dnd.DropTargetAdapter;
+import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.event.InputEvent;
+
+/*
+ * @test
+ * @key headful
+ * @bug 4407521
+ * @summary Tests that DragSourceListener.dragEnter() and
+ DragSourceListener.dragOver() are not called after
+ drag rejecting, but DragSourceListener.dragExit() is.
+ */
+
+public class RejectDragTest {
+ private static Frame frame;
+ private static Robot robot;
+ private static volatile boolean dragEnterCalled;
+ private static volatile boolean dragOverCalled;
+ private static volatile boolean dragExitCalledAtFirst;
+ private static volatile Point startPoint;
+ private static volatile Point endPoint;
+
+ public static void main(String[] args) throws Exception {
+ try {
+ robot = new Robot();
+
+ EventQueue.invokeAndWait(RejectDragTest::createAndShowUI);
+ robot.waitForIdle();
+ robot.delay(1000);
+
+ EventQueue.invokeAndWait(RejectDragTest::addDnDListeners);
+ robot.waitForIdle();
+
+ testDnD();
+ robot.waitForIdle();
+ robot.delay(200);
+ } finally {
+ EventQueue.invokeAndWait(() -> {
+ if (frame != null) {
+ frame.dispose();
+ }
+ });
+ }
+ }
+
+ private static void addDnDListeners() {
+ final DragSourceListener dragSourceListener = new DragSourceAdapter() {
+ private boolean first = true;
+
+ public void dragEnter(DragSourceDragEvent dsde) {
+ first = false;
+ dragEnterCalled = true;
+ }
+
+ public void dragExit(DragSourceEvent dse) {
+ if (first) {
+ dragExitCalledAtFirst = true;
+ first = false;
+ }
+ }
+
+ public void dragDropEnd(DragSourceDropEvent dsde) {
+ first = false;
+ }
+
+ public void dragOver(DragSourceDragEvent dsde) {
+ first = false;
+ dragOverCalled = true;
+ }
+
+ public void dropActionChanged(DragSourceDragEvent dsde) {
+ first = false;
+ }
+ };
+
+ DragGestureListener dragGestureListener =
+ dge -> dge.startDrag(null, new StringSelection("OKAY"),
+ dragSourceListener);
+ new DragSource().createDefaultDragGestureRecognizer(frame,
+ DnDConstants.ACTION_COPY,
+ dragGestureListener);
+
+ DropTargetAdapter dropTargetListener = new DropTargetAdapter() {
+ public void dragEnter(DropTargetDragEvent dtde) {
+ dtde.rejectDrag();
+ }
+
+ public void drop(DropTargetDropEvent dtde) {
+ dtde.rejectDrop();
+ }
+ };
+
+ new DropTarget(frame, dropTargetListener);
+ }
+
+ private static void createAndShowUI() {
+ frame = new Frame("RejectDragTest");
+ frame.setSize(200, 200);
+ frame.setLocationRelativeTo(null);
+ frame.setVisible(true);
+ }
+
+ private static void testDnD() throws Exception {
+ EventQueue.invokeAndWait(() -> {
+ Point start = frame.getLocationOnScreen();
+ start.translate(50, 50);
+ startPoint = start;
+
+ Point end = new Point(start);
+ end.translate(150, 150);
+ endPoint = end;
+ });
+
+ robot.mouseMove(startPoint.x, startPoint.y);
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ for (Point p = new Point(startPoint); !p.equals(endPoint);
+ p.translate(sign(endPoint.x - p.x),
+ sign(endPoint.y - p.y))) {
+ robot.mouseMove(p.x, p.y);
+ robot.delay(30);
+ }
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+
+ if (dragEnterCalled || dragOverCalled) {
+ throw new RuntimeException("Test failed: " +
+ (dragEnterCalled ? "DragSourceListener.dragEnter() was called; " : "") +
+ (dragOverCalled ? "DragSourceListener.dragOver() was called; " : "") +
+ (!dragExitCalledAtFirst ? "DragSourceListener.dragExit() was not " +
+ "called immediately after rejectDrag() " : ""));
+ }
+ }
+
+ public static int sign(int n) {
+ return Integer.compare(n, 0);
+ }
+}
diff --git a/test/jdk/java/awt/dnd/WinMoveFileToShellTest.java b/test/jdk/java/awt/dnd/WinMoveFileToShellTest.java
new file mode 100644
index 00000000000..5ae7dd3890d
--- /dev/null
+++ b/test/jdk/java/awt/dnd/WinMoveFileToShellTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2002, 2024, Oracle and/or its affiliates. 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 java.awt.Frame;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DragGestureListener;
+import java.awt.dnd.DragSource;
+import java.awt.dnd.DragSourceAdapter;
+import java.awt.dnd.DragSourceDropEvent;
+import java.awt.dnd.DragSourceListener;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+ * @test
+ * @bug 4414739
+ * @requires (os.family == "windows")
+ * @summary verifies that getDropSuccess() returns correct value for moving
+ a file from a Java drag source to the Windows shell
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual WinMoveFileToShellTest
+ */
+
+public class WinMoveFileToShellTest {
+ private static final String INSTRUCTIONS = """
+ Drag from the frame titled "Drag Frame" and drop on to Windows Desktop.
+ After Drag and Drop, check for "Drop Success" status in the log area.
+ If "Drop Success" is true press PASS else FAIL.
+ """;
+
+ public static void main(String[] args) throws Exception {
+ PassFailJFrame.builder()
+ .title("Test Instructions")
+ .instructions(INSTRUCTIONS)
+ .columns(40)
+ .testUI(WinMoveFileToShellTest::createAndShowUI)
+ .logArea(5)
+ .build()
+ .awaitAndCheck();
+ }
+
+ private static Frame createAndShowUI() {
+ Frame frame = new Frame("Drag Frame");
+ final DragSourceListener dsl = new DragSourceAdapter() {
+ public void dragDropEnd(DragSourceDropEvent e) {
+ PassFailJFrame.log("Drop Success: " + e.getDropSuccess());
+ }
+ };
+
+ DragGestureListener dgl = dge -> {
+ File file = new File(System.getProperty("test.classes", ".")
+ + File.separator + "move.me");
+ try {
+ file.createNewFile();
+ } catch (IOException exc) {
+ exc.printStackTrace();
+ }
+ ArrayList list = new ArrayList<>();
+ list.add(file);
+ dge.startDrag(null, new FileListSelection(list), dsl);
+ };
+
+ new DragSource().createDefaultDragGestureRecognizer(frame,
+ DnDConstants.ACTION_MOVE, dgl);
+ frame.setSize(200, 100);
+ return frame;
+ }
+
+ private static class FileListSelection implements Transferable {
+ private static final int FL = 0;
+
+ private static final DataFlavor[] flavors =
+ new DataFlavor[] { DataFlavor.javaFileListFlavor };
+
+
+ private List data;
+
+ public FileListSelection(List data) {
+ this.data = data;
+ }
+
+ public DataFlavor[] getTransferDataFlavors() {
+ return flavors.clone();
+ }
+
+ public boolean isDataFlavorSupported(DataFlavor flavor) {
+ for (DataFlavor dataFlavor : flavors) {
+ if (flavor.equals(dataFlavor)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public Object getTransferData(DataFlavor flavor)
+ throws UnsupportedFlavorException, IOException
+ {
+ if (flavor.equals(flavors[FL])) {
+ return data;
+ } else {
+ throw new UnsupportedFlavorException(flavor);
+ }
+ }
+ }
+}
diff --git a/test/jdk/java/awt/grab/CursorTest.java b/test/jdk/java/awt/grab/CursorTest.java
new file mode 100644
index 00000000000..f08008cbd8f
--- /dev/null
+++ b/test/jdk/java/awt/grab/CursorTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2006, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6364746 6400007
+ * @summary Cursor should be changed correctly while Swing menu is open (input is grabbed).
+ * @library /java/awt/regtesthelpers
+ * @build PassFailJFrame
+ * @run main/manual CursorTest
+*/
+
+import java.awt.FlowLayout;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+
+public class CursorTest {
+
+ static final String INSTRUCTIONS = """
+ After the test starts you will see a frame titled "Cursor Test Window",
+ with two menus in the menubar (menu1 and menu2), and a textfield and
+ a button, labeled "JButton".
+ 1. Open menu1 (it should be small and fit within the border of the frame),
+ 2. Verify that the pointer image (cursor) is the default desktop cursor.
+ 3. Move the mouse over the text field - the cursor should change its shape to caret,
+ 4. Move the mouse over the button - the cursor should be default one,
+ 5. Move the mouse to the border of the frame - cursor should be a resize one
+ (exact shape is dependent on the border you move over),
+ 6. Move the mouse out of the frame - cursor should be default one,
+ 7. Perform steps 2-6 in reverse order (after this the mouse should be over the open menu1),
+ 8. Open menu2, it should be big enough to not fit within the frame,
+ 9. Repeat steps 2-7 (you should end up with mouse over opened menu2 :),
+ 10. Close the menu.
+ 11. If on every step the cursor was as described, press Pass, press Fail otherwise.
+ """;
+
+ static JFrame createUI() {
+
+ JButton but = new JButton("JButton");
+ JPanel panel = new JPanel();
+ JTextField jtf = new JTextField("JTextField", 20);
+
+ JFrame.setDefaultLookAndFeelDecorated(true);
+ JFrame frame = new JFrame("Cursor Test Window");
+ frame.setLayout(new FlowLayout());
+ panel.add(but);
+
+ frame.getContentPane().add(jtf);
+ frame.getContentPane().add(panel);
+
+ JMenu menu1 = new JMenu("menu1");
+ menu1.add(new JMenuItem("menu1,item1"));
+ JMenuBar mb = new JMenuBar();
+ mb.add(menu1);
+ JMenu menu2 = new JMenu("menu2");
+ for (int i = 0; i < 10; i++) {
+ menu2.add(new JMenuItem("menu2,item"+i));
+ }
+ mb.add(menu2);
+ frame.setJMenuBar(mb);
+ frame.pack();
+ return frame;
+ }
+
+ public static void main(String[] args) throws Exception {
+ PassFailJFrame.builder()
+ .title("Cursor Test")
+ .instructions(INSTRUCTIONS)
+ .columns(60)
+ .testUI(CursorTest::createUI)
+ .build()
+ .awaitAndCheck();
+
+ }
+}
diff --git a/test/jdk/java/awt/grab/SystemMenuTest.java b/test/jdk/java/awt/grab/SystemMenuTest.java
new file mode 100644
index 00000000000..07676b31911
--- /dev/null
+++ b/test/jdk/java/awt/grab/SystemMenuTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2006, 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @bug 6364741
+ * @key headful
+ * @requires (os.family == "windows")
+ * @summary REG: Using frame's menu actions does not make swing menu disappear on WinXP,
+ * since Mustang-b53
+ */
+
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.Point;
+import java.awt.Robot;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.SwingUtilities;
+import javax.swing.event.MenuEvent;
+import javax.swing.event.MenuListener;
+
+public class SystemMenuTest implements MenuListener {
+
+ static volatile JMenu menu;
+ static volatile JMenu sub_menu;
+ static volatile JFrame frame;
+
+ static volatile int selectCount = 0;
+ static volatile int deselectCount = 0;
+ static volatile boolean failed = false;
+ static volatile String reason = "none";
+
+ static void createUI() {
+ SystemMenuTest smt = new SystemMenuTest();
+ sub_menu = new JMenu("SubMenu");
+ sub_menu.addMenuListener(smt);
+ sub_menu.add(new JMenuItem("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"));
+ sub_menu.add(new JMenuItem("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"));
+ menu = new JMenu("Menu");
+ menu.addMenuListener(smt);
+ menu.add(sub_menu);
+ JMenuBar mb = new JMenuBar();
+ mb.add(menu);
+
+ frame = new JFrame("JFrame");
+ frame.setJMenuBar(mb);
+ frame.pack();
+ frame.setVisible(true);
+ }
+
+ public static void main(String[] args) throws Exception {
+
+ Robot robot = new Robot();
+
+ SwingUtilities.invokeAndWait(SystemMenuTest::createUI);
+
+ try {
+ robot.waitForIdle();
+ robot.delay(2000);
+
+ Point p = menu.getLocationOnScreen();
+ robot.mouseMove(p.x + menu.getWidth() / 2, p.y + menu.getHeight() / 2);
+ robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+ robot.waitForIdle();
+ robot.delay(2000);
+
+ p = sub_menu.getLocationOnScreen();
+ robot.mouseMove(p.x + sub_menu.getWidth() / 2, p.y + sub_menu.getHeight() /2 );
+ robot.mousePress(InputEvent.BUTTON1_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_MASK);
+ robot.waitForIdle();
+ robot.delay(2000);
+
+ // Alt-Space to invoke System Menu, should close Swing menus.
+ robot.keyPress(KeyEvent.VK_ALT);
+ robot.keyPress(KeyEvent.VK_SPACE);
+ robot.delay(50);
+ robot.keyRelease(KeyEvent.VK_SPACE);
+ robot.keyRelease(KeyEvent.VK_ALT);
+ robot.waitForIdle();
+ robot.delay(2000);
+
+ if (selectCount != 2 || deselectCount != 2) {
+ throw new RuntimeException("unexpected selection count " + selectCount + ", " + deselectCount);
+ }
+ if (failed) {
+ throw new RuntimeException("Failed because " + reason);
+ }
+ } finally {
+ if (frame != null) {
+ SwingUtilities.invokeAndWait(frame::dispose);
+ }
+ }
+ }
+
+ public void menuCanceled(MenuEvent e) {
+ System.out.println("cancelled"+e.getSource());
+ }
+
+ public void menuDeselected(MenuEvent e) {
+ deselectCount++;
+ if (selectCount != 2) {
+ failed = true;
+ reason = "deselect without two selects";
+ }
+ System.out.println("deselected"+e.getSource());
+ }
+
+ public void menuSelected(MenuEvent e) {
+ if (deselectCount != 0) {
+ failed = true;
+ reason = "select without non-zero deselects";
+ }
+ selectCount++;
+ System.out.println("selected"+e.getSource());
+ }
+}
diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java
index feb5da43a5c..41c5fdf8ccd 100644
--- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java
+++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java
@@ -24,6 +24,7 @@
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Dimension;
+import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
@@ -44,6 +45,7 @@
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -69,6 +71,7 @@
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.Timer;
+import javax.swing.border.Border;
import javax.swing.text.JTextComponent;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;
@@ -287,9 +290,15 @@
*/
public final class PassFailJFrame {
- private static final String TITLE = "Test Instruction Frame";
+ /** A default title for the instruction frame. */
+ private static final String TITLE = "Test Instructions";
+
+ /** A default test timeout. */
private static final long TEST_TIMEOUT = 5;
+
+ /** A default number of rows for displaying the test instructions. */
private static final int ROWS = 10;
+ /** A default number of columns for displaying the test instructions. */
private static final int COLUMNS = 40;
/**
@@ -302,7 +311,7 @@ public final class PassFailJFrame {
*/
private static final String FAILURE_REASON = "Failure Reason:\n";
/**
- * The failure reason message when the user didn't provide one.
+ * The failure reason message when the user doesn't provide one.
*/
private static final String EMPTY_REASON = "(no reason provided)";
@@ -655,6 +664,8 @@ private static JComponent createInstructionUIPanel(String instructions,
boolean addLogArea,
int logAreaRows) {
JPanel main = new JPanel(new BorderLayout());
+ main.setBorder(createFrameBorder());
+
timeoutHandlerPanel = new TimeoutHandlerPanel(testTimeOut);
main.add(timeoutHandlerPanel, BorderLayout.NORTH);
@@ -664,7 +675,7 @@ private static JComponent createInstructionUIPanel(String instructions,
text.setEditable(false);
JPanel textPanel = new JPanel(new BorderLayout());
- textPanel.setBorder(createEmptyBorder(4, 0, 0, 0));
+ textPanel.setBorder(createEmptyBorder(GAP, 0, GAP, 0));
textPanel.add(new JScrollPane(text), BorderLayout.CENTER);
main.add(textPanel, BorderLayout.CENTER);
@@ -681,7 +692,8 @@ private static JComponent createInstructionUIPanel(String instructions,
timeoutHandlerPanel.stop();
});
- JPanel buttonsPanel = new JPanel();
+ JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER,
+ GAP, 0));
buttonsPanel.add(btnPass);
buttonsPanel.add(btnFail);
@@ -692,10 +704,12 @@ private static JComponent createInstructionUIPanel(String instructions,
if (addLogArea) {
logArea = new JTextArea(logAreaRows, columns);
logArea.setEditable(false);
+ logArea.setBorder(createTextBorder());
Box buttonsLogPanel = Box.createVerticalBox();
buttonsLogPanel.add(buttonsPanel);
+ buttonsLogPanel.add(Box.createVerticalStrut(GAP));
buttonsLogPanel.add(new JScrollPane(logArea));
main.add(buttonsLogPanel, BorderLayout.SOUTH);
@@ -713,7 +727,7 @@ private static JTextComponent configurePlainText(String instructions,
JTextArea text = new JTextArea(instructions, rows, columns);
text.setLineWrap(true);
text.setWrapStyleWord(true);
- text.setBorder(createEmptyBorder(4, 4, 4, 4));
+ text.setBorder(createTextBorder());
return text;
}
@@ -735,6 +749,29 @@ private static JTextComponent configureHTML(String instructions,
return text;
}
+ /** A default gap between components. */
+ private static final int GAP = 4;
+
+ /**
+ * Creates a default border for frames or dialogs.
+ * It uses the default gap of {@value GAP}.
+ *
+ * @return the border for frames and dialogs
+ */
+ private static Border createFrameBorder() {
+ return createEmptyBorder(GAP, GAP, GAP, GAP);
+ }
+
+ /**
+ * Creates a border set to text area.
+ * It uses the default gap of {@value GAP}.
+ *
+ * @return the border for text area
+ */
+ private static Border createTextBorder() {
+ return createEmptyBorder(GAP, GAP, GAP, GAP);
+ }
+
/**
* Creates a test UI window.
@@ -1086,26 +1123,30 @@ public void awaitAndCheck() throws InterruptedException, InvocationTargetExcepti
* Requests the description of the test failure reason from the tester.
*/
private static void requestFailureReason() {
- final JDialog dialog = new JDialog(frame, "Test Failure ", true);
- dialog.setTitle("Failure reason");
- JPanel jPanel = new JPanel(new BorderLayout());
- JTextArea jTextArea = new JTextArea(5, 20);
+ final JDialog dialog = new JDialog(frame, "Failure reason", true);
+
+ JTextArea reason = new JTextArea(5, 20);
+ reason.setBorder(createTextBorder());
JButton okButton = new JButton("OK");
okButton.addActionListener((ae) -> {
- String text = jTextArea.getText();
+ String text = reason.getText();
setFailureReason(FAILURE_REASON
+ (!text.isEmpty() ? text : EMPTY_REASON));
dialog.setVisible(false);
});
- jPanel.add(new JScrollPane(jTextArea), BorderLayout.CENTER);
-
- JPanel okayBtnPanel = new JPanel();
+ JPanel okayBtnPanel = new JPanel(new FlowLayout(FlowLayout.CENTER,
+ GAP, 0));
+ okayBtnPanel.setBorder(createEmptyBorder(GAP, 0, 0, 0));
okayBtnPanel.add(okButton);
- jPanel.add(okayBtnPanel, BorderLayout.SOUTH);
- dialog.add(jPanel);
+ JPanel main = new JPanel(new BorderLayout());
+ main.setBorder(createFrameBorder());
+ main.add(new JScrollPane(reason), BorderLayout.CENTER);
+ main.add(okayBtnPanel, BorderLayout.SOUTH);
+
+ dialog.add(main);
dialog.setLocationRelativeTo(frame);
dialog.pack();
dialog.setVisible(true);
@@ -1790,9 +1831,41 @@ public PassFailJFrame build() throws InterruptedException,
return new PassFailJFrame(this);
}
+ /**
+ * Returns the file name of the test, if the {@code test.file} property
+ * is defined, concatenated with {@code " - "} which serves as a prefix
+ * to the default instruction frame title;
+ * or an empty string if the {@code test.file} property is not defined.
+ *
+ * @return the prefix to the default title:
+ * either the file name of the test or an empty string
+ *
+ * @see jtreg
+ * test-specific system properties and environment variables
+ */
+ private static String getTestFileNamePrefix() {
+ String testFile = System.getProperty("test.file");
+ if (testFile == null) {
+ return "";
+ }
+
+ return Paths.get(testFile).getFileName().toString()
+ + " - ";
+ }
+
+ /**
+ * Validates the state of the builder and
+ * expands parameters that have no assigned values
+ * to their default values.
+ *
+ * @throws IllegalStateException if no instructions are provided,
+ * or if {@code PositionWindows} implementation is
+ * provided but neither window creator nor
+ * test window list are set
+ */
private void validate() {
if (title == null) {
- title = TITLE;
+ title = getTestFileNamePrefix() + TITLE;
}
if (instructions == null || instructions.isEmpty()) {
diff --git a/test/jdk/java/foreign/TestUpcallStress.java b/test/jdk/java/foreign/TestUpcallStress.java
new file mode 100644
index 00000000000..40607746856
--- /dev/null
+++ b/test/jdk/java/foreign/TestUpcallStress.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. 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.
+ */
+
+/*
+ * @test
+ * @requires jdk.foreign.linker != "FALLBACK"
+ * @requires (os.arch == "aarch64" | os.arch=="riscv64") & os.name == "Linux"
+ * @requires os.maxMemory > 4G
+ * @modules java.base/jdk.internal.foreign
+ * @build NativeTestHelper CallGeneratorHelper TestUpcallBase
+ * @bug 8337753
+ *
+ * @run testng/othervm/timeout=3200
+ * -Xcheck:jni
+ * -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:-VerifyDependencies
+ * --enable-native-access=ALL-UNNAMED
+ * -Dgenerator.sample.factor=17
+ * TestUpcallStress
+ */
+
+import java.lang.foreign.Arena;
+import java.lang.foreign.FunctionDescriptor;
+import java.lang.foreign.MemorySegment;
+
+import org.testng.annotations.Test;
+
+import java.lang.invoke.MethodHandle;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.*;
+import java.util.function.Consumer;
+
+public class TestUpcallStress extends TestUpcallBase {
+
+ static {
+ System.loadLibrary("TestUpcall");
+ }
+
+ @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
+ public void testUpcallsStress(int count, String fName, Ret ret, List paramTypes,
+ List fields) throws Throwable {
+ ExecutorService executor = Executors.newFixedThreadPool(16);
+ for (int threadIdx = 0; threadIdx < 16; threadIdx++) {
+ executor.submit(() -> {
+ for (int iter = 0; iter < 10000; iter++) {
+ List> returnChecks = new ArrayList<>();
+ List> argChecks = new ArrayList<>();
+ MemorySegment addr = findNativeOrThrow(fName);
+ try (Arena arena = Arena.ofConfined()) {
+ FunctionDescriptor descriptor = function(ret, paramTypes, fields);
+ MethodHandle mh = downcallHandle(LINKER, addr, arena, descriptor);
+ AtomicReference